コード例 #1
0
        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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
 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);
 }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
                    }
                }
            }
        }
コード例 #7
0
 public FileSavingController(ExtendedTorrent torrent)
 {
     DownloadedPieces = new bool[torrent.NumberOfPieces];
     MarkAlreadyDownloadedPieces();
     fileName = torrent.File.FileName;
 }
コード例 #8
0
        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);
                }
            }
        }
コード例 #9
0
        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);
        }
コード例 #10
0
        /*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);
        }
コード例 #11
0
        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
        }
コード例 #12
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);
                }
            }
        }
コード例 #13
0
 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));
 }