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  }