github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/transport/tuic/server_packet.go (about) 1 //go:build with_quic 2 3 package tuic 4 5 import ( 6 "github.com/sagernet/sing/common" 7 E "github.com/sagernet/sing/common/exceptions" 8 M "github.com/sagernet/sing/common/metadata" 9 ) 10 11 func (s *serverSession) loopMessages() { 12 select { 13 case <-s.connDone: 14 return 15 case <-s.authDone: 16 } 17 for { 18 message, err := s.quicConn.ReceiveMessage(s.ctx) 19 if err != nil { 20 s.closeWithError(E.Cause(err, "receive message")) 21 return 22 } 23 hErr := s.handleMessage(message) 24 if hErr != nil { 25 s.closeWithError(E.Cause(hErr, "handle message")) 26 return 27 } 28 } 29 } 30 31 func (s *serverSession) handleMessage(data []byte) error { 32 if len(data) < 2 { 33 return E.New("invalid message") 34 } 35 if data[0] != Version { 36 return E.New("unknown version ", data[0]) 37 } 38 switch data[1] { 39 case CommandPacket: 40 message := udpMessagePool.Get().(*udpMessage) 41 err := decodeUDPMessage(message, data[2:]) 42 if err != nil { 43 message.release() 44 return E.Cause(err, "decode UDP message") 45 } 46 s.handleUDPMessage(message, false) 47 return nil 48 case CommandHeartbeat: 49 return nil 50 default: 51 return E.New("unknown command ", data[0]) 52 } 53 } 54 55 func (s *serverSession) handleUDPMessage(message *udpMessage, udpStream bool) { 56 s.udpAccess.RLock() 57 udpConn, loaded := s.udpConnMap[message.sessionID] 58 s.udpAccess.RUnlock() 59 if !loaded || common.Done(udpConn.ctx) { 60 udpConn = newUDPPacketConn(s.ctx, s.quicConn, udpStream, true, func() { 61 s.udpAccess.Lock() 62 delete(s.udpConnMap, message.sessionID) 63 s.udpAccess.Unlock() 64 }) 65 udpConn.sessionID = message.sessionID 66 s.udpAccess.Lock() 67 s.udpConnMap[message.sessionID] = udpConn 68 s.udpAccess.Unlock() 69 go s.handler.NewPacketConnection(udpConn.ctx, udpConn, M.Metadata{ 70 Source: s.source, 71 Destination: message.destination, 72 }) 73 } 74 udpConn.inputPacket(message) 75 }