-
Notifications
You must be signed in to change notification settings - Fork 377
/
transport.go
151 lines (125 loc) · 4.79 KB
/
transport.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package proximitytransport
import (
"context"
"fmt"
"sync"
host "github.com/libp2p/go-libp2p-core/host"
peer "github.com/libp2p/go-libp2p-core/peer"
tpt "github.com/libp2p/go-libp2p-core/transport"
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
ma "github.com/multiformats/go-multiaddr"
mafmt "github.com/multiformats/go-multiaddr-fmt"
"github.com/pkg/errors"
"go.uber.org/zap"
)
// Transport is a tpt.transport.
var _ tpt.Transport = &ProximityTransport{}
// TransportMap keeps tracks of existing Transport to prevent multiple utilizations
var TransportMap sync.Map
// ProximityTransport represents any device by which you can connect to and accept
// connections from other peers.
type ProximityTransport struct {
host host.Host
upgrader *tptu.Upgrader
connMap sync.Map
lock sync.RWMutex
listener *Listener
driver NativeDriver
logger *zap.Logger
ctx context.Context
}
func NewTransport(ctx context.Context, l *zap.Logger, driver NativeDriver) func(h host.Host, u *tptu.Upgrader) (*ProximityTransport, error) {
l = l.Named("ProximityTransport")
if driver == nil {
l.Error("error: NewTransport: driver is nil")
driver = &NoopNativeDriver{}
}
return func(h host.Host, u *tptu.Upgrader) (*ProximityTransport, error) {
l.Debug("NewTransport()")
transport := &ProximityTransport{
host: h,
upgrader: u,
driver: driver,
logger: l,
ctx: ctx,
}
return transport, nil
}
}
// Dial dials the peer at the remote address.
// With proximity connections (e.g. MC, BLE, Nearby) you can only dial a device that is already connected with the native driver.
func (t *ProximityTransport) Dial(ctx context.Context, remoteMa ma.Multiaddr, remotePID peer.ID) (tpt.CapableConn, error) {
// ProximityTransport needs to have a running listener in order to dial other peer
// because native driver is initialized during listener creation.
t.lock.RLock()
defer t.lock.RUnlock()
if t.listener == nil {
return nil, errors.New("error: ProximityTransport.Dial: no active listener")
}
// remoteAddr is supposed to be equal to remotePID since with proximity transports:
// multiaddr = /<protocol>/<peerID>
remoteAddr, err := remoteMa.ValueForProtocol(t.driver.ProtocolCode())
if err != nil || remoteAddr != remotePID.Pretty() {
return nil, errors.Wrap(err, "error: ProximityTransport.Dial: wrong multiaddr")
}
// Check if native driver is already connected to peer's device.
// With proximity connections you can't really dial, only auto-connect with peer nearby.
if !t.driver.DialPeer(remoteAddr) {
return nil, errors.New("error: ProximityTransport.Dial: peer not connected through the native driver")
}
// Can't have two connections on the same multiaddr
if _, ok := t.connMap.Load(remoteAddr); ok {
return nil, errors.New("error: ProximityTransport.Dial: already connected to this address")
}
// Returns an outbound conn.
return newConn(ctx, t, remoteMa, remotePID, false)
}
// CanDial returns true if this transport believes it can dial the given
// multiaddr.
func (t *ProximityTransport) CanDial(remoteMa ma.Multiaddr) bool {
// multiaddr validation checker
return mafmt.Base(t.driver.ProtocolCode()).Matches(remoteMa)
}
// Listen listens on the given multiaddr.
// Proximity connections can't listen on more than one listener.
func (t *ProximityTransport) Listen(localMa ma.Multiaddr) (tpt.Listener, error) {
// localAddr is supposed to be equal to the localPID
// or to DefaultAddr since multiaddr == /<protocol>/<peerID>
localPID := t.host.ID().Pretty()
localAddr, err := localMa.ValueForProtocol(t.driver.ProtocolCode())
if err != nil || (localMa.String() != t.driver.DefaultAddr() && localAddr != localPID) {
return nil, errors.Wrap(err, "error: ProximityTransport.Listen: wrong multiaddr")
}
// Replaces default bind by local host peerID
if localMa.String() == t.driver.DefaultAddr() {
localMa, err = ma.NewMultiaddr(fmt.Sprintf("/%s/%s", t.driver.ProtocolName(), localPID))
if err != nil { // Should never append.
panic(err)
}
}
t.lock.RLock()
// If the a listener already exists for this driver, returns an error.
_, ok := TransportMap.Load(t.driver.ProtocolName())
if ok || t.listener != nil {
t.lock.RUnlock()
return nil, errors.New("error: ProximityTransport.Listen: one listener maximum")
}
t.lock.RUnlock()
// Register this transport
TransportMap.Store(t.driver.ProtocolName(), t)
t.lock.Lock()
defer t.lock.Unlock()
t.listener = newListener(t.ctx, localMa, t)
return t.listener, err
}
// Proxy returns true if this transport proxies.
func (t *ProximityTransport) Proxy() bool {
return false
}
// Protocols returns the set of protocols handled by this transport.
func (t *ProximityTransport) Protocols() []int {
return []int{t.driver.ProtocolCode()}
}
func (t *ProximityTransport) String() string {
return t.driver.ProtocolName()
}