internal StoreObjectClient(KyruApplication app, NodeInformation targetNode, KademliaId objectId, byte[] bytes, Action<Error> done) : base(app, targetNode) { this.objectId = objectId; this.bytes = bytes; this.done = done; }
public void TestKademliaBucket() { var bytes = new byte[20]; bytes[19] = 0xff; var id = new KademliaId(bytes); Assert.AreEqual(7, id.KademliaBucket()); bytes[19] = 0x89; id = new KademliaId(bytes); Assert.AreEqual(7, id.KademliaBucket()); bytes[19] = 0x01; id = new KademliaId(bytes); Assert.AreEqual(0, id.KademliaBucket()); bytes[19] = 0x74; id = new KademliaId(bytes); Assert.AreEqual(6, id.KademliaBucket()); bytes[10] = 0xff; id = new KademliaId(bytes); Assert.AreEqual(79, id.KademliaBucket()); bytes[0] = 0xff; id = new KademliaId(bytes); Assert.AreEqual(159, id.KademliaBucket()); }
/// <summary> /// Returns the metadata if it is stored, otherwise null. /// </summary> internal KyruObjectMetadata[] Get(KademliaId id) { lock (storage) { List<KyruObjectMetadata> metadata; if (storage.TryGetValue(id, out metadata) && metadata.Count != 0) return metadata.ToArray(); return null; } }
internal KyruObject GetObject(KademliaId id) { var bytes = Get(id); if (bytes == null) return null; using (var stream = new MemoryStream(bytes)) { var obj = Serializer.Deserialize<KyruObject>(stream); obj.ObjectId = id; return obj; } }
public void TestToString() { var bytes = new byte[20]; var id = new KademliaId(bytes); // Length must be okay Assert.AreEqual("0000000000000000000000000000000000000000", id.ToString().ToLower()); bytes[0] = 0xff; id = new KademliaId(bytes); Assert.AreEqual("ff00000000000000000000000000000000000000", id.ToString().ToLower()); bytes[0] = 0x00; bytes[19] = 0xff; id = new KademliaId(bytes); Assert.AreEqual("00000000000000000000000000000000000000ff", id.ToString().ToLower()); }
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 PrepareKademlia() { node = new Node(null); kademlia = node.Kademlia; node2 = new Node(12345, null); kademlia2 = node.Kademlia; targetEndPoint = new IPEndPoint(IPAddress.Loopback, 12345); targetId = node2.Id; node.Start(); node2.Start(); kademlia.AddNode(new IPEndPoint(IPAddress.Loopback, 12345)); Thread.Sleep(TestParameters.LocalhostCommunicationTimeout); }
internal Chunk(byte[] data, KademliaId objectId) { Data = data; ObjectId = objectId; }
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> /// Determines whether an object is locally stored. If it is, the access timestamp is updated. /// </summary> /// <returns>Whether the object with this id is locally stored.</returns> internal bool KeepObject(KademliaId id) { if (currentObjects.ContainsKey(id)) { currentObjects[id] = DateTime.Now; return true; } return false; }
internal void GetObjectFromNode(List<NodeInformation> nodes, KademliaId objectId, Action<Error, byte[]> done) { if (nodes.Count == 0) { done(Error.NotFound, null); return; } // TODO: implement fallback to next nodes in list in GetObjectClient new Thread(new GetObjectClient(app, nodes[0], objectId, done).ThreadStart).Start(); }
internal void GetObjectFromNetwork(KademliaId objectId, Action<Error, byte[]> done) { Kademlia.ValueLookup(objectId, node => { if (node == null) done(Error.NotFound, null); else GetObjectFromNode(node, objectId, done); }); }
private bool GetKContacts(List<NodeInformation> contacts, int bucket, KademliaId ignoreId) { foreach (var contact in buckets[bucket]) { if (contact.Node.NodeId == ignoreId) continue; contacts.Add(contact.Node); if (contacts.Count == k) return true; } return false; }
/// <summary> /// Removes a node that didn't respond from the Kademlia contact list. /// </summary> internal void RemoveNode(KademliaId nodeId) { var bucket = (node.Id - nodeId).KademliaBucket(); if (buckets[bucket].RemoveAll(n => n.Node.NodeId == nodeId) != 0) { this.Log("Removing contact {0}", nodeId); } }
/// <summary> /// Adds a known-good node to the kademlia contacts. This must only be called if the identity of the node is verified, such as with correct ping replies or a TCP connection. /// </summary> internal void AddVerifiedNode(IPEndPoint endPoint, KademliaId nodeId) { AddContact(new NodeInformation(endPoint, nodeId)); }
/// <summary>Sends an UDP message to a given node.</summary> /// <param name="message">The message to be sent.</param> /// <param name="target">The address of the target node.</param> /// <param name="targetNodeId">The target node ID.</param> internal void SendUdpMessage(UdpMessage message, IPEndPoint target, KademliaId targetNodeId) { message.RequestId = Random.UInt64(); message.SenderNodeId = Id; var requestIdentifier = new RequestIdentifier {EndPoint = target, RequestId = message.RequestId}; var requestInformation = new RequestInformation {OutgoingMessage = message, SecondAttempt = false, NodeId = targetNodeId}; if (message.IsRequest) { lock (outstandingRequests) { outstandingRequests.Add(requestIdentifier, requestInformation); } } SendUdp(message, target); }
internal void StoreObject(KademliaId objectId, byte[] bytes) { // TODO: store at one node, not at all new Thread(() => Kademlia.NodeLookup(KademliaId.RandomId, list => { foreach (var item in list) { StoreObject(item, objectId, bytes, error => { }); } })).Start(); }
internal void StoreObject(NodeInformation targetNode, KademliaId objectId, byte[] bytes, Action<Error> done) { new Thread(new StoreObjectClient(app, targetNode, objectId, bytes, done).ThreadStart).Start(); }
public void AllZeroIdMustNotHaveKademliaBucket() { var id = new KademliaId(new byte[20]); id.KademliaBucket(); }
internal GetObjectClient(KyruApplication app, NodeInformation targetNode, KademliaId objectId, Action<Error, byte[]> done) : base(app, targetNode) { this.objectId = objectId; this.done = done; }
private void VerifyOwnership(KademliaId objectId, KyruObjectMetadata newItem) { var message = new UdpMessage(); message.KeepObjectRequest = new KeepObjectRequest(); message.KeepObjectRequest.ObjectId = objectId; message.ResponseCallback = delegate(UdpMessage udpMessage) { if (!udpMessage.KeepObjectResponse.HasObject) return; lock (storage) { if (!storage.ContainsKey(objectId)) storage[objectId] = new List<KyruObjectMetadata>(); newItem.Timestamp = DateTime.Now.UnixTimestamp(); storage[objectId].Add(newItem); } }; node.SendUdpMessage(message, new IPEndPoint(newItem.IpAddress, newItem.Port), newItem.NodeId); }
/// <summary> /// Stores the data on this node /// </summary> /// <param name="id">the id</param> /// <param name="bytes">data</param> internal void StoreBytes(KademliaId id, byte[] bytes, bool replicate) { using (var st = new MemoryStream(bytes)) { var obj = Serializer.Deserialize<KyruObject>(st); obj.ObjectId = id; if (obj is User) { StoreObject(obj, replicate); return; } if (!VerifyObject(obj)) return; } Store(id, bytes, replicate); }
internal void Store(KademliaId id, KyruObjectMetadata[] newMetadata) { lock (storage) { if (!storage.ContainsKey(id)) { storage[id] = new List<KyruObjectMetadata>(); } var metadata = storage[id]; foreach (var newItem in newMetadata) { // make sure the timestamp isn't in the future newItem.Timestamp = Math.Min(DateTime.Now.UnixTimestamp(), newItem.Timestamp); var item = metadata.FirstOrDefault(m => m.IpAddress == newItem.IpAddress && m.NodeId == newItem.NodeId); if (item == null) { VerifyOwnership(id, newItem); metadata.Add(newItem); } else { item.Timestamp = Math.Max(item.Timestamp, newItem.Timestamp); } } } }
private byte[] Get(KademliaId id) { if (id.Bytes.All(b => b == 0)) throw new InvalidOperationException("Possible bug: tried to get object with id zero"); if (currentObjects.ContainsKey(id)) currentObjects[id] = DateTime.Now; else return null; return File.ReadAllBytes(PathFor(id)); }
internal List<NodeInformation> NearestContactsTo(KademliaId nearToId, KademliaId ignoreId) { var bucketId = nearToId.KademliaBucket(); var contacts = new List<NodeInformation>(); for (int i = bucketId; i >= 0; i--) { if (GetKContacts(contacts, i, ignoreId)) return contacts; } for (int i = bucketId + 1; i < KademliaId.Size; i++) { if (GetKContacts(contacts, i, ignoreId)) return contacts; } return contacts; }
private string PathFor(KademliaId id) { return Path.Combine(config.StoreDirectory, id.ToString()); }
internal void ValueLookup(KademliaId id, Action<List<NodeInformation>> done) { new Thread(new ValueLookup(node, id, done).ThreadStart).Start(); }
private void Store(KademliaId id, byte[] bytes, bool replicate) { if (id.Bytes.All(b => b == 0)) throw new InvalidOperationException("Possible bug: tried to store object with id zero"); if (bytes.Length > MaxObjectSize + 8) // TODO: remove hack. (8 bytes overhead for 1 MiB chunk) { this.Warn("Object larger than 1 MiB; it will not be stored. ID: {0}", id); return; } File.WriteAllBytes(PathFor(id), bytes); currentObjects[id] = DateTime.Now; if (replicate) node.StoreObject(id, bytes); }
internal byte[] GetBytes(KademliaId id) { return Get(id); }
public NodeInformation(IPEndPoint endPoint, KademliaId nodeId) { NodeId = nodeId; IpAddress = BitConverter.ToUInt32(endPoint.Address.GetAddressBytes(), 0); Port = (ushort) endPoint.Port; }