p2p: cleanup listening logic, make dial act like ssh -L
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Apr 6, 2018 at 16:11 UTC
a037ae6c93a5bafb63002e6ce0b7866bb48169e6
5 files changed
+213
-242
core/commands/p2p.go
+7
-7
@@ -105,8 +105,8 @@ var p2pListenerLsCmd = &cmds.Command{
105
106
for _, listener := range n.P2P.Listeners.Listeners {
107
output.Listeners = append(output.Listeners, P2PListenerInfoOutput{
108
- Protocol: listener.Protocol,
109
- Address: listener.Address.String(),
108
+ Protocol: listener.Protocol(),
109
+ Address: listener.Address(),
110
})
111
}
112
@@ -267,7 +267,7 @@ can transparently connect to a p2p service.
267
return
268
}
269
270
- addr, peer, err := ParsePeerParam(req.Arguments()[0])
270
+ _, peer, err := ParsePeerParam(req.Arguments()[0])
271
if err != nil {
272
res.SetError(err, cmdkit.ErrNormal)
273
return
@@ -284,15 +284,15 @@ can transparently connect to a p2p service.
284
}
285
}
286
287
- listenerInfo, err := n.P2P.Dial(n.Context(), addr, peer, proto, bindAddr)
287
+ listenerInfo, err := n.P2P.Dial(n.Context(), peer, proto, bindAddr)
288
if err != nil {
289
res.SetError(err, cmdkit.ErrNormal)
290
return
291
}
292
293
output := P2PListenerInfoOutput{
294
- Protocol: listenerInfo.Protocol,
295
- Address: listenerInfo.Address.String(),
294
+ Protocol: listenerInfo.Protocol(),
295
+ Address: listenerInfo.Address(),
296
}
297
298
res.SetOutput(&output)
@@ -331,7 +331,7 @@ var p2pListenerCloseCmd = &cmds.Command{
331
}
332
333
for _, listener := range n.P2P.Listeners.Listeners {
334
- if !closeAll && listener.Protocol != proto {
334
+ if !closeAll && listener.Protocol() != proto {
335
continue
336
}
337
listener.Close()
p2p/inbound.go
new
+70
@@ -0,0 +1,70 @@
1
+package p2p
2
+
3
+import (
4
+ "context"
5
+
6
+ ma "gx/ipfs/QmWWQ2Txc2c6tqjsBpzg5Ar652cHPGNsQQp2SejkNmkUMb/go-multiaddr"
7
+ net "gx/ipfs/QmYj8wdn5sZEHX2XMDWGBvcXJNdzVbaVpHmXvhHBVZepen/go-libp2p-net"
8
+ protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
9
+ manet "gx/ipfs/QmcGXGdw9BWDysPJQHxJinjGHha3eEg4vzFETre4woNwcX/go-multiaddr-net"
10
+)
11
+
12
+// inboundListener accepts libp2p streams and proxies them to a manet host
13
+type inboundListener struct {
14
+ p2p *P2P
15
+
16
+ // Application proto identifier.
17
+ proto string
18
+
19
+ addr ma.Multiaddr
20
+}
21
+
22
+// NewListener creates new p2p listener
23
+func (p2p *P2P) NewListener(ctx context.Context, proto string, addr ma.Multiaddr) (Listener, error) {
24
+ listenerInfo := &inboundListener{
25
+ proto: proto,
26
+ }
27
+
28
+ p2p.peerHost.SetStreamHandler(protocol.ID(proto), func(remote net.Stream) {
29
+ local, err := manet.Dial(addr)
30
+ if err != nil {
31
+ remote.Reset()
32
+ return
33
+ }
34
+
35
+ stream := StreamInfo{
36
+ Protocol: proto,
37
+
38
+ LocalPeer: p2p.identity,
39
+ LocalAddr: addr,
40
+
41
+ RemotePeer: remote.Conn().RemotePeer(),
42
+ RemoteAddr: remote.Conn().RemoteMultiaddr(),
43
+
44
+ Local: local,
45
+ Remote: remote,
46
+
47
+ Registry: &p2p.Streams,
48
+ }
49
+
50
+ p2p.Streams.Register(&stream)
51
+ stream.startStreaming()
52
+ })
53
+
54
+ p2p.Listeners.Register(listenerInfo)
55
+
56
+ return listenerInfo, nil
57
+}
58
+
59
+func (l *inboundListener) Protocol() string {
60
+ return l.proto
61
+}
62
+
63
+func (l *inboundListener) Address() string {
64
+ return l.addr.String()
65
+}
66
+
67
+func (l *inboundListener) Close() error {
68
+ l.p2p.peerHost.RemoveStreamHandler(protocol.ID(l.proto))
69
+ return l.p2p.Listeners.Deregister(l.proto)
70
+}
p2p/outbound.go
new
+119
@@ -0,0 +1,119 @@
1
+package p2p
2
+
3
+import (
4
+ "context"
5
+ "errors"
6
+ "time"
7
+
8
+ ma "gx/ipfs/QmWWQ2Txc2c6tqjsBpzg5Ar652cHPGNsQQp2SejkNmkUMb/go-multiaddr"
9
+ net "gx/ipfs/QmYj8wdn5sZEHX2XMDWGBvcXJNdzVbaVpHmXvhHBVZepen/go-libp2p-net"
10
+ protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
11
+ pstore "gx/ipfs/QmZb7hAgQEhW9dBbzBudU39gCeD4zbe6xafD52LUuF4cUN/go-libp2p-peerstore"
12
+ manet "gx/ipfs/QmcGXGdw9BWDysPJQHxJinjGHha3eEg4vzFETre4woNwcX/go-multiaddr-net"
13
+ peer "gx/ipfs/QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74/go-libp2p-peer"
14
+)
15
+
16
+// inboundListener accepts libp2p streams and proxies them to a manet host
17
+type outboundListener struct {
18
+ ctx context.Context
19
+ cancel context.CancelFunc
20
+
21
+ p2p *P2P
22
+ id peer.ID
23
+
24
+ proto string
25
+ peer peer.ID
26
+
27
+ listener manet.Listener
28
+}
29
+
30
+// Dial creates new P2P stream to a remote listener
31
+func (p2p *P2P) Dial(ctx context.Context, peer peer.ID, proto string, bindAddr ma.Multiaddr) (Listener, error) {
32
+ lnet, _, err := manet.DialArgs(bindAddr)
33
+ if err != nil {
34
+ return nil, err
35
+ }
36
+
37
+ switch lnet {
38
+ case "tcp", "tcp4", "tcp6":
39
+ maListener, err := manet.Listen(bindAddr)
40
+ if err != nil {
41
+ return nil, err
42
+ }
43
+
44
+ listener := &outboundListener{
45
+ p2p: p2p,
46
+ id: p2p.identity,
47
+
48
+ proto: proto,
49
+ peer: peer,
50
+
51
+ listener: maListener,
52
+ }
53
+
54
+ go listener.acceptConns()
55
+
56
+ return listener, nil
57
+ default:
58
+ return nil, errors.New("unsupported proto: " + lnet)
59
+ }
60
+}
61
+
62
+func (l *outboundListener) dial() (net.Stream, error) {
63
+ ctx, cancel := context.WithTimeout(l.ctx, time.Second*30) //TODO: configurable?
64
+ defer cancel()
65
+
66
+ err := l.p2p.peerHost.Connect(ctx, pstore.PeerInfo{ID: l.peer})
67
+ if err != nil {
68
+ return nil, err
69
+ }
70
+
71
+ return l.p2p.peerHost.NewStream(l.ctx, l.peer, protocol.ID(l.proto))
72
+}
73
+
74
+func (l *outboundListener) acceptConns() {
75
+ for {
76
+ local, err := l.listener.Accept()
77
+ if err != nil {
78
+ return
79
+ }
80
+
81
+ remote, err := l.dial()
82
+ if err != nil {
83
+ local.Close()
84
+ return
85
+ }
86
+
87
+ stream := StreamInfo{
88
+ Protocol: l.proto,
89
+
90
+ LocalPeer: l.id,
91
+ LocalAddr: l.listener.Multiaddr(),
92
+
93
+ RemotePeer: remote.Conn().RemotePeer(),
94
+ RemoteAddr: remote.Conn().RemoteMultiaddr(),
95
+
96
+ Local: local,
97
+ Remote: remote,
98
+
99
+ Registry: &l.p2p.Streams,
100
+ }
101
+
102
+ l.p2p.Streams.Register(&stream)
103
+ stream.startStreaming()
104
+ }
105
+}
106
+
107
+func (l *outboundListener) Close() error {
108
+ l.listener.Close()
109
+ err := l.p2p.Listeners.Deregister(l.proto)
110
+ return err
111
+}
112
+
113
+func (l *outboundListener) Protocol() string {
114
+ return l.proto
115
+}
116
+
117
+func (l *outboundListener) Address() string {
118
+ return "/ipfs/" + l.peer.String()
119
+}
p2p/p2p.go
+12
-202
@@ -1,17 +1,9 @@
1
package p2p
2
3
import (
4
- "context"
5
- "errors"
6
- "time"
7
-
8
- peer "gx/ipfs/QmQsErDt8Qgw1XrsXf2BpEzDgGWtB1YLsTAARBup5b6B9W/go-libp2p-peer"
9
- manet "gx/ipfs/QmV6FjemM1K8oXjrvuq3wuVWWoU2TLDPmNnKrxHzY3v6Ai/go-multiaddr-net"
10
- ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
11
- net "gx/ipfs/QmZNJyx9GGCX4GeuHnLB8fxaxMLs4MjTjHokxfQcCd6Nve/go-libp2p-net"
12
- pro "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
13
- pstore "gx/ipfs/Qmda4cPRvSRyox3SqgJN6DfSZGU5TtHufPTp9uXjFj71X6/go-libp2p-peerstore"
14
- p2phost "gx/ipfs/QmeMYW7Nj8jnnEfs9qhm7SxKkoDPUWXu3MsxX6BFwz34tf/go-libp2p-host"
4
+ pstore "gx/ipfs/QmZR2XWVVBCtbgBWnQhWk2xcQfaR3W8faQPriAiaaj7rsr/go-libp2p-peerstore"
5
+ p2phost "gx/ipfs/Qmb8T6YBBsjYsVGfrihQLfCJveczZnneSBqBKkYEBWDjge/go-libp2p-host"
6
+ peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer"
7
)
8
9
// P2P structure holds information on currently running streams/listeners
@@ -24,6 +16,14 @@ type P2P struct {
16
peerstore pstore.Peerstore
17
}
18
19
+type Listener interface {
20
+ Protocol() string
21
+ Address() string
22
+
23
+ // Close closes the listener. Does not affect child streams
24
+ Close() error
25
+}
26
+
27
// NewP2P creates new P2P struct
28
func NewP2P(identity peer.ID, peerHost p2phost.Host, peerstore pstore.Peerstore) *P2P {
29
return &P2P{
@@ -33,197 +33,7 @@ func NewP2P(identity peer.ID, peerHost p2phost.Host, peerstore pstore.Peerstore)
33
}
34
}
35
36
-func (p2p *P2P) newStreamTo(ctx2 context.Context, p peer.ID, protocol string) (net.Stream, error) {
37
- ctx, cancel := context.WithTimeout(ctx2, time.Second*30) //TODO: configurable?
38
- defer cancel()
39
- err := p2p.peerHost.Connect(ctx, pstore.PeerInfo{ID: p})
40
- if err != nil {
41
- return nil, err
42
- }
43
- return p2p.peerHost.NewStream(ctx2, p, pro.ID(protocol))
44
-}
45
-
46
-// Dial creates new P2P stream to a remote listener
47
-func (p2p *P2P) Dial(ctx context.Context, addr ma.Multiaddr, peer peer.ID, proto string, bindAddr ma.Multiaddr) (*ListenerInfo, error) {
48
- lnet, _, err := manet.DialArgs(bindAddr)
49
- if err != nil {
50
- return nil, err
51
- }
52
-
53
- listenerInfo := ListenerInfo{
54
- Identity: p2p.identity,
55
- Protocol: proto,
56
- }
57
-
58
- remote, err := p2p.newStreamTo(ctx, peer, proto)
59
- if err != nil {
60
- return nil, err
61
- }
62
-
63
- switch lnet {
64
- case "tcp", "tcp4", "tcp6":
65
- listener, err := manet.Listen(bindAddr)
66
- if err != nil {
67
- if err2 := remote.Reset(); err2 != nil {
68
- return nil, err2
69
- }
70
- return nil, err
71
- }
72
-
73
- listenerInfo.Address = listener.Multiaddr()
74
- listenerInfo.Closer = listener
75
- listenerInfo.Running = true
76
-
77
- go p2p.doAccept(&listenerInfo, remote, listener)
78
-
79
- default:
80
- return nil, errors.New("unsupported protocol: " + lnet)
81
- }
82
-
83
- return &listenerInfo, nil
84
-}
85
-
86
-func (p2p *P2P) doAccept(listenerInfo *ListenerInfo, remote net.Stream, listener manet.Listener) {
87
- defer listener.Close()
88
-
89
- local, err := listener.Accept()
90
- if err != nil {
91
- return
92
- }
93
-
94
- stream := StreamInfo{
95
- Protocol: listenerInfo.Protocol,
96
-
97
- LocalPeer: listenerInfo.Identity,
98
- LocalAddr: listenerInfo.Address,
99
-
100
- RemotePeer: remote.Conn().RemotePeer(),
101
- RemoteAddr: remote.Conn().RemoteMultiaddr(),
102
-
103
- Local: local,
104
- Remote: remote,
105
-
106
- Registry: &p2p.Streams,
107
- }
108
-
109
- p2p.Streams.Register(&stream)
110
- stream.startStreaming()
111
-}
112
-
113
-// Listener wraps stream handler into a listener
114
-type Listener interface {
115
- Accept() (net.Stream, error)
116
- Close() error
117
-}
118
-
119
-// P2PListener holds information on a listener
120
-type P2PListener struct {
121
- peerHost p2phost.Host
122
- conCh chan net.Stream
123
- proto pro.ID
124
- ctx context.Context
125
- cancel func()
126
-}
127
-
128
-// Accept waits for a connection from the listener
129
-func (il *P2PListener) Accept() (net.Stream, error) {
130
- select {
131
- case c := <-il.conCh:
132
- return c, nil
133
- case <-il.ctx.Done():
134
- return nil, il.ctx.Err()
135
- }
136
-}
137
-
138
-// Close closes the listener and removes stream handler
139
-func (il *P2PListener) Close() error {
140
- il.cancel()
141
- il.peerHost.RemoveStreamHandler(il.proto)
142
- return nil
143
-}
144
-
145
-// Listen creates new P2PListener
146
-func (p2p *P2P) registerStreamHandler(ctx2 context.Context, protocol string) (*P2PListener, error) {
147
- ctx, cancel := context.WithCancel(ctx2)
148
-
149
- list := &P2PListener{
150
- peerHost: p2p.peerHost,
151
- proto: pro.ID(protocol),
152
- conCh: make(chan net.Stream),
153
- ctx: ctx,
154
- cancel: cancel,
155
- }
156
-
157
- p2p.peerHost.SetStreamHandler(list.proto, func(s net.Stream) {
158
- select {
159
- case list.conCh <- s:
160
- case <-ctx.Done():
161
- s.Reset()
162
- }
163
- })
164
-
165
- return list, nil
166
-}
167
-
168
-// NewListener creates new p2p listener
169
-func (p2p *P2P) NewListener(ctx context.Context, proto string, addr ma.Multiaddr) (*ListenerInfo, error) {
170
- listener, err := p2p.registerStreamHandler(ctx, proto)
171
- if err != nil {
172
- return nil, err
173
- }
174
-
175
- listenerInfo := ListenerInfo{
176
- Identity: p2p.identity,
177
- Protocol: proto,
178
- Address: addr,
179
- Closer: listener,
180
- Running: true,
181
- Registry: &p2p.Listeners,
182
- }
183
-
184
- go p2p.acceptStreams(&listenerInfo, listener)
185
-
186
- p2p.Listeners.Register(&listenerInfo)
187
-
188
- return &listenerInfo, nil
189
-}
190
-
191
-func (p2p *P2P) acceptStreams(listenerInfo *ListenerInfo, listener Listener) {
192
- for listenerInfo.Running {
193
- remote, err := listener.Accept()
194
- if err != nil {
195
- listener.Close()
196
- break
197
- }
198
-
199
- local, err := manet.Dial(listenerInfo.Address)
200
- if err != nil {
201
- remote.Reset()
202
- continue
203
- }
204
-
205
- stream := StreamInfo{
206
- Protocol: listenerInfo.Protocol,
207
-
208
- LocalPeer: listenerInfo.Identity,
209
- LocalAddr: listenerInfo.Address,
210
-
211
- RemotePeer: remote.Conn().RemotePeer(),
212
- RemoteAddr: remote.Conn().RemoteMultiaddr(),
213
-
214
- Local: local,
215
- Remote: remote,
216
-
217
- Registry: &p2p.Streams,
218
- }
219
-
220
- p2p.Streams.Register(&stream)
221
- stream.startStreaming()
222
- }
223
- p2p.Listeners.Deregister(listenerInfo.Protocol)
224
-}
225
-
226
-// CheckProtoExists checks whether a protocol handler is registered to
36
+// CheckProtoExists checks whether a proto handler is registered to
37
// mux handler
38
func (p2p *P2P) CheckProtoExists(proto string) bool {
39
protos := p2p.peerHost.Mux().Protocols()
p2p/registry.go
+5
-33
@@ -10,41 +10,13 @@ import (
10
net "gx/ipfs/QmZNJyx9GGCX4GeuHnLB8fxaxMLs4MjTjHokxfQcCd6Nve/go-libp2p-net"
11
)
12
13
-// ListenerInfo holds information on a p2p listener.
14
-type ListenerInfo struct {
15
- // Application protocol identifier.
16
- Protocol string
17
-
18
- // Node identity
19
- Identity peer.ID
20
-
21
- // Local protocol stream address.
22
- Address ma.Multiaddr
23
-
24
- // Local protocol stream listener.
25
- Closer io.Closer
26
-
27
- // Flag indicating whether we're still accepting incoming connections, or
28
- // whether this application listener has been shutdown.
29
- Running bool
30
-
31
- Registry *ListenerRegistry
32
-}
33
-
34
-// Close closes the listener. Does not affect child streams
35
-func (c *ListenerInfo) Close() error {
36
- c.Closer.Close()
37
- err := c.Registry.Deregister(c.Protocol)
38
- return err
39
-}
40
-
41
-// ListenerRegistry is a collection of local application protocol listeners.
13
+// ListenerRegistry is a collection of local application proto listeners.
14
type ListenerRegistry struct {
43
- Listeners []*ListenerInfo
15
+ Listeners []Listener
16
}
17
18
// Register registers listenerInfo2 in this registry
47
-func (c *ListenerRegistry) Register(listenerInfo *ListenerInfo) {
19
+func (c *ListenerRegistry) Register(listenerInfo Listener) {
20
c.Listeners = append(c.Listeners, listenerInfo)
21
}
22
@@ -52,7 +24,7 @@ func (c *ListenerRegistry) Register(listenerInfo *ListenerInfo) {
24
func (c *ListenerRegistry) Deregister(proto string) error {
25
foundAt := -1
26
for i, a := range c.Listeners {
55
- if a.Protocol == proto {
27
+ if a.Protocol() == proto {
28
foundAt = i
29
break
30
}
@@ -120,7 +92,7 @@ func (s *StreamInfo) startStreaming() {
92
}()
93
}
94
123
-// StreamRegistry is a collection of active incoming and outgoing protocol app streams.
95
+// StreamRegistry is a collection of active incoming and outgoing proto app streams.
96
type StreamRegistry struct {
97
Streams []*StreamInfo
98