@cryptotaxi247 / kubo / commits / a037ae6c9

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