From: Forrest Voight Date: Mon, 8 Aug 2011 20:22:08 +0000 (-0400) Subject: fixed resource leak and incorrect exception handling in nattraverso upnp library X-Git-Tag: 0.8.2~207^2~61 X-Git-Url: https://git.novaco.in/?a=commitdiff_plain;h=013140c7b6f25c59bc01d908faf2036c2af685b3;hp=f01270868c943597ace7d9ac13c2e6cdfa1dc15c;p=p2pool.git fixed resource leak and incorrect exception handling in nattraverso upnp library --- diff --git a/nattraverso/ipdiscover.py b/nattraverso/ipdiscover.py index f8b5012..d18ec07 100644 --- a/nattraverso/ipdiscover.py +++ b/nattraverso/ipdiscover.py @@ -123,8 +123,8 @@ def _get_via_multicast(): except: raise - logging.debug("Multicast ping to retreive local IP") - return LocalNetworkMulticast().discover().addCallback(_got_multicast_ip) + logging.debug("Multicast ping to retrieve local IP") + return _discover_multicast().addCallback(_got_multicast_ip) def _get_via_connected_udp(ipaddr): """ @@ -142,66 +142,62 @@ def _get_via_connected_udp(ipaddr): port.stopListening() if is_bogus_ip(localip): - raise RuntimeError, "Invalid IP addres returned" + raise RuntimeError, "Invalid IP address returned" else: return (is_rfc1918_ip(localip), localip) -class LocalNetworkMulticast(DatagramProtocol, object): - """ - Local IP discovery protocol via multicast: - - Broadcast 3 ping multicast packet with "ping" in it - - Wait for an answer - - Retreive the ip address from the returning packet, which is ours - """ - def __init__(self, *args, **kwargs): - super(LocalNetworkMulticast, self).__init__(*args, **kwargs) - - # Nothing found yet - self.completed = False - self.result = defer.Deferred() +class _LocalNetworkMulticast(DatagramProtocol): + def __init__(self, nonce): + from p2pool.util import variable - def discover(self): - """ - Launch the discovery of an UPnP device on the local network. You should - always call this after having created the object. - - >>> result = LocalNetworkMulticast().discover().addCallback(got_upnpdevice_ip) - - @return: A deferred called with the IP address of the UPnP device - @rtype: L{twisted.internet.defer.Deferred} - """ - #The port we listen on - mcast_port = 0 - #The result of listenMulticast - mcast = None - - # 5 different UDP ports - ports = [11000+random.randint(0, 5000) for port in range(5)] - for attempt, port in enumerate(ports): - try: - mcast = reactor.listenMulticast(port, self) - mcast_port = port - break - except CannotListenError: - if attempt < 5: - print "Trying another multicast UDP port", port - else: - raise - - logging.debug("Sending multicast ping") - mcast.joinGroup('239.255.255.250', socket.INADDR_ANY) - self.transport.write('ping', ('239.255.255.250', mcast_port)) - self.transport.write('ping', ('239.255.255.250', mcast_port)) - self.transport.write('ping', ('239.255.255.250', mcast_port)) - return self.result - + self.nonce = nonce + self.address_received = variable.Event() + def datagramReceived(self, dgram, addr): """Datagram received, we callback the IP address.""" logging.debug("Received multicast pong: %s; addr:%r", dgram, addr) - if self.completed or dgram != 'ping': - # Result already handled, do nothing + if dgram != self.nonce: return + self.address_received.happened(addr[0]) + +@defer.inlineCallbacks +def _discover_multicast(): + """ + Local IP discovery protocol via multicast: + - Broadcast 3 ping multicast packet with "ping" in it + - Wait for an answer + - Retrieve the ip address from the returning packet, which is ours + """ + + nonce = str(random.randrange(2**64)) + p = _LocalNetworkMulticast(nonce) + + # 5 different UDP ports + ports = [11000+random.randint(0, 5000) for port in range(5)] + for attempt, port in enumerate(ports): + try: + mcast = reactor.listenMulticast(port, p) + mcast_port = port + except CannotListenError: + if attempt < 5: + print "Trying another multicast UDP port", port + else: + raise else: - self.completed = True - # Return the upn device ip address - self.result.callback(addr[0]) + break + + try: + yield mcast.joinGroup('239.255.255.250', socket.INADDR_ANY) + + try: + logging.debug("Sending multicast ping") + for i in xrange(3): + p.transport.write(nonce, ('239.255.255.250', mcast_port)) + + address, = yield p.address_received.get_deferred(5) + finally: + mcast.leaveGroup('239.255.255.250', socket.INADDR_ANY) + finally: + mcast.stopListening() + + defer.returnValue(address) diff --git a/p2pool/main.py b/p2pool/main.py index 50adf8a..da771f3 100644 --- a/p2pool/main.py +++ b/p2pool/main.py @@ -301,7 +301,7 @@ def main(args): yield pm._upnp.add_port_mapping(lan_ip, args.net.P2P_PORT, args.net.P2P_PORT, 'p2pool', 'TCP') except: if p2pool_init.DEBUG: - log.err() + log.err(None, "UPnP error:") yield deferral.sleep(random.expovariate(1/120)) if args.upnp: