Example #1
0
def resolve(uri):
    '''Resolve a URI using RFC3263 to list of (IP address, port) tuples each with its order, preference, transport and 
    TTL information. The application can supply a list of supported protocols if needed.'''
    if not isinstance(uri, URI): uri = URI(uri)
    transport, target = uri.param['transport'] if 'transport' in uri.param else None, uri.param['maddr'] if 'maddr' in uri.param else uri.host
    numeric, port, result, naptr, srv, result = isIPv4(target), uri.port, None, None, None, None
    #@implements rfc3263 P6L10-P8L32
    if transport: transports = [transport] # only the given transport is used
    elif numeric or port is not None: transports = [x for x in (_secproto if uri.secure else _unsecproto)]
    else:
        naptr = _query((target, dns.T_NAPTR))
        if naptr:
            transports = map(lambda y: _rproto[y[1].lower()], sorted(map(lambda x: (x['RDATA']['ORDER'], x['RDATA']['SERVICE']), naptr), lambda a,b: a[0]-b[0]))
            if uri.secure: 
                transports = filter(lambda x: x in _secproto, transports)
                if not transports: transports, naptr = _secproto, None # assume tls if not found; clear the naptr response
        else:
            srv = filter(lambda x: x[1], [(p, _query(('%s.%s'%(p, target), dns.T_SRV))) for p in [_xproto[x] for x in (_secproto if uri.secure else _unsecproto)]])
            transports = [_rxproto[y[0]] for y in srv] or uri.secure and list(_secproto) or list(_unsecproto)
    #@implements rfc3263 P8L34-P9L31
    if numeric: result = [(target, port or _proto[x][1], x) for x in transports]
    elif port is None:
        service = None
        if naptr: service = sorted(map(lambda x: (x['RDATA']['REPLACEMENT'].lower(), x['RDATA']['ORDER'], x['RDATA']['PREFERENCE'], x['RDATA']['SERVICE'].lower()), naptr), lambda a,b: a[1]-b[1])
        elif transport: service = [('%s.%s'%(_xproto[transport], target), 0, 0, _proto[transport][0])]
        if not srv: srv = filter(lambda y: y[1], [(_rproto[a[3].lower()], _query((a[0], dns.T_SRV))) for a in service]) if service else []
        if srv:
            out = sum([[sorted([(y['RDATA']['DOMAIN'].lower(), y['RDATA']['PRIORITY'], y['RDATA']['WEIGHT'], y['RDATA']['PORT'], x[0])],  lambda a,b: a[1]-b[1]) for y in x[1]] for x in srv], [])
            result = sum([[(y['RDATA'], x[1], x[2]) for y in (_query((x[0], dns.T_A)) or [])] for x in [(x[0], x[3], x[4]) for x in sum(out, [])]], [])
    return result or [(x[0], port or _proto[x[1]][1], x[1]) for x in sum([[(a, b) for a in [x['RDATA'] for x in _query((target, dns.T_A))] ] for b in transports], [])] # finally do A record on target, if nothing else worked
Example #2
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)
Example #3
0
def resolve(uri, supported=('udp', 'tcp', 'tls'), secproto=('tls',)):
    '''Resolve a URI using RFC3263 to list of (IP address, port) tuples each with its order, preference, transport and 
    TTL information. The application can supply a list of supported protocols if needed.'''
    if not isinstance(uri, URI): uri = URI(uri)
    transport = uri.param['transport'] if 'transport' in uri.param else None
    target = uri.param['maddr'] if 'maddr' in uri.param else uri.host
    numeric, port, naptr, srv, result = isIPv4(target), uri.port, None, None, None
    if uri.secure: supported = secproto # only support secproto for "sips"
    #@implements rfc3263 P6L10-P8L32
    if transport: transports = (transport,) if transport in supported else () # only the given transport is used
    elif numeric or port is not None: transports = supported
    else:
        naptr = _query((target, dns.T_NAPTR))
        if naptr: # find the first that is supported
            ordered = filter(lambda r: r[1] in supported, sorted(map(lambda r: (r['RDATA']['ORDER'], _rproto.get(r['RDATA']['SERVICE'].lower(), ''), r), naptr), lambda a,b: a[0]-b[0])) # filter out unsupported transports
            if ordered:
                selected = filter(lambda r: r[0] == ordered[0][0], ordered) # keep only top-ordered values, ignore rest
                transports, naptr = map(lambda r: r[1], selected), map(lambda r: r[2], selected) # unzip to transports and naptr values
            else: transports, naptr = supported, None # assume failure if not found; clear the naptr response
        if not naptr: # do not use "else", because naptr may be cleared in "if"
            srv = filter(lambda r: r[1], map(lambda p: (_rxproto.get(p, ''), _query(('%s.%s'%(p, target), dns.T_SRV))), map(lambda t: _xproto[t], supported)))
            if srv: transports = map(lambda s: s[0], srv)
            else: transports = supported
    #@implements rfc3263 P8L34-P9L31
    if numeric: result = map(lambda t: (target, port or _proto[t][1], t), transports)
    elif port: result = sum(map(lambda t: map(lambda r: (r['RDATA'], port, t), _query((target, dns.T_A))), transports), [])
    else:
        service = None
        if naptr: service = sorted(map(lambda x: (x['RDATA']['REPLACEMENT'].lower(), x['RDATA']['ORDER'], x['RDATA']['PREFERENCE'], x['RDATA']['SERVICE'].lower()), naptr), lambda a,b: a[1]-b[1])
        elif transport: service = [('%s.%s'%(_xproto[transport], target), 0, 0, _proto[transport][0])]
        if not srv: 
            srv = filter(lambda y: y[1], map(lambda s: (_rproto[s[3].lower()], _query((s[0], dns.T_SRV))), service)) if service else []
        if srv:
            out = list(sorted(sum(map(lambda s: map(lambda r: (r['RDATA']['DOMAIN'].lower(), r['RDATA']['PRIORITY'], r['RDATA']['WEIGHT'], r['RDATA']['PORT'], s[0]), s[1]), srv), []),  lambda a,b: a[1]-b[1]))
            result = sum(map(lambda x: map(lambda y: (y['RDATA'], x[1], x[2]), (_query((x[0], dns.T_A)) or [])), map(lambda r: (r[0], r[3], r[4]), out)), [])
    return result or map(lambda x: (x[0], port or _proto[x[1]][1], x[1]), sum(map(lambda b: map(lambda a: (a, b), map(lambda x: x['RDATA'], _query((target, dns.T_A)))), transports), [])) # finally do A record on target, if nothing else worked
Example #4
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)