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 }