github.com/xmplusdev/xmcore@v1.8.11-0.20240412132628-5518b55526af/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/xmplusdev/xmcore/common"
    11  	"github.com/xmplusdev/xmcore/common/net"
    12  	"github.com/xmplusdev/xmcore/common/protocol/tls/cert"
    13  	"github.com/xmplusdev/xmcore/common/signal/done"
    14  	"github.com/xmplusdev/xmcore/transport/internet"
    15  	"github.com/xmplusdev/xmcore/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  }