|
|
68b28b |
From c1be487bb00f2e813212031d93fcebbfbd0da60b Mon Sep 17 00:00:00 2001
|
|
|
68b28b |
From: Robbie Harwood <rharwood@redhat.com>
|
|
|
68b28b |
Date: Thu, 29 Aug 2019 11:13:41 -0400
|
|
|
68b28b |
Subject: [PATCH] Always buffer TCP data in __handle_recv()
|
|
|
68b28b |
|
|
|
68b28b |
Refactor __handle_recv() to always create a BytesIO() object for TCP
|
|
|
68b28b |
data. Linearize control flow for ease of debugging. Always apply
|
|
|
68b28b |
length checks so that we don't have to wait for EOF in the multiple-recv
|
|
|
68b28b |
case.
|
|
|
68b28b |
|
|
|
68b28b |
Fixes a bug where we wouldn't return any data because we never received
|
|
|
68b28b |
the EOF, or didn't receive it fast enough.
|
|
|
68b28b |
|
|
|
68b28b |
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
|
|
|
68b28b |
(cherry picked from commit 7e2b1ab27b843c220fe301b74bab01ed61b0f59a)
|
|
|
68b28b |
---
|
|
|
68b28b |
kdcproxy/__init__.py | 54 +++++++++++++++++++++++++-------------------
|
|
|
68b28b |
1 file changed, 31 insertions(+), 23 deletions(-)
|
|
|
68b28b |
|
|
|
68b28b |
diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py
|
|
|
68b28b |
index 6526bc9..9bc7044 100644
|
|
|
68b28b |
--- a/kdcproxy/__init__.py
|
|
|
68b28b |
+++ b/kdcproxy/__init__.py
|
|
|
68b28b |
@@ -128,29 +128,37 @@ class Application:
|
|
|
68b28b |
# length prefix. So add it.
|
|
|
68b28b |
reply = struct.pack("!I", len(reply)) + reply
|
|
|
68b28b |
return reply
|
|
|
68b28b |
- else:
|
|
|
68b28b |
- # TCP is a different story. The reply must be buffered
|
|
|
68b28b |
- # until the full answer is accumulated.
|
|
|
68b28b |
- buf = read_buffers.get(sock)
|
|
|
68b28b |
- part = sock.recv(1048576)
|
|
|
68b28b |
- if buf is None:
|
|
|
68b28b |
- if len(part) > 4:
|
|
|
68b28b |
- # got enough data in the initial package. Now check
|
|
|
68b28b |
- # if we got the full package in the first run.
|
|
|
68b28b |
- (length, ) = struct.unpack("!I", part[0:4])
|
|
|
68b28b |
- if length + 4 == len(part):
|
|
|
68b28b |
- return part
|
|
|
68b28b |
- read_buffers[sock] = buf = io.BytesIO()
|
|
|
68b28b |
-
|
|
|
68b28b |
- if part:
|
|
|
68b28b |
- # data received, accumulate it in a buffer
|
|
|
68b28b |
- buf.write(part)
|
|
|
68b28b |
- return None
|
|
|
68b28b |
- else:
|
|
|
68b28b |
- # EOF received
|
|
|
68b28b |
- read_buffers.pop(sock)
|
|
|
68b28b |
- reply = buf.getvalue()
|
|
|
68b28b |
- return reply
|
|
|
68b28b |
+
|
|
|
68b28b |
+ # TCP is a different story. The reply must be buffered until the full
|
|
|
68b28b |
+ # answer is accumulated.
|
|
|
68b28b |
+ buf = read_buffers.get(sock)
|
|
|
68b28b |
+ if buf is None:
|
|
|
68b28b |
+ read_buffers[sock] = buf = io.BytesIO()
|
|
|
68b28b |
+
|
|
|
68b28b |
+ part = sock.recv(1048576)
|
|
|
68b28b |
+ if not part:
|
|
|
68b28b |
+ # EOF received. Return any incomplete data we have on the theory
|
|
|
68b28b |
+ # that a decode error is more apparent than silent failure. The
|
|
|
68b28b |
+ # client will fail faster, at least.
|
|
|
68b28b |
+ read_buffers.pop(sock)
|
|
|
68b28b |
+ reply = buf.getvalue()
|
|
|
68b28b |
+ return reply
|
|
|
68b28b |
+
|
|
|
68b28b |
+ # Data received, accumulate it in a buffer.
|
|
|
68b28b |
+ buf.write(part)
|
|
|
68b28b |
+
|
|
|
68b28b |
+ reply = buf.getvalue()
|
|
|
68b28b |
+ if len(reply) < 4:
|
|
|
68b28b |
+ # We don't have the length yet.
|
|
|
68b28b |
+ return None
|
|
|
68b28b |
+
|
|
|
68b28b |
+ # Got enough data to check if we have the full package.
|
|
|
68b28b |
+ (length, ) = struct.unpack("!I", reply[0:4])
|
|
|
68b28b |
+ if length + 4 == len(reply):
|
|
|
68b28b |
+ read_buffers.pop(sock)
|
|
|
68b28b |
+ return reply
|
|
|
68b28b |
+
|
|
|
68b28b |
+ return None
|
|
|
68b28b |
|
|
|
68b28b |
def __filter_addr(self, addr):
|
|
|
68b28b |
if addr[0] not in (socket.AF_INET, socket.AF_INET6):
|