Project

General

Profile

Doc quassel protocols » History » Version 6

Sputnick, 02/27/2013 02:28 AM

1 1 Sputnick
h1. The Quassel Protocol
2 2 Sputnick
3 2 Sputnick
h2. Overview
4 2 Sputnick
5 3 Sputnick
When we talk about the "Quassel protocol", we mean the format of data sent between a Quassel core and connected Quassel clients. At the moment (i.e., as of version 0.8), only one protocol - the "legacy protocol" - is in use. It has evolved from Quassel's early days and hasn't really changed all that much over the years. However, back then we didn't really expect Quassel to ever become popular, much less other developers writing alternate clients such as QuasselDroid or iQuassel. Accordingly, instead of designing (and documenting) a well-defined and easy-to-use format, we chose a rather pragmatic approach for sending data over the wire: Because Qt already had a facility to (de)serialize arbitrary data types over a binary stream - using QDataStream - we simply went with that.
6 2 Sputnick
7 2 Sputnick
While being both straightforward and easy to implement in Quassel, this choice turned out to be rather unlucky in retrospect:
8 2 Sputnick
9 2 Sputnick
* QDataStream's serialization format is not the most efficient one. In particular, strings are serialized as UTF-16, which means that almost half of the data exchanged between client and core is nullbytes. However, this is partially compensated by Quassel using compression if possible.
10 2 Sputnick
* Speaking of which, we don't use streaming compression, which means that lots of potential for benefitting from recurring strings is not used. And since many of the objects we send are key/value maps which tend to have the same set of keys every time, this does matter in practice.
11 1 Sputnick
* And to add insult to injury, we waste even more space all over the place because we simply didn't think about optimizing the protocol. Mobile use of Quassel was just not on our radar in 2005.
12 3 Sputnick
* The serialization format is nowhere documented in a concise and complete way. Yes, there's documentation somewhere in Qt for built-in types; for Quassel's own types however, one would have to hunt through the source. And without reading (and understanding) some rather icky parts of Quassel code, it's close to impossible to understand what's going on even if one manages to deserialize the binary data into proper objects. Bad news for people wanting to write alternate clients. Amazingly, some smart people still managed to reverse-engineer the protocol...
13 3 Sputnick
14 4 Sputnick
To fix these and more issues, we're now planning to replace the legacy protocol by something more sensible. As the first (and most complicated) step, work is now underway to implement a protocol abstraction that will then allow us to much more easily support alternative formats. As a neat side effect, the resulting refactoring also will make some core parts of the code (e.g. SignalProxy) much nicer to understand.
15 4 Sputnick
16 4 Sputnick
h2. Protocol Abstraction - The Master Plan
17 4 Sputnick
18 4 Sputnick
h3. Requirements for new protocols
19 4 Sputnick
20 4 Sputnick
h3. Keeping compatibility
21 4 Sputnick
22 4 Sputnick
TBD: for how long?
23 4 Sputnick
24 6 Sputnick
h2. Abstract View [DRAFT]
25 4 Sputnick
26 4 Sputnick
h3. Handshake
27 4 Sputnick
28 1 Sputnick
h4. Probing
29 6 Sputnick
30 6 Sputnick
Because we might want to support more than one protocol, we cannot start to send messages right away. First, both client and core need to agree on which protocol to use and if to enable things like compression or SSL. Therefore, right after the connection has been established, a few well-defined bytes are exchanged to probe for the capabilities on both ends and to determine in which way the real data is going to be exchanged.
31 6 Sputnick
32 6 Sputnick
# The client sends a 32 bit value to the core. The lowest byte contains the supported protocols as defined in the Protocol::Type enum. The upper 24 bit contain the magic number [TBD] to indicate that a post-0.9 client is connecting. Since the resulting value is larger than 0x00400000, legacy (pre-0.9) cores will immediately close the connection. The client can detect this and reconnect in compatibility mode.
33 6 Sputnick
34 6 Sputnick
# The core replies with a 32 bit value. The lowest byte specifies the protocol it has selected based on what the client supports. Bits 8-15 contain the protocol version. The upper 16 bit contain a protocol-specific set of features that the core supports - things like compression and SSL support.
35 6 Sputnick
36 6 Sputnick
# The client sends another 32 bit value containing its own version of the protocol in bits 8-15, and the protocol-specific features to be used in bits 16-31.
37 6 Sputnick
38 6 Sputnick
# At this point, both client and core enable the agreed feature set (e.g. turn on compression and encryption). The remaining communication happens in the form of protocol messages.
39 6 Sputnick
40 6 Sputnick
_Note: The legacy protocol determines the supported and enabled feature set, as well as the protocol version, only during the handshake phase. Therefore, both compression and encryption are turned on later in the process. Also, a client reconnecting in compatibility mode will skip the probing phase and proceed directly with the handshake._
41 4 Sputnick
42 4 Sputnick
h4. Init and Authentication
43 4 Sputnick
44 5 Sputnick
h3. SigProxy Mode
45 4 Sputnick
46 4 Sputnick
h2. On-Wire Format
47 4 Sputnick
48 4 Sputnick
h3. Legacy Protocol