275 lines
10 KiB
C++
275 lines
10 KiB
C++
#ifndef UDPS_SERVER_H_
|
|
#define UDPS_SERVER_H_
|
|
|
|
/**
|
|
* @file UDPSServer.h
|
|
* @brief Multi-client UDPS session-management and fragmented-send helper.
|
|
*
|
|
* UDPSServer is a plain C++ helper (not a MARTe2 Object) that encapsulates:
|
|
* - Unicast mode: up to UDPS_SERVER_MAX_UNICAST_CLIENTS simultaneous UDP clients
|
|
* that self-register via CONNECT datagrams.
|
|
* - Multicast mode: TCP listener for CONNECT + CONFIG delivery; UDP multicast
|
|
* socket for DATA datagrams.
|
|
* - Static clients: pre-configured destinations that never need to send CONNECT
|
|
* (backward-compat for push-to-fixed-IP use cases).
|
|
*
|
|
* Threading model: UDPSServer is NOT thread-safe. All public methods must be
|
|
* called from the same thread (the owner's Execute() thread).
|
|
*/
|
|
|
|
#include "BasicTCPSocket.h"
|
|
#include "BasicUDPSocket.h"
|
|
#include "InternetHost.h"
|
|
#include "StreamString.h"
|
|
#include "StructuredDataI.h"
|
|
#include "UDPSProtocol.h"
|
|
|
|
namespace MARTe {
|
|
|
|
/**
|
|
* @brief Multi-client / multicast UDPS server helper.
|
|
*
|
|
* Usage pattern:
|
|
* @code
|
|
* UDPSServer server;
|
|
* server.Initialise(data); // in component Initialise()
|
|
* server.Start(); // in PrepareNextState() / Start()
|
|
* // inside Execute() loop:
|
|
* server.ServiceClients(); // poll CONNECT / DISCONNECT / ACK
|
|
* if (server.HasClients()) {
|
|
* server.SendConfig(cfgBuf, cfgSize); // when config changes
|
|
* server.SendData(counter, dataBuf, dataSize);
|
|
* }
|
|
* server.Stop(); // in StopCurrentStateExecution()
|
|
* @endcode
|
|
*/
|
|
class UDPSServer {
|
|
public:
|
|
|
|
/** Maximum number of simultaneous unicast clients. */
|
|
static const uint32 UDPS_SERVER_MAX_UNICAST_CLIENTS = 16u;
|
|
|
|
/** Maximum number of simultaneous multicast TCP control connections. */
|
|
static const uint32 UDPS_SERVER_MAX_TCP_CLIENTS = 8u;
|
|
|
|
/** Default stale-client eviction timeout (seconds). */
|
|
static const uint32 UDPS_SERVER_DEFAULT_CLIENT_TIMEOUT_S = 30u;
|
|
|
|
/** Default maximum UDP payload size (bytes, EXCLUDING the 17-byte header). */
|
|
static const uint32 UDPS_SERVER_DEFAULT_MAX_PAYLOAD = 1400u;
|
|
|
|
UDPSServer();
|
|
~UDPSServer();
|
|
|
|
/**
|
|
* @brief Read configuration from a StructuredDataI node.
|
|
*
|
|
* Expected keys (all optional except Port for unicast):
|
|
* - Port (uint16) UDP port to bind (unicast) or TCP listen port (multicast).
|
|
* - MulticastGroup (char*) IPv4 multicast address; presence enables multicast mode.
|
|
* - DataPort (uint16) UDP port used for DATA datagrams in multicast mode
|
|
* (defaults to Port+1 if omitted).
|
|
* - MaxPayloadSize (uint32) Max payload bytes per datagram, excluding header.
|
|
* Defaults to UDPS_SERVER_DEFAULT_MAX_PAYLOAD.
|
|
* - ClientTimeout (uint32) Seconds before a silent unicast client is evicted.
|
|
* Defaults to UDPS_SERVER_DEFAULT_CLIENT_TIMEOUT_S.
|
|
* Set to 0 to disable timeout-based eviction.
|
|
*/
|
|
bool Initialise(StructuredDataI &data);
|
|
|
|
/**
|
|
* @brief Open sockets and begin accepting clients.
|
|
* @return true on success.
|
|
*/
|
|
bool Start();
|
|
|
|
/**
|
|
* @brief Close all sockets and evict all clients. Frees cached CONFIG.
|
|
*/
|
|
bool Stop();
|
|
|
|
/**
|
|
* @brief Non-blocking poll for incoming CONNECT / DISCONNECT / ACK messages.
|
|
*
|
|
* Must be called regularly from the owner's Execute() main loop.
|
|
* In multicast mode also polls the TCP listener for new connections.
|
|
*/
|
|
void ServiceClients();
|
|
|
|
/**
|
|
* @brief Send a CONFIG payload to all active clients.
|
|
*
|
|
* Also stores a copy as the cached CONFIG, which is automatically sent to
|
|
* any new CONNECT client.
|
|
*
|
|
* @param payload Pointer to fully-assembled CONFIG payload (caller-owned).
|
|
* @param payloadSize Byte count of payload.
|
|
* @return true if at least one send succeeded (or no clients are connected).
|
|
*/
|
|
bool SendConfig(const uint8 *payload, uint32 payloadSize);
|
|
|
|
/**
|
|
* @brief Send a DATA payload to all active clients.
|
|
*
|
|
* @param counter Per-update sequence counter (same for all fragments).
|
|
* @param payload Pointer to fully-assembled DATA payload (caller-owned).
|
|
* @param payloadSize Byte count of payload.
|
|
* @return true if all sends succeeded.
|
|
*/
|
|
bool SendData(uint32 counter, const uint8 *payload, uint32 payloadSize);
|
|
|
|
/**
|
|
* @brief Add a static unicast destination that never needs to send CONNECT.
|
|
*
|
|
* The entry is never evicted by the timeout mechanism. Duplicate
|
|
* (ip, port) pairs are silently ignored.
|
|
*
|
|
* @param ip Destination IPv4 address string.
|
|
* @param port Destination UDP port.
|
|
* @return true if the client was added (or was already present).
|
|
*/
|
|
bool AddStaticClient(const char8 *ip, uint16 port);
|
|
|
|
/** @return Number of currently active clients (unicast + TCP). */
|
|
uint32 GetClientCount() const;
|
|
|
|
/** @return true if at least one client is active. */
|
|
bool HasClients() const;
|
|
|
|
/** @return true if server is in multicast mode. */
|
|
bool IsMulticast() const;
|
|
|
|
/** @return Configured port number. */
|
|
uint16 GetPort() const;
|
|
|
|
/** @return Configured maximum payload size (excluding header). */
|
|
uint32 GetMaxPayloadSize() const;
|
|
|
|
private:
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Per-client state (unicast)
|
|
// -------------------------------------------------------------------------
|
|
struct UDPSClientEntry {
|
|
char8 ipAddr[64]; ///< Client IPv4 address string
|
|
uint16 clientPort; ///< Client source port
|
|
uint64 lastSeenTicks; ///< HighResolutionTimer ticks at last contact
|
|
bool active; ///< Slot is in use
|
|
bool isStatic; ///< Never evicted by timeout; no CONNECT required
|
|
};
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Private helpers
|
|
// -------------------------------------------------------------------------
|
|
|
|
/**
|
|
* @brief Send a fragmented UDPS packet via a UDP socket.
|
|
*
|
|
* @param sock Socket to write through.
|
|
* @param dest If non-NULL, SetDestination is called before each write
|
|
* (unicast unconnected socket). If NULL, assumes the socket
|
|
* is already connected (multicast dataSocket).
|
|
* @param type UDPS_TYPE_DATA or UDPS_TYPE_CONFIG.
|
|
* @param counter Sequence counter.
|
|
* @param payload Payload bytes.
|
|
* @param payloadSize Payload byte count.
|
|
* @return true if all fragments were written without error.
|
|
*/
|
|
bool SendFragmentedUDP(BasicUDPSocket &sock,
|
|
InternetHost *dest,
|
|
uint8 type,
|
|
uint32 counter,
|
|
const uint8 *payload,
|
|
uint32 payloadSize);
|
|
|
|
/**
|
|
* @brief Send a fragmented UDPS packet via a TCP socket.
|
|
*
|
|
* Used in multicast mode to push CONFIG to each TCP control client.
|
|
*/
|
|
bool SendFragmentedTCP(BasicTCPSocket &sock,
|
|
uint8 type,
|
|
uint32 counter,
|
|
const uint8 *payload,
|
|
uint32 payloadSize);
|
|
|
|
/** Evict unicast clients that have been silent longer than clientTimeoutTicks. */
|
|
void EvictStaleUnicastClients();
|
|
|
|
/** Handle a CONNECT datagram received on serverSocket. */
|
|
void HandleUnicastConnect(const InternetHost &src);
|
|
|
|
/** Handle a DISCONNECT datagram received on serverSocket. */
|
|
void HandleUnicastDisconnect(const InternetHost &src);
|
|
|
|
/** Handle an ACK datagram received on serverSocket. */
|
|
void HandleUnicastAck(const InternetHost &src);
|
|
|
|
/**
|
|
* @brief Find a unicast client slot by IP + port.
|
|
* @return Slot index, or UDPS_SERVER_MAX_UNICAST_CLIENTS if not found.
|
|
*/
|
|
uint32 FindUnicastClient(const char8 *ip, uint16 port) const;
|
|
|
|
/**
|
|
* @brief Find the oldest (lowest lastSeenTicks) non-static unicast client.
|
|
* @return Slot index, or UDPS_SERVER_MAX_UNICAST_CLIENTS if none.
|
|
*/
|
|
uint32 FindOldestUnicastClient() const;
|
|
|
|
/** Close slot @p idx and mark it inactive. */
|
|
void EvictUnicastClient(uint32 idx);
|
|
|
|
/** Accept a new multicast TCP connection and send cached CONFIG. */
|
|
void HandleMulticastTCPConnect(BasicTCPSocket *newClient, uint32 idx);
|
|
|
|
/** Close TCP client slot @p idx. */
|
|
void EvictTCPClient(uint32 idx);
|
|
|
|
/** Cache a copy of a CONFIG payload for future CONNECT clients. */
|
|
bool CacheConfig(const uint8 *payload, uint32 payloadSize);
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Configuration
|
|
// -------------------------------------------------------------------------
|
|
uint16 port;
|
|
uint32 maxPayloadSize;
|
|
StreamString multicastGroup;
|
|
uint16 dataPort;
|
|
bool useMulticast;
|
|
uint64 clientTimeoutTicks; ///< 0 = disabled
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Unicast state
|
|
// -------------------------------------------------------------------------
|
|
UDPSClientEntry unicastClients[UDPS_SERVER_MAX_UNICAST_CLIENTS];
|
|
uint32 numUnicastClients;
|
|
|
|
BasicUDPSocket serverSocket; ///< Bound to port; receives CONNECT/DISCONNECT/ACK
|
|
BasicUDPSocket uniSendSocket; ///< Unconnected; SetDestination before each Write
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Multicast state
|
|
// -------------------------------------------------------------------------
|
|
BasicTCPSocket tcpListener;
|
|
BasicTCPSocket *tcpClients[UDPS_SERVER_MAX_TCP_CLIENTS];
|
|
uint32 numTCPClients;
|
|
BasicUDPSocket dataSocket; ///< Connected to multicastGroup:dataPort
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Shared state
|
|
// -------------------------------------------------------------------------
|
|
uint8 *cachedConfig; ///< Last SendConfig() payload (heap-allocated)
|
|
uint32 cachedConfigSize;
|
|
|
|
uint8 *sendBuf; ///< Pre-allocated fragment TX buffer
|
|
uint32 sendBufCapacity; ///< UDPS_HEADER_SIZE + maxPayloadSize
|
|
|
|
uint32 configCounter; ///< Sequence counter for CONFIG packets
|
|
bool started;
|
|
};
|
|
|
|
} // namespace MARTe
|
|
|
|
#endif // UDPS_SERVER_H_
|