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 }