mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 14:35:29 +00:00
[1829] make sure Session.send() transmits all data even after partial write.
This commit is contained in:
@@ -72,7 +72,7 @@ class Session:
|
|||||||
self._lname = None
|
self._lname = None
|
||||||
self._closed = True
|
self._closed = True
|
||||||
|
|
||||||
def sendmsg(self, env, msg = None):
|
def sendmsg(self, env, msg=None):
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if self._closed:
|
if self._closed:
|
||||||
raise SessionError("Session has been closed.")
|
raise SessionError("Session has been closed.")
|
||||||
@@ -82,15 +82,24 @@ class Session:
|
|||||||
raise ProtocolError("Envelope too large")
|
raise ProtocolError("Envelope too large")
|
||||||
if type(msg) == dict:
|
if type(msg) == dict:
|
||||||
msg = isc.cc.message.to_wire(msg)
|
msg = isc.cc.message.to_wire(msg)
|
||||||
self._socket.setblocking(1)
|
|
||||||
length = 2 + len(env);
|
length = 2 + len(env);
|
||||||
if msg:
|
if msg is not None:
|
||||||
length += len(msg)
|
length += len(msg)
|
||||||
self._socket.send(struct.pack("!I", length))
|
|
||||||
self._socket.send(struct.pack("!H", len(env)))
|
# Build entire message.
|
||||||
self._socket.send(env)
|
data = struct.pack("!I", length)
|
||||||
if msg:
|
data += struct.pack("!H", len(env))
|
||||||
self._socket.send(msg)
|
data += env
|
||||||
|
if msg is not None:
|
||||||
|
data += msg
|
||||||
|
|
||||||
|
# Send it in the blocking mode. On some systems send() may
|
||||||
|
# actually send only part of the data, so we need to repeat it
|
||||||
|
# until all data have been sent out.
|
||||||
|
self._socket.setblocking(1)
|
||||||
|
while len(data) > 0:
|
||||||
|
cc = self._socket.send(data)
|
||||||
|
data = data[cc:]
|
||||||
|
|
||||||
def recvmsg(self, nonblock = True, seq = None):
|
def recvmsg(self, nonblock = True, seq = None):
|
||||||
"""Reads a message. If nonblock is true, and there is no
|
"""Reads a message. If nonblock is true, and there is no
|
||||||
|
@@ -29,6 +29,7 @@ class MySocket():
|
|||||||
self.recvqueue = bytearray()
|
self.recvqueue = bytearray()
|
||||||
self.sendqueue = bytearray()
|
self.sendqueue = bytearray()
|
||||||
self._blocking = True
|
self._blocking = True
|
||||||
|
self.send_limit = None
|
||||||
|
|
||||||
def connect(self, to):
|
def connect(self, to):
|
||||||
pass
|
pass
|
||||||
@@ -40,7 +41,14 @@ class MySocket():
|
|||||||
self._blocking = val
|
self._blocking = val
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
self.sendqueue.extend(data);
|
# If the upper limit is specified, only "send" up to the specified
|
||||||
|
# limit
|
||||||
|
if self.send_limit is not None and len(data) > self.send_limit:
|
||||||
|
self.sendqueue.extend(data[0:self.send_limit])
|
||||||
|
return self.send_limit
|
||||||
|
else:
|
||||||
|
self.sendqueue.extend(data)
|
||||||
|
return len(data)
|
||||||
|
|
||||||
def readsent(self, length):
|
def readsent(self, length):
|
||||||
if length > len(self.sendqueue):
|
if length > len(self.sendqueue):
|
||||||
@@ -101,6 +109,17 @@ class MySocket():
|
|||||||
def gettimeout(self):
|
def gettimeout(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def set_send_limit(self, limit):
|
||||||
|
'''Specify the upper limit of the transmittable data at once.
|
||||||
|
|
||||||
|
By default, the send() method of this class "sends" all given data.
|
||||||
|
If this method is called and the its parameter is not None,
|
||||||
|
subsequent calls to send() will only transmit the specified amount
|
||||||
|
of data. This can be used to emulate the situation where send()
|
||||||
|
on a real socket object results in partial write.
|
||||||
|
'''
|
||||||
|
self.send_limit = limit
|
||||||
|
|
||||||
#
|
#
|
||||||
# We subclass the Session class we're testing here, only
|
# We subclass the Session class we're testing here, only
|
||||||
# to override the __init__() method, which wants a socket,
|
# to override the __init__() method, which wants a socket,
|
||||||
@@ -157,6 +176,16 @@ class testSession(unittest.TestCase):
|
|||||||
#print(sent)
|
#print(sent)
|
||||||
#self.assertRaises(SessionError, sess.sendmsg, {}, {"hello": "a"})
|
#self.assertRaises(SessionError, sess.sendmsg, {}, {"hello": "a"})
|
||||||
|
|
||||||
|
def test_session_sendmsg_shortwrite(self):
|
||||||
|
sess = MySession()
|
||||||
|
# Specify the upper limit of the size that can be transmitted at
|
||||||
|
# a single send() call on the faked socket (10 is an arbitrary choice,
|
||||||
|
# just reasonably small).
|
||||||
|
sess._socket.set_send_limit(10)
|
||||||
|
sess.sendmsg({'to': 'someone', 'reply': 1}, {"hello": "a"})
|
||||||
|
# The complete message should still have been transmitted in the end.
|
||||||
|
sent = sess._socket.readsentmsg();
|
||||||
|
|
||||||
def recv_and_compare(self, session, bytes, env, msg):
|
def recv_and_compare(self, session, bytes, env, msg):
|
||||||
"""Adds bytes to the recvqueue (which will be read by the
|
"""Adds bytes to the recvqueue (which will be read by the
|
||||||
session object, and compare the resultinv env and msg to
|
session object, and compare the resultinv env and msg to
|
||||||
|
Reference in New Issue
Block a user