Skip to content

Latest commit

 

History

History
1259 lines (919 loc) · 66.3 KB

Protocol.md

File metadata and controls

1259 lines (919 loc) · 66.3 KB

Introduction

RSocket is an application protocol that provides Reactive Streams semantics across a network, asynchronous, binary boundary.

For more information, please see rsocket.io.

RSocket assumes an operating paradigm. These assumptions are:

  • one-to-one communication
  • non-proxied communication. Or if proxied, the RSocket semantics and assumptions are preserved across the proxy.
  • no state preserved across transport protocol sessions by the protocol

Keywords used by this document conform to the meanings in RFC 2119.

Byte ordering is big endian for all fields.

Table of Contents

Terminology

  • Frame: A single message containing a request, response, or protocol processing.
  • Fragment: A portion of an application message that has been partitioned for inclusion in a Frame. See Fragmentation and Reassembly.
  • Transport: Protocol used to carry RSocket protocol. One of WebSockets, TCP, or Aeron. The transport MUST provide capabilities mentioned in the transport protocol section.
  • Stream: Unit of operation (request/response, etc.). See Motivations.
  • Request: A stream request. May be one of four types. As well as request for more items or cancellation of previous request.
  • Payload: A stream message (upstream or downstream). Contains data associated with a stream created by a previous request. In Reactive Streams and Rx this is the 'onNext' event.
  • Complete: Terminal event sent on a stream to signal successful completion. In Reactive Streams and Rx this is the 'onComplete' event.
    • A frame (PAYLOAD or REQUEST_CHANNEL) with the Complete bit set is sometimes referred to as COMPLETE in this document when reference to the frame is semantically about the Complete bit/event.
  • Client: The side initiating a connection.
  • Server: The side accepting connections from clients.
  • Connection: The instance of a transport session between client and server.
  • Requester: The side sending a request. A connection has at most 2 Requesters. One in each direction.
  • Responder: The side receiving a request. A connection has at most 2 Responders. One in each direction.

Versioning Scheme

RSocket follows a versioning scheme consisting of a numeric major version and a numeric minor version.

Cross version compatibility

RSocket assumes that all version changes (major and minor) are backward incompatible. A client can pass a version that it supports via the Setup Frame. It is up to a server to accept clients of lower versions than what it supports.

Data And Metadata

RSocket provides mechanisms for applications to differentiate between two types of content within a payload, Data and Metadata, with the distinction left to applications to make use of according to their needs.

The following are features of Data and Metadata.

  • Metadata can be encoded differently than Data.
  • Metadata can be "attached" (i.e. correlated) with the following entities:
    • Connection via Metadata Push and Stream ID of 0
    • Individual Request or Payload (upstream or downstream)

Framing

Transport Protocol

The RSocket protocol uses a lower level transport protocol to carry RSocket frames. A transport protocol MUST provide the following:

  1. Unicast Reliable Delivery, i.e. between a single sender and a single receiver with "at least once" message delivery guarantees.
  2. Connection-Oriented along with preservation of frame ordering. If Frame A is sent by the same source as Frame B, then Frame A will always arrive before Frame B. No assumptions about ordering across sources is assumed.
  3. Frame Check Sequence, FCS for short, is assumed to be in use either at the transport protocol or at each MAC layer hop. However, no protection against malicious corruption is assumed.

An implementation MAY "close" a transport connection due to protocol processing. When this occurs, it is assumed that the connection will have no further frames sent and all frames will be ignored.

RSocket as specified here has been designed for and tested with TCP, WebSocket, Aeron, and HTTP/2 streams as transport protocols.

Framing Protocol Usage

Some supported transport protocols for RSocket may not support specific framing that preserves message boundaries. For these protocols, a framing protocol MUST be used with the RSocket frame that prepends the RSocket Frame Length.

The frame length field MUST be omitted if the transport protocol preserves message boundaries e.g. provides compatible framing. If, however, the transport protocol only provides a stream abstraction or can merge messages without preserving boundaries, or multiple transport protocols may be used, then the frame header MUST be used.

Transport Protocol Frame Length Field Required
TCP YES
WebSocket NO
Aeron NO
HTTP/2 Stream YES

Framing Format

When using a transport protocol providing framing, the RSocket frame is simply encapsulated into the transport protocol messages directly.

    +-----------------------------------------------+
    |                RSocket Frame          ...
    |                                              
    +-----------------------------------------------+

When using a transport protocol that does not provide compatible framing, the Frame Length MUST be prepended to the RSocket Frame.

     0                   1                   2
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                    Frame Length               |
    +-----------------------------------------------+
    |                RSocket Frame          ...
    |                                              
    +-----------------------------------------------+
  • Frame Length: (24 bits = max value 16,777,215) Unsigned 24-bit integer representing the length of Frame in bytes. Excluding the Frame Length field.

NOTE: Byte ordering is big endian.

Max Frame Size

RSocket Frames (Header + Payload) MUST be limited to 16,777,215 bytes, regardless of whether the utilized transport protocol requires the Frame Length field.

Frame Header Format

RSocket frames begin with a RSocket Frame Header. The general layout is given below.

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |0|                         Stream ID                           |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |I|M|     Flags     |     Depends on Frame Type    ...
    +-------------------------------+
  • Stream ID: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer representing the stream Identifier for this frame or 0 to indicate the entire connection.
    • Transport protocols that include demultiplexing, such as HTTP/2, MAY omit the Stream ID field if all parties agree. The means of negotiation and agreement is left to the transport protocol.
  • Frame Type: (6 bits = max value 63) Type of Frame.
  • Flags: (10 bits) Any Flag bit not specifically indicated in the frame type should be set to 0 when sent and not interpreted on reception. Flags generally depend on Frame Type, but all frame types MUST provide space for the following flags:
    • (I)gnore: Ignore frame if not understood
    • (M)etadata: Metadata present

NOTE: Byte ordering is big endian.

Handling Ignore Flag

The (I)gnore flag is used for extension of the protocol. A value of 0 in a frame for this flag indicates the protocol can't ignore this frame. An implementation MAY send an ERROR[CONNECTION_ERROR] frame and close the underlying transport connection on reception of a frame that it does not understand with this bit not set.

Frame Validation

RSocket implementations may provide their own validation at the metadata level for specific frames. However, this is an application concern and not necessary for protocol processing.

Metadata Optional Header

Specific Frame Types MAY contain Metadata. If that Frame Type supports both Data and Metadata, the optional Metadata header MUST be included. This metadata header is between the Frame Header and any payload.

Metadata Length MUST be equal to the Frame Length minus the sum of the length of the Frame Header and the length of the Frame Payload, if present. If Metadata Length is not equal to this value, the frame is invalid and the receiver MUST send an ERROR[CONNECTION_ERROR] frame and close the underlying transport connection on reception unless the frame's IGNORE flag is set.

On a frame with Data and Metadata:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |              Metadata Length                  |
    +---------------------------------------------------------------+
    |                       Metadata Payload                       ...
    +---------------------------------------------------------------+
    |                       Payload of Frame                       ...
    +---------------------------------------------------------------+

On a frame that supports Data and Metadata, but Data length is 0:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |              Metadata Length                  |
    +---------------------------------------------------------------+
    |                       Metadata Payload                       ...
    +---------------------------------------------------------------+

On a frame that only has Metadata, the Metadata length field is NOT needed:

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                       Metadata Payload                       ...
    +---------------------------------------------------------------+
  • Metadata Length: (24 bits = max value 2^24-1 = 16,777,215) Unsigned 24-bit integer representing the length of Metadata in bytes. Excluding Metadata Length field.

Stream Identifiers

Generation

Stream IDs are generated by a Requester. The lifetime of a Stream ID is determined by the request type, and the semantics of the stream based on its type.

Stream ID of value 0 is reserved for any operation involving the connection.

A Stream ID MUST be locally unique for a Requester in a connection.

Stream ID generation follows general guidelines for HTTP/2 with respect to odd/even values. In other words, a client MUST generate odd Stream IDs, and a server MUST generate even Stream IDs.

Stream IDs on the client MUST start at 1 and increment by 2 sequentially, such as 1, 3, 5, 7, etc.

Stream IDs on the server MUST start at 2 and increment by 2 sequentially, such as 2, 4, 6, 8, etc.

Lifetime

Once the max Stream ID has been used (2^31-1), the Requester MAY re-use Stream IDs. A Responder MUST assume Stream IDs will be re-used.

When the max Stream ID has been used:

  1. If Stream ID re-use is not employed:

    • No new streams can be created, thus a new connection MUST be established to create new streams once the max has been met.
  2. If Stream IDs are re-used:

    • The Requester MUST re-use IDs by wrapping and restarting at ID 1 for client, and ID 2 for server, and incrementing sequentially by 2s as stated above.
    • The Requester MUST skip IDs still in use.
    • The Responder MAY choose to ERROR[REJECT] any Stream ID if it considers the ID still in use. The Requester MAY retry on the next sequential Stream ID considered unused.
    • If all Stream IDs are concurrently in use, no new streams can be created, thus a new connection MUST be established to create new streams.

It is RECOMMENDED that Stream ID re-use only be used in combination with resumability.

Frame Types

Type Value Description
RESERVED 0x00 Reserved
SETUP 0x01 Setup: Sent by client to initiate protocol processing.
LEASE 0x02 Lease: Sent by Responder to grant the ability to send requests.
KEEPALIVE 0x03 Keepalive: Connection keepalive.
REQUEST_RESPONSE 0x04 Request Response: Request single response.
REQUEST_FNF 0x05 Fire And Forget: A single one-way message.
REQUEST_STREAM 0x06 Request Stream: Request a completable stream.
REQUEST_CHANNEL 0x07 Request Channel: Request a completable stream in both directions.
REQUEST_N 0x08 Request N: Request N more items with Reactive Streams semantics.
CANCEL 0x09 Cancel Request: Cancel outstanding request.
PAYLOAD 0x0A Payload: Payload on a stream. For example, response to a request, or message on a channel.
ERROR 0x0B Error: Error at connection or application level.
METADATA_PUSH 0x0C Metadata: Asynchronous Metadata frame
RESUME 0x0D Resume: Replaces SETUP for Resuming Operation (optional)
RESUME_OK 0x0E Resume OK : Sent in response to a RESUME if resuming operation possible (optional)
EXT 0x3F Extension Header: Used To Extend more frame types as well as extensions.

SETUP Frame (0x01)

Setup frames MUST always use Stream ID 0 as they pertain to the connection.

The SETUP frame is sent by the client to inform the server of the parameters under which it desires to operate. The usage and message sequence used is shown in Connection Establishment.

One of the important parameters for a connection is the format, layout, and any schema of the data and metadata for frames. This is, for lack of a better term, referred to here as "MIME Type". An implementation MAY use typical MIME type values or MAY decide to use specific non-MIME type values to indicate format, layout, and any schema for data and metadata. The protocol implementation MUST NOT interpret the MIME type itself. This is an application concern only.

The encoding format for Data and Metadata are included separately in the SETUP.

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                         Stream ID = 0                         |
    +-----------+-+-+-+-+-----------+-------------------------------+
    |Frame Type |0|M|R|L|  Flags    |
    +-----------+-+-+-+-+-----------+-------------------------------+
    |         Major Version         |        Minor Version          |
    +-------------------------------+-------------------------------+
    |0|                 Time Between KEEPALIVE Frames               |
    +---------------------------------------------------------------+
    |0|                       Max Lifetime                          |
    +---------------------------------------------------------------+
    |         Token Length          | Resume Identification Token  ...
    +---------------+-----------------------------------------------+
    |  MIME Length  |   Metadata Encoding MIME Type                ...
    +---------------+-----------------------------------------------+
    |  MIME Length  |     Data Encoding MIME Type                  ...
    +---------------+-----------------------------------------------+
                          Metadata & Setup Payload
  • Frame Type: (6 bits) 0x01
  • Flags: (10 bits)
    • (M)etadata: Metadata present
    • (R)esume Enable: Client requests resume capability if possible. Resume Identification Token present.
    • (L)ease: Will honor LEASE (or not).
  • Major Version: (16 bits = max value 65,535) Unsigned 16-bit integer of Major version number of the protocol.
  • Minor Version: (16 bits = max value 65,535) Unsigned 16-bit integer of Minor version number of the protocol.
  • Time Between KEEPALIVE Frames: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer of Time (in milliseconds) between KEEPALIVE frames that the client will send. Value MUST be > 0.
    • For server-to-server connections, a reasonable time interval between client KEEPALIVE frames is 500ms.
    • For mobile-to-server connections, the time interval between client KEEPALIVE frames is often > 30,000ms.
  • Max Lifetime: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer of Time (in milliseconds) that a client will allow a server to not respond to a KEEPALIVE before it is assumed to be dead. Value MUST be > 0.
  • Resume Identification Token Length: (16 bits = max value 65,535) Unsigned 16-bit integer of Resume Identification Token Length in bytes. (Not present if R flag is not set)
  • Resume Identification Token: Token used for client resume identification (Not present if R flag is not set)
  • MIME Length: Encoding MIME Type Length in bytes.
  • Encoding MIME Type: MIME Type for encoding of Data and Metadata. This SHOULD be a US-ASCII string that includes the Internet media type specified in RFC 2045. Many are registered with IANA such as CBOR. Suffix rules MAY be used for handling layout. For example, application/x.netflix+cbor or application/x.reactivesocket+cbor or application/x.netflix+json. The string MUST NOT be null terminated.
  • Setup Data: includes payload describing connection capabilities of the endpoint sending the Setup header.

NOTE: A server that receives a SETUP frame that has (R)esume Enabled set, but does not support resuming operation, MUST reject the SETUP with an ERROR[REJECTED_SETUP].

ERROR Frame (0x0B)

Error frames are used for errors on individual requests/streams as well as connection errors and in response to SETUP frames.

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|0|      Flags    |
    +-----------+-+-+---------------+-------------------------------+
    |                          Error Code                           |
    +---------------------------------------------------------------+
                               Error Data
  • Frame Type: (6 bits) 0x0B
  • Error Code: (32 bits = max value 2^31-1 = 2,147,483,647) Type of Error.
    • See list of valid Error Codes below.
  • Error Data: includes Payload describing error information. Error Data SHOULD be a UTF-8 encoded string. The string MUST NOT be null terminated.

A Stream ID of 0 means the error pertains to the connection., including connection establishment. A Stream ID > 0 means the error pertains to a given stream.

The Error Data is typically an Exception message, but could include stringified stacktrace information if appropriate.

Error Codes

Type Value Description
RESERVED 0x00000000 Reserved
INVALID_SETUP 0x00000001 The Setup frame is invalid for the server (it could be that the client is too recent for the old server). Stream ID MUST be 0.
UNSUPPORTED_SETUP 0x00000002 Some (or all) of the parameters specified by the client are unsupported by the server. Stream ID MUST be 0.
REJECTED_SETUP 0x00000003 The server rejected the setup, it can specify the reason in the payload. Stream ID MUST be 0.
REJECTED_RESUME 0x00000004 The server rejected the resume, it can specify the reason in the payload. Stream ID MUST be 0.
CONNECTION_ERROR 0x00000101 The connection is being terminated. Stream ID MUST be 0. Sender or Receiver of this frame MAY close the connection immediately without waiting for outstanding streams to terminate.
CONNECTION_CLOSE 0x00000102 The connection is being terminated. Stream ID MUST be 0. Sender or Receiver of this frame MUST wait for outstanding streams to terminate before closing the connection. New requests MAY not be accepted.
APPLICATION_ERROR 0x00000201 Application layer logic generating a Reactive Streams onError event. Stream ID MUST be > 0.
REJECTED 0x00000202 Despite being a valid request, the Responder decided to reject it. The Responder guarantees that it didn't process the request. The reason for the rejection is explained in the Error Data section. Stream ID MUST be > 0.
CANCELED 0x00000203 The Responder canceled the request but may have started processing it (similar to REJECTED but doesn't guarantee lack of side-effects). Stream ID MUST be > 0.
INVALID 0x00000204 The request is invalid. Stream ID MUST be > 0.
RESERVED 0xFFFFFFFF Reserved for Extension Use

NOTE: Unsed values in the range of 0x0001 to 0x00300 are reserved for future protocol use. Values in the range of 0x00301 to 0xFFFFFFFE are reserved for application layer errors.

When this document refers to a specific Error Code as a frame, it uses this pattern: ERROR[error_code] or ERROR[error_code|error_code]

For example:

  • ERROR[INVALID_SETUP] means the ERROR frame with the INVALID_SETUP code
  • ERROR[REJECTED] means the ERROR frame with the REJECTED code
  • ERROR[CONNECTION_ERROR|REJECTED_RESUME] means the ERROR frame with either the CONNECTION_ERROR or REJECTED_RESUME code

LEASE Frame (0x02)

Lease frames MAY be sent by the client-side or server-side Responders and inform the Requester that it may send Requests for a period of time and how many it may send during that duration. See Lease Semantics for more information.

The last received LEASE frame overrides all previous LEASE frame values.

Lease frames MUST always use Stream ID 0 as they pertain to the Connection.

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                         Stream ID = 0                         |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|M|     Flags     |
    +-----------+-+-+---------------+-------------------------------+
    |0|                       Time-To-Live                          |
    +---------------------------------------------------------------+
    |0|                     Number of Requests                      |
    +---------------------------------------------------------------+
                                Metadata
  • Frame Type: (6 bits) 0x02
  • Flags: (10 bits)
    • (M)etadata: Metadata present
  • Time-To-Live (TTL): (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer of Time (in milliseconds) for validity of LEASE from time of reception. Value MUST be > 0.
  • Number of Requests: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer of Number of Requests that may be sent until next LEASE. Value MUST be > 0.

A Responder implementation MAY stop all further requests by sending a LEASE with a value of 0 for Number of Requests or Time-To-Live.

When a LEASE expires due to time, the value of the Number of Requests that a Requester may make is implicitly 0.

This frame only supports Metadata, so the Metadata Length header MUST NOT be included, even if the (M)etadata flag is set true.

KEEPALIVE Frame (0x03)

KEEPALIVE frames MUST always use Stream ID 0 as they pertain to the Connection.

KEEPALIVE frames MUST be initiated by the client and sent periodically with the (R)espond flag set.

KEEPALIVE frames MAY be initiated by the server and sent upon application request with the (R)espond flag set.

Reception of a KEEPALIVE frame with the (R)espond flag set MUST cause a client or server to send back a KEEPALIVE with the (R)espond flag NOT set. The data in the received KEEPALIVE MUST be echoed back in the generated KEEPALIVE.

Reception of a KEEPALIVE by a server indicates to the server that the client is alive.

Reception of a KEEPALIVE by a client indicates to the client that the server is alive.

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                         Stream ID = 0                         |
    +-----------+-+-+-+-------------+-------------------------------+
    |Frame Type |0|0|R|    Flags    |
    +-----------+-+-+-+-------------+-------------------------------+
    |0|                  Last Received Position                     |
    +                                                               +
    |                                                               |
    +---------------------------------------------------------------+
                                  Data
  • Frame Type: (6 bits) 0x03
  • Flags: (10 bits)
    • (R)espond with KEEPALIVE or not
  • Last Received Position: (63 bits = max value 2^63-1) Unsigned 63-bit long of Resume Last Received Position. Value MUST be > 0. (optional. Set to all 0s when not supported.)
  • Data: Data attached to a KEEPALIVE.

REQUEST_RESPONSE Frame (0x04)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+-+-------------+-------------------------------+
    |Frame Type |0|M|F|     Flags   |
    +-------------------------------+
                         Metadata & Request Data
  • Frame Type: (6 bits) 0x04
  • Flags: (10 bits)
    • (M)etadata: Metadata present
    • (F)ollows: More fragments follow this fragment.
  • Request Data: identification of the service being requested along with parameters for the request.

REQUEST_FNF (Fire-n-Forget) Frame (0x05)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+-+-------------+-------------------------------+
    |Frame Type |0|M|F|    Flags    |
    +-------------------------------+
                          Metadata & Request Data
  • Frame Type: (6 bits) 0x05
  • Flags: (10 bits)
    • (M)etadata: Metadata present
    • (F)ollows: More fragments follow this fragment.
  • Request Data: identification of the service being requested along with parameters for the request.

REQUEST_STREAM Frame (0x06)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+-+-------------+-------------------------------+
    |Frame Type |0|M|F|    Flags    |
    +-------------------------------+-------------------------------+
    |0|                    Initial Request N                        |
    +---------------------------------------------------------------+
                          Metadata & Request Data
  • Frame Type: (6 bits) 0x06
  • Flags: (10 bits)
    • (M)etadata: Metadata present
    • (F)ollows: More fragments follow this fragment.
  • Initial Request N: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer representing the initial number of items to request. Value MUST be > 0.
  • Request Data: identification of the service being requested along with parameters for the request.

See Flow Control: Reactive Streams Semantics for more information on RequestN behavior.

REQUEST_CHANNEL Frame (0x07)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+-+-+-----------+-------------------------------+
    |Frame Type |0|M|F|C|  Flags    |
    +-------------------------------+-------------------------------+
    |0|                    Initial Request N                        |
    +---------------------------------------------------------------+
                           Metadata & Request Data
  • Frame Type: (6 bits) 0x07
  • Flags: (10 bits)
    • (M)etadata: Metadata present
    • (F)ollows: More fragments follow this fragment.
    • (C)omplete: bit to indicate stream completion.
      • If set, onComplete() or equivalent will be invoked on Subscriber/Observer.
  • Initial Request N: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer representing the initial request N value for channel. Value MUST be > 0.
  • Request Data: identification of the service being requested along with parameters for the request.

A requester MUST send only one REQUEST_CHANNEL frame. Subsequent messages from requester to responder MUST be sent as PAYLOAD frames.

A requester MUST not send PAYLOAD frames after the REQUEST_CHANNEL frame until the responder sends a REQUEST_N frame granting credits for number of PAYLOADs able to be sent.

See Flow Control: Reactive Streams Semantics for more information on RequestN behavior.

REQUEST_N Frame (0x08)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|0|     Flags     |
    +-------------------------------+-------------------------------+
    |0|                         Request N                           |
    +---------------------------------------------------------------+
  • Frame Type: (6 bits) 0x08
  • Request N: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer representing the number of items to request. Value MUST be > 0.

See Flow Control: Reactive Streams Semantics for more information on RequestN behavior.

CANCEL Frame (0x09)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|0|    Flags      |
    +-------------------------------+-------------------------------+
  • Frame Type: (6 bits) 0x09

PAYLOAD Frame (0x0A)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+-+-+-+---------+-------------------------------+
    |Frame Type |0|M|F|C|N|  Flags  |
    +-------------------------------+-------------------------------+
                         Metadata & Data
  • Frame Type: (6 bits) 0x0A
  • Flags: (10 bits)
    • (M)etadata: Metadata Present.
    • (F)ollows: More fragments follow this fragment.
    • (C)omplete: bit to indicate stream completion.
      • If set, onComplete() or equivalent will be invoked on Subscriber/Observer.
    • (N)ext: bit to indicate Next (Payload Data and/or Metadata present).
      • If set, onNext(Payload) or equivalent will be invoked on Subscriber/Observer.
  • Payload Data: payload for Reactive Streams onNext.

Valid combinations of (C)omplete and (N)ext flags are:

  • Both (C)omplete and (N)ext set meaning PAYLOAD contains data and signals stream completion.
    • For example: An Observable stream receiving onNext(payload) followed by onComplete().
  • Just (C)omplete set meaning PAYLOAD contains no data and only signals stream completion.
    • For example: An Observable stream receiving onComplete().
  • Just (N)ext set meaning PAYLOAD contains data stream is NOT completed.
    • For example: An Observable stream receiving onNext(payload).

A PAYLOAD MUST NOT have both (C)complete and (N)ext empty (false).

The reason for the (N)ext flag instead of just deriving from Data length being > 0 is that 0 length data can be considered a valid PAYLOAD resulting in a delivery to the application layer with a PAYLOAD containing 0 bytes of data.

For example: An Observable stream receiving data via onNext(payload) where payload contains 0 bytes of data.

METADATA_PUSH Frame (0x0C)

A Metadata Push frame can be used to send asynchronous metadata notifications from a Requester or Responder to its peer.

METADATA_PUSH frames MUST always use Stream ID 0 as they pertain to the Connection.

Metadata tied to a particular stream uses the individual Payload frame Metadata flag.

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                         Stream ID = 0                         |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|1|     Flags     |
    +-------------------------------+-------------------------------+
                                Metadata
  • Frame Type: (6 bits) 0x0C

This frame only supports Metadata, so the Metadata Length header MUST NOT be included.

EXT (Extension) Frame (0x3F)

The general format for an extension frame is given below.

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |I|M|    Flags      |
    +-------------------------------+-------------------------------+
    |0|                      Extended Type                          |
    +---------------------------------------------------------------+
                          Depends on Extended Type...
  • Frame Type: (6 bits) 0x3F
  • Flags: (10 bits)
    • (I)gnore: Can the frame be ignored if not understood?
    • (M)etadata: Metadata Present.
  • Extended Type: (31 bits = max value 2^31-1 = 2,147,483,647) Unsigned 31-bit integer of Extended type information. Value MUST be > 0.

Resuming Operation

Due to the large number of active requests for RSocket, it is often necessary to provide the ability for resuming operation on transport failure. This behavior is totally optional for operation and may be supported or not based on an implementation choice.

Assumptions

RSocket resumption exists only for specific cases. It is not intended to be an “always works” solution. If resuming operation is not possible, the connection should be terminated with an ERROR as specified by the protocol definition.

  1. Resumption is optional behavior for implementations. But highly suggested. Clients and Servers should assume NO resumption capability by default.
  2. Resumption is an optimistic operation. It may not always succeed.
  3. Resumption is desired to be fast and require a minimum of state to be exchanged.
  4. Resumption is designed for loss of connectivity and assumes client and server state is maintained across connectivity loss. I.e. there is no assumption of loss of state by either end. This is very important as without it, all the requirements of "guaranteed messaging" come into play.
  5. Resumption assumes no changes to Lease, Data format (encoding), etc. for resuming operation. i.e. A client is not allowed to change the metadata MIME type or the data MIME type or version, etc. when resuming operation.
  6. Resumption is always initiated by the client and either allowed or denied by the server.
  7. Resumption makes no assumptions of application state for delivered frames with respect to atomicity, transactionality, etc. See above.

Implied Position

Resuming operation requires knowing the position of data reception of the previous connection. For this to be simplified, the underlying transport is assumed to support contiguous delivery of data on a per frame basis. In other words, partial frames are not delivered for processing nor are gaps allowed in the stream of frames sent by either the client or server. The current list of supported transports (TCP, WebSocket, and Aeron) all satisfy this requirement or can be made to do so in the case of TCP.

As a Requester or Responder sends REQUEST_RESPONSE, REQUEST_FNF, REQUEST_STREAM, REQUEST_CHANNEL, REQUEST_N, CANCEL, ERROR, or PAYLOAD frames, it maintains a position of that frame within the connection in that direction. This is a 64-bit value that starts at 0. As a Requester or Responder receives those tracked frames, it maintains an implied position of that frame within the connection in that direction. This is also a 64-bit value that starts at 0. The positions are calculated based on the length of encoded frames without the frame length field after any fragmentation is applied.

The reason this is “implied” is that the position is not included in each frame and is inferred simply by the message being sent/received on the connection in relation to previous frames.

This position will be used to identify the location for resuming operation to begin.

Frame types outside REQUEST(s), REQUEST_N, CANCEL, ERROR, and PAYLOAD do not have assigned (nor implied) positions.

When a client sends a RESUME frame, it sends two implied positions: the last frame that was received from the server; the earliest frame position it still retains. The server can make a determination on whether resumption is possible: have all frames past the client's last-received position been retained? and has the client retained all frames past the server's last-retained position. If resumption is allowed to continue, the server sends a RESUME_OK frame, indicating its last-received position.

Client Lifetime Management

Client lifetime management for servers MUST be extended to incorporate the length of time a client may successfully attempt resumption passed a transport disconnect. The means of client lifetime management are totally up to the implementation.

Resume Operation

All ERROR frames sent MUST be CONNECTION_ERROR or REJECTED_RESUME error code.

Client side resumption operation starts when the client desires to try to resume and starts a new transport connection. The operation then proceeds as the following:

  • Client sends RESUME frame. The client MUST NOT send any other frame types until resumption succeeds. The RESUME Identification Token MUST be the token used in the original SETUP frame. The RESUME Last Received Position field MUST be the last successfully received implied position from the server.
  • Client waits for either a RESUME_OK or ERROR[CONNECTION_ERROR|REJECTED_RESUME] frame from the server.
  • On receiving an ERROR[REJECTED_RESUME] frame, the client MUST NOT attempt resumption again.
  • On receiving a RESUME_OK, the client:
    • MUST assume that the next REQUEST, CANCEL, ERROR, and PAYLOAD frames have an implied position commencing from the last implied positions
    • MAY retransmit all REQUEST, CANCEL, ERROR, and PAYLOAD frames starting at the RESUME_OK Last Received Position field value from the server.
    • MAY send an ERROR[CONNECTION_ERROR|CONNECTION_CLOSE] frame indicating the end of the connection and MUST NOT attempt resumption again

Server side resumption operation starts when the client sends a RESUME frame. The operation then proceeds as the following:

  • On receiving a RESUME frame, the server:
    • MUST send an ERROR[REJECTED_RESUME] frame if the server does not support resuming operation.
    • use the RESUME Identification Token field to determine which client the resume pertains to. If the client is identified successfully, resumption MAY be continued. If not identified, then the server MUST send an ERROR[REJECTED_RESUME] frame.
    • if successfully identified, then the server MAY send a RESUME_OK and then:
      • MUST assume that the next REQUEST, CANCEL, ERROR, and PAYLOAD frames have an implied position commencing from the last implied positions
      • MAY retransmit all REQUEST, CANCEL, ERROR, and PAYLOAD frames starting at the RESUME Last Received Position field value from the client.
    • if successfully identified, then the server MAY send an ERROR[REJECTED_RESUME] frame if the server can not resume operation given the value of RESUME Last Received Position if the position is not one it deems valid to resume operation from or other extenuating circumstances.

A Server that receives a RESUME frame after a SETUP frame, SHOULD send an ERROR[CONNECTION_ERROR].

A Server that receives a RESUME frame after a previous RESUME frame, SHOULD send an ERROR[CONNECTION_ERROR].

Leasing semantics are NOT assumed to carry over from previous connections when resuming. LEASE semantics MUST be restarted upon a new connection by sending a LEASE frame from the server.

RESUME Frame (0x0D)

The general format for a Resume frame is given below.

RESUME frames MUST always use Stream ID 0 as they pertain to the connection.

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                         Stream ID = 0                         |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|0|    Flags      |
    +-------------------------------+-------------------------------+
    |        Major Version          |         Minor Version         |
    +-------------------------------+-------------------------------+
    |         Token Length          | Resume Identification Token  ...
    +---------------------------------------------------------------+
    |0|                                                             |
    +                 Last Received Server Position                 +
    |                                                               |
    +---------------------------------------------------------------+
    |0|                                                             |
    +                First Available Client Position                +
    |                                                               |
    +---------------------------------------------------------------+
  • Frame Type: (6 bits) 0x0D
  • Major Version: (16 bits = max value 65,535) Unsigned 16-bit integer of Major version number of the protocol.
  • Minor Version: (16 bits = max value 65,535) Unsigned 16-bit integer of Minor version number of the protocol.
  • Resume Identification Token Length: (16 bits = max value 65,535) Unsigned 16-bit integer of Resume Identification Token Length in bytes.
  • Resume Identification Token: Token used for client resume identification. Same Resume Identification used in the initial SETUP by the client.
  • Last Received Server Position: (63 bits = max value 2^63-1) Unsigned 63-bit long of the last implied position the client received from the server.
  • First Available Client Position: (63 bits = max value 2^63-1) Unsigned 63-bit long of the earliest position that the client can rewind back to prior to resending frames.

RESUME_OK Frame (0x0E)

The general format for a Resume OK frame is given below.

RESUME OK frames MUST always use Stream ID 0 as they pertain to the connection.

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                         Stream ID = 0                         |
    +-----------+-+-+---------------+-------------------------------+
    |Frame Type |0|0|    Flags      |
    +-------------------------------+-------------------------------+
    |0|                                                             |
    +               Last Received Client Position                   +
    |                                                               |
    +---------------------------------------------------------------+
  • Frame Type: (6 bits) 0x0E
  • Last Received Client Position: (63 bits = max value 2^63-1) Unsigned 63-bit long of the last implied position the server received from the client.

Keepalive Position Field

Keepalive frames include the implied position of the client (or server). When sent, they act as a means for the other end of the connection to know the position of the other side.

This information MAY be used to update state for possible retransmission, such as trimming a retransmit buffer, or possible associations with individual stream status.

Identification Token Handling

The requirements for the Resume Identification Token are implementation dependent. However, some guidelines and considerations are:

  • Tokens may be generated by the client.
  • Tokens may be generated outside the client and the server and managed externally to the protocol.
  • Tokens should uniquely identify a connection on the server. The server should not assume a generation method of the token and should consider the token opaque. This allows a client to be compatible with any RSocket implementation that supports resuming operation and allows the client full control of Identification Token generation.
  • Tokens MUST be valid for the lifetime of an individual RSocket including possible resumption.
  • A server should not accept a SETUP with a Token that is currently already being used
  • Tokens should be resilient to replay attacks and thus should only be valid for the lifetime of an individual connection
  • Tokens should not be predictable by an attacking 3rd party

Connection Establishment

NOTE: The semantics are similar to TLS False Start.

Immediately upon successful connection, the client MUST send either a SETUP or RESUME frame with Stream ID of 0. Any other frame received that is NOT a SETUP|RESUME frame or a SETUP|RESUME frame with a Stream ID > 0, MUST cause the server to send an ERROR[INVALID_SETUP] and close the connection.

See Resume Operation for more information about resuming. The rest of this section assumes use of SETUP for establishing a connection.

The client-side Requester can inform the server-side Responder as to whether it will honor LEASEs or not based on the presence of the L flag in the SETUP frame.

The client-side Requester that has NOT set the L flag in the SETUP frame may send requests immediately if it so desires without waiting for a LEASE from the server.

The client-side Requester that has set the L flag in the SETUP frame MUST wait for the server-side Responder to send a LEASE frame before it can send requests.

If the server accepts the contents of the SETUP frame, it MUST send a LEASE frame if the SETUP frame set the L flag. The server-side Requester may send requests immediately upon receiving a SETUP frame that it accepts if the L flag is not set in the SETUP frame.

If the server does NOT accept the contents of the SETUP frame, the server MUST send back an ERROR[INVALID_SETUP|UNSUPPORTED_SETUP] and then close the connection.

The server-side Requester mirrors the LEASE requests of the client-side Requester. If a client-side Requester sets the L flag in the SETUP frame, the server-side Requester MUST wait for a LEASE frame from the client-side Responder before it can send a request. The client-side Responder MUST send a LEASE frame after a SETUP frame with the L flag set.

A client assumes a SETUP is accepted if it receives a response to a request, a LEASE frame, or if it sees a REQUEST type.

A client assumes a SETUP is rejected if it receives an ERROR.

Until connection establishment is complete, a Requester MUST NOT send any Request frames.

Until connection establishment is complete, a Responder MUST NOT emit any PAYLOAD frames.

Negotiation

The assumption is that the client will be dictating to the server what it desires to do. The server will decide to support that SETUP (accept it) or not (reject it). The ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP] error code indicates the reason for the rejection.

Sequences without LEASE

The possible sequences without LEASE are below.

  1. Client-side Request, Server-side accepts SETUP
    • Client connects & sends SETUP & sends REQUEST
    • Server accepts SETUP, handles REQUEST, sends back normal sequence based on REQUEST type
  2. Client-side Request, Server-side rejects SETUP
    • Client connects & sends SETUP & sends REQUEST
    • Server rejects SETUP, sends back ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP], closes connection
  3. Server-side Request, Server-side accepts SETUP
    • Client connects & sends SETUP
    • Server accepts SETUP, sends back REQUEST type
  4. Server-side Request, Server-side rejects SETUP
    • Client connects & sends SETUP
    • Server rejects SETUP, sends back ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP], closes connection

Sequences with LEASE

The possible sequences with LEASE are below.

  1. Client-side Request, Server-side accepts SETUP
    • Client connects & sends SETUP with L flag
    • Server accepts SETUP, sends back LEASE frame
    • Client-side sends REQUEST
  2. Client-side Request, Server-side rejects SETUP
    • Client connects & sends SETUP with L flag
    • Server rejects SETUP, sends back ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP], closes connection
  3. Server-side Request, Server-side accepts SETUP
    • Client connects & sends SETUP with L flag
    • Server accepts SETUP, sends back LEASE frame
    • Client sends LEASE frame
    • Server sends REQUEST
  4. Server-side Request, Server-side rejects SETUP
    • Client connects & sends SETUP with L flag
    • Server rejects SETUP, sends back ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP], closes connection

Fragmentation And Reassembly

PAYLOAD frames and all REQUEST frames may represent a large object and MAY need to be fragmented to fit within the Frame Data size. When this occurs, the F flag indicates if more fragments follow the current frame (or not).

Fragmentation does not change the request(n) or lease counts. In other words, a fragmented PAYLOAD frame counts as a single request(n) credit, and a request counts against a single lease count, regardless of how many fragments the frame is split into.

PAYLOAD Frame

When a PAYLOAD frame needs to be fragmented, a sequence of PAYLOAD frames is delivered using the (F)ollows flag.

When a PAYLOAD is fragmented, the Metadata MUST be transmitted completely before the Data.

For example, a single PAYLOAD with 20MB of Metadata and 25MB of Data that is fragmented into 3 frames:

-- PAYLOAD frame 1
Frame length = 16MB
(M)etadata present = 1
(F)ollows = 1 (fragments coming)
Metadata Length = 16MB

16MB of METADATA
0MB of Data

-- PAYLOAD frame 2
Frame length = 16MB
(M)etadata present = 1
(F)ollows = 1 (fragments coming)
Metadata Length = 4MB

4MB of METADATA
12MB of Data

-- PAYLOAD frame 3
Frame length = 13MB
(M)etadata present = 0
(F)ollows = 0

0MB of METADATA
13MB of Data

If the sender (Requester or Responder) wants to cancel sending a fragmented sequence, it MAY send a CANCEL frame without finishing delivery of the fragments.

REQUEST Frames

When REQUEST_RESPONSE, REQUEST_FNF, REQUEST_STREAM, or REQUEST_CHANNEL frames need to be fragmented, the first frame is the REQUEST_* frame with the (F)ollows flag set, followed by a sequence of PAYLOAD frames.

When fragmented, the Metadata MUST be transmitted completely before the Data.

For example, a single PAYLOAD with 20MB of Metadata and 25MB of Data that is fragmented into 3 frames:

-- REQUEST_RESPONSE frame 1
Frame length = 16MB
(M)etadata present = 1
(F)ollows = 1 (fragments coming)
Metadata Length = 16MB

16MB of METADATA
0MB of Data

-- PAYLOAD frame 2
Frame length = 16MB
(M)etadata present = 1
(F)ollows = 1 (fragments coming)
Metadata Length = 4MB

4MB of METADATA
12MB of Data

-- PAYLOAD frame 3
Frame length = 13MB
(M)etadata present = 0
(F)ollows = 0

0MB of METADATA
13MB of Data

If the Requester wants to cancel sending a fragmented sequence, it MAY send a CANCEL frame without finishing delivery of the fragments.

Stream Sequences and Lifetimes

Streams exists for a specific period of time. So an implementation may assume that Stream IDs are valid for a finite period of time. This period of time is bound by either a) the lifetime of the underlying transport protocol connection, or b) the lifetime of a session if resumability is used to extend the session across multiple transport protocol connections. Beyond that, each interaction pattern imposes lifetime based on a sequence of interactions between Requester and Responder.

In the section below, "RQ -> RS" refers to Requester sending a frame to a Responder. And "RS -> RQ" refers to Responder sending a frame to a Requester.

In the section below, "*" refers to 0 or more and "+" refers to 1 or more.

Once a stream has "terminated", the Stream ID can be "forgotten" by the Requester and Responder, but the Stream ID MUST NOT be re-used. See Stream Identifier for more information.

Request Response

  1. RQ -> RS: REQUEST_RESPONSE
  2. RS -> RQ: PAYLOAD with COMPLETE

or

  1. RQ -> RS: REQUEST_RESPONSE
  2. RS -> RQ: ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID]

or

  1. RQ -> RS: REQUEST_RESPONSE
  2. RQ -> RS: CANCEL

Upon sending a response, the stream is terminated on the Responder.

Upon receiving a CANCEL, the stream is terminated on the Responder and the response SHOULD not be sent.

Upon sending a CANCEL, the stream is terminated on the Requester.

Upon receiving a COMPLETE or ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream is terminated on the Requester.

Request Fire-n-Forget

  1. RQ -> RS: REQUEST_FNF

Upon reception, the stream is terminated by the Responder.

Upon being sent, the stream is terminated by the Requester.

REQUEST_FNF are assumed to be best effort and MAY not be processed due to: (1) SETUP rejection, (2) mis-formatting, (3) etc.

Request Stream

  1. RQ -> RS: REQUEST_STREAM
  2. RS -> RQ: PAYLOAD*
  3. RS -> RQ: ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID]

or

  1. RQ -> RS: REQUEST_STREAM
  2. RS -> RQ: PAYLOAD*
  3. RS -> RQ: COMPLETE

or

  1. RQ -> RS: REQUEST_STREAM
  2. RS -> RQ: PAYLOAD*
  3. RQ -> RS: CANCEL

At any time, the Requester may send REQUEST_N frames.

Upon receiving a CANCEL, the stream is terminated on the Responder.

Upon sending a CANCEL, the stream is terminated on the Requester.

Upon receiving a COMPLETE or ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream is terminated on the Requester.

Upon sending a COMPLETE or ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream is terminated on the Responder.

Request Channel

COMPLETE from Requester and Responder

  1. RQ -> RS: REQUEST_CHANNEL
  2. RQ -> RS: PAYLOAD*
  3. RQ -> RS: COMPLETE

intermixed with

  1. RS -> RQ: PAYLOAD*
  2. RS -> RQ: COMPLETE

Error from Requester, Responder terminates

  1. RQ -> RS: REQUEST_CHANNEL
  2. RQ -> RS: PAYLOAD*
  3. RQ -> RS: ERROR[APPLICATION_ERROR]

intermixed with

  1. RS -> RQ: PAYLOAD*

Error from Requester, Responder already Completed

  1. RQ -> RS: REQUEST_CHANNEL
  2. RQ -> RS: PAYLOAD*
  3. RQ -> RS: ERROR[APPLICATION_ERROR]

intermixed with

  1. RS -> RQ: PAYLOAD*
  2. RS -> RQ: COMPLETE

Error from Responder, Requester terminates

  1. RQ -> RS: REQUEST_CHANNEL
  2. RQ -> RS: PAYLOAD*

intermixed with

  1. RS -> RQ: PAYLOAD*
  2. RS -> RQ: ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID]

Error from Responder, Requester already Completed

  1. RQ -> RS: REQUEST_CHANNEL
  2. RQ -> RS: PAYLOAD*
  3. RQ -> RS: COMPLETE

intermixed with

  1. RS -> RQ: PAYLOAD*
  2. RS -> RQ: ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID]

Cancel from Requester, Responder terminates

  1. RQ -> RS: REQUEST_CHANNEL
  2. RQ -> RS: PAYLOAD*
  3. RQ -> RS: COMPLETE
  4. RQ -> RS: CANCEL

intermixed with

  1. RS -> RQ: PAYLOAD*

At any time, a Requester may send PAYLOAD frames.

At any time, a Requester, as well as a Responder, may send REQUEST_N frames.

An implementation MUST only send a single initial REQUEST_CHANNEL frame from the Requester to the Responder. And a Responder MUST respond to an initial REQUEST_CHANNEL frame with a REQUEST_N frame.

Upon receiving a CANCEL, the stream is terminated on the Responder.

Upon sending a CANCEL, the stream is terminated on the Requester.

Upon receiving an ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream is terminated on both Requester and Responder.

Upon sending an ERROR[APPLICATION_ERROR|REJECTED|CANCELED|INVALID], the stream is terminated on both the Requester and Responder.

In absence of ERROR or CANCEL, the stream is terminated after both Requester and Responder have sent and received COMPLETE.

A Requester may indicate COMPLETE by setting the C bit on either the initial REQUEST_CHANNEL frame, or on the last PAYLOAD frame sent. A Requester MUST NOT send any additional PAYLOAD frames after sending a frame with the C bit set.

Flow Control

There are multiple flow control mechanics provided by the protocol.

Reactive Streams Semantics

Reactive Streams semantics are used for flow control of Streams, Subscriptions, and Channels. This is a credit-based model where the Requester grants the Responder credit for the number of PAYLOADs it can send. It is sometimes referred to as "request-n" or "request(n)".

Credits are cumulative. Once credits are granted from Requester to Responder, they cannot be revoked. For example, sending request(3) and request(2) accumulates to a value of 5, allowing the Responder to send 5 PAYLOADs.

Please note that this explicitly does NOT follow rule number 17 in https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.0/README.md#3-subscription-code

While Reactive Streams support a demand of up to 2^63-1, and treats 2^63-1 as a magic number signaling to not track demand, this is not the case for RSocket. RSocket prioritizes byte size and only uses 4 bytes instead of 8 so the magic number is unavailable.

The Requester and the Responder MUST respect the Reactive Streams semantics.

e.g. here's an example of a successful stream call with flow-control.

  1. RQ -> RS: REQUEST_STREAM (REQUEST_N=3)
  2. RS -> RQ: PAYLOAD
  3. RS -> RQ: PAYLOAD
  4. RS -> RQ: PAYLOAD
  5. RS needs to wait for a new REQUEST_N at that point
  6. RQ -> RS: REQUEST_N (N=3)
  7. RS -> RQ: PAYLOAD
  8. RS -> RQ: PAYLOAD with COMPLETE

Lease Semantics

The LEASE semantics are to control the number of individual requests (all types) that a Requester may send in a given period. The only responsibility the protocol implementation has for the LEASE is to honor it on the Requester side. The Responder application is responsible for the logic of generation and informing the Responder it should send a LEASE to the peer Requester.

Requester MUST respect the LEASE contract. The Requester MUST NOT send more than Number of Requests specified in the LEASE frame within the Time-To-Live value in the LEASE.

A Responder that receives a REQUEST that it can not honor due to LEASE restrictions MUST respond with an ERROR[REJECTED]. This includes an initial LEASE sent as part of Connection Establishment.

QoS and Prioritization

Quality of Service and Prioritization of streams are considered application or network layer concerns and are better dealt with at those layers. The metadata capabilities, including METADATA_PUSH, are tools that applications can use for effective prioritization.

Within a single stream, the frames have to be processed in order, but this is not the case between different streams. Frames with Stream ID 0 SHOULD have a higher priority (this is implementation specific), since all those frames may impact the performance of the system.

DiffServ via IP QoS are best handled by the underlying network layer protocols.

Handling the Unexpected

This protocol attempts to be very lenient in processing of received frames and SHOULD ignore conditions that do not make sense given the current context. Clarifications are given below:

  1. TCP half-open connections (and WebSockets) or other dead transports are detectable by lack of KEEPALIVE frames as specified under Keepalive Frame. The decision to close a connection due to inactivity is the applications choice.
  2. Request keepalive and timeout semantics are the responsibility of the application.
  3. Lack of REQUEST_N frames that stops a stream is an application concern and SHALL NOT be handled by the protocol.
  4. Lack of LEASE frames that stops new Requests is an application concern and SHALL NOT be handled by the protocol.
  5. If a PAYLOAD for a REQUEST_RESPONSE is received that does not have a COMPLETE flag set, the implementation MUST assume it is set and act accordingly.
  6. Reassembly of PAYLOADs and REQUEST_CHANNELs MUST assume the possibility of an infinite stream.
  7. A PAYLOAD with both F and C flags set, implicitly ignores the F flag.
  8. Flag bits not specified for a particular frame MUST be ignored.
  9. All other received frames that are not accounted for in previous sections MUST be ignored. Thus, for example:
    1. Receiving a Request frame on a Stream ID that is already in use MUST be ignored.
    2. Receiving a CANCEL on an unknown Stream ID (including 0) MUST be ignored.
    3. Receiving an ERROR on an unknown Stream ID MUST be ignored.
    4. Receiving a PAYLOAD on an unknown Stream ID (including 0) MUST be ignored.
    5. Receiving a METADATA_PUSH with a non-0 Stream ID MUST be ignored.
    6. A server MUST ignore a SETUP frame after it has accepted a previous SETUP.
    7. A server MUST ignore an ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP|REJECTED_RESUME] frame.
    8. A client MUST ignore an ERROR[INVALID_SETUP|UNSUPPORTED_SETUP|REJECTED_SETUP|REJECTED_RESUME] frame after it has completed connection establishment.
    9. A client MUST ignore a SETUP frame.