Commit d6585dce authored by Jelte Jansen's avatar Jelte Jansen

update


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac312@2916 e5f2f494-b856-4b98-b285-d166d9295462
parent a951cdc5
...@@ -39,6 +39,8 @@ class Session: ...@@ -39,6 +39,8 @@ class Session:
self._queue = [] self._queue = []
self._lock = threading.RLock() self._lock = threading.RLock()
self.set_timeout(self.MSGQ_DEFAULT_TIMEOUT); self.set_timeout(self.MSGQ_DEFAULT_TIMEOUT);
self._recv_len_size = 0
self._recv_size = 0
if socket_file is None: if socket_file is None:
if "BIND10_MSGQ_SOCKET_FILE" in os.environ: if "BIND10_MSGQ_SOCKET_FILE" in os.environ:
...@@ -120,26 +122,42 @@ class Session: ...@@ -120,26 +122,42 @@ class Session:
return isc.cc.message.from_wire(data[2:header_length+2]), None return isc.cc.message.from_wire(data[2:header_length+2]), None
return None, None return None, None
def _receive_bytes(self, length, nonblock): def _receive_bytes(self, size):
"""Returns a bytearray of length bytes as read from the socket. """Try to get size bytes of data from the socket.
Raises a ProtocolError if it reads 0 bytes, unless nonblock Raises a ProtocolError if the size is 0.
is True. Raises any error from recv().
Re-raises errors raised by recv(). Returns whatever data was available (if >0 bytes).
Returns either a bytearray of length bytes, or None (if """
nonblock is True, and less than length bytes of data is data = self._socket.recv(size)
available) if len(data) == 0: # server closed connection
""" raise ProtocolError("Read of 0 bytes: connection closed")
data = bytearray()
while length > 0:
new_data = self._socket.recv(length)
if len(new_data) == 0: # server closed connection
if nonblock:
return None
else:
raise ProtocolError("Read of 0 bytes: connection closed")
data += new_data
length -= len(new_data)
return data return data
def _receive_len_data(self):
"""Reads self._recv_len_size bytes of data from the socket into
self._recv_len_data
This is done through class variables so in the case of
an EAGAIN we can continue on a subsequent call.
Raises a ProtocolError, a socket.error (which may be
timeout or eagain), or reads until we have all data we need.
"""
while self._recv_len_size > 0:
new_data = self._receive_bytes(self._recv_len_size)
self._recv_len_data += new_data
self._recv_len_size -= len(new_data)
def _receive_data(self):
"""Reads self._recv_size bytes of data from the socket into
self._recv_data.
This is done through class variables so in the case of
an EAGAIN we can continue on a subsequent call.
Raises a ProtocolError, a socket.error (which may be
timeout or eagain), or reads until we have all data we need.
"""
while self._recv_size > 0:
new_data = self._receive_bytes(self._recv_size)
self._recv_data += new_data
self._recv_size -= len(new_data)
def _receive_full_buffer(self, nonblock): def _receive_full_buffer(self, nonblock):
if nonblock: if nonblock:
...@@ -152,16 +170,40 @@ class Session: ...@@ -152,16 +170,40 @@ class Session:
self._socket.settimeout(self._socket_timeout) self._socket.settimeout(self._socket_timeout)
try: try:
data = self._receive_bytes(4, nonblock) # we might be in a call following an EAGAIN, in which case
if data is not None: # we simply continue. In the first case, either
data_length = struct.unpack('>I', data)[0] # recv_size or recv_len size are not zero
data = self._receive_bytes(data_length, nonblock) if self._recv_size == 0:
if self._recv_len_size == 0:
# both zero, start a new full read
self._recv_len_size = 4
self._recv_len_data = bytearray()
self._receive_len_data()
self._recv_size = struct.unpack('>I', self._recv_len_data)[0]
self._recv_data = bytearray()
self._receive_data()
# no EAGAIN, so copy data and reset internal counters
data = self._recv_data
self._recv_len_size = 0
self._recv_size = 0
return (data) return (data)
except socket.timeout: except socket.timeout:
raise SessionTimeout("recv() on cc session timed out") raise SessionTimeout("recv() on cc session timed out")
except socket.error as se: except socket.error as se:
if se.errno == errno.EINTR or \ # Only keep data in case of EAGAIN
(nonblock and se.errno) == errno.EAGAIN: if se.errno == errno.EAGAIN:
return None
# unknown state otherwise, best to drop data
self._recv_len_size = 0
self._recv_size = 0
# ctrl-c can result in EINTR, return None to prevent
# stacktrace output
if se.errno == errno.EINTR:
return None return None
raise se raise se
......
...@@ -28,6 +28,7 @@ class MySocket(): ...@@ -28,6 +28,7 @@ class MySocket():
self.type = type self.type = type
self.recvqueue = bytearray() self.recvqueue = bytearray()
self.sendqueue = bytearray() self.sendqueue = bytearray()
self._blocking = True
def connect(self, to): def connect(self, to):
pass pass
...@@ -36,7 +37,7 @@ class MySocket(): ...@@ -36,7 +37,7 @@ class MySocket():
pass pass
def setblocking(self, val): def setblocking(self, val):
pass self._blocking = val
def send(self, data): def send(self, data):
self.sendqueue.extend(data); self.sendqueue.extend(data);
...@@ -68,7 +69,10 @@ class MySocket(): ...@@ -68,7 +69,10 @@ class MySocket():
def recv(self, length): def recv(self, length):
if len(self.recvqueue) == 0: if len(self.recvqueue) == 0:
return bytes() if self._blocking:
return bytes()
else:
raise socket.error(errno.EAGAIN, "Resource temporarily unavailable")
if length > len(self.recvqueue): if length > len(self.recvqueue):
raise Exception("Buffer underrun in test, does the test provide the right data?") raise Exception("Buffer underrun in test, does the test provide the right data?")
result = self.recvqueue[:length] result = self.recvqueue[:length]
...@@ -107,7 +111,8 @@ class MySession(Session): ...@@ -107,7 +111,8 @@ class MySession(Session):
self._socket_timeout = 1 self._socket_timeout = 1
self._lname = None self._lname = None
self._recvbuffer = bytearray() self._recvbuffer = bytearray()
self._recvlength = 0 self._recv_len_size = 0
self._recv_size = 0
self._sequence = 1 self._sequence = 1
self._closed = False self._closed = False
self._queue = [] self._queue = []
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment