private DhtRpcPacket(EndPoint sourceNodeEP, DhtRpcType type, BinaryNumber networkId, NodeContact[] contacts, EndPoint[] peers) { _sourceNodeEP = sourceNodeEP; _type = type; _networkId = networkId; _contacts = contacts; _peers = peers; }
private DhtRpcPacket(ushort sourceNodePort, DhtRpcType type, BinaryNumber networkID, NodeContact[] contacts, PeerEndPoint[] peers, ushort servicePort) { _sourceNodePort = sourceNodePort; _type = type; _networkID = networkID; _contacts = contacts; _peers = peers; _servicePort = servicePort; }
public DhtRpcPacket(BinaryReader bR) { int version = bR.ReadByte(); switch (version) { case 1: _sourceNodeEP = EndPointExtension.Parse(bR); _type = (DhtRpcType)bR.ReadByte(); switch (_type) { case DhtRpcType.PING: break; case DhtRpcType.FIND_NODE: _networkId = new BinaryNumber(bR.BaseStream); _contacts = new NodeContact[bR.ReadByte()]; for (int i = 0; i < _contacts.Length; i++) { _contacts[i] = new NodeContact(bR); } break; case DhtRpcType.FIND_PEERS: _networkId = new BinaryNumber(bR.BaseStream); _contacts = new NodeContact[bR.ReadByte()]; for (int i = 0; i < _contacts.Length; i++) { _contacts[i] = new NodeContact(bR); } _peers = new EndPoint[bR.ReadByte()]; for (int i = 0; i < _peers.Length; i++) { _peers[i] = EndPointExtension.Parse(bR); } break; case DhtRpcType.ANNOUNCE_PEER: _networkId = new BinaryNumber(bR.BaseStream); _peers = new EndPoint[bR.ReadByte()]; for (int i = 0; i < _peers.Length; i++) { _peers[i] = EndPointExtension.Parse(bR); } break; default: throw new IOException("Invalid DHT-RPC type."); } break; default: throw new InvalidDataException("DHT-RPC packet version not supported: " + version); } }
public DhtRpcPacket(Stream s) { int version = s.ReadByte(); switch (version) { case -1: throw new EndOfStreamException(); case 2: byte[] buffer = new byte[20]; OffsetStream.StreamRead(s, buffer, 0, 2); _sourceNodePort = BitConverter.ToUInt16(buffer, 0); _type = (DhtRpcType)s.ReadByte(); switch (_type) { case DhtRpcType.PING: break; case DhtRpcType.FIND_NODE: { OffsetStream.StreamRead(s, buffer, 0, 20); _networkID = BinaryNumber.Clone(buffer, 0, 20); int count = s.ReadByte(); _contacts = new NodeContact[count]; for (int i = 0; i < count; i++) { _contacts[i] = new NodeContact(s); } } break; case DhtRpcType.FIND_PEERS: { OffsetStream.StreamRead(s, buffer, 0, 20); _networkID = BinaryNumber.Clone(buffer, 0, 20); 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); } } break; case DhtRpcType.ANNOUNCE_PEER: { OffsetStream.StreamRead(s, buffer, 0, 20); _networkID = BinaryNumber.Clone(buffer, 0, 20); OffsetStream.StreamRead(s, buffer, 0, 2); _servicePort = BitConverter.ToUInt16(buffer, 0); int count = s.ReadByte(); _peers = new PeerEndPoint[count]; for (int i = 0; i < count; i++) { _peers[i] = new PeerEndPoint(s); } } break; default: throw new IOException("Invalid DHT-RPC type."); } break; default: throw new IOException("DHT-RPC packet version not supported: " + version); } }
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)); } } } } }