373 lines
11 KiB
C++
373 lines
11 KiB
C++
/*
|
||
sdt.h
|
||
|
||
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
|
||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
of this software and associated documentation files (the "Software"), to deal
|
||
in the Software without restriction, including without limitation the rights
|
||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
copies of the Software, and to permit persons to whom the Software is
|
||
furnished to do so, subject to the following conditions:
|
||
|
||
The above copyright notice and this permission notice shall be included in all
|
||
copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
SOFTWARE.
|
||
*/
|
||
#pragma once
|
||
|
||
#include "pdu.h"
|
||
#include "sdt/udp.h" // EPI 18
|
||
|
||
/**
|
||
* @brief @cite SDT ANSI E1.17- 2015, Architecture for Control Networks–
|
||
* Session Data Transport Protocol
|
||
*/
|
||
namespace ACN::SDT {
|
||
|
||
/**
|
||
* @brief 7.1 Protocol Code
|
||
*/
|
||
static const uint32_t SDT_PROTOCOL_ID = 1; // PDU protocol value
|
||
|
||
|
||
/**
|
||
* @brief SDT vector codes
|
||
*/
|
||
const static uint8_t REL_WRAP = 1; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t UNREL_WRAP = 2; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t CHANNEL_PARAMS = 3; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t JOIN = 4; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t JOIN_REFUSE = 5; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t JOIN_ACCEPT = 6; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t LEAVE = 7; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t LEAVING = 8; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t CONNECT = 9; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t CONNECT_ACCEPT = 10; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t CONNECT_REFUSE = 11; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t DISCONNECT = 12; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t DISCONNECTING = 13; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t ACK = 14; //!< 4.5 SDT Wrapped Messages
|
||
const static uint8_t NAK = 15; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t GET_SESSIONS = 16; //!< 4.4 SDT Base Layer Message
|
||
const static uint8_t SESSIONS = 17; //!< 4.4 SDT Base Layer Message
|
||
|
||
|
||
/**
|
||
* @brief Table 6: Reason Codes
|
||
*/
|
||
const static uint8_t NONSPECIFIC = 1; //!< Non-specific, non-SDT reason.
|
||
const static uint8_t ILLEGAL_PARAMETERS = 2; //!< Illegal channel parameters.
|
||
const static uint8_t LOW_RESOURCES = 3; //!< Insufficient resources.
|
||
const static uint8_t ALREADY_MEMBER = 4; //!< Multiple MIDs for single component.
|
||
const static uint8_t BAD_ADDRESS_TYPE = 5; //!< Unrecognized transport address type.
|
||
const static uint8_t NO_RECIPROCAL_CHANNEL = 6; //!< No upstream channel and can’t create one
|
||
const static uint8_t CHANNEL_EXPIRED = 7; //!< Channel has expired.
|
||
const static uint8_t LOST_SEQUENCE = 8; //!< Unrecoverable packets missed.
|
||
const static uint8_t SATURATED = 9; //!< Can’t keep up, processor saturation.
|
||
const static uint8_t TRANSPORT_ADDRESS_CHANGING = 10; //!< (e.g., IP number lease expired).
|
||
const static uint8_t ASKED_TO_LEAVE = 11; //!< Asked to leave the channel.
|
||
const static uint8_t NO_RECIPIENT = 12; //!< Component does not support protocol ID.
|
||
const static uint8_t ONLY_UNICAST_SUPPORTED = 13; //!< Only unicast channels are supported
|
||
|
||
|
||
/**
|
||
* @brief Table 7: Address Specification Types
|
||
*/
|
||
enum ip_addr_spec : uint8_t {
|
||
SDT_ADDR_NULL = 0, //!< Address is not present (0 octets).
|
||
SDT_ADDR_IPV4 = 1, //!< Address specified is in IP v4 format
|
||
SDT_ADDR_IPV6 = 2 //!< Address specified is in IP v6 format
|
||
};
|
||
|
||
|
||
/// 3.5.1.1 Member Identifiers
|
||
using MID = uint16_t;
|
||
|
||
|
||
namespace CLIENT {
|
||
|
||
/**
|
||
* @brief The CLIENT::Pdu class
|
||
*/
|
||
class Pdu
|
||
: public PDU::Pdu
|
||
{
|
||
public:
|
||
Pdu();
|
||
void iStream(PDU::Stream) override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.7 SDT Client Block
|
||
*/
|
||
struct client_header
|
||
: PDU::pdu_header
|
||
{
|
||
uint32_t protocol; //!< protocol number
|
||
uint16_t association; //!< association
|
||
|
||
size_t streamSize() const override { return 6; };
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
} // namespace CLIENT
|
||
|
||
|
||
/**
|
||
* @brief The SDT::Pdu class
|
||
*/
|
||
class Pdu
|
||
: public PDU::Pdu
|
||
{
|
||
public:
|
||
Pdu();
|
||
void iStream(PDU::Stream) override;
|
||
};
|
||
|
||
|
||
|
||
/**
|
||
* @brief 4.4.1.2 Channel Parameter Block
|
||
*/
|
||
struct params
|
||
: streamable
|
||
{
|
||
uint8_t Expiry; //!< number of seconds without traffic before leaving
|
||
union {
|
||
uint8_t flags = 0; //!< packed field of parameter flags
|
||
struct {
|
||
uint8_t reserved : 7;
|
||
bool NAK_Outbound : 1; //!< NAK to channel (true) or destination address (false)
|
||
};
|
||
};
|
||
|
||
uint16_t NAKholdoff; //!< calculation of a standoff time for sending NAKs
|
||
uint16_t NAKmodulus; //!< calculation of a standoff time for sending NAKs
|
||
uint16_t NAKmaxwait; //!< maximum milliseconds to wait before sending a NAK.
|
||
|
||
size_t streamSize() const override { return 8; }
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.1 Join
|
||
*/
|
||
struct join_data
|
||
: PDU::pdu_data
|
||
{
|
||
UUID::uuid cid; //!< component UUID
|
||
MID mid; //!< message ID
|
||
uint16_t channel; //!< channel number
|
||
uint16_t reciprocal; //!< reciprocol channel
|
||
uint32_t sequence; //!< sequence number
|
||
uint32_t reliable; //!< reliable number
|
||
UDP::ipAddress destination; //!< destination IP address
|
||
params parameters; //!< parameters
|
||
uint8_t expiry; //!< expiry timeout
|
||
|
||
size_t streamSize() const override;
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.2 Join Accept
|
||
*/
|
||
struct join_accept_data
|
||
: PDU::pdu_data
|
||
{
|
||
UUID::uuid leader; //!< channel leader UUID
|
||
uint16_t number; //!< channel number
|
||
MID mid; //!< message ID
|
||
uint32_t reliable; //!< reliable number
|
||
uint16_t reciprocal; //!< reciprocal channel
|
||
|
||
size_t streamSize() const override { return 26; }
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.3 Join Refuse & 4.4.4 Leaving
|
||
*/
|
||
struct join_refuse_data
|
||
: PDU::pdu_data
|
||
{
|
||
UUID::uuid leader; //!< channel leader UUID
|
||
uint16_t number; //!< channel number
|
||
MID mid; //!< message ID
|
||
uint32_t reliable; //!< realiable number
|
||
uint8_t reason; //!< NAK reason code
|
||
|
||
size_t streamSize() const override { return 25; }
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.5 NAK
|
||
*/
|
||
struct nak_data
|
||
: PDU::pdu_data
|
||
{
|
||
UUID::uuid leader; //!< leader UUID
|
||
uint16_t number; //!< channel number
|
||
MID mid; //!< message ID
|
||
uint32_t reliable; //!< reliable number
|
||
uint32_t missed_first; //!< first missed message
|
||
uint32_t missed_last; //!< last missed message
|
||
|
||
size_t streamSize() const override { return 32; }
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.6 Reliable Wrapper and Unreliable Wrapper
|
||
*/
|
||
struct wrapper_data
|
||
: PDU::pdu_data
|
||
{
|
||
uint16_t channel; //!< channel number
|
||
uint32_t sequence; //!< sequence number
|
||
uint32_t reliable; //!< reliable number
|
||
uint32_t oldest; //!< oldest sequence number
|
||
MID ack_range_begin; //!< first MID to acknowledge
|
||
MID ack_range_end; //!< last MID to acknowledge
|
||
uint16_t MAK_threshold; //!< MAK Threshold
|
||
PDU::Block<CLIENT::Pdu> block; //!< client PDU block
|
||
|
||
size_t streamSize() const override;
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
|
||
/**
|
||
* @brief 4.4.8 Get Sessions
|
||
*/
|
||
struct get_sessions_data
|
||
: PDU::pdu_data
|
||
{
|
||
UUID::uuid cid; //!< component UUID
|
||
|
||
size_t streamSize() const override { return UUID_LENGTH; }
|
||
void iStream(PDU::Stream s) override { *s >> cid; }
|
||
void oStream(PDU::Stream s) const override { *s << cid; }
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.9.1 Channel Owner Info Block
|
||
* 4.4.9.2 Channel Member Info Block
|
||
*/
|
||
struct channel_info_block
|
||
: streamable
|
||
{
|
||
MID mid; //!< MID
|
||
UUID::uuid owner; //!< channel owner UUID
|
||
uint16_t channel; //!< channel number
|
||
UDP::ipAddress destination; //!< destination IP address
|
||
UDP::ipAddress source; //!< source IP address
|
||
uint16_t reciprocal; //!< reciprocal channel
|
||
uint16_t sessions; //!< session count
|
||
std::vector<uint32_t> protocols; //!< transported protocols
|
||
|
||
size_t streamSize() const override;
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.4.9 Sessions
|
||
*/
|
||
struct sessions_data
|
||
: PDU::pdu_data
|
||
{
|
||
std::vector<channel_info_block> list; //!< list of channel info blocks
|
||
|
||
size_t streamSize() const override;
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.5.1 ACK
|
||
*/
|
||
struct ack_data
|
||
: PDU::pdu_data
|
||
{
|
||
uint32_t sequence; //!< sequence number
|
||
|
||
size_t streamSize() const override { return 4; }
|
||
void iStream(PDU::Stream s) override { *s >> sequence; }
|
||
void oStream(PDU::Stream s) const override { *s << sequence; }
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.5.2 Channel Params
|
||
*/
|
||
struct channel_params_data
|
||
: PDU::pdu_data
|
||
{
|
||
params parameters; //!< parameters
|
||
UDP::ipAddress address; //!< IP address
|
||
uint8_t expiry; //!< timeout
|
||
|
||
size_t streamSize() const override;
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.5.3 Connect, 4.5.4 Connect Accept, & 4.5.6 Disconnect
|
||
*/
|
||
struct connect_data
|
||
: PDU::pdu_data
|
||
{
|
||
uint32_t protocol; //!< protocol number
|
||
|
||
size_t streamSize() const override { return 4; }
|
||
void iStream(PDU::Stream s) override { *s >> protocol; }
|
||
void oStream(PDU::Stream s) const override { *s << protocol; }
|
||
};
|
||
|
||
|
||
/**
|
||
* @brief 4.5.5 Connect Refuse & 4.5.7 Disconnecting
|
||
*/
|
||
struct disconnecting_data
|
||
: PDU::pdu_data
|
||
{
|
||
uint32_t protocol; //!< protocol number
|
||
uint8_t reason; //!< refuse/disconnect reason code
|
||
|
||
size_t streamSize() const override { return 5; }
|
||
void iStream(PDU::Stream) override;
|
||
void oStream(PDU::Stream) const override;
|
||
};
|
||
|
||
} // ACN::SDT
|