Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit d8ed79b

Browse files
author
Solomon Hykes
committed
Merge pull request #32 from shykes/pr_out_first_draft_of_the_final_libchan_protocol
2 parents 48e1d34 + 2f5b8b4 commit d8ed79b

1 file changed

Lines changed: 187 additions & 0 deletions

File tree

PROTOCOL.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# libchan protocol specification
2+
3+
Extreme portability is a key design goal of libchan.
4+
5+
This document specifies the libchan protocol to allow multiple implementations to co-exist with
6+
full interoperability.
7+
8+
## Version
9+
10+
No version yet.
11+
12+
## Author
13+
14+
Solomon Hykes <solomon@docker.com>
15+
16+
## Status
17+
18+
This specification is still work in progress. Things will change, probably in reverse-incompatible ways.
19+
We hope to reach full API stability soon.
20+
21+
## Terminology
22+
23+
### Channel
24+
25+
A `channel` is an object which allows 2 concurrent programs to communicate with each other. The semantics
26+
of a libchan channel are very similar (but not identical) to those of Go's native channels.
27+
28+
A channel has 2 ends: a `Sender` end and a `Receiver` end. The Sender can send messages and close the channel.
29+
The Receiver can receive messages. Messages arrive in the same order they were sent.
30+
31+
A channel is uni-directional: messages can only flow in one direction. So channels are more similar to pipes
32+
than to sockets.
33+
34+
### Session
35+
36+
A session is a reliable 2-way byte stream which is used
37+
38+
### Message
39+
40+
A message is a discrete packet of data which can be sent on a channel. Messages are structured into multiple
41+
fields. The protocol defines which data types can be carried by a message, and how transports should encode and
42+
decode them.
43+
44+
### Byte stream
45+
46+
A byte stream is an object which implements raw IO with `Read`, `Write` and `Close` methods.
47+
Typical byte streams are text files, network sockets, memory buffers, pipes, and so on.
48+
49+
One distinct characteristic of libchan is that it can encode byte streams as first class fields
50+
in a message, alongside more basic types like integers or strings.
51+
52+
### Nesting
53+
54+
Libchan supports nesting. This means that a libchan message can include a channel, which itself
55+
can be used to send and receive messages, and so on all the way down.
56+
57+
Nesting is a fundamental property of libchan.
58+
59+
## Underlying transport
60+
61+
The libchan protocol requires a reliable, 2-way byte stream as a transport.
62+
The most popular options are TCP connections, unix stream sockets and TLS sessions.
63+
64+
It is also possible to use websocket as an underlying transport, which allows exposing
65+
a libchan endpoint at an HTTP1 url.
66+
67+
## Authentication and encryption
68+
69+
Libchan can optionally use TLS to authenticate and encrypt communications. After the initial
70+
handshake and protocol negotiation, the TLS session is simply used as the transport for
71+
the libchan wire protocol.
72+
73+
## Wire protocol
74+
75+
Libchan uses SPDY (protocol draft 3) as its wire protocol, with no modification.
76+
77+
## Control protocol
78+
79+
Once 2 libchan endpoints have established a SPDY session, they communicate with the following
80+
control protocol.
81+
82+
### Top-level channels
83+
84+
Each SPDY session may carry multiple concurrent channels, in both directions, using standard
85+
SPDY framing and stream multiplexing. Each libchan channel is implemented by an underlying
86+
SPDY stream.
87+
88+
To use a SPDY session, either endpoint may initiate new channels, wait for its peer to
89+
initiate new channels, or a combination of both. Channels initiated in this way are called
90+
*top-level channels*.
91+
92+
* To initiate a new top-level channel, either endpoint may initiate a new SPDY stream, then
93+
start sending messages to it (see *"sending messages"*).
94+
95+
* The endpoint initiating a top-level channel MAY NOT allow the application to receive messages
96+
from it and MUST ignore inbound messages received on that stream.
97+
98+
* When an endpoint receives a new inbound SPDY stream, and the initial headers DO NOT include
99+
the key `libchan-ref`, it MUST queue a new `Receiver` channel to pass to the application.
100+
101+
* The endpoint receiving a top-level channel MAY NOT allow the application to send messages to
102+
it.
103+
104+
105+
### Sending messages on a channel
106+
107+
Once a SPDY stream is initiated, it can be used as a channel, with the initiating endpoint holding
108+
the `Sender` end of the channel, and the recipient endpoint holding the `Receiver` end.
109+
110+
* To send a message, the sender MUST encode it using the [msgpack](https://msgpack.org) encoding format, and
111+
send a single data frame on the corresponding SPDY stream, with the encoded message as the exact content of
112+
the frame.
113+
114+
* When receiving a data frame on any active SPDY stream, the receiver MUST decode it using msgpack. If
115+
the decoding fails, the receiver MUST close the underlying stream, and future calls to `Receive` on that
116+
channel MUST return an error.
117+
118+
* If a valid msgpack message is included in the data frame, but the frame also includes garbage trailing or
119+
leading data, the frame should be handled just like an invalid encoding error.
120+
121+
* A valid msgpack decode operation with leftover trailing or leading data is considered an *invalid* msgpack
122+
decode operation, and MUST yield the corresponding error.
123+
124+
### Closing a channel
125+
126+
The endpoint which initiated a channel MAY close it by closing the underlying SPDY stream.
127+
128+
*FIXME: provide more details*
129+
130+
### Sending byte streams
131+
132+
Libchan messages support a special type called *byte streams*. Unlike regular types like integers or strings,
133+
byte streams are not fully encoded in the message. Instead, the message encodes a *reference* which allows
134+
the receiving endpoint to reconstitute the byte stream after receiving the message, and pass it to the
135+
application.
136+
137+
*FIXME: specify use of msgpack extended types to encode byte streams*
138+
139+
Libchan supports 2 methods for sending byte streams: a default method which is supported on all transports,
140+
and an optional method which requires unix stream sockets. All implementations MUST support both methods.
141+
142+
#### Default method: SPDY streams
143+
144+
The primary method for sending a byte stream is to send it over a SPDY stream, with the following protocol:
145+
146+
* When encoding a message including 1 or more byte stream values, the sender MUST assign to each value
147+
an identifier unique to the session, and store these identifiers for future use.
148+
149+
* After sending the encoded message, the sender MUST initiate 1 new SPDY stream for each byte stream value
150+
in the message.
151+
152+
* Each of those SPDY stream MUST include an initial header with as a key the string "*libchan-ref*", and
153+
as a value the identifier of the corresponding byte stream.
154+
155+
Conversely, the receiver must follow this protocol:
156+
157+
* When decoding a message including 1 or more byte stream values, the receiver MUST store the unique identifier
158+
of each value in a session-wide table of pending byte streams. It MAY then immediately pass the decoded message to the application.
159+
160+
* The sender SHOULD cap the size of its pending byte streams table to a reasonable value. It MAY make that value
161+
configurable by the application. If it receives a message with 1 or more byte stream references, and the table
162+
is full, the sender MAY suspend processing of the message until there is room in the table.
163+
164+
* When receiving new SPDY streams which include the header key "*libchan-ref*", the receiver MUST lookup that
165+
header value in the table of pending byte streams. If the value is registered in the table, that SPDY stream
166+
MUST be passed to the application.
167+
168+
On either end, once the SPDY stream for a byte-stream value is established, it MUST be exposed to the application
169+
as follows:
170+
171+
* After sending each of those SPDY streams, each write operation by the application to a byte-stream field MUST
172+
trigger the sending of a single data frame on the corresponding SPDY stream.
173+
174+
* Each read operation by the application from a byte-stream field MUST yield the content of the next
175+
data frame received on the corresponding SPDY stream. If the reading end of the SPDY stream is closed,
176+
the read operation MUST yield EOF.
177+
178+
* A close operation by the application on the a byte-stream field MUST trigger the closing of the writing end
179+
of the corresponding SPDY stream.
180+
181+
#### Optional method: file descriptor passing
182+
183+
*FIXME*
184+
185+
### Sending nested channels
186+
187+
*FIXME*

0 commit comments

Comments
 (0)