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