The Session Control Protocol (SCP) is a simple protocol running on top of TCP than can be used to create multiple lightweight connections over a single transport connection. Data from several different channels can be interleaved, and both message boundaries and end of stream markers can be provided.
Because SCP runs on top of a reliable ordered transport service it can avoid most of the extra work TCP must go through in order to ensure reliability. For example, SCP sessions do not need to be confirmed, so there is no need to wait for handshaking to complete.
One a session has been opened, the application can send messages over it, and signal the end of these application level messages. These messages are encapsulated in SCP packets and transferred over the byte stream. Messages can be split up into several different packets.
The uncompressed form of an SCP packet consists of a 64 bit header followed by zero or more octets of data. If the COMPRESSION flag in the first byte is set, the header should be interpreted as described in the section on compression.
The header contains three fields; a flag byte, the session identifier, and the packet length.
FLAGS +--------+--------+--------+--------+ +SFRP0000| Session ID | +--------+--------+--------+--------+ | LENGTH | +--------+--------+--------+--------+
Name | Mask | Description |
---|---|---|
Compressed Header | XXXX|XXX1 | Mark a Compressed Header |
SYN | 1XXX|0000 | Open A New Connection |
FIN | X1XX|0000 | Close An Existing Connection |
PUSH | XX1X|0000 | Mark an application level message boundary |
RESET | XXX1|0000 | Abort the Connection |
The RESET flag may not be sent in conjunction with any other flags.
1 | Presentation Control Protocol (PCP) |
2 | Multiplexed Data Algorithm (MDA) |
XXXX - Define PCP - select higher-level protocol to talk to. Is this necessary? Why in http MUX Define MDA - Wrapped SCP packets with options. Is this necessary? It's all optional anyway.
The following table describes the actions and state transitions that occur in response to a given event. The events are given in order of priority - if multiple flags are present, then the first matched action should be followed, and any remaining flags processed in the resultant successor state.
For example, if a session is in the CLOSED state, and it receives a packet containing a SYN, a FIN, and data, the implementation should check the table for Closed, and look for the first even that matches. In this case, the first match is for SYN; the implementation should Accept the Session, remove the SYN from the set of pending events, and move to Open-Receive.
State | Event | Action | New State |
---|---|---|---|
Closed
| RESET | Discard | Closed |
SYN (1) | Accept Session | Open-Receive | |
FIN | Discard | Closed | |
Other | Discard | Closed | |
Open-Receive
| FIN | Close Session, Discard | Closed |
RESET | Abort Session, Discard | Closed | |
SYN | Send RESET, Abort Session | Closed
| |
CLOSE | Send RESET, Close Session | Closed | |
ABORT | Send RESET, Close Session | Closed | |
DATA-IN | Read Data | Open-Receive | |
OPEN | Send SYN, Open for Writing | Open-ReadWrite | |
Open-ReadWrite | SYN | Send Reset, Close Connection | Closed |
DATA-IN | Read Data | Open-ReadWrite | |
DATA-OUT | Write Data | Open-ReadWrite | |
Shutdown | Send FIN, Close for Writing | Open-Receive | |
FIN | Close for Reading | Open-Write | |
RESET | Abort Connection | Closed | |
CLOSE | Send FIN + RESET, Close Connection | Closed | |
Open-Write | RESET | Abort Connection | Closed |
SYN | Open for Reading | Open-ReadWrite | |
Data-In | Send RESET, Abort Connection | Closed | |
Data-Out | Write Data | Open-Write | |
FIN | Send RESET, Abort Connection | Open-Write | |
CLOSE | Send FIN, Close Connection | Closed | |
Abort | Send Reset, Close Connection | Closed |
If the SCP is used to send small messages over low bandwidth links, the costs of the eight byte header may become noticeable, outweighing the savings gained from having a fixed format header.
Observed SCP traffic typically follows a predictable pattern; this predictability can be used to implement a system of header compression similar to that developed for TCP by Van Jacobsen.
The first Observation is that there are normally only a small number of session simultaneously active, and these active sessions are strongly localised in time. A small cache of recently used session Ids can be used instead of full session ids with good success.
The second observation is that message lengths are often the same for packets on a given channel, and where packets sizes do vary, they are typically small. The same cache used for session Ids can be used to store the length of the most recent message sent on a given channel. An abbreviated length field with an escape value for the previous length can be used to encode lengths for typical messages. Longer messages may need larger length fields; however the size of headers is not significant with longer messages.
Each end of an SCP connection that supports compression maintains two LRU caches, one for sending and one for receiving. Each cache contains six entries; each entry contains a session identifier and a packet length. In addition to the caches, the protocol manager also keeps a record of the last session identifier used in each direction.
Each cache is initialised to contain the following values:
Entry | SessionID | Length |
---|---|---|
0 | 0 | 0 |
1 | 1 | 7 |
2 | 1,024 | 128 |
3 | 1,025 | 128 |
4 | 1,026 | 128 |
5 | 1,027 | 128 |
The first use of one of these predefined sessions shall be considered to have an implicit SYN.
The cache for a particular direction is not be updated until the first packet with a compressed header is sent or received.
This octet is sometimes followed by a one byte extended session id , an extended length, or both.
+-+---+---+-+ |P|Len|Ses|1| +-+---+---+-+
let p = the last allocated identifier, n = the next session identifier n = p + 2; if (n >= 2^24) { n = n % 2^24 + 1024; }
The extended formats must not be used if the value could be represented using the compact format.
+--------+ | Delta | +--------+This is a single octet containing an 8-bit signed two's complement integer. This integer is added to the most recently used session identifier (which is stored in cache entry zero), and the result is used as the SessionId.
+--------+ |Length | +--------+
This is a single octet containing a length from 0-255.
To help make the compressed format a little clearer, here are a few simple examples.
To start with, the clients sending side cache is intialised to the default values.
Entry | SessionID | Length |
---|---|---|
0 | 0 | 0 |
1 | 1 | 7 |
2 | 1,024 | 128 |
3 | 1,025 | 128 |
4 | 1,026 | 128 |
5 | 1,027 | 128 |
The first packet is a 4 byte message on session 1024. The corresponding compressed header is
+-+---+---+-+ |0| 4 | 2 |1| +-+---+---+-+ P Len Ses 1
If we were using the uncompressed format, the corresponding header would be:
+---------+------------------------+ | 10000000| 1024 | Flags (SYN),8 bits, Session(1024), 24 bits +----------------------------------+ | 4 | Length (4), 32 bits +----------------------------------+
After sending this packet, the clients cache looks like this:
Entry | SessionID | Length |
---|---|---|
0 | 1,024 | 4 |
1 | 0 | 0 |
2 | 1 | 7 |
3 | 1,025 | 128 |
4 | 1,026 | 128 |
5 | 1,027 | 128 |
The next message is a 10 byte packet, also for session 1024.
+-+---+---+-+ +--------+ |0| 6 | 0 |1| | 10 | +-+---+---+-+ +--------+ P Len Ses 1 length
If we were using the uncompressed format, the corresponding header would be:
+---------+------------------------+ | 00000000| 1024 | Flags (none),8 bits, Session(1024), 24 bits +----------------------------------+ | 10 | Length (10), 32 bits +----------------------------------+
After sending this packet, the clients cache looks like this:
Entry | SessionID | Length |
---|---|---|
0 | 1,024 | 10 |
1 | 0 | 0 |
2 | 1 | 7 |
3 | 1,025 | 128 |
4 | 1,026 | 128 |
5 | 1,027 | 128 |
After this, we want to open a new channel and send a 4 byte message. The next session id is 1028, which is unallocated- thus we can use the next session id feature of the compressed header.
+-+---+---+-+ |0| 4 | 7 |1| +-+---+---+-+ P Len Ses 1
If we were using the uncompressed format, the corresponding header would be:
+---------+------------------------+ | 10000000| 1028 | Flags (SYN),8 bits, Session(1028), 24 bits +----------------------------------+ | 4 | Length (4), 32 bits +----------------------------------+
After sending this packet, the clients cache looks like this:
Entry | SessionID | Length |
---|---|---|
0 | 1,028 | 4 |
1 | 1,024 | 10 |
2 | 0 | 0 |
3 | 1 | 7 |
4 | 1,025 | 128 |
5 | 1,026 | 128 |