diff --git a/listen.go b/listen.go index 616204d..09f1a03 100644 --- a/listen.go +++ b/listen.go @@ -1,10 +1,95 @@ package hopp -import "io" 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 { - io.Closer - Accept(Conn, error) + // 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() +} diff --git a/listener.go b/listener.go deleted file mode 100644 index 616204d..0000000 --- a/listener.go +++ /dev/null @@ -1,10 +0,0 @@ -package hopp - -import "io" -import "net" - -type Listener interface { - io.Closer - Accept(Conn, error) - Addr() net.Addr -}