Some parts of the bittorrent protocol use the bencoding for data
representation. This encoding is implemented in the (torrent bencoding)
module. This module consists of a record type and two public procedures:
Data Type: dictionnary
This data type represents a dictionnary. A dictionnary is a datastructure
that associates values to keys. This field contains only one element,
alist, a association list.
Scheme Procedure: dictionnary-alistdictionnary
This procedure returns the actual association list contains in a dictionnary.
Scheme Procedure: bencodedata
This procedure takes data and returns a bytevector corresponding
to the bencoded data. The data can be a bytevector, a string,
an integer, a list or a dictionnary.
Scheme Procedure: bdecodeport
This procedure takes port and reads data from it. After it reaches
#eof, this procedure returns the data corresponding to what it read in
the bencoding. The result can be a dictionnary, a list,
a bytevector or an integer depending on the data that has been
One of the ways to get torrent informations is by loading a .torrent file.
The file contains many useful information, including announce URLs to wich
the bittorrent client can ask for more peers regularly, the hash of each piece,
their size and the list of files contained in the torrent.
From this, we can derive the infohash which is a sha-1 hash of a
part of that file and corresponds to the identifier of the torrent.
Although there are multiple methods to get peers for a torrent, they all require
the infohash of the torrent before you can start asking for peers. The infohash
itself can come either from the .torrent file as seen in this section
or a magnet:// URL. The content of this URL is actually the hexadecimal
representation of the infohash.
The (torrent metainfo) module is responsible for parsing .torrent
files. This module contains the following definitions:
Data Type: metainfo
This data type represents the necessary information contained in the .torrent
The info section of the .torrent file.
A string containing the address of the main announce URL for this torrent.
A bytevector representing the infohash of this file.
Data Type: torrent-info
This data type represents the necessary infomation contained in the info
section of the .torrent file.
A number representing the number of bytes of each piece
A bytevector representing the concatenation of each piece’s sha-1 hash.
This information is useful to independently check each piece’s integrity.
A boolean indicating whether this torrent is private i.e. whether the client
must only use the trackers present in the file or if it can use other means
such as the peer exchange protocol.
A boolean indicating whether this torrent contains a single file.
A string containing the name of the torrent. In single-file mode, this
corresponds to the filename. In multiple-file mode, this corresponds to the
name of the folder containing the files.
In single-file mode, a number representing the size of the file in bytes. In
multiple-files mode, #f.
In single-file mode, #f. In multiple-files mode, a list of
torrent-info-file objects representing the content of the torrent.
Data Type: torrent-info-file
This data type represents the necessary information to describe a file from
A number representing the size of the file in bytes.
A list of strings representing the path to the file from the top-level directory
of the torrent.
This module also defines the following procedure:
Scheme Procedure: parse-torrent-filefile
This procedure parses a .torrent file whose name is contained in file
and returns a metainfo object containing the necessary information in
The (torrent tracker) module contains definitions and procedures that
deal with connecting to a tracker and getting information.
Data Type: tracker
A string representing the host name of the tracker.
A string representing the path to the annouce page. e.g. "/announce"
A string representing the protocol used to connect to the tracker. e.g.
A number representing the port of the tracker, or #f to use the standard
port for the protocol.
The infohash of the torrent we are interested in, represented by a bytevector.
The current state of this session:
'start indicates that we still haven’t connected to the tracker
during this session;
'complete indicates that we have completed the download but haven’t
told the tracker yet;
'stop indicates that we are about to stop, but we haven’t told the
'running indicates that we are operating normally.
The number of bytes that we have uploaded during this session.
The number of bytes that we have downloaded during this session.
The number of bytes left that we need to download.
The tracker id or #f if the tracker didn’t send us its tracker id.
Data Type: tracker-response
When an error occured, a string containing the reason of the failure. Otherwise
#f. If this field is set, no other field can be considered valid.
When a warning is issued by the tracker, a string containing the content of
the warning. Otherwise #f.
A number representing the interval in seconds at which the tracker would want us
to ask for more peers.
A number representing the minimum interval in seconds the tracker wants us to
respect between two requests.
A string containing the tracker id. If no tracker id is given by the tracker,
#f. Otherwise, this value should be saved for future requests in the
id field of the tracker object.
The number of peers the tracker knows of that have finished downloading the
The number of peers the tracker knows of that have not yet finished downloading
A list of peers, each represented by an association list containing two fields:
"host" and "port". The value of these fields are integers.
Scheme Procedure: uri-protouri
Returns the protocol part of the uri, e.g. "http".
Scheme Procedure: uri-hosturi
Returns the host part of the uri.
Scheme Procedure: uri-porturi
Returns the port part of the uri as a number or #f if it is not
specified in the uri.
Scheme Procedure: uri-pageuri
Returns the path part of the uri.
Scheme Procedure: url-encodebv
This procedure takes a bytevector and returns the url-encoded value equivalent
to the content of the bytevector. This works by using the %xx encoding
for each character that cannot appear in a url.
Scheme Procedure: ask-more-peerstrackerpeeridport
This procedure will ask tracker for more peers. peerid and port
must contain respectively the peer id and port of our client. This makes a
request to the tracker and returns a tracker-response object in case
of success or a simple string containing the body of the response in case of
Scheme Procedure: get-new-trackeruriinfohashleft
This method can be used to initialize all the fields of a new tracker
object. It returns this new tracker object.
This procedures runs a fiber that connects to the given tracker.
peerid and port are our peer ID and port on which we are listening
for connections. ending-channel is a channel on which the fiber listens
from the 'stop message. peers-channel is a channel on which the
fiber will put messages about newly found peers. Messages from this fiber
are always of this form:
`(("type" 'new-peers) ("new-peers" <tracker-response-peers>)).
The (torrent protocol) module is responsible for handling protocol
messages and connecting to peers.
Data Type: peer
This data type represents a peer in the bittorrent protocol. A peer is another
client running the bittorrent protocol that either has the file we are interested
in or is interested in the file. This record type has the following fields:
A 20-bytes bytevector holding the peer-id of the remote peer.
The socket through which to communicate with the peer.
A bitfield representing the availability of pieces from that peer.
A boolean indicating whether the remote peer choked us. When we are choked,
we shouldn’t request blocks to that peer.
A boolean indicating whether the remote peer is interested by what we have. If
we wante to send it data, we should unchok it first.
A boolean indicating whether we are choking the remote peer. While we are
choking it, it shouldn’t ask
A boolean indicating whether we told the remote peer we were interested. The
remote peer will not likely unchoke us unless it is aware we are interested.
This procedure sends a handshake message to sock, a peer socket. The
handshake must be the first message sent to the peer. It specifies the
infohash and our self-id (peer id).
Scheme Procedure: receive-handshakesockinfohash
This procedure waits for the handshake on sock and compares its content
with the infohash we are interested in. If the handshake is valid, returns
the remote peer-id object associated to the connection, i.e. the peer
id of the remote peer. Otherwise, returns #f.
Scheme Procedure: receive-messagesock
This procedure waits for a message on sock and decodes it. If it is an
invalid message, returns #f or throws an exception. Otherwise it returns
a symbol or an association list corresponding to the message that was received.
This procedure sends a keep-alive message. These messages must be sent from time
to time because peers will close the connection after typically 2 minutes of
Sceme Procedure: send-chokesock
This procedure sends a message to choke the remote peer on sock. It
should not ask us for pieces anymore.
Scheme Procedure: send-unchokesock
This procedure send a message to unchoke the remote peer on sock. It can
now request pieces from us.
Scheme Procedure: send-interestedsock
Tell the remote peer on sock we are interested.
Scheme Procedure: send-not-interestedsock
Tell the remote peer on sock we are not interested.
Scheme Procedure: send-havesockpiece
Notify the remote peer on sock we have completed download of piece,
the zero-based index of the piece. It doesn’t need to be a piece downloaded
from that peer.
Scheme Procedure: send-bitfieldsockbitfield
Send a bitfield to the remote peer on sock to tell it what pieces
we already have or not. This is not required if we don’t have any piece yet.
This procedure should only be used once after the handshake and before sending
any other message.
Scheme Procedure: send-requestsockindexstartlen
Ask the remote peer on sock for a part of a piece of size len,
starting at offset start in the index piece. A typical value for
len is 16384.
Scheme Procedure: send-piecesockindexstartblock
Send a block of data to the remote peer on sock. This block corresponds
to the index piece at offset start. This should be used after a
peer asked us for a piece.
Scheme Procedure: send-cancelsockindexstartlen
Ask the remote peer on sock to cancel sending the piece to us. The other
arguments are the same as for the send-request procedure.
Scheme Procedure: send-portsocklisten-port
Send the listen-port we are listening on for the DHT protocol.
Scheme Procedure: has?bitfieldpiece
If bitfield is a representation of the bitfield of some peer, returns
whether that peer has piece number piece.
Scheme Procedure: hasbitfieldpiece
Update bitfield such that it now has the bit corresponding to piece
number piece set.
Additionnaly, this module defines higher-level functions and data types:
Data Type: potential-peer
This data type represents coordinates to a peer we aren’t currently connected
to. This is typically used to record peer lists received from trackers or
The host of the peer.
The port the peer listens on.
Determines whether we learned about that peer a short or a long time ago.
Runs a fiber that connects to a peer, listens for commands and reports peer
status. This fiber runs indefinitely until it receives a 'quit signal
on its private channel.
parent-channel is the channel to which the fiber should report changes
to the current peer. These messages are are either
`(("type" peer) ("peer" peer)) to report either a new connection or
an update to the peer fields, or `(("type" peer-closed) ("peer" peer))
to signal the peer is disconnected and should not be taken into account anymore.
This last message is given only when the fiber stops unexpectedly after it
advertised a new peer. If an error occured before the connection could be
advertised to the parent-channel, no message is sent to the channel.
peer is a potential-peer whose host and port fields
are used to connect to the peer it represents. peerid is the peer ID of
this client. infohash is the infohash of the torrent that should be
recovered from that peer and bitfield is the bitfield representation of
the pieces we have and don’t have yet.