from .exception import DeserializationException
+RECV_TIMEOUT_DEFAULT = object()
+
+
class Transport(object):
HEADER_LENGTH = 4
MAX_SEGMENT = 512 * 1024
def send(self, packet):
self.socket.sendall(struct.pack("!I", len(packet)) + packet)
- def receive(self, timeout=None):
+ def receive(self, timeout=RECV_TIMEOUT_DEFAULT):
raw_length = self._recvall(self.HEADER_LENGTH, timeout)
length, = struct.unpack("!I", raw_length)
payload = self._recvall(length)
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
- def _recvall(self, count, timeout=None):
+ def _recvall(self, count, timeout=RECV_TIMEOUT_DEFAULT):
"""Ensure to read count bytes from the socket"""
data = b""
- if count > 0:
+ old_timeout = self.socket.gettimeout()
+ if timeout is not RECV_TIMEOUT_DEFAULT:
self.socket.settimeout(timeout)
- while len(data) < count:
- buf = self.socket.recv(count - len(data))
- self.socket.settimeout(None)
- if not buf:
- raise socket.error('Connection closed')
- data += buf
+ try:
+ while len(data) < count:
+ buf = self.socket.recv(count - len(data))
+ self.socket.settimeout(None)
+ if not buf:
+ raise socket.error('Connection closed')
+ data += buf
+ finally:
+ self.socket.settimeout(old_timeout)
return data
import socket
from .exception import SessionException, CommandException, EventUnknownException
-from .protocol import Transport, Packet, Message
+from .protocol import Transport, Packet, Message, RECV_TIMEOUT_DEFAULT
from .command_wrappers import CommandWrappers
class Session(CommandWrappers, object):
def __init__(self, sock=None):
+ """Establish a session with an IKE daemon.
+
+ By default, the session will connect to the `/var/run/charon.vici` Unix
+ domain socket.
+
+ If there is a need to connect a socket in another location or set
+ specific settings on the socket (like a timeout), create and connect
+ a socket and pass it to the `sock` parameter.
+
+ .. note::
+
+ In case a timeout is set on the socket, the internal read code
+ will temporarily disable it after receiving the first byte to avoid
+ partial read corruptions.
+
+ :param sock: socket connected to the IKE daemon (optional)
+ :type sock: socket.socket
+ """
if sock is None:
sock = socket.socket(socket.AF_UNIX)
sock.connect("/var/run/charon.vici")
)
)
- def listen(self, event_types, timeout=None):
+ def listen(self, event_types, timeout=RECV_TIMEOUT_DEFAULT):
"""Register and listen for the given events.
If a timeout is given, the generator produces a (None, None) tuple