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,110 @@
|
||||
#ifndef TCPS_SERVICE_STREAM_H_
|
||||
#define TCPS_SERVICE_STREAM_H_
|
||||
|
||||
/**
|
||||
* @file TCPSServiceStream.h
|
||||
* @brief UDPSServerI handle that publishes one named stream through a
|
||||
* TCPStreamService instead of through a private listening socket.
|
||||
*
|
||||
* It is what a TCPStreamer uses when its `Service` key is set. All socket work
|
||||
* (accept, handshake, flush, eviction) is done by the service's threads; the
|
||||
* producer thread only builds the frame and copies it into the bounded queue of
|
||||
* every subscribed connection (SendData never blocks on a socket).
|
||||
*/
|
||||
|
||||
#include "FastPollingMutexSem.h"
|
||||
#include "ReferenceT.h"
|
||||
#include "StreamString.h"
|
||||
#include "MutexSem.h"
|
||||
#include "TCPSStreamTapI.h"
|
||||
#include "TCPStreamService.h"
|
||||
#include "UDPSProtocol.h"
|
||||
#include "UDPSTransportI.h"
|
||||
|
||||
namespace MARTe {
|
||||
|
||||
struct TCPSConn;
|
||||
|
||||
class TCPSServiceStream : public UDPSServerI {
|
||||
public:
|
||||
/** Default maximum payload bytes per frame (matches TCPSServer). */
|
||||
static const uint32 TCPSS_DEFAULT_MAX_PAYLOAD = 60000u;
|
||||
|
||||
TCPSServiceStream(const char8 *serviceObjectName, const char8 *streamName);
|
||||
virtual ~TCPSServiceStream();
|
||||
|
||||
/** Keys: MaxPayloadSize (uint32, 1..1 MiB, default 60000). */
|
||||
virtual bool Initialise(StructuredDataI &data);
|
||||
/** Resolve the service by name and register the stream (fails on a duplicate name). */
|
||||
virtual bool Start();
|
||||
/** Unregister and drop every subscriber (idempotent). */
|
||||
virtual bool Stop();
|
||||
/** No-op: the service threads do the housekeeping. */
|
||||
virtual void ServiceClients();
|
||||
virtual bool SendConfig(const uint8 *payload, uint32 payloadSize);
|
||||
virtual bool SendData(uint32 counter, const uint8 *payload, uint32 payloadSize);
|
||||
virtual bool HasClients() const;
|
||||
virtual bool IsMulticast() const;
|
||||
/** @return the service's bound port (0 while the service is unresolved). */
|
||||
virtual uint16 GetPort() const;
|
||||
|
||||
const char8 *GetStreamName() const;
|
||||
uint32 GetClientCount() const;
|
||||
/** @return DATA frames discarded for slow subscribers (all time). */
|
||||
uint64 GetClientDrops() const;
|
||||
uint32 GetMaxPayloadSize() const;
|
||||
|
||||
/** Most taps one stream can carry. */
|
||||
static const uint32 TCPSS_MAX_TAPS = 4u;
|
||||
/**
|
||||
* Observe every CONFIG / DATA this stream publishes. The cached CONFIG (if any) is
|
||||
* replayed to the new tap before AddTap returns. Taps run on the producer thread.
|
||||
* @return false if the tap table is full.
|
||||
*/
|
||||
bool AddTap(TCPSStreamTapI *tap);
|
||||
/** Remove a tap; once it returns no callback is running or will start. */
|
||||
void RemoveTap(TCPSStreamTapI *tap);
|
||||
|
||||
/* ---- called by TCPStreamService with its topology lock held ---- */
|
||||
/** Add a connection and prime it with the cached CONFIG. @return false if full. */
|
||||
bool AttachConn(TCPSConn *c, uint16 streamIdx);
|
||||
void DetachConn(TCPSConn *c);
|
||||
/** Ask every subscriber to close and forget them. */
|
||||
void DropAllConns();
|
||||
|
||||
private:
|
||||
bool BuildFrame(uint8 *&buf, uint32 &cap, uint8 type, uint32 counter,
|
||||
const uint8 *payload, uint32 payloadSize, uint32 &frameBytes);
|
||||
void Distribute(bool isConfig, const uint8 *frame, uint32 frameBytes);
|
||||
|
||||
StreamString serviceName;
|
||||
mutable StreamString streamName;
|
||||
ReferenceT<TCPStreamService> service;
|
||||
bool registered;
|
||||
uint32 maxPayloadSize;
|
||||
|
||||
FastPollingMutexSem mutex; ///< guards subs, numSubs, cachedConfig*, drops
|
||||
TCPSConn **subs;
|
||||
uint16 *subIdx; ///< stream index each subscriber knows this stream by
|
||||
uint32 capSubs;
|
||||
volatile uint32 numSubs;
|
||||
uint8 *cachedConfigFrame;
|
||||
uint32 cachedConfigBytes;
|
||||
uint32 cachedConfigCap;
|
||||
uint32 configCounter;
|
||||
uint64 drops;
|
||||
|
||||
FastPollingMutexSem tapMutex; ///< held while a tap callback runs
|
||||
TCPSStreamTapI *taps[TCPSS_MAX_TAPS];
|
||||
volatile uint32 numTaps;
|
||||
|
||||
uint8 *dataFrame; ///< producer-thread scratch
|
||||
uint32 dataFrameCap;
|
||||
|
||||
TCPSServiceStream(const TCPSServiceStream &);
|
||||
TCPSServiceStream &operator=(const TCPSServiceStream &);
|
||||
};
|
||||
|
||||
} // namespace MARTe
|
||||
|
||||
#endif // TCPS_SERVICE_STREAM_H_
|
||||
Reference in new issue
Block a user