Updates from issue #54 - obtaining local ip, logging, standalone

This commit is contained in:
sirMackk 2015-03-07 19:22:09 -05:00
parent 5ca4540f1d
commit e2bb5952eb
1 changed files with 57 additions and 28 deletions

View File

@ -4,7 +4,7 @@ from gevent import monkey
monkey.patch_socket()
import re, urllib2, httplib
import re, urllib2, httplib, logging
from urlparse import urlparse
from xml.dom.minidom import parseString
@ -16,7 +16,7 @@ from xml.dom.minidom import parseString
remove_whitespace = re.compile(r'>\s*<')
def _m_search_ssdp():
def _m_search_ssdp(local_ip):
"""
Broadcast a UDP SSDP M-SEARCH packet and return response.
"""
@ -32,13 +32,17 @@ def _m_search_ssdp():
)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((local_ip, 10000))
sock.sendto(ssdp_request, ('239.255.255.250', 1900))
sock.settimeout(5)
try:
return sock.recv(2048)
except socket.error:
except socket.error, err:
# no reply from IGD, possibly no IGD on LAN
logging.debug("UDP SSDP M-SEARCH send error using ip %s: %s" % (local_ip, err))
return False
@ -102,12 +106,11 @@ def _get_local_ip():
return s.getsockname()[0]
def _create_soap_message(port, description="UPnPPunch", protocol="TCP",
def _create_soap_message(local_ip, port, description="UPnPPunch", protocol="TCP",
upnp_schema='WANIPConnection'):
"""
Build a SOAP AddPortMapping message.
"""
current_ip = _get_local_ip()
soap_message = """<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
@ -125,7 +128,7 @@ def _create_soap_message(port, description="UPnPPunch", protocol="TCP",
</s:Body>
</s:Envelope>""".format(port=port,
protocol=protocol,
host_ip=current_ip,
host_ip=local_ip,
description=description,
upnp_schema=upnp_schema)
return remove_whitespace.sub('><', soap_message)
@ -138,9 +141,11 @@ def _parse_for_errors(soap_response):
err_msg = _node_val(
err_dom.getElementsByTagName('errorDescription')[0]
)
logging.error('SOAP request error: {0} - {1}'.format(err_code, err_msg))
raise Exception(
'SOAP request error: {0} - {1}'.format(err_code, err_msg)
)
return False
else:
return True
@ -171,35 +176,59 @@ def open_port(port=15441, desc="UpnpPunch"):
Attempt to forward a port using UPnP.
"""
idg_response = _m_search_ssdp()
local_ips = [_get_local_ip()]
try:
local_ips += socket.gethostbyname_ex('')[2] # Get ip by '' hostrname not supported on all platform
except:
pass
if not idg_response:
return False
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0)) # Using google dns route
local_ips.append(s.getsockname()[0])
except:
pass
location = _retrieve_location_from_ssdp(idg_response)
local_ips = list(set(local_ips)) # Delete duplicates
logging.debug("Found local ips: %s" % local_ips)
if not location:
return False
for local_ip in local_ips:
logging.debug("Trying using local ip: %s" % local_ip)
idg_response = _m_search_ssdp(local_ip)
parsed = _parse_igd_profile(
_retrieve_igd_profile(location)
)
if not idg_response:
logging.debug("No IGD response")
continue
if not parsed:
return False
location = _retrieve_location_from_ssdp(idg_response)
control_url, upnp_schema = parsed
if not location:
logging.debug("No location")
continue
soap_messages = [_create_soap_message(port, desc, proto, upnp_schema)
for proto in ['TCP', 'UDP']]
parsed = _parse_igd_profile(
_retrieve_igd_profile(location)
)
requests = [gevent.spawn(
_send_soap_request, location, upnp_schema, control_url, message
) for message in soap_messages]
if not parsed:
logging.debug("IGD parse error using location %s" % repr(location))
continue
gevent.joinall(requests, timeout=3)
control_url, upnp_schema = parsed
if all(requests):
return True
else:
return False
soap_messages = [_create_soap_message(local_ip, port, desc, proto, upnp_schema)
for proto in ['TCP', 'UDP']]
requests = [gevent.spawn(
_send_soap_request, location, upnp_schema, control_url, message
) for message in soap_messages]
gevent.joinall(requests, timeout=3)
if all([request.value for request in requests]):
return True
return False
if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG)
print open_port(15441, "ZeroNet")