github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/uot/client.go (about)

     1  package uot
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  
     7  	E "github.com/sagernet/sing/common/exceptions"
     8  	M "github.com/sagernet/sing/common/metadata"
     9  	N "github.com/sagernet/sing/common/network"
    10  )
    11  
    12  type Client struct {
    13  	Dialer  N.Dialer
    14  	Version uint8
    15  }
    16  
    17  func (c *Client) DialConn(conn net.Conn, isConnect bool, destination M.Socksaddr) (*Conn, error) {
    18  	switch c.Version {
    19  	case 0, Version:
    20  		request := Request{
    21  			IsConnect:   isConnect,
    22  			Destination: destination,
    23  		}
    24  		err := WriteRequest(conn, request)
    25  		if err != nil {
    26  			return nil, err
    27  		}
    28  		return NewConn(conn, request), nil
    29  	case LegacyVersion:
    30  		return NewConn(conn, Request{}), nil
    31  	default:
    32  		return nil, E.New("unknown protocol version: ", c.Version)
    33  	}
    34  }
    35  
    36  func (c *Client) DialEarlyConn(conn net.Conn, isConnect bool, destination M.Socksaddr) (*Conn, error) {
    37  	switch c.Version {
    38  	case 0, Version:
    39  		request := Request{
    40  			IsConnect:   isConnect,
    41  			Destination: destination,
    42  		}
    43  		return NewLazyConn(conn, request), nil
    44  	case LegacyVersion:
    45  		return NewConn(conn, Request{}), nil
    46  	default:
    47  		return nil, E.New("unknown protocol version: ", c.Version)
    48  	}
    49  }
    50  
    51  func (c *Client) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
    52  	switch N.NetworkName(network) {
    53  	case N.NetworkUDP:
    54  		tcpConn, err := c.Dialer.DialContext(ctx, N.NetworkTCP, RequestDestination(c.Version))
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  		uConn, err := c.DialEarlyConn(tcpConn, true, destination)
    59  		if err != nil {
    60  			tcpConn.Close()
    61  			return nil, err
    62  		}
    63  		return uConn, nil
    64  	default:
    65  		return c.Dialer.DialContext(ctx, network, destination)
    66  	}
    67  }
    68  
    69  func (c *Client) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
    70  	tcpConn, err := c.Dialer.DialContext(ctx, N.NetworkTCP, RequestDestination(c.Version))
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	uConn, err := c.DialEarlyConn(tcpConn, false, destination)
    75  	if err != nil {
    76  		tcpConn.Close()
    77  		return nil, err
    78  	}
    79  	return uConn, nil
    80  }