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