internal static void PrepareOverlappedFakeContacts(Kademlia kademlia1, Kademlia kademlia2, int contacts) { for (int i = 0; i < contacts; i++) { var id = KademliaId.RandomId; var ni = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12345), id); RegisterFakeContact(kademlia1, ni); } for (int i = 0; i < contacts; i++) { var id = KademliaId.RandomId; var ni = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12345), id); RegisterFakeContact(kademlia2, ni); } for (int i = 0; i < contacts; i++) { var id = KademliaId.RandomId; var ni = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12345), id); RegisterFakeContact(kademlia1, ni); RegisterFakeContact(kademlia2, ni); } }
internal void RemoveFromKademliaWhenRequestTimeout() { var id = KademliaId.RandomId; var ni = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 65432), id); var message = new UdpMessage(); kademlia.HandleIncomingRequest(ni, message); var response = new UdpMessage(); response.ResponseId = message.RequestId; response.SenderNodeId = id; message.ResponseCallback(response); Assert.AreEqual(1, kademlia.CurrentContactCount); // actual test bool noResponse = false; message = new UdpMessage(); message.PingRequest = new PingRequest(); message.ResponseCallback = udpMessage => Assert.Fail("The response callback should not be called in this test"); message.NoResponseCallback = () => noResponse = true; node.SendUdpMessage(message, ni.EndPoint, id); for (int i = 0; i < Node.TimeoutTicks; i++) node.TimerElapsed(); Assert.AreEqual(1, kademlia.CurrentContactCount); for (int i = 0; i < Node.TimeoutTicks; i++) node.TimerElapsed(); Assert.IsTrue(noResponse, "The no-response callback should be called in this test"); Assert.AreEqual(0, kademlia.CurrentContactCount); }
internal static void RegisterFakeContact(Kademlia kademlia, NodeInformation ni) { var message = new UdpMessage(); kademlia.HandleIncomingRequest(ni, message); if (message.ResponseCallback == null) return; var response = new UdpMessage(); response.ResponseId = message.RequestId; response.SenderNodeId = ni.NodeId; message.ResponseCallback(response); }
internal void PrepareKademlia() { node = new Node(null); kademlia = node.Kademlia; node2 = new Node(12345, null); kademlia2 = node2.Kademlia; targetId = node2.Id; var ni = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12345), targetId); TestHelper.RegisterFakeContact(kademlia, ni); // set LastSeen to a time beyond the ping interval var contact = Mirror.ForObject(kademlia)["FirstContact"].Invoke(); Mirror.ForObject(contact)["LastSeen"].Value = DateTime.Now - TimeSpan.FromHours(1.1); }
internal void KademliaContactsAfterNewContact() { for (int i = 0; i < 10; i++) { var id = KademliaId.RandomId; var ni = new NodeInformation(new IPEndPoint(i + 1, i + 1), id); var message = new UdpMessage(); kademlia.HandleIncomingRequest(ni, message); Assert.AreEqual(i, kademlia.CurrentContactCount); Assert.IsNotNull(message.PingRequest); var response = new UdpMessage(); response.ResponseId = message.RequestId; response.SenderNodeId = id; message.ResponseCallback(response); Assert.AreEqual(i + 1, kademlia.CurrentContactCount); } }
internal void CreateNodes() { KyruTimer.Reset(); nodeA = new KyruApplication(12345).Node; nodeB = new KyruApplication(12346).Node; nodeC = new KyruApplication(12347).Node; nodeAInfo = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12345), nodeA.Id); nodeBInfo = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12346), nodeB.Id); nodeCInfo = new NodeInformation(new IPEndPoint(IPAddress.Loopback, 12347), nodeC.Id); nodeA.Start(); nodeB.Start(); nodeC.Start(); nodeA.Kademlia.AddNode(nodeBInfo.EndPoint); nodeC.Kademlia.AddNode(nodeBInfo.EndPoint); KyruTimer.Start(); Thread.Sleep(TestParameters.LocalhostCommunicationTimeout); }
private bool Equals(NodeInformation other) { return Equals((KademliaId)NodeId, (KademliaId)other.NodeId) && IpAddress == other.IpAddress && Port == other.Port; }
internal KnownNode(NodeInformation node) { Node = node; LastSeen = DateTime.Now; }
/// <returns>Whether the contact needs to be pinged.</returns> private bool IsNewContact(NodeInformation contact) { if (node.Id == contact.NodeId) return false; var bucket = buckets[(node.Id - contact.NodeId).KademliaBucket()]; if (bucket.Count >= k) { // the bucket is full return false; } return bucket.Find(n => n.Node == contact) == null; }
private void AddContact(NodeInformation contact) { if (node.Id == contact.NodeId) return; var bucketIndex = (node.Id - contact.NodeId).KademliaBucket(); var bucket = buckets[bucketIndex]; var existingContact = bucket.FirstOrDefault(n => n.Node == contact); if (existingContact == null) { if (bucket.Count >= k) { // the bucket is full return; } //this.Log("Adding contact {0} ({1})", contact.NodeId, contact.EndPoint); bucket.Add(new KnownNode(contact)); if (CurrentContactCount == 1) { // populate the contacts list NodeLookup(node.Id, nodes => { foreach (var n in nodes) { NodeLookup(n.NodeId, _ => { }); } }); } } else { existingContact.LastSeen = DateTime.Now; } }
/// <summary> /// Notifies Kademlia about incoming request messages, to maintain the contact list. If necessary, a ping request is added to the response message. /// </summary> /// <param name="sendingNode">The node that sent us a request.</param> /// <param name="outgoingMessage">The message object that will be sent.</param> internal void HandleIncomingRequest(NodeInformation sendingNode, UdpMessage outgoingMessage) { if (sendingNode.NodeId == node.Id) return; if (IsNewContact(sendingNode)) { outgoingMessage.PingRequest = new PingRequest(); outgoingMessage.ResponseCallback = message => AddContact(new NodeInformation(sendingNode.EndPoint, message.SenderNodeId)); } else { AddContact(sendingNode); } }
/// <summary>Processes an incoming FindNode request.</summary> /// <param name="node">The sending node</param> /// <param name="request">The message received from the sending node</param> private void IncomingFindNode(NodeInformation node, UdpMessage request) { UdpMessage response = CreateUdpReply(request); Kademlia.HandleIncomingRequest(node, response); var contacts = Kademlia.NearestContactsTo(request.FindNodeRequest.NodeId, node.NodeId); response.FindNodeResponse = new FindNodeResponse(); response.FindNodeResponse.Nodes = contacts.ToArray(); SendUdpMessage(response, node); }
private void StoreTestObject() { // create the test object objectId = KademliaId.RandomId; var chunkId = KademliaId.RandomId; var user = new User(); user.ObjectId = objectId; var userFile = new UserFile(); userFile.ChunkList.Add(chunkId); user.Add(userFile); var ms = new MemoryStream(); Serializer.Serialize(ms, user); bytes = ms.ToArray(); // store it var ct = new CallbackTimeout<Error>(); var ni = new NodeInformation(new IPEndPoint(IPAddress.Loopback, nodes[1].Port), nodes[1].Id); nodes[0].StoreObject(ni, objectId, bytes, ct.Done); if (!ct.Block(TestParameters.LocalhostCommunicationTimeout)) { Assert.Fail("No response within timeout"); } Assert.AreEqual(Error.Success, ct.Result); }
/// <summary>Processes an incoming FindValue request.</summary> /// <param name="node">The sending node</param> /// <param name="request">The message received from the sending node</param> private void IncomingFindValue(NodeInformation node, UdpMessage request) { UdpMessage response = CreateUdpReply(request); Kademlia.HandleIncomingRequest(node, response); response.FindValueResponse = new FindValueResponse(); var metadata = MetadataStorage.Get(request.FindValueRequest.ObjectId); if (metadata == null) { var contacts = Kademlia.NearestContactsTo(request.FindValueRequest.ObjectId, request.SenderNodeId); response.FindValueResponse.Nodes = contacts.ToArray(); } else { response.FindValueResponse.Data = metadata; } SendUdpMessage(response, node); }
internal void StoreObject(NodeInformation targetNode, KademliaId objectId, byte[] bytes, Action<Error> done) { new Thread(new StoreObjectClient(app, targetNode, objectId, bytes, done).ThreadStart).Start(); }
/// <summary>Sends an UDP message to a given node.</summary> /// <param name="message">The message to be sent.</param> /// <param name="targetNode">The target node.</param> private void SendUdpMessage(UdpMessage message, NodeInformation targetNode) { SendUdpMessage(message, targetNode.EndPoint, targetNode.NodeId); }
private void OnUdpReceive(IAsyncResult ar) { if (!running) { return; } var endPoint = new IPEndPoint(IPAddress.Any, 0); var data = udp.EndReceive(ar, ref endPoint); UdpListen(); var ms = new MemoryStream(data); var protocolVersion = ms.ReadByte(); if (protocolVersion != ProtocolVersion) { this.Warn("Ignoring message from {0} with unknown protocol version {1}", endPoint, protocolVersion); return; } var incomingMessage = Serializer.Deserialize<UdpMessage>(ms); if (!incomingMessage.Validate(endPoint)) return; var ni = new NodeInformation(endPoint, incomingMessage.SenderNodeId); if (incomingMessage.ResponseId != 0) { var identifier = new RequestIdentifier {EndPoint = ni.EndPoint, RequestId = incomingMessage.ResponseId}; lock (outstandingRequests) { if (!outstandingRequests.ContainsKey(identifier)) { this.Warn("{2} from {0} has unknown response ID {1:X16}", endPoint, incomingMessage.ResponseId, incomingMessage.Inspect()); } else { var request = outstandingRequests[identifier]; if (request.NodeId != null && request.NodeId != incomingMessage.SenderNodeId) { this.Warn("In {0}, node ID from {1} does not match (expected {2}, received {3})", incomingMessage.Inspect(), endPoint, request.NodeId, (KademliaId) incomingMessage.SenderNodeId); } else { outstandingRequests.Remove(identifier); // the callback will deal with handling the actual response request.OutgoingMessage.ResponseCallback(incomingMessage); } } } } if (incomingMessage.PingRequest != null) { IncomingPing(ni, incomingMessage); } else if (incomingMessage.FindNodeRequest != null) { IncomingFindNode(ni, incomingMessage); } else if (incomingMessage.FindValueRequest != null) { IncomingFindValue(ni, incomingMessage); } else if (incomingMessage.StoreRequest != null) { IncomingStore(ni, incomingMessage); } else if (incomingMessage.KeepObjectRequest != null) { IncomingKeepObject(ni, incomingMessage); } }
/// <summary>Processes an incoming Store request.</summary> /// <param name="node">The sending node</param> /// <param name="request">The message received from the sending node</param> private void IncomingStore(NodeInformation node, UdpMessage request) { UdpMessage response = CreateUdpReply(request); Kademlia.HandleIncomingRequest(node, response); MetadataStorage.Store(request.StoreRequest.ObjectId, request.StoreRequest.Data); response.StoreResponse = new StoreResponse(); SendUdpMessage(response, node); }
/// <summary>Processes an incoming Ping request.</summary> /// <param name="node">The sending node</param> /// <param name="request">The message received from the sending node</param> private void IncomingPing(NodeInformation node, UdpMessage request) { UdpMessage response = CreateUdpReply(request); Kademlia.HandleIncomingRequest(node, response); SendUdpMessage(response, node); }
/// <summary>Processes an incoming KeepObject request.</summary> /// <param name="node">The sending node</param> /// <param name="request">The message received from the sending node</param> private void IncomingKeepObject(NodeInformation node, UdpMessage request) { UdpMessage response = CreateUdpReply(request); Kademlia.HandleIncomingRequest(node, response); response.KeepObjectResponse = new KeepObjectResponse(); response.KeepObjectResponse.HasObject = app.LocalObjectStorage.KeepObject(request.KeepObjectRequest.ObjectId); SendUdpMessage(response, node); }