Skip to content

Arrow Protocol

Ondřej Perutka edited this page Jul 12, 2023 · 7 revisions

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.

Contents

Roles

There are two roles recognized by this protocol:

  • Arrow Service
  • Arrow Client

Arrow Service

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.

Arrow Client

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

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).

Messages

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

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.

ACK message

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 message

Ping request used for connection health checks. It is periodically sent by both - server and client. The message contains no data. ACK is expected.

REGISTER message

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 (setting window_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)
REDIRECT message

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).

UPDATE message

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.

HUP message

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)
RESET_SVC_TABLE message

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.

SCAN_NETWORK message

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.

GET_STATUS message

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).

STATUS message

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
GET_SCAN_REPORT message

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.

SCAN_REPORT message

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
DATA_ACK message

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
CONNECT 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 structure

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).

Service types
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)
Status flags
0              32
+------------+---+
| reserved   | S |
+------------+---+
  • S - bit flag; 1 if the network scanner is running, 0 otherwise
ACK/HUP error codes
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

Protocol states

There are three different connection states:

  1. 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)
  2. established - normal operation state, all message types except REGISTER are allowed
  3. disconnected - no more messages are accepted, connection will be closed immediately

Procedures

Pairing procedure

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:

  1. An unpaired Arrow Client attempts to connect to a well-known Arrow Service sending its UUID, passphrase and MAC address.
  2. 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.
  3. 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.
  4. The Arrow Service accepts the client for a limited period of time on its next connection attempt.
  5. The Angelcam web interface displays a list of video streams provided by the device.
  6. The customer selects a single MAC address from the list.
  7. Angelcam QR code reader connects to the corresponding video stream for a limited period of time and waits for the QR code.
  8. The client points his QR code to the IP camera he selected.
  9. Once the QR code is verified, the Arrow Client is accepted permanently and linked to the customer's user account.

Standard handshake procedure

This procedure is used in case of a registration request received from an already paired client. It consists of the following steps:

  1. An Arrow Client attempts to connect to a well-known Arrow Service sending its UUID, passphrase and MAC address.
  2. The service verifies the passphrase and sends an ACK message.

Sessions

An Arrow client MUST support multiple sessions per service. Every session is basically a separate connection to the service. This is the expected behavior:

  1. If the client receives a CONNECT message with unknown svc_id, it MUST respond with a HUP packet, where the session_id field will be set to the value from the received message.
  2. If the client receives a CONNECT message with known svc_id but unknown session_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.
  3. If the client receives a CONNECT message with known svc_id and session_id that has already been associated with a different connection, it MUST respond with a HUP packet, where the session_id field will be set to the value from the received message.
  4. If the client receives a data message with unknown session_id, it MUST respond with a HUP packet, where the session_id field will be set to the value from the received message.
  5. 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).
  6. 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 and session_id fields set correctly for the session.
  7. If the client receives a HUP packet from the Arrow Service, it MUST close the corresponding session connection.
  8. If a session connection gets closed by the corresponding local service, the client MUST send a HUP packet with the corresponding svc_id and session_id to the Arrow Service.
  9. 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.

Flow control

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.

Revisions

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