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

import (
	"fmt"

Jeromy's avatar
Jeromy committed
6 7
	inet "github.com/libp2p/go-libp2p-net"
	ma "github.com/multiformats/go-multiaddr"
Jeromy's avatar
Jeromy committed
8
)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9

Steven Allen's avatar
Steven Allen committed
10 11 12
// 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
13 14 15
	errs := make([]error, len(addrs))
	var succeeded int
	for i, a := range addrs {
16
		if err := s.AddListenAddr(a); err != nil {
Jeromy's avatar
Jeromy committed
17
			errs[i] = err
18 19
		} else {
			succeeded++
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20 21 22
		}
	}

Jeromy's avatar
Jeromy committed
23 24
	for i, e := range errs {
		if e != nil {
Jeromy's avatar
Jeromy committed
25
			log.Warningf("listen on %s failed: %s", addrs[i], errs[i])
Jeromy's avatar
Jeromy committed
26
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27
	}
28

Jeromy's avatar
Jeromy committed
29 30 31 32
	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
33 34 35
	return nil
}

Steven Allen's avatar
Steven Allen committed
36 37 38 39 40 41
// 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 {
		return ErrNoTransport
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42
	}
Jeromy's avatar
Jeromy committed
43

Steven Allen's avatar
Steven Allen committed
44
	list, err := tpt.Listen(a)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45 46 47 48
	if err != nil {
		return err
	}

Steven Allen's avatar
Steven Allen committed
49 50 51 52 53
	s.listeners.Lock()
	if s.listeners.m == nil {
		s.listeners.Unlock()
		list.Close()
		return ErrSwarmClosed
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54
	}
Steven Allen's avatar
Steven Allen committed
55 56 57
	s.refs.Add(1)
	s.listeners.m[list] = struct{}{}
	s.listeners.Unlock()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58

Jeromy's avatar
Jeromy committed
59 60
	maddr := list.Multiaddr()

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
61 62
	// signal to our notifiees on successful conn.
	s.notifyAll(func(n inet.Notifiee) {
Steven Allen's avatar
Steven Allen committed
63
		n.Listen(s, maddr)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64 65
	})

Steven Allen's avatar
Steven Allen committed
66 67 68 69 70 71 72 73
	go func() {
		defer func() {
			list.Close()
			s.listeners.Lock()
			delete(s.listeners.m, list)
			s.listeners.Unlock()
			s.refs.Done()
		}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
74
		for {
Steven Allen's avatar
Steven Allen committed
75 76
			c, err := list.Accept()
			if err != nil {
Jeromy's avatar
Jeromy committed
77
				log.Warningf("swarm listener accept error: %s", err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78 79
				return
			}
Steven Allen's avatar
Steven Allen committed
80 81 82 83
			log.Debugf("swarm listener accepted connection: %s", c)
			s.refs.Add(1)
			go func() {
				defer s.refs.Done()
84
				_, err := s.addConn(c, inet.DirInbound)
Steven Allen's avatar
Steven Allen committed
85 86 87 88 89 90
				if err != nil {
					// Probably just means that the swarm has been closed.
					log.Warningf("add conn failed: ", err)
					return
				}
			}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
		}
Steven Allen's avatar
Steven Allen committed
92
	}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
93 94
	return nil
}