All the time I was working with XMPP I realized this protocol has a lot of flaws to use in mobile devices, even the lack of sync for the messages between several devices. This protocol tries to solve those flaws:
- Use of bandwidth. This protocol is binary and use keywords to save a lof of bandwidth using the same protocol and the same featureas as XMPP.
- Reliability of the messages. Using ACKs in every sent ensure all of the messages will arrive to the destin and in the same order. The protocol is async, but for messages the server must to use a pipeline sent.
- Multi-device. Capabilities to ensure the messages are delivered on all the devices the user has registered.
- Security. Ensuring a certificate is valid between client and server (client must to check server certificate and server must to check client certificate) ensure the communication should be more secure.
Auth is based on SSL. If the SSL certificate for connect to the server should be valid and associated to only one user.
Register is performed when an user connects to the server with an invalid certificate and request register in the system. The register is the only one action could be performed with an invalid certificate. The information will be pass in the content to the register system in the server and this determines if the certificate will be ok to continue or the connection is dropped.
For security reasons if an user tries to register more than 3 (or a configurable number of) times with invalid certificates, from the same IP with failed results the server must to deny the connection to the server again from that IP.
Communication is completely binary, async and bilateral. The packet should be (type-1):
+--+--------+--------+--------+--------+------------
|CC| ID | FROM | TO | LENGTH | PAYLOAD ...
+--+--------+--------+--------+--------+------------
or could be this one too (depends on the command) (type-2):
+--+--------+--------+--------+
|CC| ID | FROM | TO |
+--+--------+--------+--------+
COMMAND (CC) byte:
- 00 - (type 2) PING
- 01 - (type 2) ACK
- 02 - (type 2) RECEIPT
- 03 - (type 1) MESSAGE
- 04 - (type 1) PRESENCE
- 05 - (type 1) REQUEST
- 06 - (type 1) REGISTER
- FF - (type 1) ERROR
ID is a 32-bits data. Should be sequential. The client use its own numbers and the server uses another numbers. The numbers are restarted in each reconnection.
FROM is a 32-bits number. It's related to the Contact ID for the client.
TO is a 32-bits number. It's related to the Contact ID for the client.
LENGTH is a 32-bits unsigned number.
PAYLOAD is the message.
Contacts are saved for each client in the server. Numbered as:
- 00000000 - Server
- 00000001 - Client
- 00000002 - Contact 1 for User
- 00000003 - Contact 2 for User
- ...
- FFFFFFFF - Unknown
Each user has capability to have 4,2G of contacts. There are only 3 numbers reserved (0, 1 and the last FFFFFFFF).
When an user is connected to the server, the server sent to the client a contact sync command with a version (see below in the requests section). The client have to reply to this request with a result command sending a new copy of the table in case the version are different between client and server, or with an result command but with an empty payload:
Example 1. Sending table (synced)
S: 2 REQUEST GET S -> C CONTACTS SYNC "a2c9e5"
C: 2 ACK C -> S
Example 2. Sending table (no version synced)
S: 2 REQUEST GET S -> C CONTACTS SYNC "a2c9e5"
C: 2 ACK C -> S [ 'user1', 'user2', 'user3', ... ]
S: 3 REQUEST GET S -> C CONTACTS SYNC "15dc7e"
C: 3 ACK C -> S
The message has its payload as follow:
+--+--------+-----------
|TP| LENGTH | CONTENT...
+--+--------+-----------
TYPE (TP) is a 8-bits number representing:
- 00 - no content
- 01 - text
- 02 - binary
If CONTENT is present can content text or binary data, as long as specified in the 32-bits number represented by LENGTH.
The presence is a way to notify users when another user is online, offline or with another status. The payload for presence is as follow:
+--+----+-----------
|TP| LN | CONTENT...
+--+----+-----------
TYPE (TP) is a 8-bits number representing:
- 00 - offline
- 01 - online
- FF - custom (specified by CONTENT)
LENGTH (LN) is a 32-bits unsigned number.
Each request has its payload codified as follow:
NAMESPACE PARAMS PARAM+
+--------+--+----------
| NS |PS| PARAMS...
+--------+--+----------
NAMESPACE (NS) is a 4-bytes code referencing to a functionality available in the server:
- CONL - contact list
- CONI - contact info
- CONA - contact add
- CONR - contact remove
- BLKL - black/block list
- BLKI - black/block info
- BLKA - black/block add
- BLKR - black/block remove
- PRVG - private storage get
- PRVS - private storage set
- GRPL - group list
- GRPI - group info
- GRPC - group create
- GRPA - group invite/add contact
- GRPV - group leave
- GRPK - group kick a contact
- GRPR - group remove/destroy
PARAMS is a 8-bits number representing the number of params there are in the request is possible to indicate 0 to 255 params.
PARAM is a 8-bits number representing:
- 00 - NULL (no content)
- 01 - TRUE (no content)
- 02 - FALSE (no content)
- 03 - BYTE (PARAM_CONTENT is a byte)
- 04 - STRING (PARAM_CONTENT is 32-bits LENGTH and the CONTENT)
- 05 - INTEGER (PARAM_CONTENT is a 32-bits big endian number)
- 06 - FLOAT (PARAM_CONTENT is a 32-bits float number)
- 07 - ARRAY adds a LENGTH (32 bits) and ELEMENTS based on this table.
- 08 - HASH adds a LENGTH (32 bits), KEY as STRING and VALUE based on this table.
If an user is connected using 2 devices, the first time the system will send a presence to the subscriptors of those presences but not the second time. And when the users goes offline only for the last device disconnected from the system will be sent the offline presence to the subscriptors.
All the messages wrote to the other clients are copied and received by the other devices.
Example:
C1: connected
S : PRESENCE C1 -> SUBS
C2: connected
C1: 4 MESSAGE C -> X 01 "Hi world!"
S : 4 ACK S -> C1
S : 4 MESSAGE C -> X 01 "Hi world!" (copy for C2)
C2: 4 ACK C2 -> S
S : 4 MESSAGE C -> X 01 "Hi world!"
X : 4 ACK X -> S
S : 4 RECEIPT S -> C1
C1: 4 ACK C1 -> S
When a device is created this should exists until timeout (configured in days) to store the offline messages for the device.
A session example:
C starts communication with the server S
C: 1 PING C -> S
S: 1 ACK S -> C
C: 2 REQUEST GET C -> S CONTACTS
S: 2 ACK S -> C [ "Server", "MySelf", "Friend 1", "Friend 2" ]
C: 3 REQUEST GET C -> S INFO 0
S: 3 ACK S -> C [ "name" => "Server", "version" => "1.0", supports => [ ... ] ]
C: 4 MESSAGE C -> 2 01 "Hi world!"
S: 4 ACK S -> C
S: 4 MESSAGE C -> 2 01 "Hi world!"
2: 4 ACK 2 -> S
S: 4 RECEIPT S -> C
C: 4 ACK C -> S