package hopp import "net" import "context" import "crypto/tls" import "github.com/quic-go/quic-go" // TODO: dial should be super simple like it is now, and there should be a // "dialer" which the dial function dial configures automaticaly, but the dialer // should offer much more options when used directlym // Dial opens a connection to a server. The network must be one of "udp", // "udp4", "udp6", or "unixgram". func Dial(ctx context.Context, network, address string) (Conn, error) { return (Dialer { }).Dial(ctx, network, address) } // TODO: export when there are options here type Dialer struct { TLSConfig *tls.Config } // Dial opens a connection to a server. The network must be one of "quic", // "quic4", "quic6", or "unix". func (diale Dialer) Dial(ctx context.Context, network, address string) (Conn, error) { switch network { case "quic", "quic4", "quic6": return diale.dialQUIC(ctx, network, address) case "unix": return diale.dialUnix(ctx, network, address) default: return nil, ErrUnknownNetwork } } func (diale Dialer) dialQUIC(ctx context.Context, network, address string) (Conn, error) { udpNetwork, err := quicNetworkToUDPNetwork(network) if err != nil { return nil, err } addr, err := net.ResolveUDPAddr(udpNetwork, address) if err != nil { return nil, err } udpConn, err := net.DialUDP(udpNetwork, nil, addr) if err != nil { return nil, err } conn, err := quic.Dial(ctx, udpConn, addr, diale.tlsConfig(), diale.quicConfig()) if err != nil { return nil, err } return AdaptB(quicMultiConn { underlying: conn }), nil } func (diale Dialer) dialUnix(ctx context.Context, network, address string) (Conn, error) { if network != "unix" { return nil, ErrUnknownNetwork } addr, err := net.ResolveUnixAddr(network, address) if err != nil { return nil, err } conn, err := net.DialUnix(network, nil, addr) if err != nil { return nil, err } // REMEMBER - THIS IS VERY IMPORTANT: // WHEN YOU INEVITABLY COPY PASTE THIS FOR THE SERVER-SIDE, CHANGE THE // PARTY CONSTANT TO ServerSide! OTHERWISE THERE WILL BE COLLISIONS! return AdaptA(conn, ClientSide), nil } func (diale Dialer) tlsConfig() *tls.Config { conf := diale.TLSConfig.Clone() conf.NextProtos = []string { "HOPP/0", } return conf } func (diale Dialer) quicConfig() *quic.Config { return &quic.Config { // TODO: perhaps we might want to put something here // the quic config shouldn't be exported, just set up // automatically. we can't have that strangely built quic-go // package be part of the API, or any third-party packages for // that matter. it must all be abstracted away. } } func quicNetworkToUDPNetwork(network string) (string, error) { switch network { case "quic4": return "udp4", nil case "quic6": return "udp6", nil case "quic": return "udp", nil default: return "", ErrUnknownNetwork } }