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

     1  // Copyright 2018 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  	"io"
    10  	"net"
    11  	"os"
    12  )
    13  
    14  // This file contains implementations of the transport primitives that use the standard network
    15  // package.
    16  
    17  // NetListenOptions is the optional arguments to the NetListen function.
    18  type NetListenOptions struct {
    19  	NetListenConfig net.ListenConfig
    20  	NetDialer       net.Dialer
    21  }
    22  
    23  // NetListener returns a new Listener that listens on a socket using the net package.
    24  func NetListener(ctx context.Context, network, address string, options NetListenOptions) (Listener, error) {
    25  	ln, err := options.NetListenConfig.Listen(ctx, network, address)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	return &netListener{net: ln}, nil
    30  }
    31  
    32  // netListener is the implementation of Listener for connections made using the net package.
    33  type netListener struct {
    34  	net net.Listener
    35  }
    36  
    37  // Accept blocks waiting for an incoming connection to the listener.
    38  func (l *netListener) Accept(context.Context) (io.ReadWriteCloser, error) {
    39  	return l.net.Accept()
    40  }
    41  
    42  // Close will cause the listener to stop listening. It will not close any connections that have
    43  // already been accepted.
    44  func (l *netListener) Close() error {
    45  	addr := l.net.Addr()
    46  	err := l.net.Close()
    47  	if addr.Network() == "unix" {
    48  		rerr := os.Remove(addr.String())
    49  		if rerr != nil && err == nil {
    50  			err = rerr
    51  		}
    52  	}
    53  	return err
    54  }
    55  
    56  // Dialer returns a dialer that can be used to connect to the listener.
    57  func (l *netListener) Dialer() Dialer {
    58  	return NetDialer(l.net.Addr().Network(), l.net.Addr().String(), net.Dialer{})
    59  }
    60  
    61  // NetDialer returns a Dialer using the supplied standard network dialer.
    62  func NetDialer(network, address string, nd net.Dialer) Dialer {
    63  	return &netDialer{
    64  		network: network,
    65  		address: address,
    66  		dialer:  nd,
    67  	}
    68  }
    69  
    70  type netDialer struct {
    71  	network string
    72  	address string
    73  	dialer  net.Dialer
    74  }
    75  
    76  func (n *netDialer) Dial(ctx context.Context) (io.ReadWriteCloser, error) {
    77  	return n.dialer.DialContext(ctx, n.network, n.address)
    78  }
    79  
    80  // NetPipeListener returns a new Listener that listens using net.Pipe.
    81  // It is only possibly to connect to it using the Dialer returned by the
    82  // Dialer method, each call to that method will generate a new pipe the other
    83  // side of which will be returned from the Accept call.
    84  func NetPipeListener(ctx context.Context) (Listener, error) {
    85  	return &netPiper{
    86  		done:   make(chan struct{}),
    87  		dialed: make(chan io.ReadWriteCloser),
    88  	}, nil
    89  }
    90  
    91  // netPiper is the implementation of Listener build on top of net.Pipes.
    92  type netPiper struct {
    93  	done   chan struct{}
    94  	dialed chan io.ReadWriteCloser
    95  }
    96  
    97  // Accept blocks waiting for an incoming connection to the listener.
    98  func (l *netPiper) Accept(context.Context) (io.ReadWriteCloser, error) {
    99  	// Block until the pipe is dialed or the listener is closed,
   100  	// preferring the latter if already closed at the start of Accept.
   101  	select {
   102  	case <-l.done:
   103  		return nil, errClosed
   104  	default:
   105  	}
   106  	select {
   107  	case rwc := <-l.dialed:
   108  		return rwc, nil
   109  	case <-l.done:
   110  		return nil, errClosed
   111  	}
   112  }
   113  
   114  // Close will cause the listener to stop listening. It will not close any connections that have
   115  // already been accepted.
   116  func (l *netPiper) Close() error {
   117  	// unblock any accept calls that are pending
   118  	close(l.done)
   119  	return nil
   120  }
   121  
   122  func (l *netPiper) Dialer() Dialer {
   123  	return l
   124  }
   125  
   126  func (l *netPiper) Dial(ctx context.Context) (io.ReadWriteCloser, error) {
   127  	client, server := net.Pipe()
   128  
   129  	select {
   130  	case l.dialed <- server:
   131  		return client, nil
   132  
   133  	case <-l.done:
   134  		client.Close()
   135  		server.Close()
   136  		return nil, errClosed
   137  	}
   138  }