private static List <Bencoding> DecodeList(Stream s)
        {
            List <Bencoding> list = new List <Bencoding>();

            while (true)
            {
                Bencoding b = Bencoding.Decode(s);

                if (b == null)
                {
                    break;
                }

                list.Add(b);
            }

            return(list);
        }
        private static Dictionary <string, Bencoding> DecodeDictionary(Stream s)
        {
            Dictionary <string, Bencoding> dict = new Dictionary <string, Bencoding>();

            while (true)
            {
                Bencoding b = Bencoding.Decode(s);

                if (b == null)
                {
                    break;
                }

                if (b.Type != BencodingType.String)
                {
                    throw new Exception("Invalid bencoded dictionary format.");
                }

                dict.Add(b.ValueString, Decode(s));
            }

            return(dict);
        }
        protected override void UpdateTracker(TrackerClientEvent @event, IPEndPoint clientEP)
        {
            string queryString;

            queryString = "?info_hash=" + Uri.EscapeDataString(Encoding.ASCII.GetString(_infoHash)) +
                          "&peer_id=" + Uri.EscapeDataString(Encoding.ASCII.GetString(_clientID.PeerID));

            switch (clientEP.Address.ToString())
            {
            case "0.0.0.0":
            case "127.0.0.1":
            case "::":
            case "::1":
                break;

            default:
                if (clientEP.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                {
                    queryString += "&ipv6=" + clientEP.Address.ToString();
                }
                else
                {
                    queryString += "&ip=" + clientEP.Address.ToString();
                }

                break;
            }

            queryString += "&port=" + clientEP.Port +
                           "&uploaded=0&downloaded=0&left=0&corrupt=0" +
                           "&key=" + BitConverter.ToString(_clientID.ClientKey).Replace("-", "");

            switch (@event)
            {
            case TrackerClientEvent.Started:
                queryString += "&event=started";
                break;

            case TrackerClientEvent.Stopped:
                queryString += "&event=stopped";
                break;

            case TrackerClientEvent.Completed:
                queryString += "&event=completed";
                break;
            }

            queryString += "&numwant=" + _clientID.NumWant;

            if (_clientID.Compact)
            {
                queryString += "&compact=1";
            }
            else
            {
                queryString += "&compact=0";
            }

            if (_clientID.NoPeerID)
            {
                queryString += "&no_peer_id=1";
            }

            using (WebClientEx webClient = new WebClientEx())
            {
                webClient.Proxy     = _proxy;
                webClient.Timeout   = 30000; //30 sec timeout
                webClient.UserAgent = _clientID.HttpUserAgent;
                webClient.AddHeader("Accept-Encoding", _clientID.HttpAcceptEncoding);
                webClient.KeepAlive = false;

                using (Stream responseStream = webClient.OpenRead(_trackerURI.AbsoluteUri + queryString))
                {
                    switch (@event)
                    {
                    case TrackerClientEvent.None:
                    case TrackerClientEvent.Started:
                        Bencoding x = Bencoding.Decode(responseStream);

                        switch (x.Type)
                        {
                        case BencodingType.Dictionary:
                            _peers.Clear();

                            foreach (var item in x.ValueDictionary)
                            {
                                switch (item.Key)
                                {
                                case "peers":
                                    switch (item.Value.Type)
                                    {
                                    case BencodingType.String:
                                        ParseCompactPeersIPv4(item.Value.Value as byte[], _peers);
                                        break;

                                    case BencodingType.List:
                                        foreach (var peerObj in item.Value.ValueList)
                                        {
                                            var peer = peerObj.ValueDictionary;

                                            _peers.Add(new IPEndPoint(IPAddress.Parse(peer["ip"].ValueString), Convert.ToInt32(peer["port"].ValueInteger)));
                                        }
                                        break;
                                    }
                                    break;

                                case "peers_ipv6":
                                case "peers6":
                                    switch (item.Value.Type)
                                    {
                                    case BencodingType.String:
                                        ParseCompactPeersIPv6(item.Value.Value as byte[], _peers);
                                        break;
                                    }
                                    break;

                                case "interval":
                                    if (item.Value.Type == BencodingType.Integer)
                                    {
                                        _interval = Convert.ToInt32(item.Value.Value);
                                    }
                                    break;

                                case "min interval":
                                    if (item.Value.Type == BencodingType.Integer)
                                    {
                                        _minInterval = Convert.ToInt32(item.Value.Value);
                                    }
                                    break;
                                }
                            }
                            break;

                        default:
                            throw new TrackerClientException("Invalid data received from tracker. Expected bencoded dictionary.");
                        }
                        break;
                    }
                }
            }
        }