torrent

package
v0.0.0-...-1364d92 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2019 License: MIT Imports: 10 Imported by: 4

Documentation

Index

Constants

View Source
const (
	BindNone = iota
	BindDone = iota
	BindRecv = iota
	BindRun  = iota
)

The Bind states of a peer are:

  • BindNone - the initial state during the bind stage; if the message format is unexpected the state will remain BindNode
  • BindDone - the state which announced that work was done, even though the work is done only for building the peer's connections
  • BindRecv - if the initialization phase is done(i.e. the peer began to build its connection list) and the message can be passed towards a specific Connection based on the sender's ID
  • BindRun - the BindRun state anounced that the phase Tracker sent all the necessary informations so we can finish the initialization phase; when the peer arrives in the BindRun state the function Run is called synchronously

Variables

Functions

This section is empty.

Types

type Binder

type Binder func(m interface{}) int

A Binder is a function which associates a state by using a Peer's internal state and a message m. See Peer's Bind function for more details.

type Choke

type Choke struct{ Id string }

Original BitTorrent protocol message used to notify a node that it has been choked. See the 'Messsage' section for a list with all the types of messages.

type Choker

type Choker interface {
	Interested(conn Upload)
	NotInterested(conn Upload)

	Run()
}

A Choker is a structure which periodically chokes and unchokes connections based on the Tit-for-Tat strategy. When an Upload component is unchoked, the respective upload component is allowed to upload new pieces to other peers. Furthermore, the Choker reacts to Interested and NotInterested notifications arriving from Upload components.

We consider only the rate heuristic used for peers rather than the heuristic used for seeds. That is, we use the connections with the highest upload rate.

We do not model snubbing.

For modelling simplicity, we randomize the optimistics.

Version 5.3.0 uses allocates 30% of the slots to seeds and 70% to other peers.

The seeder will have no upload made to it. The seeder can either:

  • upload to best download rates
  • upload randomly

For the moment our implementation is random.

func NewChoker

func NewChoker(manager Manager, time func() int) Choker

type Components

type Components struct {
	// Internal data structures.
	Picker  Picker
	Storage Storage
	Choker  Choker
	Manager Manager

	// External(simulated) data structures.
	Transport interfaces.Transport
	Time      func() int
}

The Components structure is a container keeping all global data structures associated with a Peer.

type ConnAdder

type ConnAdder func(id string)

A connection adder is a function which should be called when a new peer is added. We only define a separate type for making the peer internals extensible by introducing seams.

type ConnReq

type ConnReq struct {
	Id   string
	Link Link
}

Connection establishment used for a three way handshake. For greater detail on how handshakes work, see the Handshake interface. See the 'Messsage' section for a list with all the types of messages.

type Connector

type Connector struct {
	*Components

	From string
	To   string

	Upload    Upload
	Download  Download
	Handshake Handshake
	// contains filtered or unexported fields
}

The Connector is only an interface towards Upload and Download components. For simplicity at building the Connector is initialized using a builder pattern(with no build intermediary structure).

func NewConnector

func NewConnector(from, to string, components *Components) *Connector

func (*Connector) Recv

func (c *Connector) Recv(m interface{})

The Recv method is called whenever a message is dispached for processing towards the Connector.

func (*Connector) Register

func (c *Connector) Register(p *Peer) *Connector

The Register method is used to bind the Connection to a Peer. The Peer will call this method from `AddConnector(id string)`.

func (*Connector) Run

func (c *Connector) Run()

The Connector is a Runner, thus having the Run and Recv(m interface {}) methods. The Run method should be called when the connector is registered.

func (*Connector) WithDownload

func (c *Connector) WithDownload(newDownload func(*Connector) Download) *Connector

Decorate the connection with a new Download. To support multiple types of download, we use a 'func(*Connector) Download' for interfacing.

func (*Connector) WithUpload

func (c *Connector) WithUpload(newUpload func(*Connector) Upload) *Connector

Decorate the connection with a new Upload. To support multiple types of download, we use a 'func(*Connector) Download' for interfacing.

type Download

type Download interface {
	Runner

	Choked() bool     // Returns if the peer that uploads to me chokes me.
	Interested() bool // Returns if I'm interested in the uploader's piece.

	Me() string   // The ID of the peer that I download from.
	From() string // The ID of the peer that I download from.

	RequestMore() // Request more pieces from a the peer.

	Rate() float64 // Measure download rates.
}

A Download component is reponsible for a long time download connection between 2 peers. It can be used to check the state of the download, process incoming messages, measure the download rates and request more pieces to download from the Picker.

func NewDownload

func NewDownload(connector *Connector) Download

type Handshake

type Handshake interface {
	Runner

	Uplink() Link
	Downlink() Link
	Done() bool
}

A Handshake is used to establish a connection between 2 peers. The Handshake handles the communication between 2 Peer instances, exchanging their link references. The Handshake provides a Downlink(created at construction) and an Uplink(transfered via a control message from the other peer). The Handshake hides the connection establishment, blocking until all the necessary control messages were received.

func NewHandshake

func NewHandshake(connector *Connector) Handshake

type Have

type Have struct {
	Id    string // The Id of the sender.
	Index int    // Index of the piece that the sender has.
}

A 'Have' message is sent to neighbours whenever a peer obtains a new piece. This message is part of the Original BitTorrent protocol. See the 'Messsage' section for a list with all the types of messages.

type Interested

type Interested struct{ Id string }

Original BitTorrent protocol message used by a node to show that it is interested in at least one of the messages advertised via 'Have' messages by another node. See the 'Messsage' section for a list with all the types of messages.

type Join

type Join struct {
	Id string
}

The Join message is a Tracker control message. This message is sent by a node to the tracker when it wants to join the torrent. See the 'Messsage' section for a list with all the types of messages.

type Manager

type Manager interface {
	AddConnector(conn *Connector)

	Uploads() []Upload
	Downloads() []Download
}

The Connection Manager is a lock-guarded list of Connectors. Since we assume reliable delivery, unlike in version 5.3, the Connection Manager does not have further responsibilities such as keeping connections alive.

func NewConnectionManager

func NewConnectionManager() Manager

type Neighbours

type Neighbours struct {
	Ids []string
}

The Neighbours message is a Tracker control message. This message is sent by the tracker as a response to a Join message. See the 'Messsage' section for a list with all the types of messages.

type NotInterested

type NotInterested struct{ Id string }

Original BitTorrent protocol message used by a node to show that it is not interested in any of the messages advertised via 'Have' messages by another node. NotInterested messages are also sent after all useful Pieces have been received to mark download completion. See the 'Messsage' section for a list with all the types of messages.

type Peer

type Peer struct {
	*Components

	// Information used for initializing the peer.
	Id      string
	Tracker string
	Ids     []string

	// -- BitTorrent protocol --
	Pieces []PieceMeta

	// -- BitTorrent components --
	// A map of Connectiors for all the nodes provided by the Tracker or by other
	// peers via connection initialization.
	Connectors map[string]Runner
	// contains filtered or unexported fields
}

func (*Peer) AddConnector

func (p *Peer) AddConnector(id string)

Function called when a new Connector towards the node id should be initialized.

func (*Peer) Bind

func (p *Peer) Bind(m interface{}) (state int)

A Bind function associates a state by using a Peer's internal state and a received message m. The messages handled are TrackerReq, Neighbours, SeedRes. The rest of messages will be further processed in case the Peer's Connectors were initalized. For more details on the returned states, see the Constants.

func (*Peer) CheckMessages

func (p *Peer) CheckMessages(bind Binder, process Processor)

CheckMessages is a function which runs until the node departs the system. It registers all the incoming messages. The messages are checked using a Binder which identifies the state of the Peer and the messages are processed by being passed to a Processor. The Processor looks at the state returned by the binder and acts correspondingly dispaching the message accordingly.

The CheckMessages function is exposed in the public API to make building on the current protocol easier by following the same Binder-Processor pattern.

func (*Peer) GetId

func (p *Peer) GetId(m interface{}) (id string)

A function used to extract the Id from an incoming message. The GetId function is also a mechanism used to filter messages outside the established protocol since it checks the message types explicitly, rather than using reflection.

func (*Peer) Init

func (p *Peer) Init()

Initilization function called synchronously after a node has joined the peer-to-peer system. In this function we find who the tracker is by interacting with the bootstrap node, respond to other peers which ask who the tracker is and, finally, send the tracker a Join request.

func (*Peer) New

func (p *Peer) New(util TorrentNodeUtil) TorrentNode

The New function is the construction function for the TorrentNode. The peer should be partially initialized in this function by using the TorrentNodeUtil's components. The TorrentNodeUtil is an interface which allows a node to interact with the Speer simulator.

func (*Peer) OnJoin

func (p *Peer) OnJoin()

The OnJoin function is called when the peer join the system and is part of the Implementation of Torrent Node interface.

func (*Peer) OnLeave

func (p *Peer) OnLeave()

The OnLeave function is called when the peer leaves0 the system and is part of the Implementation of Torrent Node interface.

func (*Peer) Process

func (p *Peer) Process(m interface{}, state int)

Process is a Processor function which calls the Run function when the node reaches the BindRun state. Afterwards, when the node is in the BindRecv state, the Process function will redirect the message to the RunRecv method.

func (*Peer) Run

func (p *Peer) Run(connAdd ConnAdder)

The run function is called at the end of the initialization phase. It initializes most of the internal components of a peer exposed by the Components structure. Moreover, it starts all the asynchronous routines such as the Choker and registers all the connections provided by the Tracker.

func (*Peer) RunRecv

func (p *Peer) RunRecv(id string, m interface{}, connAdd ConnAdder)

The RunRecv function is used to dispach the message towards a Connector's Recv method.

type Picker

type Picker interface {
	GotHave(peer string, index int)

	Active(index int)
	Inactive(index int)

	Next(peer string) (int, bool)
}

The Picker is responsible for choosing the next piece to be selected by a peer.(Next) To keep it updated each peer can notify if the a piece has been requested(Active) or if a request has been dropped(Inactive). Moreover, the Picker should be notified when a new Have piece did arrive.

func NewPicker

func NewPicker(Storage Storage) Picker

type Piece

type Piece struct {
	Id string

	// The index assoicated with the piece. Each Piece is identified by a unique
	// index as part of a file.
	Index int
	// The index of the first byte in the file. Typically the piece sizes are
	// equal, so Begin = Index * PieceLength.
	Begin int
	// The actual data associated with the piece. In our case, this is associated
	// with Speer simulator's interfaces.Data type.
	Piece Data
}

The meta-data associated with a piece sent as a response to a `Request` message. This message is part of the Original BitTorrent protocol. See the 'Messsage' section for a list with all the types of messages.

type PieceMeta

type PieceMeta struct {
	Index  int
	Begin  int
	Length int
}

PieceMeta is the metadata associated with a piece.

type Processor

type Processor func(m interface{}, state int)

A Processor is a function which processes a message only if the Peer is in a correct state. To see the possible states, see Constants.

type Request

type Request struct {
	Id string

	// We only use the index for requests instead of specifying
	// the begin and length of the data.
	Index int
}

A 'Request' message is sent when a node is unchoked and a piece was advertised by a Peer. The node will request a piece with a specific index. This message is part of the Original BitTorrent protocol. See the 'Messsage' section for a list with all the types of messages.

type Runner

type Runner interface {
	Run()
	Recv(interface{})
}

type SeedReq

type SeedReq struct {
	From string
}

The SeedReq is a message used for intergration with Speer. For simplicity, a Tracker will decide which nodes are seeds. This message is useless in a real deployment. Each peer sends a 'seed request' and in the 'seed response' finds if it's a seed and how many pieces it has. See the 'Messsage' section for a list with all the types of messages.

type SeedRes

type SeedRes struct {
	Pieces []PieceMeta
}

The SeedRes is a message used for intergration with Speer. See 'SeedReq' for details. See the 'Messsage' section for a list with all the types of messages.

type Selector

type Selector func(b, h map[int]bool, t map[int]int) (int, bool)

type Storage

type Storage interface {
	Have(index int) (PieceMeta, bool)
	Store(Piece)

	Pieces() []int
}

Storage is a concurrent-safe piece storage module. The synchronization is done via a read-write lock and the pieces are stored using a map. When the download is finished it also notifies the Configuration module.

func NewStorage

func NewStorage(id string, pieces []PieceMeta, time func() int) Storage

type TorrentDownload

type TorrentDownload struct {
	*Components

	// Requests that were made, but we still did not received a piece
	// back as a response.
	ActiveRequests map[int]bool
	// contains filtered or unexported fields
}

The Download component is the most complex one, reacting to `choke`, `unchoke`, `piece` and `have` messages. It keeps a list of active requests, which are requests that have been sent but a piece was not yet received. When the Download gets an `unchoke` message it populates the active requests list by asking the Picker for next pieces to request. Then, the requests for the picked pieces are sent. The `have` messages received by the Download result in Picker getting notified and in a potential change of interest via sending an interested message.

The implementation follows the 'download.py' file from BitTorrent 5.3.0 release. We moved here some of the responsibility of 'MultiDownload.py' and 'RequestManager.py'.

For a more details on the implementation check the message receival internal functions from the code. (gotHave, gotChoke, etc.)

func (*TorrentDownload) Choked

func (d *TorrentDownload) Choked() bool

Returns if the peer that uploads to me chokes me.

func (*TorrentDownload) From

func (d *TorrentDownload) From() string

The ID of the peer that I download from.

func (*TorrentDownload) Interested

func (d *TorrentDownload) Interested() bool

Returns if I'm interested in the uploader's piece.

func (*TorrentDownload) Me

func (d *TorrentDownload) Me() string

The ID of the peer that downloads.

func (*TorrentDownload) Rate

func (d *TorrentDownload) Rate() float64

Calculate the download rate as a moving average.

func (*TorrentDownload) Recv

func (d *TorrentDownload) Recv(m interface{})

func (*TorrentDownload) RequestMore

func (d *TorrentDownload) RequestMore()

Request more pieces from a the peer. The pieces are chosen using the Picker.

func (*TorrentDownload) Run

func (d *TorrentDownload) Run()

type TorrentPicker

type TorrentPicker struct {
	*sync.RWMutex

	Storage Storage

	Have map[string]map[int]bool // the pieces that the remote peers have

	Bans map[int]bool // the pieces that I already have stored
	// contains filtered or unexported fields
}

This structures follows the 'PiecePicker.py' file implementation from BitTorrent 5.3.0 release.

We follow the description in Bram Cohen's Incentives Build Robustness in BitTorrent, that is: - the policy is rarest first - first pieces are provided in random order rather than by rarest first policy

We do not model endgame mode. A piece’s rarity is defined by the number of peers in the local neighborhood that have that particular piece.

Some reponsibilities of the 'RequestManager.py' have been moved to this file, that is the accounting of active requests.

func (*TorrentPicker) Active

func (p *TorrentPicker) Active(index int)

Mark a certain pice as being in an active request -- that is the transfer has been scheduled, but it is not yet finished.

func (*TorrentPicker) GotHave

func (p *TorrentPicker) GotHave(peer string, index int)

Handler for receiving a `Have` message.

func (*TorrentPicker) Inactive

func (p *TorrentPicker) Inactive(index int)

Mark a piece as inactive -- that is the request has been eliminated or the piece transfer has finished. (see `download.go`)

func (*TorrentPicker) IsBanned

func (p *TorrentPicker) IsBanned(index int) bool

func (*TorrentPicker) IterateBuckers

func (p *TorrentPicker) IterateBuckers(peer string, selector Selector) (int, bool)

func (*TorrentPicker) Next

func (p *TorrentPicker) Next(peer string) (int, bool)

Return the next piece for a certain peer.

func (*TorrentPicker) SelectBucket

func (p *TorrentPicker) SelectBucket(bucket map[int]bool,
	haves map[int]bool,
	tiebreaks map[int]int) (int, bool)

type TorrentUpload

type TorrentUpload struct {
	*Components
	// contains filtered or unexported fields
}

The Upload is a reactive component. It listens for `interested` and `notInterested` messages and notifies the Choker. It starts uploads when it receives a request for a piece and it provides a choke/unchoke interface for the Choker to call.

func (*TorrentUpload) Choke

func (u *TorrentUpload) Choke()

Function called when we want to choke the upload connection.

func (*TorrentUpload) Choking

func (u *TorrentUpload) Choking() bool

Return if I am choking the connection.

func (*TorrentUpload) IsInterested

func (u *TorrentUpload) IsInterested() bool

Return if the other peer is interested in my pieces.

func (*TorrentUpload) Me

func (u *TorrentUpload) Me() string

The ID of the peer that uploads.

func (*TorrentUpload) Rate

func (u *TorrentUpload) Rate() float64

Returns the downoad rate of the connection.

func (*TorrentUpload) Recv

func (u *TorrentUpload) Recv(m interface{})

func (*TorrentUpload) Run

func (u *TorrentUpload) Run()

func (*TorrentUpload) To

func (u *TorrentUpload) To() string

The ID of the peer that I upload to.

func (*TorrentUpload) Unchoke

func (u *TorrentUpload) Unchoke()

Function called when we want to unchoke an upload.

type Tracker

type Tracker struct {
	Ids []string

	Limit int
	Neigh int
	Id    string

	Transport Transport
}

The Tracker works as a bootstrapping mechanism. Firstly, when a peer wants to join the network it will ask the tracker for a list of peers to which it can connect to. The tracker has a pool of peers, from which it randomly chooses a fixed number of peers to pass to the requester. The second step, thus, consists of the tracker sending the list of peers to the requester. The peer will then try to connect to any of these peers.

A modification that we make from the original Tracker is the fact that we use SeedReq for intergration with Speer. For simplicity, a Tracker will decide which nodes are seeds. This messages are useless in a real deployment.

The Tracker reacts to messages:

  • TrackerReq
  • Join
  • SeedReq

func (*Tracker) CheckMessages

func (t *Tracker) CheckMessages(process func(interface{}))

func (*Tracker) Join

func (t *Tracker) Join(msg Join, getNeighbours func(string) interface{})

func (*Tracker) Neighbours

func (t *Tracker) Neighbours(id string) interface{}

func (*Tracker) New

func (t *Tracker) New(util TorrentNodeUtil) TorrentNode

func (*Tracker) OnJoin

func (t *Tracker) OnJoin()

func (*Tracker) OnLeave

func (t *Tracker) OnLeave()

func (*Tracker) Recv

func (t *Tracker) Recv(m interface{})

type TrackerReq

type TrackerReq struct {
	From string
}

The TrackerReq is a messages used for bootstraping. When a node joins the simulated network, it has access to only one node. The message will be sent to that node as question 'Who is the Tracker?'. See the 'Messsage' section for a list with all the types of messages.

type TrackerRes

type TrackerRes struct {
	Id string
}

The TrackerRes is a messages used for bootstraping. When a node joins the simulated network, it has access to only one node. The message is a response to a TrackerReq question 'Who is the Tracker?'. See the 'Messsage' section for a list with all the types of messages.

type Unchoke

type Unchoke struct{ Id string }

Original BitTorrent protocol message used to notify a node that it has been unchoked. See the 'Messsage' section for a list with all the types of messages.

type Upload

type Upload interface {
	Runner

	Choke()   // Actions done when I choke a connection(upload)
	Unchoke() // Actions done when I unchoke a connection(upload)

	Me() string // The Uploader's ID.
	To() string // The ID of the receiving end.

	Choking() bool      // Returns if I'm choking the connection
	IsInterested() bool // Returns if the other peer is interested in my pieces
	Rate() float64      // Returns the download rate of the connection.
}

See TorrentUpload for more details.

func NewUpload

func NewUpload(connector *Connector) Upload

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL