From 70d9aebc9d9c9d90383c32a67ef4ad8f9772d26a Mon Sep 17 00:00:00 2001 From: Darren Horrocks Date: Sat, 22 Nov 2014 13:45:09 +0000 Subject: [PATCH] local peer discovery --- LocalPeerDiscovery.cs | 97 ++++++++++++++++++++++++++++++++++++------- README.md | 8 ++-- 2 files changed, 85 insertions(+), 20 deletions(-) diff --git a/LocalPeerDiscovery.cs b/LocalPeerDiscovery.cs index d5b097e..bf1da3f 100644 --- a/LocalPeerDiscovery.cs +++ b/LocalPeerDiscovery.cs @@ -1,4 +1,5 @@ -using System.Net.Sockets; +using System.Diagnostics; +using System.Net.Sockets; using System.Text; using System.Threading; @@ -10,57 +11,105 @@ public class LocalPeerDiscovery private const int lpdMulticastPort = 6771; private readonly Socket udpReaderSocket; + private readonly Socket udpSenderSocket; private Thread thread; private bool _killSwitch; public delegate void NewPeerCB(IPAddress address, int port, String infoHash); - public event NewPeerCB NewPeer; + private int ttl = 8; + + public int TTL + { + get { return ttl; } + set + { + ttl = value; + + udpSenderSocket.SetSocketOption(SocketOptionLevel.IP, + SocketOptionName.MulticastTimeToLive, + ttl); + } + } + public LocalPeerDiscovery() { udpReaderSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + udpSenderSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); } - public LocalPeerDiscovery(Socket socket) + public LocalPeerDiscovery(Socket receive, Socket send) + { + ValidateSocket(receive, "receive"); + ValidateSocket(send, "send"); + + udpReaderSocket = receive; + udpSenderSocket = send; + } + + [DebuggerHidden, DebuggerStepThrough] + private void ValidateSocket(Socket socket, String name) { if (socket == null) { - throw new ArgumentNullException("socket"); + throw new ArgumentNullException(name); } if (socket.ProtocolType != ProtocolType.Udp) { - throw new ArgumentException("socket must be a UDP socket", "socket"); + throw new ArgumentException("socket must be a UDP socket", name); } if (socket.SocketType != SocketType.Dgram) { - throw new ArgumentException("socket must be a datagram socket", "socket"); + throw new ArgumentException("socket must be a datagram socket", name); } - - udpReaderSocket = socket; } public void Open() { + IPAddress address = IPAddress.Parse(lpdMulticastAddress); + SetupReaderSocket(address, lpdMulticastPort); + SetupSenderSocket(address, lpdMulticastPort); + + thread = new Thread(Process); + thread.Start(); + } + + private void SetupReaderSocket(IPAddress address, int port) + { + var endPoint = new IPEndPoint(IPAddress.Any, port); + udpReaderSocket.ExclusiveAddressUse = false; udpReaderSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - IPAddress address = IPAddress.Parse(lpdMulticastAddress); - - var endPoint = new IPEndPoint(IPAddress.Any, lpdMulticastPort); udpReaderSocket.Bind(endPoint); - udpReaderSocket.SetSocketOption(SocketOptionLevel.IP, - SocketOptionName.AddMembership, + udpReaderSocket.SetSocketOption(SocketOptionLevel.IP, + SocketOptionName.AddMembership, new MulticastOption(address, IPAddress.Any)); + } - thread = new Thread(Process); - thread.Start(); + private void SetupSenderSocket(IPAddress address, int port) + { + var endPoint = new IPEndPoint(address, port); + + udpReaderSocket.ExclusiveAddressUse = false; + udpReaderSocket.SetSocketOption(SocketOptionLevel.Socket, + SocketOptionName.ReuseAddress, + true); + udpSenderSocket.SetSocketOption(SocketOptionLevel.IP, + SocketOptionName.AddMembership, + new MulticastOption(address)); + udpSenderSocket.SetSocketOption(SocketOptionLevel.IP, + SocketOptionName.MulticastTimeToLive, + TTL); + + udpSenderSocket.Connect(endPoint); } public void Close() @@ -69,6 +118,7 @@ public void Close() thread.Abort(); udpReaderSocket.Close(); + udpSenderSocket.Close(); } private void Process() @@ -114,5 +164,22 @@ private void Process() } } } + + public void Announce(int listeningPort, String infoHash) + { + String message = String.Format("BT-SEARCH * HTTP/1.1\r\n" + + "Host: {2}:{3}\r\n" + + "Port: {0}\r\n" + + "Infohash: {1}\r\n" + + "\r\n\r\n", + listeningPort, + infoHash, + lpdMulticastAddress, + lpdMulticastPort); + + byte[] buffer = Encoding.ASCII.GetBytes(message); + + udpSenderSocket.Send(buffer); + } } } diff --git a/README.md b/README.md index 3fff936..6f7dc26 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,8 @@ System.Net.Torrent Open source bittorrent scraper and peer wire implementation written in C# -- [x] UDP Announce -- [x] UDP Scrape -- [x] HTTP Announce -- [x] HTTP Scrape +- [x] Tracker Announce (HTTP/UDP) +- [x] Tracker Scrape (HTTP/UDP) - [x] PeerWire (TCP) Client - [x] Choke - [x] Unchoke @@ -18,6 +16,6 @@ Open source bittorrent scraper and peer wire implementation written in C# - [x] Piece - [x] Fast Protocol Extensions - [x] Extended Protocol Extensions -- [ ] Local Peer Discovery +- [x] Local Peer Discovery (Non-existant Multicast BEP-14) - [x] Peer Exchange (utPEX) - [x] Trackerless Metadata (utMetadata) \ No newline at end of file