Пример #1
0
        public static void ReceiveHandshake(IO.Stream stream, ref ByteField20 infoDigest)
        {
            // read in protocol string
            byte[] protocolVersionLength = new byte[1];
            if (stream.Read(protocolVersionLength, 0, protocolVersionLength.Length) != protocolVersionLength.Length)
            {
                throw new System.Exception("Invalid handshake protocol");
            }
            if (protocolVersionLength[0] != 19)
            {
                throw new System.Exception("Invalid handshake protocol");
            }
            byte[] protocolBytes = new byte[protocolVersionLength[0]];
            if (stream.Read(protocolBytes, 0, protocolBytes.Length) != protocolBytes.Length)
            {
                throw new System.Exception("Invalid handshake protocol");
            }
            string protocol = System.Text.ASCIIEncoding.ASCII.GetString(protocolBytes, 0, protocolBytes.Length);

            if (protocol != protocolString)
            {
                throw new System.Exception("Invalid handshake protocol");
            }

            // 8 zeros
            byte[] zeroes = new byte[8];
            if (stream.Read(zeroes, 0, zeroes.Length) != zeroes.Length)
            {
                throw new System.Exception("Invalid handshake protocol");
            }

            // SHA digest
            stream.Read(infoDigest.Data, 0, infoDigest.Data.Length);
        }
Пример #2
0
 public Session(ByteField20 localPeerId)
 {
     mLocalPeerId = localPeerId;
     if (Config.ActiveConfig.ProxyURL != "")               // set web proxy
     {
         System.Net.WebRequest.DefaultWebProxy = new Net.WebProxy(Config.ActiveConfig.ProxyURL);
     }
     SetAllowUnsafeHeaderParsing20();
     this.StartServer();
 }
Пример #3
0
        public static void SendHandshake(IO.Stream stream, ByteField20 infoDigest)
        {
            stream.WriteByte((byte)protocolString.Length);
            stream.Write(System.Text.ASCIIEncoding.ASCII.GetBytes(protocolString), 0, protocolString.Length);

            // 8 zeros
            stream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 8);

            // SHA digest
            stream.Write(infoDigest.Data, 0, infoDigest.Data.Length);
        }
Пример #4
0
		public static void SendHandshake(IO.Stream stream, ByteField20 infoDigest)
		{
			stream.WriteByte((byte)protocolString.Length);
			stream.Write(System.Text.ASCIIEncoding.ASCII.GetBytes(protocolString), 0, protocolString.Length);

			// 8 zeros
			stream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 8);

			// SHA digest
			stream.Write(infoDigest.Data, 0, infoDigest.Data.Length);
		}
Пример #5
0
        public Torrent FindTorrent(ByteField20 infoDigest)
        {
            lock (this.mTorrents)
            {
                foreach (Torrent torrent in this.mTorrents)
                {
                    if (torrent.Metainfo.InfoDigest.Equals(infoDigest))
                    {
                        return(torrent);
                    }
                }

                return(null);
            }
        }
Пример #6
0
        /// <summary>
        /// Helper thread method to start the connection to peers
        /// </summary>
        /// <param name="state"></param>
        private void StartPeerConnectionThread(System.IAsyncResult result)
        {
            object[]        objs = (object[])result.AsyncState;
            Sockets.Socket  socket = (Sockets.Socket)objs[0];
            PeerInformation peerinfo = (PeerInformation)objs[1];
            ByteField20     infoDigest = new ByteField20(), peerId = new ByteField20();

            Sockets.NetworkStream netStream;

            try
            {
                socket.EndConnect(result);

                netStream = new Sockets.NetworkStream(socket, true);

                // send handshake info
                PeerProtocol.SendHandshake(netStream, this.infofile.InfoDigest);
                PeerProtocol.ReceiveHandshake(netStream, ref infoDigest);
                PeerProtocol.SendPeerId(netStream, this.mSession.LocalPeerID);

                if (!PeerProtocol.ReceivePeerId(netStream, ref peerId))
                {                 // NAT check
                    socket.Close();
                    return;
                }

                // check info digest matches and we are not attempting to connect to ourself
                if (infoDigest.Equals(this.infofile.InfoDigest) && !peerId.Equals(this.mSession.LocalPeerID))
                {
                    peerinfo.ID = peerId;
                    this.AddPeer(socket, netStream, peerinfo);
                }
                else                 // info digest doesn't match, close the connection
                {
                    socket.Close();
                }
            }
            catch (System.Exception e)
            {
                Config.LogException(e);
                // die if the connection failed
                if (socket != null)
                {
                    socket.Close();
                }
                return;
            }
        }
Пример #7
0
 /// <summary></summary>
 /// <returns>True if the objects are equal</returns>
 public override bool Equals(object obj)
 {
     if (obj is ByteField20)
     {
         ByteField20 sha = (ByteField20)obj;
         for (int i = 0; i < this.data.Length; ++i)
         {
             if (this.data[i] != sha.data[i])
             {
                 return(false);
             }
         }
         return(true);
     }
     else
     {
         return(false);
     }
 }
Пример #8
0
        private static ByteField20 DefaultCalculatePeerId()
        {
            // calculate our peer id
            string peerIdString = "-TN" + string.Format("{0:00}", Config.MajorVersionNumber)
                                  + string.Format("{0:00}", Config.MinorVersionNumber) + "-";

            ByteField20 peerId = new ByteField20();

            System.Array.Copy(System.Text.ASCIIEncoding.ASCII.GetBytes(peerIdString), 0, peerId.Data, 0, peerIdString.Length);

            const string peerChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

            System.Random rand = new System.Random();

            for (int i = peerIdString.Length; i < 20; ++i)
            {
                peerId.Data[i] = (byte)peerChars[rand.Next(0, peerChars.Length - 1)];
            }

            return(peerId);
        }
Пример #9
0
		public static void ReceiveHandshake(IO.Stream stream, ref ByteField20 infoDigest)
		{
			// read in protocol string
			byte[] protocolVersionLength = new byte[1];
			if ( stream.Read( protocolVersionLength, 0, protocolVersionLength.Length ) != protocolVersionLength.Length )
				throw new System.Exception( "Invalid handshake protocol" );
			if ( protocolVersionLength[0] != 19 )
				throw new System.Exception( "Invalid handshake protocol" );
			byte[] protocolBytes = new byte[ protocolVersionLength[ 0 ] ];
			if ( stream.Read( protocolBytes, 0, protocolBytes.Length ) != protocolBytes.Length )
				throw new System.Exception( "Invalid handshake protocol" );
			string protocol = System.Text.ASCIIEncoding.ASCII.GetString(protocolBytes, 0, protocolBytes.Length);
			if (protocol != protocolString)
				throw new System.Exception( "Invalid handshake protocol" );

			// 8 zeros
			byte[] zeroes = new byte[ 8 ];
			if ( stream.Read( zeroes, 0, zeroes.Length ) != zeroes.Length )
				throw new System.Exception( "Invalid handshake protocol" );

			// SHA digest
			stream.Read(infoDigest.Data, 0, infoDigest.Data.Length);
		}
Пример #10
0
        /// <summary>
        /// Parses the response from the tracker, and updates the peer list
        /// </summary>
        /// <param name="stream">IO stream from response</param>
        private void ParseTrackerResponse(IO.Stream stream)
        {
            this.peerList.Clear();

/*
 *                      // because the response stream does not support seeking, we copy the contents to a memorystream
 *                      // to send to the bencoder. This shouldnt cause too much of a performance penalty as it shouldnt
 *                      // be too large anyway.
 *                      byte[] data = new byte[ 1024 ];
 *                      IO.MemoryStream responseStream = new IO.MemoryStream();
 *                      int dataRead = 0;
 *
 *                      while ((dataRead = stream.Read(data, 0, data.Length)) > 0)
 *                      {
 *                              responseStream.Write(data, 0, dataRead);
 *                      }
 *
 *                      responseStream.Seek(0, IO.SeekOrigin.Begin);
 */
            ///

            BEncode.Dictionary dic = BEncode.NextDictionary(stream);

            // note: sometimes IPs can be duplicated in quick disconnection, so there is a check for any duplications

            if (dic.Contains("failure reason"))
            {
                throw new IO.IOException("Tracker connection failed: " + dic.GetString("failure reason"));
            }
            else
            {
                this.updateInterval = dic.GetInteger("interval");

                BEncode.Element peers = dic["peers"];

                if (peers is BEncode.List)
                {
                    // peer list comes as a list of dictionaries
                    BEncode.List dicList = (BEncode.List)peers;

                    foreach (BEncode.Dictionary dicPeer in dicList)
                    {
                        ByteField20     peerId   = new ByteField20(dicPeer.GetBytes("peer id"));
                        string          peerIp   = dicPeer.GetString("ip");
                        int             port     = dicPeer.GetInteger("port");
                        PeerInformation peerinfo = new PeerInformation(peerIp, port, peerId);

                        if (!this.peerList.Contains(peerinfo))
                        {
                            this.peerList.Add(peerinfo);
                        }
                    }
                }
                else if (peers is BEncode.String)
                {
                    // else its compressed (this is pretty common)
                    byte[] compactPeers = ((BEncode.String)peers).Data;

                    for (int i = 0; i < compactPeers.Length; i += 6)
                    {
                        int ip1 = 0xFF & compactPeers[i];
                        int ip2 = 0xFF & compactPeers[i + 1];
                        int ip3 = 0xFF & compactPeers[i + 2];
                        int ip4 = 0xFF & compactPeers[i + 3];
                        int po1 = 0xFF & compactPeers[i + 4];
                        int po2 = 0xFF & compactPeers[i + 5];

                        string          peerIp   = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
                        int             port     = (po1 * 256) + po2;
                        PeerInformation peerinfo = new PeerInformation(peerIp, port);

                        if (!this.peerList.Contains(peerinfo))
                        {
                            this.peerList.Add(peerinfo);
                        }
                    }
                }
                else
                {
                    throw new TrackerException("Unexcepted error");
                }
            }
        }
Пример #11
0
		/// <summary>
		/// This *must* be called before any operations are performed. This should be in the constructor, but as it can be a time-consuming process
		/// it was decided against. This analyzes the file to look for which pieces are downloaded, or if the torrent has just started it will create the
		/// new, empty files.
		/// </summary>
		/// <param name="callback">Callback delegate to inform the caller of the progress</param>
		public void CheckIntegrity( bool forced, CheckIntegrityCallback callback)
		{
			// if their already is a piece file in the application directory, load it from there. (unless it is forced where is has to do it)
			if ( forced || !GetPieceInfoFromFile(callback))
			{
				int dataPosition = 0, filePosition = 0;
				int i = 0;
				byte[] data = new byte[this.infofile.GetPieceLength(0)];
				Crypto.SHA1 sha = Crypto.SHA1CryptoServiceProvider.Create();

				for (int currentFile=0; currentFile<this.infofile.FileCount; ++currentFile)
				{
					int fileLength = this.infofile.GetFileLength(currentFile);
					string path = this.infofile.GetFileName(currentFile);

					IO.FileInfo fileInfo = new IO.FileInfo(path);
				
					if (!fileInfo.Exists)
					{
						// create the file if it does not exist
						this.CreateEmptyFile(fileInfo, fileLength);

						int fileDataLeft = 0;

						if (dataPosition > 0)
						{
							// if dataPosition does not equal zero, meaning we have some of a piece from the last file. This automatically fails,
							// and we move onto the next piece.
							i++;
							fileDataLeft = fileLength - (this.infofile.GetPieceLength(0) - dataPosition);
						}
						else
							fileDataLeft = fileLength - filePosition;

						int numPieces = fileDataLeft / this.infofile.GetPieceLength(0);
						i += numPieces;
						if (fileDataLeft % this.infofile.GetPieceLength(0) > 0)
						{
							// set the next file's filePosition, and fail the next piece
							filePosition = this.infofile.GetPieceLength(i) - (fileDataLeft % this.infofile.GetPieceLength(i));
							i++;
						}
						else
						{
							filePosition = 0;
						}

						dataPosition = 0;

						if (callback != null)
							callback(this, i, false, ((float)(i+1)/(float)this.infofile.PieceCount) * 100.0f);

						// move onto next file
						continue;
					}
					else
					{
						// check the length, otherwise truncate it
						if (fileInfo.Length != fileLength)
							this.TruncateFile(fileInfo, fileLength);

						// open the file, start checking.
						IO.FileStream fstream = fileInfo.OpenRead();

						while (filePosition < fileLength)
						{
							int dataToRead = System.Math.Min(fileLength - filePosition, this.infofile.GetPieceLength(i) - dataPosition);
							byte[] tempData = new byte[dataToRead];
							fstream.Read(tempData, 0, tempData.Length);
					
							if (dataToRead + dataPosition >= this.infofile.GetPieceLength(i))
							{
								// piece finished
								System.Array.Copy(tempData, 0, data, dataPosition, dataToRead);
								sha.ComputeHash(data, 0, this.infofile.GetPieceLength(i));

								ByteField20 final = new ByteField20(sha.Hash);
								bool good = final.Equals( this.infofile.GetSHADigest(i) );
				
								if (!good) // if piece is good we can subtract it from the bytes left to download
									numBytesLeft += this.infofile.GetPieceLength(i);
					
								this.piecesDownloaded.Set(i, good);

								if (callback != null)
									callback(this, i, good, ((float)(i+1)/(float)this.infofile.PieceCount) * 100.0f);

								i++;
								dataPosition = 0;
							}
							else
							{
								System.Array.Copy(tempData, 0, data, dataPosition, dataToRead);
								dataPosition += dataToRead;
							}

							filePosition += dataToRead;
						}

						filePosition = 0;
						fstream.Close();
					}
				}
			}

			if (this.PercentChanged != null)
				this.PercentChanged(this, this.PercentComplete);
		}
Пример #12
0
        private void OnAccept(System.IAsyncResult result)
        {
            Sockets.Socket socket;

            try
            {
                // Accept connections from other peers, find the appropriate torrent and add the peer to it
                socket = this.mListener.EndAccept(result);
            }
            catch (System.Exception)
            {
                if (this.mListener != null)
                {
                    this.mListener.Close();
                }
                this.mListener = null;
                return;
            }

            try
            {
                ByteField20           infoDigest = new ByteField20(), peerId = new ByteField20();
                Sockets.NetworkStream netStream = new Sockets.NetworkStream(socket, true);

                PeerProtocol.ReceiveHandshake(netStream, ref infoDigest);

                Torrent torrent = this.FindTorrent(infoDigest);

                if (torrent != null)
                {
                    // found it, finish handshaking and add the peer to the list
                    PeerProtocol.SendHandshake(netStream, torrent.Metainfo.InfoDigest);
                    PeerProtocol.SendPeerId(netStream, mLocalPeerId);

                    if (!PeerProtocol.ReceivePeerId(netStream, ref peerId))
                    {                     // NAT check, discard
                        socket.Close();
                    }
                    else
                    {
                        if (!peerId.Equals(mLocalPeerId))                             // make sure we aren't connecting to ourselves
                        {
                            Net.IPEndPoint  endPoint        = (Net.IPEndPoint)socket.RemoteEndPoint;
                            PeerInformation peerInformation = new PeerInformation(endPoint.Address.ToString(), endPoint.Port, peerId);

                            // add the peer to the torrent
                            torrent.AddPeer(socket, netStream, peerInformation);
                        }
                        else
                        {
                            socket.Close();
                        }
                    }
                }
                else
                {
                    socket.Close();
                }
            }
            catch (System.Exception e)
            {
                Config.LogException(e);
                socket.Close();
            }

            this.mListener.BeginAccept(new System.AsyncCallback(OnAccept), null);
        }
Пример #13
0
        /// <summary>
        /// This *must* be called before any operations are performed. This should be in the constructor, but as it can be a time-consuming process
        /// it was decided against. This analyzes the file to look for which pieces are downloaded, or if the torrent has just started it will create the
        /// new, empty files.
        /// </summary>
        /// <param name="callback">Callback delegate to inform the caller of the progress</param>
        public void CheckIntegrity(bool forced, CheckIntegrityCallback callback)
        {
            // if their already is a piece file in the application directory, load it from there. (unless it is forced where is has to do it)
            if (forced || !GetPieceInfoFromFile(callback))
            {
                int         dataPosition = 0, filePosition = 0;
                int         i    = 0;
                byte[]      data = new byte[this.infofile.GetPieceLength(0)];
                Crypto.SHA1 sha  = Crypto.SHA1CryptoServiceProvider.Create();

                for (int currentFile = 0; currentFile < this.infofile.FileCount; ++currentFile)
                {
                    int    fileLength = this.infofile.GetFileLength(currentFile);
                    string path       = this.infofile.GetFileName(currentFile);

                    IO.FileInfo fileInfo = new IO.FileInfo(path);

                    if (!fileInfo.Exists)
                    {
                        // create the file if it does not exist
                        this.CreateEmptyFile(fileInfo, fileLength);

                        int fileDataLeft = 0;

                        if (dataPosition > 0)
                        {
                            // if dataPosition does not equal zero, meaning we have some of a piece from the last file. This automatically fails,
                            // and we move onto the next piece.
                            i++;
                            fileDataLeft = fileLength - (this.infofile.GetPieceLength(0) - dataPosition);
                        }
                        else
                        {
                            fileDataLeft = fileLength - filePosition;
                        }

                        int numPieces = fileDataLeft / this.infofile.GetPieceLength(0);
                        i += numPieces;
                        if (fileDataLeft % this.infofile.GetPieceLength(0) > 0)
                        {
                            // set the next file's filePosition, and fail the next piece
                            filePosition = this.infofile.GetPieceLength(i) - (fileDataLeft % this.infofile.GetPieceLength(i));
                            i++;
                        }
                        else
                        {
                            filePosition = 0;
                        }

                        dataPosition = 0;

                        if (callback != null)
                        {
                            callback(this, i, false, ((float)(i + 1) / (float)this.infofile.PieceCount) * 100.0f);
                        }

                        // move onto next file
                        continue;
                    }
                    else
                    {
                        // check the length, otherwise truncate it
                        if (fileInfo.Length != fileLength)
                        {
                            this.TruncateFile(fileInfo, fileLength);
                        }

                        // open the file, start checking.
                        IO.FileStream fstream = fileInfo.OpenRead();

                        while (filePosition < fileLength)
                        {
                            int    dataToRead = System.Math.Min(fileLength - filePosition, this.infofile.GetPieceLength(i) - dataPosition);
                            byte[] tempData   = new byte[dataToRead];
                            fstream.Read(tempData, 0, tempData.Length);

                            if (dataToRead + dataPosition >= this.infofile.GetPieceLength(i))
                            {
                                // piece finished
                                System.Array.Copy(tempData, 0, data, dataPosition, dataToRead);
                                sha.ComputeHash(data, 0, this.infofile.GetPieceLength(i));

                                ByteField20 final = new ByteField20(sha.Hash);
                                bool        good  = final.Equals(this.infofile.GetSHADigest(i));

                                if (!good)                                 // if piece is good we can subtract it from the bytes left to download
                                {
                                    numBytesLeft += this.infofile.GetPieceLength(i);
                                }

                                this.piecesDownloaded.Set(i, good);

                                if (callback != null)
                                {
                                    callback(this, i, good, ((float)(i + 1) / (float)this.infofile.PieceCount) * 100.0f);
                                }

                                i++;
                                dataPosition = 0;
                            }
                            else
                            {
                                System.Array.Copy(tempData, 0, data, dataPosition, dataToRead);
                                dataPosition += dataToRead;
                            }

                            filePosition += dataToRead;
                        }

                        filePosition = 0;
                        fstream.Close();
                    }
                }
            }

            if (this.PercentChanged != null)
            {
                this.PercentChanged(this, this.PercentComplete);
            }
        }
Пример #14
0
 public static bool ReceivePeerId(IO.Stream stream, ref ByteField20 peerId)
 {
     return(stream.Read(peerId.Data, 0, peerId.Data.Length) > 0);
 }
Пример #15
0
        /// <summary>Constructs a MetainfoFile</summary>
        /// <param name="istream">Stream to read data from</param>
        public MetainfoFile(IO.Stream istream)
        {
            BEncode.Dictionary mainDictionary = (BEncode.Dictionary)BEncode.NextElement(istream);
            this.announceUrl = mainDictionary.GetString(new BEncode.String("announce"));

            if (mainDictionary.Contains("comment"))
            {
                this.comment = mainDictionary.GetString("comment");
            }
            if (mainDictionary.Contains("created by"))
            {
                this.createdBy = mainDictionary.GetString("created by");
            }
            if (mainDictionary.Contains("creation date"))
            {
                int creation = mainDictionary.GetInteger("creation date");
                this.creationDate = new System.DateTime(1970, 1, 1, 0, 0, 0);
                this.creationDate = this.creationDate.AddSeconds(creation);
            }

            BEncode.Dictionary infoDictionary = mainDictionary.GetDictionary("info");
            this.name        = infoDictionary.GetString("name");
            this.pieceLength = infoDictionary.GetInteger("piece length");

            this.pieceFileName = this.name.ToLower().Replace(' ', '_');

            // Get SHA digests
            byte[] pieces    = infoDictionary.GetBytes("pieces");
            int    numPieces = pieces.Length / 20;

            this.shaDigestList.Capacity = numPieces;

            for (int i = 0; i < numPieces; ++i)
            {
                this.shaDigestList.Add(new ByteField20(pieces, i * 20));
            }

            // Get filenames and lengths
            if (infoDictionary.Contains("length"))
            {
                // one file
                this.fileList.Add(name);

                int fileLength = infoDictionary.GetInteger("length");
                this.fileLengthList.Add(fileLength);
                this.totalSize = fileLength;
            }
            else
            {
                // multiple files - a list of dictionaries containing the filename and length
                BEncode.List files = infoDictionary.GetList("files");
                this.fileList.Capacity = this.fileLengthList.Capacity = files.Count;
                this.totalSize         = 0;

                foreach (BEncode.Dictionary fileDic in files)
                {
                    BEncode.List pathList = fileDic.GetList("path");
                    string       path     = this.name + IO.Path.DirectorySeparatorChar;

                    for (int i = 0; i < pathList.Count - 1; ++i)
                    {
                        path += pathList[i].ToString() + IO.Path.DirectorySeparatorChar;
                    }

                    path += pathList[pathList.Count - 1];

                    this.fileList.Add(path);

                    int fileLength = fileDic.GetInteger("length");
                    this.fileLengthList.Add(fileLength);
                    this.totalSize += fileLength;
                }
            }

            // calculate the SHA-1 digest of the info dictionary - this is required for the tracker protocol
            istream.Seek(infoDictionary.Position, IO.SeekOrigin.Begin);
            byte[] infoData = new byte[infoDictionary.Length];
            istream.Read(infoData, 0, infoData.Length);

            this.infoDigest = ByteField20.ComputeSHAHash(infoData);
        }
Пример #16
0
 public static void SendPeerId(IO.Stream netStream, ByteField20 peerId)
 {
     netStream.Write(peerId.Data, 0, peerId.Data.Length);
 }
Пример #17
0
		private void OnAccept(System.IAsyncResult result)
		{
			Sockets.Socket socket;

			try
			{
				// Accept connections from other peers, find the appropriate torrent and add the peer to it
				socket = this.mListener.EndAccept(result);
			}
			catch (System.Exception)
			{
				if (this.mListener != null)
					this.mListener.Close();
				this.mListener = null;
				return;
			}

			try
			{
				ByteField20 infoDigest = new ByteField20(), peerId = new ByteField20();
				Sockets.NetworkStream netStream = new Sockets.NetworkStream(socket, true);
				
				PeerProtocol.ReceiveHandshake(netStream, ref infoDigest);

				Torrent torrent = this.FindTorrent(infoDigest);

				if (torrent != null)
				{
					// found it, finish handshaking and add the peer to the list
					PeerProtocol.SendHandshake(netStream, torrent.Metainfo.InfoDigest);
					PeerProtocol.SendPeerId(netStream, mLocalPeerId );

					if ( !PeerProtocol.ReceivePeerId( netStream, ref peerId ))
					{ // NAT check, discard
						socket.Close();
					}
					else
					{
						if ( !peerId.Equals( mLocalPeerId ) ) // make sure we aren't connecting to ourselves
						{
							Net.IPEndPoint endPoint = (Net.IPEndPoint)socket.RemoteEndPoint;
							PeerInformation peerInformation = new PeerInformation( endPoint.Address.ToString(), endPoint.Port, peerId );

							// add the peer to the torrent
							torrent.AddPeer( socket, netStream, peerInformation );
						}
						else
							socket.Close();
					}
				}
				else
					socket.Close();
			}
			catch (System.Exception e)
			{
				Config.LogException( e );
				socket.Close();
			}

			this.mListener.BeginAccept(new System.AsyncCallback(OnAccept), null);
		}
Пример #18
0
		private static ByteField20 DefaultCalculatePeerId()
		{
			// calculate our peer id
			string peerIdString = "-TN" + string.Format("{0:00}", Config.MajorVersionNumber)
				+ string.Format("{0:00}", Config.MinorVersionNumber) + "-";
			
			ByteField20 peerId = new ByteField20();
			System.Array.Copy(System.Text.ASCIIEncoding.ASCII.GetBytes(peerIdString), 0, peerId.Data, 0, peerIdString.Length);
			
			const string peerChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
			
			System.Random rand = new System.Random();

			for (int i=peerIdString.Length; i<20; ++i)
			{
				peerId.Data[i] = (byte)peerChars[rand.Next(0, peerChars.Length-1)];
			}

			return peerId;
		}
Пример #19
0
		public Session( ByteField20 localPeerId )
		{
			mLocalPeerId = localPeerId;
			if ( Config.ActiveConfig.ProxyURL != "" ) // set web proxy
			{
				System.Net.WebRequest.DefaultWebProxy = new Net.WebProxy( Config.ActiveConfig.ProxyURL );
			}
			SetAllowUnsafeHeaderParsing20();
			this.StartServer();
		}
Пример #20
0
		public Torrent FindTorrent(ByteField20 infoDigest)
		{
			lock ( this.mTorrents )
			{
				foreach ( Torrent torrent in this.mTorrents )
				{
					if (torrent.Metainfo.InfoDigest.Equals(infoDigest))
					{
						return torrent;
					}
				}
			
				return null;
			}
		}
Пример #21
0
		/// <summary>Constructs a MetainfoFile</summary>
		/// <param name="istream">Stream to read data from</param>
		public MetainfoFile(IO.Stream istream)
		{
			BEncode.Dictionary mainDictionary = (BEncode.Dictionary)BEncode.NextElement(istream);
			this.announceUrl = mainDictionary.GetString(new BEncode.String("announce"));
			
			if (mainDictionary.Contains("comment"))
				this.comment = mainDictionary.GetString("comment");
			if (mainDictionary.Contains("created by"))
				this.createdBy = mainDictionary.GetString("created by");
			if (mainDictionary.Contains("creation date"))
			{
				int creation = mainDictionary.GetInteger("creation date");
				this.creationDate = new System.DateTime(1970, 1, 1, 0, 0, 0);
				this.creationDate = this.creationDate.AddSeconds(creation);
			}
			
			BEncode.Dictionary infoDictionary = mainDictionary.GetDictionary("info");
			this.name = infoDictionary.GetString("name");
			this.pieceLength = infoDictionary.GetInteger("piece length");

			this.pieceFileName = this.name.ToLower().Replace(' ', '_');
			
			// Get SHA digests
			byte[] pieces = infoDictionary.GetBytes("pieces");
			int numPieces = pieces.Length / 20;
			
			this.shaDigestList.Capacity = numPieces;
			
			for (int i=0; i<numPieces; ++i)
			{
				this.shaDigestList.Add( new ByteField20(pieces, i*20) );
			}
			
			// Get filenames and lengths
			if (infoDictionary.Contains("length"))
			{
				// one file
				this.fileList.Add(name);
				
				int fileLength = infoDictionary.GetInteger("length");
				this.fileLengthList.Add(fileLength);
				this.totalSize = fileLength;
			}
			else
			{
				// multiple files - a list of dictionaries containing the filename and length
				BEncode.List files = infoDictionary.GetList("files");
				this.fileList.Capacity = this.fileLengthList.Capacity = files.Count;
				this.totalSize = 0;
				
				foreach (BEncode.Dictionary fileDic in files)
				{
					BEncode.List pathList = fileDic.GetList("path");
					string path = this.name + IO.Path.DirectorySeparatorChar;
					
					for (int i=0; i<pathList.Count-1; ++i)
					{
						path += pathList[i].ToString() + IO.Path.DirectorySeparatorChar;
					}

					path += pathList[ pathList.Count-1 ];
					
					this.fileList.Add(path);
					
					int fileLength = fileDic.GetInteger("length");
					this.fileLengthList.Add(fileLength);
					this.totalSize += fileLength;
				}
			}
			
			// calculate the SHA-1 digest of the info dictionary - this is required for the tracker protocol
			istream.Seek(infoDictionary.Position, IO.SeekOrigin.Begin);
			byte[] infoData = new byte[ infoDictionary.Length ];
			istream.Read(infoData, 0, infoData.Length);
			
			this.infoDigest = ByteField20.ComputeSHAHash(infoData);
		}
Пример #22
0
		/// <summary>
		/// Parses the response from the tracker, and updates the peer list
		/// </summary>
		/// <param name="stream">IO stream from response</param>
		private void ParseTrackerResponse(IO.Stream stream)
		{
			this.peerList.Clear();
/*
			// because the response stream does not support seeking, we copy the contents to a memorystream
			// to send to the bencoder. This shouldnt cause too much of a performance penalty as it shouldnt
			// be too large anyway.
			byte[] data = new byte[ 1024 ];
			IO.MemoryStream responseStream = new IO.MemoryStream();
			int dataRead = 0;

			while ((dataRead = stream.Read(data, 0, data.Length)) > 0)
			{
				responseStream.Write(data, 0, dataRead);
			}

			responseStream.Seek(0, IO.SeekOrigin.Begin);
*/
			///

			BEncode.Dictionary dic = BEncode.NextDictionary(stream);

			// note: sometimes IPs can be duplicated in quick disconnection, so there is a check for any duplications
			
			if (dic.Contains("failure reason"))
			{
				throw new IO.IOException("Tracker connection failed: " + dic.GetString("failure reason"));
			}
			else
			{
				this.updateInterval = dic.GetInteger("interval");

				BEncode.Element peers = dic["peers"];

				if (peers is BEncode.List)
				{
					// peer list comes as a list of dictionaries
					BEncode.List dicList = (BEncode.List)peers;

					foreach (BEncode.Dictionary dicPeer in dicList)
					{
						ByteField20 peerId = new ByteField20(dicPeer.GetBytes("peer id"));
						string peerIp = dicPeer.GetString("ip");
						int port = dicPeer.GetInteger("port");
						PeerInformation peerinfo = new PeerInformation(peerIp, port, peerId);

						if (!this.peerList.Contains(peerinfo))
							this.peerList.Add(peerinfo);
					}
				}
				else if (peers is BEncode.String)
				{
					// else its compressed (this is pretty common)
					byte[] compactPeers = ((BEncode.String)peers).Data;

					for (int i=0; i<compactPeers.Length; i += 6)
					{
						int	ip1 = 0xFF & compactPeers[i];
						int	ip2 = 0xFF & compactPeers[i+1];
						int	ip3 = 0xFF & compactPeers[i+2];
						int	ip4 = 0xFF & compactPeers[i+3];
						int	po1 = 0xFF & compactPeers[i+4];
						int	po2 = 0xFF & compactPeers[i+5];

						string peerIp = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
						int	port = (po1 * 256) + po2;
						PeerInformation peerinfo = new PeerInformation(peerIp, port);

						if (!this.peerList.Contains(peerinfo))
							this.peerList.Add(peerinfo);
					}
				}
				else
					throw new TrackerException("Unexcepted error");
			}
		}
Пример #23
0
		public static void SendPeerId(IO.Stream netStream, ByteField20 peerId)
		{
			netStream.Write(peerId.Data, 0, peerId.Data.Length);
		}
Пример #24
0
		/// <summary>
		/// Helper thread method to start the connection to peers
		/// </summary>
		/// <param name="state"></param>
		private void StartPeerConnectionThread(System.IAsyncResult result)
		{
			object[] objs = (object[])result.AsyncState;
			Sockets.Socket socket = (Sockets.Socket)objs[0];
			PeerInformation peerinfo = (PeerInformation)objs[1];
			ByteField20 infoDigest = new ByteField20(), peerId = new ByteField20();
			Sockets.NetworkStream netStream;

			try
			{
				socket.EndConnect(result);

				netStream = new Sockets.NetworkStream(socket, true);

				// send handshake info
				PeerProtocol.SendHandshake(netStream, this.infofile.InfoDigest);
				PeerProtocol.ReceiveHandshake(netStream, ref infoDigest);
				PeerProtocol.SendPeerId(netStream, this.mSession.LocalPeerID );

				if (!PeerProtocol.ReceivePeerId(netStream, ref peerId))
				{ // NAT check
					socket.Close();
					return;
				}

				// check info digest matches and we are not attempting to connect to ourself
				if ( infoDigest.Equals( this.infofile.InfoDigest ) && !peerId.Equals( this.mSession.LocalPeerID ) )
				{
					peerinfo.ID = peerId;
					this.AddPeer(socket, netStream, peerinfo);
				}
				else // info digest doesn't match, close the connection
					socket.Close();
			}
			catch (System.Exception e)
			{
				Config.LogException(e);
				// die if the connection failed
				if (socket != null)
					socket.Close();
				return;
			}
		}
Пример #25
0
		public static bool ReceivePeerId(IO.Stream stream, ref ByteField20 peerId)
		{
			return stream.Read(peerId.Data, 0, peerId.Data.Length) > 0;
		}