private DhtRpcPacket(int transactionID, NodeContact sourceNode, RpcPacketType type, RpcQueryType queryType) { _transactionID = transactionID; _sourceNode = sourceNode; _type = type; _queryType = queryType; }
private object QueryFind(NodeContact[] initialContacts, BinaryID nodeID, RpcQueryType queryType) { List <NodeContact> availableContacts = new List <NodeContact>(initialContacts); List <NodeContact> respondedContacts = new List <NodeContact>(); List <NodeContact> failedContacts = new List <NodeContact>(); NodeContact[] alphaContacts; int alpha = KADEMLIA_ALPHA; bool finalRound = false; while (true) { //pick alpha contacts to query from available contacts lock (availableContacts) { alphaContacts = PickClosestContacts(availableContacts, alpha); } if (alphaContacts.Length < 1) { //no contacts available to query further lock (respondedContacts) { if (respondedContacts.Count > KADEMLIA_K) { return(KBucket.GetClosestContacts(respondedContacts, nodeID, KADEMLIA_K)); } else if (respondedContacts.Count > 0) { return(respondedContacts.ToArray()); } } return(null); } object lockObj = new object(); List <NodeContact> receivedContacts = new List <NodeContact>(); List <PeerEndPoint> receivedPeers = null; if (queryType == RpcQueryType.FIND_PEERS) { receivedPeers = new List <PeerEndPoint>(); } lock (lockObj) { //query each alpha contact async foreach (NodeContact alphaContact in alphaContacts) { ThreadPool.QueueUserWorkItem(QueryFindAsync, new object[] { lockObj, queryType, alphaContact, nodeID, availableContacts, respondedContacts, failedContacts, receivedContacts, receivedPeers }); } //wait for any of the contact to return new contacts if (Monitor.Wait(lockObj, QUERY_TIMEOUT)) { //got reply! if (queryType == RpcQueryType.FIND_PEERS) { lock (receivedPeers) { if (receivedPeers.Count > 0) { return(receivedPeers.ToArray()); } } } lock (receivedContacts) { if (receivedContacts.Count < 1) { //current round failed to return any new closer nodes if (finalRound) { if (queryType == RpcQueryType.FIND_PEERS) { return(null); } lock (respondedContacts) { if (respondedContacts.Count > KADEMLIA_K) { return(KBucket.GetClosestContacts(respondedContacts, nodeID, KADEMLIA_K)); } else { return(respondedContacts.ToArray()); } } } else { //resend query to k closest node not already queried finalRound = true; alpha = KADEMLIA_K; } } else { finalRound = false; alpha = KADEMLIA_ALPHA; } } } } } }
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 { } }
public DhtRpcPacket(Stream s, IPAddress nodeIP) { int version = s.ReadByte(); switch (version) { case 1: byte[] buffer = new byte[20]; OffsetStream.StreamRead(s, buffer, 0, 4); _transactionID = BitConverter.ToInt32(buffer, 0); OffsetStream.StreamRead(s, buffer, 0, 20); BinaryID nodeID = BinaryID.Clone(buffer, 0, 20); OffsetStream.StreamRead(s, buffer, 0, 2); _sourceNode = new NodeContact(nodeID, new IPEndPoint(nodeIP, BitConverter.ToUInt16(buffer, 0))); _type = (RpcPacketType)s.ReadByte(); _queryType = (RpcQueryType)s.ReadByte(); switch (_queryType) { case RpcQueryType.FIND_NODE: OffsetStream.StreamRead(s, buffer, 0, 20); _networkID = BinaryID.Clone(buffer, 0, 20); if (_type == RpcPacketType.Response) { int count = s.ReadByte(); _contacts = new NodeContact[count]; for (int i = 0; i < count; i++) { _contacts[i] = new NodeContact(s); } } break; case RpcQueryType.FIND_PEERS: OffsetStream.StreamRead(s, buffer, 0, 20); _networkID = BinaryID.Clone(buffer, 0, 20); if (_type == RpcPacketType.Response) { int count = s.ReadByte(); _contacts = new NodeContact[count]; for (int i = 0; i < count; i++) { _contacts[i] = new NodeContact(s); } count = s.ReadByte(); _peers = new PeerEndPoint[count]; for (int i = 0; i < count; i++) { _peers[i] = new PeerEndPoint(s); } OffsetStream.StreamRead(s, buffer, 0, 20); _token = new BinaryID(buffer); } break; case RpcQueryType.ANNOUNCE_PEER: OffsetStream.StreamRead(s, buffer, 0, 20); _networkID = BinaryID.Clone(buffer, 0, 20); if (_type == RpcPacketType.Query) { OffsetStream.StreamRead(s, buffer, 0, 2); _servicePort = BitConverter.ToUInt16(buffer, 0); OffsetStream.StreamRead(s, buffer, 0, 20); _token = new BinaryID(buffer); } break; } break; default: throw new IOException("DHT-RPC packet version not supported: " + version); } }