Module Contents¶
Introduction¶
The sliplib
module implements the encoding and decoding
functionality for SLIP packets, as described in RFC 1055.
It defines encoding, decoding, and validation functions,
as well as various classes that can be used to to wrap
the SLIP protocol over different kinds of byte streams.
The SLIP protocol is described in RFC 1055 (A Nonstandard for Transmission of IP Datagrams over Serial Lines: SLIP, J. Romkey, June 1988). The original purpose of the protocol is to provide a mechanism to indicate the boundaries of IP packets, in particular when the IP packets are sent over a connection that does not provide a framing mechanism, such as serial lines or dial-up connections.
There is, however, nothing specific to IP in the SLIP protocol. The protocol describes a generic framing method that can be used for any type of data that must be transmitted over a (continuous) byte stream. In fact, the main reason for creating this module was the need to communicate with a third-party application that used SLIP over TCP (which is a continuous byte stream) to frame variable length data structures.
The SLIP protocol uses four special byte values:
Byte value |
Name |
Purpose |
---|---|---|
|
|
to delimit messages |
|
|
to escape |
|
|
the escaped value of the |
|
|
the escaped value of the |
An END
byte in the message is encoded as the sequence
ESC+ESC_END
(b'\xdb\xdc'
)
in the slip packet,
and an ESC
byte in the message is encoded
as the sequence ESC+ESC_ESC
(b'\xdb\xdd'
).
Decoded |
Encoded |
---|---|
|
|
|
|
As a consequence, an ESC
byte in an encoded SLIP packet
must always be followed by an ESC_END
or an ESC_ESC
byte;
anything else is a protocol error.
Low level Usage¶
Constants¶
-
END
¶
-
ESC
¶
-
ESC_END
¶
-
ESC_ESC
¶ These constants represent the special bytes used by SLIP for delimiting and encoding messages.
Functions¶
The following are lower-level functions, that should normally not be used directly.
-
encode
(msg)¶ Encodes a message (a byte sequence) into a SLIP-encoded packet.
-
decode
(packet)¶ Retrieves the message from the SLIP-encoded packet.
- Parameters
packet (bytes) – The SLIP-encoded message. Note that this must be exactly one complete packet. The
decode()
function does not provide any buffering for incomplete packages, nor does it provide support for decoding data with multiple packets.- Returns
The decoded message
- Raises
ProtocolError – if the packet contains an invalid byte sequence.
- Return type
Classes¶
-
class
Driver
¶ Class to handle the SLIP-encoding and decoding of messages
This class manages the handling of encoding and decoding of messages according to the SLIP protocol.
Class
Driver
offers the following methods:- Return type
-
send
(message)¶ Encodes a message into a SLIP-encoded packet.
The message can be any arbitrary byte sequence.
-
receive
(data)¶ Decodes data and gives a list of decoded messages.
Processes
data
, which must be a bytes-like object, and returns a (possibly empty) list withbytes
objects, each containing a decoded message. Any non-terminated SLIP packets indata
are buffered, and processed with the next call toreceive()
.- Parameters
A bytes-like object to be processed.
An empty
data
parameter forces the internal buffer to be flushed and decoded.To accommodate iteration over byte sequences, an integer in the range(0, 256) is also accepted.
- Returns
A (possibly empty) list of decoded messages.
- Raises
ProtocolError – When data contains an invalid byte sequence.
- Return type
List[bytes]
To enable recovery from a
ProtocolError
, theDriver
class offers the following attribute and method:-
messages
¶ A list of decoded messages.
The read-only attribute
messages
contains the messages that were already decoded before aProtocolError
was raised. This enables the handler of theProtocolError
exception to recover the messages up to the point where the error occurred. This attribute is cleared after it has been read.
-
flush
()¶ Gives a list of decoded messages.
Decodes the packets in the internal buffer. This enables the continuation of the processing of received packets after a
ProtocolError
has been handled.- Returns
A (possibly empty) list of decoded messages from the buffered packets.
- Raises
ProtocolError – When any of the buffered packets contains an invalid byte sequence.
- Return type
List[bytes]
High Level Usage¶
SlipWrapper¶
-
class
SlipWrapper
(stream)¶ Base class that provides a message based interface to a byte stream
SlipWrapper
combines aDriver
instance with a byte stream. TheSlipWrapper
class is an abstract base class. It offers the methodssend_msg()
andrecv_msg()
to send and receive single messages over the byte stream, but it does not of itself provide the means to interact with the stream.To interact with a concrete stream, a derived class must implement the methods
send_bytes()
andrecv_bytes()
to write to and read from the stream.A
SlipWrapper
instance can be iterated over. Each iteration will provide the next message that is received from the byte stream.Changed in version 0.5: Allow iteration over a
SlipWrapper
instance.To instantiate a
SlipWrapper
, the user must provide an existing byte stream- Parameters
stream (bytestream) – The byte stream that will be wrapped.
Class
SlipWrapper
offers the following methods and attributes:-
send_msg
(message)¶ Send a SLIP-encoded message over the stream.
-
recv_msg
()¶ Receive a single message from the stream.
- Returns
A SLIP-decoded message
- Return type
- Raises
ProtocolError – when a SLIP protocol error has been encountered. A subsequent call to
recv_msg()
(after handling the exception) will return the message from the next packet.
-
driver
¶ The
SlipWrapper
’sDriver
instance.
-
stream
¶ The wrapped stream.
In addition,
SlipWrapper
requires that derived classes implement the following methods:-
send_bytes
(packet)¶ Send a packet over the stream.
Derived classes must implement this method.
-
recv_bytes
()¶ Receive data from the stream.
Derived classes must implement this method.
Note
The convention used within the
SlipWrapper
class is thatrecv_bytes()
returns an empty bytes object to indicate that the end of the byte stream has been reached and no further data will be received. Derived implementations must ensure that this convention is followed.- Returns
The bytes received from the stream
- Return type
SlipStream¶
-
class
SlipStream
(stream[, chunk_size])¶ Bases:
sliplib.slipwrapper.SlipWrapper
Class that wraps an IO stream with a
Driver
SlipStream
combines aDriver
instance with a concrete byte stream. The byte stream must support the methodsread()
andwrite()
. To avoid conflicts and ambiguities caused by different newline conventions, streams that have anencoding
attribute (such asio.StringIO
objects, or text files that are not opened in binary mode) are not accepted as a byte stream.The
SlipStream
class has all the methods and attributes from its base classSlipWrapper
. In addition it directly exposes all methods and attributes of the containedstream
, except for the following:read*()
andwrite*()
. These methods are not supported, because byte-oriented read and write operations would invalidate the internal state maintained bySlipStream
.Similarly,
seek()
,tell()
, andtruncate()
are not supported, because repositioning or truncating the stream would invalidate the internal state.raw()
,detach()
and other methods that provide access to or manipulate the stream’s internal data.
In stead of the
read*()
andwrite*()
methods aSlipStream
object provides the methodrecv_msg()
andsend_msg()
to read and write SLIP-encoded messages.Deprecated since version 0.6: Direct access to the methods and attributes of the contained
stream
will be removed in version 1.0To instantiate a
SlipStream
object, the user must provide a pre-constructed open byte stream that is ready for reading and/or writing- Parameters
stream (bytestream) – The byte stream that will be wrapped.
chunk_size (int) – the number of bytes to read per read operation. The default value for chunck_size is io.DEFAULT_BUFFER_SIZE. Setting the chunk_size is useful when the stream has a low bandwidth and/or bursty data (e.g. a serial port interface). In such cases it is useful to have a chunk_size of 1, to avoid that the application hangs or becomes unresponsive.
New in version 0.6: The chunk_size parameter.
A
SlipStream
instance can e.g. be useful to read slip-encoded messages from a file:with open('/path/to/a/slip/encoded/file', mode='rb') as f: slip_file = SlipStream(f) for msg in slip_file: # Do something with the message
A
SlipStream
instance has the following attributes in addition to the attributes offered by its base classSlipWrapper
:-
readable
¶ Indicates if the wrapped stream is readable. The value is True if the readability of the wrapped stream cannot be determined.
-
writable
¶ Indicates if the wrapped stream is writable. The value is True if the writabilty of the wrapped stream cannot be determined.
SlipSocket¶
-
class
SlipSocket
(sock)¶ Bases:
sliplib.slipwrapper.SlipWrapper
Class that wraps a TCP
socket
with aDriver
SlipSocket
combines aDriver
instance with asocket
. TheSlipStream
class has all the methods from its base classSlipWrapper
. In addition it directly exposes all methods and attributes of the containedsocket
, except for the following:send*()
andrecv*()
. These methods are not supported, because byte-oriented send and receive operations would invalidate the internal state maintained bySlipSocket
.Similarly,
makefile()
is not supported, because byte- or line-oriented read and write operations would invalidate the internal state.share()
(Windows only) anddup()
. The internal state of theSlipSocket
would have to be duplicated and shared to make these methods meaningful. Because of the lack of a convincing use case for this, sharing and duplication is not supported.The
accept()
method is delegated to the containedsocket
, but the socket that is returned by thesocket
’saccept()
method is automatically wrapped in aSlipSocket
object.
In stead of the
socket
’ssend*()
andrecv*()
methods aSlipSocket
provides the methodsend_msg()
andrecv_msg()
to send and receive SLIP-encoded messages.Deprecated since version 0.6: Direct access to the methods and attributes of the contained
socket
other than family, type, and proto will be removed in version 1.0Only TCP sockets are supported. Using the SLIP protocol on UDP sockets is not supported for the following reasons:
UDP is datagram-based. Using SLIP with UDP therefore introduces ambiguity: should SLIP packets be allowed to span multiple UDP datagrams or not?
UDP does not guarantee delivery, and does not guarantee that datagrams are delivered in the correct order.
To instantiate a
SlipSocket
, the user must provide a pre-constructed TCP socket. An alternative way to instantiate s SlipSocket is to use the class methodcreate_connection()
.- Parameters
sock (socket.socket) – An existing TCP socket, i.e. a socket with type
socket.SOCK_STREAM
Class
SlipSocket
offers the following methods in addition to the methods offered by its base classSlipWrapper
:-
accept
()¶ Accepts an incoming connection.
- Returns
A (SlipSocket, remote_address) pair. The
SlipSocket
object can be used to exchange SLIP-encoded data with the socket at the remote_address.- Return type
Tuple[
SlipSocket
, Tuple]
See also
-
classmethod
create_connection
(address, timeout=None, source_address=None)¶ Create a SlipSocket connection.
This convenience method creates a connection to a socket at the specified address using the
socket.create_connection()
function. The socket that is returned from that call is automatically wrapped in aSlipSocket
object.- Parameters
address (Address) – The remote address.
timeout (float) – Optional timeout value.
source_address (Address) – Optional local address for the near socket.
- Returns
A SlipSocket that is connected to the socket at the remote address.
- Return type
See also
Note
The
accept()
andcreate_connection()
methods do not magically turn the socket at the remote address into a SlipSocket. For the connection to work properly, the remote socket must already have been configured to use the SLIP protocol.The following commonly used
socket.socket
methods are exposed through aSlipSocket
object. These methods are simply delegated to the wrapped socket instance.-
bind
(address)¶ Bind the SlipSocket to address.
- Parameters
address (Tuple) – The IP address to bind to.
- Return type
See also
-
close
()¶ Close the SlipSocket.
See also
- Return type
-
connect
(address)¶ Connect SlipSocket to a remote socket at address.
- Parameters
address (Tuple) – The IP address of the remote socket.
- Return type
See also
-
connect_ex
(address)¶ Connect SlipSocket to a remote socket at address.
- Parameters
address (Tuple) – The IP address of the remote socket.
- Return type
See also
-
getpeername
()¶ Get the IP address of the remote socket to which SlipSocket is connected.
- Returns
The remote IP address.
- Return type
Tuple
See also
-
getsockname
()¶ Get SlipSocket’s own address.
- Returns
The local IP address.
- Return type
Tuple
See also
-
listen
([backlog])¶ Enable a SlipSocket server to accept connections.
See also
-
shutdown
(how)¶ Shutdown the connection.
- Parameters
how (int) – Flag to indicate which halves of the connection must be shut down.
- Return type
See also
Since the wrapped socket is available as the
socket
attribute, any othersocket.socket
method can be invoked through that attribute.Warning
Avoid using
socket.socket
methods that affect the bytes that are sent or received through the socket. Doing so will invalidate the internal state of the enclosedDriver
instance, resulting in corrupted SLIP messages. In particular, do not use any of therecv*()
orsend*()
methods on thesocket
attribute.A
SlipSocket
instance has the following attributes in addition to the attributes offered by its base classSlipWrapper
:-
socket
¶ The wrapped socket. This is actually just an alias for the
stream
attribute in the base class.
-
family
¶ The wrapped socket’s address family. Usually
socket.AF_INET
(IPv4) orsocket.AF_INET6
(IPv6).
-
type
¶ The wrapped socket’s type. Always
socket.SOCK_STREAM
.
-
proto
¶ The wrapped socket’s protocol number. Usually 0.
SlipRequestHandler¶
-
class
SlipRequestHandler
(request, client_address, server)¶ Bases:
socketserver.BaseRequestHandler
Base class for request handlers for SLIP-based communication
This class is derived from
socketserver.BaseRequestHandler
for the purpose of creating TCP server instances that can handle incoming SLIP-based connections.To implement a specific behaviour, all that is needed is to derive a class that defines a
handle()
method that usesself.request
to send and receive SLIP-encoded messages.The interface is identical to that offered by the
socketserver.BaseRequestHandler
baseclass. To do anything useful, a derived class must define a newhandle()
method, and may override any of the other methods.-
setup
()¶ Initializes the request handler.
The original socket (available via
self.request
) is wrapped in aSlipSocket
object. Derived classes may override this method, but should callsuper().setup()
before accessing anySlipSocket
methods or attributes onself.request
.- Return type
-
handle
()¶ Services the request. Must be defined by a derived class.
Note that in general it does not make sense to use a
SlipRequestHandler
object to handle a single transmission, as is e.g. common with HTTP. The purpose of the SLIP protocol is to allow separation of messages in a continuous byte stream. As such, it is expected that thehandle()
method of a derived class is capable of handling multiple SLIP messages:def handle(self): while True: msg = self.request.recv_msg() if msg == b'': break # Do something with the message
- Return type
-
Exceptions¶
-
exception
ProtocolError
¶ Exception to indicate that a SLIP protocol error has occurred.
This exception is raised when an attempt is made to decode a packet with an invalid byte sequence. An invalid byte sequence is either an
ESC
byte followed by any byte that is not anESC_ESC
orESC_END
byte, or a trailingESC
byte as last byte of the packet.The
ProtocolError
carries the invalid packet as the first (and only) element in in itsargs
tuple.