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'xdbxdc'
)
in the slip packet,
and an ESC
byte in the message is encoded
as the sequence ESC+ESC_ESC
(b'xdbxdd'
).
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
The following constants represent the special bytes used by SLIP for delimiting and encoding messages.
- END = b'\xc0'
The SLIP END byte.
- ESC = b'\xdb'
The SLIP ESC byte.
- ESC_END = b'\xdc'
The SLIP byte that, when preceded by an ESC byte, represents an escaped END byte.
- ESC_ESC = b'\xdd'
The SLIP byte that, when preceded by an ESC byte, represents an escaped ESC byte.
Functions
The following are lower-level functions, that should normally not be used directly.
- decode(packet)[source]
Retrieves the message from the SLIP-encoded packet.
- Parameters:
packet (
bytes
) – The SLIP-encoded message. Note that this must be exactly one complete packet. Thedecode()
function does not provide any buffering for incomplete packages, nor does it provide support for decoding data with multiple packets.- Return type:
- Returns:
The decoded message
- Raises:
ProtocolError – if the packet contains an invalid byte sequence.
Classes
- class Driver[source]
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:- send(message)[source]
Encodes a message into a SLIP-encoded packet.
The message can be any arbitrary byte sequence.
- get(*, block=True, timeout=None)[source]
Get the next decoded message.
Remove and decode a SLIP packet from the internal buffer, and return the resulting message. If block is True and timeout is None`(the default), then this method blocks until a message is available. If `timeout is a positive number, the blocking will last for at most timeout seconds, and the method will return None if no message became available in that time. If block is False the method returns immediately with either a message or None.
- Return type:
Optional
[bytes
]- Returns:
A decoded SLIP message, or an empty bytestring b”” if no further message will come available.
- Raises:
ProtocolError – When the packet that contained the message had an invalid byte sequence.
- Parameters:
New in version 0.7.
- receive(data)[source]
Decodes data to extract the SLIP-encoded messages.
Processes
data
, which must be a bytes-like object, and extracts and buffers the SLIP messages contained therein.A non-terminated SLIP packet in
data
is also buffered, and processed with the next call toreceive()
.- Parameters:
A bytes-like object to be processed.
An empty
data
parameter indicates that no more data will follow.To accommodate iteration over byte sequences, an integer in the range(0, 256) is also accepted.
- Return type:
- Returns:
None.
Changed in version 0.7: receive() no longer returns a list of decoded messages.
High Level Usage
SlipWrapper
- ByteStream = TypeVar(ByteStream)
Invariant
TypeVar
.ByteStream is a
TypeVar
that stands for a generic byte stream.
- class SlipWrapper(stream)[source]
Bases:
Generic
[ByteStream
]Base class that provides a message based interface to a byte stream
SlipWrapper
combines aDriver
instance with a (generic) 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:- recv_msg()[source]
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
ByteStream
.
In addition,
SlipWrapper
requires that derived classes implement the following methods:- recv_bytes()[source]
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.- Return type:
- Returns:
The bytes received from the stream
SlipStream
- protocol IOStream[source]
Bases:
Protocol
Protocol class for wrappable byte streams.
Any object that produces and consumes a byte stream and contains the two required methods can be used. Typically, an IOStream is a subclass of
io.RawIOBase
,io.BufferedIOBase
,io.FileIO
, or similar classes, but this is not required.Classes that implement this protocol must have the following methods / attributes:
- class SlipStream(stream, chunk_size=8192)[source]
Bases:
SlipWrapper
[IOStream
]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.
Instead 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 (
IOStream
) – 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
:- chunk_size
The number of bytes to read during each read operation.
SlipSocket
- TCPAddress(*args, **kwargs)
TCPAddress stands for either an IPv4 address, i.e. a (host, port) tuple, or an IPv6 address, i.e. a (host, port, flowinfo, scope_id) tuple.
- class SlipSocket(sock)[source]
Bases:
SlipWrapper
[socket
]Class that wraps a TCP
socket
with aDriver
SlipSocket
combines aDriver
instance with asocket
. TheSlipSocket
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.
Instead 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()[source]
Accepts an incoming connection.
- Returns:
A tuple with a
SlipSocket
object and the remote IP address.- Return type:
- classmethod create_connection(address, timeout=None, source_address=None)[source]
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 (
TCPAddress
) – The remote address.timeout (float) – Optional timeout value.
source_address (
TCPAddress
) – 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. See the documentation forsocket.socket
for more information on these methods.- bind(address)[source]
Bind the SlipSocket to address.
- Parameters:
address (
TCPAddress
) – The address to bind to.- Return type:
- connect(address)[source]
Connect SlipSocket to a remote socket at address.
- Parameters:
address (
TCPAddress
) – The IP address of the remote socket.- Return type:
- connect_ex(address)[source]
Connect SlipSocket to a remote socket at address.
- Parameters:
address (
TCPAddress
) – The IP address of the remote socket.- Return type:
- fileno()[source]
Get the socket’s file descriptor.
- Return type:
- Returns:
The wrapped socket’s file descriptor, or -1 on failure.
- getpeername()[source]
Get the IP address of the remote socket to which SlipSocket is connected.
- Returns:
The remote IP address.
- Return type:
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 and read-only properties 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.
SlipRequestHandler
- class SlipRequestHandler(request, client_address, server)[source]
Bases:
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 do anything useful, a derived class must define a new
handle()
method that usesself.request
to send and receive SLIP-encoded messages.Other methods can of course also be overridden if necessary.
Initializes the request handler.
The type of the
request
parameter depends on the type of server that instantiates the request handler. If the server is a SlipServer, thenrequest
is a SlipSocket. Otherwise, it is a regular socket, and must be wrapped in a SlipSocket before it can be used.- Parameters:
- handle()[source]
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, for example:def handle(self): while True: msg = self.request.recv_msg() if msg == b"": break # Do something with the message
- Return type:
- class SlipServer(server_address, handler_class, bind_and_activate=True)[source]
Bases:
TCPServer
Base class for SlipSocket based server classes.
This is a convenience class, that offers a minor enhancement over the regular
TCPServer
from the standard library. The classTCPServer
is hardcoded to use only IPv4 addresses. It must be subclassed in order to use IPv6 addresses. TheSlipServer
class uses the address that is provided during instantiation to determine if it must muse an IPv4 or IPv6 socket.- Parameters:
server_address (
Union
[Tuple
[str
,int
],Tuple
[str
,int
,int
,int
]]) – The address on which the server listenshandler_class (
type
[SlipRequestHandler
]) – The class that will be instantiated to handle an incoming requestbind_and_activate (
bool
) – Flag to indicate if the server must be bound and activated at creation time.
Exceptions
- exception ProtocolError[source]
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.