private void UpdateTrackerAsync(object state)
        {
            object[] parameters = state as object[];

            TrackerClient      tracker = parameters[0] as TrackerClient;
            TrackerClientEvent @event  = (TrackerClientEvent)parameters[1];
            IPEndPoint         localEP = parameters[2] as IPEndPoint;

            try
            {
                tracker.Update(@event, localEP);

                switch (@event)
                {
                case TrackerClientEvent.Started:
                case TrackerClientEvent.Completed:
                case TrackerClientEvent.None:
                    if (_lookupOnly)
                    {
                        tracker.Update(TrackerClientEvent.Stopped, localEP);
                    }

                    if (tracker.Peers.Count > 0)
                    {
                        if (_ipv4DhtNode != null)
                        {
                            _ipv4DhtNode.AddNode(tracker.Peers);
                        }

                        if (_ipv6DhtNode != null)
                        {
                            _ipv6DhtNode.AddNode(tracker.Peers);
                        }

                        DiscoveredPeers?.Invoke(this, tracker.Peers);
                    }

                    break;
                }

                tracker.CustomUpdateInterval = _customUpdateInterval;
            }
            catch
            {
                if (tracker.RetriesDone < TRACKER_MAX_RETRIES)
                {
                    tracker.CustomUpdateInterval = TRACKER_RETRY_UPDATE_INTERVAL_SECONDS;
                }
                else
                {
                    tracker.CustomUpdateInterval = TRACKER_FAILED_UPDATE_INTERVAL_SECONDS;
                }
            }
        }
        public async Task UpdateAsync(TrackerClientEvent @event, IPEndPoint clientEP)
        {
            lock (_isUpdatingLock)
            {
                if (_isUpdating)
                {
                    return;
                }

                _isUpdating = true;
            }

            try
            {
                await UpdateTrackerAsync(@event, clientEP);

                _lastException = null;
                _retriesDone   = 0;
            }
            catch (Exception ex)
            {
                if (ex.InnerException == null)
                {
                    _lastException = ex;
                }
                else
                {
                    _lastException = ex.InnerException;
                }

                _retriesDone++;
                _interval = _minInterval;

                throw;
            }
            finally
            {
                _lastClientEP = clientEP;
                _lastUpdated  = DateTime.UtcNow;

                lock (_isUpdatingLock)
                {
                    _isUpdating = false;
                }
            }
        }
示例#3
0
        private void UpdateTrackerAsync(object state)
        {
            object[] parameters = state as object[];

            TrackerClient      tracker = parameters[0] as TrackerClient;
            TrackerClientEvent @event  = (TrackerClientEvent)parameters[1];
            IPEndPoint         localEP = parameters[2] as IPEndPoint;

            try
            {
                tracker.Update(@event, localEP);

                _network.MakeConnection(tracker.Peers);
            }
            catch
            { }
        }
 protected abstract Task UpdateTrackerAsync(TrackerClientEvent @event, IPEndPoint clientEP);
 protected abstract void UpdateTracker(TrackerClientEvent @event, IPEndPoint clientEP);
        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;
                    }
                }
            }
        }
        protected override void UpdateTracker(TrackerClientEvent @event, IPEndPoint clientEP)
        {
            SocksUdpAssociateRequestHandler proxyRequestHandler = null;
            UdpClient udpClient = null;

            if (_proxy == null)
            {
                udpClient = new UdpClient(_trackerURI.Host, _trackerURI.Port);
                udpClient.Client.ReceiveTimeout = 10000;
            }
            else
            {
                switch (_proxy.Type)
                {
                case NetProxyType.Socks5:
                    proxyRequestHandler = _proxy.SocksProxy.UdpAssociate();
                    proxyRequestHandler.ReceiveTimeout = 10000;
                    break;

                case NetProxyType.Http:
                    throw new NotSupportedException("Http proxy not supported by Udp tracker.");

                default:
                    throw new NotSupportedException("Proxy type not supported by Udp tracker.");
                }
            }

            try
            {
                for (int n = 0; n < 2; n++)
                {
                    if ((_connectionID == null) || (_connectionIDExpires <= DateTime.UtcNow))
                    {
                        //GET CONNECTION ID
                        _rnd.GetBytes(_transactionID);
                        _connectionID        = GetConnectionID(udpClient, proxyRequestHandler, _transactionID);
                        _connectionIDExpires = DateTime.UtcNow.AddMinutes(1);
                    }

                    try
                    {
                        _rnd.GetBytes(_transactionID);
                        byte[] announceResponse;
                        int    announceResponseLength = GetAnnounceResponse(udpClient, proxyRequestHandler, _transactionID, _connectionID, @event, clientEP, out announceResponse);

                        byte[] buffer = new byte[4];

                        Buffer.BlockCopy(announceResponse, 8, buffer, 0, 4);
                        Array.Reverse(buffer);
                        _interval = BitConverter.ToInt32(buffer, 0);

                        Buffer.BlockCopy(announceResponse, 12, buffer, 0, 4);
                        Array.Reverse(buffer);
                        _leachers = BitConverter.ToInt32(buffer, 0);

                        Buffer.BlockCopy(announceResponse, 16, buffer, 0, 4);
                        Array.Reverse(buffer);
                        _seeders = BitConverter.ToInt32(buffer, 0);

                        _peers.Clear();

                        if (_proxy == null)
                        {
                            if (udpClient.Client.AddressFamily == AddressFamily.InterNetworkV6)
                            {
                                ParsePeersIPv6(announceResponse, announceResponseLength, _peers);
                            }
                            else
                            {
                                ParsePeersIPv4(announceResponse, announceResponseLength, _peers);
                            }
                        }
                        else
                        {
                            int x = (announceResponseLength - 26) % 6;

                            if (x == 0)
                            {
                                ParsePeersIPv4(announceResponse, announceResponseLength, _peers);
                            }
                            else
                            {
                                ParsePeersIPv6(announceResponse, announceResponseLength, _peers);
                            }
                        }

                        return;
                    }
                    catch (SocketException ex)
                    {
                        if (ex.ErrorCode != (int)SocketError.TimedOut)
                        {
                            throw new TrackerClientException(ex.Message, ex);
                        }
                    }
                }

                throw new TrackerClientException("No response from tracker.");
            }
            finally
            {
                if (proxyRequestHandler != null)
                {
                    proxyRequestHandler.Dispose();
                }

                if (udpClient != null)
                {
                    udpClient.Close();
                }
            }
        }
        private int GetAnnounceResponse(UdpClient udpClient, SocksUdpAssociateRequestHandler proxyRequestHandler, byte[] transactionID, byte[] connectionID, TrackerClientEvent @event, IPEndPoint clientEP, out byte[] response)
        {
            byte[] request = new byte[98];

            //connection_id 64bit
            Buffer.BlockCopy(connectionID, 0, request, 0, 8);

            //action 32bit
            request[11] = 1;

            //transaction_id 32bit
            Buffer.BlockCopy(transactionID, 0, request, 12, 4);

            //info_hash 20 bytes
            Buffer.BlockCopy(_infoHash, 0, request, 16, 20);

            //peer_id 20 bytes
            Buffer.BlockCopy(_clientID.PeerID, 0, request, 36, 20);

            //downloaded 64bit
            //left 64bit
            //uploaded 64bit

            //event 32bit
            request[83] = Convert.ToByte(@event);

            //ip address 32bit
            if (clientEP.Address.AddressFamily == AddressFamily.InterNetwork)
            {
                switch (clientEP.Address.ToString())
                {
                case "0.0.0.0":
                case "127.0.0.1":
                    break;

                default:
                    Buffer.BlockCopy(clientEP.Address.GetAddressBytes(), 0, request, 84, 4);
                    break;
                }
            }

            //key 32bit
            Buffer.BlockCopy(_clientID.ClientKey, 0, request, 88, 4);

            //num_want
            Buffer.BlockCopy(BitConverter.GetBytes(_clientID.NumWant), 0, request, 92, 4);

            //port 16bit
            byte[] portBuffer = BitConverter.GetBytes(clientEP.Port);
            Array.Reverse(portBuffer);
            Buffer.BlockCopy(portBuffer, 2, request, 96, 2);

            int responseLength;

            if (_proxy == null)
            {
                //SEND ANNOUNCE REQUEST
                udpClient.Send(request, request.Length);

                //RECV ANNOUNCE RESPONSE
                IPEndPoint remoteEP = null;
                response       = udpClient.Receive(ref remoteEP);
                responseLength = response.Length;
            }
            else
            {
                //SEND ANNOUNCE REQUEST
                proxyRequestHandler.SendTo(request, 0, request.Length, new SocksEndPoint(_trackerURI.Host, _trackerURI.Port));

                //RECV ANNOUNCE RESPONSE
                response = new byte[1024];
                SocksEndPoint remoteEP;
                responseLength = proxyRequestHandler.ReceiveFrom(response, 0, response.Length, out remoteEP);
            }

            //check response length
            if (responseLength < 20)
            {
                throw new TrackerClientException("Invalid response received for announce request.");
            }

            //check response transaction id
            for (int j = 0; j < 4; j++)
            {
                if (response[4 + j] != transactionID[j])
                {
                    throw new TrackerClientException("Invalid transaction id received for announce request.");
                }
            }

            //check response action
            if (response[3] != 1)
            {
                throw new TrackerClientException("Invalid action received for announce request.");
            }

            return(responseLength);
        }
        protected override async Task UpdateTrackerAsync(TrackerClientEvent @event, IPEndPoint clientEP)
        {
            SocksProxyUdpAssociateHandler proxyHandler = null;
            Socket   udpSocket = null;
            EndPoint trackerEP = new DomainEndPoint(_trackerURI.Host, _trackerURI.Port);

            if (_proxy == null)
            {
                trackerEP = await trackerEP.GetIPEndPointAsync();

                udpSocket = new Socket(trackerEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
            }
            else
            {
                switch (_proxy.Type)
                {
                case NetProxyType.Socks5:
                    proxyHandler = await(_proxy as SocksProxy).UdpAssociateAsync();
                    break;

                default:
                    throw new NotSupportedException("Proxy type is not supported by Udp tracker.");
                }
            }

            try
            {
                for (int n = 0; n < 2; n++)
                {
                    if ((_connectionId == null) || (_connectionIdExpires <= DateTime.UtcNow))
                    {
                        //GET CONNECTION ID
                        _rnd.GetBytes(_transactionID);
                        _connectionId = await GetConnectionIdAsync(udpSocket, proxyHandler, trackerEP, _transactionID);

                        _connectionIdExpires = DateTime.UtcNow.AddMinutes(1);
                    }

                    try
                    {
                        _rnd.GetBytes(_transactionID);
                        byte[] announceResponse = await GetAnnounceResponseAsync(udpSocket, proxyHandler, trackerEP, _transactionID, _connectionId, @event, clientEP);

                        byte[] buffer = new byte[4];

                        Buffer.BlockCopy(announceResponse, 8, buffer, 0, 4);
                        Array.Reverse(buffer);
                        _interval = BitConverter.ToInt32(buffer, 0);

                        Buffer.BlockCopy(announceResponse, 12, buffer, 0, 4);
                        Array.Reverse(buffer);
                        _leachers = BitConverter.ToInt32(buffer, 0);

                        Buffer.BlockCopy(announceResponse, 16, buffer, 0, 4);
                        Array.Reverse(buffer);
                        _seeders = BitConverter.ToInt32(buffer, 0);

                        _peers.Clear();

                        if (_proxy == null)
                        {
                            if (udpSocket.AddressFamily == AddressFamily.InterNetworkV6)
                            {
                                ParsePeersIPv6(announceResponse, announceResponse.Length, _peers);
                            }
                            else
                            {
                                ParsePeersIPv4(announceResponse, announceResponse.Length, _peers);
                            }
                        }
                        else
                        {
                            int x = (announceResponse.Length - 26) % 6;

                            if (x == 0)
                            {
                                ParsePeersIPv4(announceResponse, announceResponse.Length, _peers);
                            }
                            else
                            {
                                ParsePeersIPv6(announceResponse, announceResponse.Length, _peers);
                            }
                        }

                        return;
                    }
                    catch (SocketException ex)
                    {
                        if (ex.ErrorCode != (int)SocketError.TimedOut)
                        {
                            throw new TrackerClientException(ex.Message, ex);
                        }
                    }
                }

                throw new TrackerClientException("No response from tracker.");
            }
            finally
            {
                if (proxyHandler != null)
                {
                    proxyHandler.Dispose();
                }

                if (udpSocket != null)
                {
                    udpSocket.Close();
                }
            }
        }
        private async Task <byte[]> GetAnnounceResponseAsync(Socket udpSocket, SocksProxyUdpAssociateHandler proxyHandler, EndPoint trackerEP, byte[] transactionID, byte[] connectionID, TrackerClientEvent @event, IPEndPoint clientEP)
        {
            byte[] request = new byte[98];
            {
                //connection_id 64bit
                Buffer.BlockCopy(connectionID, 0, request, 0, 8);

                //action 32bit
                request[11] = 1;

                //transaction_id 32bit
                Buffer.BlockCopy(transactionID, 0, request, 12, 4);

                //info_hash 20 bytes
                Buffer.BlockCopy(_infoHash, 0, request, 16, 20);

                //peer_id 20 bytes
                Buffer.BlockCopy(_clientID.PeerID, 0, request, 36, 20);

                //downloaded 64bit
                //left 64bit
                //uploaded 64bit

                //event 32bit
                request[83] = Convert.ToByte(@event);

                //ip address 32bit
                if (clientEP.Address.AddressFamily == AddressFamily.InterNetwork)
                {
                    switch (clientEP.Address.ToString())
                    {
                    case "0.0.0.0":
                    case "127.0.0.1":
                        break;

                    default:
                        Buffer.BlockCopy(clientEP.Address.GetAddressBytes(), 0, request, 84, 4);
                        break;
                    }
                }

                //key 32bit
                Buffer.BlockCopy(_clientID.ClientKey, 0, request, 88, 4);

                //num_want
                Buffer.BlockCopy(BitConverter.GetBytes(_clientID.NumWant), 0, request, 92, 4);

                //port 16bit
                byte[] portBuffer = BitConverter.GetBytes(clientEP.Port);
                Array.Reverse(portBuffer);
                Buffer.BlockCopy(portBuffer, 2, request, 96, 2);
            }

            byte[] buffer = new byte[1024];
            int    bytesReceived;

            if (_proxy == null)
            {
                bytesReceived = await udpSocket.UdpQueryAsync(request, buffer, await trackerEP.GetIPEndPointAsync(), TIMEOUT, 3, true);
            }
            else
            {
                bytesReceived = await proxyHandler.UdpQueryAsync(request, buffer, await trackerEP.GetIPEndPointAsync(), TIMEOUT, 3, true);
            }

            //check response length
            if (bytesReceived < 20)
            {
                throw new TrackerClientException("Invalid response received for announce request.");
            }

            //check response transaction id
            for (int j = 0; j < 4; j++)
            {
                if (buffer[4 + j] != transactionID[j])
                {
                    throw new TrackerClientException("Invalid transaction id received for announce request.");
                }
            }

            //check response action
            if (buffer[3] != 1)
            {
                throw new TrackerClientException("Invalid action received for announce request.");
            }

            byte[] response = new byte[bytesReceived];
            Buffer.BlockCopy(buffer, 0, response, 0, bytesReceived);
            return(response);
        }