コード例 #1
0
 def sendto(self, identity, data, timeout=30):
     '''Send a single data object to the remote peer in datagram mode.'''
     values = yield self.get(guid=H(identity))
     for value in map(lambda x: x.value, values):
         try:
             value = int(value)
         except:
             print 'invalid non-integer value=%r' % (value)
             continue
         seq = dht._seq = dht._seq + 1
         net = self.net
         request = Message(name='Datagram:Request',
                           src=net.node,
                           dest=value,
                           seq=seq,
                           sock=hasattr(self, 'identity') and self.identity
                           or None,
                           peer=identity,
                           value=str(data))
         if value == net.node.guid: yield net.put(request, timeout=timeout)
         elif self.isSuperNode:
             yield net.put(Message(name='Route:Request',
                                   src=net.node,
                                   dest=value,
                                   payload=request),
                           timeout=timeout)
         else:
             yield net.send(Message(name='Proxy:Request',
                                    src=net.node,
                                    payload=request),
                            node=self.client.neighbors[0])
     raise StopIteration(None)
コード例 #2
0
 def get(self, guid, maxvalues=16, Kp=None, timeout=5):
     '''Invoke the get method on the connected DHT node if this is a client.'''
     if self.server or not self.neighbors:
         if _debug: print 'client.get not a client with valid connections'
         raise StopIteration([])
     net = self.net
     seq = dht._seq = dht._seq + 1
     request = Message(name='Get:Request',
                       seq=seq,
                       src=net.node,
                       dest=guid,
                       maxvalues=maxvalues,
                       hash=Kp and H(str(Kp)) or None)
     yield net.send(Message(name='Proxy:Request',
                            src=net.node,
                            payload=request),
                    node=self.neighbors[0],
                    timeout=5)
     response = yield net.get(timeout=timeout,
                              criteria=lambda x: x.seq == seq and x.name ==
                              'Get:Response')  # wait for response
     result = [(v.value, k.nonce, v.Kp, k.expires) for k, v in zip(
         response.get('keyss', [None] *
                      len(response['vals'])), response['vals'])
               ] if response else []
     raise StopIteration(
         result
     )  # don't use response.values as it is a built-in method of base class dict of Message.
コード例 #3
0
 def pinghandler(self):
     '''Respond to Ping:Request.'''
     while True:
         msg = yield self.net.get(lambda x: x.name == 'Ping:Request')
         if _debug: print 'received ping request'
         yield self.net.send(msg=Message(name='Ping:Response'),
                             node=msg.remote)
コード例 #4
0
 def put(self, guid, value, nonce, expires, Ks=None, put=True, timeout=30):
     '''Forward the put request to the connected DHT node.'''
     if self.server or not self.neighbors:  # this is a server, or doesn't have valid connections
         if _debug: print 'client.put not a client with valid connections'
         raise StopIteration(False)
     net = self.net
     seq = dht._seq = dht._seq + 1
     request = Message(name='Put:Request', date=time.time(), seq=seq, src=net.node, dest=guid, nonce=nonce, expires=expires, put=put, \
                 value=str(value) if put else None, hash=H(str(value)), Kp=Ks and dht.extractPublicKey(Ks) or None, \
                 sigma=dht.sign(Ks, H(str(guid) + str(value) + str(nonce) + str(expires))) if Ks else None)
     yield net.send(Message(name='Proxy:Request',
                            src=net.node,
                            payload=request),
                    node=self.neighbors[0],
                    timeout=5)
     response = yield net.get(timeout=timeout,
                              criteria=lambda x: x.seq == seq and x.name ==
                              'Put:Response')  # wait for response
     raise StopIteration(response and response.result)
コード例 #5
0
 def parse(self, data, addr, type):
     '''Parse a message from given remote (host, port) and return parsed Message and remote Node.
     Returns None as message if can't be parsed.'''
     if len(data) < Hsize: return (None, None)
     guid, data = dht.bin2int(data[0:Hsize]), data[Hsize:]
     node = Node(ip=addr[0], port=addr[1], type=type, guid=guid)
     try:
         msg = Message(raw=data)
     except:
         return (None, None)
     return (msg, node)
コード例 #6
0
 def connect(self, identity, timeout=30):
     '''Connect to the given identity. It returns a Socket object on success or None on error.'''
     values = yield self.get(guid=H(identity))
     if _debug: print 'connect() found values=%r' % (values)
     for value in map(lambda x: x.value, values):
         try:
             value = int(value)
         except:
             print 'invalid non-integer value=%r' % (value)
             continue
         sock = Socket(sock=self, peer=(identity, value), server=False)
         seq = dht._seq = dht._seq + 1
         net = self.net
         request = Message(name='Connect:Request',
                           src=net.node,
                           dest=value,
                           seq=seq,
                           sock=hasattr(self, 'identity') and self.identity
                           or None,
                           peer=identity)
         if value == net.node.guid: yield net.put(request, timeout=5)
         elif self.isSuperNode:
             yield net.put(Message(name='Route:Request',
                                   src=net.node,
                                   dest=value,
                                   payload=request),
                           timeout=5)
         else:
             yield net.send(Message(name='Proxy:Request',
                                    src=net.node,
                                    payload=request),
                            node=self.client.neighbors[0])
         response = yield net.get(
             timeout=timeout,
             criteria=lambda x: x.seq == seq and x.name ==
             'Connect:Response')  # wait for response
         if response: raise StopIteration(sock)
         else: sock.close()
     raise StopIteration(None)
コード例 #7
0
 def requesthandler(msg):
     p = msg.payload
     response = None
     if self.server:  # only if a server
         if p.name == 'Put:Request':
             result = yield dht.put(net, p.dest, p.value, p.nonce,
                                    p.expires, p.Ks, p.put)
             response = Message(name='Put:Response',
                                seq=p.seq,
                                result=result)
         elif p.name == 'Get:Request':
             result = yield dht.get(net, p.dest, p.maxvalues, p.Kp)
             response = Message(name='Get:Response',
                                seq=p.seq,
                                guid=p.guid,
                                vals=result)
         if response:
             yield self.net.send(Message(name='Proxy:Response',
                                         src=net.node,
                                         payload=response),
                                 node=msg.src,
                                 timeout=5)
コード例 #8
0
 def accept(self, timeout=None):
     '''Accept an incoming connection. It returns a Socket object on success or None on error.'''
     net = self.net
     msg = yield net.get(timeout=timeout,
                         criteria=lambda x: x.name == 'Connect:Request' and
                         x.peer == self.identity)  # wait for request
     if _debug: print 'accept msg=%r' % (msg)
     if not msg: raise StopIteration(None)
     sock = Socket(sock=self, peer=(msg.sock, msg.src.guid), server=True)
     yield net.send(Message(name='Connect:Response',
                            seq=msg.seq,
                            result=True),
                    node=msg.src)
     raise StopIteration(sock)
コード例 #9
0
 def discoverhandler(self, timeout=3):
     '''Respond to a Discover:Request message, for both multicast and unicast.'''
     while True:
         msg = yield self.net.get(lambda x: x.name == 'Discover:Request')
         if _debug: print 'received discover request'
         if msg.remote.hostport == self.net.node.hostport:
             if _debug: print 'discoverhandler() ignoring our own packet'
             continue  # don't compare Node but only hostport. Ignore if our packet.
         if msg.multicast:  # wait randomly before replying to multicast discover
             if _debug:
                 print 'discoverhandler() wait before responding to multicast'
             response = yield self.net.get(
                 lambda x: x.name == 'Discover:Response' and x.multicast,
                 timeout=(random.random() + 0.5) * timeout)
             if response:  # someone else sent a response, we don't have to send anymore
                 continue
         neighbors = ([self.net.node, self.net.nodetcp]
                      if self.server else []) + self.neighbors
         if not msg.multicast or neighbors:
             response = Message(name='Discover:Response',
                                neighbors=neighbors)
             dest = (msg.remote
                     if not msg.multicast else self.net.nodemcast)
             yield self.net.send(msg=response, node=dest)
コード例 #10
0
 def bootstrap(self, timeout=5, interval=30):
     '''A generator to perform bootstrap function.'''
     candidates = self.candidates[:]  # a copy of list of candidates
     while True:
         if _debug:
             print self.net.name, 'bootstrap server=', self.server, 'neighbors=', len(
                 self.neighbors), 'candidates=', len(candidates)
         if not self.server and not self.neighbors and candidates:  # more candidates but no more neighbors
             node = candidates.pop(0)
             if _debug: print 'bootstrap trying node=', repr(node)
             if node.type == socket.SOCK_DGRAM and isMulticast(node.ip):
                 yield self.net.send(Message(name='Discover:Request'),
                                     node=node)
                 msg = yield self.net.get(
                     lambda x: x.name == 'Discover:Response' and x.
                     multicast,
                     timeout=timeout)
             else:
                 if not isIPv4(node.ip):  # is a IP address?
                     node = Node(ip=socket.gethostbyname(node.ip),
                                 port=node.port,
                                 type=node.type,
                                 guid=node.guid)
                 yield self.net.send(Message(name='Discover:Request'),
                                     node=node)
                 msg = yield self.net.get(
                     lambda x: x.name == 'Discover:Response' and not x.
                     multicast,
                     timeout=timeout)
             if msg:
                 added = False
                 for node in msg.neighbors:
                     if node.hostport == msg.remote.hostport:  # whether msg.remote exists in msg.neighbors, which means remote is a server and we are already connected.
                         if _debug: print 'received neighbor', repr(node)
                         self.neighbors.insert(
                             0,
                             node)  # put this as most preferred neighbor.
                         added = True
                     else:
                         if _debug: print 'received candidate', repr(node)
                         candidates.append(
                             node)  # put this as the next candidate
                 if added:
                     yield self.net.put(
                         Message(name='Discover:Indication',
                                 node=self.node,
                                 neighbors=self.neighbors)
                     )  # indicate change in client.
             else:
                 if _debug: print 'bootstrap did not receive response.'
         elif not self.server and self.neighbors:  # perform neighbor refresh
             yield dht.randomsleep(timeout)
             result = yield self.net.send(Message(name='Ping:Request'),
                                          node=self.neighbors[0],
                                          timeout=timeout)
             if not result:  # no response received, remove the neighbor
                 del self.neighbors[0]
                 yield self.net.put(
                     Message(name='Discover:Indication',
                             node=self.node,
                             neighbors=self.neighbors)
                 )  # indicate change in client.
         elif not self.server and not self.neighbors and not candidates:
             candidates = self.candidates[:]
             yield dht.randomsleep(timeout)
         else:  # just wait before trying again.
             yield dht.randomsleep(interval)