Example #1
0
        /// <summary>
        /// Computes the "info_hash" of the provided torrent (BDictionary).
        /// </summary>
        /// <param name="torrent">The BDicionary containing the torrent file.</param>
        /// <returns>An InfoHash object with the SHA1 hash.</returns>
        public static InfoHash ComputeInfoHash(BDictionary torrent)
        {
            IBValue info = null;

            //looks for the "info" dictionary
            foreach (KeyValuePair <string, IBValue> item in torrent.Items)
            {
                if (item.Key == "info" && item.Value is BDictionary)
                {
                    info = item.Value;
                    break;
                }
            }

            //if found, then computes the SHA1 hash and returns it
            if (info != null)
            {
                //the info_hash is the sha1 hash of the bencoded "info" dictionary, so gets it
                string      bencoded = info.ToBEncodedString();
                List <byte> bytes    = new List <byte>(bencoded.Length);

                //adds its bytes to a list to be used in the ComputeHash function
                foreach (char c in info.ToBEncodedString())
                {
                    bytes.Add((byte)c);
                }

                SHA1 sha1 = SHA1.Create();
                return(InfoHash.FromByteArray(sha1.ComputeHash(bytes.ToArray())));
            }

            //if the "info" dictionary is not found, then returns an empty InfoHash to avoid exceptions...
            return(InfoHash.FromByteArray(new byte[] { }));
        }
Example #2
0
        /// <summary>
        /// 解读一条用户连接消息。
        /// </summary>
        /// <param name="message">待解读的消息。</param>
        /// <param name="infoHash">解读出的 InfoHash。</param>
        /// <param name="bitTorrentClientPort">解读出的用户监听端口。</param>
        /// <exception cref="System.ArgumentException">解读的不是用户连接消息时发生。</exception>
        public static void GetPeerMessageContent(KMessage message, out InfoHash infoHash, out ushort bitTorrentClientPort)
        {
            //if (message.Content.Data.Length != 22)
            //{
            //    throw new ArgumentException("要解读的不是一条用户连接消息。");
            //}
            //infoHash = InfoHash.FromByteArray(message.Content.Data.Take(20).ToArray());
            //bitTorrentClientPort = BitConverter.ToUInt16(message.Content.Data, 20);
            BEncodedDictionary dictionary;

            try
            {
                dictionary           = BEncodedValue.Decode <BEncodedDictionary>(message.Content.Data);
                infoHash             = InfoHash.FromByteArray((dictionary["infohash"] as BEncodedString).TextBytes);
                bitTorrentClientPort = (ushort)((dictionary["bt client port"] as BEncodedNumber).Number);
            }
            catch (Exception)
            {
                throw new ArgumentException("附带数据不是用户连接消息数据。");
            }
            // 这里遇到了一个奇怪的问题,就是编解码的时候
#warning 系统的编解码和网络的编解码字节序可能不同!
            // BitConverter 的编解码和网络的编解码顺序可能不同
            // 但是奇怪的是,即使这样,KMessage 还能正常解码,地址大多数是正常的,但是端口大多数是不正常的
            // 即使是端口,也只是低2字节被颠倒了,高2字节都为零所以无法验证
            // 所以目前的临时方法是直接将低2字节颠倒回来,而且只保留低2字节
            // 再次测试后发现似乎是 μTorrent 自己的诈和……(以前)第一次收到的是错误的(后来在调试的时候,第一次好像也对了),接下来收到的都是正确的……
            //var b1 = (byte)((bitTorrentClientPort & 0x0000ff00) >> 8);
            //var b2 = (byte)(bitTorrentClientPort & 0x000000ff);
            //bitTorrentClientPort = (int)(((int)b2 << 8) + b1);
        }
Example #3
0
        /// <summary>
        /// 解码连接到接入点时收到的字节数组,并应用这些信息。
        /// </summary>
        /// <param name="data">收到的数据。</param>
        ///// <param name="sendPeerEnter">解码过程中是否应该广播 PeerEnterNetwork 消息。</param>
        /// <exception cref="System.FormatException">解码失败时发生。</exception>
        /// <remarks>
        /// 需要发送 PeerEnterNetwork 消息的情况会发生于:A开启客户端和μT,B开启客户端和μT,A(用户列表非空)再尝试连接B,此时如果B并没有保存全网的用户列表,那么A就要广播 PeerEnterNetwork。
        /// </remarks>
        private void DecodeTargetInformation(byte[] data)
        {
            // 如果对方发过来的是空,那么就肯定不会有数据啦
            if (data.Length > 0)
            {
                BEncodedDictionary dictionary = BEncodedDictionary.Decode(data) as BEncodedDictionary;
                if (dictionary == null)
                {
                    throw new FormatException("无法解码。");
                }
                BEncodedList       connList  = dictionary["connections"] as BEncodedList;
                BEncodedDictionary peersDict = dictionary["peers"] as BEncodedDictionary;

                // 规范 v1.2
                // 先确认自己,同时 if ... 是兼容老版的通信
                if (dictionary.ContainsKey("your endpoint"))
                {
                    BEncodedDictionary yourEndPoint = dictionary["your endpoint"] as BEncodedDictionary;
                    var ip   = new IPAddress((yourEndPoint["ip"] as BEncodedString).TextBytes);
                    var port = BitConverter.ToUInt16((yourEndPoint["port"] as BEncodedString).TextBytes, 0);
                    // 分别设置 KClient、TrackerServer 和 BT 客户端的自己
                    SetLocalEndPoint(new IPEndPoint(ip, port));
                    TrackerServer.SetLocalEndPoint(new IPEndPoint(ip, TrackerServer.LocalEndPoint.Port));
                    TrackerServer.SetMyself(new IPEndPoint(ip, TrackerServer.Myself.EndPoint.GetPortNumber()));

                    this.FreeToGo          = true;
                    TrackerServer.FreeToGo = true;
                }

                // ...
                lock (ConnectionList)
                {
                    foreach (var item in connList)
                    {
                        var       d   = item as BEncodedDictionary;
                        KEndPoint kep = KEndPoint.Empty;
                        kep.SetAddress((d["ip"] as BEncodedString).TextBytes);
                        kep.SetPort((int)BitConverter.ToUInt16((d["port"] as BEncodedString).TextBytes, 0));
                        try
                        {
                            AddToConnectionList(kep);
                        }
                        catch (Exception)
                        {
                        }
                    }
                }

                // 如果已经有用户登记了,那么应该广播
                if (TrackerServer.Seeds.Count > 0)
                {
                    lock (TrackerServer.Seeds)
                    {
                        foreach (var kv in TrackerServer.Seeds)
                        {
                            // 广播消息
                            BroadcastMyselfAddAsPeer(kv.Key);
                        }
                    }
                }
                lock (TrackerServer.Seeds)
                {
                    foreach (var kv in peersDict)
                    {
                        InfoHash    infoHash = InfoHash.FromByteArray(kv.Key.TextBytes);
                        List <Peer> peers    = new List <Peer>((kv.Value as BEncodedList).Count);
                        foreach (var item in (kv.Value as BEncodedList))
                        {
                            var       d   = item as BEncodedDictionary;
                            KEndPoint kep = KEndPoint.Empty;
                            kep.SetAddress((d["ip"] as BEncodedString).TextBytes);
                            kep.SetPort((int)BitConverter.ToUInt16((d["port"] as BEncodedString).TextBytes, 0));
                            Peer peer = Peer.Create(kep);
                            peers.Add(peer);
                        }
                        try
                        {
                            TrackerServer.Seeds.Add(infoHash, peers);
                        }
                        catch (Exception)
                        {
                        }
                    }
                }
            }
            else
            {
                Logger.Log("待解码的数据为空,这意味着对方客户端目前持有的连接列表和用户列表为空。");
            }
        }