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