private static IEnumerable <Contact> LoadBootstrapData() { foreach (var line in File.ReadAllLines("Bootstrap.txt").OmitComments("#", "//")) { UdpContact udpC = null; try { string[] split = line.Split(' '); Guid a = Guid.Parse(split[0]); Guid b = Guid.Parse(split[1]); Guid c = Guid.Parse(split[2]); Guid d = Guid.Parse(split[3]); Identifier512 id = new Identifier512(a, b, c, d); IPAddress ip = IPAddress.Parse(split[4]); int port = Int32.Parse(split[5]); udpC = new UdpContact(id, networkId, ip, port); Console.WriteLine("Loaded bootstrap contact " + udpC); } catch (Exception e) { Console.WriteLine("Exception parsing bootstrap file: " + e); } if (udpC != null) { yield return(udpC); } } }
static void Main(string[] args) { myDomainMappings = ReadDomainMappings("MyDomainMappings.txt"); ReadSettings(ref dnsport, ref peerport); dnsServer = new DnsServer(new Dictionary <string, DomainMapping>() { { "hellequin.p2p", new DomainMapping() { Address = IPAddress.Parse("78.105.97.103"), Name = "hellequin.p2p", TimeToLive = TimeSpan.FromSeconds(1234) } } }); dnsServer.Start(); Identifier512 myId = Identifier512.NewIdentifier(); routingTable = new DistributedRoutingTable(Identifier512.NewIdentifier(), (a) => new UdpContact(a.LocalIdentifier, networkId, LocalIp, peerport), networkId, new Configuration()); UdpContact.InitialiseUdp(routingTable, peerport); Console.WriteLine("Bootstrapping DHT"); routingTable.Bootstrap(LoadBootstrapData()); Console.WriteLine("Bootstrap finished"); Console.WriteLine("There are " + routingTable.ContactCount + " Contacts"); Console.WriteLine("Press any key to close"); Console.ReadLine(); UdpContact.Stop(); }
/// <summary> /// Finds the closest contact in the network. Does several round trips to the network /// </summary> /// <param name="target">The target.</param> /// <returns>an IEnumerable<contact> in order of distance from the target. Can be cast into a GetClosestNodes.ClosestResults</contact></returns> public IEnumerable <Contact> GetClosestContacts(Identifier512 target, Func <Contact, bool> terminate = null) { MinMaxHeap <Contact> heap = new MinMaxHeap <Contact>(new ContactComparer(target), contacts.ClosestNodes(target).Take(RoutingTable.Configuration.LookupConcurrency)); HashSet <Identifier512> contacted = new HashSet <Identifier512>(); contacted.Add(RoutingTable.LocalIdentifier); int iterations = 0; HashSet <Contact> uniqueDiscoveries; do { iterations++; uniqueDiscoveries = new HashSet <Contact>( //hashet means we only get each result once heap //from the set of results we know about .Where(c => !contacted.Contains(c.Identifier)) //which we have not already contacted .SelectMany(c => { try { return(RemoteGetClosest(RoutingTable.LocalContact, c, target, RoutingTable.Configuration.LookupConcurrency, RoutingTable.Configuration.LookupTimeout)); } catch (TimeoutException) { return(null); } }) //select the closest ones they know about .Where(n => n != null) .Where(r => !heap.Contains(r))); //remove the results we already know about //Make the system aware of these potentially new nodes foreach (var c in uniqueDiscoveries) { contacts.Update(c); } //make sure we never contact these nodes again contacted.UnionWith(heap.Select(a => a.Identifier)); //add the new results heap.AddMany(uniqueDiscoveries); while (heap.Count > RoutingTable.Configuration.LookupConcurrency) { heap.RemoveMax(); } if (terminate != null) { if (uniqueDiscoveries.Where(a => terminate(a)).FirstOrDefault() != null) { break; } } }while (uniqueDiscoveries.Count != 0 && heap.Minimum.Identifier != target); return(new ClosestResults(heap, iterations)); //while (heap.Count > 0) // yield return heap.RemoveMin(); }
/// <summary> /// Create a new DistributedRoutingTable /// </summary> /// <param name="localIdentifier">The identifier of this node, or null to autogenerate one</param> /// <param name="createLocalContact">A factory function which creates a contact for this table</param> /// <param name="networkId">the ID of the network this routing table is part of</param> /// <param name="configuration">The configuration of this node</param> public DistributedRoutingTable(Identifier512 localIdentifier, Func <DistributedRoutingTable, Contact> createLocalContact, Guid networkId, Configuration configuration) { LocalIdentifier = localIdentifier != null ? localIdentifier : Identifier512.NewIdentifier(); NetworkId = networkId; Configuration = configuration; LocalContact = createLocalContact(this); contacts = new ContactCollection(this); //Register internal consumers RegisterConsumer(MessageCallback = new Callback()); RegisterConsumer(getClosest = new GetClosestNodes(contacts, MessageCallback)); }
/// <summary> /// Returns an enumeration of all nodes in ascending order of distance from the given identifier /// </summary> /// <param name="identifier">The identifier.</param> /// <returns></returns> public IEnumerable <Contact> ClosestNodes(Identifier512 identifier) { int mid = Identifier512.CommonPrefixLength(identifier, LocalIdentifier); if (mid != 512) { foreach (var contact in buckets[mid].OrderWithComparer(new ContactComparer(identifier))) { yield return(contact); } } //loop through buckets, moving up and down from mid concatenating the two buckets either side of mid and returning them in order of distance List <Contact> contacts = new List <Contact>(); bool moreLow = true; bool moreHigh = true; for (int i = 1; moreHigh || moreLow; i++) { int indexHigh = mid + i; int indexLow = mid - i; contacts.Clear(); if (indexHigh >= buckets.Length) { moreHigh = false; } else { contacts.AddRange(buckets[indexHigh]); } if (indexLow < 0) { moreLow = false; } else { contacts.AddRange(buckets[indexLow]); } foreach (var contact in contacts.OrderWithComparer(new ContactComparer(identifier))) { yield return(contact); } } }
/// <summary> /// Gets the closest nodes the remote contact has to a given contact /// </summary> /// <param name="local">The local contact</param> /// <param name="remote">The remote node to ask</param> /// <param name="target">The target to search for</param> /// <param name="limit">The limit of items to return</param> /// <param name="timeout">The maximum time to wait</param> /// <returns>a collection of contacts in order of distance from the target, or null if timed out</returns> public IEnumerable <Contact> RemoteGetClosest(Contact local, Contact remote, Identifier512 target, int limit, int timeout) { var token = callback.AllocateToken(); RequestMessage request = new RequestMessage(token.Id, target, limit); using (MemoryStream mStream = new MemoryStream()) { Serializer.Serialize <RequestMessage>(mStream, request); remote.Send(local, ConsumerId, mStream.ToArray()); } if (!token.Wait(timeout)) { throw new TimeoutException(); } callback.FreeToken(token); return(DecodeResponse(token.Response)); }
/// <summary> /// Moves the specified contact to the top of the most recently used queue /// </summary> /// <param name="source">The source.</param> internal void Update(Contact source) { if (Configuration.UpdateRoutingTable) { if (source == null) { return; } if (source.Identifier == LocalIdentifier) { return; } if (source.NetworkId != NetworkId) { throw new ArgumentException("Network Id of contact and ContactCollection must be the same"); } buckets[Identifier512.CommonPrefixLength(source.Identifier, LocalIdentifier)].Update(source); } }
private static UdpContact ReadContact(BinaryReader reader) { int idBytesLength = IPAddress.NetworkToHostOrder(reader.ReadInt32()); byte[] idBytes = reader.ReadBytes(idBytesLength); Identifier512 id = new Identifier512(idBytes); int netIdBytesLength = IPAddress.NetworkToHostOrder(reader.ReadInt32()); byte[] netIdBytes = reader.ReadBytes(netIdBytesLength); Guid netId = new Guid(netIdBytes); int port = IPAddress.NetworkToHostOrder(reader.ReadInt32()); int addrBytesLength = IPAddress.NetworkToHostOrder(reader.ReadInt32()); byte[] addrBytes = reader.ReadBytes(addrBytesLength); IPAddress address = new IPAddress(addrBytes); return(new UdpContact(id, netId, address, port)); }
private static void ReadSettings(ref int dnsport, ref int peerport) { foreach (var line in File.ReadAllLines("Settings.txt").OmitComments("#", "//").Select(a => a.ToLowerInvariant().Replace(" ", "").Replace("\t", "").Split('='))) { switch (line[0]) { case "dnsport": dnsport = Int32.Parse(line[1]); break; case "peerport": peerport = Int32.Parse(line[1]); break; case "localip": LocalIp = IPAddress.Parse(line[1]); break; case "networkid": networkId = Guid.Parse(line[1]); break; case "routingidentifier": var s = line[1].Split(','); routingIdentifier = new Identifier512(Guid.Parse(s[0]), Guid.Parse(s[1]), Guid.Parse(s[2]), Guid.Parse(s[3])); break; default: Console.WriteLine("Unknown setting " + line[0]); break; } } }
public RequestMessage(long callbackId, Identifier512 target, int limit) { CallbackId = callbackId; Target = target; Limit = limit; }
/// <summary> /// Initializes a new instance of the <see cref="Contact"/> class. /// </summary> /// <param name="identifier">The identifier of the DistributedRoutingTable this contact represents</param> /// <param name="networkId">The network id.</param> public Contact(Identifier512 identifier, Guid networkId) { Identifier = identifier; networkIdBytes = networkId.ToByteArray(); }
public UdpContact(Identifier512 id, Guid networkId, IPAddress ip, int port) : base(id, networkId) { Ip = ip; Port = port; }
/// <summary> /// Initializes a new instance of the <see cref="ContactComparer"/> class. /// </summary> /// <param name="target">The target.</param> public ContactComparer(Identifier512 target) { comparer = new IdentifierComparer(target); }