Thursday, July 15, 2010

Info - Bittorrent Wire Protocol

Ohhkay. I'm not going to claim any great wisdom in this, but I will try to cover this component and what it does, with regards to the bittorrent wire protocol.

Specification, where?
Bittorrent.org's BEP 0003 covers the wire protocol, but the link to the section is crap. It's after this bit. Theory.org is a bit easier to digest in my opinion, starting with an introduction section.

Wire
After opening the TCP connection the two parties send a handshake, which provides their capabilities, identities and a confirmation of the torrent they are interested in (the info hash). Theoretically, the party opening the connection will send their handshake first, the party who opened the connection waiting until receiving the info hash before starting their part of the handshake. After this, the two parties use the connection in the same manner, sending messages to one another about what their state is and requesting parts of the torrent. If there's ever an error the connection should be broken.

Messages
Messages are structured with a 4 bytes header, which gives the length of the message, and for messages other than keepalive this is followed by a byte identifying the type of message.
The component informs an observer of the messsage id and the message payload after receiving a complete message. This is simpler than interfacing with the incoming stream directly.

Onto files:
Implementation of WireReader XPCOM component
IDL for WireReader XPCOM component

Example of usage:

// Attempt to connect to the peer
// These should be real values
var peerIpAddress = "127.0.0.1";
var peerPort = 6882;
var infoHash = String.fromCharCode(0,0,0,0,0);
infoHash = infoHash + infoHash + infoHash + infoHash;
var ourId = "01234567890123456789";
var remoteId = ""; // When remote peer id unknown, use empty string

var transportService =
Components.classes["@mozilla.org/network/socket-transport-service;1"].
getService(Components.interfaces.nsISocketTransportService);
var transport = transportService.createTransport(null,0,peerIpAddress,peerPort,null);

var listener = {
onHandshake : function ( context, reader ) {
// Received a valid handshake.
},
onRemoteId : function ( context, reader, remotePeerId ) {
// Received the remote peer id (20 byte identifier of remote peer)

},
onMessage : function( context, reader, messageId, messageBody ) {
// Good.
switch(message_id) {
// Keepalive doesn't have a message id, so we've used -1
case -1: alert("Keepalive"); break;
case 0: alert("Choke"); break;
case 1: alert("UnChoke"); break;
case 2: alert("Interested"); break;
case 3: alert("Not Interested"); break;
// etc.
default: alert("Message with id " + messageId);
}
// Message body is a string, representing the
// bytes in the message.
},
onDisconnect : function( context, reader ) {
// Disconnected
}
};
// Start reading from the input stream of the transport
reader.init(transport, ourId, remoteId, infoHash, listener, null /* context */);


More information on the wire protocol (Theory.org) Bittorrent Protocol Specification (BEP0003)
The bencoding XPCOM component.
The bittorrent tracker XPCOM component.
The Bittorrent File Info XPCOM component.
The Bittorrent File Storage XPCOM component.

No comments:

Post a Comment