github.com/yaling888/clash@v1.53.0/transport/vless/conn.go (about)

     1  package vless
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"net"
     7  
     8  	"github.com/yaling888/clash/common/pool"
     9  	"github.com/yaling888/clash/common/uuid"
    10  )
    11  
    12  type Conn struct {
    13  	net.Conn
    14  	dst      *DstAddr
    15  	id       uuid.UUID
    16  	received bool
    17  }
    18  
    19  func (vc *Conn) Read(b []byte) (int, error) {
    20  	if vc.received {
    21  		return vc.Conn.Read(b)
    22  	}
    23  
    24  	if err := vc.recvResponse(); err != nil {
    25  		return 0, err
    26  	}
    27  	vc.received = true
    28  	return vc.Conn.Read(b)
    29  }
    30  
    31  func (vc *Conn) sendRequest() error {
    32  	buf := pool.BufferWriter{}
    33  
    34  	buf.PutUint8(Version)       // protocol version
    35  	buf.PutSlice(vc.id.Bytes()) // 16 bytes of uuid
    36  	buf.PutUint8(0)             // addon data length. 0 means no addon data
    37  	// buf.PutString("")           // addon data
    38  
    39  	// Command
    40  	if vc.dst.UDP {
    41  		buf.PutUint8(CommandUDP)
    42  	} else {
    43  		buf.PutUint8(CommandTCP)
    44  	}
    45  
    46  	// Port AddrType Addr
    47  	buf.PutUint16be(uint16(vc.dst.Port))
    48  	buf.PutUint8(vc.dst.AddrType)
    49  	buf.PutSlice(vc.dst.Addr)
    50  
    51  	_, err := vc.Conn.Write(buf.Bytes())
    52  	return err
    53  }
    54  
    55  func (vc *Conn) recvResponse() error {
    56  	var buf [2]byte
    57  	if _, err := io.ReadFull(vc.Conn, buf[:]); err != nil {
    58  		return err
    59  	}
    60  
    61  	if buf[0] != Version {
    62  		return errors.New("unexpected response version")
    63  	}
    64  
    65  	length := int64(buf[1])
    66  	if length > 0 { // addon data length > 0
    67  		_, _ = io.CopyN(io.Discard, vc.Conn, length) // just discard
    68  	}
    69  
    70  	return nil
    71  }
    72  
    73  // newConn return a Conn instance
    74  func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) {
    75  	c := &Conn{
    76  		Conn: conn,
    77  		id:   client.uuid,
    78  		dst:  dst,
    79  	}
    80  
    81  	if err := c.sendRequest(); err != nil {
    82  		return nil, err
    83  	}
    84  	return c, nil
    85  }