/
transport.go
132 lines (110 loc) · 4.43 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
package mc
import (
"context"
"fmt"
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"
"github.com/pkg/errors"
"go.uber.org/zap"
mcdrv "berty.tech/berty/v2/go/internal/multipeer-connectivity-transport/driver"
mcma "berty.tech/berty/v2/go/internal/multipeer-connectivity-transport/multiaddr"
)
const DefaultBind = "/mc/Qmeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
// logger is global because HandleFoundPeer must be able to call it
// FIXME: remove global logger
var logger *zap.Logger = zap.NewNop()
// Transport is a tpt.transport.
var _ tpt.Transport = &ProximityTransport{}
// 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
ctx context.Context
}
func ProximityTransportConstructor(ctx context.Context, l *zap.Logger) func(h host.Host, u *tptu.Upgrader) (*ProximityTransport, error) {
if l != nil {
logger = l.Named("ProximityTransport")
}
return func(h host.Host, u *tptu.Upgrader) (*ProximityTransport, error) {
logger.Debug("ProximityTransportConstructor()")
return &ProximityTransport{
host: h,
upgrader: u,
ctx: ctx,
}, 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.
gLock.RLock()
defer gLock.RUnlock()
if gListener == nil {
return nil, errors.New("proximityTransport: ProximityTransport.Dial: no active listener")
}
// remoteAddr is supposed to be equal to remotePID since with proximity transports:
// multiaddr = /<protocol>/<peerID>
remoteAddr, err := remoteMa.ValueForProtocol(mcma.P_MC)
if err != nil || remoteAddr != remotePID.Pretty() {
return nil, errors.Wrap(err, "proximityTransport: 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 !mcdrv.DialPeer(remoteAddr) {
return nil, errors.New("proximityTransport: ProximityTransport.Dial: peer not connected through the native driver")
}
// Can't have two connections on the same multiaddr
if _, ok := connMap.Load(remoteAddr); ok {
return nil, errors.New("proximityTransport: 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 {
return mcma.MC.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 DefaultBind since multiaddr == /<protocol>/<peerID>
localPID := t.host.ID().Pretty()
localAddr, err := localMa.ValueForProtocol(mcma.P_MC)
if err != nil || (localMa.String() != DefaultBind && localAddr != localPID) {
return nil, errors.Wrap(err, "proximityTransport: ProximityTransport.Listen: wrong multiaddr")
}
// Replaces default bind by local host peerID
if localMa.String() == DefaultBind {
localMa, err = ma.NewMultiaddr(fmt.Sprintf("/mc/%s", localPID))
if err != nil { // Should never append.
panic(err)
}
}
// If a global listener already exists, returns an error.
gLock.RLock()
if gListener != nil {
gLock.RUnlock()
return nil, errors.New("proximityTransport: ProximityTransport.Listen: one listener maximum")
}
gLock.RUnlock()
return newListener(t.ctx, localMa, t), nil
}
// 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{mcma.P_MC}
}
func (t *ProximityTransport) String() string {
return "MC"
}