masque_compression_capsule (masque v0.7.0)

View Source

Encode/decode the three Compression Context capsules used by Connect-UDP-Bind (draft-ietf-masque-connect-udp-listen-11 sections 3.1 - 3.3):

  • COMPRESSION_ASSIGN (0x11) - Context ID + IP Version + (IP Address + UDP Port if Version != 0).
  • COMPRESSION_ACK (0x12) - Context ID only.
  • COMPRESSION_CLOSE (0x13) - Context ID only; zero is malformed.

Pure data: this module never touches state, transports or sessions. It only encodes / decodes wire bytes and validates the structural rules the draft pins on these capsule bodies. Lifecycle invariants (singleton uncompressed, parity, per-tuple uniqueness, post-close prohibition, ACK accounting) live in masque_compression_table.

Summary

Functions

Decode the body bytes of a Compression Context capsule into the matching record. The capsule type is determined by the caller from the capsule frame.

Encode a typed capsule record onto the RFC 9297 capsule frame.

Convenience: encode the body for a given capsule type atom.

Types

capsule_record/0

-type capsule_record() ::
          #compression_assign{context_id :: pos_integer(),
                              ip_version :: 0 | 4 | 6,
                              address :: undefined | inet:ip_address(),
                              port :: undefined | inet:port_number()} |
          #compression_ack{context_id :: pos_integer()} |
          #compression_close{context_id :: pos_integer()}.

decode_error/0

-type decode_error() ::
          truncated | malformed_varint | bad_ip_version | zero_context_id | trailing_bytes |
          bad_ip_address | bad_udp_port.

Functions

decode_ack(Body)

-spec decode_ack(binary()) ->
                    {ok, #compression_ack{context_id :: pos_integer()}} | {error, decode_error()}.

decode_assign(Body)

-spec decode_assign(binary()) ->
                       {ok,
                        #compression_assign{context_id :: pos_integer(),
                                            ip_version :: 0 | 4 | 6,
                                            address :: undefined | inet:ip_address(),
                                            port :: undefined | inet:port_number()}} |
                       {error, decode_error()}.

decode_body(Type, Body)

-spec decode_body(non_neg_integer(), binary()) -> {ok, capsule_record()} | {error, decode_error()}.

Decode the body bytes of a Compression Context capsule into the matching record. The capsule type is determined by the caller from the capsule frame.

decode_close(Body)

-spec decode_close(binary()) ->
                      {ok, #compression_close{context_id :: pos_integer()}} | {error, decode_error()}.

encode(Compression_assign)

-spec encode(capsule_record()) -> iodata().

Encode a typed capsule record onto the RFC 9297 capsule frame.

encode(_, R)

-spec encode(assign | ack | close, capsule_record()) -> binary().

Convenience: encode the body for a given capsule type atom.

encode_ack(Compression_ack)

-spec encode_ack(#compression_ack{context_id :: pos_integer()}) -> binary().

encode_assign(Compression_assign)

-spec encode_assign(#compression_assign{context_id :: pos_integer(),
                                        ip_version :: 0 | 4 | 6,
                                        address :: undefined | inet:ip_address(),
                                        port :: undefined | inet:port_number()}) ->
                       binary().

encode_close(Compression_close)

-spec encode_close(#compression_close{context_id :: pos_integer()}) -> binary().