Compare commits
No commits in common. 'c9' and 'i8c-stream-DL1' have entirely different histories.
c9
...
i8c-stream
@ -1 +1 @@
|
|||||||
SOURCES/kdcproxy-1.0.0.tar.gz
|
SOURCES/kdcproxy-0.4.tar.gz
|
||||||
|
@ -1 +1 @@
|
|||||||
4b2da76684ff66ad28d5d5104a23a41d5413cc11 SOURCES/kdcproxy-1.0.0.tar.gz
|
48cffec358fe9e15a66fb040b6b7fc87f642f6da SOURCES/kdcproxy-0.4.tar.gz
|
||||||
|
@ -0,0 +1,84 @@
|
|||||||
|
From c1be487bb00f2e813212031d93fcebbfbd0da60b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Thu, 29 Aug 2019 11:13:41 -0400
|
||||||
|
Subject: [PATCH] Always buffer TCP data in __handle_recv()
|
||||||
|
|
||||||
|
Refactor __handle_recv() to always create a BytesIO() object for TCP
|
||||||
|
data. Linearize control flow for ease of debugging. Always apply
|
||||||
|
length checks so that we don't have to wait for EOF in the multiple-recv
|
||||||
|
case.
|
||||||
|
|
||||||
|
Fixes a bug where we wouldn't return any data because we never received
|
||||||
|
the EOF, or didn't receive it fast enough.
|
||||||
|
|
||||||
|
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
(cherry picked from commit 7e2b1ab27b843c220fe301b74bab01ed61b0f59a)
|
||||||
|
---
|
||||||
|
kdcproxy/__init__.py | 54 +++++++++++++++++++++++++-------------------
|
||||||
|
1 file changed, 31 insertions(+), 23 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py
|
||||||
|
index 6526bc9..9bc7044 100644
|
||||||
|
--- a/kdcproxy/__init__.py
|
||||||
|
+++ b/kdcproxy/__init__.py
|
||||||
|
@@ -128,29 +128,37 @@ class Application:
|
||||||
|
# length prefix. So add it.
|
||||||
|
reply = struct.pack("!I", len(reply)) + reply
|
||||||
|
return reply
|
||||||
|
- else:
|
||||||
|
- # TCP is a different story. The reply must be buffered
|
||||||
|
- # until the full answer is accumulated.
|
||||||
|
- buf = read_buffers.get(sock)
|
||||||
|
- part = sock.recv(1048576)
|
||||||
|
- if buf is None:
|
||||||
|
- if len(part) > 4:
|
||||||
|
- # got enough data in the initial package. Now check
|
||||||
|
- # if we got the full package in the first run.
|
||||||
|
- (length, ) = struct.unpack("!I", part[0:4])
|
||||||
|
- if length + 4 == len(part):
|
||||||
|
- return part
|
||||||
|
- read_buffers[sock] = buf = io.BytesIO()
|
||||||
|
-
|
||||||
|
- if part:
|
||||||
|
- # data received, accumulate it in a buffer
|
||||||
|
- buf.write(part)
|
||||||
|
- return None
|
||||||
|
- else:
|
||||||
|
- # EOF received
|
||||||
|
- read_buffers.pop(sock)
|
||||||
|
- reply = buf.getvalue()
|
||||||
|
- return reply
|
||||||
|
+
|
||||||
|
+ # TCP is a different story. The reply must be buffered until the full
|
||||||
|
+ # answer is accumulated.
|
||||||
|
+ buf = read_buffers.get(sock)
|
||||||
|
+ if buf is None:
|
||||||
|
+ read_buffers[sock] = buf = io.BytesIO()
|
||||||
|
+
|
||||||
|
+ part = sock.recv(1048576)
|
||||||
|
+ if not part:
|
||||||
|
+ # EOF received. Return any incomplete data we have on the theory
|
||||||
|
+ # that a decode error is more apparent than silent failure. The
|
||||||
|
+ # client will fail faster, at least.
|
||||||
|
+ read_buffers.pop(sock)
|
||||||
|
+ reply = buf.getvalue()
|
||||||
|
+ return reply
|
||||||
|
+
|
||||||
|
+ # Data received, accumulate it in a buffer.
|
||||||
|
+ buf.write(part)
|
||||||
|
+
|
||||||
|
+ reply = buf.getvalue()
|
||||||
|
+ if len(reply) < 4:
|
||||||
|
+ # We don't have the length yet.
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+ # Got enough data to check if we have the full package.
|
||||||
|
+ (length, ) = struct.unpack("!I", reply[0:4])
|
||||||
|
+ if length + 4 == len(reply):
|
||||||
|
+ read_buffers.pop(sock)
|
||||||
|
+ return reply
|
||||||
|
+
|
||||||
|
+ return None
|
||||||
|
|
||||||
|
def __filter_addr(self, addr):
|
||||||
|
if addr[0] not in (socket.AF_INET, socket.AF_INET6):
|
@ -0,0 +1,28 @@
|
|||||||
|
From 5cfde6d085320da3fb5d4c6506e6d6253438669c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Fri, 2 Aug 2019 13:54:05 -0400
|
||||||
|
Subject: [PATCH] Correct addrs sorting to be by TCP/UDP
|
||||||
|
|
||||||
|
Fixes any potential cases where the resolver might yield UDP addresses
|
||||||
|
first.
|
||||||
|
|
||||||
|
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
(cherry picked from commit d0b35c2b71a172f409b4311d36538d8fa3433c58)
|
||||||
|
---
|
||||||
|
kdcproxy/__init__.py | 3 ++-
|
||||||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py
|
||||||
|
index c59f2b3..6526bc9 100644
|
||||||
|
--- a/kdcproxy/__init__.py
|
||||||
|
+++ b/kdcproxy/__init__.py
|
||||||
|
@@ -227,7 +227,8 @@ class Application:
|
||||||
|
#
|
||||||
|
# Stick a None address on the end so we can get one
|
||||||
|
# more attempt after all servers have been contacted.
|
||||||
|
- addrs = tuple(sorted(filter(self.__filter_addr, addrs)))
|
||||||
|
+ addrs = tuple(sorted(filter(self.__filter_addr, addrs),
|
||||||
|
+ key=lambda a: a[2]))
|
||||||
|
for addr in addrs + (None,):
|
||||||
|
if addr is not None:
|
||||||
|
# Bypass unspecified socktypes
|
@ -1,100 +0,0 @@
|
|||||||
From 7b7aee01d72be5a310678cdad189cb7382f28549 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Robbie Harwood <rharwood@redhat.com>
|
|
||||||
Date: Tue, 19 Jan 2021 11:41:40 -0500
|
|
||||||
Subject: [PATCH] Drop coverage from tests
|
|
||||||
|
|
||||||
To my knowledge, we've never looked at or done anything with this
|
|
||||||
output. Test coverage is a noble goal, but this project is mostly
|
|
||||||
complete, so we don't expect heavy development soon.
|
|
||||||
|
|
||||||
Requested-by: Petr Viktorin <pviktori@redhat.com>
|
|
||||||
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
|
|
||||||
(cherry picked from commit 86c3da13d5d6cdb5822d194f2b820da1fd31dddb)
|
|
||||||
[rharwood@redhat.com: .gitignore]
|
|
||||||
---
|
|
||||||
.coveragerc | 23 -----------------------
|
|
||||||
MANIFEST.in | 1 -
|
|
||||||
setup.py | 2 +-
|
|
||||||
tox.ini | 12 ++----------
|
|
||||||
4 files changed, 3 insertions(+), 35 deletions(-)
|
|
||||||
delete mode 100644 .coveragerc
|
|
||||||
|
|
||||||
diff --git a/.coveragerc b/.coveragerc
|
|
||||||
deleted file mode 100644
|
|
||||||
index 4038562..0000000
|
|
||||||
--- a/.coveragerc
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,23 +0,0 @@
|
|
||||||
-[run]
|
|
||||||
-branch = True
|
|
||||||
-source =
|
|
||||||
- kdcproxy
|
|
||||||
- tests.py
|
|
||||||
-
|
|
||||||
-[paths]
|
|
||||||
-source =
|
|
||||||
- kdcproxy
|
|
||||||
- .tox/*/lib/python*/site-packages/kdcproxy
|
|
||||||
-
|
|
||||||
-[report]
|
|
||||||
-ignore_errors = False
|
|
||||||
-precision = 1
|
|
||||||
-exclude_lines =
|
|
||||||
- pragma: no cover
|
|
||||||
- raise AssertionError
|
|
||||||
- raise NotImplementedError
|
|
||||||
- if 0:
|
|
||||||
- if False:
|
|
||||||
- if __name__ == .__main__.:
|
|
||||||
- if PY3
|
|
||||||
- if not PY3
|
|
||||||
diff --git a/MANIFEST.in b/MANIFEST.in
|
|
||||||
index 362f840..ff6b9a7 100644
|
|
||||||
--- a/MANIFEST.in
|
|
||||||
+++ b/MANIFEST.in
|
|
||||||
@@ -2,4 +2,3 @@ include README COPYING
|
|
||||||
include tox.ini
|
|
||||||
include setup.cfg
|
|
||||||
include tests.py tests.krb5.conf
|
|
||||||
-include .coveragerc
|
|
||||||
diff --git a/setup.py b/setup.py
|
|
||||||
index 20b335e..4b34fcc 100644
|
|
||||||
--- a/setup.py
|
|
||||||
+++ b/setup.py
|
|
||||||
@@ -29,7 +29,7 @@ install_requires = [
|
|
||||||
]
|
|
||||||
|
|
||||||
extras_require = {
|
|
||||||
- "tests": ["pytest", "coverage", "WebTest"],
|
|
||||||
+ "tests": ["pytest", "WebTest"],
|
|
||||||
"test_pep8": ['flake8', 'flake8-import-order', 'pep8-naming']
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/tox.ini b/tox.ini
|
|
||||||
index 038d996..9672cee 100644
|
|
||||||
--- a/tox.ini
|
|
||||||
+++ b/tox.ini
|
|
||||||
@@ -1,21 +1,13 @@
|
|
||||||
[tox]
|
|
||||||
minversion = 2.3.1
|
|
||||||
-envlist = py36,py37,py38,py39,pep8,py3pep8,doc,coverage-report
|
|
||||||
+envlist = py36,py37,py38,py39,pep8,py3pep8,doc
|
|
||||||
skip_missing_interpreters = true
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
deps =
|
|
||||||
.[tests]
|
|
||||||
commands =
|
|
||||||
- {envpython} -m coverage run --parallel \
|
|
||||||
- -m pytest --capture=no --strict {posargs}
|
|
||||||
-
|
|
||||||
-[testenv:coverage-report]
|
|
||||||
-deps = coverage
|
|
||||||
-skip_install = true
|
|
||||||
-commands =
|
|
||||||
- {envpython} -m coverage combine
|
|
||||||
- {envpython} -m coverage report --show-missing
|
|
||||||
+ {envpython} -m pytest --capture=no --strict {posargs}
|
|
||||||
|
|
||||||
[testenv:pep8]
|
|
||||||
basepython = python3
|
|
@ -0,0 +1,36 @@
|
|||||||
|
From 2164f10fe5d992006f42c4a8d682f23b04ffbf12 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Thu, 9 Aug 2018 14:57:56 -0400
|
||||||
|
Subject: [PATCH] Make webtest an optional dependency
|
||||||
|
|
||||||
|
Resolves: #38
|
||||||
|
(cherry picked from commit c0bee88c60deb176d420d90447d24c370d70727a)
|
||||||
|
---
|
||||||
|
tests.py | 7 ++++++-
|
||||||
|
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/tests.py b/tests.py
|
||||||
|
index 992529f..c2b1fc0 100644
|
||||||
|
--- a/tests.py
|
||||||
|
+++ b/tests.py
|
||||||
|
@@ -33,7 +33,11 @@ from dns.rdataclass import IN as RDCLASS_IN
|
||||||
|
from dns.rdatatype import SRV as RDTYPE_SRV
|
||||||
|
from dns.rdtypes.IN.SRV import SRV
|
||||||
|
|
||||||
|
-from webtest import TestApp as WebTestApp
|
||||||
|
+try:
|
||||||
|
+ from webtest import TestApp as WebTestApp
|
||||||
|
+except ImportError:
|
||||||
|
+ print("webtest not installed! Tests will be skipped")
|
||||||
|
+ WebTestApp = "skip"
|
||||||
|
|
||||||
|
import kdcproxy
|
||||||
|
from kdcproxy import codec
|
||||||
|
@@ -45,6 +49,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
KRB5_CONFIG = os.path.join(HERE, 'tests.krb5.conf')
|
||||||
|
|
||||||
|
|
||||||
|
+@unittest.skipIf(WebTestApp == "skip", "webtest not installed")
|
||||||
|
class KDCProxyWSGITests(unittest.TestCase):
|
||||||
|
addrinfo = [
|
||||||
|
(2, 1, 6, '', ('128.66.0.2', 88)),
|
@ -0,0 +1,71 @@
|
|||||||
|
From d66084656bd01e22a5f23119968bd939d380875c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Mon, 18 Nov 2024 10:01:16 +0100
|
||||||
|
Subject: [PATCH] Use dedicated "kdcproxy" logger
|
||||||
|
|
||||||
|
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||||
|
(cherry picked from commit c8a69dbc0777579ba3bf3d156baed0966327ebc2)
|
||||||
|
---
|
||||||
|
kdcproxy/__init__.py | 7 +++++--
|
||||||
|
kdcproxy/config/__init__.py | 7 +++++--
|
||||||
|
2 files changed, 10 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py
|
||||||
|
index cfec0f3..a84ad4a 100644
|
||||||
|
--- a/kdcproxy/__init__.py
|
||||||
|
+++ b/kdcproxy/__init__.py
|
||||||
|
@@ -37,6 +37,9 @@ else:
|
||||||
|
import httplib
|
||||||
|
import urlparse
|
||||||
|
|
||||||
|
+logging.basicConfig()
|
||||||
|
+logger = logging.getLogger('kdcproxy')
|
||||||
|
+
|
||||||
|
|
||||||
|
class HTTPException(Exception):
|
||||||
|
|
||||||
|
@@ -326,8 +329,8 @@ class Application:
|
||||||
|
fail_socktype = self.addr2socktypename(fail_addr)
|
||||||
|
fail_ip = fail_addr[4][0]
|
||||||
|
fail_port = fail_addr[4][1]
|
||||||
|
- logging.warning("Exchange with %s:[%s]:%d failed: %s",
|
||||||
|
- fail_socktype, fail_ip, fail_port, e)
|
||||||
|
+ logger.warning("Exchange with %s:[%s]:%d failed: %s",
|
||||||
|
+ fail_socktype, fail_ip, fail_port, e)
|
||||||
|
if reply is not None:
|
||||||
|
break
|
||||||
|
|
||||||
|
diff --git a/kdcproxy/config/__init__.py b/kdcproxy/config/__init__.py
|
||||||
|
index 5bff159..93af69a 100644
|
||||||
|
--- a/kdcproxy/config/__init__.py
|
||||||
|
+++ b/kdcproxy/config/__init__.py
|
||||||
|
@@ -32,6 +32,9 @@ except ImportError: # Python 2.x
|
||||||
|
import dns.rdatatype
|
||||||
|
import dns.resolver
|
||||||
|
|
||||||
|
+logging.basicConfig()
|
||||||
|
+logger = logging.getLogger('kdcproxy')
|
||||||
|
+
|
||||||
|
|
||||||
|
class IResolver(object):
|
||||||
|
|
||||||
|
@@ -60,14 +63,14 @@ class KDCProxyConfig(IConfig):
|
||||||
|
try:
|
||||||
|
self.__cp.read(filename)
|
||||||
|
except configparser.Error:
|
||||||
|
- logging.error("Unable to read config file: %s", filename)
|
||||||
|
+ logger.error("Unable to read config file: %s", filename)
|
||||||
|
|
||||||
|
try:
|
||||||
|
mod = self.__cp.get(self.GLOBAL, "configs")
|
||||||
|
try:
|
||||||
|
importlib.import_module("kdcproxy.config." + mod)
|
||||||
|
except ImportError as e:
|
||||||
|
- logging.log(logging.ERROR, "Error reading config: %s" % e)
|
||||||
|
+ logger.log(logging.ERROR, "Error reading config: %s" % e)
|
||||||
|
except configparser.Error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
@ -0,0 +1,158 @@
|
|||||||
|
From c8ed63653cfdf4a55ad4cf26cb11e8938b227f13 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Mon, 18 Nov 2024 09:38:13 +0100
|
||||||
|
Subject: [PATCH] Use exponential backoff for connection retries
|
||||||
|
|
||||||
|
Calls to socket.connect() are non-blocking, hence all subsequent calls
|
||||||
|
to socket.sendall() will fail if the target KDC service is temporarily
|
||||||
|
or indefinitely unreachable. Since the kdcproxy task uses busy-looping,
|
||||||
|
it results in the journal to be flooded with warning logs.
|
||||||
|
|
||||||
|
This commit introduces a per-socket reactivation delay which increases
|
||||||
|
exponentially as the number of reties is incremented, until timeout is
|
||||||
|
reached (i.e. 100ms, 200ms, 400ms, 800ms, 1.6s, 3.2s, ...).
|
||||||
|
|
||||||
|
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||||
|
(cherry picked from commit bac3c99c1b23487e38d965a79173ce9519e19c75)
|
||||||
|
---
|
||||||
|
kdcproxy/__init__.py | 63 +++++++++++++++++++++++++++++++++++++++++---
|
||||||
|
1 file changed, 60 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py
|
||||||
|
index 9bc7044..cfec0f3 100644
|
||||||
|
--- a/kdcproxy/__init__.py
|
||||||
|
+++ b/kdcproxy/__init__.py
|
||||||
|
@@ -60,6 +60,13 @@ class HTTPException(Exception):
|
||||||
|
return "%d %s" % (self.code, httplib.responses[self.code])
|
||||||
|
|
||||||
|
|
||||||
|
+class SocketException(Exception):
|
||||||
|
+
|
||||||
|
+ def __init__(self, message, sock):
|
||||||
|
+ super(Exception, self).__init__(message)
|
||||||
|
+ self.sockfno = sock.fileno()
|
||||||
|
+
|
||||||
|
+
|
||||||
|
class Application:
|
||||||
|
MAX_LENGTH = 128 * 1024
|
||||||
|
SOCKTYPES = {
|
||||||
|
@@ -67,10 +74,23 @@ class Application:
|
||||||
|
"udp": socket.SOCK_DGRAM,
|
||||||
|
}
|
||||||
|
|
||||||
|
+ def addr2socktypename(self, addr):
|
||||||
|
+ ret = None
|
||||||
|
+ for name in self.SOCKTYPES:
|
||||||
|
+ if self.SOCKTYPES[name] == addr[1]:
|
||||||
|
+ ret = name
|
||||||
|
+ break
|
||||||
|
+ return ret
|
||||||
|
+
|
||||||
|
def __init__(self):
|
||||||
|
self.__resolver = MetaResolver()
|
||||||
|
|
||||||
|
def __await_reply(self, pr, rsocks, wsocks, timeout):
|
||||||
|
+ starting_time = time.time()
|
||||||
|
+ send_error = None
|
||||||
|
+ recv_error = None
|
||||||
|
+ failing_sock = None
|
||||||
|
+ reactivations = {}
|
||||||
|
extra = 0
|
||||||
|
read_buffers = {}
|
||||||
|
while (timeout + extra) > time.time():
|
||||||
|
@@ -91,6 +111,12 @@ class Application:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for sock in w:
|
||||||
|
+ # Fetch reactivation tuple:
|
||||||
|
+ # 1st element: reactivation index (-1 = first activation)
|
||||||
|
+ # 2nd element: planned reactivation time (0.0 = now)
|
||||||
|
+ (rn, rt) = reactivations.get(sock, (-1, 0.0))
|
||||||
|
+ if rt > time.time():
|
||||||
|
+ continue
|
||||||
|
try:
|
||||||
|
if self.sock_type(sock) == socket.SOCK_DGRAM:
|
||||||
|
# If we proxy over UDP, remove the 4-byte length
|
||||||
|
@@ -100,8 +126,13 @@ class Application:
|
||||||
|
sock.sendall(pr.request)
|
||||||
|
extra = 10 # New connections get 10 extra seconds
|
||||||
|
except Exception as e:
|
||||||
|
- logging.warning("Conection broken while writing (%s)", e)
|
||||||
|
+ send_error = e
|
||||||
|
+ failing_sock = sock
|
||||||
|
+ reactivations[sock] = (rn + 1,
|
||||||
|
+ time.time() + 2.0**(rn + 1) / 10)
|
||||||
|
continue
|
||||||
|
+ if sock in reactivations:
|
||||||
|
+ del reactivations[sock]
|
||||||
|
rsocks.append(sock)
|
||||||
|
wsocks.remove(sock)
|
||||||
|
|
||||||
|
@@ -109,7 +140,8 @@ class Application:
|
||||||
|
try:
|
||||||
|
reply = self.__handle_recv(sock, read_buffers)
|
||||||
|
except Exception as e:
|
||||||
|
- logging.warning("Connection broken while reading (%s)", e)
|
||||||
|
+ recv_error = e
|
||||||
|
+ failing_sock = sock
|
||||||
|
if self.sock_type(sock) == socket.SOCK_STREAM:
|
||||||
|
# Remove broken TCP socket from readers
|
||||||
|
rsocks.remove(sock)
|
||||||
|
@@ -117,6 +149,21 @@ class Application:
|
||||||
|
if reply is not None:
|
||||||
|
return reply
|
||||||
|
|
||||||
|
+ if reactivations:
|
||||||
|
+ raise SocketException("Timeout while sending packets after %.2fs "
|
||||||
|
+ "and %d tries: %s" % (
|
||||||
|
+ (timeout + extra) - starting_time,
|
||||||
|
+ sum(map(lambda r: r[0],
|
||||||
|
+ reactivations.values())),
|
||||||
|
+ send_error),
|
||||||
|
+ failing_sock)
|
||||||
|
+ elif recv_error is not None:
|
||||||
|
+ raise SocketException("Timeout while receiving packets after "
|
||||||
|
+ "%.2fs: %s" % (
|
||||||
|
+ (timeout + extra) - starting_time,
|
||||||
|
+ recv_error),
|
||||||
|
+ failing_sock)
|
||||||
|
+
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __handle_recv(self, sock, read_buffers):
|
||||||
|
@@ -214,6 +261,7 @@ class Application:
|
||||||
|
reply = None
|
||||||
|
wsocks = []
|
||||||
|
rsocks = []
|
||||||
|
+ sockfno2addr = {}
|
||||||
|
for server in map(urlparse.urlparse, servers):
|
||||||
|
# Enforce valid, supported URIs
|
||||||
|
scheme = server.scheme.lower().split("+", 1)
|
||||||
|
@@ -260,6 +308,7 @@ class Application:
|
||||||
|
continue
|
||||||
|
except io.BlockingIOError:
|
||||||
|
pass
|
||||||
|
+ sockfno2addr[sock.fileno()] = addr
|
||||||
|
wsocks.append(sock)
|
||||||
|
|
||||||
|
# Resend packets to UDP servers
|
||||||
|
@@ -270,7 +319,15 @@ class Application:
|
||||||
|
|
||||||
|
# Call select()
|
||||||
|
timeout = time.time() + (15 if addr is None else 2)
|
||||||
|
- reply = self.__await_reply(pr, rsocks, wsocks, timeout)
|
||||||
|
+ try:
|
||||||
|
+ reply = self.__await_reply(pr, rsocks, wsocks, timeout)
|
||||||
|
+ except SocketException as e:
|
||||||
|
+ fail_addr = sockfno2addr[e.sockfno]
|
||||||
|
+ fail_socktype = self.addr2socktypename(fail_addr)
|
||||||
|
+ fail_ip = fail_addr[4][0]
|
||||||
|
+ fail_port = fail_addr[4][1]
|
||||||
|
+ logging.warning("Exchange with %s:[%s]:%d failed: %s",
|
||||||
|
+ fail_socktype, fail_ip, fail_port, e)
|
||||||
|
if reply is not None:
|
||||||
|
break
|
||||||
|
|
||||||
|
--
|
||||||
|
2.46.0
|
||||||
|
|
Loading…
Reference in new issue