/// <summary> /// Find contact's closest nodes to id /// </summary> /// <param name="node">Node to query</param> /// <param name="id">Id to compare</param> /// <returns>Closest nodes to id</returns> public IEnumerable <ContactNode> FindNode(ContactNode node, Id id) { Message.MnlMessage msg = new Message.MnlMessage.Builder() .SetType(MessageType.Query) .SetQueryType(QueryType.FindNode) .SetOriginatorId(Id) .Build(); msg.Payload.Add("target", id.Value); Message.MnlMessage response = _server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response; List <ContactNode> nodes = new List <ContactNode>(); if (response == null) { return(nodes); } UpdateLastSeen(node); if (response.Payload.ContainsKey("nodes")) { byte[] nodeString = (byte[])response.Payload["nodes"]; int offset = 0; while (offset < nodeString.Length) { nodes.Add(new ContactNode(nodeString, ref offset)); } } return(nodes); }
public MnlMessage SendMessageSync(ContactNode toNode, Message.MnlMessage msg, bool validate, int timeout) { msg.TranId = GenerateTranId(); ManualResetEventSlim eventReset = new ManualResetEventSlim(); msg.AddCallback((m) => eventReset.Set()); ulong msgId = GetMessageId(toNode.EndPoint.Address, BitConverter.ToUInt16(Encoding.ASCII.GetBytes(msg.TranId), 0)); _messages.AddOrUpdate(msgId, new PendingMnlMessage() { RecipientId = toNode.Id, SentMessage = msg, ValidateId = validate }, (k, v) => v); byte[] rawMsg = msg.ToBytes(); _udpClient.Send(rawMsg, rawMsg.Length, toNode.EndPoint); if (eventReset.Wait(timeout)) { PendingMnlMessage msgFromQueue; if (_messages.TryRemove(msgId, out msgFromQueue)) { return(msgFromQueue.SentMessage); } } return(msg); }
private void UpdateLastSeen(ContactNode node) { var bucket = BucketList.GetBucket(node.Id); if (bucket.Contains(node.Id)) { bucket.SeenNow(node); } }
/// <summary> /// Pings other node /// </summary> /// <param name="node">Node to ping</param> /// <returns></returns> public MnlMessage Ping(ContactNode node) { Message.MnlMessage msg = new Message.MnlMessage.Builder() .SetType(MessageType.Query) .SetQueryType(QueryType.Ping) .SetOriginatorId(Id) .Build(); UpdateLastSeen(node); return(_server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response); }
/// <summary> /// Find contact's closest nodes to id /// </summary> /// <param name="node">Node to query</param> /// <param name="id">Id to compare</param> /// <returns>Closest nodes to id</returns> public bool GetPeers(ContactNode node, Id infohash, out IEnumerable <ContactNode> nodes, out object token) { Message.MnlMessage msg = new Message.MnlMessage.Builder() .SetType(MessageType.Query) .SetQueryType(QueryType.GetPeers) .SetOriginatorId(Id) .SetInfohash(infohash) .Build(); UpdateLastSeen(node); Message.MnlMessage response = _server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response; List <ContactNode> contacts = new List <ContactNode>(); nodes = contacts; token = null; if (response == null) { return(false); } if (response.Payload.ContainsKey("token")) { token = response.Payload["token"]; } if (response.Payload.ContainsKey("values")) { List <object> valuesStrings = (List <object>)response.Payload["values"]; foreach (object peerInfo in valuesStrings) { contacts.Add(ContactNode.FromPeerInfo(peerInfo as byte[])); } return(true); } else if (response.Payload.ContainsKey("nodes")) { byte[] nodeString = (byte[])response.Payload["nodes"]; int offset = 0; while (offset < nodeString.Length) { contacts.Add(new ContactNode(nodeString, ref offset)); } return(false); } return(false); }
public bool TryReplaceLeastSeenContactFromBucket(ContactNode newContact) { var bucket = Owner.BucketList.GetBucket(newContact.Id); var leastSeen = bucket.GetLeastSeen(); Message.MnlMessage pongMsg = Owner.Ping(leastSeen); if (pongMsg == null) { bucket.Replace(leastSeen.Id, newContact); return(true); } return(false); }
/// <summary> /// Find contact's closest nodes to id /// </summary> /// <param name="node">Node to query</param> /// <param name="id">Id to compare</param> /// <returns></returns> public MnlMessage AnnouncePeer(ContactNode node, Id infohash, int port, object token, int?impliedPort) { Message.MnlMessage msg = new Message.MnlMessage.Builder() .SetType(MessageType.Query) .SetQueryType(QueryType.AnnouncePeer) .SetOriginatorId(Id) .SetInfohash(infohash) .Build(); msg.Payload.Add("port", port); msg.Payload.Add("implied_port", impliedPort ?? 0); msg.Payload.Add("token", token ?? new byte[0]); UpdateLastSeen(node); return(_server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response); }
private void LookupNodes(Id nodeId, CancellationToken cancelToken) { SortedSet <Id> queriedNodes = new SortedSet <Id>(new Id.IdComparer()); List <Task> tasks = new List <Task>(MaxConcurrentThreads); int triesCount = 0; ContactNode closestContact = Owner.BucketList.GetClosestContactToId(nodeId); if (closestContact == null) { return; } Id prevClosestId = closestContact.Id ^ nodeId; while (queriedNodes.Count < 256) { var shortListSnapshot = Owner.BucketList.GetClosestNodes(nodeId, MaxConcurrentThreads).Where((n) => !queriedNodes.Contains(n.Id)).ToList(); foreach (var node in shortListSnapshot) { tasks.Add(Task.Run(() => { IEnumerable <ContactNode> contacts = Owner.FindNode(node, nodeId); foreach (var contact in contacts) { if (Owner.BucketList.Put(contact) == Buckets.BucketList.BucketPutResult.BucketIsFull) { TryReplaceLeastSeenContactFromBucket(contact); } } Debug.WriteLine($"Added {contacts.Count()} contacts"); })); queriedNodes.Add(node.Id); if (tasks.Count >= MaxConcurrentThreads) { break; } Debug.WriteLine($"Queried nodes count - {queriedNodes.Count}"); } try { Task.WaitAll(tasks.ToArray(), cancelToken); tasks.Clear(); } catch (OperationCanceledException) { return; } ContactNode closestNode = Owner.BucketList.GetClosestContactToId(nodeId); Id currentMin = closestNode.Id ^ nodeId; if (currentMin >= prevClosestId) { if (triesCount < ReplicationCount) { triesCount++; continue; } //Can't get any closer, stopping. Debug.WriteLine($"Can't get any closer, breaking search"); break; } prevClosestId = currentMin; } }
/// <summary> /// Processes request from other node. Used by NodeServer class /// </summary> /// <param name="msg">Request to process</param> /// <param name="origAddress">Request originator adress</param> public void ProcessQuery(Message.MnlMessage msg, IPEndPoint origAddress) { switch (msg.QueryType) { case QueryType.Ping: { _server.SendMessage(origAddress, PrepareResponse(msg)); break; } case QueryType.FindNode: { Message.MnlMessage response = PrepareResponse(msg); Id targetId = new Id((byte[])msg.Payload["target"]); var closestNodes = BucketList.GetClosestNodes(targetId, NodesPerQuery); response.Payload.Add("nodes", closestNodes.Select((n) => n.ToBytes()).ToList()); _server.SendMessage(origAddress, response); break; } case QueryType.GetPeers: { Message.MnlMessage response = PrepareResponse(msg); Id targetId = new Id((byte[])msg.Payload["info_hash"]); if (Storage.ContainsPeersFor(targetId)) { response.Payload.Add("values", Storage.GetForinfoHash(targetId) .Select((n) => n.ToBytes(true)).ToList()); response.Payload.Add("token", _tokenStorage.AcquireNewToken(origAddress.Address).AsBytes()); } else { response.Payload.Add("nodes", BucketList.GetClosestNodes(targetId, NodesPerQuery) .Select((n) => n.ToBytes()).ToList()); } _server.SendMessage(origAddress, response); break; } case QueryType.AnnouncePeer: { Message.MnlMessage response = PrepareResponse(msg); Token token = Token.FromBytes((byte[])msg.Payload["token"]); if (_tokenStorage.Validate(origAddress.Address, token)) { Id infoHash = new Id((byte[])msg.Payload["info_hash"]); Id originatorId = new Id((byte[])msg.Payload["id"]); Bucket originatorBucket = BucketList.GetBucket(originatorId); ContactNode originatorNode = originatorBucket.GetNode(originatorId); bool isImpliedPort = !msg.Payload.ContainsKey("port") || (int)msg.Payload["port"] > 0; originatorNode.UtpPort = isImpliedPort ? originatorNode.EndPoint.Port : (int)msg.Payload["port"]; Storage.Put(originatorNode, infoHash); _server.SendMessage(origAddress, response); } else { _server.SendBadToken(origAddress); } break; } } Id msgOrigId = new Id((byte[])msg.Payload["id"]); var bucket = BucketList.GetBucket(msgOrigId); //UpdateLastSeen(bucket.GetNode(msgOrigId)); }