private byte[] GenerateExtentionDict() { var extensionDict = new Dictionary <byte[], object>(); var supportedExtensions = new Dictionary <byte[], object>(); supportedExtensions.Set("ut_metadata", 2); extensionDict.Set("m", supportedExtensions); // metadata_size is unnecessary if we are requesting. If we're providing metadata, we should add this. // extensionDict.Set("metadata_size", 0); extensionDict.Set("p", Client.myPort); extensionDict.Set("v", "Ditto 0.1.0"); return(Bencoding.Encode(extensionDict)); }
void sendPing(IPEndPoint destination, byte[] token) { var dict = Bencoding.Dict(); dict.Set("t", token); dict.Set("y", "q"); dict.Set("q", "ping"); dict.Set("ro", 1); var args = Bencoding.Dict(); args.Set("id", nodeId); dict.Set("a", args); var encoded = Bencoding.Encode(dict); socket.SendTo(encoded, destination); }
void sendGetPeers(IPEndPoint destination, byte[] token, byte[] infohash) { var dict = Bencoding.Dict(); dict.Set("t", token); dict.Set("y", "q"); dict.Set("q", "get_peers"); dict.Set("ro", 1); var args = Bencoding.Dict(); args.Set("id", nodeId); args.Set("info_hash", infohash); dict.Set("a", args); var encoded = Bencoding.Encode(dict); socket.SendTo(encoded, destination); }
public void InitiateHandshake(byte[] infoHash) { logger.LogInformation("Our Peer id: " + Client.peerId.ToHuman()); var fixedHeader = new byte[20]; fixedHeader[0] = (byte)19; "BitTorrent protocol".ToASCII().CopyTo(fixedHeader, 1); var bufferBitfield = new byte[8]; bufferBitfield[5] = (byte)16; Client.extensionsEnabled = true; TcpClient connection = new TcpClient(); connection.ConnectAsync(peer.Address, peer.Port).Wait(); if (!connection.Connected) { throw new Exception("Failed to connect to Peer."); } var initialHandshake = new byte[68]; fixedHeader.CopyTo(initialHandshake, 0); bufferBitfield.CopyTo(initialHandshake, fixedHeader.Length); infoHash.CopyTo(initialHandshake, fixedHeader.Length + bufferBitfield.Length); Client.peerId.CopyTo(initialHandshake, fixedHeader.Length + bufferBitfield.Length + infoHash.Length); logger.LogInformation(LoggingEvents.HANDSHAKE_OUTGOING, "Sending our handshake to " + peer.Address + ":" + peer.Port); using (var stream = connection.GetStream()) { stream.Write(initialHandshake); logger.LogInformation(LoggingEvents.HANDSHAKE_INCOMING, "Received response from Peer."); var theirFixedHeader = stream.ReadBytes(20); if (!theirFixedHeader.SequenceEqual(fixedHeader)) { throw new Exception("Peer failed to return fixed header; aborting connection."); } var theirBuffer = stream.ReadBytes(8); if (theirBuffer[5] == 16) { theirExtensionsEnabled = true; } var theirInfoHash = stream.ReadBytes(20); logger.LogInformation(LoggingEvents.HANDSHAKE_INCOMING, "Peer's infohash is: " + theirInfoHash.ToHuman()); if (!theirInfoHash.SequenceEqual(infoHash)) { throw new Exception("Peer failed to return a matching infohash; aborting connection."); } var theirpeerId = stream.ReadBytes(20); logger.LogInformation(LoggingEvents.HANDSHAKE_INCOMING, "The Peer's ID is " + theirpeerId.ToHuman()); if (Client.extensionsEnabled && theirExtensionsEnabled) { var theirExtensionHeader = GetPeerExtensionHeader(stream); var decodedExtensionHeader = Bencoding.DecodeDict(theirExtensionHeader); var theirExtensions = decodedExtensionHeader.GetDict("m"); logger.LogInformation(LoggingEvents.EXTENSION_HEADER_IN, "Peer's extension header:" + Environment.NewLine + Bencoding.ToHuman(theirExtensionHeader)); var extensionDict = GenerateExtentionDict(); var extensionHeader = new byte[extensionDict.Length + 6]; var lengthPrefix = (extensionDict.Length + 2).EncodeBytes(); Array.Copy(lengthPrefix, extensionHeader, 4); extensionHeader[4] = 20; extensionHeader[5] = 0; extensionDict.CopyTo(extensionHeader, 6); stream.Write(extensionHeader); logger.LogInformation(LoggingEvents.EXTENSION_HEADER_OUT, "Sending our extension header: " + Environment.NewLine + Bencoding.ToHuman(extensionDict)); // Send interested message stream.Write(1.EncodeBytes()); stream.Write(new byte[1] { 2 }); logger.LogInformation(LoggingEvents.PEER_PROTOCOL_MSG, "Sent interested message."); if (theirExtensions.ContainsKey("ut_metadata")) { logger.LogInformation(LoggingEvents.METADATA_EXCHANGE, "They also support metadata exchange. Lets try that."); var theirMetadataExtensionId = (byte)theirExtensions.Get("ut_metadata"); var metadataExchange = new MetadataExchange(decodedExtensionHeader.Get("metadata_size")); try { torrent.Metadata = metadataExchange.GetMetadata(stream, connection, 2, theirMetadataExtensionId, infoHash); } catch (MetadataException e) { logger.LogWarning("Unable to get metadata from current peer: ", e); } } } } }
static byte[] serialize(object value) { return(Bencoding.Encode(value)); }
// Plug in your encoding and decoding functions here. static object deserialize(byte[] bytes) { return(Bencoding.Decode(bytes)); }
private void handleMessage(UDPSocket.ReceivedPacket message) { var value = Bencoding.DecodeDict(message.Data); var type = value.GetString("y"); switch (type) { case "r": { var key = new QueryKey { Token = value.GetBytes("t"), EP = message.Source }; if (pendingQueries.ContainsKey(key)) { var responseSource = pendingQueries[key]; pendingQueries.Remove(key); responseSource.TrySetResult(value); } else { logger.LogDebug("Got unexpected response message."); } break; } case "e": { var key = new QueryKey { Token = value.GetBytes("t"), EP = message.Source }; logger.LogError($"Got error mesage for {key}."); if (pendingQueries.ContainsKey(key)) { var responseSource = pendingQueries[key]; pendingQueries.Remove(key); var errors = value.GetList("e"); var code = (Int64)errors[0]; var errorMessage = ((byte[])errors[1]).FromASCII(); var exception = new Exception($"{code} {errorMessage}"); responseSource.TrySetException(new Exception[] { exception }); } else { logger.LogError($"But I don't even know {key}!"); } break; } case "q": { logger.LogDebug($"Ignored query mesage from {message.Source}."); // do nothing because we're read-only break; } default: { logger.LogDebug($"Got unknown mesage from {message.Source}."); // maybe we could send an error? break; } } }