1 2--- a replacement for aproto ------------------------------------------- 3 4When it comes down to it, aproto's primary purpose is to forward 5various streams between the host computer and client device (in either 6direction). 7 8This replacement further simplifies the concept, reducing the protocol 9to an extremely straightforward model optimized to accomplish the 10forwarding of these streams and removing additional state or 11complexity. 12 13The host side becomes a simple comms bridge with no "UI", which will 14be used by either commandline or interactive tools to communicate with 15a device or emulator that is connected to the bridge. 16 17The protocol is designed to be straightforward and well-defined enough 18that if it needs to be reimplemented in another environment (Java 19perhaps), there should not problems ensuring perfect interoperability. 20 21The protocol discards the layering aproto has and should allow the 22implementation to be much more robust. 23 24 25--- protocol overview and basics --------------------------------------- 26 27The transport layer deals in "messages", which consist of a 24 byte 28header followed (optionally) by a payload. The header consists of 6 2932 bit words which are sent across the wire in little endian format. 30 31struct message { 32 unsigned command; /* command identifier constant (A_CNXN, ...) */ 33 unsigned arg0; /* first argument */ 34 unsigned arg1; /* second argument */ 35 unsigned data_length; /* length of payload (0 is allowed) */ 36 unsigned data_crc32; /* crc32 of data payload */ 37 unsigned magic; /* command ^ 0xffffffff */ 38}; 39 40Receipt of an invalid message header, corrupt message payload, or an 41unrecognized command MUST result in the closing of the remote 42connection. The protocol depends on shared state and any break in the 43message stream will result in state getting out of sync. 44 45The following sections describe the six defined message types in 46detail. Their format is COMMAND(arg0, arg1, payload) where the payload 47is represented by a quoted string or an empty string if none should be 48sent. 49 50The identifiers "local-id" and "remote-id" are always relative to the 51*sender* of the message, so for a receiver, the meanings are effectively 52reversed. 53 54 55 56--- CONNECT(version, maxdata, "system-identity-string") ---------------- 57 58Command constant: A_CNXN 59 60The CONNECT message establishes the presence of a remote system. 61The version is used to ensure protocol compatibility and maxdata 62declares the maximum message body size that the remote system 63is willing to accept. 64 65Currently, version=0x01000000 and maxdata=256*1024. Older versions of adb 66hard-coded maxdata=4096, so CONNECT and AUTH packets sent to a device must not 67be larger than that because they're sent before the CONNECT from the device 68that tells the adb server what maxdata the device can support. 69 70Both sides send a CONNECT message when the connection between them is 71established. Until a CONNECT message is received no other messages may 72be sent. Any messages received before a CONNECT message MUST be ignored. 73 74If a CONNECT message is received with an unknown version or insufficiently 75large maxdata value, the connection with the other side must be closed. 76 77The system identity string should be "<systemtype>:<serialno>:<banner>" 78where systemtype is "bootloader", "device", or "host", serialno is some 79kind of unique ID (or empty), and banner is a human-readable version 80or identifier string. The banner is used to transmit useful properties. 81 82--- STLS(type, version, "") -------------------------------------------- 83 84Command constant: A_STLS 85 86The TLS message informs the recipient that the connection will be encrypted 87and will need to perform a TLS handshake. version is the current version of 88the protocol. 89 90 91--- AUTH(type, 0, "data") ---------------------------------------------- 92 93Command constant: A_AUTH 94 95The AUTH message informs the recipient that authentication is required to 96connect to the sender. If type is TOKEN(1), data is a random token that 97the recipient can sign with a private key. The recipient replies with an 98AUTH packet where type is SIGNATURE(2) and data is the signature. If the 99signature verification succeeds, the sender replies with a CONNECT packet. 100 101If the signature verification fails, the sender replies with a new AUTH 102packet and a new random token, so that the recipient can retry signing 103with a different private key. 104 105Once the recipient has tried all its private keys, it can reply with an 106AUTH packet where type is RSAPUBLICKEY(3) and data is the public key. If 107possible, an on-screen confirmation may be displayed for the user to 108confirm they want to install the public key on the device. 109 110 111--- OPEN(local-id, 0, "destination") ----------------------------------- 112 113Command constant: A_OPEN 114 115The OPEN message informs the recipient that the sender has a stream 116identified by local-id that it wishes to connect to the named 117destination in the message payload. The local-id may not be zero. 118 119The OPEN message MUST result in either a READY message indicating that 120the connection has been established (and identifying the other end) or 121a CLOSE message, indicating failure. An OPEN message also implies 122a READY message sent at the same time. 123 124Common destination naming conventions include: 125 126* "tcp:<host>:<port>" - host may be omitted to indicate localhost 127* "udp:<host>:<port>" - host may be omitted to indicate localhost 128* "vsock:<CID>:<port>" 129* "local-dgram:<identifier>" 130* "local-stream:<identifier>" 131* "shell" - local shell service 132* "upload" - service for pushing files across (like aproto's /sync) 133* "fs-bridge" - FUSE protocol filesystem bridge 134 135 136--- READY(local-id, remote-id, "") ------------------------------------- 137 138Command constant: A_OKAY 139 140The READY message informs the recipient that the sender's stream 141identified by local-id is ready for write messages and that it is 142connected to the recipient's stream identified by remote-id. 143 144Neither the local-id nor the remote-id may be zero. 145 146A READY message containing a remote-id which does not map to an open 147stream on the recipient's side is ignored. The stream may have been 148closed while this message was in-flight. 149 150The local-id is ignored on all but the first READY message (where it 151is used to establish the connection). Nonetheless, the local-id MUST 152not change on later READY messages sent to the same stream. 153 154 155--- WRITE(local-id, remote-id, "data") --------------------------------- 156 157Command constant: A_WRTE 158 159The WRITE message sends data to the recipient's stream identified by 160remote-id. The payload MUST be <= maxdata in length. 161 162A WRITE message containing a remote-id which does not map to an open 163stream on the recipient's side is ignored. The stream may have been 164closed while this message was in-flight. 165 166A WRITE message may not be sent until a READY message is received. 167Once a WRITE message is sent, an additional WRITE message may not be 168sent until another READY message has been received. Recipients of 169a WRITE message that is in violation of this requirement will CLOSE 170the connection. 171 172 173--- CLOSE(local-id, remote-id, "") ------------------------------------- 174 175Command constant: A_CLSE 176 177The CLOSE message informs recipient that the connection between the 178sender's stream (local-id) and the recipient's stream (remote-id) is 179broken. The remote-id MUST not be zero, but the local-id MAY be zero 180if this CLOSE indicates a failed OPEN. 181 182A CLOSE message containing a remote-id which does not map to an open 183stream on the recipient's side is ignored. The stream may have 184already been closed by the recipient while this message was in-flight. 185 186The recipient should not respond to a CLOSE message in any way. The 187recipient should cancel pending WRITEs or CLOSEs, but this is not a 188requirement, since they will be ignored. 189 190 191--- SYNC(online, sequence, "") ----------------------------------------- 192 193Command constant: A_SYNC 194 195*** obsolete, no longer used *** 196 197The SYNC message was used by the io pump to make sure that stale 198outbound messages are discarded when the connection to the remote side 199is broken. It was only used internally to the bridge and never valid 200to send across the wire. 201 202* when the connection to the remote side goes offline, the io pump 203 sends a SYNC(0, 0) and starts discarding all messages 204* when the connection to the remote side is established, the io pump 205 sends a SYNC(1, token) and continues to discard messages 206* when the io pump receives a matching SYNC(1, token), it once again 207 starts accepting messages to forward to the remote side 208 209 210--- message command constants ------------------------------------------ 211 212#define A_SYNC 0x434e5953 213#define A_CNXN 0x4e584e43 214#define A_AUTH 0x48545541 215#define A_OPEN 0x4e45504f 216#define A_OKAY 0x59414b4f 217#define A_CLSE 0x45534c43 218#define A_WRTE 0x45545257 219#define A_STLS 0x534C5453 220 221 222 223--- implementation details --------------------------------------------- 224 225The core of the bridge program will use three threads. One thread 226will be a select/epoll loop to handle io between various inbound and 227outbound connections and the connection to the remote side. 228 229The remote side connection will be implemented as two threads (one for 230reading, one for writing) and a datagram socketpair to provide the 231channel between the main select/epoll thread and the remote connection 232threadpair. The reason for this is that for usb connections, the 233kernel interface on linux and osx does not allow you to do meaningful 234nonblocking IO. 235 236The endian swapping for the message headers will happen (as needed) in 237the remote connection threadpair and that the rest of the program will 238always treat message header values as native-endian. 239 240The bridge program will be able to have a number of mini-servers 241compiled in. They will be published under known names (examples 242"shell", "fs-bridge", etc) and upon receiving an OPEN() to such a 243service, the bridge program will create a stream socketpair and spawn 244a thread or subprocess to handle the io. 245 246 247--- simplified / embedded implementation ------------------------------- 248 249For limited environments, like the bootloader, it is allowable to 250support a smaller, fixed number of channels using pre-assigned channel 251ID numbers such that only one stream may be connected to a bootloader 252endpoint at any given time. The protocol remains unchanged, but the 253"embedded" version of it is less dynamic. 254 255The bootloader will support two streams. A "bootloader:debug" stream, 256which may be opened to get debug messages from the bootloader and a 257"bootloader:control", stream which will support the set of basic 258bootloader commands. 259 260Example command stream dialogues: 261 "flash_kernel,2515049,........\n" "okay\n" 262 "flash_ramdisk,5038,........\n" "fail,flash write error\n" 263 "bogus_command......" <CLOSE> 264 265 266--- future expansion --------------------------------------------------- 267 268I plan on providing either a message or a special control stream so that 269the client device could ask the host computer to setup inbound socket 270translations on the fly on behalf of the client device. 271 272 273The initial design does handshaking to provide flow control, with a 274message flow that looks like: 275 276 >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE 277 278The far side may choose to issue the READY message as soon as it receives 279a WRITE or it may defer the READY until the write to the local stream 280succeeds. A future version may want to do some level of windowing where 281multiple WRITEs may be sent without requiring individual READY acks. 282 283------------------------------------------------------------------------ 284 285--- smartsockets ------------------------------------------------------- 286 287Port 5037 is used for smart sockets which allow a client on the host 288side to request access to a service in the host adb daemon or in the 289remote (device) daemon. The service is requested by ascii name, 290preceeded by a 4 digit hex length. Upon successful connection an 291"OKAY" response is sent, otherwise a "FAIL" message is returned. Once 292connected the client is talking to that (remote or local) service. 293 294client: <hex4> <service-name> 295server: "OKAY" 296 297client: <hex4> <service-name> 298server: "FAIL" <hex4> <reason> 299 300