continuing SDT development

This commit is contained in:
Kevin Matz 2021-02-03 13:50:24 -05:00
parent 149f5b809d
commit 8f0822f719
5 changed files with 298 additions and 44 deletions

View File

@ -24,6 +24,7 @@
#include "appliance.h"
#include "dmp.h"
#include "sdt.h"
#include "rlp.h"
#include "rlp-udp.h"
@ -35,7 +36,11 @@ Appliance::Appliance(UUID::uuid cid)
: Component(cid)
{
registerRlpVectorHandler(SDT::SDT_PROTOCOL_ID,
std::bind(&Appliance::rootSdtHandler, this, std::placeholders::_1));
std::bind(&Appliance::rootSdtHandler, this,
std::placeholders::_1));
registerRlpVectorHandler(DMP::DMP_PROTOCOL_ID,
std::bind(&Appliance::rootDmpHandler, this,
std::placeholders::_1));
};
@ -74,6 +79,9 @@ void Appliance::UdpStreamHandler(PDU::Stream stream) {
void Appliance::TcpStreamHandler(PDU::Stream stream) {
// verify the TCP preamble
RLP::TCP::preamble_t preamble(stream);
// implementations shall check the ACN Packet Identifier. If the ACN Packet
// Identifier is not correct the receiver shall close the connection.
if (!preamble)
stream->setstate(stream->rdstate() | std::ios_base::failbit);
@ -129,7 +137,15 @@ void Appliance::deregisterRlpVector() {
/**
*/
void Appliance::rootSdtHandler(std::shared_ptr<RLP::Pdu>) {
void Appliance::rootSdtHandler(std::shared_ptr<RLP::Pdu> rlp) {
}
/**
*/
void Appliance::rootDmpHandler(std::shared_ptr<RLP::Pdu> rlp) {
}

View File

@ -68,6 +68,9 @@ protected:
virtual void GetSessions() {};
virtual void Sessions() {};
// process DMP frames
virtual void rootDmpHandler(std::shared_ptr<RLP::Pdu>);
private:
std::map<uint32_t, std::vector<PDU::Handler<RLP::Pdu>>> rlp_vectors_;
std::vector<std::shared_ptr<SDT::Session>> sessions_;

View File

@ -24,28 +24,20 @@
#pragma once
#include <cstdint>
#include "sdt.h"
// ACN EPI 17. Operation of SDT on UDP Networks
// ACN EPI 18 - Operation of SDT on UDP Networks
namespace ACN {
namespace SDT {
namespace UDP {
using std::uint8_t;
using std::uint16_t;
// Table 1. IPv4 Address Specification
struct acn_sdt_udp_ipv4_addr_t {
ip_addr_spec_t type; // SDT_ADDR_IPV4
// 3 Address Specification
struct address_t {
uint8_t type;
uint16_t udp_port;
uint8_t ipv4[4];
};
// Table 2. IPv6 Address Specification
struct acn_sdt_udp_ipv6_addr_t {
ip_addr_spec_t type; // SDT_ADDR_IPV6
uint16_t udp_port;
uint8_t ipv4[16];
union {
uint8_t ipv4[4];
uint8_t ipv6[16];
};
};
// Table 3. SDT symbolic parameters

View File

@ -38,27 +38,73 @@ bool SessionId::operator== (const SessionId & other) const {
}
/**
Constuct a sequenced channel with an owner and a direction.
@param owner the owner of the channel
@param direction the direction of channel communication
*/
Channel::Channel(std::shared_ptr<Component> owner, Direction direction) {
owner_ = owner;
direction_ = direction;
}
/**
deconstructor that closes the channel cleanly.
*/
Channel::~Channel() {
// TODO: close the channel.
}
/**
Construct a new session.
*/
Session::Session() {
}
/**
deconstructor that leaves the session gracefully.
*/
Session::~Session() {
// TODO: Disconnect the session.
}
/**
get the ID of the session
*/
SessionId Session::id() {
SessionId ret;
ret.cid = leader->cid();
ret.number = number;
ret.protocol = protocol;
ret.number = number_;
ret.protocol = protocol_;
return ret;
}
Pdu::Pdu(PDU::Stream stream)
: PDU::Pdu(stream, 1) // vectors are 1 octet
{
// if (stream->fail()) return;
// if (!buffer_->good()) return;
}
client_pdu_header_t::client_pdu_header_t(PDU::Stream stream) {
protocol = stream->read32();
association = stream->read16();
}
ClientPdu::ClientPdu(PDU::Stream stream)
: PDU::Pdu(stream, 2) // vectors are 2 octets (MID)
{
if (stream->fail()) return;
if (!buffer_->good()) return;
// SDT client blocks are the only SDT type to have a header.
// SDT client blocks have a different vector length?!?
// if (flags_.hasHeader)
// setHeader(new sdt_header(buffer_));
if (flags_.hasHeader)
setHeader(new client_pdu_header_t(buffer_));
}
}; // SDT

View File

@ -24,10 +24,12 @@
#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
@ -50,26 +52,147 @@ enum Direction {
upstream // Session upstream traffic
};
struct Channel {
std::shared_ptr<Component> owner;
Direction direction = internal;
};
// 3.5.1.1 Member Identifiers
using MID = uint16_t;
struct Session {
uint16_t number;
uint32_t protocol;
std::shared_ptr<ACN::Component> leader;
std::shared_ptr<Channel> downstream;
std::unordered_map<MID, std::shared_ptr<Channel>> upstream;
SessionId id();
private:
MID next_id_ = 1;
// 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 zero : 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.
};
// 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;
uint32_t expiry;
};
// 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;
};
// 4.4.3 Join Refuse
struct join_refuse_data_t : PDU::pdu_data {
UUID::uuid leader;
uint16_t number;
MID mid;
uint32_t reliable;
uint8_t code;
};
// 4.4.4 Leaving
struct leaving_data_t : PDU::pdu_data {
UUID::uuid leader;
uint16_t number;
MID mid;
uint32_t reliable;
uint8_t code;
};
// 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;
};
// 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;
// SDT client block
};
// 4.4.7 SDT Client Block
struct client_pdu_header_t : PDU::pdu_header {
uint32_t protocol;
uint16_t association;
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
@ -94,13 +217,33 @@ enum sdt_vector_t {
SESSIONS = 17,
};
// Table 7: Address Specification Types
enum ip_addr_spec_t {
SDT_ADDR_NULL = 0,
SDT_ADDR_IPV4 = 1,
SDT_ADDR_IPV6 = 2
// 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 cant create one
CHANNEL_EXPIRED = 7, // Channel has expired.
LOST_SEQUENCE = 8, // Unrecoverable packets missed.
SATURATED = 9, // Cant 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
{
@ -108,5 +251,59 @@ 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