Validating Packet Formats
View SourceFor demonstration purposes, let's move to a different example. Let's say we have an existing packet format, one that we would like to be able to extend in the future by providing different format IDs or types. Now, let's define an initial structure:
| Byte 0 | Byte 1 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Source Port | Destination Port | ||||||||||||||
| Packet Type | Payload Type | Payload | |||||||||||||
Now, to start, let's say we want to define a "Hello" and a "Goodbye" packet. To differentiate between them, we can specify the value of their type. Let's make the "Hello" a Packet Type binary "00" and the "Goodbye" packet a "11":
| Byte 0 | Byte 1 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Source Port | Destination Port | ||||||||||||||
| Packet Type = 0b00 | Payload Type | Payload | |||||||||||||
| Byte 0 | Byte 1 | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Source Port | Destination Port | ||||||||||||||
| Packet Type = 0b11 | Payload Type | Payload | |||||||||||||
To make this straightforward to represent, Etiquette
allows specifying a fixed: value argument to each
field. So let's proceed and create their
definitions:
defmodule SaluteSpec do
use Etiquette.Spec
packet "My Salute Packet", id: :salute do
field "Source Port", 8
field "Destination Port", 8
field "Packet Type", 2
field "Payload Type", 6
field "Payload", 8
end
packet "Hello Packet", id: :hello do
field "Source Port", 8
field "Destination Port", 8
field "Packet Type", 2, fixed: 0b00
field "Payload Type", 6
field "Payload", 8
end
packet "Goodbye Packet", id: :goodbye do
field "Source Port", 8
field "Destination Port", 8
field "Packet Type", 2, fixed: 0b11
field "Payload Type", 6
field "Payload", 8
end
endNow that we have created a packet containing an identifying element (the Packet Type), the generated functions for the Hello and Goodbye packets will use that information to validate the structure of provided data.
For example, we can now use
iex> SaluteSpec.is_hello?(<<0::8, 0::8, 0b00::2, 0x3F::6, "somedata">>)
true
iex> SaluteSpec.is_hello?(<<0::8, 0::8, 0b11::2, 0x3F::6, "somedata">>)
falseWhich is using the expected fixed values to validate that the packets follow the defined specification.
If a packet specification has no specified fixed values for any of its fields,
it is also possible to determine if a given bitstring fits a specification just
by looking at the length. For example, A single byte of data cannot be a "Hello"
packet by itself (because the specification has declared it to be at least 4
bytes), so is_hello? would be false in this case. However, if the argument of
is_hello? is larger than the specified length of the packet, it can be true
for the same reason that the generated parse functions can accept larger
binaries than what they parse. See
the length guide for
more details on why this is the case.
Continue through the
Packet Types and Subtypes guide
to learn about other field arguments that can help
you streamline the creation of packet variants.