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 */ 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 58The CONNECT message establishes the presence of a remote system. 59The version is used to ensure protocol compatibility and maxdata 60declares the maximum message body size that the remote system 61is willing to accept. 62 63Currently, version=0x01000000 and maxdata=4096 64 65Both sides send a CONNECT message when the connection between them is 66established. Until a CONNECT message is received no other messages may 67be sent. Any messages received before a CONNECT message MUST be ignored. 68 69If a CONNECT message is received with an unknown version or insufficiently 70large maxdata value, the connection with the other side must be closed. 71 72The system identity string should be "<systemtype>:<serialno>:<banner>" 73where systemtype is "bootloader", "device", or "host", serialno is some 74kind of unique ID (or empty), and banner is a human-readable version 75or identifier string (informational only). 76 77 78--- OPEN(local-id, 0, "destination") ----------------------------------- 79 80The OPEN message informs the recipient that the sender has a stream 81identified by local-id that it wishes to connect to the named 82destination in the message payload. The local-id may not be zero. 83 84The OPEN message MUST result in either a READY message indicating that 85the connection has been established (and identifying the other end) or 86a CLOSE message, indicating failure. An OPEN message also implies 87a READY message sent at the same time. 88 89Common destination naming conventions include: 90 91* "tcp:<host>:<port>" - host may be omitted to indicate localhost 92* "udp:<host>:<port>" - host may be omitted to indicate localhost 93* "local-dgram:<identifier>" 94* "local-stream:<identifier>" 95* "shell" - local shell service 96* "upload" - service for pushing files across (like aproto's /sync) 97* "fs-bridge" - FUSE protocol filesystem bridge 98 99 100--- READY(local-id, remote-id, "") ------------------------------------- 101 102The READY message informs the recipient that the sender's stream 103identified by local-id is ready for write messages and that it is 104connected to the recipient's stream identified by remote-id. 105 106Neither the local-id nor the remote-id may be zero. 107 108A READY message containing a remote-id which does not map to an open 109stream on the recipient's side is ignored. The stream may have been 110closed while this message was in-flight. 111 112The local-id is ignored on all but the first READY message (where it 113is used to establish the connection). Nonetheless, the local-id MUST 114not change on later READY messages sent to the same stream. 115 116 117 118--- WRITE(0, remote-id, "data") ---------------------------------------- 119 120The WRITE message sends data to the recipient's stream identified by 121remote-id. The payload MUST be <= maxdata in length. 122 123A WRITE message containing a remote-id which does not map to an open 124stream on the recipient's side is ignored. The stream may have been 125closed while this message was in-flight. 126 127A WRITE message may not be sent until a READY message is received. 128Once a WRITE message is sent, an additional WRITE message may not be 129sent until another READY message has been received. Recipients of 130a WRITE message that is in violation of this requirement will CLOSE 131the connection. 132 133 134--- CLOSE(local-id, remote-id, "") ------------------------------------- 135 136The CLOSE message informs recipient that the connection between the 137sender's stream (local-id) and the recipient's stream (remote-id) is 138broken. The remote-id MUST not be zero, but the local-id MAY be zero 139if this CLOSE indicates a failed OPEN. 140 141A CLOSE message containing a remote-id which does not map to an open 142stream on the recipient's side is ignored. The stream may have 143already been closed by the recipient while this message was in-flight. 144 145The recipient should not respond to a CLOSE message in any way. The 146recipient should cancel pending WRITEs or CLOSEs, but this is not a 147requirement, since they will be ignored. 148 149 150--- SYNC(online, sequence, "") ----------------------------------------- 151 152The SYNC message is used by the io pump to make sure that stale 153outbound messages are discarded when the connection to the remote side 154is broken. It is only used internally to the bridge and never valid 155to send across the wire. 156 157* when the connection to the remote side goes offline, the io pump 158 sends a SYNC(0, 0) and starts discarding all messages 159* when the connection to the remote side is established, the io pump 160 sends a SYNC(1, token) and continues to discard messages 161* when the io pump receives a matching SYNC(1, token), it once again 162 starts accepting messages to forward to the remote side 163 164 165--- message command constants ------------------------------------------ 166 167#define A_SYNC 0x434e5953 168#define A_CNXN 0x4e584e43 169#define A_OPEN 0x4e45504f 170#define A_OKAY 0x59414b4f 171#define A_CLSE 0x45534c43 172#define A_WRTE 0x45545257 173 174 175 176--- implementation details --------------------------------------------- 177 178The core of the bridge program will use three threads. One thread 179will be a select/epoll loop to handle io between various inbound and 180outbound connections and the connection to the remote side. 181 182The remote side connection will be implemented as two threads (one for 183reading, one for writing) and a datagram socketpair to provide the 184channel between the main select/epoll thread and the remote connection 185threadpair. The reason for this is that for usb connections, the 186kernel interface on linux and osx does not allow you to do meaningful 187nonblocking IO. 188 189The endian swapping for the message headers will happen (as needed) in 190the remote connection threadpair and that the rest of the program will 191always treat message header values as native-endian. 192 193The bridge program will be able to have a number of mini-servers 194compiled in. They will be published under known names (examples 195"shell", "fs-bridge", etc) and upon receiving an OPEN() to such a 196service, the bridge program will create a stream socketpair and spawn 197a thread or subprocess to handle the io. 198 199 200--- simplified / embedded implementation ------------------------------- 201 202For limited environments, like the bootloader, it is allowable to 203support a smaller, fixed number of channels using pre-assigned channel 204ID numbers such that only one stream may be connected to a bootloader 205endpoint at any given time. The protocol remains unchanged, but the 206"embedded" version of it is less dynamic. 207 208The bootloader will support two streams. A "bootloader:debug" stream, 209which may be opened to get debug messages from the bootloader and a 210"bootloader:control", stream which will support the set of basic 211bootloader commands. 212 213Example command stream dialogues: 214 "flash_kernel,2515049,........\n" "okay\n" 215 "flash_ramdisk,5038,........\n" "fail,flash write error\n" 216 "bogus_command......" <CLOSE> 217 218 219--- future expansion --------------------------------------------------- 220 221I plan on providing either a message or a special control stream so that 222the client device could ask the host computer to setup inbound socket 223translations on the fly on behalf of the client device. 224 225 226The initial design does handshaking to provide flow control, with a 227message flow that looks like: 228 229 >OPEN <READY >WRITE <READY >WRITE <READY >WRITE <CLOSE 230 231The far side may choose to issue the READY message as soon as it receives 232a WRITE or it may defer the READY until the write to the local stream 233succeeds. A future version may want to do some level of windowing where 234multiple WRITEs may be sent without requiring individual READY acks. 235 236------------------------------------------------------------------------ 237 238--- smartsockets ------------------------------------------------------- 239 240Port 5037 is used for smart sockets which allow a client on the host 241side to request access to a service in the host adb daemon or in the 242remote (device) daemon. The service is requested by ascii name, 243preceeded by a 4 digit hex length. Upon successful connection an 244"OKAY" response is sent, otherwise a "FAIL" message is returned. Once 245connected the client is talking to that (remote or local) service. 246 247client: <hex4> <service-name> 248server: "OKAY" 249 250client: <hex4> <service-name> 251server: "FAIL" <hex4> <reason> 252 253