diff --git a/src/MonoTorrent.Client/MonoTorrent.Client.Modes/Mode.cs b/src/MonoTorrent.Client/MonoTorrent.Client.Modes/Mode.cs index 4a5591a5c..77ea3f676 100644 --- a/src/MonoTorrent.Client/MonoTorrent.Client.Modes/Mode.cs +++ b/src/MonoTorrent.Client/MonoTorrent.Client.Modes/Mode.cs @@ -249,7 +249,7 @@ protected virtual async void HandlePeerExchangeMessage (PeerId id, PeerExchangeM if ((Manager.Peers.Available + Manager.OpenConnections) >= Manager.Settings.MaximumConnections) return; - var newPeers = PeerDecoder.Decode (BEncodedString.FromMemory (message.Added)); + var newPeers = PeerInfo.FromCompact (message.Added.Span, id.Connection.AddressBytes.Length == 16 ? System.Net.Sockets.AddressFamily.InterNetworkV6 : System.Net.Sockets.AddressFamily.InterNetwork); for (int i = 0; i < newPeers.Count && i < message.AddedDotF.Length; i++) newPeers[i] = new PeerInfo (newPeers[i].ConnectionUri, newPeers[i].PeerId, (message.AddedDotF.Span[i] & 0x2) == 0x2); diff --git a/src/MonoTorrent.Client/MonoTorrent.Client/Managers/PeerExchangeManager.cs b/src/MonoTorrent.Client/MonoTorrent.Client/Managers/PeerExchangeManager.cs index f8ca34b0e..da04a87f4 100644 --- a/src/MonoTorrent.Client/MonoTorrent.Client/Managers/PeerExchangeManager.cs +++ b/src/MonoTorrent.Client/MonoTorrent.Client/Managers/PeerExchangeManager.cs @@ -93,9 +93,13 @@ internal void OnTick () var added = memory.Slice (0, len * 6); var addedDotF = memory.Slice (added.Length, len); + int stride = 6; + for (int i = 0; i < len; i++) { var peer = addedPeers.Dequeue (); - peer.Peer.CompactPeer (added.Span.Slice (i * 6, 6)); + if (!peer.Peer.TryWriteCompactPeer (added.Span.Slice (i * stride, stride), out int written) || written != stride) + throw new NotSupportedException (); + if (EncryptionTypes.SupportsRC4 (peer.Peer.AllowedEncryption)) { addedDotF.Span[i] = 0x01; } else { @@ -107,16 +111,17 @@ internal void OnTick () // The remainder of our buffer can be filled with dropped peers. // We do some math to slice the remainder of the original memory - // buffer to an even multiple of 6. Then we calculate how many + // buffer to an even multiple of 'stride'. Then we calculate how many // peers we actually want to put in it, and then we slice it one // more time if we don't have enough dropped peers. var dropped = memory.Slice (added.Length + addedDotF.Length); - dropped = dropped.Slice (0, (dropped.Length / 6) * 6); - len = Math.Min (dropped.Length / 6, droppedPeers.Count); - dropped = dropped.Slice (0, len * 6); + dropped = dropped.Slice (0, (dropped.Length / stride) * stride); + len = Math.Min (dropped.Length / stride, droppedPeers.Count); + dropped = dropped.Slice (0, len * stride); for (int i = 0; i < len; i++) - droppedPeers.Dequeue ().Peer.CompactPeer (dropped.Span.Slice (i * 6, 6)); + if (!droppedPeers.Dequeue ().Peer.TryWriteCompactPeer (dropped.Span.Slice (i * stride, stride), out int written) || written != stride) + throw new NotSupportedException (); (var message, var releaser) = PeerMessage.Rent (); message.Initialize (new ExtensionSupports (new[] { PeerExchangeMessage.Support }), added, addedDotF, dropped, memoryReleaser); diff --git a/src/MonoTorrent.Client/MonoTorrent.Client/Peers/Peer.cs b/src/MonoTorrent.Client/MonoTorrent.Client/Peers/Peer.cs index 8748b838c..f12f9a870 100644 --- a/src/MonoTorrent.Client/MonoTorrent.Client/Peers/Peer.cs +++ b/src/MonoTorrent.Client/MonoTorrent.Client/Peers/Peer.cs @@ -130,8 +130,8 @@ public override string ToString () internal byte[] CompactPeer () => Info.CompactPeer (); - internal void CompactPeer (Span buffer) - => Info.CompactPeer (buffer); + internal bool TryWriteCompactPeer (Span buffer, out int written) + => Info.TryWriteCompactPeer (buffer, out written); internal static BEncodedList Encode (IEnumerable peers) { diff --git a/src/MonoTorrent.Client/MonoTorrent.Client/Peers/PeerDecoder.cs b/src/MonoTorrent.Client/MonoTorrent.Client/Peers/PeerDecoder.cs index 5d5182067..d4daf24ea 100644 --- a/src/MonoTorrent.Client/MonoTorrent.Client/Peers/PeerDecoder.cs +++ b/src/MonoTorrent.Client/MonoTorrent.Client/Peers/PeerDecoder.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; +using System.Net.Sockets; using MonoTorrent.BEncoding; @@ -36,15 +37,15 @@ namespace MonoTorrent { static class PeerDecoder { - public static IList Decode (BEncodedList peers) + public static IList Decode (BEncodedList peers, AddressFamily addressFamily) { var list = new List (peers.Count); foreach (BEncodedValue value in peers) { try { - if (value is BEncodedDictionary) - list.Add (DecodeFromDict ((BEncodedDictionary) value)); - else if (value is BEncodedString) - foreach (PeerInfo p in Decode ((BEncodedString) value)) + if (value is BEncodedDictionary dict) + list.Add (DecodeFromDict (dict)); + else if (value is BEncodedString str) + foreach (var p in PeerInfo.FromCompact (str.Span, addressFamily)) list.Add (p); } catch { // If something is invalid and throws an exception, ignore it @@ -73,8 +74,5 @@ static PeerInfo DecodeFromDict (BEncodedDictionary dict) var connectionUri = new Uri ($"ipv4://{dict[IPKey]}:{dict[PortKey]}"); return new PeerInfo (connectionUri, peerId); } - - public static IList Decode (BEncodedString peers) - => PeerInfo.FromCompact (peers.Span); } } diff --git a/src/MonoTorrent.Dht/MonoTorrent.Dht.Tasks/GetPeersTask.cs b/src/MonoTorrent.Dht/MonoTorrent.Dht.Tasks/GetPeersTask.cs index faa93a657..d9cc8a4e8 100644 --- a/src/MonoTorrent.Dht/MonoTorrent.Dht.Tasks/GetPeersTask.cs +++ b/src/MonoTorrent.Dht/MonoTorrent.Dht.Tasks/GetPeersTask.cs @@ -84,7 +84,7 @@ public async Task> ExecuteAsync () // The response had some actual peers if (response.Values != null) { // We have actual peers! - var peers = response.Values.OfType ().SelectMany (t => PeerInfo.FromCompact (t.Span)).ToArray (); + var peers = response.Values.OfType ().SelectMany (t => PeerInfo.FromCompact (t.Span, Engine.AddressFamily)).ToArray (); Engine.RaisePeersFound (InfoHash, peers); foreach (var peer in peers) FoundPeers.Add (peer); diff --git a/src/MonoTorrent.Dht/MonoTorrent.Dht/DhtEngine.cs b/src/MonoTorrent.Dht/MonoTorrent.Dht/DhtEngine.cs index 07473d6b8..46558ebfa 100644 --- a/src/MonoTorrent.Dht/MonoTorrent.Dht/DhtEngine.cs +++ b/src/MonoTorrent.Dht/MonoTorrent.Dht/DhtEngine.cs @@ -30,6 +30,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Sockets; using System.Security.Cryptography; using System.Threading.Tasks; @@ -74,6 +75,9 @@ public class DhtEngine : IDisposable, IDhtEngine internal static MainLoop MainLoop { get; } = new MainLoop ("DhtLoop"); + // IPV6 - create an IPV4 and an IPV6 dht engine + public AddressFamily AddressFamily { get; private set; } = AddressFamily.InterNetwork; + public TimeSpan AnnounceInterval => DefaultAnnounceInternal; public bool Disposed { get; private set; } diff --git a/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/AnnounceResponseMessage.cs b/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/AnnounceResponseMessage.cs index e955f4b85..42389aa72 100644 --- a/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/AnnounceResponseMessage.cs +++ b/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/AnnounceResponseMessage.cs @@ -29,26 +29,34 @@ using System; using System.Collections.Generic; +using System.Net.Sockets; namespace MonoTorrent.Messages.UdpTracker { public class AnnounceResponseMessage : UdpTrackerMessage { - public override int ByteLength => (4 * 5 + Peers.Count * 6); + public AddressFamily AddressFamily { get; private set; } + public override int ByteLength => (4 * 5 + Peers.Count * Stride); public TimeSpan Interval { get; private set; } public int Leechers { get; private set; } public List Peers { get; private set; } public int Seeders { get; private set; } + int Stride => AddressFamily switch { + AddressFamily.InterNetwork => 6, + AddressFamily.InterNetworkV6 => 18, + _ => throw new NotSupportedException () + }; - public AnnounceResponseMessage () - : this (0, TimeSpan.Zero, 0, 0, new List ()) + public AnnounceResponseMessage (AddressFamily addressFamily) + : this (addressFamily, 0, TimeSpan.Zero, 0, 0, new List ()) { } - public AnnounceResponseMessage (int transactionId, TimeSpan interval, int leechers, int seeders, List peers) + public AnnounceResponseMessage (AddressFamily addressFamily, int transactionId, TimeSpan interval, int leechers, int seeders, List peers) : base (1, transactionId) { + AddressFamily = addressFamily; Interval = interval; Leechers = leechers; Peers = peers; @@ -64,7 +72,7 @@ public override void Decode (ReadOnlySpan buffer) Leechers = ReadInt (ref buffer); Seeders = ReadInt (ref buffer); - IList peers = PeerInfo.FromCompact (buffer); + IList peers = PeerInfo.FromCompact (buffer, AddressFamily); Peers.AddRange (peers); } @@ -79,7 +87,8 @@ public override int Encode (Span buffer) Write (ref buffer, Seeders); for (int i = 0; i < Peers.Count; i++) - Peers[i].CompactPeer (buffer.Slice (i * 6)); + if (!Peers[i].TryWriteCompactPeer (buffer.Slice (i * Stride, Stride), out int dataWritten) || dataWritten != Stride) + throw new InvalidOperationException (); return written - buffer.Length; } diff --git a/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/UdpTrackerMessage.cs b/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/UdpTrackerMessage.cs index d9c07d81f..56a99d4a7 100644 --- a/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/UdpTrackerMessage.cs +++ b/src/MonoTorrent.Trackers/MonoTorrent.Client.Messages.UdpTracker/UdpTrackerMessage.cs @@ -28,6 +28,7 @@ using System; +using System.Net.Sockets; namespace MonoTorrent.Messages.UdpTracker { @@ -42,7 +43,7 @@ protected UdpTrackerMessage (int action, int transactionId) TransactionId = transactionId; } - public static UdpTrackerMessage DecodeMessage (ReadOnlySpan buffer, MessageType type) + public static UdpTrackerMessage DecodeMessage (ReadOnlySpan buffer, MessageType type, AddressFamily addressFamily) { UdpTrackerMessage m; var actionBuffer = type == MessageType.Request ? buffer.Slice (8) : buffer; @@ -58,7 +59,7 @@ public static UdpTrackerMessage DecodeMessage (ReadOnlySpan buffer, Messag if (type == MessageType.Request) m = new AnnounceMessage (); else - m = new AnnounceResponseMessage (); + m = new AnnounceResponseMessage (addressFamily); break; case 2: if (type == MessageType.Request) diff --git a/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/HTTPTrackerConnection.cs b/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/HTTPTrackerConnection.cs index 09eeed3e9..588c28961 100644 --- a/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/HTTPTrackerConnection.cs +++ b/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/HTTPTrackerConnection.cs @@ -33,6 +33,7 @@ using System.IO; using System.Linq; using System.Net.Http; +using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -52,6 +53,8 @@ public class HttpTrackerConnection : ITrackerConnection static readonly Random random = new Random (); + public AddressFamily AddressFamily { get; } + public bool CanScrape { get; } public Uri? ScrapeUri { get; } @@ -69,7 +72,14 @@ public class HttpTrackerConnection : ITrackerConnection HttpClient Client { get; } public HttpTrackerConnection (Uri announceUri, HttpClient client) + : this(announceUri, client, AddressFamily.InterNetwork) + { + + } + + public HttpTrackerConnection (Uri announceUri, HttpClient client, AddressFamily addressFamily) { + AddressFamily = addressFamily; Uri = announceUri; Client = client; @@ -282,9 +292,9 @@ AnnounceResponse HandleAnnounce (InfoHash infoHash, BEncodedDictionary dict) case ("peers"): if (keypair.Value is BEncodedList bencodedList) // Non-compact response - peers.AddRange (PeerDecoder.Decode (bencodedList)); + peers.AddRange (PeerDecoder.Decode (bencodedList, AddressFamily)); else if (keypair.Value is BEncodedString bencodedStr) // Compact response - peers.AddRange (PeerDecoder.Decode (bencodedStr)); + peers.AddRange (PeerInfo.FromCompact (bencodedStr.Span, AddressFamily)); break; case ("failure reason"): diff --git a/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/UdpTrackerConnection.cs b/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/UdpTrackerConnection.cs index e4fd02b2c..441ffb506 100644 --- a/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/UdpTrackerConnection.cs +++ b/src/MonoTorrent.Trackers/MonoTorrent.Connections.Tracker/UdpTrackerConnection.cs @@ -188,7 +188,7 @@ async Task ConnectAsync () { while (!token.IsCancellationRequested) { UdpReceiveResult received = await client.ReceiveAsync (); - var rsp = UdpTrackerMessage.DecodeMessage (received.Buffer.AsSpan (0, received.Buffer.Length), MessageType.Response); + var rsp = UdpTrackerMessage.DecodeMessage (received.Buffer.AsSpan (0, received.Buffer.Length), MessageType.Response, received.RemoteEndPoint.AddressFamily); if (transactionId == rsp.TransactionId) { if (rsp is ErrorMessage error) { diff --git a/src/MonoTorrent.Trackers/MonoTorrent.Connections.TrackerServer/UdpTrackerListener.cs b/src/MonoTorrent.Trackers/MonoTorrent.Connections.TrackerServer/UdpTrackerListener.cs index 63f019484..d75852eee 100644 --- a/src/MonoTorrent.Trackers/MonoTorrent.Connections.TrackerServer/UdpTrackerListener.cs +++ b/src/MonoTorrent.Trackers/MonoTorrent.Connections.TrackerServer/UdpTrackerListener.cs @@ -104,7 +104,7 @@ async void ReceiveAsync (UdpClient client, CancellationToken token) if (data.Length < 16) return; //bad request - var request = UdpTrackerMessage.DecodeMessage (data.AsSpan (0, data.Length), MessageType.Request); + var request = UdpTrackerMessage.DecodeMessage (data.AsSpan (0, data.Length), MessageType.Request, result.RemoteEndPoint.AddressFamily); if (sendTask != null) { try { @@ -180,16 +180,16 @@ protected virtual async Task ReceiveAnnounce (UdpClient client, AnnounceMessage case ("peers"): if (keypair.Value is BEncodedList) // Non-compact response - peers.AddRange (PeerDecoder.Decode ((BEncodedList) keypair.Value)); - else if (keypair.Value is BEncodedString) // Compact response - peers.AddRange (PeerDecoder.Decode ((BEncodedString) keypair.Value)); + peers.AddRange (PeerDecoder.Decode ((BEncodedList) keypair.Value, remotePeer.AddressFamily)); + else if (keypair.Value is BEncodedString str) // Compact response + peers.AddRange (PeerInfo.FromCompact (str.Span, remotePeer.AddressFamily)); break; default: break; } } - m = new AnnounceResponseMessage (announceMessage.TransactionId, interval, leechers, seeders, peers); + m = new AnnounceResponseMessage (remotePeer.AddressFamily, announceMessage.TransactionId, interval, leechers, seeders, peers); } byte[] data = m.Encode (); await client.SendAsync (data, data.Length, remotePeer); diff --git a/src/MonoTorrent/MonoTorrent.Connections.Peer/IPeerConnection.cs b/src/MonoTorrent/MonoTorrent.Connections.Peer/IPeerConnection.cs index 36589f351..9b26f78d3 100644 --- a/src/MonoTorrent/MonoTorrent.Connections.Peer/IPeerConnection.cs +++ b/src/MonoTorrent/MonoTorrent.Connections.Peer/IPeerConnection.cs @@ -29,6 +29,7 @@ using System; using System.Net; +using System.Net.Sockets; using ReusableTasks; diff --git a/src/MonoTorrent/MonoTorrent.csproj b/src/MonoTorrent/MonoTorrent.csproj index e3dc748f4..3f4b74960 100644 --- a/src/MonoTorrent/MonoTorrent.csproj +++ b/src/MonoTorrent/MonoTorrent.csproj @@ -2,6 +2,7 @@ false + true net6.0;net5.0;netcoreapp3.0;netstandard2.1;netstandard2.0 diff --git a/src/MonoTorrent/MonoTorrent/PeerInfo.cs b/src/MonoTorrent/MonoTorrent/PeerInfo.cs index 3917aaab2..094364545 100644 --- a/src/MonoTorrent/MonoTorrent/PeerInfo.cs +++ b/src/MonoTorrent/MonoTorrent/PeerInfo.cs @@ -28,9 +28,12 @@ using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; +using System.Linq; using System.Net; +using System.Net.Sockets; using System.Text; using MonoTorrent.BEncoding; @@ -44,6 +47,8 @@ public sealed class PeerInfo : IEquatable public Uri ConnectionUri { get; } + IPEndPoint? EndPoint { get; } + public PeerInfo (Uri connectionUri) : this (connectionUri, BEncodedString.Empty) { @@ -55,7 +60,13 @@ public PeerInfo (Uri connectionUri, BEncodedString peerId) } public PeerInfo (Uri connectionUri, BEncodedString peerId, bool maybeSeeder) - => (ConnectionUri, PeerId, MaybeSeeder) = (connectionUri ?? throw new ArgumentNullException (nameof (connectionUri)), peerId ?? throw new ArgumentNullException (nameof (BEncodedString)), maybeSeeder); + : this (connectionUri, peerId, maybeSeeder, IPAddress.TryParse (connectionUri.Host, out var ip) ? new IPEndPoint (ip, connectionUri.Port) : null) + { + + } + + internal PeerInfo (Uri connectionUri, BEncodedString peerId, bool maybeSeeder, IPEndPoint? endPoint) + => (ConnectionUri, PeerId, MaybeSeeder, EndPoint) = (connectionUri ?? throw new ArgumentNullException (nameof (connectionUri)), peerId ?? throw new ArgumentNullException (nameof (BEncodedString)), maybeSeeder, endPoint); public override bool Equals (object? obj) => Equals (obj as PeerInfo); @@ -67,77 +78,72 @@ public override int GetHashCode () => ConnectionUri.GetHashCode (); public byte[] CompactPeer () - => CompactPeer (ConnectionUri); - - public void CompactPeer (Span buffer) - => CompactPeer (ConnectionUri, buffer); - - public static byte[] CompactPeer (Uri uri) { - byte[] data = new byte[6]; - CompactPeer (uri, data); - return data; + var buffer = new byte[2 + (EndPoint!.AddressFamily == AddressFamily.InterNetworkV6 ? 16 : 4)]; + if (!TryWriteCompactPeer (ConnectionUri, buffer, out int written) || written != buffer.Length) + throw new InvalidOperationException (); + return buffer; } - public static void CompactPeer (Uri uri, Span buffer) + public bool TryWriteCompactPeer (Span buffer, out int written) + => TryWriteCompactPeer (ConnectionUri, buffer, out written); + + bool TryWriteCompactPeer (Uri uri, Span buffer, out int written) { - foreach (char value in uri.Host.AsSpan ()) { - if (value == '.') { - buffer = buffer.Slice (1); - } else if (value >= '0' && value <= '9') { - buffer[0] = (byte) (buffer[0] * 10 + (byte) (value - '0')); - } else { - throw new NotSupportedException ("Invalid character in what should have been an ip address."); - } + if(EndPoint == null) { + written = 0; + return false; } - buffer = buffer.Slice (1); - BinaryPrimitives.WriteUInt16BigEndian (buffer.Slice (0, 2), (ushort) uri.Port); + + if (!EndPoint.Address.TryWriteBytes (buffer, out written)) + return false; + + BinaryPrimitives.WriteUInt16BigEndian (buffer.Slice (written, 2), (ushort) uri.Port); + written += 2; + return true; } - public static IList FromCompact (ReadOnlySpan buffer) + public static IList FromCompact (ReadOnlySpan buffer, AddressFamily addressFamily) { - var sb = new StringBuilder (27); var list = new List ((buffer.Length / 6) + 1); - FromCompact (buffer, sb, list); + FromCompact (buffer, addressFamily, list); return list; } - public static IList FromCompact (IEnumerable data) + public static IList FromCompact (IEnumerable data, AddressFamily addressFamily) { - var sb = new StringBuilder (27); var list = new List (); foreach (var buffer in data) - FromCompact (buffer.AsSpan (), sb, list); + FromCompact (buffer, addressFamily, list); return list; } - static void FromCompact (ReadOnlySpan buffer, StringBuilder sb, List list) + static void FromCompact (ReadOnlySpan buffer, AddressFamily addressFamily, List results) { - // "Compact Response" peers are encoded in network byte order. - // IP's are the first four bytes - // Ports are the following 2 bytes - var byteOrderedData = buffer; - int i = 0; - ushort port; - while ((i + 5) < byteOrderedData.Length) { - sb.Remove (0, sb.Length); - - sb.Append ("ipv4://"); - sb.Append (byteOrderedData[i++]); - sb.Append ('.'); - sb.Append (byteOrderedData[i++]); - sb.Append ('.'); - sb.Append (byteOrderedData[i++]); - sb.Append ('.'); - sb.Append (byteOrderedData[i++]); - - port = BinaryPrimitives.ReadUInt16BigEndian (byteOrderedData.Slice (i)); - i += 2; - sb.Append (':'); - sb.Append (port); - - var uri = new Uri (sb.ToString ()); - list.Add (new PeerInfo (uri)); + (var sizeOfIP, var prefix) = addressFamily switch { + AddressFamily.InterNetwork => (4, "ipv4://"), + AddressFamily.InterNetworkV6 => (16, "ipv6://"), + _ => throw new NotSupportedException () + }; + + var stride = sizeOfIP + 2; + + // Round it off into a multipl eof 'stride' bytes. + buffer = buffer.Slice (0, (buffer.Length / stride) * stride); + + while (buffer.Length > 0) { + var ipBuffer = buffer.Slice (0, sizeOfIP); + var portBuffer = buffer.Slice (sizeOfIP, 2); +#if NETSTANDARD2_0 + var ip = new IPAddress (ipBuffer.ToArray ()); +#else + var ip = new IPAddress (ipBuffer); +#endif + var port = BinaryPrimitives.ReadUInt16BigEndian (portBuffer); + + var endPoint = new IPEndPoint (ip, port); + results.Add (new PeerInfo (new Uri (prefix + endPoint.ToString ()), BEncodedString.Empty, false, endPoint)); + buffer = buffer.Slice (stride); } } } diff --git a/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/PeerInfoTests.cs b/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/PeerInfoTests.cs index cdf5283b2..4154271ac 100644 --- a/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/PeerInfoTests.cs +++ b/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/PeerInfoTests.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Sockets; using MonoTorrent.BEncoding; @@ -35,7 +37,22 @@ public void CompactPeer () PeerInfo p = new PeerInfo (uri, peerId); byte[] compact = p.CompactPeer (); - var peer = PeerDecoder.Decode (compact)[0]; + var peer = PeerInfo.FromCompact (compact, AddressFamily.InterNetwork)[0]; + Assert.AreEqual (p.ConnectionUri, peer.ConnectionUri, "#1"); + Assert.AreEqual (p, peer, "#2"); + } + + [Test] + public void CompactPeerIPV6 () + { + string peerId = "12345abcde12345abcde"; + Uri uri = new Uri ($"ipv6://[{IPAddress.IPv6Any}]:12345"); + PeerInfo p = new PeerInfo (uri, peerId); + + byte[] compact = p.CompactPeer (); + Assert.AreEqual (18, compact.Length); + + var peer = PeerInfo.FromCompact (compact, AddressFamily.InterNetworkV6)[0]; Assert.AreEqual (p.ConnectionUri, peer.ConnectionUri, "#1"); Assert.AreEqual (p, peer, "#2"); } @@ -43,10 +60,10 @@ public void CompactPeer () [Test] public void CorruptDictionary () { - BEncodedList l = new BEncodedList (); - BEncodedDictionary d = new BEncodedDictionary (); - l.Add (d); - IList decoded = PeerDecoder.Decode (l); + BEncodedList l = new BEncodedList { + new BEncodedDictionary () + }; + IList decoded = PeerDecoder.Decode (l, AddressFamily.InterNetwork); Assert.AreEqual (0, decoded.Count, "#1"); } @@ -58,26 +75,26 @@ public void CorruptList () list.Add ((BEncodedString) peers[i].CompactPeer ()); list.Insert (2, new BEncodedNumber (5)); - VerifyDecodedPeers (PeerDecoder.Decode (list)); + VerifyDecodedPeers (PeerDecoder.Decode (list, AddressFamily.InterNetwork)); list.Clear (); list.Add (new BEncodedString (new byte[3])); - IList decoded = PeerDecoder.Decode (list); + IList decoded = PeerDecoder.Decode (list, AddressFamily.InterNetwork); Assert.AreEqual (0, decoded.Count, "#1"); } [Test] public void CorruptString () { - IList p = PeerDecoder.Decode ("1234"); + IList p = PeerInfo.FromCompact (new BEncodedString ("1234").Span, AddressFamily.InterNetwork); Assert.AreEqual (0, p.Count, "#1"); byte[] b = { 255, 255, 255, 255, 255, 255 }; - p = PeerDecoder.Decode (b); + p = PeerInfo.FromCompact (b, AddressFamily.InterNetwork); Assert.AreEqual (1, p.Count, "#2"); b = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; - p = PeerDecoder.Decode (b); + p = PeerInfo.FromCompact (b, AddressFamily.InterNetwork); Assert.AreEqual (1, p.Count, "#3"); } @@ -89,7 +106,7 @@ public void DecodeList () foreach (PeerInfo p in peers) list.Add ((BEncodedString) p.CompactPeer ()); - VerifyDecodedPeers (PeerDecoder.Decode (list)); + VerifyDecodedPeers (PeerDecoder.Decode (list, AddressFamily.InterNetwork)); } [Test] @@ -105,16 +122,18 @@ public void DecodeDictionary () list.Add (dict); } - VerifyDecodedPeers (PeerDecoder.Decode (list)); + VerifyDecodedPeers (PeerDecoder.Decode (list, AddressFamily.InterNetwork)); } [Test] public void DecodeCompact () { - byte[] bytes = new byte[peers.Count * 6]; + int stride = 6; + byte[] bytes = new byte[peers.Count * stride]; for (int i = 0; i < peers.Count; i++) - peers[i].CompactPeer (bytes.AsSpan (i * 6, 6)); - VerifyDecodedPeers (PeerDecoder.Decode (bytes)); + if (!peers[i].TryWriteCompactPeer (bytes.AsSpan (i * stride, stride), out int written) || written != stride) + Assert.Fail ("Incorrect number of bytes written"); + VerifyDecodedPeers (PeerInfo.FromCompact (bytes, AddressFamily.InterNetwork)); } [Test] @@ -127,7 +146,7 @@ public void DecodePeerId () }; dict["peer id"] = peerId; - var peer = PeerDecoder.Decode (new BEncodedList { dict }).Single (); + var peer = PeerDecoder.Decode (new BEncodedList { dict }, AddressFamily.InterNetwork).Single (); Assert.AreEqual (peerId, peer.PeerId, "#1"); } diff --git a/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/UdpTrackerTests.cs b/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/UdpTrackerTests.cs index c8602a7be..0de46f9fc 100644 --- a/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/UdpTrackerTests.cs +++ b/src/Tests/Tests.MonoTorrent.Client/MonoTorrent.Client/UdpTrackerTests.cs @@ -125,7 +125,7 @@ public void FixtureTeardown () public void AnnounceMessageTest () { AnnounceMessage m = new AnnounceMessage (0, 12345, announceparams, announceparams.InfoHashes.V1OrV2); - AnnounceMessage d = (AnnounceMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Request); + AnnounceMessage d = (AnnounceMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Request, AddressFamily.InterNetwork); Check (m, MessageType.Request); Assert.AreEqual (1, m.Action); @@ -138,8 +138,8 @@ public void AnnounceMessageTest () public void AnnounceResponseTest () { var peers = peerEndpoints.Select (t => new PeerInfo (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 (), MessageType.Response); + AnnounceResponseMessage m = new AnnounceResponseMessage (AddressFamily.InterNetwork, 12345, TimeSpan.FromSeconds (10), 43, 65, peers); + AnnounceResponseMessage d = (AnnounceResponseMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Response, AddressFamily.InterNetwork); Check (m, MessageType.Response); Assert.AreEqual (1, m.Action); @@ -152,7 +152,7 @@ public void AnnounceResponseTest () public void ConnectMessageTest () { ConnectMessage m = new ConnectMessage (); - ConnectMessage d = (ConnectMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Request); + ConnectMessage d = (ConnectMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Request, AddressFamily.InterNetwork); Check (m, MessageType.Request); Assert.AreEqual (0, m.Action, "#0"); @@ -166,7 +166,7 @@ public void ConnectMessageTest () public void ConnectResponseTest () { ConnectResponseMessage m = new ConnectResponseMessage (5371, 12345); - ConnectResponseMessage d = (ConnectResponseMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Response); + ConnectResponseMessage d = (ConnectResponseMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Response, AddressFamily.InterNetwork); Check (m, MessageType.Response); Assert.AreEqual (0, m.Action, "#0"); @@ -195,7 +195,7 @@ public void ScrapeMessageTest () hashes.Add (InfoHash.FromMemory (hash3)); ScrapeMessage m = new ScrapeMessage (12345, 123, hashes); - ScrapeMessage d = (ScrapeMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Request); + ScrapeMessage d = (ScrapeMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Request, AddressFamily.InterNetwork); Check (m, MessageType.Request); Assert.AreEqual (2, m.Action); @@ -213,7 +213,7 @@ public void ScrapeResponseTest () }; ScrapeResponseMessage m = new ScrapeResponseMessage (12345, details); - ScrapeResponseMessage d = (ScrapeResponseMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Response); + ScrapeResponseMessage d = (ScrapeResponseMessage) UdpTrackerMessage.DecodeMessage (m.Encode (), MessageType.Response, AddressFamily.InterNetwork); Check (m, MessageType.Response); Assert.AreEqual (2, m.Action); @@ -226,7 +226,7 @@ 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"); + Assert.IsTrue (Toolbox.ByteMatch (e, UdpTrackerMessage.DecodeMessage (e, type, AddressFamily.InterNetwork).Encode ()), "#2"); } [Test]