From 7a9092247370fa6b2b76ba858063bad16d06b016 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Fri, 13 Jun 2014 13:52:47 +0000 Subject: [PATCH] Catch various network/server errors. --- src/ddns/errors.py | 32 ++++++++++++++++++++++++++++++++ src/ddns/system.py | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/ddns/errors.py b/src/ddns/errors.py index cd935d0..f9cc3f6 100644 --- a/src/ddns/errors.py +++ b/src/ddns/errors.py @@ -23,6 +23,10 @@ class DDNSError(Exception): pass +class DDNSNetworkError(DDNSError): + pass + + class DDNSAbuseError(DDNSError): """ Thrown when the server reports @@ -56,6 +60,20 @@ class DDNSConfigurationError(DDNSError): pass +class DDNSConnectionRefusedError(DDNSNetworkError): + """ + Thrown when a connection is refused. + """ + pass + + +class DDNSConnectionTimeoutError(DDNSNetworkError): + """ + Thrown when a connection to a server has timed out. + """ + pass + + class DDNSHostNotFoundError(DDNSError): """ Thrown when a configuration entry could @@ -72,6 +90,13 @@ class DDNSInternalServerError(DDNSError): pass +class DDNSNetworkUnreachableError(DDNSNetworkError): + """ + Thrown when a network is not reachable. + """ + pass + + class DDNSRequestError(DDNSError): """ Thrown when a request could @@ -80,6 +105,13 @@ class DDNSRequestError(DDNSError): pass +class DDNSServiceUnavailableError(DDNSNetworkError): + """ + Equivalent to HTTP error code 503. + """ + pass + + class DDNSUpdateError(DDNSError): """ Thrown when an update could not be diff --git a/src/ddns/system.py b/src/ddns/system.py index 90226b3..59dc218 100644 --- a/src/ddns/system.py +++ b/src/ddns/system.py @@ -26,6 +26,7 @@ import urllib import urllib2 from __version__ import CLIENT_VERSION +from .errors import * from i18n import _ # Initialize the logger. @@ -61,7 +62,12 @@ class DDNSSystem(object): Sends a request to an external web server to determine the current default IP address. """ - response = self.send_request("http://checkip6.dns.lightningwirelabs.com") + try: + response = self.send_request("http://checkip6.dns.lightningwirelabs.com", timeout=10) + + # If the server could not be reached, we will return nothing. + except DDNSNetworkError: + return if not response.code == 200: return @@ -79,7 +85,12 @@ class DDNSSystem(object): XXX does not work for IPv6. """ - response = self.send_request("http://checkip4.dns.lightningwirelabs.com") + try: + response = self.send_request("http://checkip4.dns.lightningwirelabs.com", timeout=10) + + # If the server could not be reached, we will return nothing. + except DDNSNetworkError: + return if response.code == 200: match = re.search(r"Your IP address is: (\d+.\d+.\d+.\d+)", response.read()) @@ -129,7 +140,7 @@ class DDNSSystem(object): logger.debug(" %s: %s" % (k, v)) try: - resp = urllib2.urlopen(req) + resp = urllib2.urlopen(req, timeout=timeout) # Log response header. logger.debug(_("Response header:")) @@ -139,9 +150,30 @@ class DDNSSystem(object): # Return the entire response object. return resp + except urllib2.HTTPError, e: + # 503 - Service Unavailable + if e.code == 503: + raise DDNSServiceUnavailableError + + # Raise all other unhandled exceptions. + raise + except urllib2.URLError, e: + if e.reason: + # Network Unreachable (e.g. no IPv6 access) + if e.reason.errno == 101: + raise DDNSNetworkUnreachableError + elif e.reason.errno == 111: + raise DDNSConnectionRefusedError + + # Raise all other unhandled exceptions. raise + except socket.timeout, e: + logger.debug(_("Connection timeout")) + + raise DDNSConnectionTimeoutError + def _format_query_args(self, data): args = [] -- 2.39.2