Ejemplo n.º 1
0
def createSockets(preferred=('0.0.0.0', 0)):
    '''Create three listening sockets (UDP, TCP, UDP-multicast) based on the preferred address tuple
    (address, port). The complication is due to different behavior of multicast socket and socket 
    bind on different platforms. For example, Windows does not allow socket bind() with multicast address.
    
    If preferred argument has any '0.0.0.0' or unicast address, then the UDP-multicast socket is not 
    allocated and is set to None in returned tuple.
    
    If preferred argument has multicast address, then the UDP-multicast socket is allocated and returned.
    The returned multicast socket is bound to ('0.0.0.0', port) where port is from preferred argument.
    
    If preferred argument has unicast address then unicast sockets are tried to be bound to that
    address, and if fails then any '0.0.0.0'. 
    
    If preferred argument has a valid port, then unicast sockets are tried to be bound to that port,
    and if fails then any port. There is an exception -- if the preferred argument also has a 
    multicast address then UDP socket is always bound to any port instead of the preferred port.
    This allows the unicast and multicast sockets to be independent of each other and bound to
    different ports.
    
    If preferred argument is not a multicast address, then the unicast sockets (UDP and TCP) are
    tried to be bound to the same ports is possible, where attempt to bind the TCP is made first.
    
    If a UDP-multicast socket is allocated, then ttl and loopback options are set to 1.
    '''
    addr, port = preferred
    udp = tcp = mcast = None # will be returned
    multicast = isMulticast(addr)
    if multicast: 
        mcast = socket.socket(type=socket.SOCK_DGRAM)
        mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try: mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        except AttributeError: pass # ignore if no REUSEPORT 
        try: mcast.bind((addr, port))
        except socket.error, E: # on windows we get this error (10049) when binding to multicast addr 
            if E[0] == 10049: 
                mcast.close()
                mcast = socket.socket(type=socket.SOCK_DGRAM) # we need to create a new socket otherwise it gives 10022 Invalid argument error on second bind
                mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                try: mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
                except AttributeError: pass # ignore if no REUSEPORT 
                try: mcast.bind(('0.0.0.0', port))
                except socket.error:
                    mcast.close()
                    mcast = None; # probably we couldn't bind to the port.
        if mcast is not None:
            mcast.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1) # scope to local network only
            mcast.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
            mcast.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(addr) + socket.inet_aton('0.0.0.0'))
Ejemplo n.º 2
0
 def send(self, msg, node, timeout=None):
     model, src, dst = self.model, self.node.guid, node.guid
     toSend = True
     if model is not None:
         if src in model.nodes and dst in model.nodes: 
             s, d = model.nodes[src], model.nodes[dst]
             sin, din = s.index, d.index
             if s.removed: 
                 toSend = False
                 if _debug: print 'Not sending', msg, ' because source is removed'
             elif msg.name not in ('Hash:Request', 'Hash:Response', 'Ack:Indication'):
                 if _debug: print '%d=>%s \t%s'%(sin, str(din) if not isMulticast(node.ip) else 'M', msg.name) 
         if toSend:  
             model.sendMessage(src, dst, msg.name)
     # if self.view is not None: self.view.Refresh() # TODO: use a timer instead, otherwise it flickers
     if toSend:
         return p2p.Network.send(self, msg, node, timeout=timeout)
     else:
         raise StopIteration, True
Ejemplo n.º 3
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) 
Ejemplo n.º 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)
Ejemplo n.º 5
0
def createSockets(preferred=('0.0.0.0', 0)):
    '''Create three listening sockets (UDP, TCP, UDP-multicast) based on the preferred address tuple
    (address, port). The complication is due to different behavior of multicast socket and socket 
    bind on different platforms. For example, Windows does not allow socket bind() with multicast address.
    
    If preferred argument has any '0.0.0.0' or unicast address, then the UDP-multicast socket is not 
    allocated and is set to None in returned tuple.
    
    If preferred argument has multicast address, then the UDP-multicast socket is allocated and returned.
    The returned multicast socket is bound to ('0.0.0.0', port) where port is from preferred argument.
    
    If preferred argument has unicast address then unicast sockets are tried to be bound to that
    address, and if fails then any '0.0.0.0'. 
    
    If preferred argument has a valid port, then unicast sockets are tried to be bound to that port,
    and if fails then any port. There is an exception -- if the preferred argument also has a 
    multicast address then UDP socket is always bound to any port instead of the preferred port.
    This allows the unicast and multicast sockets to be independent of each other and bound to
    different ports.
    
    If preferred argument is not a multicast address, then the unicast sockets (UDP and TCP) are
    tried to be bound to the same ports is possible, where attempt to bind the TCP is made first.
    
    If a UDP-multicast socket is allocated, then ttl and loopback options are set to 1.
    '''
    addr, port = preferred
    udp = tcp = mcast = None  # will be returned
    multicast = isMulticast(addr)
    if multicast:
        mcast = socket.socket(type=socket.SOCK_DGRAM)
        mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        try:
            mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
        except AttributeError:
            pass  # ignore if no REUSEPORT
        try:
            mcast.bind((addr, port))
        except socket.error, E:  # on windows we get this error (10049) when binding to multicast addr
            if E[0] == 10049:
                mcast.close()
                mcast = socket.socket(
                    type=socket.SOCK_DGRAM
                )  # we need to create a new socket otherwise it gives 10022 Invalid argument error on second bind
                mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                try:
                    mcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
                except AttributeError:
                    pass  # ignore if no REUSEPORT
                try:
                    mcast.bind(('0.0.0.0', port))
                except socket.error:
                    mcast.close()
                    mcast = None
                    # probably we couldn't bind to the port.
        if mcast is not None:
            mcast.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL,
                             1)  # scope to local network only
            mcast.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
            mcast.setsockopt(
                socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                socket.inet_aton(addr) + socket.inet_aton('0.0.0.0'))