# `diameter_codec`
[🔗](https://github.com/erlang/otp/blob/master/lib/diameter/src/base/diameter_codec.erl#L23)

Decode and encode of Diameter messages.

Incoming Diameter messages are decoded from binary() before being communicated
to `m:diameter_app` callbacks. Similarly, outgoing Diameter messages are encoded
into binary() before being passed to the appropriate `m:diameter_transport`
module for transmission. The functions documented here implement the default
encode/decode.

> #### Warning {: .warning }
>
> The diameter user does not need to call functions here explicitly when sending
> and receiving messages using `diameter:call/4` and the callback interface
> documented in `m:diameter_app`: diameter itself provides encode/decode as a
> consequence of configuration passed to `diameter:start_service/2`, and the
> results may differ from those returned by the functions documented here,
> depending on configuration.

The [header()](`m:diameter_codec#header`) and
[packet()](`m:diameter_codec#packet`) records below are defined in diameter.hrl,
which can be included as follows.

```erlang
-include_lib("diameter/include/diameter.hrl").
```

Application-specific records are defined in the hrl files resulting from
dictionary file compilation.

## DATA TYPES

- **`uint8()  = 0..255`{: #integers }**

- **`uint24() = 0..16777215`**

- **`uint32() = 0..4294967295`** - 8-bit, 24-bit and 32-bit integers occurring
  in Diameter and AVP headers.

- **`avp() = #diameter_avp{}`{: #avp }** - The application-neutral
  representation of an AVP. Primarily intended for use by relay applications
  that need to handle arbitrary Diameter applications. A service implementing a
  specific Diameter application (for which it configures a dictionary) can
  manipulate values of type [message()](`m:diameter_codec#message`) instead.

  Fields have the following types.

  - **`code = uint32()`**

  - **`is_mandatory = boolean()`**

  - **`need_encryption = boolean()`**

  - **`vendor_id = uint32() | undefined`** - Values in the AVP header,
    corresponding to AVP Code, the M flag, P flags and Vendor-ID respectively. A
    Vendor-ID other than `undefined` implies a set V flag.

  - **`data = iolist()`** - The data bytes of the AVP.

  - **`name = atom()`** - The name of the AVP as defined in the dictionary file
    in question, or `undefined` if the AVP is unknown to the dictionary file in
    question.

  - **`value = term()`** - The decoded value of an AVP. Will be `undefined` on
    decode if the data bytes could not be decoded, the AVP is unknown, or if the
    [decode format](`m:diameter#decode_format`) is `none`. The type of a decoded
    value is as document in [diameter_dict(4)](diameter_dict.md#DATA_TYPES).

  - **`type = atom()`** - The type of the AVP as specified in the dictionary
    file in question (or one it inherits). Possible types are `undefined` and
    the Diameter types: `OctetString`, `Integer32`, `Integer64`, `Unsigned32`,
    `Unsigned64`, `Float32`, `Float64`, `Grouped`, `Enumerated`, `Address`,
    `Time`, `UTF8String`, `DiameterIdentity`, `DiameterURI`, `IPFilterRule` and
    `QoSFilterRule`.

- **`dictionary() = module()`{: #dictionary }** - The name of a generated
  dictionary module as generated by [diameterc(1)](diameterc_cmd.md) or
  `diameter_make:codec/2`. The interface provided by a dictionary module is an
  implementation detail that may change.

- **`header() = #diameter_header{}`{: #header }** - The record representation of
  the Diameter header. Values in a [packet()](`m:diameter_codec#packet`)
  returned by `decode/2` are as extracted from the incoming message. Values set
  in an [packet()](`m:diameter_codec#packet`) passed to `encode/2` are preserved
  in the encoded binary(), with the exception of `length`, `cmd_code` and
  `application_id`, all of which are determined by the
  [dictionary()](`m:diameter_codec#dictionary`) in question.

  > #### Note {: .info }
  >
  > It is not necessary to set header fields explicitly in outgoing messages as
  > diameter itself will set appropriate values. Setting inappropriate values
  > can be useful for test purposes.

  Fields have the following types.

  - **`version = uint8()`**

  - **`length = uint24()`**

  - **`cmd_code = uint24()`**

  - **`application_id = uint32()`**

  - **`hop_by_hop_id = uint32()`**

  - **`end_to_end_id = uint32()`** - Values of the Version, Message Length,
    Command-Code, Application-ID, Hop-by-Hop Identifier and End-to-End
    Identifier fields of the Diameter header.

  - **`is_request = boolean()`**

  - **`is_proxiable = boolean()`**

  - **`is_error = boolean()`**

  - **`is_retransmitted = boolean()`** - Values corresponding to the R(equest),
    P(roxiable), E(rror) and T(Potentially re-transmitted message) flags of the
    Diameter header.

- **`message() = record() | maybe_improper_list()`{: #message }** - The
  representation of a Diameter message as passed to `diameter:call/4` or
  returned from a [handle_request/3](`c:diameter_app:handle_request/3`)
  callback. The record representation is as outlined in
  [diameter_dict(4)](diameter_dict.md#MESSAGE_RECORDS): a message as defined in
  a dictionary file is encoded as a record with one field for each component
  AVP. Equivalently, a message can also be encoded as a list whose head is the
  atom-valued message name (as specified in the relevant dictionary file) and
  whose tail is either a list of AVP name/values pairs or a map with values
  keyed on AVP names. The format at decode is determined by
  [diameter:service_opt()](`m:diameter#service_opt`)
  [decode_format](`m:diameter#decode_format`). Any of the formats is accepted at
  encode.

  Another list-valued representation allows a message to be specified as a list
  whose head is a [header()](`m:diameter_codec#header`) and whose tail is an
  [avp()](`m:diameter_codec#avp`) list. This representation is used by diameter
  itself when relaying requests as directed by the return value of a
  [handle_request/3](`c:diameter_app:handle_request/3`) callback. It differs
  from the other two in that it bypasses the checks for messages that do not
  agree with their definitions in the dictionary in question: messages are sent
  exactly as specified.

- **`packet() = #diameter_packet{}`{: #packet }** - A container for incoming and
  outgoing Diameter messages. Fields have the following types.

  - **`header = `[`header()`](`m:diameter_codec#header`)` | undefined`** - The
    Diameter header of the message. Can be (and typically should be) `undefined`
    for an outgoing message in a non-relay application, in which case diameter
    provides appropriate values.

  - **`avps = [`[`avp()`](`m:diameter_codec#avp`)`] | undefined`** - The AVPs of
    the message. Ignored for an outgoing message if the `msg` field is set to a
    value other than `undefined`.

  - **`msg = `[`message()`](`m:diameter_codec#message`)` | undefined`** - The
    incoming/outgoing message. For an incoming message, a term corresponding to
    the configured [decode format](`m:diameter#decode_format`) if the message
    can be decoded in a non-relay application, `undefined` otherwise. For an
    outgoing message, setting a
    `[`[`header()`](`m:diameter_codec#header`)`|`[`avp()`](`m:diameter_codec#avp`)`]`
    list is equivalent to setting the `header` and `avps` fields to the
    corresponding values.

    > #### Warning {: .warning }
    >
    > A value in the `msg` field does _not_ imply an absence of decode errors.
    > The `errors` field should also be examined.

  - **`bin = binary()`** - The incoming message prior to encode or the outgoing
    message after encode.

  - **`errors = [5000..5999 | {5000..5999, avp()}]`** - Errors detected at
    decode of an incoming message, as identified by a corresponding 5xxx series
    Result-Code (Permanent Failures). For an incoming request, these should be
    used to formulate an appropriate answer as documented for the
    [handle_request/3](`c:diameter_app:handle_request/3`) callback in
    `m:diameter_app`. For an incoming answer, the
    [diameter:application_opt()](`m:diameter#application_opt`) `answer_errors`
    determines the behaviour.

  - **`transport_data = term()`** - An arbitrary term of meaning only to the
    transport process in question, as documented in `m:diameter_transport`.

## SEE ALSO

[diameterc(1)](diameterc_cmd.md), `m:diameter_app`,
[diameter_dict(4)](diameter_dict.md), `m:diameter_make`

# `dictionary`
*not exported* *since OTP R15B03* 

```elixir
-type dictionary() :: module().
```

The name of a generated [dictionary module](`m:diameter_codec#dictionary`)
as generated by [diameterc(1)](diameterc_cmd.md) or `diameter_make:codec/2`.
The interface provided by a dictionary module is an
implementation detail that may change.

# `message`
*since OTP R15B03* 

```elixir
-type message() :: record() | maybe_improper_list().
```

The representation of a Diameter [message](`m:diameter_codec#message`)
as passed to `diameter:call/4` or returned from a
[handle_request/3](`c:diameter_app:handle_request/3`) callback.

# `packet`
*since OTP R15B03* 

```elixir
-type packet() ::
          #diameter_packet{header :: term(),
                           avps :: term(),
                           msg :: term(),
                           bin :: term(),
                           errors :: term(),
                           transport_data :: term()}.
```

A [container](`m:diameter_codec#packet`) for incoming and outgoing
Diameter messages.

# `decode`
*since OTP R15B03* 

```elixir
-spec decode(Mod, Bin) -> Pkt when Mod :: dictionary(), Bin :: binary(), Pkt :: packet().
```

Decode a Diameter message.

# `encode`
*since OTP R15B03* 

```elixir
-spec encode(Mod, Msg) -> Pkt when Mod :: dictionary(), Msg :: message() | packet(), Pkt :: packet().
```

Encode a Diameter message.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
