From 8f0822f71919bd33eb3f22b823137f55e024ebbd Mon Sep 17 00:00:00 2001 From: Kevin Matz Date: Wed, 3 Feb 2021 13:50:24 -0500 Subject: [PATCH] continuing SDT development --- libESTA/acn/appliance.cpp | 20 +++- libESTA/acn/appliance.h | 3 + libESTA/acn/sdt-udp.h | 24 ++-- libESTA/acn/sdt.cpp | 58 +++++++++- libESTA/acn/sdt.h | 237 ++++++++++++++++++++++++++++++++++---- 5 files changed, 298 insertions(+), 44 deletions(-) diff --git a/libESTA/acn/appliance.cpp b/libESTA/acn/appliance.cpp index 4c1fa08..70d2699 100644 --- a/libESTA/acn/appliance.cpp +++ b/libESTA/acn/appliance.cpp @@ -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) { +void Appliance::rootSdtHandler(std::shared_ptr rlp) { + +} + + +/** + +*/ +void Appliance::rootDmpHandler(std::shared_ptr rlp) { } diff --git a/libESTA/acn/appliance.h b/libESTA/acn/appliance.h index ed242c3..c891196 100644 --- a/libESTA/acn/appliance.h +++ b/libESTA/acn/appliance.h @@ -68,6 +68,9 @@ protected: virtual void GetSessions() {}; virtual void Sessions() {}; + // process DMP frames + virtual void rootDmpHandler(std::shared_ptr); + private: std::map>> rlp_vectors_; std::vector> sessions_; diff --git a/libESTA/acn/sdt-udp.h b/libESTA/acn/sdt-udp.h index f4eee28..3f39875 100644 --- a/libESTA/acn/sdt-udp.h +++ b/libESTA/acn/sdt-udp.h @@ -24,28 +24,20 @@ #pragma once #include -#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 diff --git a/libESTA/acn/sdt.cpp b/libESTA/acn/sdt.cpp index f688a87..c8ae0d9 100644 --- a/libESTA/acn/sdt.cpp +++ b/libESTA/acn/sdt.cpp @@ -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 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 diff --git a/libESTA/acn/sdt.h b/libESTA/acn/sdt.h index 9337801..9ce984e 100644 --- a/libESTA/acn/sdt.h +++ b/libESTA/acn/sdt.h @@ -24,10 +24,12 @@ #pragma once #include +#include #include #include #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 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 leader; - std::shared_ptr downstream; - std::unordered_map> 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 protocols; +}; + +// 4.4.9 Sessions +struct sessions_data_t : PDU::pdu_data { + std::list 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 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 { @@ -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, Direction); + ~Channel(); + +private: + std::shared_ptr 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 leader; + std::shared_ptr downstream; + std::unordered_map> upstream; + +private: + uint16_t number_; + uint32_t protocol_; + MID next_id_ = 1; +}; + } // SDT } // ACN