github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/transport/internet/quic/hub.go (about) 1 package quic 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/quic-go/quic-go" 8 "github.com/quic-go/quic-go/logging" 9 "github.com/quic-go/quic-go/qlog" 10 "github.com/xtls/xray-core/common" 11 "github.com/xtls/xray-core/common/net" 12 "github.com/xtls/xray-core/common/protocol/tls/cert" 13 "github.com/xtls/xray-core/common/signal/done" 14 "github.com/xtls/xray-core/transport/internet" 15 "github.com/xtls/xray-core/transport/internet/tls" 16 ) 17 18 // Listener is an internet.Listener that listens for TCP connections. 19 type Listener struct { 20 rawConn *sysConn 21 listener *quic.Listener 22 done *done.Instance 23 addConn internet.ConnHandler 24 } 25 26 func (l *Listener) acceptStreams(conn quic.Connection) { 27 for { 28 stream, err := conn.AcceptStream(context.Background()) 29 if err != nil { 30 newError("failed to accept stream").Base(err).WriteToLog() 31 select { 32 case <-conn.Context().Done(): 33 return 34 case <-l.done.Wait(): 35 if err := conn.CloseWithError(0, ""); err != nil { 36 newError("failed to close connection").Base(err).WriteToLog() 37 } 38 return 39 default: 40 time.Sleep(time.Second) 41 continue 42 } 43 } 44 45 conn := &interConn{ 46 stream: stream, 47 local: conn.LocalAddr(), 48 remote: conn.RemoteAddr(), 49 } 50 51 l.addConn(conn) 52 } 53 } 54 55 func (l *Listener) keepAccepting() { 56 for { 57 conn, err := l.listener.Accept(context.Background()) 58 if err != nil { 59 newError("failed to accept QUIC connection").Base(err).WriteToLog() 60 if l.done.Done() { 61 break 62 } 63 time.Sleep(time.Second) 64 continue 65 } 66 go l.acceptStreams(conn) 67 } 68 } 69 70 // Addr implements internet.Listener.Addr. 71 func (l *Listener) Addr() net.Addr { 72 return l.listener.Addr() 73 } 74 75 // Close implements internet.Listener.Close. 76 func (l *Listener) Close() error { 77 l.done.Close() 78 l.listener.Close() 79 l.rawConn.Close() 80 return nil 81 } 82 83 // Listen creates a new Listener based on configurations. 84 func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) { 85 if address.Family().IsDomain() { 86 return nil, newError("domain address is not allows for listening quic") 87 } 88 89 tlsConfig := tls.ConfigFromStreamSettings(streamSettings) 90 if tlsConfig == nil { 91 tlsConfig = &tls.Config{ 92 Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.DNSNames(internalDomain), cert.CommonName(internalDomain)))}, 93 } 94 } 95 96 config := streamSettings.ProtocolSettings.(*Config) 97 rawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{ 98 IP: address.IP(), 99 Port: int(port), 100 }, streamSettings.SocketSettings) 101 if err != nil { 102 return nil, err 103 } 104 105 quicConfig := &quic.Config{ 106 KeepAlivePeriod: 0, 107 HandshakeIdleTimeout: time.Second * 8, 108 MaxIdleTimeout: time.Second * 300, 109 MaxIncomingStreams: 32, 110 MaxIncomingUniStreams: -1, 111 Tracer: func(ctx context.Context, p logging.Perspective, ci quic.ConnectionID) *logging.ConnectionTracer { 112 return qlog.NewConnectionTracer(&QlogWriter{connID: ci}, p, ci) 113 }, 114 } 115 116 conn, err := wrapSysConn(rawConn.(*net.UDPConn), config) 117 if err != nil { 118 conn.Close() 119 return nil, err 120 } 121 tr := quic.Transport{ 122 ConnectionIDLength: 12, 123 Conn: conn, 124 } 125 qListener, err := tr.Listen(tlsConfig.GetTLSConfig(), quicConfig) 126 if err != nil { 127 conn.Close() 128 return nil, err 129 } 130 131 listener := &Listener{ 132 done: done.New(), 133 rawConn: conn, 134 listener: qListener, 135 addConn: handler, 136 } 137 138 go listener.keepAccepting() 139 140 return listener, nil 141 } 142 143 func init() { 144 common.Must(internet.RegisterTransportListener(protocolName, Listen)) 145 }