private DhtRpcPacket ProcessQuery(DhtRpcPacket query, IPAddress remoteNodeIP) { AddNode(new IPEndPoint(remoteNodeIP, query.SourceNodePort)); switch (query.Type) { case DhtRpcType.PING: return(DhtRpcPacket.CreatePingPacket(_currentNode)); case DhtRpcType.FIND_NODE: return(DhtRpcPacket.CreateFindNodePacketResponse(_currentNode, query.NetworkID, _routingTable.GetKClosestContacts(query.NetworkID))); case DhtRpcType.FIND_PEERS: PeerEndPoint[] peers = _currentNode.GetPeers(query.NetworkID); if (peers.Length == 0) { return(DhtRpcPacket.CreateFindPeersPacketResponse(_currentNode, query.NetworkID, _routingTable.GetKClosestContacts(query.NetworkID), peers)); } else { return(DhtRpcPacket.CreateFindPeersPacketResponse(_currentNode, query.NetworkID, new NodeContact[] { }, peers)); } case DhtRpcType.ANNOUNCE_PEER: _currentNode.StorePeer(query.NetworkID, new PeerEndPoint(remoteNodeIP, query.ServicePort)); return(DhtRpcPacket.CreateAnnouncePeerPacketResponse(_currentNode, query.NetworkID, _currentNode.GetPeers(query.NetworkID))); default: throw new Exception("Invalid DHT-RPC type."); } }
public static DhtRpcPacket CreateFindPeersPacketQuery(NodeContact sourceNode, BinaryID networkID) { DhtRpcPacket packet = new DhtRpcPacket(GetRandomTransactionID(), sourceNode, RpcPacketType.Query, RpcQueryType.FIND_PEERS); packet._networkID = networkID; return(packet); }
public static DhtRpcPacket CreateAnnouncePeerPacketResponse(int transactionID, NodeContact sourceNode, BinaryID networkID) { DhtRpcPacket packet = new DhtRpcPacket(transactionID, sourceNode, RpcPacketType.Response, RpcQueryType.ANNOUNCE_PEER); packet._networkID = networkID; return(packet); }
public static DhtRpcPacket CreateFindNodePacketResponse(int transactionID, NodeContact sourceNode, BinaryID networkID, NodeContact[] contacts) { DhtRpcPacket packet = new DhtRpcPacket(transactionID, sourceNode, RpcPacketType.Response, RpcQueryType.FIND_NODE); packet._networkID = networkID; packet._contacts = contacts; return(packet); }
public static DhtRpcPacket CreateAnnouncePeerPacketQuery(NodeContact sourceNode, BinaryID networkID, ushort servicePort, BinaryID token) { DhtRpcPacket packet = new DhtRpcPacket(GetRandomTransactionID(), sourceNode, RpcPacketType.Query, RpcQueryType.ANNOUNCE_PEER); packet._networkID = networkID; packet._servicePort = servicePort; packet._token = token; return(packet); }
private DhtRpcPacket Query(DhtRpcPacket query, NodeContact contact) { if (_currentNode.NodeEP.AddressFamily != contact.NodeEP.AddressFamily) { return(null); } Stream s = null; try { s = _manager.GetConnectionStream(contact.NodeEP); //set timeout s.WriteTimeout = QUERY_TIMEOUT; s.ReadTimeout = QUERY_TIMEOUT; //send query query.WriteTo(s); s.Flush(); //read response DhtRpcPacket response = new DhtRpcPacket(s); //auto add contact or update last seen time { NodeContact bucketContact = _routingTable.FindContact(contact.NodeID); if (bucketContact == null) { contact.UpdateLastSeenTime(); _routingTable.AddContact(contact); } else { bucketContact.UpdateLastSeenTime(); } } return(response); } catch { contact.IncrementRpcFailCount(); return(null); } finally { if (s != null) { s.Dispose(); } } }
public static DhtRpcPacket CreateFindPeersPacketResponse(int transactionID, NodeContact sourceNode, BinaryID networkID, NodeContact[] contacts, PeerEndPoint[] peers, BinaryID token) { DhtRpcPacket packet = new DhtRpcPacket(transactionID, sourceNode, RpcPacketType.Response, RpcQueryType.FIND_PEERS); packet._networkID = networkID; packet._contacts = contacts; packet._peers = peers; packet._token = token; return(packet); }
private void ReadResponsePacketsAsync(object parameter) { Socket udpClient = parameter as Socket; EndPoint remoteEP; FixMemoryStream recvStream = new FixMemoryStream(BUFFER_MAX_SIZE); byte[] bufferRecv = recvStream.Buffer; int bytesRecv; if (udpClient.AddressFamily == AddressFamily.InterNetwork) { remoteEP = new IPEndPoint(IPAddress.Any, 0); } else { remoteEP = new IPEndPoint(IPAddress.IPv6Any, 0); } try { while (true) { bytesRecv = udpClient.ReceiveFrom(bufferRecv, ref remoteEP); if (bytesRecv > 0) { recvStream.SetLength(bytesRecv); recvStream.Position = 0; IPEndPoint remoteNodeEP = remoteEP as IPEndPoint; if (NetUtilities.IsIPv4MappedIPv6Address(remoteNodeEP.Address)) { remoteNodeEP = new IPEndPoint(NetUtilities.ConvertFromIPv4MappedIPv6Address(remoteNodeEP.Address), remoteNodeEP.Port); } try { DhtRpcPacket response = new DhtRpcPacket(recvStream, remoteNodeEP.Address); ProcessPacket(response); } catch { } } } } catch (Exception ex) { Debug.Write("DhtClient.ReadResponsePacketsAsync", ex); } }
public void AddNode(NodeContact contact) { if (!NetUtilities.IsPrivateIP(contact.NodeEP.Address) && (contact.NodeEP.AddressFamily == _currentNode.NodeEP.AddressFamily)) { if (_routingTable.AddContact(contact)) { ThreadPool.QueueUserWorkItem(delegate(object state) { Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact); }); } } }
private NodeContact Ping(IPEndPoint nodeEP) { DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacketQuery(_currentNode), new NodeContact(null, nodeEP)); if (response == null) { return(null); } else { return(response.SourceNode); } }
public byte[] ProcessPacket(byte[] dhtPacket, int offset, int count, IPAddress remoteNodeIP) { using (MemoryStream mS = new MemoryStream(dhtPacket, offset, count, false)) { DhtRpcPacket response = ProcessPacket(new DhtRpcPacket(mS, remoteNodeIP)); if (response == null) { return(null); } return(response.ToArray()); } }
private PeerEndPoint[] QueryAnnounce(NodeContact[] initialContacts, BinaryNumber networkID, ushort servicePort) { NodeContact[] contacts = QueryFindNode(initialContacts, networkID); if ((contacts == null) || (contacts.Length == 0)) { return(null); } List <PeerEndPoint> peers = new List <PeerEndPoint>(); lock (peers) { foreach (NodeContact contact in contacts) { Thread t = new Thread(delegate(object state) { DhtRpcPacket response = Query(DhtRpcPacket.CreateAnnouncePeerPacketQuery(_currentNode, networkID, servicePort), contact); if ((response != null) && (response.Type == DhtRpcType.ANNOUNCE_PEER) && (response.Peers.Length > 0)) { lock (peers) { foreach (PeerEndPoint peer in response.Peers) { if (!peers.Contains(peer)) { peers.Add(peer); } } Monitor.Pulse(peers); } } }); t.IsBackground = true; t.Start(); } if (Monitor.Wait(peers, QUERY_TIMEOUT)) { return(peers.ToArray()); } return(null); } }
public void AcceptConnection(Stream s, IPAddress remoteNodeIP) { //set timeout s.WriteTimeout = QUERY_TIMEOUT; s.ReadTimeout = QUERY_TIMEOUT; while (true) { DhtRpcPacket response = ProcessQuery(new DhtRpcPacket(s), remoteNodeIP); if (response == null) { break; } response.WriteTo(s); s.Flush(); } }
internal bool Ping(NodeContact contact) { DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacketQuery(_currentNode), contact); if (response == null) { return(false); } else { if (contact.Equals(response.SourceNode)) { return(true); } else { contact.IncrementRpcFailCount(); return(false); } } }
private void QueryAnnounceAsync(object state) { try { object[] parameters = state as object[]; NodeContact contact = parameters[0] as NodeContact; BinaryID networkID = parameters[1] as BinaryID; List <PeerEndPoint> peers = parameters[2] as List <PeerEndPoint>; ushort servicePort = (ushort)parameters[3]; DhtRpcPacket responsePacket = Query(DhtRpcPacket.CreateFindPeersPacketQuery(_currentNode, networkID), contact); if ((responsePacket != null) && (responsePacket.QueryType == RpcQueryType.FIND_PEERS)) { if (responsePacket.Peers.Length > 0) { lock (peers) { foreach (PeerEndPoint peer in responsePacket.Peers) { if (!peers.Contains(peer)) { peers.Add(peer); } } //Monitor.Pulse(peers); //removed so that response from multiple nodes is collected till query times out } } Query(DhtRpcPacket.CreateAnnouncePeerPacketQuery(_currentNode, networkID, servicePort, responsePacket.Token), contact); } } catch { } }
private void QueryFindAsync(object state) { try { object[] parameters = state as object[]; object lockObj = parameters[0] as object; RpcQueryType queryType = (RpcQueryType)parameters[1]; NodeContact contact = parameters[2] as NodeContact; BinaryID nodeID = parameters[3] as BinaryID; List <NodeContact> availableContacts = parameters[4] as List <NodeContact>; List <NodeContact> respondedContacts = parameters[5] as List <NodeContact>; List <NodeContact> failedContacts = parameters[6] as List <NodeContact>; List <NodeContact> receivedContacts = parameters[7] as List <NodeContact>; DhtRpcPacket responsePacket; if (queryType == RpcQueryType.FIND_NODE) { responsePacket = Query(DhtRpcPacket.CreateFindNodePacketQuery(_currentNode, nodeID), contact); } else { responsePacket = Query(DhtRpcPacket.CreateFindPeersPacketQuery(_currentNode, nodeID), contact); } if ((responsePacket == null) || (responsePacket.QueryType != queryType)) { //time out //add contact to failed contacts lock (failedContacts) { if (!failedContacts.Contains(contact)) { failedContacts.Add(contact); } } return; } //got reply! switch (queryType) { case RpcQueryType.FIND_NODE: lock (receivedContacts) { lock (respondedContacts) { //add contact to responded contacts list if (!respondedContacts.Contains(contact)) { respondedContacts.Add(contact); } lock (failedContacts) { //add received contacts to received contacts list foreach (NodeContact receivedContact in responsePacket.Contacts) { if (!respondedContacts.Contains(receivedContact) && !failedContacts.Contains(receivedContact)) { receivedContacts.Add(receivedContact); } } } } //add received contacts to available contacts list lock (availableContacts) { foreach (NodeContact receivedContact in receivedContacts) { if (!availableContacts.Contains(receivedContact)) { availableContacts.Add(receivedContact); } } } } if (responsePacket.Contacts.Length > 0) { //pulse only if the contact has sent next level contacts list lock (lockObj) { Monitor.Pulse(lockObj); } } break; case RpcQueryType.FIND_PEERS: if (responsePacket.Peers.Length > 0) { List <PeerEndPoint> receivedPeers = parameters[8] as List <PeerEndPoint>; lock (receivedPeers) { foreach (PeerEndPoint peer in responsePacket.Peers) { if (!receivedPeers.Contains(peer)) { receivedPeers.Add(peer); } } } lock (lockObj) { Monitor.Pulse(lockObj); } } break; } } catch { } }
private object QueryFind(NodeContact[] initialContacts, BinaryNumber nodeID, DhtRpcType queryType) { if (initialContacts.Length < 1) { return(null); } List <NodeContact> seenContacts = new List <NodeContact>(initialContacts); List <NodeContact> learnedNotQueriedContacts = new List <NodeContact>(initialContacts); List <NodeContact> respondedContacts = new List <NodeContact>(); List <PeerEndPoint> receivedPeers = null; int alpha = KADEMLIA_ALPHA; bool finalRound = false; bool checkTerminationCondition = false; if (queryType == DhtRpcType.FIND_PEERS) { receivedPeers = new List <PeerEndPoint>(); } NodeContact previousClosestSeenContact = KBucket.SelectClosestContacts(seenContacts, nodeID, 1)[0]; while (true) { NodeContact[] alphaContacts; //pick alpha contacts to query from learned contacts lock (learnedNotQueriedContacts) { alphaContacts = KBucket.SelectClosestContacts(learnedNotQueriedContacts, nodeID, alpha); //remove selected alpha contacts from learned not queries contacts list foreach (NodeContact alphaContact in alphaContacts) { learnedNotQueriedContacts.Remove(alphaContact); } } if (alphaContacts.Length < 1) { checkTerminationCondition = true; } else { object lockObj = new object(); lock (lockObj) { //query each alpha contact async foreach (NodeContact alphaContact in alphaContacts) { Thread t = new Thread(delegate(object state) { DhtRpcPacket response; if (queryType == DhtRpcType.FIND_NODE) { response = Query(DhtRpcPacket.CreateFindNodePacketQuery(_currentNode, nodeID), alphaContact); } else { response = Query(DhtRpcPacket.CreateFindPeersPacketQuery(_currentNode, nodeID), alphaContact); } if ((response == null) || (response.Type != queryType)) { //time out or error //ignore contact by removing from seen contacts list lock (seenContacts) { seenContacts.Remove(alphaContact); } return; } //got reply! if ((queryType == DhtRpcType.FIND_PEERS) && (response.Peers.Length > 0)) { lock (receivedPeers) { foreach (PeerEndPoint peer in response.Peers) { if (!receivedPeers.Contains(peer)) { receivedPeers.Add(peer); } } } } //add alpha contact to responded contacts list lock (respondedContacts) { if (!respondedContacts.Contains(alphaContact)) { respondedContacts.Add(alphaContact); } } //add received contacts to learned contacts list lock (seenContacts) { lock (learnedNotQueriedContacts) { foreach (NodeContact contact in response.Contacts) { if (!seenContacts.Contains(contact)) { seenContacts.Add(contact); learnedNotQueriedContacts.Add(contact); } } } } //no pulse for final round to wait for all k contacts to respond. this allows any failed node contact to be removed from seen contacts list during the wait. lock (lockObj) { Monitor.Pulse(lockObj); } }); t.IsBackground = true; t.Start(); } //wait for any of the node contact to return new contacts if (Monitor.Wait(lockObj, QUERY_TIMEOUT)) { //got reply or final round! NodeContact currentClosestSeenContact; lock (seenContacts) { currentClosestSeenContact = KBucket.SelectClosestContacts(seenContacts, nodeID, 1)[0]; } BinaryNumber previousDistance = nodeID ^ previousClosestSeenContact.NodeID; BinaryNumber currentDistance = nodeID ^ currentClosestSeenContact.NodeID; if (previousDistance <= currentDistance) { //current round failed to return a node contact any closer than the closest already seen if (finalRound) { //final round over, check for termination condition checkTerminationCondition = true; } else { //resend query to k closest node not already queried finalRound = true; alpha = KADEMLIA_K; } } else { //current closest seen contact is closer than previous closest seen contact previousClosestSeenContact = currentClosestSeenContact; finalRound = false; alpha = KADEMLIA_ALPHA; } } } } if (checkTerminationCondition) { checkTerminationCondition = false; //reset if (queryType == DhtRpcType.FIND_PEERS) { //check only in final round to get most peers lock (receivedPeers) { if (receivedPeers.Count > 0) { return(receivedPeers.ToArray()); } return(null); } } //lookup terminates when k closest seen contacts have responded NodeContact[] kClosestSeenContacts; lock (seenContacts) { kClosestSeenContacts = KBucket.SelectClosestContacts(seenContacts, nodeID, KADEMLIA_K); } lock (respondedContacts) { bool success = true; foreach (NodeContact contact in kClosestSeenContacts) { if (!respondedContacts.Contains(contact)) { success = false; break; } } if (success) { return(kClosestSeenContacts); } if (alphaContacts.Length < 1) { return(KBucket.SelectClosestContacts(respondedContacts, nodeID, KADEMLIA_K)); } } } } }
internal bool Ping(NodeContact contact) { DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact); return(response != null); }
private DhtRpcPacket ProcessPacket(DhtRpcPacket packet) { switch (packet.PacketType) { case RpcPacketType.Query: #region Query DhtRpcPacket response = null; switch (packet.QueryType) { case RpcQueryType.PING: #region PING { response = DhtRpcPacket.CreatePingPacketResponse(packet.TransactionID, _currentNode); } #endregion break; case RpcQueryType.FIND_NODE: #region FIND_NODE { NodeContact[] contacts = _routingTable.GetKClosestContacts(packet.NetworkID); response = DhtRpcPacket.CreateFindNodePacketResponse(packet.TransactionID, _currentNode, packet.NetworkID, contacts); } #endregion break; case RpcQueryType.FIND_PEERS: #region GET_PEERS { PeerEndPoint[] peers = _currentNode.GetPeers(packet.NetworkID); NodeContact[] contacts; if (peers.Length < 1) { contacts = _routingTable.GetKClosestContacts(packet.NetworkID); } else { contacts = new NodeContact[] { } }; response = DhtRpcPacket.CreateFindPeersPacketResponse(packet.TransactionID, _currentNode, packet.NetworkID, contacts, peers, GetToken(packet.SourceNode.NodeEP.Address)); } #endregion break; case RpcQueryType.ANNOUNCE_PEER: #region ANNOUNCE_PEER { IPAddress remoteNodeIP = packet.SourceNode.NodeEP.Address; if (IsTokenValid(packet.Token, remoteNodeIP)) { _currentNode.StorePeer(packet.NetworkID, new PeerEndPoint(remoteNodeIP, packet.ServicePort)); } response = DhtRpcPacket.CreateAnnouncePeerPacketResponse(packet.TransactionID, _currentNode, packet.NetworkID); } #endregion break; } return(response); #endregion case RpcPacketType.Response: #region Response Transaction transaction = null; lock (_transactions) { if (_transactions.ContainsKey(packet.TransactionID)) { transaction = _transactions[packet.TransactionID]; } } if ((transaction != null) && ((transaction.RemoteNodeID == null) || transaction.RemoteNodeID.Equals(packet.SourceNode.NodeID)) && transaction.RemoteNodeEP.Equals(packet.SourceNode.NodeEP)) { lock (transaction) { transaction.ResponsePacket = packet; Monitor.Pulse(transaction); } } return(null); #endregion } return(null); }
private void ReadQueryPacketsAsync(object parameter) { Socket udpListener = parameter as Socket; EndPoint remoteEP; FixMemoryStream recvBufferStream = new FixMemoryStream(BUFFER_MAX_SIZE); FixMemoryStream sendBufferStream = new FixMemoryStream(BUFFER_MAX_SIZE); int bytesRecv; if (udpListener.AddressFamily == AddressFamily.InterNetwork) { remoteEP = new IPEndPoint(IPAddress.Any, 0); } else { remoteEP = new IPEndPoint(IPAddress.IPv6Any, 0); } try { while (true) { bytesRecv = udpListener.ReceiveFrom(recvBufferStream.Buffer, ref remoteEP); if (bytesRecv > 0) { recvBufferStream.Position = 0; recvBufferStream.SetLength(bytesRecv); IPEndPoint remoteNodeEP = remoteEP as IPEndPoint; if (NetUtilities.IsIPv4MappedIPv6Address(remoteNodeEP.Address)) { remoteNodeEP = new IPEndPoint(NetUtilities.ConvertFromIPv4MappedIPv6Address(remoteNodeEP.Address), remoteNodeEP.Port); } try { DhtRpcPacket request = new DhtRpcPacket(recvBufferStream, remoteNodeEP.Address); DhtRpcPacket response = ProcessPacket(request); //send response if (response != null) { sendBufferStream.Position = 0; response.WriteTo(sendBufferStream); udpListener.SendTo(sendBufferStream.Buffer, 0, (int)sendBufferStream.Position, SocketFlags.None, remoteEP); } //if contact doesnt exists then add contact else update last seen time KBucket closestBucket = _routingTable.FindClosestBucket(request.SourceNode.NodeID); NodeContact contact = closestBucket.FindContactInCurrentBucket(request.SourceNode.NodeID); if (contact == null) { //check if the closest bucket can accomodate another contact if (!closestBucket.IsCurrentBucketFull(true)) { ThreadPool.QueueUserWorkItem(AddContactAfterPingAsync, request.SourceNode); } } else { contact.UpdateLastSeenTime(); } } catch { } } } } catch (Exception ex) { Debug.Write("DhtClient.ReadQueryPacketsAsync", ex); } }
private DhtRpcPacket Query(DhtRpcPacket packet, NodeContact contact) { Transaction transaction = new Transaction(contact.NodeID, contact.NodeEP); try { lock (_transactions) { _transactions.Add(packet.TransactionID, transaction); } lock (transaction) { lock (_sendBufferStream) { _sendBufferStream.Position = 0; packet.WriteTo(_sendBufferStream); if (_proxyEnabled) { _manager.SendDhtPacket(contact.NodeEP, _sendBufferStream.Buffer, 0, (int)_sendBufferStream.Position); } else { _udpClient.SendTo(_sendBufferStream.Buffer, 0, (int)_sendBufferStream.Position, SocketFlags.None, contact.NodeEP); } } if (!Monitor.Wait(transaction, QUERY_TIMEOUT)) { contact.IncrementRpcFailCount(); return(null); } //auto add contact or update last seen time if (contact.NodeID == null) { contact = transaction.ResponsePacket.SourceNode; } KBucket closestBucket = _routingTable.FindClosestBucket(contact.NodeID); NodeContact bucketContact = closestBucket.FindContactInCurrentBucket(contact.NodeID); if (bucketContact == null) { closestBucket.AddContactInCurrentBucket(contact); } else { bucketContact.UpdateLastSeenTime(); } return(transaction.ResponsePacket); } } finally { lock (_transactions) { _transactions.Remove(packet.TransactionID); } } }