golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/jsonrpc2_v2/serve.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package jsonrpc2
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"io"
    11  	"runtime"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  )
    16  
    17  // Listener is implemented by protocols to accept new inbound connections.
    18  type Listener interface {
    19  	// Accept accepts an inbound connection to a server.
    20  	// It blocks until either an inbound connection is made, or the listener is closed.
    21  	Accept(context.Context) (io.ReadWriteCloser, error)
    22  
    23  	// Close closes the listener.
    24  	// Any blocked Accept or Dial operations will unblock and return errors.
    25  	Close() error
    26  
    27  	// Dialer returns a dialer that can be used to connect to this listener
    28  	// locally.
    29  	// If a listener does not implement this it will return nil.
    30  	Dialer() Dialer
    31  }
    32  
    33  // Dialer is used by clients to dial a server.
    34  type Dialer interface {
    35  	// Dial returns a new communication byte stream to a listening server.
    36  	Dial(ctx context.Context) (io.ReadWriteCloser, error)
    37  }
    38  
    39  // Server is a running server that is accepting incoming connections.
    40  type Server struct {
    41  	listener Listener
    42  	binder   Binder
    43  	async    *async
    44  
    45  	shutdownOnce sync.Once
    46  	closing      int32 // atomic: set to nonzero when Shutdown is called
    47  }
    48  
    49  // Dial uses the dialer to make a new connection, wraps the returned
    50  // reader and writer using the framer to make a stream, and then builds
    51  // a connection on top of that stream using the binder.
    52  //
    53  // The returned Connection will operate independently using the Preempter and/or
    54  // Handler provided by the Binder, and will release its own resources when the
    55  // connection is broken, but the caller may Close it earlier to stop accepting
    56  // (or sending) new requests.
    57  func Dial(ctx context.Context, dialer Dialer, binder Binder) (*Connection, error) {
    58  	// dial a server
    59  	rwc, err := dialer.Dial(ctx)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	return newConnection(ctx, rwc, binder, nil), nil
    64  }
    65  
    66  // NewServer starts a new server listening for incoming connections and returns
    67  // it.
    68  // This returns a fully running and connected server, it does not block on
    69  // the listener.
    70  // You can call Wait to block on the server, or Shutdown to get the sever to
    71  // terminate gracefully.
    72  // To notice incoming connections, use an intercepting Binder.
    73  func NewServer(ctx context.Context, listener Listener, binder Binder) *Server {
    74  	server := &Server{
    75  		listener: listener,
    76  		binder:   binder,
    77  		async:    newAsync(),
    78  	}
    79  	go server.run(ctx)
    80  	return server
    81  }
    82  
    83  // Wait returns only when the server has shut down.
    84  func (s *Server) Wait() error {
    85  	return s.async.wait()
    86  }
    87  
    88  // Shutdown informs the server to stop accepting new connections.
    89  func (s *Server) Shutdown() {
    90  	s.shutdownOnce.Do(func() {
    91  		atomic.StoreInt32(&s.closing, 1)
    92  		s.listener.Close()
    93  	})
    94  }
    95  
    96  // run accepts incoming connections from the listener,
    97  // If IdleTimeout is non-zero, run exits after there are no clients for this
    98  // duration, otherwise it exits only on error.
    99  func (s *Server) run(ctx context.Context) {
   100  	defer s.async.done()
   101  
   102  	var activeConns sync.WaitGroup
   103  	for {
   104  		rwc, err := s.listener.Accept(ctx)
   105  		if err != nil {
   106  			// Only Shutdown closes the listener. If we get an error after Shutdown is
   107  			// called, assume that was the cause and don't report the error;
   108  			// otherwise, report the error in case it is unexpected.
   109  			if atomic.LoadInt32(&s.closing) == 0 {
   110  				s.async.setError(err)
   111  			}
   112  			// We are done generating new connections for good.
   113  			break
   114  		}
   115  
   116  		// A new inbound connection.
   117  		activeConns.Add(1)
   118  		_ = newConnection(ctx, rwc, s.binder, activeConns.Done) // unregisters itself when done
   119  	}
   120  	activeConns.Wait()
   121  }
   122  
   123  // NewIdleListener wraps a listener with an idle timeout.
   124  //
   125  // When there are no active connections for at least the timeout duration,
   126  // calls to Accept will fail with ErrIdleTimeout.
   127  //
   128  // A connection is considered inactive as soon as its Close method is called.
   129  func NewIdleListener(timeout time.Duration, wrap Listener) Listener {
   130  	l := &idleListener{
   131  		wrapped:   wrap,
   132  		timeout:   timeout,
   133  		active:    make(chan int, 1),
   134  		timedOut:  make(chan struct{}),
   135  		idleTimer: make(chan *time.Timer, 1),
   136  	}
   137  	l.idleTimer <- time.AfterFunc(l.timeout, l.timerExpired)
   138  	return l
   139  }
   140  
   141  type idleListener struct {
   142  	wrapped Listener
   143  	timeout time.Duration
   144  
   145  	// Only one of these channels is receivable at any given time.
   146  	active    chan int         // count of active connections; closed when Close is called if not timed out
   147  	timedOut  chan struct{}    // closed when the idle timer expires
   148  	idleTimer chan *time.Timer // holds the timer only when idle
   149  }
   150  
   151  // Accept accepts an incoming connection.
   152  //
   153  // If an incoming connection is accepted concurrent to the listener being closed
   154  // due to idleness, the new connection is immediately closed.
   155  func (l *idleListener) Accept(ctx context.Context) (io.ReadWriteCloser, error) {
   156  	rwc, err := l.wrapped.Accept(ctx)
   157  
   158  	select {
   159  	case n, ok := <-l.active:
   160  		if err != nil {
   161  			if ok {
   162  				l.active <- n
   163  			}
   164  			return nil, err
   165  		}
   166  		if ok {
   167  			l.active <- n + 1
   168  		} else {
   169  			// l.wrapped.Close Close has been called, but Accept returned a
   170  			// connection. This race can occur with concurrent Accept and Close calls
   171  			// with any net.Listener, and it is benign: since the listener was closed
   172  			// explicitly, it can't have also timed out.
   173  		}
   174  		return l.newConn(rwc), nil
   175  
   176  	case <-l.timedOut:
   177  		if err == nil {
   178  			// Keeping the connection open would leave the listener simultaneously
   179  			// active and closed due to idleness, which would be contradictory and
   180  			// confusing. Close the connection and pretend that it never happened.
   181  			rwc.Close()
   182  		} else {
   183  			// In theory the timeout could have raced with an unrelated error return
   184  			// from Accept. However, ErrIdleTimeout is arguably still valid (since we
   185  			// would have closed due to the timeout independent of the error), and the
   186  			// harm from returning a spurious ErrIdleTimeout is negligible anyway.
   187  		}
   188  		return nil, ErrIdleTimeout
   189  
   190  	case timer := <-l.idleTimer:
   191  		if err != nil {
   192  			// The idle timer doesn't run until it receives itself from the idleTimer
   193  			// channel, so it can't have called l.wrapped.Close yet and thus err can't
   194  			// be ErrIdleTimeout. Leave the idle timer as it was and return whatever
   195  			// error we got.
   196  			l.idleTimer <- timer
   197  			return nil, err
   198  		}
   199  
   200  		if !timer.Stop() {
   201  			// Failed to stop the timer — the timer goroutine is in the process of
   202  			// firing. Send the timer back to the timer goroutine so that it can
   203  			// safely close the timedOut channel, and then wait for the listener to
   204  			// actually be closed before we return ErrIdleTimeout.
   205  			l.idleTimer <- timer
   206  			rwc.Close()
   207  			<-l.timedOut
   208  			return nil, ErrIdleTimeout
   209  		}
   210  
   211  		l.active <- 1
   212  		return l.newConn(rwc), nil
   213  	}
   214  }
   215  
   216  func (l *idleListener) Close() error {
   217  	select {
   218  	case _, ok := <-l.active:
   219  		if ok {
   220  			close(l.active)
   221  		}
   222  
   223  	case <-l.timedOut:
   224  		// Already closed by the timer; take care not to double-close if the caller
   225  		// only explicitly invokes this Close method once, since the io.Closer
   226  		// interface explicitly leaves doubled Close calls undefined.
   227  		return ErrIdleTimeout
   228  
   229  	case timer := <-l.idleTimer:
   230  		if !timer.Stop() {
   231  			// Couldn't stop the timer. It shouldn't take long to run, so just wait
   232  			// (so that the Listener is guaranteed to be closed before we return)
   233  			// and pretend that this call happened afterward.
   234  			// That way we won't leak any timers or goroutines when Close returns.
   235  			l.idleTimer <- timer
   236  			<-l.timedOut
   237  			return ErrIdleTimeout
   238  		}
   239  		close(l.active)
   240  	}
   241  
   242  	return l.wrapped.Close()
   243  }
   244  
   245  func (l *idleListener) Dialer() Dialer {
   246  	return l.wrapped.Dialer()
   247  }
   248  
   249  func (l *idleListener) timerExpired() {
   250  	select {
   251  	case n, ok := <-l.active:
   252  		if ok {
   253  			panic(fmt.Sprintf("jsonrpc2: idleListener idle timer fired with %d connections still active", n))
   254  		} else {
   255  			panic("jsonrpc2: Close finished with idle timer still running")
   256  		}
   257  
   258  	case <-l.timedOut:
   259  		panic("jsonrpc2: idleListener idle timer fired more than once")
   260  
   261  	case <-l.idleTimer:
   262  		// The timer for this very call!
   263  	}
   264  
   265  	// Close the Listener with all channels still blocked to ensure that this call
   266  	// to l.wrapped.Close doesn't race with the one in l.Close.
   267  	defer close(l.timedOut)
   268  	l.wrapped.Close()
   269  }
   270  
   271  func (l *idleListener) connClosed() {
   272  	select {
   273  	case n, ok := <-l.active:
   274  		if !ok {
   275  			// l is already closed, so it can't close due to idleness,
   276  			// and we don't need to track the number of active connections any more.
   277  			return
   278  		}
   279  		n--
   280  		if n == 0 {
   281  			l.idleTimer <- time.AfterFunc(l.timeout, l.timerExpired)
   282  		} else {
   283  			l.active <- n
   284  		}
   285  
   286  	case <-l.timedOut:
   287  		panic("jsonrpc2: idleListener idle timer fired before last active connection was closed")
   288  
   289  	case <-l.idleTimer:
   290  		panic("jsonrpc2: idleListener idle timer active before last active connection was closed")
   291  	}
   292  }
   293  
   294  type idleListenerConn struct {
   295  	wrapped   io.ReadWriteCloser
   296  	l         *idleListener
   297  	closeOnce sync.Once
   298  }
   299  
   300  func (l *idleListener) newConn(rwc io.ReadWriteCloser) *idleListenerConn {
   301  	c := &idleListenerConn{
   302  		wrapped: rwc,
   303  		l:       l,
   304  	}
   305  
   306  	// A caller that forgets to call Close may disrupt the idleListener's
   307  	// accounting, even though the file descriptor for the underlying connection
   308  	// may eventually be garbage-collected anyway.
   309  	//
   310  	// Set a (best-effort) finalizer to verify that a Close call always occurs.
   311  	// (We will clear the finalizer explicitly in Close.)
   312  	runtime.SetFinalizer(c, func(c *idleListenerConn) {
   313  		panic("jsonrpc2: IdleListener connection became unreachable without a call to Close")
   314  	})
   315  
   316  	return c
   317  }
   318  
   319  func (c *idleListenerConn) Read(p []byte) (int, error)  { return c.wrapped.Read(p) }
   320  func (c *idleListenerConn) Write(p []byte) (int, error) { return c.wrapped.Write(p) }
   321  
   322  func (c *idleListenerConn) Close() error {
   323  	defer c.closeOnce.Do(func() {
   324  		c.l.connClosed()
   325  		runtime.SetFinalizer(c, nil)
   326  	})
   327  	return c.wrapped.Close()
   328  }