Add TCPStreamer/TCPStreamerClient (TCP transport behind the UDPSServerI/UDPSClientI seam), an optional single in-process TCPStreamService serving many streams over worker threads, multiplexed SUBSCRIBE (comma list, stream index in fragmentIdx), and TCPStreamJoin, which merges several streams into one sample-and-hold stream paced by a master. StreamHub takes a comma list of streams over one connection. Includes GTests, E2E scenarios s58-s73 and docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
164 lines
6.6 KiB
C++
164 lines
6.6 KiB
C++
#ifndef TCPS_CLIENT_H_
|
|
#define TCPS_CLIENT_H_
|
|
|
|
/**
|
|
* @file TCPSClient.h
|
|
* @brief Auto-reconnecting TCP receiver for the UDPS wire format.
|
|
*
|
|
* TCPSClient is the consumer-side counterpart of TCPSServer. It connects to a
|
|
* TCPSServer, reads UDPS frames (17-byte header + payload) from the byte stream
|
|
* and delivers CONFIG / DATA payloads through UDPSClientListener, so any
|
|
* listener written for UDPSClient works unchanged.
|
|
*
|
|
* It runs its own thread (SingleThreadService); every wait inside Execute() is
|
|
* bounded by 50 ms so Stop() is prompt. A partial frame survives across
|
|
* iterations. Bad magic, an oversize length, or a fragmented frame means the
|
|
* stream cannot be trusted any more: the connection is dropped and re-opened.
|
|
*
|
|
* There is no CONNECT / ACK / keepalive traffic: the TCP connection is the
|
|
* session and the server sends CONFIG on accept.
|
|
*/
|
|
|
|
#include "EmbeddedServiceMethodBinderI.h"
|
|
#include "FastPollingMutexSem.h"
|
|
#include "ExecutionInfo.h"
|
|
#include "SingleThreadService.h"
|
|
#include "StreamString.h"
|
|
#include "StructuredDataI.h"
|
|
#include "UDPSClient.h"
|
|
#include "UDPSProtocol.h"
|
|
#include "UDPSTransportI.h"
|
|
|
|
namespace MARTe {
|
|
|
|
class TCPSClient;
|
|
|
|
/**
|
|
* One stream of a (possibly multiplexed) TCPSClient connection, seen as an
|
|
* independent UDPSClientI. Obtained from TCPSClient::GetStream(). Start()/Stop()
|
|
* are reference counted so the shared connection runs while any stream wants it.
|
|
*/
|
|
class TCPSClientStream : public UDPSClientI {
|
|
public:
|
|
TCPSClientStream(TCPSClient &owner, uint32 index);
|
|
virtual ~TCPSClientStream();
|
|
/** The connection is configured through its TCPSClient; always succeeds. */
|
|
virtual bool Initialise(StructuredDataI &data);
|
|
virtual void SetListener(UDPSClientListener *newListener);
|
|
virtual bool Start();
|
|
virtual bool Stop();
|
|
virtual uint32 GetLastDataGap() const;
|
|
private:
|
|
TCPSClient &owner;
|
|
uint32 index;
|
|
bool started;
|
|
};
|
|
|
|
class TCPSClient : public UDPSClientI, public EmbeddedServiceMethodBinderI {
|
|
public:
|
|
|
|
/** Most streams one connection can multiplex. */
|
|
static const uint32 TCPS_CLIENT_MAX_STREAMS = UDPS_TCP_MAX_STREAMS;
|
|
|
|
/** Default delay between reconnect attempts (seconds). */
|
|
static const uint32 TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S = 2u;
|
|
|
|
TCPSClient();
|
|
virtual ~TCPSClient();
|
|
|
|
/**
|
|
* Keys:
|
|
* - ServerAddr (char*) IPv4 address or host name. Default 127.0.0.1.
|
|
* - Port (uint32) Server TCP port. Required.
|
|
* - StreamName (char*) Optional. When set, a SUBSCRIBE frame carrying
|
|
* this name is sent right after every connect, to
|
|
* select one stream of a TCPStreamService. A plain
|
|
* TCPSServer ignores (discards) it. A comma
|
|
* separated list ("a,b,c") multiplexes several
|
|
* streams over this one connection; stream i of
|
|
* the list is reached through GetStream(i).
|
|
* - SilenceTimeout (float32) Seconds without any received byte before the
|
|
* connection is considered dead. Default 0
|
|
* (disabled: TCP reports a dead peer itself).
|
|
* - ReconnectDelay (float32) Seconds between connection attempts. Default 2.
|
|
* - CPUMask (uint32) Receive thread affinity. Default 0xFFFFFFFF.
|
|
* - StackSize (uint32) Receive thread stack. Default 65536.
|
|
*/
|
|
virtual bool Initialise(StructuredDataI &data);
|
|
virtual void SetListener(UDPSClientListener *newListener);
|
|
/** Listener of stream @p index (0 = SetListener()). Call before Start(). */
|
|
void SetStreamListener(uint32 index, UDPSClientListener *newListener);
|
|
/** @return number of streams subscribed to (1 unless StreamName is a list). */
|
|
uint32 GetNumStreams() const;
|
|
/**
|
|
* @return a UDPSClientI for stream @p index, owned by this client (NULL if out of
|
|
* range). Valid after Initialise().
|
|
*/
|
|
UDPSClientI *GetStream(uint32 index);
|
|
/** Counter gap of the DATA frame of stream @p index being delivered. */
|
|
uint32 GetStreamDataGap(uint32 index) const;
|
|
/** Reference-counted Start()/Stop() used by the TCPSClientStream facades. */
|
|
bool AcquireStart();
|
|
bool ReleaseStop();
|
|
virtual bool Start();
|
|
virtual bool Stop();
|
|
|
|
/** Thread entry point; do not call directly. */
|
|
virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info);
|
|
|
|
/** Packets the server dropped for this client just before the DATA frame being delivered. */
|
|
virtual uint32 GetLastDataGap() const;
|
|
|
|
/** @return true while a connection is established. */
|
|
bool IsConnected() const;
|
|
/** @return connections established since Start(). */
|
|
uint32 GetConnectionCount() const;
|
|
/** @return connections dropped because of a protocol violation. */
|
|
uint32 GetProtocolErrors() const;
|
|
|
|
private:
|
|
bool Connect();
|
|
void Disconnect();
|
|
/** One bounded receive step. @return false when the connection is lost. */
|
|
bool ReceiveStep();
|
|
/** Deliver the complete frame sitting in rxBuf. @return false on a protocol error. */
|
|
bool Dispatch();
|
|
/** Validate StreamName as one name or a comma separated list; sets numStreams. */
|
|
bool ParseStreamList();
|
|
|
|
StreamString serverAddr;
|
|
StreamString streamName;
|
|
uint32 serverPort;
|
|
uint64 silenceTimeoutTicks;
|
|
uint64 reconnectDelayTicks;
|
|
uint32 cpuMask;
|
|
uint32 stackSize;
|
|
|
|
uint32 numStreams;
|
|
UDPSClientListener *listeners[UDPS_TCP_MAX_STREAMS];
|
|
TCPSClientStream *facades[UDPS_TCP_MAX_STREAMS];
|
|
FastPollingMutexSem refMutex;
|
|
uint32 startRefs;
|
|
SingleThreadService threadService;
|
|
|
|
int fd;
|
|
volatile bool connected;
|
|
volatile bool stopping;
|
|
uint64 lastDataTicks;
|
|
uint64 disconnectTick;
|
|
volatile uint32 connectionCount;
|
|
volatile uint32 protocolErrors;
|
|
|
|
uint8 *rxBuf; ///< header + payload of the frame being received
|
|
uint32 rxHave; ///< bytes of the current frame received so far
|
|
uint32 rxWant; ///< total bytes the current frame needs (header first)
|
|
bool rxHeaderOk; ///< header validated; rxWant covers the payload
|
|
uint32 lastDataCounter[UDPS_TCP_MAX_STREAMS]; ///< counter of the last delivered DATA frame
|
|
bool lastDataCounterValid[UDPS_TCP_MAX_STREAMS]; ///< false until the first DATA frame of a connection
|
|
uint32 lastDataGap[UDPS_TCP_MAX_STREAMS]; ///< frames missing before the one being delivered
|
|
};
|
|
|
|
} // namespace MARTe
|
|
|
|
#endif // TCPS_CLIENT_H_
|