feat(tcp): TCPStreamer DataSources, in-process TCPStreamService, stream multiplexing and TCPStreamJoin
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>
This commit is contained in:
1 parent
5562877c99
commit
50d85363a3
79 files changed
+12348
-138
No files matched your search
@@ -0,0 +1,163 @@
|
||||
#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_
|
||||
Reference in new issue
Block a user