10 "github.com/anacrolix/missinggo"
13 type dialer interface {
14 dial(_ context.Context, addr string) (net.Conn, error)
17 type socket interface {
22 func listen(network, addr string) (socket, error) {
23 if isTcpNetwork(network) {
24 return listenTcp(network, addr)
25 } else if isUtpNetwork(network) {
26 return listenUtp(network, addr)
28 panic(fmt.Sprintf("unknown network %q", network))
32 func isTcpNetwork(s string) bool {
33 return strings.Contains(s, "tcp")
36 func isUtpNetwork(s string) bool {
37 return strings.Contains(s, "utp") || strings.Contains(s, "udp")
40 func listenTcp(network, address string) (s socket, err error) {
41 l, err := net.Listen(network, address)
45 return tcpSocket{l}, nil
48 type tcpSocket struct {
52 func (me tcpSocket) dial(ctx context.Context, addr string) (net.Conn, error) {
53 return net.Dial(me.Addr().Network(), addr)
56 func setPort(addr string, port int) string {
57 host, _, err := net.SplitHostPort(addr)
61 return net.JoinHostPort(host, strconv.FormatInt(int64(port), 10))
64 func listenAll(networks []string, getHost func(string) string, port int) ([]socket, error) {
65 if len(networks) == 0 {
68 var nahs []networkAndHost
69 for _, n := range networks {
70 nahs = append(nahs, networkAndHost{n, getHost(n)})
73 ss, retry, err := listenAllRetry(nahs, port)
80 type networkAndHost struct {
85 func listenAllRetry(nahs []networkAndHost, port int) (ss []socket, retry bool, err error) {
86 ss = make([]socket, 1, len(nahs))
87 portStr := strconv.FormatInt(int64(port), 10)
88 ss[0], err = listen(nahs[0].Network, net.JoinHostPort(nahs[0].Host, portStr))
90 return nil, false, fmt.Errorf("first listen: %s", err)
93 if err != nil || retry {
94 for _, s := range ss {
100 portStr = strconv.FormatInt(int64(missinggo.AddrPort(ss[0].Addr())), 10)
101 for _, nah := range nahs[1:] {
102 s, err := listen(nah.Network, net.JoinHostPort(nah.Host, portStr))
105 missinggo.IsAddrInUse(err) && port == 0,
106 fmt.Errorf("subsequent listen: %s", err)
113 func listenUtp(network, addr string) (s socket, err error) {
114 us, err := NewUtpSocket(network, addr)
118 return utpSocketSocket{us, network}, nil
121 type utpSocketSocket struct {
126 func (me utpSocketSocket) dial(ctx context.Context, addr string) (net.Conn, error) {
127 return me.utpSocket.DialContext(ctx, me.network, addr)