package hopp import "net" import "context" import "crypto/tls" import "github.com/quic-go/quic-go" // Listener is an object which listens for incoming HOPP connections. type Listener interface { // Accept waits for and returns the next connection to the listener. Accept() (Conn, error) // Close closes the listener. Any blocked Accept operations will be // unblocked and return errors. Close() error // Addr returns the listener's network address. Addr() net.Addr } // Listen listens for incoming HOPP connections. The network must be one of // "quic", "quic4", (IPv4-only) "quic6" (IPv6-only), or "unix". func Listen(network, address string) (Listener, error) { switch network { case "quic", "quic4", "quic6": return ListenQUIC(network, address, nil) case "unix": return ListenUnix(network, address) default: return nil, ErrUnknownNetwork } } // ListenQUIC listens for incoming HOPP connections using QUIC as a transport. // The network must be one of "quic", "quic4", (IPv4-only) or "quic6" // (IPv6-only). func ListenQUIC(network, address string, tlsConf *tls.Config) (Listener, error) { tlsConf = tlsConfig(tlsConf) quicConf := quicConfig() udpNetwork, err := quicNetworkToUDPNetwork(network) if err != nil { return nil, err } addr, err := net.ResolveUDPAddr(udpNetwork, address) if err != nil { return nil, err } udpListener, err := net.ListenUDP(udpNetwork, addr) if err != nil { return nil, err } quicListener, err := quic.Listen(udpListener, tlsConf, quicConf) if err != nil { return nil, err } return &listenerQUIC { underlying: quicListener, }, nil } // ListenUnix listens for incoming HOPP connections using a Unix domain socket // as a transport. The network must be "unix". func ListenUnix(network, address string) (Listener, error) { if network != "unix" { return nil, ErrUnknownNetwork } addr, err := net.ResolveUnixAddr(network, address) if err != nil { return nil, err } unixListener, err := net.ListenUnix(network, addr) if err != nil { return nil, err } return &listenerUnix { underlying: unixListener, }, nil } type listenerQUIC struct { underlying *quic.Listener } func (this *listenerQUIC) Accept() (Conn, error) { conn, err := this.underlying.Accept(context.Background()) if err != nil { return nil, err } return AdaptB(quicMultiConn { underlying: conn }), nil } func (this *listenerQUIC) Close() error { return this.underlying.Close() } func (this *listenerQUIC) Addr() net.Addr { return this.underlying.Addr() } type listenerUnix struct { underlying *net.UnixListener } func (this *listenerUnix) Accept() (Conn, error) { conn, err := this.underlying.Accept() if err != nil { return nil, err } return AdaptA(conn, ServerSide), nil } func (this *listenerUnix) Close() error { return this.underlying.Close() } func (this *listenerUnix) Addr() net.Addr { return this.underlying.Addr() }