/// <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); }
public Builder(byte[] msg) { Bencoder bencoder = new Bencoder(); var decodedMsg = bencoder.DecodeElement(msg); Dictionary <string, object> msgFields = (Dictionary <string, object>)decodedMsg; _msg = new MnlMessage(); try { _msg.TranId = Bencoder.DefEncoding.GetString((byte[])msgFields["t"]); } catch (KeyNotFoundException) { throw new MalformedPacketException("t"); } try { _msg.Type = (MessageType)(Bencoder.DefEncoding.GetString((byte[])msgFields["y"])[0]); } catch (KeyNotFoundException) { throw new MalformedPacketException("y"); } if (msgFields.ContainsKey("q")) { _msg.QueryType = Bencoder.DefEncoding.GetString((byte[])msgFields["q"]); } switch (_msg.Type) { case MessageType.Query: try { _msg.Payload = (Dictionary <string, object>)msgFields["a"]; } catch (KeyNotFoundException) { throw new MalformedPacketException("a"); } break; case MessageType.Response: try { _msg.Payload = (Dictionary <string, object>)msgFields["r"]; } catch (KeyNotFoundException) { throw new MalformedPacketException("r"); } break; case MessageType.Error: try { List <object> errList = (List <object>)msgFields["e"]; int codeIdx = errList[0] is int? 0 : 1; _msg.ErrorCode = (ErrorType)errList[codeIdx]; if (errList.Count > 1) { _msg.ErrorMessage = Bencoder.DefEncoding.GetString((byte[])errList[codeIdx == 0 ? 1 : 0]); //TODO: ??? } } catch (KeyNotFoundException) { throw new MalformedPacketException("e"); } return; } _msg.OriginatorId = new Id((byte[])_msg.Payload["id"]); }
private MnlMessage PrepareResponse(Message.MnlMessage toMsg) { return(new Message.MnlMessage.Builder() .SetTranId(toMsg.TranId) .SetType(MessageType.Response) .SetOriginatorId(Id) .Build()); }
/// <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); }
public void SetResponse(MnlMessage response) { Response = response; OnResponse?.Invoke(response); }
public Builder() { _msg = new MnlMessage(); }
private void ListenIncoming(Node ownerNode) { while (!_stopped) { try { IPEndPoint incomingIpEndPoint = new IPEndPoint(IPAddress.Any, EndPoint.Port); byte[] rawMsg = _udpClient.Receive(ref incomingIpEndPoint); if (!IsLegitMnlDhtMessage(rawMsg)) { continue; } Message.MnlMessage incomingMsg = null; try { incomingMsg = new Message.MnlMessage.Builder(rawMsg).Build(); } catch (Bittorrent.InvalidFieldException ife) { MnlMessage errMessage = new MnlMessage.Builder() .SetTranId(GenerateTranId()) .SetType(MessageType.Error) .SetErrorCode(ErrorType.ProtocolError) .SetErrorMessage(ife.Message) .Build(); Debug.WriteLine($"Sending incorrect field message {ife.Message}"); SendMessage(incomingIpEndPoint, errMessage); continue; } catch (MalformedPacketException mpe) { MnlMessage errMessage = new MnlMessage.Builder() .SetTranId(GenerateTranId()) .SetType(MessageType.Error) .SetErrorCode(ErrorType.ProtocolError) .SetErrorMessage(mpe.Message) .Build(); Debug.WriteLine($"Sending malformed packet message {mpe.Message}"); SendMessage(incomingIpEndPoint, errMessage); continue; } ulong msgIdx = GetMessageId(incomingIpEndPoint.Address, BitConverter.ToUInt16(Encoding.ASCII.GetBytes(incomingMsg.TranId.PadLeft(2, '\0')), 0)); if (_messages.ContainsKey(msgIdx)) { PendingMnlMessage rqMsg; if (_messages.TryRemove(msgIdx, out rqMsg)) { if (incomingMsg.Type == MessageType.Error) { Debug.WriteLine($"Recieved error {incomingMsg.ErrorMessage}"); switch (incomingMsg.ErrorCode) { case ErrorType.ProtocolError: case ErrorType.MethodUnknown: Debug.WriteLine($"!!!Error {incomingMsg.ErrorMessage}"); break; default: continue; } } if (rqMsg.ValidateId) { if (rqMsg.RecipientId != incomingMsg.OriginatorId) { Debug.WriteLine($"Node {incomingIpEndPoint} id mismatch!"); OnMaliciousMessage?.Invoke(incomingIpEndPoint, rqMsg.RecipientId, rqMsg.SentMessage); continue; } } rqMsg.SentMessage.SetResponse(incomingMsg); } } else { if (incomingMsg.Type == MessageType.Query) { ownerNode.ProcessQuery(incomingMsg, incomingIpEndPoint); } } } catch (SocketException se) { if (se.SocketErrorCode != SocketError.Interrupted) { throw; } } } }
public void SendMessage(IPEndPoint toEndPoint, Message.MnlMessage msg) { byte[] rawMsg = msg.ToBytes(); _udpClient.Send(rawMsg, rawMsg.Length, toEndPoint); }
/// <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)); }