TC is a bidirectional message-based protocol. It assumes an underlying stream for communication between a controlling process (the "client" or "controller") and a Tor process (or "server"). The stream may be implemented via TCP, TLS-over-TCP, a Unix-domain socket, or so on, but it must provide reliable in-order delivery. For security, the stream should not be accessible by untrusted parties.
In TC, the client and server send typed messages to each other over the underlying stream. The client sends "commands" and the server sends "replies".
By default, all messages from the server are in response to messages from the client. Some client requests, however, will cause the server to send messages to the client indefinitely far into the future. Such "asynchronous" replies are marked as such.
Servers respond to messages in the order messages are received.
This is an evolving protocol; new client and server behavior will be allowed in future versions. To allow new backward-compatible behavior on behalf of the client, we may add new commands and allow existing commands to take new arguments in future versions. To allow new backward-compatible server behavior, we note various places below where servers speaking a future version of this protocol may insert new data, and note that clients should/must "tolerate" unexpected elements in these places. There are two ways that we do this:
- Adding a new field to a message:
For example, we might say "This message has three space-separated fields; clients MUST tolerate more fields." This means that a client MUST NOT crash or otherwise fail to parse the message or other subsequent messages when there are more than three fields, and that it SHOULD function at least as well when more fields are provided as it does when it only gets the fields it accepts. The most obvious way to do this is by ignoring additional fields; the next-most-obvious way is to report additional fields verbatim to the user, perhaps as part of an expert UI. * Adding a new possible value to a list of alternatives: For example, we might say "This field will be OPEN, CLOSED, or CONNECTED. Clients MUST tolerate unexpected values." This means that a client MUST NOT crash or otherwise fail to parse the message or other subsequent messages when there are unexpected values, and that it SHOULD try to handle the rest of the message as well as it can. The most obvious way to do this is by pretending that each list of alternatives has an additional "unrecognized value" element, and mapping any unrecognized values to that element; the next-most-obvious way is to create a separate "unrecognized value" element for each unrecognized value. Clients SHOULD NOT "tolerate" unrecognized alternatives by pretending that the message containing them is absent. For example, a stream closed for an unrecognized reason is nevertheless closed, and should be reported as such. (If some list of alternatives is given, and there isn't an explicit statement that clients must tolerate unexpected values, clients still must tolerate unexpected values. The only exception would be if there were an explicit statement that no future values will ever be added.)