Skip to content

Commit 7e2b1ab

Browse files
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>
1 parent d0b35c2 commit 7e2b1ab

1 file changed

Lines changed: 31 additions & 23 deletions

File tree

kdcproxy/__init__.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -128,29 +128,37 @@ def __handle_recv(self, sock, read_buffers):
128128
# length prefix. So add it.
129129
reply = struct.pack("!I", len(reply)) + reply
130130
return reply
131-
else:
132-
# TCP is a different story. The reply must be buffered
133-
# until the full answer is accumulated.
134-
buf = read_buffers.get(sock)
135-
part = sock.recv(1048576)
136-
if buf is None:
137-
if len(part) > 4:
138-
# got enough data in the initial package. Now check
139-
# if we got the full package in the first run.
140-
(length, ) = struct.unpack("!I", part[0:4])
141-
if length + 4 == len(part):
142-
return part
143-
read_buffers[sock] = buf = io.BytesIO()
144-
145-
if part:
146-
# data received, accumulate it in a buffer
147-
buf.write(part)
148-
return None
149-
else:
150-
# EOF received
151-
read_buffers.pop(sock)
152-
reply = buf.getvalue()
153-
return reply
131+
132+
# TCP is a different story. The reply must be buffered until the full
133+
# answer is accumulated.
134+
buf = read_buffers.get(sock)
135+
if buf is None:
136+
read_buffers[sock] = buf = io.BytesIO()
137+
138+
part = sock.recv(1048576)
139+
if not part:
140+
# EOF received. Return any incomplete data we have on the theory
141+
# that a decode error is more apparent than silent failure. The
142+
# client will fail faster, at least.
143+
read_buffers.pop(sock)
144+
reply = buf.getvalue()
145+
return reply
146+
147+
# Data received, accumulate it in a buffer.
148+
buf.write(part)
149+
150+
reply = buf.getvalue()
151+
if len(reply) < 4:
152+
# We don't have the length yet.
153+
return None
154+
155+
# Got enough data to check if we have the full package.
156+
(length, ) = struct.unpack("!I", reply[0:4])
157+
if length + 4 == len(reply):
158+
read_buffers.pop(sock)
159+
return reply
160+
161+
return None
154162

155163
def __filter_addr(self, addr):
156164
if addr[0] not in (socket.AF_INET, socket.AF_INET6):

0 commit comments

Comments
 (0)