314 lines
8.0 KiB
C++
314 lines
8.0 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 <cstdint>
|
||
#include <list>
|
||
#include <memory>
|
||
#include <unordered_map>
|
||
#include "component.h"
|
||
#include "pdu.h"
|
||
#include "sdt-udp.h" // EPI 18
|
||
|
||
// ANSI E1.17- 2015, Architecture for Control Networks–
|
||
// Session Data Transport Protocol
|
||
namespace ACN {
|
||
namespace SDT {
|
||
|
||
// 3.1 Session Identity
|
||
struct SessionId {
|
||
UUID::uuid cid; // the component ID (CID) of the session leader
|
||
uint16_t number; // the session number the leader has assigned
|
||
uint32_t protocol; // the ID of the protocol carried by the session
|
||
bool operator== (const SessionId &) const;
|
||
};
|
||
|
||
// 3.3 Sequenced Channels
|
||
// Sequenced channels transport three categories of traffic:
|
||
enum Direction {
|
||
internal, // SDT internal traffic
|
||
downstream, // Session downstream traffic
|
||
upstream // Session upstream traffic
|
||
};
|
||
|
||
// 3.5.1.1 Member Identifiers
|
||
using MID = uint16_t;
|
||
|
||
// 4.4.1.2 Channel Parameter Block
|
||
struct params_t {
|
||
uint8_t Expiry; // number of seconds without traffic before leaving
|
||
struct {
|
||
uint8_t NAK_Outbound : 1; // NAK to channel (1) or destination address (0)
|
||
uint8_t reserved : 7;
|
||
};
|
||
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.
|
||
params_t() {};
|
||
params_t(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.1 Join
|
||
struct join_data_t : PDU::pdu_data {
|
||
MID mid;
|
||
uint16_t number;
|
||
uint16_t reciprocal;
|
||
uint32_t sequence;
|
||
uint32_t reliable;
|
||
UDP::address_t destination;
|
||
params_t parameters;
|
||
uint8_t expiry;
|
||
join_data_t() {};
|
||
join_data_t(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.2 Join Accept
|
||
struct join_accept_data_t : PDU::pdu_data {
|
||
UUID::uuid leader;
|
||
uint16_t number;
|
||
MID mid;
|
||
uint32_t reliable;
|
||
uint16_t reciprocal;
|
||
join_accept_data_t() {};
|
||
join_accept_data_t(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.3 Join Refuse
|
||
// 4.4.4 Leaving
|
||
struct join_refuse_data_t : PDU::pdu_data {
|
||
UUID::uuid leader;
|
||
uint16_t number;
|
||
MID mid;
|
||
uint32_t reliable;
|
||
uint8_t code;
|
||
join_refuse_data_t() {};
|
||
join_refuse_data_t(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.5 NAK
|
||
struct nak_data_t : PDU::pdu_data {
|
||
UUID::uuid leader;
|
||
uint16_t number;
|
||
MID mid;
|
||
uint32_t reliable;
|
||
uint32_t missed_first;
|
||
uint32_t missed_last;
|
||
nak_data_t() {};
|
||
nak_data_t(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.6 Reliable Wrapper and Unreliable Wrapper
|
||
struct wrapper_data_t : PDU::pdu_data {
|
||
uint16_t number;
|
||
uint32_t sequence;
|
||
uint32_t reliable;
|
||
uint32_t oldest;
|
||
MID ack_range_begin;
|
||
MID ack_range_end;
|
||
uint16_t MAK_threshold;
|
||
wrapper_data_t() {};
|
||
wrapper_data_t(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.7 SDT Client Block
|
||
struct client_pdu_header_t : PDU::pdu_header {
|
||
uint32_t protocol;
|
||
uint16_t association;
|
||
client_pdu_header_t() {};
|
||
client_pdu_header_t(PDU::Stream);
|
||
};
|
||
|
||
// Client Block PDU
|
||
class ClientPdu
|
||
: public PDU::Pdu
|
||
{
|
||
public:
|
||
ClientPdu(PDU::Stream);
|
||
};
|
||
|
||
// 4.4.8 Get Sessions
|
||
struct get_sessions_data_t : PDU::pdu_data {
|
||
UUID::uuid cid;
|
||
};
|
||
|
||
|
||
// 4.4.9.1 Channel Owner Info Block
|
||
struct channel_info_block_t {
|
||
MID mid;
|
||
UUID::uuid owner;
|
||
uint16_t number;
|
||
UDP::address_t destination;
|
||
UDP::address_t source;
|
||
uint16_t reciprocal;
|
||
uint16_t count;
|
||
std::list<uint32_t> protocols;
|
||
};
|
||
|
||
// 4.4.9 Sessions
|
||
struct sessions_data_t : PDU::pdu_data {
|
||
std::list<channel_info_block_t> list;
|
||
};
|
||
|
||
// 4.5.1 ACK
|
||
struct ack_data_t : PDU::pdu_data {
|
||
uint32_t reliable;
|
||
};
|
||
|
||
// 4.5.2 Channel Params
|
||
struct channel_params_data_t : PDU::pdu_data {
|
||
params_t parameters;
|
||
UDP::address_t address;
|
||
uint8_t expiry;
|
||
};
|
||
|
||
// 4.5.3 Connect
|
||
// 4.5.4 Connect Accept
|
||
// 4.5.6 Disconnect
|
||
struct connect_data_t : PDU::pdu_data {
|
||
uint32_t protocol;
|
||
};
|
||
|
||
// 4.5.5 Connect Refuse
|
||
// 4.5.7 Disconnecting
|
||
struct connect_refuse_data_t : PDU::pdu_data {
|
||
uint32_t protocol;
|
||
uint8_t code;
|
||
};
|
||
|
||
|
||
// 7.1 Protocol Code
|
||
static const uint32_t SDT_PROTOCOL_ID = 1; // PDU protocol value
|
||
|
||
// 7.2 PDU Vector Codes
|
||
enum sdt_vector_t {
|
||
REL_WRAP = 1,
|
||
UNREL_WRAP = 2,
|
||
CHANNEL_PARAMS = 3,
|
||
JOIN = 4,
|
||
JOIN_REFUSE = 5,
|
||
JOIN_ACCEPT = 6,
|
||
LEAVE = 7,
|
||
LEAVING = 8,
|
||
CONNECT = 9,
|
||
CONNECT_ACCEPT = 10,
|
||
CONNECT_REFUSE = 11,
|
||
DISCONNECT = 12,
|
||
DISCONNECTING = 13,
|
||
ACK = 14,
|
||
NAK = 15,
|
||
GET_SESSIONS = 16,
|
||
SESSIONS = 17,
|
||
};
|
||
|
||
// 7.4 Other Symbolic Parameters
|
||
|
||
// Table 6: Reason Codes
|
||
enum reason_code_t {
|
||
NONSPECIFIC = 1, // Non-specific, non-SDT reason.
|
||
ILLEGAL_PARAMETERS = 2, // Illegal channel parameters.
|
||
LOW_RESOURCES = 3, // Insufficient resources.
|
||
ALREADY_MEMBER = 4, // Multiple MIDs for single component.
|
||
BAD_ADDRESS_TYPE = 5, // Unrecognized transport address type.
|
||
NO_RECIPROCAL_CHANNEL = 6, // No upstream channel and can’t create one
|
||
CHANNEL_EXPIRED = 7, // Channel has expired.
|
||
LOST_SEQUENCE = 8, // Unrecoverable packets missed.
|
||
SATURATED = 9, // Can’t keep up, processor saturation.
|
||
TRANSPORT_ADDRESS_CHANGING = 10, // (e.g., IP number lease expired).
|
||
ASKED_TO_LEAVE = 11, // Asked to leave the channel.
|
||
NO_RECIPIENT = 12, // Component does not support protocol ID.
|
||
ONLY_UNICAST_SUPPORTED = 13 // Only unicast channels are supported
|
||
};
|
||
|
||
// Table 7: Address Specification Types
|
||
enum ip_addr_spec_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
|
||
};
|
||
|
||
// PDU type for this protocol
|
||
class Pdu
|
||
: public PDU::Pdu
|
||
{
|
||
public:
|
||
Pdu(PDU::Stream);
|
||
};
|
||
|
||
|
||
// Sequenced channels are unidirectional communication channels (unicast or
|
||
// multicast) from an owner component to one or more member components.
|
||
class Channel {
|
||
public:
|
||
Channel(std::shared_ptr<Component>, Direction);
|
||
~Channel();
|
||
|
||
private:
|
||
std::shared_ptr<Component> owner_;
|
||
Direction direction_ = internal;
|
||
};
|
||
|
||
|
||
// A session has a single leader and zero or more session members. The leader
|
||
// communicates to members using the downstream address. Members respond to the
|
||
// leader on the upstream address. A unique session identifier identifies a
|
||
// session.
|
||
class Session {
|
||
public:
|
||
Session();
|
||
~Session();
|
||
|
||
SessionId id();
|
||
|
||
// 4.4 SDT Base Layer Messages (non ad-hoc)
|
||
void join_accept() {};
|
||
void join_refuse() {};
|
||
void leaving() {};
|
||
void nak() {};
|
||
void reliable_wrapper() {};
|
||
void unreliable_wrapper() {};
|
||
|
||
// 4.5 SDT Wrapped Messages
|
||
void ack();
|
||
void channel_params();
|
||
void leave();
|
||
void connect();
|
||
void connect_accept();
|
||
void connect_refuse();
|
||
void disconnect();
|
||
void disconnecting();
|
||
|
||
protected:
|
||
std::shared_ptr<ACN::Component> leader;
|
||
std::shared_ptr<Channel> downstream;
|
||
std::unordered_map<MID, std::shared_ptr<Channel>> upstream;
|
||
|
||
private:
|
||
uint16_t number_;
|
||
uint32_t protocol_;
|
||
MID next_id_ = 1;
|
||
};
|
||
|
||
} // SDT
|
||
} // ACN
|