private void AnnounceCallback(IAsyncResult ar) { ConnectAnnounceState announceState = (ConnectAnnounceState)ar; try { if (announceState.SavedException != null) { FailureMessage = announceState.SavedException.Message; DoAnnounceComplete(false, announceState.AsyncState, new List <Peer>()); return; } UdpTrackerMessage rsp = Receive(announceState, announceState.Data); if (!(rsp is AnnounceResponseMessage)) { DoAnnounceComplete(false, announceState.AsyncState, new List <Peer>()); return; } MinUpdateInterval = ((AnnounceResponseMessage)rsp).Interval; CompleteAnnounce(rsp, announceState.AsyncState); } catch { DoAnnounceComplete(false, announceState.AsyncState, null); } }
async Task <UdpTrackerMessage> ReceiveAsync(UdpClient client, int transactionId, CancellationToken token) { while (!token.IsCancellationRequested) { UdpReceiveResult received = await client.ReceiveAsync(); var rsp = UdpTrackerMessage.DecodeMessage(received.Buffer, 0, received.Buffer.Length, MessageType.Response); if (transactionId == rsp.TransactionId) { if (rsp is ErrorMessage error) { FailureMessage = error.Error; throw new Exception("The tracker returned an error."); } else { return(rsp); } } } // If we get here then the token will have been cancelled. We need the additional // 'throw' statement to keep the compiler happy. token.ThrowIfCancellationRequested(); throw new OperationCanceledException("The tracker did not respond."); }
private bool ConnectCallback(IAsyncResult ar) { UdpTrackerAsyncState trackerState = (UdpTrackerAsyncState)ar; try { UdpTrackerMessage msg = Receive(trackerState, trackerState.Data); if (msg == null) { return(false);//bad transaction id } ConnectResponseMessage rsp = msg as ConnectResponseMessage; if (rsp == null) { //is there a possibility to have a message which is not error message or connect rsp but udp msg FailureMessage = ((ErrorMessage)msg).Error; return(false);//error message } connectionId = rsp.ConnectionId; hasConnected = true; amConnecting = false; return(true); } catch { return(false); } }
private static void Check(IMessage message, MessageType type) { var e = message.Encode(); Assert.AreEqual(e.Length, message.ByteLength, "#1"); Assert.IsTrue(Toolbox.ByteMatch(e, UdpTrackerMessage.DecodeMessage(e, 0, e.Length, type).Encode()), "#2"); }
public static UdpTrackerMessage DecodeMessage(byte[] buffer, int offset, int count, MessageType type) { UdpTrackerMessage m = null; int action = type == MessageType.Request ? ReadInt(buffer, offset + 8) : ReadInt(buffer, offset); switch (action) { case 0: if (type == MessageType.Request) { m = new ConnectMessage(); } else { m = new ConnectResponseMessage(); } break; case 1: if (type == MessageType.Request) { m = new AnnounceMessage(); } else { m = new AnnounceResponseMessage(); } break; case 2: if (type == MessageType.Request) { m = new ScrapeMessage(); } else { m = new ScrapeResponseMessage(); } break; case 3: m = new ErrorMessage(); break; default: throw new ProtocolException(string.Format("Invalid udp message received: {0}", buffer[offset])); } try { m.Decode(buffer, offset, count); } catch { m = new ErrorMessage(0, "Couldn't decode the tracker response"); } return(m); }
private async Task SendRequestAsync(UdpTrackerMessage message) { var encodedMessage = message.Encode(); var dataWriter1 = new DataWriter(_tracker.OutputStream); try { dataWriter1.WriteBytes(encodedMessage); await dataWriter1.StoreAsync(); } finally { dataWriter1.DetachStream(); } ClientEngine.MainLoop.QueueTimeout(RetryDelay, () => { lock (_lock) { if (_timeout == 0) { return(false); } if (_timeout <= 4) { _timeout++; try { var dataWriter = new DataWriter(_tracker.OutputStream); try { dataWriter.WriteBytes(encodedMessage); dataWriter.StoreAsync().AsTask().Wait(); } finally { dataWriter.DetachStream(); } } catch (Exception exception1) { var exception = exception1; lock (_lock) { _timeout = 0; } _taskCompletionSource.TrySetException(exception); return(false); } return(true); } _timeout = 0; _taskCompletionSource.TrySetException(new Exception("Announce timeout.")); } return(false); }); }
private async Task <byte[]> SendAndReceiveAsync(UdpTrackerMessage message) { lock (_lock) _timeout = 1; _taskCompletionSource = new TaskCompletionSource <byte[]>(); await SendRequestAsync(message); return(await _taskCompletionSource.Task); }
async Task <UdpTrackerMessage> SendAndReceiveAsync(UdpTrackerMessage msg) { var cts = new CancellationTokenSource(TimeSpan.FromSeconds(RetryDelay.TotalSeconds * MaxRetries)); using (var udpClient = new UdpClient(Uri.Host, Uri.Port)) using (cts.Token.Register(() => udpClient.Dispose())) { SendAsync(udpClient, msg, cts.Token); return(await ReceiveAsync(udpClient, msg.TransactionId, cts.Token)); } }
async void ReceiveAsync(UdpClient client, CancellationToken token) { Task sendTask = null; while (!token.IsCancellationRequested) { try { var result = await client.ReceiveAsync(); byte[] data = result.Buffer; if (data.Length < 16) { return;//bad request } UdpTrackerMessage request = UdpTrackerMessage.DecodeMessage(data, 0, data.Length, MessageType.Request); if (sendTask != null) { try { await sendTask; } catch { } } switch (request.Action) { case 0: sendTask = ReceiveConnect(client, (ConnectMessage)request, result.RemoteEndPoint); break; case 1: sendTask = ReceiveAnnounce(client, (AnnounceMessage)request, result.RemoteEndPoint); break; case 2: sendTask = ReceiveScrape(client, (ScrapeMessage)request, result.RemoteEndPoint); break; case 3: sendTask = ReceiveError(client, (ErrorMessage)request, result.RemoteEndPoint); break; default: throw new ProtocolException(string.Format("Invalid udp message received: {0}", request.Action)); } } catch (Exception e) { Logger.Log(null, e.ToString()); } } }
public void AnnounceMessageTest() { AnnounceMessage m = new AnnounceMessage(0, 12345, announceparams); AnnounceMessage d = (AnnounceMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Request); Check(m, MessageType.Request); Assert.AreEqual(1, m.Action); Assert.AreEqual(m.Action, d.Action); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode())); Assert.AreEqual(12345, d.ConnectionId); }
private void ReceiveData(IAsyncResult ar) { try { System.Net.Sockets.UdpClient listener = (System.Net.Sockets.UdpClient)ar.AsyncState; byte[] data = listener.EndReceive(ar, ref endpoint); #endif if (data.Length < 16) { return;//bad request } UdpTrackerMessage request = UdpTrackerMessage.DecodeMessage(data, 0, data.Length, MessageType.Request); switch (request.Action) { case 0: ReceiveConnect((ConnectMessage)request); break; case 1: ReceiveAnnounce((AnnounceMessage)request); break; case 2: ReceiveScrape((ScrapeMessage)request); break; case 3: ReceiveError((ErrorMessage)request); break; default: throw new ProtocolException(string.Format("Invalid udp message received: {0}", request.Action)); } } catch (Exception e) { Logger.Log(null, e.ToString()); } finally { if (Running) { #if NETSTANDARD1_5 result = await listener.ReceiveAsync(); ReceiveData(result, client); #else listener.BeginReceive(new AsyncCallback(ReceiveData), listener); #endif } } }
async void SendAsync(UdpClient client, UdpTrackerMessage msg, CancellationToken token) { byte[] buffer = msg.Encode(); try { do { client.Send(buffer, buffer.Length); await Task.Delay(RetryDelay, token); }while (!token.IsCancellationRequested); } catch { } }
public void AnnounceResponseTest() { var peers = peerEndpoints.Select(t => new Peer("", new Uri($"ipv4://{t.Address}:{t.Port}"))).ToList(); AnnounceResponseMessage m = new AnnounceResponseMessage(12345, TimeSpan.FromSeconds(10), 43, 65, peers); AnnounceResponseMessage d = (AnnounceResponseMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Response); Check(m, MessageType.Response); Assert.AreEqual(1, m.Action); Assert.AreEqual(m.Action, d.Action); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode())); Assert.AreEqual(12345, d.TransactionId); }
private UdpTrackerMessage Receive(UdpTrackerAsyncState trackerState, byte[] receivedMessage) { timeout = 0;//we have receive so unactive the timeout byte[] data = receivedMessage; UdpTrackerMessage rsp = UdpTrackerMessage.DecodeMessage(data, 0, data.Length, MessageType.Response); if (trackerState.Message.TransactionId != rsp.TransactionId) { FailureMessage = "Invalid transaction Id in response from udp tracker!"; return(null);//to raise event fail outside } return(rsp); }
public void ConnectMessageTest() { ConnectMessage m = new ConnectMessage(); ConnectMessage d = (ConnectMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Request); Check(m, MessageType.Request); Assert.AreEqual(0, m.Action, "#0"); Assert.AreEqual(m.Action, d.Action, "#1"); Assert.AreEqual(m.ConnectionId, d.ConnectionId, "#2"); Assert.AreEqual(m.TransactionId, d.TransactionId, "#3"); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode()), "#4"); }
public void ConnectResponseTest() { ConnectResponseMessage m = new ConnectResponseMessage(5371, 12345); ConnectResponseMessage d = (ConnectResponseMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), MessageType.Response); Check(m, MessageType.Response); Assert.AreEqual(0, m.Action, "#0"); Assert.AreEqual(m.Action, d.Action, "#1"); Assert.AreEqual(m.ConnectionId, d.ConnectionId, "#2"); Assert.AreEqual(m.TransactionId, d.TransactionId, "#3"); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode()), "#4"); Assert.AreEqual(12345, d.ConnectionId); Assert.AreEqual(5371, d.TransactionId); }
private void CompleteScrape(UdpTrackerMessage message, object state) { ErrorMessage error = message as ErrorMessage; if (error != null) { FailureMessage = error.Error; DoScrapeComplete(false, state); } else { //response.Scrapes not used for moment //ScrapeResponseMessage response = (ScrapeResponseMessage)message; DoScrapeComplete(true, state); } }
void SendAsync(UdpClient client, UdpTrackerMessage msg, CancellationToken token) { byte[] buffer = msg.Encode(); client.Send(buffer, buffer.Length); ClientEngine.MainLoop.QueueTimeout(RetryDelay, () => { try { if (!token.IsCancellationRequested) { client.Send(buffer, buffer.Length); } return(!token.IsCancellationRequested); } catch { return(false); } }); }
public void ConnectResponseTest() { var expectedMessage = new ConnectResponseMessage(5371, 12345); var actualMessage = (ConnectResponseMessage) UdpTrackerMessage.DecodeMessage(expectedMessage.Encode(), 0, expectedMessage.ByteLength, MessageType.Response); Check(expectedMessage, MessageType.Response); Assert.AreEqual(0, expectedMessage.Action, "#0"); Assert.AreEqual(expectedMessage.Action, actualMessage.Action, "#1"); Assert.AreEqual(expectedMessage.ConnectionId, actualMessage.ConnectionId, "#2"); Assert.AreEqual(expectedMessage.TransactionId, actualMessage.TransactionId, "#3"); Assert.IsTrue(Toolbox.ByteMatch(expectedMessage.Encode(), actualMessage.Encode()), "#4"); Assert.AreEqual(12345, actualMessage.ConnectionId); Assert.AreEqual(5371, actualMessage.TransactionId); }
private void CompleteAnnounce(UdpTrackerMessage message, object state) { ErrorMessage error = message as ErrorMessage; if (error != null) { FailureMessage = error.Error; DoAnnounceComplete(false, state, new List <Peer>()); } else { AnnounceResponseMessage response = (AnnounceResponseMessage)message; DoAnnounceComplete(true, state, response.Peers); //TODO seeders and leechers is not used in event. } }
public void ScrapeResponseTest() { List <ScrapeDetails> details = new List <ScrapeDetails>(); details.Add(new ScrapeDetails(1, 2, 3)); details.Add(new ScrapeDetails(4, 5, 6)); details.Add(new ScrapeDetails(7, 8, 9)); ScrapeResponseMessage m = new ScrapeResponseMessage(12345, details); ScrapeResponseMessage d = (ScrapeResponseMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Response); Check(m, MessageType.Response); Assert.AreEqual(2, m.Action); Assert.AreEqual(m.Action, d.Action); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode())); Assert.AreEqual(12345, d.TransactionId); }
public void AnnounceResponseTest() { List <Peer> peers = new List <Peer>(); peers.Add(new Peer(new string('1', 20), new Uri("tcp://127.0.0.1:1"))); peers.Add(new Peer(new string('2', 20), new Uri("tcp://127.0.0.1:2"))); peers.Add(new Peer(new string('3', 20), new Uri("tcp://127.0.0.1:3"))); AnnounceResponseMessage m = new AnnounceResponseMessage(12345, TimeSpan.FromSeconds(10), 43, 65, peers); AnnounceResponseMessage d = (AnnounceResponseMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Response); Check(m, MessageType.Response); Assert.AreEqual(1, m.Action); Assert.AreEqual(m.Action, d.Action); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode())); Assert.AreEqual(12345, d.TransactionId); }
async Task <(UdpTrackerMessage, string)> SendAndReceiveAsync(UdpTrackerMessage msg) { var cts = new CancellationTokenSource(TimeSpan.FromSeconds(RetryDelay.TotalSeconds * MaxRetries)); try { // Calling the UdpClient ctor which takes a hostname, or calling the Connect method, // results in a synchronous DNS resolve. Ensure we're on a threadpool thread to avoid // blocking. await new ThreadSwitcher(); using var udpClient = new UdpClient(Uri.Host, Uri.Port); using (cts.Token.Register(() => udpClient.Dispose())) { SendAsync(udpClient, msg, cts.Token); return(await ReceiveAsync(udpClient, msg.TransactionId, cts.Token).ConfigureAwait(false)); } } catch { cts.Token.ThrowIfCancellationRequested(); throw; } }
public void ScrapeResponseTest() { var details = new List <ScrapeDetails> { new ScrapeDetails(1, 2, 3), new ScrapeDetails(4, 5, 6), new ScrapeDetails(7, 8, 9) }; var expectedMessage = new ScrapeResponseMessage(12345, details); var actualMessage = (ScrapeResponseMessage) UdpTrackerMessage.DecodeMessage(expectedMessage.Encode(), 0, expectedMessage.ByteLength, MessageType.Response); Check(expectedMessage, MessageType.Response); Assert.AreEqual(2, expectedMessage.Action); Assert.AreEqual(expectedMessage.Action, actualMessage.Action); Assert.IsTrue(Toolbox.ByteMatch(expectedMessage.Encode(), actualMessage.Encode())); Assert.AreEqual(12345, actualMessage.TransactionId); }
async Task <UdpTrackerMessage> ReceiveAsync(UdpClient client, int transactionId, CancellationToken token) { while (!token.IsCancellationRequested) { var received = await client.ReceiveAsync(); UdpTrackerMessage rsp = UdpTrackerMessage.DecodeMessage(received.Buffer, 0, received.Buffer.Length, MessageType.Response); if (transactionId == rsp.TransactionId) { if (rsp is ErrorMessage error) { FailureMessage = error.Error; throw new Exception("The tracker returned an error."); } else { return(rsp); } } } throw new Exception("The tracker did not respond."); }
public void ScrapeMessageTest() { List <byte[]> hashes = new List <byte[]>(); Random r = new Random(); byte[] hash1 = new byte[20]; byte[] hash2 = new byte[20]; byte[] hash3 = new byte[20]; r.NextBytes(hash1); r.NextBytes(hash2); r.NextBytes(hash3); hashes.Add(hash1); hashes.Add(hash2); hashes.Add(hash3); ScrapeMessage m = new ScrapeMessage(12345, 123, hashes); ScrapeMessage d = (ScrapeMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Request); Check(m, MessageType.Request); Assert.AreEqual(2, m.Action); Assert.AreEqual(m.Action, d.Action); Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode())); }
private void ScrapeCallback(IAsyncResult ar) { try { ConnectScrapeState scrapeState = (ConnectScrapeState)ar; if (scrapeState.SavedException != null) { FailureMessage = scrapeState.SavedException.Message; DoScrapeComplete(false, scrapeState.AsyncState); return; } UdpTrackerMessage rsp = Receive(scrapeState, scrapeState.Data); if (!(rsp is ScrapeResponseMessage)) { DoScrapeComplete(false, scrapeState.AsyncState); return; } CompleteScrape(rsp, scrapeState.AsyncState); } catch { // Nothing to do i think } }
async void ReceiveAsync(UdpClient client, CancellationToken token) { Task sendTask = null; while (!token.IsCancellationRequested) { try { UdpReceiveResult result = await client.ReceiveAsync(); byte[] data = result.Buffer; if (data.Length < 16) { return; //bad request } var request = UdpTrackerMessage.DecodeMessage(data.AsSpan(0, data.Length), MessageType.Request); if (sendTask != null) { try { await sendTask; } catch { } } sendTask = request.Action switch { 0 => ReceiveConnect(client, (ConnectMessage)request, result.RemoteEndPoint), 1 => ReceiveAnnounce(client, (AnnounceMessage)request, result.RemoteEndPoint), 2 => ReceiveScrape(client, (ScrapeMessage)request, result.RemoteEndPoint), 3 => ReceiveError(client, (ErrorMessage)request, result.RemoteEndPoint), _ => throw new InvalidOperationException($"Invalid udp message received: {request.Action}") }; } catch (Exception e) { logger.Exception(e, "Exception while receiving a message"); } } }
void Check(UdpTrackerMessage message, MessageType type) { byte[] e = message.Encode(); Assert.AreEqual(e.Length, message.ByteLength, "#1"); Assert.IsTrue(Toolbox.ByteMatch(e, UdpTrackerMessage.DecodeMessage(e, type).Encode()), "#2"); }