async void MessageReceived(byte[] buffer, IPEndPoint endpoint) { await DhtEngine.MainLoop; // Don't handle new messages if we have already stopped the dht engine. if (Listener.Status == ListenerStatus.NotListening) { return; } // I should check the IP address matches as well as the transaction id // FIXME: This should throw an exception if the message doesn't exist, we need to handle this // and return an error message (if that's what the spec allows) try { if (DhtMessageFactory.TryDecodeMessage((BEncodedDictionary)BEncodedValue.Decode(buffer, false), out DhtMessage message)) { Monitor.ReceiveMonitor.AddDelta(buffer.Length); ReceiveQueue.Enqueue(new KeyValuePair <IPEndPoint, DhtMessage> (endpoint, message)); } } catch (MessageException) { // Caused by bad transaction id usually - ignore } catch (Exception) { //throw new Exception("IP:" + endpoint.Address.ToString() + "bad transaction:" + e.Message); } }
internal void Start() { DhtMessageFactory = new DhtMessageFactory(); if (Listener.Status != ListenerStatus.Listening) { Listener.Start(); } }
void TimeoutMessage(SendDetails v) { DhtMessageFactory.UnregisterSend((QueryMessage)v.Message); WaitingResponse.Remove(v.Message.TransactionId); v.CompletionSource?.TrySetResult(new SendQueryEventArgs(v.Node, v.Destination, (QueryMessage)v.Message)); RaiseMessageSent(v.Node, v.Destination, (QueryMessage)v.Message); }
public void PingResponseDecode() { PingEncode(); DhtMessageFactory.RegisterSend(message); string text = "d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re"; PingResponse m = (PingResponse)Decode(text); Assert.AreEqual(infohash, m.Id); Compare(m, "d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re"); }
public void FindNodeResponseDecode() { FindNodeEncode(); DhtMessageFactory.RegisterSend(message); string text = "d1:rd2:id20:abcdefghij01234567895:nodes9:def456...e1:t2:aa1:y1:re"; FindNodeResponse m = (FindNodeResponse)Decode(text); Assert.AreEqual(id, m.Id, "#1"); Assert.AreEqual((BEncodedString)"def456...", m.Nodes, "#2"); Assert.AreEqual(transactionId, m.TransactionId, "#3"); Compare(m, text); }
public void AnnouncePeerResponseDecode() { // Register the query as being sent so we can decode the response AnnouncePeerDecode(); DhtMessageFactory.RegisterSend(message); string text = "d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re"; AnnouncePeerResponse m = (AnnouncePeerResponse)Decode(text); Assert.AreEqual(infohash, m.Id, "#1"); Compare(m, text); }
internal void Stop() { DhtMessageFactory = new DhtMessageFactory(); SendQueue.Clear(); ReceiveQueue.Clear(); WaitingResponse.Clear(); WaitingResponseTimedOut.Clear(); if (Listener.Status != ListenerStatus.NotListening) { Listener.Stop(); } }
public async Task SendAsync(byte[] buffer, IPEndPoint endpoint) { if (SendAsynchronously) { await Task.Yield(); } if (DhtMessageFactory.TryDecodeMessage(BEncodedValue.Decode <BEncodedDictionary> (buffer), out DhtMessage message)) { MessageSent?.Invoke(message, endpoint); } else { throw new Exception("Could not decode the message"); } }
public void ErrorReceived() { int failedCount = 0; var pingSuccessful = new TaskCompletionSource <bool> (); var ping = new Ping(node.Id) { TransactionId = transactionId }; engine.MessageLoop.QuerySent += (o, e) => { // This ping should not time out. if (e.Query.TransactionId.Equals(ping.TransactionId)) { pingSuccessful.TrySetResult(!e.TimedOut && e.Response == null && e.Error != null); } }; listener.MessageSent += (message, endpoint) => { // This TransactionId should be registered and it should be pending a response. if (!DhtMessageFactory.IsRegistered(ping.TransactionId) || engine.MessageLoop.PendingQueries != 1) { pingSuccessful.TrySetResult(false); } if (message.TransactionId.Equals(ping.TransactionId)) { listener.RaiseMessageReceived(new ErrorMessage(ping.TransactionId, ErrorCode.ServerError, "Ooops"), node.EndPoint); failedCount++; } }; // Send the ping var task = engine.SendQueryAsync(ping, node); // The query should complete, and the message should not have timed out. Assert.IsTrue(task.Wait(100000), "#1"); Assert.IsTrue(pingSuccessful.Task.Wait(1000), "#2"); Assert.IsTrue(pingSuccessful.Task.Result, "#3"); Assert.IsFalse(DhtMessageFactory.IsRegistered(ping.TransactionId), "#4"); Assert.AreEqual(0, engine.MessageLoop.PendingQueries, "#5"); Assert.AreEqual(1, failedCount, "#6"); }
public void GetPeersResponseDecode() { GetPeersEncode(); DhtMessageFactory.RegisterSend(message); string text = "d1:rd2:id20:abcdefghij01234567895:token8:aoeusnth6:valuesl6:axje.u6:idhtnmee1:t2:aa1:y1:re"; GetPeersResponse m = (GetPeersResponse)Decode(text); Assert.AreEqual(token, m.Token, "#1"); Assert.AreEqual(id, m.Id, "#2"); BEncodedList l = new BEncodedList(); l.Add((BEncodedString)"axje.u"); l.Add((BEncodedString)"idhtnm"); Assert.AreEqual(l, m.Values, "#3"); Compare(m, text); }
public MessageLoop(DhtEngine engine, TransferMonitor monitor) { Engine = engine ?? throw new ArgumentNullException(nameof(engine)); Monitor = monitor; DhtMessageFactory = new DhtMessageFactory(); Listener = new NullDhtListener(); ReceiveQueue = new Queue <KeyValuePair <IPEndPoint, DhtMessage> > (); SendQueue = new Queue <SendDetails> (); Timeout = TimeSpan.FromSeconds(15); WaitingResponse = new Dictionary <BEncodedValue, SendDetails> (); WaitingResponseTimedOut = new List <SendDetails> (); Task sendTask = null; DhtEngine.MainLoop.QueueTimeout(TimeSpan.FromMilliseconds(5), () => { monitor.ReceiveMonitor.Tick(); monitor.SendMonitor.Tick(); if (engine.Disposed) { return(false); } try { if (sendTask == null || sendTask.IsCompleted) { sendTask = SendMessages(); } while (ReceiveQueue.Count > 0) { ReceiveMessage(); } TimeoutMessages(); } catch (Exception ex) { Debug.WriteLine("Error in DHT main loop:"); Debug.WriteLine(ex); } return(!engine.Disposed); }); }
void TimeoutMessage() { foreach (KeyValuePair <BEncodedValue, SendDetails> v in WaitingResponse) { if (Timeout == TimeSpan.Zero || v.Value.SentAt.Elapsed > Timeout) { WaitingResponseTimedOut.Add(v.Value); } } foreach (SendDetails v in WaitingResponseTimedOut) { DhtMessageFactory.UnregisterSend((QueryMessage)v.Message); WaitingResponse.Remove(v.Message.TransactionId); v.CompletionSource?.TrySetResult(new SendQueryEventArgs(v.Node, v.Destination, (QueryMessage)v.Message)); RaiseMessageSent(v.Node, v.Destination, (QueryMessage)v.Message); } WaitingResponseTimedOut.Clear(); }
internal void EnqueueSend(DhtMessage message, Node node, IPEndPoint endpoint, TaskCompletionSource <SendQueryEventArgs> tcs = null) { if (message.TransactionId == null) { if (message is ResponseMessage) { throw new ArgumentException("Message must have a transaction id"); } do { message.TransactionId = TransactionId.NextId(); } while (DhtMessageFactory.IsRegistered(message.TransactionId)); } // We need to be able to cancel a query message if we time out waiting for a response if (message is QueryMessage) { DhtMessageFactory.RegisterSend((QueryMessage)message); } SendQueue.Enqueue(new SendDetails(node, endpoint, message, tcs)); }
async void MessageReceived(byte[] buffer, IPEndPoint endpoint) { await DhtEngine.MainLoop; // I should check the IP address matches as well as the transaction id // FIXME: This should throw an exception if the message doesn't exist, we need to handle this // and return an error message (if that's what the spec allows) try { DhtMessage message; if (DhtMessageFactory.TryDecodeMessage((BEncodedDictionary)BEncodedValue.Decode(buffer, 0, buffer.Length, false), out message)) { ReceiveQueue.Enqueue(new KeyValuePair <IPEndPoint, DhtMessage>(endpoint, message)); } } catch (MessageException) { // Caused by bad transaction id usually - ignore } catch (Exception) { //throw new Exception("IP:" + endpoint.Address.ToString() + "bad transaction:" + e.Message); } }
private void TimeoutMessage() { foreach (var v in WaitingResponse) { if (Timeout == TimeSpan.Zero || v.Value.SentAt.Elapsed > Timeout) { WaitingResponseTimedOut.Add(v.Value); } } foreach (var v in WaitingResponseTimedOut) { DhtMessageFactory.UnregisterSend((QueryMessage)v.Message); WaitingResponse.Remove(v.Message.TransactionId); if (v.CompletionSource != null) { v.CompletionSource.TrySetResult(new SendQueryEventArgs(v.Node, v.Destination, (QueryMessage)v.Message)); } RaiseMessageSent(v.Node, v.Destination, (QueryMessage)v.Message); } WaitingResponseTimedOut.Clear(); }
public void Setup() { DhtMessage.UseVersionKey = false; DhtMessageFactory = new DhtMessageFactory(); }
private DhtMessage Decode(string p) { byte[] buffer = Encoding.UTF8.GetBytes(p); return(DhtMessageFactory.DecodeMessage(BEncodedValue.Decode <BEncodedDictionary>(buffer))); }