swarm + net: add explicit listen addresses
Juan Batiz-Benet committed
Nov 5, 2014 at 03:59 UTC
0135e3ebbe2d8e676190d5832fec8c7a869ee1a0
8 files changed
+138
-23
core/core.go
+21
-11
@@ -123,7 +123,12 @@ func NewIpfsNode(cfg *config.Config, online bool) (n *IpfsNode, err error) {
123
}
124
125
// setup the network
126
- n.Network, err = inet.NewIpfsNetwork(ctx, n.Identity, n.Peerstore, muxMap)
126
+ listenAddrs, err := listenAddresses(cfg)
127
+ if err != nil {
128
+ return nil, err
129
+ }
130
+
131
+ n.Network, err = inet.NewIpfsNetwork(ctx, listenAddrs, n.Identity, n.Peerstore, muxMap)
132
if err != nil {
133
return nil, err
134
}
@@ -183,16 +188,6 @@ func initIdentity(cfg *config.Config, peers peer.Peerstore, online bool) (peer.P
188
return nil, err
189
}
190
186
- // address is optional
187
- if len(cfg.Addresses.Swarm) > 0 {
188
- maddr, err := ma.NewMultiaddr(cfg.Addresses.Swarm)
189
- if err != nil {
190
- return nil, err
191
- }
192
-
193
- peer.AddAddress(maddr)
194
- }
195
-
191
// when not online, don't need to parse private keys (yet)
192
if online {
193
skb, err := base64.StdEncoding.DecodeString(cfg.Identity.PrivKey)
@@ -233,3 +228,18 @@ func initConnections(ctx context.Context, cfg *config.Config, pstore peer.Peerst
228
}
229
}
230
}
231
+
232
+func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
233
+ var listen []ma.Multiaddr
234
+
235
+ if len(cfg.Addresses.Swarm) > 0 {
236
+ maddr, err := ma.NewMultiaddr(cfg.Addresses.Swarm)
237
+ if err != nil {
238
+ return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm: %s", cfg.Addresses.Swarm)
239
+ }
240
+
241
+ listen = append(listen, maddr)
242
+ }
243
+
244
+ return listen, nil
245
+}
net/interface.go
+10
@@ -6,6 +6,8 @@ import (
6
srv "github.com/jbenet/go-ipfs/net/service"
7
peer "github.com/jbenet/go-ipfs/peer"
8
ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
9
+
10
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
11
)
12
13
// Network is the interface IPFS uses for connecting to the world.
@@ -37,6 +39,14 @@ type Network interface {
39
40
// SendMessage sends given Message out
41
SendMessage(msg.NetMessage) error
42
+
43
+ // ListenAddresses returns a list of addresses at which this network listens.
44
+ ListenAddresses() []ma.Multiaddr
45
+
46
+ // InterfaceListenAddresses returns a list of addresses at which this network
47
+ // listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
48
+ // use the known local interfaces.
49
+ InterfaceListenAddresses() ([]ma.Multiaddr, error)
50
}
51
52
// Sender interface for network services.
net/net.go
+15
-2
@@ -8,6 +8,7 @@ import (
8
ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
9
10
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
11
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12
)
13
14
// IpfsNetwork implements the Network interface,
@@ -27,7 +28,7 @@ type IpfsNetwork struct {
28
}
29
30
// NewIpfsNetwork is the structure that implements the network interface
30
-func NewIpfsNetwork(ctx context.Context, local peer.Peer,
31
+func NewIpfsNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.Peer,
32
peers peer.Peerstore, pmap *mux.ProtocolMap) (*IpfsNetwork, error) {
33
34
in := &IpfsNetwork{
@@ -37,7 +38,7 @@ func NewIpfsNetwork(ctx context.Context, local peer.Peer,
38
}
39
40
var err error
40
- in.swarm, err = swarm.NewSwarm(ctx, local, peers)
41
+ in.swarm, err = swarm.NewSwarm(ctx, listen, local, peers)
42
if err != nil {
43
in.Close()
44
return nil, err
@@ -96,3 +97,15 @@ func (n *IpfsNetwork) GetPeerList() []peer.Peer {
97
func (n *IpfsNetwork) GetBandwidthTotals() (in uint64, out uint64) {
98
return n.muxer.GetBandwidthTotals()
99
}
100
+
101
+// ListenAddresses returns a list of addresses at which this network listens.
102
+func (n *IpfsNetwork) ListenAddresses() []ma.Multiaddr {
103
+ return n.swarm.ListenAddresses()
104
+}
105
+
106
+// InterfaceListenAddresses returns a list of addresses at which this network
107
+// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
108
+// use the known local interfaces.
109
+func (n *IpfsNetwork) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
110
+ return n.swarm.InterfaceListenAddresses()
111
+}
net/swarm/addrs.go
new
+74
@@ -0,0 +1,74 @@
1
+package swarm
2
+
3
+import (
4
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
5
+
6
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7
+)
8
+
9
+// ListenAddresses returns a list of addresses at which this swarm listens.
10
+func (s *Swarm) ListenAddresses() []ma.Multiaddr {
11
+ addrs := make([]ma.Multiaddr, len(s.listeners))
12
+ for i, l := range s.listeners {
13
+ addrs[i] = l.Multiaddr()
14
+ }
15
+ return addrs
16
+}
17
+
18
+// InterfaceListenAddresses returns a list of addresses at which this swarm
19
+// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
20
+// use the known local interfaces.
21
+func (s *Swarm) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
22
+ return resolveUnspecifiedAddresses(s.ListenAddresses())
23
+}
24
+
25
+// resolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
26
+// use the known local interfaces.
27
+func resolveUnspecifiedAddresses(unspecifiedAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
28
+ var outputAddrs []ma.Multiaddr
29
+
30
+ // todo optimize: only fetch these if we have a "any" addr.
31
+ ifaceAddrs, err := interfaceAddresses()
32
+ if err != nil {
33
+ return nil, err
34
+ }
35
+
36
+ for _, a := range unspecifiedAddrs {
37
+
38
+ // split address into its components
39
+ split := ma.Split(a)
40
+
41
+ // if first component (ip) is not unspecified, use it as is.
42
+ if !manet.IsIPUnspecified(split[0]) {
43
+ outputAddrs = append(outputAddrs)
44
+ continue
45
+ }
46
+
47
+ // unspecified? add one address per interface.
48
+ for _, ia := range ifaceAddrs {
49
+ split[0] = ia
50
+ joined := ma.Join(split...)
51
+ outputAddrs = append(outputAddrs, joined)
52
+ }
53
+ }
54
+
55
+ log.Info("InterfaceListenAddresses:", outputAddrs)
56
+ return outputAddrs, nil
57
+}
58
+
59
+// interfaceAddresses returns a list of addresses associated with local machine
60
+func interfaceAddresses() ([]ma.Multiaddr, error) {
61
+ maddrs, err := manet.InterfaceMultiaddrs()
62
+ if err != nil {
63
+ return nil, err
64
+ }
65
+
66
+ var nonLoopback []ma.Multiaddr
67
+ for _, a := range maddrs {
68
+ if !manet.IsIPLoopback(a) {
69
+ nonLoopback = append(nonLoopback, a)
70
+ }
71
+ }
72
+
73
+ return nonLoopback, nil
74
+}
net/swarm/conn.go
+13
-3
@@ -12,14 +12,14 @@ import (
12
)
13
14
// Open listeners for each network the swarm should listen on
15
-func (s *Swarm) listen() error {
15
+func (s *Swarm) listen(addrs []ma.Multiaddr) error {
16
hasErr := false
17
retErr := &ListenErr{
18
- Errors: make([]error, len(s.local.Addresses())),
18
+ Errors: make([]error, len(addrs)),
19
}
20
21
// listen on every address
22
- for i, addr := range s.local.Addresses() {
22
+ for i, addr := range addrs {
23
err := s.connListen(addr)
24
if err != nil {
25
hasErr = true
@@ -37,11 +37,21 @@ func (s *Swarm) listen() error {
37
// Listen for new connections on the given multiaddr
38
func (s *Swarm) connListen(maddr ma.Multiaddr) error {
39
40
+ resolved, err := resolveUnspecifiedAddresses([]ma.Multiaddr{maddr})
41
+ if err != nil {
42
+ return err
43
+ }
44
+
45
list, err := conn.Listen(s.Context(), maddr, s.local, s.peers)
46
if err != nil {
47
return err
48
}
49
50
+ // add resolved local addresses to peer
51
+ for _, addr := range resolved {
52
+ s.local.AddAddress(addr)
53
+ }
54
+
55
// make sure port can be reused. TOOD this doesn't work...
56
// if err := setSocketReuse(list); err != nil {
57
// return err
net/swarm/swarm.go
+3
-5
@@ -13,6 +13,7 @@ import (
13
ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
14
15
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
16
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17
)
18
19
var log = u.Logger("swarm")
@@ -70,7 +71,7 @@ type Swarm struct {
71
}
72
73
// NewSwarm constructs a Swarm, with a Chan.
73
-func NewSwarm(ctx context.Context, local peer.Peer, ps peer.Peerstore) (*Swarm, error) {
74
+func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr, local peer.Peer, ps peer.Peerstore) (*Swarm, error) {
75
s := &Swarm{
76
Pipe: msg.NewPipe(10),
77
conns: conn.MultiConnMap{},
@@ -83,7 +84,7 @@ func NewSwarm(ctx context.Context, local peer.Peer, ps peer.Peerstore) (*Swarm,
84
s.ContextCloser = ctxc.NewContextCloser(ctx, s.close)
85
86
go s.fanOut()
86
- return s, s.listen()
87
+ return s, s.listen(listenAddrs)
88
}
89
90
// close stops a swarm. It's the underlying function called by ContextCloser
@@ -210,6 +211,3 @@ func (s *Swarm) GetPeerList() []peer.Peer {
211
s.connsLock.RUnlock()
212
return out
213
}
213
-
214
-// Temporary to ensure that the Swarm always matches the Network interface as we are changing it
215
-// var _ Network = &Swarm{}
net/swarm/swarm_test.go
+1
-1
@@ -57,7 +57,7 @@ func makeSwarms(ctx context.Context, t *testing.T, addrs []string) ([]*Swarm, []
57
for _, addr := range addrs {
58
local := setupPeer(t, addr)
59
peerstore := peer.NewPeerstore()
60
- swarm, err := NewSwarm(ctx, local, peerstore)
60
+ swarm, err := NewSwarm(ctx, local.Addresses(), local, peerstore)
61
if err != nil {
62
t.Fatal(err)
63
}
routing/dht/dht_test.go
+1
-1
@@ -24,7 +24,7 @@ func setupDHT(ctx context.Context, t *testing.T, p peer.Peer) *IpfsDHT {
24
peerstore := peer.NewPeerstore()
25
26
dhts := netservice.NewService(ctx, nil) // nil handler for now, need to patch it
27
- net, err := inet.NewIpfsNetwork(ctx, p, peerstore, &mux.ProtocolMap{
27
+ net, err := inet.NewIpfsNetwork(ctx, p.Addresses(), p, peerstore, &mux.ProtocolMap{
28
mux.ProtocolID_Routing: dhts,
29
})
30
if err != nil {