SatCat5
coap_connection.h
1 // Copyright 2024-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 // CoAP request/response handling for a single client-server connection
6 
7 #pragma once
8 
9 #include <satcat5/ccsds_spp.h>
10 #include <satcat5/coap_constants.h>
11 #include <satcat5/udp_core.h>
12 
13 // Maximum outgoing message size, excluding Eth/IP/UDP overhead.
14 // Default matches the recommended maximum from Section 4.6.
15 #ifndef SATCAT5_COAP_BUFFSIZE
16 #define SATCAT5_COAP_BUFFSIZE 1152
17 #endif
18 
19 // Store a record of the last N received requests (Msg ID + token).
20 // Allows detection of new requests without assuming sequential IDs.
21 // Stale out-of-order deliveries must not exceed this upper bound.
22 #ifndef SATCAT5_COAP_HISTORY
23 #define SATCAT5_COAP_HISTORY 4
24 #endif
25 
26 namespace satcat5 {
27  namespace coap {
60  class Connection
61  : protected satcat5::net::Protocol
62  , protected satcat5::poll::Timer
63  , protected satcat5::io::ArrayWriteStatic<SATCAT5_COAP_BUFFSIZE>
64  {
65  public:
66  // Accessors for the cache state.
67  inline bool is_idle() const
68  { return m_state == State::IDLE && m_allow_reuse; }
69  inline bool is_match_addr() const
70  { return m_addr->matches_reply_address(); }
71  bool is_match_coap(
72  const satcat5::coap::ReadHeader* msg) const;
73  bool is_match_reuse() const;
74  inline bool is_await() const
75  { return m_state == State::WAIT_RESPONSE_U
76  || m_state == State::WAIT_RESPONSE_M
77  || m_state == State::RESPONSE_SEP1;}
78  inline bool is_connecting() const
79  { return m_state == State::CONNECT_IDLE
80  || m_state == State::CONNECT_BUSY; }
81  inline bool is_request() const
82  { return m_state == State::REQUEST_CON
83  || m_state == State::REQUEST_NON
84  || m_state == State::REQUEST_SEP; }
85  inline bool is_response() const
86  { return m_state == State::RESPONSE_CACHE
87  || m_state == State::RESPONSE_DEFER
88  || m_state == State::RESPONSE_SEP1
89  || m_state == State::RESPONSE_SEP2; }
90  inline bool is_separate() const
91  { return m_state == State::RESPONSE_SEP1
92  || m_state == State::RESPONSE_SEP2; }
93  inline u16 msg_id() const
94  { return m_msgid[m_meta_idx]; }
95  inline u64 token() const
96  { return m_token[m_meta_idx]; }
97  inline u8 tkl() const
98  { return m_flags[m_meta_idx] & 0x0F; }
99 
101  void close();
102 
103  // Child class SHOULD implement a connect(...) method that
104  // sets connection parameters for outgoing requests. That
105  // method must call connected() to update the parent state.
106  // (See examples ConnectionSpp and ConnectionUdp, below.)
107  // Connections in this state remain open until explicitly
108  // closed, and are not reused even if they appear to be idle.
109 
112  bool ping(u16 msg_id);
113 
115  inline u32 get_proxy_token() const
116  { return m_proxy_token; }
117 
122  inline void set_proxy_token(u32 token)
123  { m_proxy_token = token; }
124 
126  bool ready() const;
127 
131 
137 
140  bool open_separate(const satcat5::coap::ReadHeader* msg);
141 
145 
149  { return is_separate() ? continue_separate() : open_response(); }
150 
154  bool error_response(satcat5::coap::Code code, const char* why = 0);
155 
157  u8 response_type() const;
158 
161  bool test_inject(unsigned len, const void* data);
162 
163  protected:
168  Connection(
169  satcat5::coap::Endpoint* endpoint,
170  satcat5::net::Address* addr);
171  ~Connection() SATCAT5_OPTIONAL_DTOR;
172 
176  void init(satcat5::coap::Endpoint* endpoint);
177 
178  // External event handling.
179  friend satcat5::coap::Endpoint;
180  bool deliver(satcat5::coap::Reader* msg);
181  void frame_rcvd(satcat5::io::LimitedRead& src) override;
182  void timer_event() override;
183  bool write_finalize() override;
184 
185  // Internal event handling.
186  bool connected(bool allow_reuse);
187  void error_event();
188  int match_history(const satcat5::coap::ReadHeader* msg) const;
189  void push_history(const satcat5::coap::ReadHeader* msg);
190  void reset_hard();
191  void reset_soft();
192  bool send_buffer();
193  bool send_empty(u8 typ, u16 id);
194  bool send_first();
195  void timer_rand(u32 base_msec);
196 
197  // Internal state.
198  enum class State {
199  IDLE, // Idle
200  ERROR, // Error-handling in progress
201  CONNECT_IDLE, // Connection in progress, otherwise idle
202  CONNECT_BUSY, // Connection in progress, transmit once ready
203  WAIT_RESPONSE_U, // Unicast request received, awaiting response
204  WAIT_RESPONSE_M, // Multicast request received, awaiting response
205  REQUEST_CON, // Confirmable request with timed retransmit
206  REQUEST_NON, // Nonconfirmable request without retransmit
207  REQUEST_SEP, // Waiting to receive part 2 of separated response
208  RESPONSE_CACHE, // Standard response with cached retransmit
209  RESPONSE_DEFER, // Delayed response to multicast query
210  RESPONSE_SEP1, // Waiting to send separated response
211  RESPONSE_SEP2}; // Waiting for ACK to separated response
212  satcat5::coap::Endpoint* m_coap; // Client or server
213  satcat5::net::Address* const m_addr; // Remote address object
214  State m_state; // Connection state
215  u32 m_proxy_token; // Reverse-proxy identifier
216  u8 m_allow_reuse; // Ephemeral connection?
217  u8 m_tx_count; // Transmission count
218  u8 m_meta_idx; // History write index [0..N)
219  u8 m_meta_count; // History depth [0..N]
220  u8 m_flags[SATCAT5_COAP_HISTORY]; // History of transaction flags
221  u16 m_msgid[SATCAT5_COAP_HISTORY]; // History of message IDs
222  u64 m_token[SATCAT5_COAP_HISTORY]; // History of tokens (0-8 bytes)
223 
224  private:
225  // Linked list of other Connection objects.
228  };
229 
232  public:
235  satcat5::coap::Endpoint* endpoint,
237 
240  bool connect(u16 apid);
241 
242  private:
245  };
246 
249  public:
252  satcat5::coap::Endpoint* endpoint,
253  satcat5::udp::Dispatch* iface)
254  : Connection(endpoint, &m_udp), m_udp(iface) {}
255 
258  : Connection(nullptr, &m_udp), m_udp(nullptr) {}
259 
262  void init(
263  satcat5::coap::Endpoint* endpoint,
264  satcat5::udp::Dispatch* iface);
265 
268  bool connect(
269  const satcat5::udp::Addr& dstaddr,
270  const satcat5::udp::Port& dstport = satcat5::udp::PORT_COAP,
271  const satcat5::udp::Port& srcport = satcat5::udp::PORT_NONE,
272  bool allow_reuse = false);
273 
275  bool is_match_addr(
276  const satcat5::udp::Addr& dstaddr,
277  const satcat5::udp::Port& dstport) const;
278 
281  };
282 
284  template <unsigned SIZE>
285  class ConnectionUdpArray final {
286  public:
289  satcat5::coap::Endpoint* endpoint,
290  satcat5::udp::Dispatch* iface)
291  : m_array{} // Use default constructor
292  {
293  for (unsigned a = 0 ; a < SIZE ; ++a) {
294  m_array[a].init(endpoint, iface);
295  }
296  }
297 
299  inline ConnectionUdp& operator[](unsigned idx)
300  { return m_array[idx]; }
301 
302  private:
303  satcat5::coap::ConnectionUdp m_array[SIZE];
304  };
305  }
306 }
CCSDS Space Packet Protocol.
Implemention of "net::Address" API for CCSDS-SPP packets.
Definition: ccsds_spp.h:169
Implemention of "net::Dispatch" API for CCSDS-SPP packets.
Definition: ccsds_spp.h:199
CoAP request/response handling for a single client-server connection.
bool is_separate() const
< Awaiting separate response?
bool is_match_reuse() const
Idle or continue same connection.
bool write_finalize() override
Mark end of frame and release temporary working data.
bool open_separate(const satcat5::coap::ReadHeader *msg)
If able, send the first half of a separated response.
bool is_connecting() const
< Connection in progress?
u8 tkl() const
< Most recent token length
bool is_match_addr() const
< Match reply endpoint?
u64 token() const
< Most recent message token
bool ready() const
Ready to send a request?
satcat5::io::Writeable * open_response_auto()
Automatically call open_response() or continue_separate().
u8 response_type() const
Determine the expected response type for an incoming request.
bool is_request() const
< Any request state?
void timer_event() override
Child class MUST override this method.
void frame_rcvd(satcat5::io::LimitedRead &src) override
Dispatch calls frame_rcvd(...) for each incoming frame with with a matching net::Type value.
satcat5::io::Writeable * continue_separate()
If able, send the second half of a separated response.
bool is_response() const
< Any response state?
bool test_inject(unsigned len, const void *data)
Test only: Send a message using the active connection.
bool ping(u16 msg_id)
If able, send a ping request to the remote client.
u16 msg_id() const
< Most recent message ID
bool is_idle() const
< Idle and ready for use?
bool error_response(satcat5::coap::Code code, const char *why=0)
If able, return an error in response to an incoming request from a remote client.
satcat5::io::Writeable * open_response()
If able, accept an incoming request from a remote client.
bool is_match_coap(const satcat5::coap::ReadHeader *msg) const
Connection(satcat5::coap::Endpoint *endpoint, satcat5::net::Address *addr)
Constructor is only accessible to child classes.
bool is_await() const
< Awaiting initial response?
satcat5::io::Writeable * open_request()
If able, send a request to the current remote server.
void set_proxy_token(u32 token)
Set identifier for matching incoming proxy responses.
u32 get_proxy_token() const
Query the most recent proxy token.
void init(satcat5::coap::Endpoint *endpoint)
Deferred initialization of the upstream interface.
void close()
Close any open connections and reset state.
Variant of coap::Connection for CCSDS-SPP connections.
satcat5::ccsds_spp::Address m_spp
Connection to a specific APID.
bool connect(u16 apid)
Set remote APID for later calls to open_request().
ConnectionSpp(satcat5::coap::Endpoint *endpoint, satcat5::ccsds_spp::Dispatch *iface)
Create cache object and link it to the designated endpoint.
Statically-allocated array of ConnectionUdp objects.
ConnectionUdpArray(satcat5::coap::Endpoint *endpoint, satcat5::udp::Dispatch *iface)
Link each ConnectionUdp object to the specified interfaces.
ConnectionUdp & operator[](unsigned idx)
Access an internal connection object by index.
Variant of coap::Connection for UDP connections.
void init(satcat5::coap::Endpoint *endpoint, satcat5::udp::Dispatch *iface)
Deferred initialization of the upstream interface.
bool connect(const satcat5::udp::Addr &dstaddr, const satcat5::udp::Port &dstport=satcat5::udp::PORT_COAP, const satcat5::udp::Port &srcport=satcat5::udp::PORT_NONE, bool allow_reuse=false)
Set remote endpoint for later calls to open_request().
ConnectionUdp(satcat5::coap::Endpoint *endpoint, satcat5::udp::Dispatch *iface)
Create cache object and link it to the designated endpoint.
ConnectionUdp()
Default constructor must subsequently call init().
satcat5::udp::Address m_udp
Connection to a specific IP address and UDP port.
CoAP endpoint (i.e., client, server, or combined client+server).
Definition: coap_endpoint.h:41
Parser for CoAP message headers only.
Definition: coap_reader.h:80
Base-class for parsing CoAP message headers and options.
Definition: coap_reader.h:162
Thin wrapper for ArrayWrite with a built-in buffer.
Definition: io_writeable.h:169
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
Defines a generic API for sending data to a specific destination, such as a MAC address,...
Definition: net_address.h:30
virtual bool matches_reply_address() const =0
Does this Address object match the parent interface's current reply address? Multicast destinations s...
A net::Protocol is the counterpart to net::Dispatch that handles a particular data stream,...
Definition: net_protocol.h:28
Timer objects are polled after a fixed delay or at a regular interval.
Definition: polling.h:213
Implementation of "net::Address" for UDP Dispatch.
Definition: udp_core.h:72
Dispatcher sorts incoming UDP messages by port index.
Definition: udp_dispatch.h:20
Helper functions for manipulating singly-linked lists.
Definition: list.h:52
Constants relating to the Constrained Applications Protocol (CoAP)
CoAP message header CODE field (Section 12.1).
IPv4 address is a 32-bit unsigned integer.
Definition: ip_core.h:15
UDP and TCP ports are both 16-bit unsigned integers.
Definition: ip_core.h:119