private static int GetIndexOfNextPieceAvaivable(Peer peer, FileSavingController fileSavingController) { int index; do { index = peer.IndexOfNextAvaivablePiece; if (index == -1) { return(-1); //peer has no more pieces left to offer } } while (fileSavingController.DownloadedPieces[index]); return(index); }
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 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 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); }