private const int TimeTolerance = 1;//seconds to wait for answer public static byte[] UdpTrackerResponse(string trackerAddress, ExtendedTorrent torrent, int listeningPort, string peerId) { int trackerPort; string strippedAddress = SplitTrackerAddress(trackerAddress, out trackerPort); if (trackerPort == -1) { return(null); } byte[] transactionId = BitConverter.GetBytes(new Random().Next(0, int.MaxValue)); byte[] connectionid = GetConnectionId(strippedAddress, trackerPort, transactionId, listeningPort); if (connectionid == null) { return(null); } byte[] response = GetAnnounceResponse(strippedAddress, trackerPort, connectionid, transactionId, torrent, listeningPort, peerId); int err = ValidateAnnounceResponse(response, transactionId); if (err != 0) { return(null); } return(response); }
private static List <Peer> GetPeerList(ExtendedTorrent torrent, int listeningPort) { var peerList = new List <Peer>(); foreach (var tracker in torrent.Trackers) { string trackerAddress = tracker[0];//tracker's address is nested in a list within a list Console.WriteLine(trackerAddress); if (trackerAddress.Contains("udp://")) { byte[] trackerResponse = UdpProtolocHandler.UdpTrackerResponse(trackerAddress, torrent, listeningPort, torrent.PeerId); if (trackerResponse != null) { var trackerPeers = UdpProtolocHandler.GetPeerListFromUdpTrackerResponse(trackerResponse, torrent); if (trackerPeers.Count > 0) { peerList.AddRange(trackerPeers); } Console.WriteLine("IPs collected:" + trackerPeers.Count); } else { Console.WriteLine("Failed collect IP's"); } } else { Console.WriteLine("Unsupported protocol"); } Console.WriteLine(); } return(peerList); }
static void Main(string[] args) { string weekendmp3 = @"D364D9E12EF2B8C4FF44BB7E36E749126C119E2D.torrent";//*full .torrent file path is needed here var torrent = new ExtendedTorrent(weekendmp3); var peerList = GetPeerList(torrent, Utilities.listeningPort); Download(peerList, torrent); }
private static byte[] GetPeerHandshakeMessage(ExtendedTorrent torrent, string peerId) { byte[] handshake = new byte[49 + BitTorrentProtocol.ProtocolNameLength]; handshake[0] = Convert.ToByte(BitTorrentProtocol.ProtocolNameLength); Array.Copy(BitTorrentProtocol.ProtocolNameBytes, 0, handshake, 1, BitTorrentProtocol.ProtocolNameLength); Array.Copy(BitConverter.GetBytes((long)0), 0, handshake, BitTorrentProtocol.ProtocolNameLength + 1, 8); //reserved Array.Copy(torrent.GetInfoHashBytes(), 0, handshake, BitTorrentProtocol.ProtocolNameLength + 9, 20); Array.Copy(Encoding.ASCII.GetBytes(peerId), 0, handshake, BitTorrentProtocol.ProtocolNameLength + 29, 20); return(handshake); }
private static byte[] DownloadPiece(int index, ExtendedTorrent torrent, NetworkStream stream, FileSavingController fileSavingController) { long sizeOfPiece = torrent.PieceSize; if (fileSavingController.DownloadedPieces.Length - 1 == index)//last package special { long lastPackageLengthDifference = torrent.NumberOfPieces * torrent.PieceSize - torrent.TotalSize; sizeOfPiece = torrent.PieceSize - lastPackageLengthDifference; } int sizeOfRequestedBlock = Utilities.blockSize; byte[] piece = new byte[sizeOfPiece]; for (int pieceOffset = 0; pieceOffset < sizeOfPiece; pieceOffset += sizeOfRequestedBlock) { int requestLength = sizeOfPiece - pieceOffset < sizeOfRequestedBlock ? (int)(sizeOfPiece - pieceOffset) : sizeOfRequestedBlock;//last block size will be smaller than the rest of byte[] requestMessage = GetNextRequestMessage(index, pieceOffset, requestLength); stream.Write(requestMessage, 0, requestMessage.Length); byte[] response = new byte[requestLength + 13];//13 = 4b len + 1b id + 4b index + 4b begin try { stream.ReadTimeout = _peerTolerance * 1000; int responseLength = stream.Read(response, 0, response.Length); if (responseLength == 0) { Console.WriteLine("Response Length 0"); return(null); } int err = ValidatePieceMessage(response, requestLength, index, pieceOffset); if (err != 0) { //Console.WriteLine("Fail code:"+err); return(null); } Array.Copy(response, 13, piece, pieceOffset, requestLength); } catch (IOException) { Console.WriteLine("Connection timed out"); return(BitConverter.GetBytes(-1)); } } return(piece); }
private static void Download(List <Peer> peerList, ExtendedTorrent torrent) { FileSavingController fileSavingController = new FileSavingController(torrent); while (true) { foreach (var peer in peerList) { int success = PeerWireProtocolHandler.ConnectToPeer(peer, torrent, torrent.PeerId, fileSavingController); Console.WriteLine(peer.IpAddress + " " + peer.Port); Console.WriteLine("Error:" + GetErrorMessage(success)); if (success == 100) { Environment.Exit(0); } } } }
public FileSavingController(ExtendedTorrent torrent) { DownloadedPieces = new bool[torrent.NumberOfPieces]; MarkAlreadyDownloadedPieces(); fileName = torrent.File.FileName; }
private static byte[] GetAnnounceResponse(string trackerAddress, int trackerPort, byte[] connectionId, byte[] transactionId, ExtendedTorrent torrent, int listeningPort, string peerId) { byte[] requestPacket = GetAnnounceRequestPacketZero(connectionId, transactionId, torrent, listeningPort, peerId); using (var udpClient = new UdpClient(listeningPort)) { var timeToWait = TimeSpan.FromSeconds(TimeTolerance); udpClient.Connect(trackerAddress, trackerPort); udpClient.Send(requestPacket, requestPacket.Length); var asyncResult = udpClient.BeginReceive(null, null); asyncResult.AsyncWaitHandle.WaitOne(timeToWait); if (!asyncResult.IsCompleted) { return(null); } try { IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); byte[] receiveBytes = udpClient.EndReceive(asyncResult, ref remoteIpEndPoint); return(receiveBytes); } catch (Exception) { return(null); } } }
public static List <Peer> GetPeerListFromUdpTrackerResponse(byte[] trackerResponse, ExtendedTorrent torrent) { var peerList = new List <Peer>(); for (int i = 20; i < trackerResponse.Length; i += 6) { var ipBytes = trackerResponse.SubArray(i, 4); var portBytes = trackerResponse.SubArray(i + 4, 2); try { Peer peer = new Peer(ipBytes, portBytes, torrent.NumberOfPieces); peerList.Add(peer); } catch (ArgumentException) { } } return(peerList); }
/*TBC * public static byte[] GetAnnounceRequestPacket(byte[] connectionId, byte[] transactionId, Torrent torrent, int localPort) * { * byte[] announcePacket = new byte[98]; * Array.Copy(connectionId, 0, announcePacket, 0, 8); * Array.Copy(BitConverter.GetBytes(1).Reverse().ToArray(), 0, announcePacket, 8, 4);//action * Array.Copy(transactionId, 0, announcePacket, 12, 4); * Array.Copy(torrent.GetInfoHashBytes(), 0, announcePacket, 16, 20); * Array.Copy(Encoding.ASCII.GetBytes(GeneratePeerId()), 0, announcePacket, 36, 20); * Array.Copy(BitConverter.GetBytes(torrent).Reverse().ToArray(), 0, announcePacket, 56, 8);//downloaded * Array.Copy(BitConverter.GetBytes(torrent.Left).Reverse().ToArray(), 0, announcePacket, 64, 8);//left * Array.Copy(BitConverter.GetBytes(torrent.Uploaded).Reverse().ToArray(), 0, announcePacket, 72, 8);//uploaded * * //4bytes: event (0) + 4bytes: ip addr (0) * Array.Copy(BitConverter.GetBytes((long)0), 0, announcePacket, 80, 8); * byte[] key = BitConverter.GetBytes(new Random().Next(0, int.MaxValue)).Reverse().ToArray(); * Array.Copy(key, 0, announcePacket, 88, 4); * Array.Copy(BitConverter.GetBytes(-1).Reverse().ToArray(), 0, announcePacket, 92, 4); * Array.Copy(BitConverter.GetBytes((ushort)localPort).Reverse().ToArray(), 0, announcePacket, 96, 2); * return announcePacket; * }*/ private static byte[] GetAnnounceRequestPacketZero(byte[] connectionId, byte[] transactionId, ExtendedTorrent torrent, int localPort, string peerId) { byte[] announcePacket = new byte[98]; Array.Copy(connectionId, 0, announcePacket, 0, 8); Array.Copy(BitConverter.GetBytes(1).Reverse().ToArray(), 0, announcePacket, 8, 4);//action 1 - announce Array.Copy(transactionId, 0, announcePacket, 12, 4); Array.Copy(torrent.GetInfoHashBytes(), 0, announcePacket, 16, 20); Array.Copy(Encoding.ASCII.GetBytes(peerId), 0, announcePacket, 36, 20); Array.Copy(BitConverter.GetBytes((long)0), 0, announcePacket, 56, 8); //downloaded Array.Copy(BitConverter.GetBytes(torrent.TotalSize).Reverse().ToArray(), 0, announcePacket, 64, 8); //left Array.Copy(BitConverter.GetBytes((long)0), 0, announcePacket, 72, 8); //event 0-none //4bytes: event (0) + 4bytes: ip addr (0) Array.Copy(BitConverter.GetBytes((long)0), 0, announcePacket, 80, 8); byte[] key = BitConverter.GetBytes(new Random().Next(0, int.MaxValue)).Reverse().ToArray(); Array.Copy(key, 0, announcePacket, 88, 4); Array.Copy(BitConverter.GetBytes(-1), 0, announcePacket, 92, 4);//default Array.Copy(BitConverter.GetBytes((ushort)localPort).Reverse().ToArray(), 0, announcePacket, 96, 2); return(announcePacket); }
private static int ValidatePeerHandshake(byte[] response, int responseLength, ExtendedTorrent torrent) { int peerPstrLength = Convert.ToInt32(response[0]); if (responseLength < peerPstrLength + 49) { return(1); //possible keep alive message } if (peerPstrLength != BitTorrentProtocol.ProtocolNameLength) { return(2); } byte[] peerProtocolNamebytes = response.SubArray(1, peerPstrLength); if (!peerProtocolNamebytes.SequenceEqual(BitTorrentProtocol.ProtocolNameBytes)) { return(2); //not BitTorrentProtocol } byte[] receivedInfoHash = response.SubArray(peerPstrLength + 9, 20); if (!receivedInfoHash.SequenceEqual(torrent.GetInfoHashBytes())) { return(3); //bad info hash } return(0); //handshake correct }
public static int ConnectToPeer(Peer peer, ExtendedTorrent torrent, string peerId, FileSavingController fileSavingController) { byte[] handshakeMessage = GetPeerHandshakeMessage(torrent, peerId); using (var tcpClient = new TcpClient()) { try { var result = tcpClient.BeginConnect(peer.IpAddress, peer.Port, null, null); var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(_peerTolerance)); if (!success) { return(-1); } using (var stream = tcpClient.GetStream()) { //handshaking process stream.Write(handshakeMessage, 0, handshakeMessage.Length); byte[] response = new byte[512]; int responseLength = stream.Read(response, 0, response.Length); int validationErr = ValidatePeerHandshake(response, responseLength, torrent); if (validationErr != 0) { return(validationErr); } int responseWithoutHandshakeLength = responseLength - 49 - BitTorrentProtocol.ProtocolNameLength; byte[] responseWithoutHandshake = response.SubArray(49 + BitTorrentProtocol.ProtocolNameLength, responseWithoutHandshakeLength); //handle bitfield message int responseId = GetMessageId(responseWithoutHandshake); switch (responseId) { case -1: return(-1); case 5: HandleBitfieldMessage(responseWithoutHandshake, responseWithoutHandshakeLength, peer, stream); break; default: return(4); } //Send interested: <len=0001><id=2> byte[] interested = new byte[5]; Array.Copy(BitConverter.GetBytes(1).Reverse().ToArray(), 0, interested, 0, 4); interested[4] = Convert.ToByte(2); stream.Write(interested, 0, 5); //receive unchoke: <len=0001><id=1> byte[] potentialUnchoke = new byte[5]; stream.Read(potentialUnchoke, 0, 5); int len = BitConverter.ToInt32(potentialUnchoke.SubArray(0, 4).Reverse().ToArray(), 0); int id = Convert.ToInt32(potentialUnchoke[4]); if (len != 1 || id != 1) { return(5); } //4.request for piece //set index of next piece to download int index = GetIndexOfNextPieceAvaivable(peer, fileSavingController); if (index == -1) { return(10); } //downloading sequence int consecutiveFails = 0; while (consecutiveFails < 7) { byte[] piece = DownloadPiece(index, torrent, stream, fileSavingController); if (piece == null) { Console.WriteLine(DateTime.Now + "||Piece #" + index + " Failed to download"); consecutiveFails++; } else if (BitConverter.ToInt32(piece.SubArray(0, 4), 0) == -1) { return(-2); } else { bool hashesMatch = CheckIfHashesMatch(piece, torrent, index); if (hashesMatch) { fileSavingController.SavePiece(piece, index); Console.WriteLine(DateTime.Now + " | Downloaded piece #" + index); var compl = fileSavingController.DownloadedPieces.Where(c => c).Count(); Console.WriteLine("Downloaded " + compl + "/" + fileSavingController.DownloadedPieces.Length + " pieces"); if (compl == fileSavingController.DownloadedPieces.Length) { fileSavingController.PiecesToSingleFile(); return(100); } } else { return(11); } } index = GetIndexOfNextPieceAvaivable(peer, fileSavingController); if (index == -1) { return(10); } } return(-1); } } catch (IOException) { return(-1); } } }
private static bool CheckIfHashesMatch(byte[] piece, ExtendedTorrent torrent, int indexOfPiece) { byte[] localHash = torrent.Pieces.SubArray(indexOfPiece * 20, 20); byte[] receivedHash = new SHA1Managed().ComputeHash(piece); return(localHash.SequenceEqual(receivedHash)); }