/// <summary> /// An announcement has been received (via unconnected message); react accordingly. /// </summary> private void OnAnnounceResponseReceived(AnnounceResponseMessage message, IPEndPoint endpoint) { // heed only ipv4 for now... TBD what to do about this if (endpoint.AddressFamily == AddressFamily.InterNetwork) { PeerAnnounceResponseCount++; logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.OnAnnounceResponseReceived({endpoint}) -- {ConnectionsStatusString()}"); // we shouldn't know this peer yet, let's check. if (netManager.ConnectedPeerList.Any(peer => peer.EndPoint.Equals(endpoint))) { // surprise, we do! must have been a race. return; } if (AnnouncedEndPoints.Contains(endpoint)) { return; } AnnouncedEndPoints.Add(endpoint); logger?.WriteNet(NetLogLevel.Info, $"DistributedHost.OnAnnounceResponseReceived({endpoint}) -- sending connect request"); // So, connect away. (Note this could still race -- Connect is thread-safe but the // AddPeer method is not. TODO: look at fixing this.) // Deliberately ignore the netPeer return value; we let the OnPeerConnected event carry the ball. netManager.Connect(endpoint, RequestKey); } }
/// <summary> /// Called when announce is requested. /// </summary> protected override void OnAnnounce() { AnnounceResponseMessage message; Uri uri; this.OnAnnouncing(this, EventArgs.Empty); try { uri = this.GetUri(); Debug.WriteLine($"{this.TrackerUri} -> {uri}"); if (AnnounceResponseMessage.TryDecode(uri.ExecuteBinaryRequest(), out message)) { Debug.WriteLine($"{this.TrackerUri} <- {message}"); this.UpdateInterval = message.UpdateInterval; this.OnAnnounced(this, new AnnouncedEventArgs(message.UpdateInterval, message.LeecherCount, message.SeederCount, message.Peers)); } } catch (Exception ex) { Debug.WriteLine($"could not send message to HTTP tracker {this.TrackerUri} for torrent {this.TorrentInfoHash}: {ex.Message}"); } }
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); }
//QUICKHACK: format bencoded val and get it back wereas must refactor tracker system to have more generic object... protected virtual void ReceiveAnnounce(AnnounceMessage announceMessage) { UdpTrackerMessage m; BEncodedDictionary dict = Handle(getCollection(announceMessage), endpoint.Address, false); if (dict.ContainsKey(RequestParameters.FailureKey)) { m = new ErrorMessage(announceMessage.TransactionId, dict[RequestParameters.FailureKey].ToString()); } else { TimeSpan interval = TimeSpan.Zero; int leechers = 0; int seeders = 0; List <System.Net.BitTorrent.Client.Peer> peers = new List <System.Net.BitTorrent.Client.Peer>(); foreach (KeyValuePair <BEncodedString, BEncodedValue> keypair in dict) { switch (keypair.Key.Text) { case ("complete"): seeders = Convert.ToInt32(keypair.Value.ToString()); //same as seeder? break; case ("incomplete"): leechers = Convert.ToInt32(keypair.Value.ToString()); //same as leecher? break; case ("interval"): interval = TimeSpan.FromSeconds(int.Parse(keypair.Value.ToString())); break; case ("peers"): if (keypair.Value is BEncodedList) // Non-compact response { peers.AddRange(System.Net.BitTorrent.Client.Peer.Decode((BEncodedList)keypair.Value)); } else if (keypair.Value is BEncodedString) // Compact response { peers.AddRange(System.Net.BitTorrent.Client.Peer.Decode((BEncodedString)keypair.Value)); } break; default: break; } } m = new AnnounceResponseMessage(announceMessage.TransactionId, interval, leechers, seeders, peers); } byte[] data = m.Encode(); #if NETSTANDARD1_5 listener.SendAsync(data, data.Length, endpoint); #else listener.Send(data, data.Length, endpoint); #endif }
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); }
//QUICKHACK: format bencoded val and get it back wereas must refactor tracker system to have more generic object... protected virtual async Task ReceiveAnnounce(UdpClient client, AnnounceMessage announceMessage, IPEndPoint remotePeer) { UdpTrackerMessage m; BEncodedDictionary dict = Handle(getCollection(announceMessage), remotePeer.Address, false); if (dict.ContainsKey(TrackerRequest.FailureKey)) { m = new ErrorMessage(announceMessage.TransactionId, dict[TrackerRequest.FailureKey].ToString()); } else { TimeSpan interval = TimeSpan.Zero; int leechers = 0; int seeders = 0; var peers = new List <MonoTorrent.Client.Peer> (); foreach (KeyValuePair <BEncodedString, BEncodedValue> keypair in dict) { switch (keypair.Key.Text) { case ("complete"): seeders = Convert.ToInt32(keypair.Value.ToString()); //same as seeder? break; case ("incomplete"): leechers = Convert.ToInt32(keypair.Value.ToString()); //same as leecher? break; case ("interval"): interval = TimeSpan.FromSeconds(int.Parse(keypair.Value.ToString())); break; case ("peers"): if (keypair.Value is BEncodedList) // Non-compact response { peers.AddRange(MonoTorrent.Client.Peer.Decode((BEncodedList)keypair.Value)); } else if (keypair.Value is BEncodedString) // Compact response { peers.AddRange(MonoTorrent.Client.Peer.Decode((BEncodedString)keypair.Value)); } break; default: break; } } m = new AnnounceResponseMessage(announceMessage.TransactionId, interval, leechers, seeders, peers); } byte[] data = m.Encode(); await client.SendAsync(data, data.Length, remotePeer); }
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 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); }
/// <summary> /// An announcement has been received (via broadcast); react accordingly. /// </summary> private void OnAnnounceReceived(AnnounceMessage message, IPEndPoint endpoint) { // heed only ipv4 for now... TBD what to do about this if (endpoint.AddressFamily == AddressFamily.InterNetwork) { // is this actually our own announcement!? SerializedSocketAddress incomingAddress = new SerializedSocketAddress(endpoint.Serialize()); if (incomingAddress == this.SocketAddress) { // ignore this, we're talking to ourselves return; } PeerAnnounceCount++; // do we know this peer already? // (could happen in race scenario) if (netManager.ConnectedPeerList.Any(peer => peer.EndPoint.Equals(endpoint))) { return; } // did we already respond to this peer? if (AnnouncedEndPoints.Contains(endpoint)) { return; } // did this peer know us already? (typical scenario given re-announcements) if (message.KnownPeers.Contains(SocketAddress)) { return; } logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.OnAnnounceReceived({endpoint}) -- responding. {ConnectionsStatusString()}]"); // send announce response AnnounceResponseMessage response = new AnnounceResponseMessage { }; SendUnconnectedMessage(response, endpoint); } }
public static UdpTrackerMessage DecodeMessage(byte[] buffer, int offset, int count, MessageType type) { UdpTrackerMessage m = null; var 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; }
public void AnnounceResponseMessage_TryDecode() { AnnounceResponseMessage message; byte[] data = "00000001 00003300 00000002 00000003 00000004 09080706 2002 01020304 3003".Replace(" ", string.Empty).ToByteArray(); if (AnnounceResponseMessage.TryDecode(data, 0, out message)) { Assert.AreEqual(32, message.Length); Assert.AreEqual(1, (int)message.Action); Assert.AreEqual(13056, message.TransactionId); Assert.AreEqual(2, message.Interval.TotalSeconds); Assert.AreEqual(3, message.LeecherCount); Assert.AreEqual(4, message.SeederCount); Assert.AreEqual(2, message.Peers.Count()); Assert.AreEqual(new IPEndPoint(IPAddress.Parse("9.8.7.6"), 8194), message.Peers.ElementAt(0)); Assert.AreEqual(new IPEndPoint(IPAddress.Parse("1.2.3.4"), 12291), message.Peers.ElementAt(1)); CollectionAssert.AreEqual(data, message.Encode()); } else { Assert.Fail(); } }
public void AnnounceResponseTest() { var peers = new List<Peer> { new Peer(new string('1', 20), new Uri("tcp://127.0.0.1:1")), new Peer(new string('2', 20), new Uri("tcp://127.0.0.1:2")), new Peer(new string('3', 20), new Uri("tcp://127.0.0.1:3")) }; var m = new AnnounceResponseMessage(12345, TimeSpan.FromSeconds(10), 43, 65, peers); var 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); }