swarm_listen.go 2.56 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3 4
package swarm

import (
	"fmt"
5
	"time"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
6

tavit ohanian's avatar
tavit ohanian committed
7
	"gitlab.dms3.io/p2p/go-p2p-core/network"
8

9
	ma "gitlab.dms3.io/mf/go-multiaddr"
Jeromy's avatar
Jeromy committed
10
)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11

Steven Allen's avatar
Steven Allen committed
12 13 14
// Listen sets up listeners for all of the given addresses.
// It returns as long as we successfully listen on at least *one* address.
func (s *Swarm) Listen(addrs ...ma.Multiaddr) error {
Jeromy's avatar
Jeromy committed
15 16 17
	errs := make([]error, len(addrs))
	var succeeded int
	for i, a := range addrs {
18
		if err := s.AddListenAddr(a); err != nil {
Jeromy's avatar
Jeromy committed
19
			errs[i] = err
20 21
		} else {
			succeeded++
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
22 23 24
		}
	}

Jeromy's avatar
Jeromy committed
25 26
	for i, e := range errs {
		if e != nil {
Cory Schwartz's avatar
Cory Schwartz committed
27
			log.Warnw("listening failed", "on", addrs[i], "error", errs[i])
Jeromy's avatar
Jeromy committed
28
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29
	}
30

Jeromy's avatar
Jeromy committed
31 32 33 34
	if succeeded == 0 && len(addrs) > 0 {
		return fmt.Errorf("failed to listen on any addresses: %s", errs)
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35 36 37
	return nil
}

Steven Allen's avatar
Steven Allen committed
38 39 40 41 42
// AddListenAddr tells the swarm to listen on a single address. Unlike Listen,
// this method does not attempt to filter out bad addresses.
func (s *Swarm) AddListenAddr(a ma.Multiaddr) error {
	tpt := s.TransportForListening(a)
	if tpt == nil {
43 44 45 46 47 48 49 50 51 52 53
		// TransportForListening will return nil if either:
		// 1. No transport has been registered.
		// 2. We're closed (so we've nulled out the transport map.
		//
		// Distinguish between these two cases to avoid confusing users.
		select {
		case <-s.proc.Closing():
			return ErrSwarmClosed
		default:
			return ErrNoTransport
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54
	}
Jeromy's avatar
Jeromy committed
55

Steven Allen's avatar
Steven Allen committed
56
	list, err := tpt.Listen(a)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
57 58 59 60
	if err != nil {
		return err
	}

Steven Allen's avatar
Steven Allen committed
61 62 63 64 65
	s.listeners.Lock()
	if s.listeners.m == nil {
		s.listeners.Unlock()
		list.Close()
		return ErrSwarmClosed
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
66
	}
Steven Allen's avatar
Steven Allen committed
67 68
	s.refs.Add(1)
	s.listeners.m[list] = struct{}{}
69
	s.listeners.cacheEOL = time.Time{}
Steven Allen's avatar
Steven Allen committed
70
	s.listeners.Unlock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71

Jeromy's avatar
Jeromy committed
72 73
	maddr := list.Multiaddr()

74
	// signal to our notifiees on listen.
75
	s.notifyAll(func(n network.Notifiee) {
Steven Allen's avatar
Steven Allen committed
76
		n.Listen(s, maddr)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77 78
	})

Steven Allen's avatar
Steven Allen committed
79 80 81 82 83
	go func() {
		defer func() {
			list.Close()
			s.listeners.Lock()
			delete(s.listeners.m, list)
84
			s.listeners.cacheEOL = time.Time{}
Steven Allen's avatar
Steven Allen committed
85
			s.listeners.Unlock()
86 87 88 89 90

			// signal to our notifiees on listen close.
			s.notifyAll(func(n network.Notifiee) {
				n.ListenClose(s, maddr)
			})
Steven Allen's avatar
Steven Allen committed
91 92
			s.refs.Done()
		}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93
		for {
Steven Allen's avatar
Steven Allen committed
94 95
			c, err := list.Accept()
			if err != nil {
Matt Joiner's avatar
Matt Joiner committed
96
				if s.ctx.Err() == nil {
97
					// only log if the swarm is still running.
Matt Joiner's avatar
Matt Joiner committed
98 99
					log.Errorf("swarm listener accept error: %s", err)
				}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
100 101
				return
			}
102

Steven Allen's avatar
Steven Allen committed
103 104 105 106
			log.Debugf("swarm listener accepted connection: %s", c)
			s.refs.Add(1)
			go func() {
				defer s.refs.Done()
107
				_, err := s.addConn(c, network.DirInbound)
108 109 110 111 112 113
				switch err {
				case nil:
				case ErrSwarmClosed:
					// ignore.
					return
				default:
Cory Schwartz's avatar
Cory Schwartz committed
114
					log.Warnw("adding connection failed", "to", a, "error", err)
Steven Allen's avatar
Steven Allen committed
115 116 117
					return
				}
			}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
118
		}
Steven Allen's avatar
Steven Allen committed
119
	}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121
	return nil
}