diff options
author | Vratko Polak <vrpolak@cisco.com> | 2019-10-11 16:53:08 +0200 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2020-02-18 13:29:06 +0000 |
commit | 7e8a3ece6f050240ce8836c37a718720d27da97e (patch) | |
tree | ff3060d318a6d6c791deaacfabc03c5cb46d6a1b /src | |
parent | 1c45b85dff2a0e8c60541cfa5371090fb9502e18 (diff) |
papi: harden socket handling
In the previous implementation of socket transport for PAPI,
socket methods .send and .recv_into were used.
But they are not guaranteed to send/receive all the data
for the full message. The receive part contained a loop,
but it handled only the main message, not the header.
This patch replaces .send with .sendall
and uses newly defined _read_fixed method.
Also, removed Paul from maintainers,
as he is not active much, lately.
Type: fix
Change-Id: Iae1a68bf8f9e666856b7c7d62ebfe22defc5dfe1
Signed-off-by: Vratko Polak <vrpolak@cisco.com>
(cherry picked from commit 6df2c7954126a316f86908526c3bb4d649f06597)
Diffstat (limited to 'src')
-rw-r--r-- | src/vpp-api/python/vpp_papi/vpp_transport_socket.py | 42 |
1 files changed, 24 insertions, 18 deletions
diff --git a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py index 6c06791959d..d50b9b886b6 100644 --- a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py +++ b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py @@ -188,31 +188,37 @@ class VppTransport(object): # Send header header = self.header.pack(0, len(buf), 0) - n = self.socket.send(header) - n = self.socket.send(buf) - if n == 0: - raise VppTransportSocketIOError(1, 'Not connected') + if self.socket.sendall(header) is None: + raise VppTransportSocketIOError(1, 'Failed to send') + if self.socket.sendall(buf) is None: + raise VppTransportSocketIOError(1, 'Failed to send') + + def _read_fixed(self, size): + """Repeat receive until fixed size is read. Return empty on error.""" + buf = bytearray(size) + view = memoryview(buf) + left = size + while 1: + got = self.socket.recv_into(view, left) + if got <= 0: + # Read error. + return "" + if got >= left: + # TODO: Raise if got > left? + break + left -= got + view = view[got:] + return buf def _read(self): - hdr = self.socket.recv(16) + """Read single complete message, return it or empty on error.""" + hdr = self._read_fixed(16) if not hdr: return (_, hdrlen, _) = self.header.unpack(hdr) # If at head of message # Read rest of message - msg = self.socket.recv(hdrlen) - if hdrlen > len(msg): - nbytes = len(msg) - buf = bytearray(hdrlen) - view = memoryview(buf) - view[:nbytes] = msg - view = view[nbytes:] - left = hdrlen - nbytes - while left: - nbytes = self.socket.recv_into(view, left) - view = view[nbytes:] - left -= nbytes - return buf + msg = self._read_fixed(hdrlen) if hdrlen == len(msg): return msg raise VppTransportSocketIOError(1, 'Unknown socket read error') |