github.com/uber/kraken@v0.1.4/lib/torrent/scheduler/conn/handshaker.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package conn 15 16 import ( 17 "errors" 18 "fmt" 19 "net" 20 21 "github.com/uber/kraken/core" 22 "github.com/uber/kraken/gen/go/proto/p2p" 23 "github.com/uber/kraken/lib/torrent/networkevent" 24 "github.com/uber/kraken/lib/torrent/storage" 25 "github.com/uber/kraken/utils/bandwidth" 26 27 "github.com/andres-erbsen/clock" 28 "github.com/uber-go/tally" 29 "github.com/willf/bitset" 30 "go.uber.org/zap" 31 ) 32 33 // RemoteBitfields represents the bitfields of an agent's peers for a given torrent. 34 type RemoteBitfields map[core.PeerID]*bitset.BitSet 35 36 func (rb RemoteBitfields) marshalBinary() (map[string][]byte, error) { 37 rbBytes := make(map[string][]byte) 38 for peerID, bitfield := range rb { 39 b, err := bitfield.MarshalBinary() 40 if err != nil { 41 return nil, err 42 } 43 rbBytes[peerID.String()] = b 44 } 45 return rbBytes, nil 46 } 47 48 func (rb RemoteBitfields) unmarshalBinary(rbBytes map[string][]byte) error { 49 for peerIDStr, bitfieldBytes := range rbBytes { 50 peerID, err := core.NewPeerID(peerIDStr) 51 if err != nil { 52 return fmt.Errorf("peer id: %s", err) 53 } 54 bitfield := bitset.New(0) 55 if err := bitfield.UnmarshalBinary(bitfieldBytes); err != nil { 56 return err 57 } 58 rb[peerID] = bitfield 59 } 60 return nil 61 } 62 63 // handshake contains the same fields as a protobuf bitfield message, but with 64 // the fields converted into types used within the scheduler package. As such, 65 // in this package "handshake" and "bitfield message" are usually synonymous. 66 type handshake struct { 67 peerID core.PeerID 68 digest core.Digest 69 infoHash core.InfoHash 70 bitfield *bitset.BitSet 71 remoteBitfields RemoteBitfields 72 namespace string 73 } 74 75 func (h *handshake) toP2PMessage() (*p2p.Message, error) { 76 b, err := h.bitfield.MarshalBinary() 77 if err != nil { 78 return nil, err 79 } 80 rb, err := h.remoteBitfields.marshalBinary() 81 if err != nil { 82 return nil, err 83 } 84 return &p2p.Message{ 85 Type: p2p.Message_BITFIELD, 86 Bitfield: &p2p.BitfieldMessage{ 87 PeerID: h.peerID.String(), 88 Name: h.digest.Hex(), 89 InfoHash: h.infoHash.String(), 90 BitfieldBytes: b, 91 RemoteBitfieldBytes: rb, 92 Namespace: h.namespace, 93 }, 94 }, nil 95 } 96 97 func handshakeFromP2PMessage(m *p2p.Message) (*handshake, error) { 98 if m.Type != p2p.Message_BITFIELD { 99 return nil, fmt.Errorf("expected bitfield message, got %s", m.Type) 100 } 101 peerID, err := core.NewPeerID(m.Bitfield.PeerID) 102 if err != nil { 103 return nil, fmt.Errorf("peer id: %s", err) 104 } 105 ih, err := core.NewInfoHashFromHex(m.Bitfield.InfoHash) 106 if err != nil { 107 return nil, fmt.Errorf("info hash: %s", err) 108 } 109 d, err := core.NewSHA256DigestFromHex(m.Bitfield.Name) 110 if err != nil { 111 return nil, fmt.Errorf("name: %s", err) 112 } 113 bitfield := bitset.New(0) 114 if err := bitfield.UnmarshalBinary(m.Bitfield.BitfieldBytes); err != nil { 115 return nil, err 116 } 117 remoteBitfields := make(RemoteBitfields) 118 if err := remoteBitfields.unmarshalBinary(m.Bitfield.RemoteBitfieldBytes); err != nil { 119 return nil, err 120 } 121 122 return &handshake{ 123 peerID: peerID, 124 infoHash: ih, 125 bitfield: bitfield, 126 digest: d, 127 namespace: m.Bitfield.Namespace, 128 remoteBitfields: remoteBitfields, 129 }, nil 130 } 131 132 // PendingConn represents half-opened, pending connection initialized by a 133 // remote peer. 134 type PendingConn struct { 135 handshake *handshake 136 nc net.Conn 137 } 138 139 // PeerID returns the remote peer id. 140 func (pc *PendingConn) PeerID() core.PeerID { 141 return pc.handshake.peerID 142 } 143 144 // Digest returns the digest of the blob the remote peer wants to open. 145 func (pc *PendingConn) Digest() core.Digest { 146 return pc.handshake.digest 147 } 148 149 // InfoHash returns the info hash of the torrent the remote peer wants to open. 150 func (pc *PendingConn) InfoHash() core.InfoHash { 151 return pc.handshake.infoHash 152 } 153 154 // Bitfield returns the bitfield of the remote peer's torrent. 155 func (pc *PendingConn) Bitfield() *bitset.BitSet { 156 return pc.handshake.bitfield 157 } 158 159 // RemoteBitfields returns the bitfield of the remote peer's torrent. 160 func (pc *PendingConn) RemoteBitfields() RemoteBitfields { 161 return pc.handshake.remoteBitfields 162 } 163 164 // Namespace returns the namespace of the remote peer's torrent. 165 func (pc *PendingConn) Namespace() string { 166 return pc.handshake.namespace 167 } 168 169 // Close closes the connection. 170 func (pc *PendingConn) Close() { 171 pc.nc.Close() 172 } 173 174 // HandshakeResult wraps data returned from a successful handshake. 175 type HandshakeResult struct { 176 Conn *Conn 177 Bitfield *bitset.BitSet 178 RemoteBitfields RemoteBitfields 179 } 180 181 // Handshaker defines the handshake protocol for establishing connections to 182 // other peers. 183 type Handshaker struct { 184 config Config 185 stats tally.Scope 186 clk clock.Clock 187 bandwidth *bandwidth.Limiter 188 networkEvents networkevent.Producer 189 peerID core.PeerID 190 events Events 191 } 192 193 // NewHandshaker creates a new Handshaker. 194 func NewHandshaker( 195 config Config, 196 stats tally.Scope, 197 clk clock.Clock, 198 networkEvents networkevent.Producer, 199 peerID core.PeerID, 200 events Events, 201 logger *zap.SugaredLogger) (*Handshaker, error) { 202 203 config = config.applyDefaults() 204 205 stats = stats.Tagged(map[string]string{ 206 "module": "conn", 207 }) 208 209 bl, err := bandwidth.NewLimiter(config.Bandwidth, bandwidth.WithLogger(logger)) 210 if err != nil { 211 return nil, fmt.Errorf("bandwidth: %s", err) 212 } 213 214 return &Handshaker{ 215 config: config, 216 stats: stats, 217 clk: clk, 218 bandwidth: bl, 219 networkEvents: networkEvents, 220 peerID: peerID, 221 events: events, 222 }, nil 223 } 224 225 // Accept upgrades a raw network connection opened by a remote peer into a 226 // PendingConn. 227 func (h *Handshaker) Accept(nc net.Conn) (*PendingConn, error) { 228 hs, err := h.readHandshake(nc) 229 if err != nil { 230 return nil, fmt.Errorf("read handshake: %s", err) 231 } 232 return &PendingConn{hs, nc}, nil 233 } 234 235 // Establish upgrades a PendingConn returned via Accept into a fully 236 // established Conn. 237 func (h *Handshaker) Establish( 238 pc *PendingConn, 239 info *storage.TorrentInfo, 240 remoteBitfields RemoteBitfields) (*Conn, error) { 241 242 // Namespace is one-directional: it is only supplied by the connection opener 243 // and is not reciprocated by the connection acceptor. 244 if err := h.sendHandshake(pc.nc, info, remoteBitfields, ""); err != nil { 245 return nil, fmt.Errorf("send handshake: %s", err) 246 } 247 c, err := h.newConn(pc.nc, pc.handshake.peerID, info, true) 248 if err != nil { 249 return nil, fmt.Errorf("new conn: %s", err) 250 } 251 return c, nil 252 } 253 254 // Initialize returns a fully established Conn for the given torrent to the 255 // given peer / address. Also returns the bitfield of the remote peer and 256 // its connections for the torrent. 257 func (h *Handshaker) Initialize( 258 peerID core.PeerID, 259 addr string, 260 info *storage.TorrentInfo, 261 remoteBitfields RemoteBitfields, 262 namespace string) (*HandshakeResult, error) { 263 264 nc, err := net.DialTimeout("tcp", addr, h.config.HandshakeTimeout) 265 if err != nil { 266 return nil, fmt.Errorf("dial: %s", err) 267 } 268 r, err := h.fullHandshake(nc, peerID, info, remoteBitfields, namespace) 269 if err != nil { 270 nc.Close() 271 return nil, err 272 } 273 return r, nil 274 } 275 276 func (h *Handshaker) sendHandshake( 277 nc net.Conn, 278 info *storage.TorrentInfo, 279 remoteBitfields RemoteBitfields, 280 namespace string) error { 281 282 hs := &handshake{ 283 peerID: h.peerID, 284 digest: info.Digest(), 285 infoHash: info.InfoHash(), 286 bitfield: info.Bitfield(), 287 remoteBitfields: remoteBitfields, 288 namespace: namespace, 289 } 290 msg, err := hs.toP2PMessage() 291 if err != nil { 292 return err 293 } 294 return sendMessageWithTimeout(nc, msg, h.config.HandshakeTimeout) 295 } 296 297 func (h *Handshaker) readHandshake(nc net.Conn) (*handshake, error) { 298 m, err := readMessageWithTimeout(nc, h.config.HandshakeTimeout) 299 if err != nil { 300 return nil, fmt.Errorf("read message: %s", err) 301 } 302 hs, err := handshakeFromP2PMessage(m) 303 if err != nil { 304 return nil, fmt.Errorf("handshake from p2p message: %s", err) 305 } 306 return hs, nil 307 } 308 309 func (h *Handshaker) fullHandshake( 310 nc net.Conn, 311 peerID core.PeerID, 312 info *storage.TorrentInfo, 313 remoteBitfields RemoteBitfields, 314 namespace string) (*HandshakeResult, error) { 315 316 if err := h.sendHandshake(nc, info, remoteBitfields, namespace); err != nil { 317 return nil, fmt.Errorf("send handshake: %s", err) 318 } 319 hs, err := h.readHandshake(nc) 320 if err != nil { 321 return nil, fmt.Errorf("read handshake: %s", err) 322 } 323 if hs.peerID != peerID { 324 return nil, errors.New("unexpected peer id") 325 } 326 c, err := h.newConn(nc, peerID, info, false) 327 if err != nil { 328 return nil, fmt.Errorf("new conn: %s", err) 329 } 330 return &HandshakeResult{c, hs.bitfield, hs.remoteBitfields}, nil 331 } 332 333 func (h *Handshaker) newConn( 334 nc net.Conn, 335 peerID core.PeerID, 336 info *storage.TorrentInfo, 337 openedByRemote bool) (*Conn, error) { 338 339 return newConn( 340 h.config, 341 h.stats, 342 h.clk, 343 h.networkEvents, 344 h.bandwidth, 345 h.events, 346 nc, 347 h.peerID, 348 peerID, 349 info, 350 openedByRemote, 351 zap.NewNop().Sugar()) 352 }