-
Notifications
You must be signed in to change notification settings - Fork 18
Arrow Protocol
This document describes Arrow communication protocol used between Angelcam Arrow Services and Arrow Client. It is a binary protocol with minimal overhead designed to encapsulate multiple connections to different services within a target network. The protocol allows to easily connect different kinds of local services into the Angelcam cloud without the need of a public IP address and setting up port forwarding on the edge of the target network. Despite providing access to user's local services, the protocol is secure. It does not open the whole target network, only those services passed explicitly by the client. The whole communication between the Arrow Client and Arrow Services is secured using TLS v1.2 or newer.
- Roles
- Communication channel
-
Messages
-
Arrow Control Protocol
- ACK message
- PING message
- REGISTER message
- REDIRECT message
- UPDATE message
- HUP message
- RESET_SVC_TABLE message
- SCAN_NETWORK message
- GET_STATUS message
- STATUS message
- GET_SCAN_REPORT message
- SCAN_REPORT message
- DATA_ACK message
- CONNECT message
- Service table structure
- Service types
- Status flags
- ACK/HUP error codes
-
Arrow Control Protocol
- Protocol states
- Procedures
- Sessions
- Revisions
There are two roles recognized by this protocol:
- Arrow Service
- Arrow Client
It is a server application which accepts connections from clients. It is responsible for client authentication, maintaining the connection, initiating connections to client's local services and load balancing.
It is a client application running within a target network. It might be configured to provide access to one or multiple services in the target network. Typical use case is an Arrow Client running in an IP camera providing access to its RTSP server. The client is responsible for connecting to an Arrow Service and serving its requests.
Communication channel between Arrow Client and an Arrow Service is a regular TCP connection secured by TLS v1.2 or newer. Identity of the Arrow Service is verified using a CA certificate. Arrow Clients are identified by their UUID and a key. Both the UUID and the key are generated directly by clients on their first boot. Arrow Services store only the clients' UUID and salted SHA-256 fingerprint of their key. Identity of a client is verified only once for each added Arrow device using so-called Pairing Procedure (see below).
All Arrow Messages exchanged between Arrow Clients and Arrow Services have binary headers, they MUST use the network byte order and they MUST have the following structure:
0 8 24 32 56 88
+------------+------------+------------+------------+------------+
| version | svc_id | reserved | session_id | body_size |
+------------+------------+------------+------------+------------+
| body |
+----------------------------------------------------------------+
-
version
- unsigned integer; major version of this protocol -
svc_id
- unsigned integer; service ID (see the service table below) -
session_id
- unsigned integer; session ID identifying a connection to a local service (it is generated by the Arrow Service) -
body_size
- unsigned integer; size of the message body
Service ID 0x00
is reserved for the Arrow Control Protocol service.
Arrow Control Protocol is a sub-protocol of the Arrow Protocol. It is used mainly for checking the connection status, session handling and various notifications. All Control Protocol messages are sent as an Arrow Message body with service ID 0x00
(session ID is ignored). They have the following structure:
0 16 32
+------------+------------+------------+
| msg_id | type | data |
+------------+------------+------------+
-
msg_id
- unsigned integer; message ID (used for request/response pairing) -
type
- unsigned integer; message type (see below)
Length of the data
part can be determined from the corresponding Arrow Message body_size
. The following table lists all Control Protocol message types:
name | type | optional | S -> C | C -> S | expected response |
---|---|---|---|---|---|
ACK | 0x0000 |
• | • | none | |
PING | 0x0001 |
• | • | ACK | |
REGISTER | 0x0002 |
• | ACK | ||
REDIRECT | 0x0003 |
• | none | ||
UPDATE | 0x0004 |
• | none | ||
HUP | 0x0005 |
• | • | none | |
RESET_SVC_TABLE | 0x0006 |
• | none | ||
SCAN_NETWORK | 0x0007 |
• | none | ||
GET_STATUS | 0x0008 |
• | STATUS | ||
STATUS | 0x0009 |
• | none | ||
GET_SCAN_REPORT | 0x000a |
• | • | SCAN_REPORT | |
SCAN_REPORT | 0x000b |
• | none | ||
DATA_ACK | 0x000c |
• | • | none | |
CONNECT | 0x000d |
• | none |
Note that some message types are optional. Client implementations does not have to handle such messages. However, clients MUST respond to all unknown messages by sending an ACK message with the UNSUPPORTED_METHOD error code.
The message is a response to another Control Protocol message. It might be sent by both - client and server. The message consists of 32-bit unsigned integer used as an error code.
Ping request used for connection health checks. It is periodically sent by both - server and client. The message contains no data. ACK is expected.
Registration request sent by a client when a new connection is established. The message contains client credentials, optional extended info and a service table. ACK is expected. The message has the following structure:
0 128 256 304 320 352
+-------------+-------------+-------------+-------------+-------------+
| uuid | key | mac_addr | window_size | flags |
+-------------+-------------+-------------+-------------+-------------+
352
+---------------------------------------------------------------------+
| extended_info |
+---------------------------------------------------------------------+
| svc_table |
+---------------------------------------------------------------------+
-
uuid
- 16 octets; UUIDv4 identifying the Arrow Client (see RFC 4122) -
key
- 16 octets; key for identity verification -
mac_addr
- 6 octets; MAC address of a client's network interface -
window_size
- unsigned integer; session capacity minus 1 (settingwindow_size
to 255 means that either side can send 256 bytes into a session channel) -
flags
- unsigned integer; client flags-
0x0001
- the client can be used as a gateway (i.e. it will accept connection requests even for non-localhost services)
-
-
extended_info
- null-terminated string; optional JSON containing more data about the client -
svc_table
- client's service table (see below for its structure)
The message can be sent by server to redirect a client to another server. No ACK is expected, the server closes connection immediately after sending the redirect command. Message data consist of a "host:port" NULL terminated string (its length can be determined from body_size
).
The command is sent by client every time the content of its service table gets changed. The message consists only from the service table (see below). No ACK is expected.
Hangup notification. It might be sent by both - client and server to notify the other side of the communication that a session with a given ID has been terminated. No ACK is expected. The message has the following structure:
0 8 32 64
+------------+------------+------------+
| reserved | session_id | err |
+------------+------------+------------+
-
session_id
- unsigned integer, session ID -
err
- error code (see below)
Request for the service table reset (i.e. the client should discard all services found using the network scanner). It is sent by server and the message contains no data. No ACK is expected.
Request for scanning the client's local network. Clients which do not support this feature should ignore this message without sending any ACK. It is sent by server and the message contains no data. No ACK is expected.
Request for sending a client status message. It is sent by server and the message contains no data. STATUS message is expected (see below for its structure).
Response for the GET_STATUS request. It is sent by client. No ACK is expected. The message has the following structure:
0 16 48 80
+--------------+--------------+--------------------+
| request_id | status_flags | active_sessions |
+--------------+--------------+--------------------+
-
request_id
- unsigned integer;msg_id
of a corresponding GET_STATUS request -
status_flags
- client status flags (see below) -
active_sessions
- unsigned integer; number of active sessions
Request for sending a scan report message. It is sent by server and the message contains no data. SCAN_REPORT message is expected (see below for its structure). Note that this message is optional.
Response for the GET_SCAN_REPORT request. It is sent by client. No ACK is expected. The message has the following structure:
0 16 48
+-----------------+-----------------+
| request_id | host_count |
+-----------------+-----------------+
48
+--------+--------+--------+--------+
| host_1 | host_2 | ... | host_n |
+--------+--------+--------+--------+
+-----------------------------------+
| service_table |
+-----------------------------------+
-
request_id
- unsigned integer;msg_id
of a corresponding GET_SCAN_REPORT request -
host_count
- unsigned integer; number of host records -
host_i
- host record; scan report related to a particular host (see below for the record structure) -
service_table
- service table; services discovered on this scan event (see below for the service table structure)
And every host record have the following structure:
0 8 56 64 192 208
+------------+------------+------------+------------+------------+
| flags | mac_addr | ip_version | ip_addr | port_count |
+------------+------------+------------+------------+------------+
208 224 240
+------------+------------+-------------------------+------------+
| port_1 | port_2 | ... | port_n |
+------------+------------+-------------------------+------------+
-
flags
- unsigned integer; host info flags:-
0x01
: discovered using ARP scan -
0x02
: discovered using ICMP echo scan
-
-
mac_addr
- 6 octets; MAC address of the host -
ip_version
- unsigned integer; IP protocol version (the only two valid options are 4 and 6) -
ip_addr
- 16 octets; left-aligned IP address of the host -
port_count
- unsigned integer; number of open ports -
port_i
- unsigned integer; open port
A message sent by either side to allow more session data to be sent by the other side. The message has the following structure:
0 8 32 64
+--------------+--------------+--------------+
| reserved | session_id | length |
+--------------+--------------+--------------+
-
session_id
- unsigned integer; session ID -
length
- unsigned integer; number of additional bytes that can be sent by the receiver of this message
Message initiating a new session. The message has the following structure:
0 16 24 48
+--------------+--------------+--------------+
| svc_id | reserved | session_id |
+--------------+--------------+--------------+
-
svc_id
- unsigned integer; service ID (see the service table below) -
session_id
- unsigned integer; session ID (generated by the Arrow Service)
Service table consists of the following records:
0 16 32 80
+------------+------------+------------+
| svc_id | svc_type | mac_addr |
+------------+------------+------------+
80 88 216 232
+------------+------------+------------+
| ip_version | ip_addr | port |
+------------+------------+------------+
232
+--------------------------------------+
| path |
+--------------------------------------+
-
svc_id
- unsigned integer; service ID -
svc_type
- unsigned integer; service type (see the table below) -
mac_addr
- 6 octets; MAC address of the service host (00:00:00:00:00:00 in case it is unknown) -
ip_version
- unsigned integer; IP protocol version (the only two valid options are 4 and 6) -
ip_addr
- 16 octets; left-aligned IP address of the service host -
port
- unsigned integer; service port -
path
- NULL terminated string; URL path (e.g. "/some/path.sdp?param=value")
The table ends with a record with service ID 0x00
and service type 0x00
(the other fields are ignored).
name | type | description |
---|---|---|
Arrow Control Protocol | 0x0000 |
Arrow Control Protocol pseudo service |
RTSP | 0x0001 |
RTSP service |
Locked RTSP | 0x0002 |
locked RTSP service with unknown path and credentials (usually discovered using network scanner) |
Unknown RTSP | 0x0003 |
RTSP service with unknown path (usually discovered using network scanner) |
Unsupported RTSP | 0x0004 |
RTSP service with known path but unsupported streams (i.e. a service without any H.264 or generic MPEG4 video streams) |
HTTP | 0x0005 |
HTTP service |
MJPEG | 0x0006 |
HTTP service with a Motion JPEG endpoint |
Locked MJPEG | 0x0007 |
locked HTTP service believed to have a Motion JPEG endpoint, the path and the credentials are not known |
TCP | 0xffff |
TCP service (used for manual forwarding) |
0 32
+------------+---+
| reserved | S |
+------------+---+
-
S
- bit flag;1
if the network scanner is running,0
otherwise
Code | Name | Description |
---|---|---|
0x00000000 |
NO_ERROR | OK |
0x00000001 |
UNSUPPORTED_PROTOCOL_VERSION | unsupported version of the Arrow protocol |
0x00000002 |
UNAUTHORIZED | access denied (client is not registered) |
0x00000003 |
CONNECTION_ERROR | cannot connect to a given service |
0x00000004 |
UNSUPPORTED_METHOD | unsupported method |
0xffffffff |
INTERNAL_SERVER_ERROR | internal server error |
There are three different connection states:
- handshake - initial state, server is waiting for client's REGISTER request, after sending ACK response, the connection is either established or disconnected (no other message types are allowed)
- established - normal operation state, all message types except REGISTER are allowed
- disconnected - no more messages are accepted, connection will be closed immediately
The pairing procedure is used to verify identity of a customer on his attempt to add a device under his Angelcam account. It consists of the following steps:
- An unpaired Arrow Client attempts to connect to a well-known Arrow Service sending its UUID, passphrase and MAC address.
- The service rejects the connection as it does not know the device. Any other registration attempts received from the device will be rejected until there is a corresponding pairing request for the device MAC address.
- A customer willing to add his Arrow Client under his Angelcam account generates a unique QR code using Angelcam website. MAC address of the device is requested in order to identify the device.
- The Arrow Service accepts the client for a limited period of time on its next connection attempt.
- The Angelcam web interface displays a list of video streams provided by the device.
- The customer selects a single MAC address from the list.
- Angelcam QR code reader connects to the corresponding video stream for a limited period of time and waits for the QR code.
- The client points his QR code to the IP camera he selected.
- Once the QR code is verified, the Arrow Client is accepted permanently and linked to the customer's user account.
This procedure is used in case of a registration request received from an already paired client. It consists of the following steps:
- An Arrow Client attempts to connect to a well-known Arrow Service sending its UUID, passphrase and MAC address.
- The service verifies the passphrase and sends an ACK message.
An Arrow client MUST support multiple sessions per service. Every session is basically a separate connection to the service. This is the expected behavior:
- If the client receives a CONNECT message with unknown
svc_id
, it MUST respond with a HUP packet, where thesession_id
field will be set to the value from the received message. - If the client receives a CONNECT message with known
svc_id
but unknownsession_id
, it MUST create a new connection to the corresponding service. The connection will be used then for all following communication labelled with the given session ID. - If the client receives a CONNECT message with known
svc_id
andsession_id
that has already been associated with a different connection, it MUST respond with a HUP packet, where thesession_id
field will be set to the value from the received message. - If the client receives a data message with unknown
session_id
, it MUST respond with a HUP packet, where thesession_id
field will be set to the value from the received message. - If the client receives a data message with a known
session_id
, it passes the message body to the corresponding connection (i.e. a connection that was previously opened for the session ID). - If a session connection yields any data (i.e. the local service sends something), the data must be sent to the Arrow Service as Arrow Message body. The message MUST have the corresponding
svc_id
andsession_id
fields set correctly for the session. - If the client receives a HUP packet from the Arrow Service, it MUST close the corresponding session connection.
- If a session connection gets closed by the corresponding local service, the client MUST send a HUP packet with the corresponding
svc_id
andsession_id
to the Arrow Service. - If the client sends a message with
session_id
that is not known to the Arrow Service, the Arrow Service will respond with a HUP packet.
Each side is allowed to send only a certain amount of data into the session channel. This is the session capacity. The exact capacity is specified by the client as window_size
in the REGISTER message. It is an error to send more data into the session channel and the remote peer MUST respond with a HUP message in such situation. Once either side is ready to receive more data (e.g. after forwarding its internal buffer to the corresponding connection), it SHOULD send a DATA_ACK message specifying the number of additional bytes it is willing to accept.
Revision | Description |
---|---|
v0.1.0 |
initial revision |
v0.1.1 |
added the Unknown RTSP service type |
v0.1.2 |
added the Unsupported RTSP service type |
v0.1.3 |
added the HTTP and TCP service types |
v1.0.0 |
added scan report messages and support for optional message types in the Control Protocol |
v1.1.0 |
added the MJPEG and Locked MJPEG service types |
v1.1.1 |
added detailed explanation of session handling |
v2.0.0 |
added session flow control and extended REGISTER message |