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; } } }
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); }