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:
Martino FerrariandClaude Opus 4.6 committed 2026-11-06 13:41:27 +01:00
1 parent 5562877c99
commit 50d85363a3
79 files changed
+12348 -138

No files matched your search

+203 -9
View File
@@ -92,6 +92,7 @@ StreamHub::StreamHub()
memset(calibration_, 0, sizeof(CalibrationEntry) * kMaxCalibration);
for (uint32 i = 0u; i < kMaxSessions; i++) {
sessionActive_[i] = false;
sessionMux_[i] = -1;
configBroadcast_[i] = false;
capHarvested_[i] = false;
for (uint32 s = 0u; s < UDPSS_MAX_SIGNALS; s++) {
@@ -273,11 +274,33 @@ bool StreamHub::Initialise(StructuredDataI &cfg) {
}
cfg.Read("DataPort", dataPort32);
char transport[8] = "udp";
char streamName[256] = "";
StreamString trStr;
if (cfg.Read("Transport", trStr)) {
strncpy(transport, trStr.Buffer(), sizeof(transport) - 1u);
}
StreamString snStr;
if (cfg.Read("StreamName", snStr)) {
strncpy(streamName, snStr.Buffer(), sizeof(streamName) - 1u);
}
if ((strcmp(transport, "tcp") == 0) && (strchr(streamName, ',') != static_cast<char *>(0))) {
/* Several streams over one connection: slots are allocated by the helper. */
if (!AddMuxSourceInternal(label, addr, port32, addr, streamName, nodeId.Buffer())) {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Warning,
"StreamHub: failed to start multiplexed source '%s'.", nodeId.Buffer());
}
cfg.MoveToAncestor(1u);
continue;
}
sessions_[numSessions_].SetRingCapacities(ringTemporal_, ringScalar_);
bool ok = sessions_[numSessions_].Initialise(
nodeId.Buffer(), label, addr,
static_cast<uint16>(port32), maxPoints_,
mcGroup, static_cast<uint16>(dataPort32));
mcGroup, static_cast<uint16>(dataPort32),
transport, streamName);
if (ok) {
sessions_[numSessions_].SetRecorderConfig(recorderCfg_);
@@ -1201,15 +1224,20 @@ void StreamHub::HandleAddSource(const char *json) {
JsonGetString(json, "addr", addr, sizeof(addr));
JsonGetString(json, "multicastGroup", mcGroup, sizeof(mcGroup));
JsonGetFloat(json, "dataPort", dataPortF);
char transport[8] = "udp";
char streamName[256] = "";
JsonGetString(json, "transport", transport, sizeof(transport));
JsonGetString(json, "streamName", streamName, sizeof(streamName));
if (AddSourceInternal(label, addr, mcGroup,
static_cast<uint16>(dataPortF))) {
static_cast<uint16>(dataPortF), transport, streamName)) {
BroadcastSources();
}
}
bool StreamHub::AddSourceInternal(const char *label, const char *addrPort,
const char *mcGroup, uint16 dataPort) {
const char *mcGroup, uint16 dataPort,
const char *transport, const char *streamName) {
if ((addrPort == static_cast<const char *>(0)) || (addrPort[0] == '\0')) {
return false;
}
@@ -1226,6 +1254,12 @@ bool StreamHub::AddSourceInternal(const char *label, const char *addrPort,
*colon = '\0';
}
if ((transport != static_cast<const char *>(0)) && (strcmp(transport, "tcp") == 0) &&
(streamName != static_cast<const char *>(0)) &&
(strchr(streamName, ',') != static_cast<const char *>(0))) {
return AddMuxSourceInternal(label, host, port, addrPort, streamName);
}
/* Whole add is serialized against other WS-thread add/remove requests.
* The push thread never takes this mutex: it only observes the
* sessionActive_[] flag, which is set last (after a successful Start). */
@@ -1256,7 +1290,7 @@ bool StreamHub::AddSourceInternal(const char *label, const char *addrPort,
sessions_[idx].SetRingCapacities(ringTemporal_, ringScalar_);
bool ok = sessions_[idx].Initialise(id, lbl, host,
static_cast<uint16>(port), maxPoints_,
mcGroup, dataPort);
mcGroup, dataPort, transport, streamName);
if (ok) {
sessions_[idx].SetRecorderConfig(recorderCfg_);
ok = sessions_[idx].Start();
@@ -1275,14 +1309,151 @@ bool StreamHub::AddSourceInternal(const char *label, const char *addrPort,
return ok;
}
bool StreamHub::SourceIsActive(const char *addrPort) {
bool StreamHub::AddMuxSourceInternal(const char *label, const char *host, uint32 port,
const char *addrPort, const char *streamList,
const char *idPrefix) {
char list[MARTe::UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD + 1u];
strncpy(list, streamList, sizeof(list) - 1u);
list[sizeof(list) - 1u] = '\0';
const char *names[kMaxSessions];
uint32 n = 0u;
char *cur = list;
while (cur != static_cast<char *>(0)) {
char *comma = strchr(cur, ',');
if (comma != static_cast<char *>(0)) { *comma = '\0'; }
if ((cur[0] == '\0') || (n >= kMaxSessions)) {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Warning,
"StreamHub: bad stream list '%s' (empty name or more than %u streams).",
streamList, kMaxSessions);
return false;
}
names[n++] = cur;
cur = (comma != static_cast<char *>(0)) ? (comma + 1) : static_cast<char *>(0);
}
(void) sessionsMutex_.FastLock();
uint32 slots[kMaxSessions];
uint32 found = 0u;
for (uint32 i = 0u; (i < kMaxSessions) && (found < n); i++) {
if (!sessionActive_[i]) { slots[found++] = i; }
}
uint32 mux = kMaxSessions;
for (uint32 i = 0u; i < kMaxSessions; i++) {
if (muxClients_[i].client == static_cast<MARTe::TCPSClient *>(0)) { mux = i; break; }
}
if ((found < n) || (mux == kMaxSessions)) {
sessionsMutex_.FastUnLock();
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Warning,
"StreamHub: not enough free sessions for %u streams, ignoring addSource.", n);
return false;
}
MARTe::TCPSClient *client = new MARTe::TCPSClient();
ConfigurationDatabase cfg;
(void) cfg.Write("ServerAddr", host);
(void) cfg.Write("Port", port);
(void) cfg.Write("StreamName", streamList);
bool ok = client->Initialise(cfg) && (client->GetNumStreams() == n);
if (!ok) {
delete client;
sessionsMutex_.FastUnLock();
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Warning,
"StreamHub: could not set up the multiplexed receiver for '%s'.", streamList);
return false;
}
muxClients_[mux].client = client;
muxClients_[mux].refs = 0u;
const char *base = ((label != static_cast<const char *>(0)) && (label[0] != '\0')) ? label
: static_cast<const char *>(0);
/* Initialise every session (listeners attached) before any can receive. */
uint32 initialised = 0u;
for (uint32 k = 0u; (k < n) && ok; k++) {
const uint32 idx = slots[k];
char id[16 + 256];
if (idPrefix != static_cast<const char *>(0)) {
snprintf(id, sizeof(id), "%s_%s", idPrefix, names[k]);
} else {
snprintf(id, sizeof(id), "s%u", nextSourceId_++);
}
char lbl[160];
if (base != static_cast<const char *>(0)) {
snprintf(lbl, sizeof(lbl), "%s_%s", base, names[k]);
} else {
snprintf(lbl, sizeof(lbl), "%s", names[k]);
}
configBroadcast_[idx] = false;
for (uint32 s = 0u; s < UDPSS_MAX_SIGNALS; s++) { pushCursor_[idx][s] = 0u; }
sessions_[idx].SetRingCapacities(ringTemporal_, ringScalar_);
ok = sessions_[idx].Initialise(id, lbl, host, static_cast<uint16>(port), maxPoints_,
"", 0u, "tcp", names[k], client->GetStream(k));
if (ok) {
sessionMux_[idx] = static_cast<MARTe::int32>(mux);
muxClients_[mux].refs++;
initialised++;
}
}
for (uint32 k = 0u; (k < initialised) && ok; k++) {
sessions_[slots[k]].SetRecorderConfig(recorderCfg_);
ok = sessions_[slots[k]].Start();
}
if (ok) {
for (uint32 k = 0u; k < n; k++) {
sessionActive_[slots[k]] = true;
numSessions_++;
}
} else {
for (uint32 k = 0u; k < initialised; k++) { ReleaseMuxSlot(slots[k]); }
if (muxClients_[mux].client != static_cast<MARTe::TCPSClient *>(0)) {
delete muxClients_[mux].client; /* no session ever attached */
muxClients_[mux].client = static_cast<MARTe::TCPSClient *>(0);
}
}
sessionsMutex_.FastUnLock();
if (ok) {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information,
"StreamHub: added %u multiplexed sessions over one connection (%s).", n, addrPort);
}
return ok;
}
void StreamHub::ReleaseMuxSlot(uint32 slot) {
/* Caller holds sessionsMutex_. */
if (sessionMux_[slot] < 0) { return; }
const uint32 m = static_cast<uint32>(sessionMux_[slot]);
sessions_[slot].DetachClient();
sessionMux_[slot] = -1;
if ((muxClients_[m].refs > 0u) && (--muxClients_[m].refs == 0u)) {
delete muxClients_[m].client;
muxClients_[m].client = static_cast<MARTe::TCPSClient *>(0);
}
}
bool StreamHub::SourceIsActive(const char *addrPort, const char *streamName) {
if (strchr(streamName, ',') != static_cast<const char *>(0)) {
/* A list is active when every stream of it is. */
char list[MARTe::UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD + 1u];
strncpy(list, streamName, sizeof(list) - 1u);
list[sizeof(list) - 1u] = '\0';
bool all = true;
char *cur = list;
while (all && (cur != static_cast<char *>(0))) {
char *comma = strchr(cur, ',');
if (comma != static_cast<char *>(0)) { *comma = '\0'; }
all = SourceIsActive(addrPort, cur);
cur = (comma != static_cast<char *>(0)) ? (comma + 1) : static_cast<char *>(0);
}
return all;
}
for (uint32 i = 0u; i < kMaxSessions; i++) {
if (!sessionActive_[i]) { continue; }
StreamString adr = sessions_[i].GetAddr();
char cur[96];
(void) snprintf(cur, sizeof(cur), "%s:%u", adr.Buffer(),
static_cast<uint32>(sessions_[i].GetPort()));
if (strcmp(cur, addrPort) == 0) { return true; }
StreamString sn = sessions_[i].GetStreamName();
if ((strcmp(cur, addrPort) == 0) && (strcmp(sn.Buffer(), streamName) == 0)) { return true; }
}
return false;
}
@@ -1335,11 +1506,16 @@ bool StreamHub::LoadSourcesFile(bool skipActive, bool clearCalibration) {
(void) JsonGetString(obj, "label", label, sizeof(label));
(void) JsonGetString(obj, "multicastGroup", mcGroup, sizeof(mcGroup));
(void) JsonGetFloat(obj, "dataPort", dataPortF);
if (skipActive && SourceIsActive(addr)) {
char transport[8] = "udp";
char streamName[256] = "";
(void) JsonGetString(obj, "transport", transport, sizeof(transport));
(void) JsonGetString(obj, "streamName", streamName, sizeof(streamName));
if (skipActive && SourceIsActive(addr, streamName)) {
/* Already streaming — leave the live session untouched. */
}
else if (AddSourceInternal(label, addr, mcGroup,
static_cast<uint16>(dataPortF))) {
static_cast<uint16>(dataPortF),
transport, streamName)) {
nLoaded++;
}
}
@@ -1414,6 +1590,14 @@ void StreamHub::HandleSaveSources() {
static_cast<uint32>(dpt));
}
}
StreamString trn = sessions_[i].GetTransport();
if (strcmp(trn.Buffer(), "tcp") == 0) {
(void) fprintf(f, ",\n \"transport\": \"tcp\"");
StreamString sn = sessions_[i].GetStreamName();
if (sn.Size() > 0u) {
(void) fprintf(f, ",\n \"streamName\": \"%s\"", sn.Buffer());
}
}
(void) fprintf(f, "\n }");
nSaved++;
}
@@ -1500,16 +1684,26 @@ void StreamHub::HandleRemoveSource(const char *json) {
break;
}
}
bool shared = false;
if (found < kMaxSessions) {
sessionActive_[found] = false;
configBroadcast_[found] = false; /* allow re-broadcast on slot reuse */
numSessions_--;
if (sessionMux_[found] >= 0) {
/* One stream of a shared receiver: stop it and drop its listener
* under the lock, so the slot cannot be reused underneath. */
sessions_[found].Stop();
ReleaseMuxSlot(found);
shared = true;
}
}
sessionsMutex_.FastUnLock();
if (found == kMaxSessions) { return; }
sessions_[found].Stop();
if (!shared) {
sessions_[found].Stop();
}
REPORT_ERROR_STATIC(MARTe::ErrorManagement::Information,
"StreamHub: removed session '%s'.", id);
+34 -3
View File
@@ -231,11 +231,27 @@ private:
* @return true if the session was started.
*/
bool AddSourceInternal(const char *label, const char *addrPort,
const char *mcGroup, uint16 dataPort);
const char *mcGroup, uint16 dataPort,
const char *transport = "udp",
const char *streamName = "");
/**
* @brief TCP source whose streamName is a comma separated list "a,b,c": one
* TCPSClient (one socket) feeds one session per stream, labelled
* "<label>_<stream>" (just "<stream>" without a label). Session ids are
* "s<N>", or "<idPrefix>_<stream>" when @p idPrefix (the config node id) is given.
* @return true if every session was started (none is left behind otherwise).
*/
bool AddMuxSourceInternal(const char *label, const char *host, uint32 port,
const char *addrPort, const char *streamList,
const char *idPrefix = static_cast<const char *>(0));
/** @brief Detach @p slot from its shared receiver; frees the receiver with its last session. */
void ReleaseMuxSlot(uint32 slot);
/**
* @brief Load sources and calibration from sourcesFile_ (a flat JSON array
* of {"label","addr","multicastGroup","dataPort"} source blocks and
* of {"label","addr","multicastGroup","dataPort","transport","streamName"} source blocks and
* {"source","signal","scale","offset","unit"} calibration blocks).
* @param skipActive when true, a source whose "host:port" is already
* streaming is left alone instead of being started a second time.
@@ -247,7 +263,7 @@ private:
bool LoadSourcesFile(bool skipActive, bool clearCalibration = false);
/** @return true if a session for this "host:port" is already active. */
bool SourceIsActive(const char *addrPort);
bool SourceIsActive(const char *addrPort, const char *streamName = "");
/**
* @brief Store or replace one calibration entry. An identity entry
@@ -280,6 +296,21 @@ private:
/* ---- Members --------------------------------------------------------- */
/** A multiplexed receiver shared by several sessions (deleted with the last one). */
struct MuxClient {
MuxClient() : client(static_cast<MARTe::TCPSClient *>(0)), refs(0u) {}
~MuxClient() { delete client; }
MARTe::TCPSClient *client;
uint32 refs;
private:
MuxClient(const MuxClient &);
MuxClient &operator=(const MuxClient &);
};
/* Declared before sessions_ so it is destroyed after them: a session stops
* its (facade of a) shared receiver from its own destructor. */
MuxClient muxClients_[kMaxSessions];
MARTe::int32 sessionMux_[kMaxSessions]; ///< Index into muxClients_, or -1
UDPSourceSession sessions_[kMaxSessions];
uint32 numSessions_; ///< Count of active sessions (not an upper slot bound)
bool sessionActive_[kMaxSessions]; ///< Per-slot in-use flag (slots are not compacted on removal)
@@ -51,6 +51,8 @@ UDPSourceSession::UDPSourceSession()
ringTemporal_(1000000u),
ringScalar_(100000u),
initialised_(false),
client_(static_cast<MARTe::UDPSClientI *>(0)),
external_(false),
numSignals_(0u),
publishMode_(0u),
configured_(false),
@@ -112,7 +114,10 @@ bool UDPSourceSession::Initialise(const char *id, const char *label,
const char *addr, uint16 port,
uint32 maxPts,
const char *mcGroup,
uint16 dataPort) {
uint16 dataPort,
const char *transport,
const char *streamName,
MARTe::UDPSClientI *external) {
(void) Stop();
id_ = id;
@@ -121,25 +126,42 @@ bool UDPSourceSession::Initialise(const char *id, const char *label,
port_ = port;
mcGroup_ = (mcGroup != static_cast<const char *>(0)) ? mcGroup : "";
dataPort_ = dataPort;
transport_ = ((transport != static_cast<const char *>(0)) && (strcmp(transport, "tcp") == 0)) ? "tcp" : "udp";
streamName_ = (streamName != static_cast<const char *>(0)) ? streamName : "";
maxPoints_ = (maxPts > 0u) ? maxPts : 20000u;
/* Build ConfigurationDatabase for UDPSClient */
ConfigurationDatabase cfg;
(void) cfg.Write("ServerAddr", addr);
(void) cfg.Write("Port", static_cast<uint32>(port));
if ((mcGroup != static_cast<const char *>(0)) && (strlen(mcGroup) > 0u)) {
const bool useTcp = (transport_ == "tcp");
if (useTcp) {
if (streamName_.Size() > 0u) {
(void) cfg.Write("StreamName", streamName_.Buffer());
}
} else if ((mcGroup != static_cast<const char *>(0)) && (strlen(mcGroup) > 0u)) {
(void) cfg.Write("MulticastGroup", mcGroup);
if (dataPort > 0u) {
(void) cfg.Write("DataPort", static_cast<uint32>(dataPort));
}
}
if (!client_.Initialise(cfg)) {
external_ = (external != static_cast<MARTe::UDPSClientI *>(0));
if (external_) {
client_ = external; /* already configured by its owner */
}
else {
client_ = useTcp ? static_cast<MARTe::UDPSClientI *>(&tcpClient_)
: static_cast<MARTe::UDPSClientI *>(&udpClient_);
}
if (!external_ && !client_->Initialise(cfg)) {
REPORT_ERROR_STATIC(MARTe::ErrorManagement::FatalError,
"UDPSourceSession[%s]: Failed to initialise UDPSClient.", id);
"UDPSourceSession[%s]: Failed to initialise %s client.",
id, useTcp ? "TCPSClient" : "UDPSClient");
client_ = static_cast<MARTe::UDPSClientI *>(0);
return false;
}
client_.SetListener(this);
client_->SetListener(this);
(void) metaMutex_.FastLock();
numSignals_ = 0u;
@@ -165,12 +187,22 @@ bool UDPSourceSession::Start() {
statByteCount_ = 0u;
stateStr_ = "connecting";
statsMutex_.FastUnLock();
return client_.Start();
return client_->Start();
}
void UDPSourceSession::DetachClient() {
if (!external_) { return; }
(void) Stop();
if (client_ != static_cast<MARTe::UDPSClientI *>(0)) {
client_->SetListener(static_cast<MARTe::UDPSClientListener *>(0));
}
client_ = static_cast<MARTe::UDPSClientI *>(0);
external_ = false;
}
bool UDPSourceSession::Stop() {
if (!initialised_) { return true; }
return client_.Stop();
if (!initialised_ || (client_ == static_cast<MARTe::UDPSClientI *>(0))) { return true; }
return client_->Stop();
}
/*---------------------------------------------------------------------------*/
@@ -200,7 +232,7 @@ void UDPSourceSession::OnUDPSConfig(const uint8 *payload, uint32 payloadSize) {
void UDPSourceSession::OnUDPSData(const uint8 *payload, uint32 payloadSize) {
/* Valid only for the duration of this callback. */
ParseDataPayload(payload, payloadSize, client_.GetLastDataGap());
ParseDataPayload(payload, payloadSize, client_->GetLastDataGap());
}
/*---------------------------------------------------------------------------*/
@@ -947,6 +979,10 @@ StreamString UDPSourceSession::GetMulticastGroup() const { return mcGroup_; }
uint16 UDPSourceSession::GetDataPort() const { return dataPort_; }
StreamString UDPSourceSession::GetTransport() const { return transport_; }
StreamString UDPSourceSession::GetStreamName() const { return streamName_; }
bool UDPSourceSession::IsConfigured() const {
(void) metaMutex_.FastLock();
bool c = configured_;
@@ -11,6 +11,7 @@
#define STREAMHUB_UDP_SOURCE_SESSION_H_
#include "UDPSClient.h"
#include "TCPSClient.h"
#include "UDPSProtocol.h"
#include "FastPollingMutexSem.h"
#include "HighResolutionTimer.h"
@@ -158,11 +159,23 @@ public:
* @param maxPts Ring buffer capacity per signal.
* @param mcGroup Multicast group (empty string = unicast).
* @param dataPort Multicast data port (0 = port+1).
* @param transport "udp" (default) or "tcp". TCP ignores mcGroup/dataPort.
* @param streamName TCP only: stream to subscribe to on a TCPStreamService
* ("" = plain TCPStreamer, no subscription).
* @param external Optional receiver owned by the caller (one stream of a
* multiplexed TCPSClient, see TCPSClient::GetStream()). When set the
* session does not create or configure its own client; call
* DetachClient() before the receiver is destroyed.
* @return true on success.
*/
bool Initialise(const char *id, const char *label,
const char *addr, uint16 port, uint32 maxPts,
const char *mcGroup = "", uint16 dataPort = 0u);
const char *mcGroup = "", uint16 dataPort = 0u,
const char *transport = "udp", const char *streamName = "",
MARTe::UDPSClientI *external = static_cast<MARTe::UDPSClientI *>(0));
/** @brief Stop and forget an external receiver (no-op for built-in receivers). */
void DetachClient();
/** @brief Start the UDPSClient background thread. */
bool Start();
@@ -236,6 +249,12 @@ public:
/** @return Multicast data port (0 = port+1 default). */
uint16 GetDataPort() const;
/** @return "udp" or "tcp". */
StreamString GetTransport() const;
/** @return TCP stream name ("" = none). */
StreamString GetStreamName() const;
/** @return true after the first CONFIG packet has been fully parsed. */
bool IsConfigured() const;
@@ -443,13 +462,18 @@ private:
uint16 port_;
StreamString mcGroup_; ///< Multicast group ("" = unicast)
uint16 dataPort_; ///< Multicast data port (0 = port+1)
StreamString transport_; ///< "udp" or "tcp"
StreamString streamName_;///< TCPStreamService stream name ("" = none)
uint32 maxPoints_;
uint32 ringTemporal_; ///< Ring capacity for multi-element signals
uint32 ringScalar_; ///< Ring capacity for scalar signals
bool initialised_;
/* UDPSClient (owns the background thread) */
UDPSClient client_;
/* Receivers (each owns a background thread); client_ points at the active one. */
UDPSClient udpClient_;
MARTe::TCPSClient tcpClient_;
MARTe::UDPSClientI *client_;
bool external_; ///< client_ is owned by the caller
/* Signal metadata — protected by metaMutex_ */
mutable FastPollingMutexSem metaMutex_;
@@ -0,0 +1,25 @@
#############################################################
#
# Copyright 2015 F4E | European Joint Undertaking for ITER
# and the Development of Fusion Energy ('Fusion for Energy')
#
# Licensed under the EUPL, Version 1.1 or - as soon they
# will be approved by the European Commission - subsequent
# versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the
# Licence.
# You may obtain a copy of the Licence at:
#
# http://ec.europa.eu/idabc/eupl
#
# Unless required by applicable law or agreed to in
# writing, software distributed under the Licence is
# distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
# See the Licence for the specific language governing
# permissions and limitations under the Licence.
#
#############################################################
include Makefile.inc
@@ -0,0 +1,63 @@
#############################################################
#
# Copyright 2015 F4E | European Joint Undertaking for ITER
# and the Development of Fusion Energy ('Fusion for Energy')
#
# Licensed under the EUPL, Version 1.1 or - as soon they
# will be approved by the European Commission - subsequent
# versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the
# Licence.
# You may obtain a copy of the Licence at:
#
# http://ec.europa.eu/idabc/eupl
#
# Unless required by applicable law or agreed to in
# writing, software distributed under the Licence is
# distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
# See the Licence for the specific language governing
# permissions and limitations under the Licence.
#
#############################################################
OBJSX = TCPStreamer.x
PACKAGE=Components/DataSources
ROOT_DIR=../../../../
MAKEDEFAULTDIR=$(MARTe2_DIR)/MakeDefaults
include $(MAKEDEFAULTDIR)/MakeStdLibDefs.$(TARGET)
INCLUDES += -I.
INCLUDES += -I$(ROOT_DIR)/Common/UDP
INCLUDES += -I$(ROOT_DIR)/Source/Components/Interfaces/UDPStream
INCLUDES += -I$(ROOT_DIR)/Source/Components/DataSources/UDPStreamer
INCLUDES += -I$(ROOT_DIR)/Source/Components/Interfaces/TCPStreamService
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L0Types
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L2Objects
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L3Streams
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Messages
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Configuration
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L3Services
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4Messages
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams
LIBRARIES += -L$(BUILD_DIR)/../../Interfaces/UDPStream -lUDPStream
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/TCPStreamService -lTCPStreamService
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/DataSources/UDPStreamer -lUDPStreamer
all: $(OBJS) \
$(BUILD_DIR)/TCPStreamer$(LIBEXT) \
$(BUILD_DIR)/TCPStreamer$(DLLEXT)
echo $(OBJS)
include depends.$(TARGET)
include $(MAKEDEFAULTDIR)/MakeStdLibRules.$(TARGET)
@@ -0,0 +1,172 @@
/**
* @file TCPStreamer.cpp
* @brief Source file for class TCPStreamer
* @date 05/11/2026
* @author Martino Ferrari
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*
* @details This source file contains the definition of all the methods for
* the class TCPStreamer (public, protected, and private).
*/
#define DLL_API
#include <string.h>
#include "AdvancedErrorManagement.h"
#include "ConfigurationDatabase.h"
#include "TCPStreamer.h"
namespace MARTe {
/* Owned by the TCPStreamService when Service is set. */
static const char8 *const tcpStreamerServiceKeys[] = {
"Port", "MaxClients", "ClientQueueDepth", "ClientStallTimeout", "SendBufferSize"
};
static const char8 *const tcpStreamerRejectedKeys[] = {
"MulticastGroup", "Interface", "DataPort", "ClientTimeout"
};
TCPStreamer::TCPStreamer() : UDPStreamer(), serviceStream(NULL_PTR(TCPSServiceStream *)) {
tcpServer = new TCPSServer();
SetServer(tcpServer);
}
TCPStreamer::~TCPStreamer() {
/* tcpServer is owned (and deleted) by UDPStreamer. */
tcpServer = NULL_PTR(TCPSServer *);
serviceStream = NULL_PTR(TCPSServiceStream *);
}
bool TCPStreamer::Initialise(StructuredDataI &data) {
bool ok = true;
const uint32 numKeys = data.GetNumberOfChildren();
for (uint32 i = 0u; (i < numKeys) && ok; i++) {
const char8 *name = data.GetChildName(i);
if (name == NULL_PTR(const char8 *)) {
continue;
}
for (uint32 k = 0u; k < (sizeof(tcpStreamerRejectedKeys) / sizeof(tcpStreamerRejectedKeys[0])); k++) {
if (strcmp(name, tcpStreamerRejectedKeys[k]) == 0) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Parameter '%s' is UDP-only and not supported by TCPStreamer.", name);
ok = false;
}
}
}
StreamString serviceName;
if (ok && data.Read("Service", serviceName) && (serviceName.Size() > 0u)) {
for (uint32 i = 0u; (i < numKeys) && ok; i++) {
const char8 *name = data.GetChildName(i);
for (uint32 k = 0u; (name != NULL_PTR(const char8 *)) &&
(k < (sizeof(tcpStreamerServiceKeys) / sizeof(tcpStreamerServiceKeys[0]))); k++) {
if (strcmp(name, tcpStreamerServiceKeys[k]) == 0) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Parameter '%s' belongs to the TCPStreamService and cannot be set together with Service.",
name);
ok = false;
}
}
}
StreamString streamName;
if (ok && (!data.Read("StreamName", streamName) || (streamName.Size() == 0u))) {
streamName = GetName();
}
if (ok && (streamName.Size() > TCPS_MAX_STREAM_NAME)) {
REPORT_ERROR(ErrorManagement::ParametersError,
"StreamName is longer than %u characters.", TCPS_MAX_STREAM_NAME);
ok = false;
}
if (ok) {
serviceStream = new TCPSServiceStream(serviceName.Buffer(), streamName.Buffer());
SetServer(serviceStream); /* replaces (and deletes) the private TCPSServer */
tcpServer = NULL_PTR(TCPSServer *);
}
}
if (ok) {
ok = UDPStreamer::Initialise(data);
}
return ok;
}
bool TCPStreamer::UsesService() const {
return serviceStream != NULL_PTR(TCPSServiceStream *);
}
uint16 TCPStreamer::GetBoundPort() const {
return UsesService() ? serviceStream->GetPort() : tcpServer->GetPort();
}
uint32 TCPStreamer::GetClientCount() const {
return UsesService() ? serviceStream->GetClientCount() : tcpServer->GetClientCount();
}
uint64 TCPStreamer::GetClientDrops() const {
return UsesService() ? serviceStream->GetClientDrops() : tcpServer->GetClientDrops();
}
uint32 TCPStreamer::GetStallEvictions() const {
return UsesService() ? 0u : tcpServer->GetStallEvictions();
}
uint32 TCPStreamer::DefaultMaxPayloadSize() const {
return TCPSServer::TCPS_DEFAULT_MAX_PAYLOAD;
}
bool TCPStreamer::InitialiseTransport(StructuredDataI &data) {
if (UsesService()) {
ConfigurationDatabase scdb;
bool sok = scdb.Write("MaxPayloadSize", GetMaxPayloadSize());
if (sok) {
sok = scdb.MoveToRoot();
}
if (sok) {
sok = serviceStream->Initialise(scdb);
}
if (!sok) {
REPORT_ERROR(ErrorManagement::ParametersError, "Could not configure the service stream.");
}
return sok;
}
ConfigurationDatabase cdb;
/* The base class has already resolved Port and MaxPayloadSize. */
bool ok = cdb.Write("Port", static_cast<uint32>(GetPort()));
if (ok) {
ok = cdb.Write("MaxPayloadSize", GetMaxPayloadSize());
}
const char8 *const optional[] = {
"MaxClients", "ClientQueueDepth", "ClientStallTimeout", "SendBufferSize"
};
for (uint32 k = 0u; (k < (sizeof(optional) / sizeof(optional[0]))) && ok; k++) {
uint32 v = 0u;
if (data.Read(optional[k], v)) {
ok = cdb.Write(optional[k], v);
}
}
if (ok) {
ok = cdb.MoveToRoot();
}
if (ok) {
ok = tcpServer->Initialise(cdb);
}
if (!ok) {
REPORT_ERROR(ErrorManagement::ParametersError, "Could not configure the TCPSServer.");
}
return ok;
}
CLASS_REGISTER(TCPStreamer, "1.0")
} /* namespace MARTe */
@@ -0,0 +1,112 @@
/**
* @file TCPStreamer.h
* @brief Header file for class TCPStreamer
* @date 05/11/2026
* @author Martino Ferrari
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*
* @details This header file contains the declaration of the class TCPStreamer
* with all of its public, protected and private members.
*/
#ifndef TCPSTREAMER_H_
#define TCPSTREAMER_H_
#include "TCPSServer.h"
#include "TCPSServiceStream.h"
#include "UDPStreamer.h"
namespace MARTe {
/**
* @brief A DataSource that streams MARTe2 signals to TCP clients.
*
* @details Identical to UDPStreamer (same signals, quantisation, time modes and
* PublishingMode handling, same UDPS wire format) except that the network side
* is a TCPSServer: every client gets the CONFIG on connect and then every DATA
* frame, in order, over its own TCP connection. A client that cannot keep up
* only loses its own frames (counted by GetClientDrops()) and is disconnected
* after ClientStallTimeout seconds without progress; the RT thread and the
* other clients are unaffected.
*
* @par Configuration
* All UDPStreamer keys apply except the UDP-only ones (MulticastGroup,
* Interface, DataPort, ClientTimeout), which are rejected.
* | Parameter | Type | Default | Description |
* |--------------------|--------|---------|-------------|
* | Port | uint16 | 44500 | TCP listen port. |
* | MaxPayloadSize | uint32 | 60000 | Frame budget used to size Accumulate batches. |
* | MaxClients | uint32 | 16 | Simultaneous clients (1..1024). |
* | ClientQueueDepth | uint32 | 8 | DATA frames queued per client (1..4096). |
* | ClientStallTimeout | uint32 | 5 | Seconds without progress before a client is dropped; 0 disables. |
* | SendBufferSize | uint32 | 0 | SO_SNDBUF for client sockets; 0 keeps the OS default. |
*
* @par Shared service mode
* With `Service = <name of a TCPStreamService>` the DataSource does not open a
* socket of its own: it publishes a stream called `StreamName` (default: the
* DataSource name) through the shared in-process service, which serves many
* streams from one port with a pool of worker threads. Clients select the
* stream with the `StreamName` key of TCPStreamerClient / StreamHub. In this
* mode Port, MaxClients, ClientQueueDepth, ClientStallTimeout and
* SendBufferSize belong to the service and are rejected here.
* | Parameter | Type | Default | Description |
* |------------|--------|-----------------|-------------|
* | Service | string | *(absent)* | Object name of the TCPStreamService. |
* | StreamName | string | DataSource name | Stream name, unique per service (1..255 chars). |
*
* @par Example
* <pre>
* +Streamer = {
* Class = TCPStreamer
* Port = 44500
* Signals = {
* Time = { Type = uint64 }
* Value = { Type = float32 }
* }
* }
* </pre>
*/
class TCPStreamer : public UDPStreamer {
public:
CLASS_REGISTER_DECLARATION()
TCPStreamer();
virtual ~TCPStreamer();
/** Rejects the UDP-only keys, then behaves as UDPStreamer::Initialise(). */
virtual bool Initialise(StructuredDataI &data);
/** @return true when publishing through a TCPStreamService. */
bool UsesService() const;
/** @return the port actually bound (meaningful once started; resolves Port = 0). */
uint16 GetBoundPort() const;
/** @return clients currently connected. */
uint32 GetClientCount() const;
/** @return DATA frames dropped across all clients because their queue was full. */
uint64 GetClientDrops() const;
/** @return clients disconnected for exceeding ClientStallTimeout. */
uint32 GetStallEvictions() const;
protected:
virtual uint32 DefaultMaxPayloadSize() const;
virtual bool InitialiseTransport(StructuredDataI &data);
private:
TCPSServer *tcpServer; /**< Alias of the private transport (NULL in service mode). */
TCPSServiceStream *serviceStream; /**< Alias of the service handle (NULL in standalone mode). */
};
} /* namespace MARTe */
#endif /* TCPSTREAMER_H_ */
@@ -0,0 +1,145 @@
../../../..//Build/x86-linux/Components/DataSources/TCPStreamer/TCPStreamer.o: TCPStreamer.cpp \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyObject.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabaseNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Fnv1aHashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/HashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/UnorderedMap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilterObjectName.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TypeConversion.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
TCPStreamer.h \
../../../..//Source/Components/Interfaces/UDPStream/TCPSServer.h \
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/Interfaces/TCPStreamService/TCPSServiceStream.h \
../../../..//Source/Components/Interfaces/TCPStreamService/TCPStreamService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/DataSources/UDPStreamer/UDPStreamer.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/EventSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/MemoryDataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/DataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/StatefulI.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSServer.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicTCPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetHostCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetMulticastCore.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HandleI.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/SocketCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h
@@ -0,0 +1,145 @@
TCPStreamer.o: TCPStreamer.cpp \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyObject.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabaseNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Fnv1aHashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/HashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/UnorderedMap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilterObjectName.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TypeConversion.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
TCPStreamer.h \
../../../..//Source/Components/Interfaces/UDPStream/TCPSServer.h \
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/Interfaces/TCPStreamService/TCPSServiceStream.h \
../../../..//Source/Components/Interfaces/TCPStreamService/TCPStreamService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/DataSources/UDPStreamer/UDPStreamer.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/EventSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/MemoryDataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/DataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/StatefulI.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSServer.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicTCPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetHostCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetMulticastCore.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HandleI.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/SocketCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h
@@ -0,0 +1,25 @@
#############################################################
#
# Copyright 2015 F4E | European Joint Undertaking for ITER
# and the Development of Fusion Energy ('Fusion for Energy')
#
# Licensed under the EUPL, Version 1.1 or - as soon they
# will be approved by the European Commission - subsequent
# versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the
# Licence.
# You may obtain a copy of the Licence at:
#
# http://ec.europa.eu/idabc/eupl
#
# Unless required by applicable law or agreed to in
# writing, software distributed under the Licence is
# distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
# See the Licence for the specific language governing
# permissions and limitations under the Licence.
#
#############################################################
include Makefile.inc
@@ -0,0 +1,62 @@
#############################################################
#
# Copyright 2015 F4E | European Joint Undertaking for ITER
# and the Development of Fusion Energy ('Fusion for Energy')
#
# Licensed under the EUPL, Version 1.1 or - as soon they
# will be approved by the European Commission - subsequent
# versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the
# Licence.
# You may obtain a copy of the Licence at:
#
# http://ec.europa.eu/idabc/eupl
#
# Unless required by applicable law or agreed to in
# writing, software distributed under the Licence is
# distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
# See the Licence for the specific language governing
# permissions and limitations under the Licence.
#
#############################################################
OBJSX = TCPStreamerClient.x
PACKAGE=Components/DataSources
ROOT_DIR=../../../../
MAKEDEFAULTDIR=$(MARTe2_DIR)/MakeDefaults
include $(MAKEDEFAULTDIR)/MakeStdLibDefs.$(TARGET)
INCLUDES += -I.
INCLUDES += -I$(ROOT_DIR)/Common/UDP
INCLUDES += -I$(ROOT_DIR)/Source/Components/Interfaces/UDPStream
INCLUDES += -I$(ROOT_DIR)/Source/Components/DataSources/UDPStreamerClient
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L0Types
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L2Objects
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L3Streams
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Messages
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Configuration
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L3Services
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L4Messages
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L5GAMs
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams
LIBRARIES += -L$(MARTe2_DIR)/Build/$(TARGET)/Core -lMARTe2
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/Interfaces/UDPStream -lUDPStream
LIBRARIES += -L$(ROOT_DIR)/Build/$(TARGET)/Components/DataSources/UDPStreamerClient -lUDPStreamerClient
all: $(OBJS) \
$(BUILD_DIR)/TCPStreamerClient$(LIBEXT) \
$(BUILD_DIR)/TCPStreamerClient$(DLLEXT)
echo $(OBJS)
include depends.$(TARGET)
include $(MAKEDEFAULTDIR)/MakeStdLibRules.$(TARGET)
@@ -0,0 +1,122 @@
/**
* @file TCPStreamerClient.cpp
* @brief Source file for class TCPStreamerClient
* @date 05/11/2026
* @author Martino Ferrari
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*
* @details This source file contains the definition of all the methods for
* the class TCPStreamerClient (public, protected, and private).
*/
#define DLL_API
#include <string.h>
#include "AdvancedErrorManagement.h"
#include "ConfigurationDatabase.h"
#include "TCPStreamerClient.h"
namespace MARTe {
static const char8 *const tcpClientRejectedKeys[] = {
"MulticastGroup", "DataPort", "Interface", "KeepAliveInterval"
};
TCPStreamerClient::TCPStreamerClient() : UDPStreamerClient() {
tcpClient = new TCPSClient();
SetClient(tcpClient);
}
TCPStreamerClient::~TCPStreamerClient() {
/* tcpClient is owned (and deleted) by UDPStreamerClient. */
tcpClient = NULL_PTR(TCPSClient *);
}
bool TCPStreamerClient::Initialise(StructuredDataI &data) {
bool ok = true;
const uint32 numKeys = data.GetNumberOfChildren();
for (uint32 i = 0u; (i < numKeys) && ok; i++) {
const char8 *name = data.GetChildName(i);
if (name == NULL_PTR(const char8 *)) {
continue;
}
for (uint32 k = 0u; k < (sizeof(tcpClientRejectedKeys) / sizeof(tcpClientRejectedKeys[0])); k++) {
if (strcmp(name, tcpClientRejectedKeys[k]) == 0) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Parameter '%s' is UDP-only and not supported by TCPStreamerClient.", name);
ok = false;
}
}
}
if (ok) {
ok = UDPStreamerClient::Initialise(data);
}
return ok;
}
bool TCPStreamerClient::IsConnected() const {
return tcpClient->IsConnected();
}
uint32 TCPStreamerClient::GetConnectionCount() const {
return tcpClient->GetConnectionCount();
}
uint32 TCPStreamerClient::GetProtocolErrors() const {
return tcpClient->GetProtocolErrors();
}
bool TCPStreamerClient::InitialiseTransport(StructuredDataI &data) {
/* The TCP defaults differ from the UDP ones (no silence timeout, 2 s
* reconnect delay), so read them here rather than from the base members. */
float32 silenceTimeout = 0.0F;
if (!data.Read("SilenceTimeout", silenceTimeout)) {
silenceTimeout = 0.0F;
}
float32 reconnectDelay = static_cast<float32>(TCPSClient::TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S);
if (!data.Read("ReconnectDelay", reconnectDelay)) {
reconnectDelay = static_cast<float32>(TCPSClient::TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S);
}
ConfigurationDatabase cdb;
bool ok = cdb.Write("ServerAddr", serverAddress);
if (ok) { ok = cdb.Write("Port", static_cast<uint32>(port)); }
if (ok) { ok = cdb.Write("SilenceTimeout", silenceTimeout); }
if (ok) { ok = cdb.Write("ReconnectDelay", reconnectDelay); }
if (ok) { ok = cdb.Write("CPUMask", cpuMask); }
if (ok) { ok = cdb.Write("StackSize", stackSize); }
StreamString streamName;
if (ok && data.Read("StreamName", streamName)) {
if (strchr(streamName.Buffer(), ',') != NULL_PTR(char8 *)) {
REPORT_ERROR(ErrorManagement::ParametersError,
"StreamName must be a single stream: a TCPStreamerClient cannot multiplex.");
ok = false;
}
if (ok) {
ok = cdb.Write("StreamName", streamName.Buffer());
}
}
if (ok) { ok = cdb.MoveToRoot(); }
if (ok) { ok = tcpClient->Initialise(cdb); }
if (!ok) {
REPORT_ERROR(ErrorManagement::ParametersError, "Could not configure the TCPSClient receiver.");
}
tcpClient->SetListener(this);
return ok;
}
CLASS_REGISTER(TCPStreamerClient, "1.0")
} /* namespace MARTe */
@@ -0,0 +1,79 @@
/**
* @file TCPStreamerClient.h
* @brief Header file for class TCPStreamerClient
* @date 05/11/2026
* @author Martino Ferrari
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*
* @details This header file contains the declaration of the class
* TCPStreamerClient with all of its public, protected and private members.
*/
#ifndef TCPSTREAMERCLIENT_H_
#define TCPSTREAMERCLIENT_H_
#include "TCPSClient.h"
#include "UDPStreamerClient.h"
namespace MARTe {
/**
* @brief A DataSource that receives a TCPStreamer (or any TCP UDPS server)
* stream and exposes it as input signals.
*
* @details Same signal handling and CONFIG validation as UDPStreamerClient; the
* transport is a TCPSClient that connects, reads framed UDPS packets, and
* reconnects automatically when the connection is lost.
*
* @par Configuration
* | Parameter | Type | Default | Description |
* |----------------|---------|-----------|-------------|
* | ServerAddress | string | 127.0.0.1 | Server IPv4 address or host name. |
* | Port | uint16 | 44500 | Server TCP port. |
* | SilenceTimeout | float32 | 0 | Seconds without any received byte before reconnecting; 0 disables. |
* | ReconnectDelay | float32 | 2 | Seconds between connection attempts. |
* | StreamName | string | *(absent)* | Stream to subscribe to on a TCPStreamService (omit for a plain TCPStreamer). |
* | CPUMask | uint32 | 0xFFFFFFFF| Receiver thread affinity. |
* | StackSize | uint32 | (default) | Receiver thread stack size. |
*
* MulticastGroup, DataPort, Interface and KeepAliveInterval are UDP-only and
* rejected.
*/
class TCPStreamerClient : public UDPStreamerClient {
public:
CLASS_REGISTER_DECLARATION()
TCPStreamerClient();
virtual ~TCPStreamerClient();
/** Rejects the UDP-only keys, then behaves as UDPStreamerClient::Initialise(). */
virtual bool Initialise(StructuredDataI &data);
/** @return true while connected to the server. */
bool IsConnected() const;
/** @return connections established so far. */
uint32 GetConnectionCount() const;
/** @return connections dropped because of a protocol violation. */
uint32 GetProtocolErrors() const;
protected:
virtual bool InitialiseTransport(StructuredDataI &data);
private:
TCPSClient *tcpClient; /**< Alias of the transport owned by UDPStreamerClient. */
};
} /* namespace MARTe */
#endif /* TCPSTREAMERCLIENT_H_ */
@@ -0,0 +1,144 @@
../../../..//Build/x86-linux/Components/DataSources/TCPStreamerClient/TCPStreamerClient.o: TCPStreamerClient.cpp \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyObject.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabaseNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Fnv1aHashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/HashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/UnorderedMap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilterObjectName.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TypeConversion.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
TCPStreamerClient.h \
../../../..//Source/Components/Interfaces/UDPStream/TCPSClient.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSClient.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicTCPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetHostCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetMulticastCore.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HandleI.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/SocketCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/DataSources/UDPStreamerClient/UDPStreamerClient.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/EventSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/MemoryDataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/DataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/StatefulI.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSClient.h
@@ -0,0 +1,144 @@
TCPStreamerClient.o: TCPStreamerClient.cpp \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/AnyObject.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/ConfigurationDatabaseNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Fnv1aHashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/HashFunction.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/UnorderedMap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilterObjectName.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L4Configuration/TypeConversion.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
TCPStreamerClient.h \
../../../..//Source/Components/Interfaces/UDPStream/TCPSClient.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSClient.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicTCPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicSocket.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetHostCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/InternetMulticastCore.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HandleI.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/Environment/Linux/SocketCore.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/DataSources/UDPStreamerClient/UDPStreamerClient.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/EventSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/MemoryDataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/DataSourceI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L5GAMs/StatefulI.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSClient.h
@@ -84,6 +84,7 @@ UDPStreamer::UDPStreamer()
: MemoryDataSourceI(), EmbeddedServiceMethodBinderI(), executor(*this) {
port = UDPS_DEFAULT_PORT;
maxPayloadSize = UDPS_DEFAULT_MAX_PAYLOAD;
server = new UDPSServer();
cpuMask = 0xFFFFFFFFu;
stackSize = THREADS_DEFAULT_STACKSIZE;
publishMode = UDPStreamerPublishStrict;
@@ -135,7 +136,11 @@ UDPStreamer::~UDPStreamer() {
}
}
(void)server.Stop();
if (server != NULL_PTR(UDPSServerI *)) {
(void)server->Stop();
delete server;
server = NULL_PTR(UDPSServerI *);
}
HeapI *heapAccum = GlobalObjectsDatabase::Instance()->GetStandardHeap();
if (accumBuffer != NULL_PTR(uint8 *)) {
@@ -192,7 +197,7 @@ bool UDPStreamer::Initialise(StructuredDataI &data) {
if (ok) {
if (!data.Read("MaxPayloadSize", maxPayloadSize)) {
maxPayloadSize = UDPS_DEFAULT_MAX_PAYLOAD;
maxPayloadSize = DefaultMaxPayloadSize();
REPORT_ERROR(ErrorManagement::Information,
"MaxPayloadSize not specified; using default %u.",
maxPayloadSize);
@@ -286,38 +291,58 @@ bool UDPStreamer::Initialise(StructuredDataI &data) {
}
if (ok) {
// Build server config with already-resolved Port and MaxPayloadSize so
// UDPSServer::Initialise() always sees them, even when defaults were used.
ConfigurationDatabase serverCfg;
(void)serverCfg.Write("Port", static_cast<uint32>(port));
(void)serverCfg.Write("MaxPayloadSize", maxPayloadSize);
// Forward optional multicast / timeout params if present in caller's data.
StreamString mcGroup;
if (data.Read("MulticastGroup", mcGroup) && (mcGroup.Size() > 0u)) {
(void)serverCfg.Write("MulticastGroup", mcGroup.Buffer());
uint32 dp = 0u;
if (data.Read("DataPort", dp)) {
(void)serverCfg.Write("DataPort", dp);
}
StreamString iface;
if (data.Read("Interface", iface)) {
(void)serverCfg.Write("Interface", iface);
} else {
ok = false;
REPORT_ERROR(ErrorManagement::InitialisationError,
"Missing mandatory interface for multicasting");
}
}
uint32 clientTimeout = 0u;
if (data.Read("ClientTimeout", clientTimeout)) {
(void)serverCfg.Write("ClientTimeout", clientTimeout);
}
ok = server.Initialise(serverCfg);
ok = InitialiseTransport(data);
}
return ok;
}
uint32 UDPStreamer::DefaultMaxPayloadSize() const {
return UDPS_DEFAULT_MAX_PAYLOAD;
}
bool UDPStreamer::InitialiseTransport(StructuredDataI &data) {
bool ok = true;
// Build server config with already-resolved Port and MaxPayloadSize so
// UDPSServer::Initialise() always sees them, even when defaults were used.
ConfigurationDatabase serverCfg;
(void)serverCfg.Write("Port", static_cast<uint32>(port));
(void)serverCfg.Write("MaxPayloadSize", maxPayloadSize);
// Forward optional multicast / timeout params if present in caller's data.
StreamString mcGroup;
if (data.Read("MulticastGroup", mcGroup) && (mcGroup.Size() > 0u)) {
(void)serverCfg.Write("MulticastGroup", mcGroup.Buffer());
uint32 dp = 0u;
if (data.Read("DataPort", dp)) {
(void)serverCfg.Write("DataPort", dp);
}
StreamString iface;
if (data.Read("Interface", iface)) {
(void)serverCfg.Write("Interface", iface);
} else {
ok = false;
REPORT_ERROR(ErrorManagement::InitialisationError,
"Missing mandatory interface for multicasting");
}
}
uint32 clientTimeout = 0u;
if (data.Read("ClientTimeout", clientTimeout)) {
(void)serverCfg.Write("ClientTimeout", clientTimeout);
}
ok = server->Initialise(serverCfg);
return ok;
}
void UDPStreamer::SetServer(UDPSServerI *newServer) {
if (server != NULL_PTR(UDPSServerI *)) {
delete server;
}
server = newServer;
}
UDPSServerI *UDPStreamer::Transport() const { return server; }
bool UDPStreamer::SetConfiguredDatabase(StructuredDataI &data) {
bool ok = MemoryDataSourceI::SetConfiguredDatabase(data);
if (!ok) {
@@ -804,7 +829,7 @@ bool UDPStreamer::PrepareNextState(const char8 *const currentStateName,
const char8 *const nextStateName) {
bool ok = true;
ok = server.Start();
ok = server->Start();
/* Build the CONFIG payload and cache it in the server so any CONNECT client
* receives it immediately. The config is static for the lifetime of this
@@ -818,7 +843,7 @@ bool UDPStreamer::PrepareNextState(const char8 *const currentStateName,
if (cfgBuf != NULL_PTR(uint8 *)) {
uint32 cfgPayloadSize = 0u;
if (BuildConfigPayload(cfgBuf, configBufSize, cfgPayloadSize)) {
(void)server.SendConfig(cfgBuf, cfgPayloadSize);
(void)server->SendConfig(cfgBuf, cfgPayloadSize);
} else {
REPORT_ERROR(ErrorManagement::Warning,
"Could not build initial CONFIG payload.");
@@ -992,7 +1017,7 @@ ErrorManagement::ErrorType UDPStreamer::Execute(ExecutionInfo &info) {
/* --- Poll for incoming control commands (CONNECT / DISCONNECT / ACK) ---
*/
server.ServiceClients();
server->ServiceClients();
/* Synchronise() already gates publication to the correct rate (size/time
* for Accumulate, every-Nth for Decimate, every call for Strict). The
@@ -1015,12 +1040,12 @@ ErrorManagement::ErrorType UDPStreamer::Execute(ExecutionInfo &info) {
}
bufMutex.FastUnLock();
if ((fill > 0u) && server.HasClients()) {
if ((fill > 0u) && server->HasClients()) {
SerializeAccumulated(scratchBuffer, scratchTimestamps, fill);
uint32 sendBytes =
UDPS_TIMESTAMP_BYTES + 4u + fill * singleCycleWireBytes;
packetCounter++;
if (!server.SendData(packetCounter, wireBuffer, sendBytes)) {
if (!server->SendData(packetCounter, wireBuffer, sendBytes)) {
REPORT_ERROR(ErrorManagement::Warning,
"Failed to send Accumulate DATA packet (counter=%u).",
packetCounter);
@@ -1040,11 +1065,11 @@ ErrorManagement::ErrorType UDPStreamer::Execute(ExecutionInfo &info) {
}
bufMutex.FastUnLock();
if (pending && server.HasClients()) {
if (pending && server->HasClients()) {
QuantizeAndSerialize(scratchBuffer, ts);
packetCounter++;
if (!server.SendData(packetCounter, wireBuffer, totalWireBytes)) {
if (!server->SendData(packetCounter, wireBuffer, totalWireBytes)) {
REPORT_ERROR(ErrorManagement::Warning,
"Failed to send DATA packet (counter=%u).",
packetCounter);
@@ -1056,7 +1081,7 @@ ErrorManagement::ErrorType UDPStreamer::Execute(ExecutionInfo &info) {
}
if (info.GetStage() == ExecutionInfo::TerminationStage) {
(void)server.Stop();
(void)server->Stop();
REPORT_ERROR(ErrorManagement::Information,
"UDPStreamer background thread terminated.");
}
@@ -1367,9 +1392,9 @@ uint16 UDPStreamer::GetPort() const { return port; }
uint32 UDPStreamer::GetMaxPayloadSize() const { return maxPayloadSize; }
bool UDPStreamer::IsClientConnected() const { return server.HasClients(); }
bool UDPStreamer::IsClientConnected() const { return server->HasClients(); }
bool UDPStreamer::IsMulticast() const { return server.IsMulticast(); }
bool UDPStreamer::IsMulticast() const { return server->IsMulticast(); }
uint32 UDPStreamer::GetDroppedPublications() const { return droppedPublications; }
@@ -39,6 +39,7 @@
#include "SingleThreadService.h"
#include "StreamString.h"
#include "UDPSServer.h"
#include "UDPSTransportI.h"
/*---------------------------------------------------------------------------*/
/* Class declaration */
@@ -333,6 +334,33 @@ public:
*/
uint32 GetDroppedPublications() const;
protected:
/**
* @brief MaxPayloadSize used when the configuration does not specify one.
* @details Transport specific (a datagram budget for UDP, a frame budget for
* TCP), hence overridable. Called from Initialise(), not the constructor.
*/
virtual uint32 DefaultMaxPayloadSize() const;
/**
* @brief Configures the transport from the already-resolved Port and
* MaxPayloadSize plus whatever transport keys @p data carries.
* @details The default implementation configures the UDPSServer (unicast /
* multicast). A subclass that installs another transport with SetServer()
* overrides this to configure it instead.
*/
virtual bool InitialiseTransport(StructuredDataI &data);
/**
* @brief Replaces the transport. Takes ownership; only valid before Start().
*/
void SetServer(UDPSServerI *newServer);
/**
* @brief The transport currently in use (owned by this object).
*/
UDPSServerI *Transport() const;
private:
/**
* @brief Serializes the CONFIG payload into buf and sets payloadSize.
@@ -417,8 +445,8 @@ private:
uint8 *wireBuffer; /**< Pre-allocated buffer for the serialized DATA payload */
uint32 totalWireBytes; /**< Total bytes of all signals after quantization + 8-byte timestamp prefix */
/* Networking — handled by UDPSServer */
UDPSServer server; /**< Multi-client session manager (unicast and multicast) */
/* Networking — handled by a UDPSServerI (UDPSServer by default) */
UDPSServerI *server; /**< Owned transport; see SetServer() */
/* Thread management */
SingleThreadService executor; /**< Background thread service */
@@ -135,4 +135,6 @@
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
../../../..//Common/UDP/UDPSProtocol.h
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h
@@ -135,4 +135,6 @@ UDPStreamer.o: UDPStreamer.cpp \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/BasicUDPSocket.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/FileSystem/L1Portability/InternetHost.h \
../../../..//Common/UDP/UDPSProtocol.h
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h
@@ -131,7 +131,8 @@ static float64 DequantValue(float64 raw, uint8 quantType,
UDPStreamerClient::UDPStreamerClient() :
MemoryDataSourceI(),
UDPSClientListener(),
client() {
client(NULL_PTR(UDPSClientI *)) {
client = new UDPSClient();
serverAddress = UDPS_CLIENT_DEFAULT_ADDR;
port = UDPS_CLIENT_DEFAULT_PORT;
maxPayloadSize = UDPS_CLIENT_DEFAULT_MAX_PAYLOAD;
@@ -160,9 +161,13 @@ UDPStreamerClient::UDPStreamerClient() :
UDPStreamerClient::~UDPStreamerClient() {
(void) dataSem.Post();
if (receiverUp) {
(void) client.Stop();
receiverUp = false;
if (client != NULL_PTR(UDPSClientI *)) {
if (receiverUp) {
(void) client->Stop();
receiverUp = false;
}
delete client;
client = NULL_PTR(UDPSClientI *);
}
HeapI *heap = GlobalObjectsDatabase::Instance()->GetStandardHeap();
@@ -258,36 +263,49 @@ bool UDPStreamerClient::Initialise(StructuredDataI &data) {
}
}
/* Forward the transport parameters to the shared UDPSClient receiver,
* translating the DataSource parameter names to the UDPSClient keys. */
if (ok) {
ConfigurationDatabase cdb;
ok = cdb.Write("ServerAddr", serverAddress);
if (ok) { ok = cdb.Write("Port", static_cast<uint32>(port)); }
if (ok && useMulticast) {
ok = cdb.Write("MulticastGroup", multicastGroup);
if (ok) { ok = cdb.Write("DataPort", static_cast<uint32>(dataPort)); }
if (ok && (multicastInterface.Size() > 0u)) {
ok = cdb.Write("Interface", multicastInterface);
}
}
if (ok) { ok = cdb.Write("MaxPayloadSize", maxPayloadSize); }
if (ok) { ok = cdb.Write("KeepAliveInterval", keepAliveInterval); }
if (ok) { ok = cdb.Write("SilenceTimeout", silenceTimeout); }
if (ok) { ok = cdb.Write("CPUMask", cpuMask); }
if (ok) { ok = cdb.Write("StackSize", stackSize); }
if (ok) { ok = cdb.MoveToRoot(); }
if (ok) { ok = client.Initialise(cdb); }
if (!ok) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Could not configure the UDPSClient receiver.");
}
client.SetListener(this);
ok = InitialiseTransport(data);
}
return ok;
}
bool UDPStreamerClient::InitialiseTransport(StructuredDataI &data) {
/* Forward the transport parameters to the shared UDPSClient receiver,
* translating the DataSource parameter names to the UDPSClient keys. */
bool ok = true;
ConfigurationDatabase cdb;
ok = cdb.Write("ServerAddr", serverAddress);
if (ok) { ok = cdb.Write("Port", static_cast<uint32>(port)); }
if (ok && useMulticast) {
ok = cdb.Write("MulticastGroup", multicastGroup);
if (ok) { ok = cdb.Write("DataPort", static_cast<uint32>(dataPort)); }
if (ok && (multicastInterface.Size() > 0u)) {
ok = cdb.Write("Interface", multicastInterface);
}
}
if (ok) { ok = cdb.Write("MaxPayloadSize", maxPayloadSize); }
if (ok) { ok = cdb.Write("KeepAliveInterval", keepAliveInterval); }
if (ok) { ok = cdb.Write("SilenceTimeout", silenceTimeout); }
if (ok) { ok = cdb.Write("CPUMask", cpuMask); }
if (ok) { ok = cdb.Write("StackSize", stackSize); }
if (ok) { ok = cdb.MoveToRoot(); }
if (ok) { ok = client->Initialise(cdb); }
if (!ok) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Could not configure the UDPSClient receiver.");
}
client->SetListener(this);
return ok;
}
void UDPStreamerClient::SetClient(UDPSClientI *newClient) {
if (client != NULL_PTR(UDPSClientI *)) {
delete client;
}
client = newClient;
}
bool UDPStreamerClient::SetConfiguredDatabase(StructuredDataI &data) {
bool ok = MemoryDataSourceI::SetConfiguredDatabase(data);
if (!ok) {
@@ -377,7 +395,7 @@ bool UDPStreamerClient::PrepareNextState(const char8 *const currentStateName,
const char8 *const nextStateName) {
bool ok = true;
if (!receiverUp) {
ok = client.Start();
ok = client->Start();
if (ok) {
receiverUp = true;
}
@@ -160,6 +160,27 @@ public:
*/
virtual void OnUDPSDisconnected();
protected:
/**
* @brief Configures the transport from the already-parsed members and
* registers this object as its listener.
* @details The default implementation configures the UDPSClient (unicast /
* multicast). A subclass that installs another transport with SetClient()
* overrides this to configure it instead.
*/
virtual bool InitialiseTransport(StructuredDataI &data);
/**
* @brief Replaces the transport. Takes ownership; only valid before Start().
*/
void SetClient(UDPSClientI *newClient);
/* Configuration parameters shared with transport subclasses */
StreamString serverAddress; /**< Server IP address. */
uint16 port; /**< Server port. */
uint32 cpuMask; /**< Background thread CPU affinity. */
uint32 stackSize; /**< Background thread stack size. */
private:
/**
* @brief Decodes a single snapshot from a DATA payload into @p dst.
@@ -171,13 +192,9 @@ private:
void DecodeSnapshot(const uint8 *payload, uint32 size, uint8 *dst);
/* Configuration parameters */
StreamString serverAddress; /**< Server IP address. */
uint16 port; /**< Server port. */
uint32 maxPayloadSize; /**< Max payload bytes per datagram. */
uint32 keepAliveInterval; /**< Seconds between unicast keepalive ACKs (0 disables). */
float32 silenceTimeout; /**< Seconds of no data before reconnect (sub-second allowed, 0 disables). */
uint32 cpuMask; /**< Background thread CPU affinity. */
uint32 stackSize; /**< Background thread stack size. */
StreamString multicastGroup; /**< Multicast group IP; empty = unicast. */
StreamString multicastInterface; /**< Local IPv4 address for multicast join; empty = INADDR_ANY. */
uint16 dataPort; /**< UDP port for DATA datagrams (multicast). */
@@ -191,7 +208,7 @@ private:
uint8 publishMode; /**< UDPS_PUBLISH_* from CONFIG. */
/* Shared receiver (same code base as the StreamHub hub) */
UDPSClient client; /**< Transport, reassembly and reconnect. */
UDPSClientI *client; /**< Owned transport (UDPSClient by default); see SetClient(). */
bool receiverUp; /**< True once the receiver thread is started. */
/* Double-buffering for RT safety */
@@ -136,4 +136,5 @@
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h
@@ -136,4 +136,5 @@ UDPStreamerClient.o: UDPStreamerClient.cpp \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h
@@ -0,0 +1 @@
include Makefile.inc
@@ -0,0 +1,33 @@
#############################################################
# MARTe2 Integrated Components — TCPStreamService
#############################################################
OBJSX=TCPSFrameQueue.x TCPSServiceStream.x TCPSWorker.x TCPStreamService.x TCPStreamJoin.x
PACKAGE=Components/Interfaces
ROOT_DIR=../../../../
MAKEDEFAULTDIR=$(MARTe2_DIR)/MakeDefaults
include $(MAKEDEFAULTDIR)/MakeStdLibDefs.$(TARGET)
INCLUDES += -I.
INCLUDES += -I$(ROOT_DIR)/Common/UDP
INCLUDES += -I$(ROOT_DIR)/Source/Components/Interfaces/UDPStream
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L0Types
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L2Objects
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L3Streams
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Messages
INCLUDES += -I$(MARTe2_DIR)/Source/Core/BareMetal/L4Configuration
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/Scheduler/L3Services
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L1Portability
INCLUDES += -I$(MARTe2_DIR)/Source/Core/FileSystem/L3Streams
all: $(OBJS) $(SUBPROJ) \
$(BUILD_DIR)/TCPStreamService$(LIBEXT) \
$(BUILD_DIR)/TCPStreamService$(DLLEXT)
echo $(OBJS)
include depends.$(TARGET)
include $(MAKEDEFAULTDIR)/MakeStdLibRules.$(TARGET)
@@ -0,0 +1,70 @@
#ifndef TCPS_CONN_H_
#define TCPS_CONN_H_
/**
* @file TCPSConn.h
* @brief One accepted connection of a TCPStreamService (internal).
*
* Ownership: created by the acceptor thread, then owned and deleted by exactly
* one TCPSWorker. `streams` and `closeRequested` are the only fields touched
* from other threads; `stream` is guarded by the service topology lock, the
* queue by `qMutex`.
*/
#include "CompilerTypes.h"
#include "FastPollingMutexSem.h"
#include "TCPSFrameQueue.h"
#include "TCPStreamService.h"
#include "UDPSProtocol.h"
#include <unistd.h>
namespace MARTe {
class TCPSWorker;
class TCPSServiceStream;
struct TCPSConn {
TCPSConn(int socketFd, TCPSWorker *owner, uint32 queueDepth, uint64 handshakeDeadline)
: fd(socketFd), worker(owner), subscribed(false), hsHave(0u),
hsWant(UDPS_HEADER_SIZE), hsHeaderOk(false), hsDeadline(handshakeDeadline),
numStreams(0u), closeRequested(false) {
for (uint32 i = 0u; i < TCPS_MAX_CONN_STREAMS; i++) {
streams[i] = NULL_PTR(TCPSServiceStream *);
}
q.Init(queueDepth);
}
~TCPSConn() {
if (fd >= 0) {
(void)close(fd);
}
}
int fd;
TCPSWorker *worker;
/* Worker-thread only. */
bool subscribed;
uint8 hs[UDPS_HEADER_SIZE + TCPS_MAX_SUBSCRIBE_PAYLOAD + 1u];
uint32 hsHave;
uint32 hsWant;
bool hsHeaderOk;
uint64 hsDeadline;
/* Service topology lock. */
TCPSServiceStream *streams[TCPS_MAX_CONN_STREAMS]; ///< index = stream index on the wire
uint32 numStreams;
volatile bool closeRequested;
/* qMutex. */
FastPollingMutexSem qMutex;
TCPSFrameQueue q;
private:
TCPSConn(const TCPSConn &);
TCPSConn &operator=(const TCPSConn &);
};
} // namespace MARTe
#endif // TCPS_CONN_H_
@@ -0,0 +1,204 @@
/**
* @file TCPSFrameQueue.cpp
* @brief Implementation of TCPSFrameQueue.
*/
#include "TCPSFrameQueue.h"
#include "HighResolutionTimer.h"
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/types.h>
namespace MARTe {
struct TCPSFrameQueue::Slot {
Slot() : buf(NULL_PTR(uint8 *)), cap(0u), len(0u), isConfig(false), stream(0u) {}
~Slot() {
if (buf != NULL_PTR(uint8 *)) {
delete[] buf;
}
}
uint8 *buf;
uint32 cap;
uint32 len;
bool isConfig;
uint16 stream;
};
/** magic(4) + type(1) + counter(4): offset of the header's fragmentIdx field. */
static const uint32 TCPS_FRAGIDX_OFFSET = 9u;
TCPSFrameQueue::TCPSFrameQueue()
: slots(NULL_PTR(Slot **)), cap(0u), depth(0u), count(0u), sent(0u), lastProgress(0u) {
}
TCPSFrameQueue::~TCPSFrameQueue() {
if (slots != NULL_PTR(Slot **)) {
for (uint32 i = 0u; i < cap; i++) {
delete slots[i];
}
delete[] slots;
}
}
void TCPSFrameQueue::Init(uint32 d) {
depth = d;
cap = d + 2u;
slots = new Slot *[cap];
for (uint32 i = 0u; i < cap; i++) {
slots[i] = new Slot();
}
count = 0u;
sent = 0u;
lastProgress = HighResolutionTimer::Counter();
}
void TCPSFrameQueue::Reserve(uint32 numStreams) {
const uint32 want = numStreams * (depth + 2u);
if (want > cap) {
Slot **grown = new Slot *[want];
for (uint32 i = 0u; i < cap; i++) {
grown[i] = slots[i];
}
for (uint32 i = cap; i < want; i++) {
grown[i] = new Slot();
}
delete[] slots;
slots = grown;
cap = want;
}
}
/** Remove slot @p i, keeping order; the slot object is recycled at the end. */
void TCPSFrameQueue::RemoveAt(uint32 i) {
Slot *v = slots[i];
for (uint32 j = i + 1u; j < count; j++) {
slots[j - 1u] = slots[j];
}
slots[count - 1u] = v;
count--;
}
bool TCPSFrameQueue::Push(uint16 streamIdx, bool isConfig, const uint8 *frame,
uint32 frameBytes, uint32 &dropped) {
const uint32 firstFree = (sent > 0u) ? 1u : 0u; // slots below this are on the wire
if (isConfig) {
uint32 i = firstFree;
while (i < count) {
if (slots[i]->stream == streamIdx) {
if (!slots[i]->isConfig) {
dropped++;
}
RemoveAt(i);
} else {
i++;
}
}
} else {
uint32 dataCount = 0u;
for (uint32 i = 0u; i < count; i++) {
if ((slots[i]->stream == streamIdx) && !slots[i]->isConfig) {
dataCount++;
}
}
if (dataCount >= depth) {
uint32 victim = count;
for (uint32 i = firstFree; (i < count) && (victim == count); i++) {
if ((slots[i]->stream == streamIdx) && !slots[i]->isConfig) {
victim = i;
}
}
dropped++;
if (victim == count) {
return false; // only the frame on the wire is queued
}
RemoveAt(victim);
}
}
if (count >= cap) {
dropped++;
return false;
}
Slot &s = *slots[count];
if (s.cap < frameBytes) {
if (s.buf != NULL_PTR(uint8 *)) {
delete[] s.buf;
}
s.buf = new uint8[frameBytes];
s.cap = frameBytes;
}
memcpy(s.buf, frame, frameBytes);
if (frameBytes >= (TCPS_FRAGIDX_OFFSET + 2u)) {
memcpy(&s.buf[TCPS_FRAGIDX_OFFSET], &streamIdx, 2u);
}
s.len = frameBytes;
s.isConfig = isConfig;
s.stream = streamIdx;
if (count == 0u) {
sent = 0u;
lastProgress = HighResolutionTimer::Counter();
}
count++;
return true;
}
/** Account for @p bytes written from the head of the queue. */
void TCPSFrameQueue::Consume(uint32 bytes) {
while ((bytes > 0u) && (count > 0u)) {
const uint32 left = slots[0]->len - sent;
if (bytes >= left) {
bytes -= left;
RemoveAt(0u);
sent = 0u;
} else {
sent += bytes;
bytes = 0u;
}
}
}
bool TCPSFrameQueue::Flush(int fd) {
bool alive = true;
while (alive && (count > 0u)) {
struct iovec iov[TCPS_MAX_BATCH];
uint32 n = (count < TCPS_MAX_BATCH) ? count : TCPS_MAX_BATCH;
for (uint32 i = 0u; i < n; i++) {
const uint32 off = (i == 0u) ? sent : 0u;
iov[i].iov_base = &slots[i]->buf[off];
iov[i].iov_len = slots[i]->len - off;
}
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = n;
ssize_t w = sendmsg(fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT);
if (w > 0) {
lastProgress = HighResolutionTimer::Counter();
Consume(static_cast<uint32>(w));
} else if ((w < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
break;
} else if ((w < 0) && (errno == EINTR)) {
continue;
} else {
alive = false;
}
}
return alive;
}
bool TCPSFrameQueue::Empty() const {
return count == 0u;
}
uint64 TCPSFrameQueue::LastProgress() const {
return lastProgress;
}
} // namespace MARTe
@@ -0,0 +1,79 @@
#ifndef TCPS_FRAME_QUEUE_H_
#define TCPS_FRAME_QUEUE_H_
/**
* @file TCPSFrameQueue.h
* @brief Bounded per-connection output queue of UDPS frames (header + payload).
*
* Same semantics as the per-client queue inside TCPSServer: at most `depth`
* DATA frames wait; when full the oldest DATA frame that is not already
* (partially) on the wire is discarded and counted. A CONFIG is never dropped
* and, when queued, discards the DATA frames behind the one on the wire (they
* were encoded for the previous layout).
*
* Not thread-safe: the owner serialises Push() / Flush().
*/
#include "CompilerTypes.h"
namespace MARTe {
class TCPSFrameQueue {
public:
TCPSFrameQueue();
~TCPSFrameQueue();
/** Allocate `depth` DATA slots plus two CONFIG slots (room for one stream). */
void Init(uint32 depth);
/**
* Make room for @p numStreams multiplexed streams: each gets its own `depth`
* DATA frames plus two CONFIG slots. Grow-only; call while the queue is idle
* (before the connection is attached to any stream).
*/
void Reserve(uint32 numStreams);
/**
* Append a complete frame (copied). The frame is stamped with @p streamIdx in
* its header's fragmentIdx field. Accounting is per stream: a full stream
* evicts its own oldest DATA, and a CONFIG only discards the queued frames
* of its own stream.
* @param[in,out] dropped incremented by the number of DATA frames discarded.
* @return false if the frame itself was refused (queue full of in-flight data).
*/
bool Push(uint16 streamIdx, bool isConfig, const uint8 *frame, uint32 frameBytes,
uint32 &dropped);
/**
* Write as much as the socket accepts without blocking, batching up to
* TCPS_MAX_BATCH frames per system call.
* @return false if the connection is broken.
*/
bool Flush(int fd);
/** Most frames sent by one sendmsg(). */
static const uint32 TCPS_MAX_BATCH = 16u;
bool Empty() const;
/** HRT ticks of the last byte written (or of the queue becoming non-empty). */
uint64 LastProgress() const;
private:
struct Slot;
TCPSFrameQueue(const TCPSFrameQueue &);
TCPSFrameQueue &operator=(const TCPSFrameQueue &);
void RemoveAt(uint32 i);
void Consume(uint32 bytes);
Slot **slots;
uint32 cap;
uint32 depth;
uint32 count;
uint32 sent;
uint64 lastProgress;
};
} // namespace MARTe
#endif // TCPS_FRAME_QUEUE_H_
@@ -0,0 +1,329 @@
/**
* @file TCPSServiceStream.cpp
* @brief Implementation of TCPSServiceStream.
*/
#define DLL_API
#include "TCPSServiceStream.h"
#include "AdvancedErrorManagement.h"
#include "ObjectRegistryDatabase.h"
#include "TCPSConn.h"
#include "TCPSWorker.h"
#include <string.h>
namespace MARTe {
const uint32 TCPSServiceStream::TCPSS_DEFAULT_MAX_PAYLOAD;
static const uint32 TCPSS_MAX_FRAME_PAYLOAD = 1048576u;
TCPSServiceStream::TCPSServiceStream(const char8 *serviceObjectName, const char8 *name)
: serviceName(serviceObjectName), streamName(name), registered(false),
maxPayloadSize(TCPSS_DEFAULT_MAX_PAYLOAD), subs(NULL_PTR(TCPSConn **)), subIdx(NULL_PTR(uint16 *)),
capSubs(0u), numSubs(0u), cachedConfigFrame(NULL_PTR(uint8 *)),
cachedConfigBytes(0u), cachedConfigCap(0u), configCounter(0u), drops(0u),
numTaps(0u), dataFrame(NULL_PTR(uint8 *)), dataFrameCap(0u) {
for (uint32 i = 0u; i < TCPSS_MAX_TAPS; i++) {
taps[i] = NULL_PTR(TCPSStreamTapI *);
}
}
TCPSServiceStream::~TCPSServiceStream() {
(void)Stop();
if (cachedConfigFrame != NULL_PTR(uint8 *)) {
delete[] cachedConfigFrame;
}
if (dataFrame != NULL_PTR(uint8 *)) {
delete[] dataFrame;
}
if (subs != NULL_PTR(TCPSConn **)) {
delete[] subs;
}
if (subIdx != NULL_PTR(uint16 *)) {
delete[] subIdx;
}
}
bool TCPSServiceStream::Initialise(StructuredDataI &data) {
bool ok = true;
maxPayloadSize = TCPSS_DEFAULT_MAX_PAYLOAD;
(void)data.Read("MaxPayloadSize", maxPayloadSize);
if ((maxPayloadSize == 0u) || (maxPayloadSize > TCPSS_MAX_FRAME_PAYLOAD)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServiceStream: MaxPayloadSize %u must be in 1..%u.",
maxPayloadSize, TCPSS_MAX_FRAME_PAYLOAD);
ok = false;
}
if ((streamName.Size() > 0u) && (strchr(streamName.Buffer(), ',') != NULL_PTR(char8 *))) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServiceStream: StreamName '%s' may not contain a comma.",
streamName.Buffer());
ok = false;
}
if ((streamName.Size() == 0u) || (streamName.Size() > TCPS_MAX_STREAM_NAME)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServiceStream: StreamName must be 1..%u characters.",
TCPS_MAX_STREAM_NAME);
ok = false;
}
return ok;
}
bool TCPSServiceStream::Start() {
if (registered) {
return true;
}
if (!service.IsValid()) {
ReferenceT<TCPStreamService> found =
ObjectRegistryDatabase::Instance()->Find(serviceName.Buffer());
if (!found.IsValid()) {
REPORT_ERROR_STATIC(ErrorManagement::InitialisationError,
"TCPSServiceStream: no TCPStreamService named '%s'.",
serviceName.Buffer());
return false;
}
service = found;
}
mutex.FastLock();
if (subs == NULL_PTR(TCPSConn **)) {
capSubs = service->MaxClients();
subs = new TCPSConn *[capSubs];
subIdx = new uint16[capSubs];
}
numSubs = 0u;
mutex.FastUnLock();
registered = service->RegisterStream(this);
return registered;
}
bool TCPSServiceStream::Stop() {
if (registered) {
service->UnregisterStream(this); // drops every subscriber
registered = false;
}
mutex.FastLock();
if (cachedConfigFrame != NULL_PTR(uint8 *)) {
cachedConfigBytes = 0u;
}
mutex.FastUnLock();
return true;
}
void TCPSServiceStream::ServiceClients() {
}
bool TCPSServiceStream::BuildFrame(uint8 *&buf, uint32 &cap, uint8 type, uint32 counter,
const uint8 *payload, uint32 payloadSize,
uint32 &frameBytes) {
bool ok = (payloadSize <= TCPSS_MAX_FRAME_PAYLOAD);
if (ok) {
const uint32 need = UDPS_HEADER_SIZE + payloadSize;
if (cap < need) {
if (buf != NULL_PTR(uint8 *)) {
delete[] buf;
}
buf = new uint8[need];
cap = need;
}
UDPSBuildHeader(buf, type, counter, 0u, 1u, payloadSize);
if (payloadSize > 0u) {
memcpy(&buf[UDPS_HEADER_SIZE], payload, payloadSize);
}
frameBytes = need;
}
return ok;
}
/** Caller holds `mutex`. */
void TCPSServiceStream::Distribute(bool isConfig, const uint8 *frame, uint32 frameBytes) {
for (uint32 i = 0u; i < numSubs; i++) {
TCPSConn *c = subs[i];
uint32 dropped = 0u;
c->qMutex.FastLock();
const bool wasEmpty = c->q.Empty();
(void)c->q.Push(subIdx[i], isConfig, frame, frameBytes, dropped);
c->qMutex.FastUnLock();
drops += dropped;
if (wasEmpty) {
c->worker->Wake();
}
}
}
bool TCPSServiceStream::SendConfig(const uint8 *payload, uint32 payloadSize) {
if (!registered) {
return false;
}
if (payloadSize > TCPSS_MAX_FRAME_PAYLOAD) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServiceStream: CONFIG of %u bytes exceeds the frame limit.",
payloadSize);
return false;
}
mutex.FastLock();
configCounter++;
bool ok = BuildFrame(cachedConfigFrame, cachedConfigCap, UDPS_TYPE_CONFIG, configCounter,
payload, payloadSize, cachedConfigBytes);
if (ok) {
Distribute(true, cachedConfigFrame, cachedConfigBytes);
}
mutex.FastUnLock();
if (ok && (numTaps > 0u)) {
tapMutex.FastLock();
for (uint32 i = 0u; i < numTaps; i++) {
taps[i]->OnTapConfig(this, payload, payloadSize);
}
tapMutex.FastUnLock();
}
return ok;
}
bool TCPSServiceStream::SendData(uint32 counter, const uint8 *payload, uint32 payloadSize) {
if (!registered) {
return false;
}
if (numTaps > 0u) {
tapMutex.FastLock();
for (uint32 i = 0u; i < numTaps; i++) {
taps[i]->OnTapData(this, counter, payload, payloadSize);
}
tapMutex.FastUnLock();
}
if (numSubs == 0u) {
return true;
}
uint32 frameBytes = 0u;
if (!BuildFrame(dataFrame, dataFrameCap, UDPS_TYPE_DATA, counter, payload, payloadSize,
frameBytes)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServiceStream: DATA of %u bytes exceeds the frame limit.",
payloadSize);
return false;
}
mutex.FastLock();
Distribute(false, dataFrame, frameBytes);
mutex.FastUnLock();
return true;
}
bool TCPSServiceStream::AddTap(TCPSStreamTapI *tap) {
bool ok = false;
uint8 *cfg = NULL_PTR(uint8 *);
uint32 cfgBytes = 0u;
mutex.FastLock();
if (cachedConfigBytes > UDPS_HEADER_SIZE) {
cfgBytes = cachedConfigBytes - UDPS_HEADER_SIZE;
cfg = new uint8[cfgBytes];
memcpy(cfg, &cachedConfigFrame[UDPS_HEADER_SIZE], cfgBytes);
}
mutex.FastUnLock();
tapMutex.FastLock();
if (numTaps < TCPSS_MAX_TAPS) {
taps[numTaps] = tap;
numTaps = numTaps + 1u;
ok = true;
if (cfg != NULL_PTR(uint8 *)) {
tap->OnTapConfig(this, cfg, cfgBytes);
}
}
tapMutex.FastUnLock();
if (cfg != NULL_PTR(uint8 *)) {
delete[] cfg;
}
return ok;
}
void TCPSServiceStream::RemoveTap(TCPSStreamTapI *tap) {
tapMutex.FastLock();
for (uint32 i = 0u; i < numTaps; i++) {
if (taps[i] == tap) {
taps[i] = taps[numTaps - 1u];
numTaps = numTaps - 1u;
break;
}
}
tapMutex.FastUnLock();
}
bool TCPSServiceStream::HasClients() const {
/* A tap (TCPStreamJoin) consumes frames like a subscriber: the producer must keep publishing. */
return (numSubs > 0u) || (numTaps > 0u);
}
bool TCPSServiceStream::IsMulticast() const {
return false;
}
uint16 TCPSServiceStream::GetPort() const {
return service.IsValid() ? service->GetBoundPort() : static_cast<uint16>(0u);
}
const char8 *TCPSServiceStream::GetStreamName() const {
return streamName.Buffer();
}
uint32 TCPSServiceStream::GetClientCount() const {
return numSubs;
}
uint64 TCPSServiceStream::GetClientDrops() const {
return drops;
}
uint32 TCPSServiceStream::GetMaxPayloadSize() const {
return maxPayloadSize;
}
bool TCPSServiceStream::AttachConn(TCPSConn *c, uint16 streamIdx) {
bool ok = false;
mutex.FastLock();
if (numSubs < capSubs) {
// The CONFIG goes in first so the client always decodes DATA against it.
if (cachedConfigBytes > 0u) {
uint32 dropped = 0u;
c->qMutex.FastLock();
(void)c->q.Push(streamIdx, true, cachedConfigFrame, cachedConfigBytes, dropped);
c->qMutex.FastUnLock();
}
subs[numSubs] = c;
subIdx[numSubs] = streamIdx;
numSubs = numSubs + 1u;
ok = true;
}
mutex.FastUnLock();
return ok;
}
void TCPSServiceStream::DetachConn(TCPSConn *c) {
mutex.FastLock();
for (uint32 i = 0u; i < numSubs; i++) {
if (subs[i] == c) {
subs[i] = subs[numSubs - 1u];
subIdx[i] = subIdx[numSubs - 1u];
numSubs = numSubs - 1u;
break;
}
}
mutex.FastUnLock();
}
void TCPSServiceStream::DropAllConns() {
mutex.FastLock();
for (uint32 i = 0u; i < numSubs; i++) {
TCPSConn *c = subs[i];
for (uint32 k = 0u; k < c->numStreams; k++) {
if (c->streams[k] == this) {
c->streams[k] = NULL_PTR(TCPSServiceStream *);
}
}
subs[i]->closeRequested = true;
subs[i]->worker->Wake();
}
numSubs = 0u;
mutex.FastUnLock();
}
} // namespace MARTe
@@ -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_
@@ -0,0 +1,40 @@
#ifndef TCPS_STREAM_TAP_I_H_
#define TCPS_STREAM_TAP_I_H_
/**
* @file TCPSStreamTapI.h
* @brief Hooks used by TCPStreamJoin to follow the streams of a TCPStreamService.
*
* TCPSStreamTapI observes the CONFIG / DATA payloads a stream publishes (on the
* producer's thread, after the frame went to the subscribers). TCPSStreamObserverI
* observes streams registering with / leaving a service.
*/
#include "CompilerTypes.h"
namespace MARTe {
class TCPSServiceStream;
class TCPSStreamTapI {
public:
virtual ~TCPSStreamTapI() {}
/** A CONFIG payload was published (or the cached one is replayed on AddTap). */
virtual void OnTapConfig(TCPSServiceStream *source, const uint8 *payload, uint32 payloadSize) = 0;
/** A DATA payload was published. */
virtual void OnTapData(TCPSServiceStream *source, uint32 counter, const uint8 *payload,
uint32 payloadSize) = 0;
};
class TCPSStreamObserverI {
public:
virtual ~TCPSStreamObserverI() {}
/** @p stream just registered. May call back into the service. */
virtual void OnStreamRegistered(TCPSServiceStream *stream) = 0;
/** @p stream is leaving (it is still valid during the call). */
virtual void OnStreamUnregistered(TCPSServiceStream *stream) = 0;
};
} // namespace MARTe
#endif // TCPS_STREAM_TAP_I_H_
@@ -0,0 +1,266 @@
/**
* @file TCPSWorker.cpp
* @brief Implementation of TCPSWorker.
*/
#define DLL_API
#include "TCPSWorker.h"
#include "AdvancedErrorManagement.h"
#include "Atomic.h"
#include "HighResolutionTimer.h"
#include "TCPSConn.h"
#include "TCPStreamService.h"
#include "UDPSProtocol.h"
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
namespace MARTe {
/** Longest wait in poll(): bounds Stop() latency and the stall / handshake checks. */
static const int TCPS_WORKER_SLICE_MS = 50;
TCPSWorker::TCPSWorker(TCPStreamService &owner, uint32 maxConnections)
: service(owner), maxConns(maxConnections), thread(*this),
incoming(new TCPSConn *[maxConnections]), numIncoming(0u),
conns(new TCPSConn *[maxConnections]), numConns(0u),
pfds(new struct pollfd[maxConnections + 1u]), load(0) {
wakeFd[0] = -1;
wakeFd[1] = -1;
if (pipe(wakeFd) == 0) {
for (int i = 0; i < 2; i++) {
int flags = fcntl(wakeFd[i], F_GETFL, 0);
if (flags >= 0) {
(void)fcntl(wakeFd[i], F_SETFL, flags | O_NONBLOCK);
}
}
}
}
TCPSWorker::~TCPSWorker() {
Stop();
CloseAll();
for (uint32 i = 0u; i < numIncoming; i++) {
delete incoming[i];
service.ConnClosed();
}
delete[] incoming;
delete[] conns;
delete[] pfds;
for (int i = 0; i < 2; i++) {
if (wakeFd[i] >= 0) {
(void)close(wakeFd[i]);
}
}
}
bool TCPSWorker::Start(uint32 cpuMask, uint32 stackSize) {
if (wakeFd[0] < 0) {
return false;
}
thread.SetCPUMask(cpuMask);
thread.SetStackSize(stackSize);
return thread.Start() == ErrorManagement::NoError;
}
void TCPSWorker::Stop() {
(void)thread.Stop();
}
bool TCPSWorker::AddIncoming(TCPSConn *c) {
bool ok = false;
incomingMutex.FastLock();
if (numIncoming < maxConns) {
incoming[numIncoming] = c;
numIncoming++;
ok = true;
}
incomingMutex.FastUnLock();
if (ok) {
Atomic::Increment(&load);
Wake();
}
return ok;
}
void TCPSWorker::Wake() {
if (wakeFd[1] >= 0) {
const uint8 b = 1u;
// EAGAIN means the pipe is already full of wake-ups: nothing to add.
ssize_t r = write(wakeFd[1], &b, 1u);
(void)r;
}
}
int32 TCPSWorker::Load() const {
return load;
}
void TCPSWorker::AdoptIncoming() {
incomingMutex.FastLock();
for (uint32 i = 0u; i < numIncoming; i++) {
conns[numConns] = incoming[i];
numConns++;
}
numIncoming = 0u;
incomingMutex.FastUnLock();
}
void TCPSWorker::CloseConn(TCPSConn *c) {
service.Detach(c);
delete c; // closes the socket
service.ConnClosed();
Atomic::Decrement(&load);
}
void TCPSWorker::CloseAll() {
for (uint32 i = 0u; i < numConns; i++) {
CloseConn(conns[i]);
}
numConns = 0u;
}
bool TCPSWorker::Drain(TCPSConn &c) {
uint8 scratch[64];
bool alive = true;
for (;;) {
ssize_t n = recv(c.fd, scratch, sizeof(scratch), MSG_DONTWAIT);
if (n > 0) {
continue; // clients have nothing more to say after SUBSCRIBE
}
if (n == 0) {
alive = false;
} else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
alive = true;
} else if (errno == EINTR) {
continue;
} else {
alive = false;
}
break;
}
return alive;
}
bool TCPSWorker::HandshakeStep(TCPSConn &c) {
ssize_t n = recv(c.fd, &c.hs[c.hsHave], c.hsWant - c.hsHave, MSG_DONTWAIT);
if (n == 0) {
return false;
}
if (n < 0) {
return (errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR);
}
c.hsHave += static_cast<uint32>(n);
if (!c.hsHeaderOk && (c.hsHave >= UDPS_HEADER_SIZE)) {
UDPSPacketHeader h;
memcpy(&h, c.hs, UDPS_HEADER_SIZE);
if ((h.magic != UDPS_MAGIC) || (h.type != UDPS_TYPE_SUBSCRIBE) ||
(h.payloadBytes == 0u) || (h.payloadBytes > TCPS_MAX_SUBSCRIBE_PAYLOAD)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPStreamService: connection did not open with a valid SUBSCRIBE; closing.");
service.NoteRejected();
return false;
}
c.hsHeaderOk = true;
c.hsWant = UDPS_HEADER_SIZE + h.payloadBytes;
}
if (c.hsHeaderOk && (c.hsHave == c.hsWant)) {
c.hs[c.hsWant] = 0u;
char8 *names = reinterpret_cast<char8 *>(&c.hs[UDPS_HEADER_SIZE]);
if (!service.Attach(&c, names)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPStreamService: cannot attach to '%s'; closing.", names);
service.NoteRejected();
return false;
}
c.subscribed = true;
}
return true;
}
ErrorManagement::ErrorType TCPSWorker::Execute(ExecutionInfo &info) {
if (info.GetStage() == ExecutionInfo::TerminationStage) {
return ErrorManagement::NoError;
}
if (info.GetStage() != ExecutionInfo::MainStage) {
return ErrorManagement::NoError;
}
AdoptIncoming();
pfds[0].fd = wakeFd[0];
pfds[0].events = POLLIN;
pfds[0].revents = 0;
for (uint32 i = 0u; i < numConns; i++) {
TCPSConn *c = conns[i];
short ev = POLLIN;
if (c->subscribed) {
c->qMutex.FastLock();
if (!c->q.Empty()) {
ev = static_cast<short>(ev | POLLOUT);
}
c->qMutex.FastUnLock();
}
pfds[i + 1u].fd = c->fd;
pfds[i + 1u].events = ev;
pfds[i + 1u].revents = 0;
}
int pr = poll(pfds, static_cast<nfds_t>(numConns + 1u), TCPS_WORKER_SLICE_MS);
if (pr < 0) {
return ErrorManagement::NoError; // EINTR
}
if ((pfds[0].revents & POLLIN) != 0) {
uint8 sink[64];
while (read(wakeFd[0], sink, sizeof(sink)) > 0) {
}
}
const uint64 now = HighResolutionTimer::Counter();
const uint64 stallTicks = service.StallTicks();
uint32 kept = 0u;
for (uint32 i = 0u; i < numConns; i++) {
TCPSConn *c = conns[i];
const short re = pfds[i + 1u].revents;
bool keep = !c->closeRequested && ((re & (POLLERR | POLLNVAL)) == 0);
if (keep && ((re & (POLLIN | POLLHUP)) != 0)) {
keep = c->subscribed ? Drain(*c) : HandshakeStep(*c);
}
if (keep && c->subscribed) {
c->qMutex.FastLock();
keep = c->q.Flush(c->fd);
if (keep && !c->q.Empty() && (stallTicks > 0u) &&
(now > c->q.LastProgress()) && ((now - c->q.LastProgress()) > stallTicks)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPStreamService: client stalled; disconnecting.");
service.NoteEviction();
keep = false;
}
c->qMutex.FastUnLock();
}
if (keep && !c->subscribed && (now > c->hsDeadline)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPStreamService: SUBSCRIBE timeout; closing.");
service.NoteRejected();
keep = false;
}
if (keep) {
conns[kept] = c;
kept++;
} else {
CloseConn(c);
}
}
numConns = kept;
return ErrorManagement::NoError;
}
} // namespace MARTe
@@ -0,0 +1,68 @@
#ifndef TCPS_WORKER_H_
#define TCPS_WORKER_H_
/**
* @file TCPSWorker.h
* @brief One I/O thread of a TCPStreamService (internal).
*
* Owns a set of connections, polls them (plus a self-pipe used by producers to
* announce new frames), performs the SUBSCRIBE handshake, flushes the bounded
* queues and evicts stalled / dead peers.
*/
#include "EmbeddedServiceMethodBinderI.h"
#include "ExecutionInfo.h"
#include "FastPollingMutexSem.h"
#include "SingleThreadService.h"
#include <poll.h>
namespace MARTe {
class TCPStreamService;
struct TCPSConn;
class TCPSWorker : public EmbeddedServiceMethodBinderI {
public:
TCPSWorker(TCPStreamService &owner, uint32 maxConns);
virtual ~TCPSWorker();
bool Start(uint32 cpuMask, uint32 stackSize);
void Stop();
/** Hand a freshly accepted connection to this worker (acceptor thread). */
bool AddIncoming(TCPSConn *c);
/** Interrupt the poll so queued data is flushed now (any thread, cheap). */
void Wake();
/** @return connections currently assigned (approximate). */
int32 Load() const;
virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info);
private:
void AdoptIncoming();
bool HandshakeStep(TCPSConn &c);
bool Drain(TCPSConn &c);
void CloseConn(TCPSConn *c);
void CloseAll();
TCPStreamService &service;
uint32 maxConns;
SingleThreadService thread;
int wakeFd[2];
FastPollingMutexSem incomingMutex;
TCPSConn **incoming;
uint32 numIncoming;
TCPSConn **conns;
uint32 numConns;
struct pollfd *pfds;
volatile int32 load;
};
} // namespace MARTe
#endif // TCPS_WORKER_H_
@@ -0,0 +1,494 @@
/**
* @file TCPStreamJoin.cpp
* @brief Source file for class TCPStreamJoin
* @date 06/11/2026
* @author Martino Ferrari
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*/
#define DLL_API
#include "TCPStreamJoin.h"
#include "AdvancedErrorManagement.h"
#include "ConfigurationDatabase.h"
#include "ObjectRegistryDatabase.h"
#include "UDPSProtocol.h"
#include <stdio.h>
#include <string.h>
namespace MARTe {
const uint32 TCPStreamJoin::TCPSJ_MAX_SOURCES;
TCPStreamJoin::Source::Source()
: stream(NULL_PTR(TCPSServiceStream *)), configOk(false), cfg(NULL_PTR(uint8 *)),
cfgBytes(0u), numSigs(0u), hrt(0u), body(NULL_PTR(uint8 *)), bodyCap(0u),
bodySize(0u), haveBody(false) {
}
TCPStreamJoin::Source::~Source() {
if (cfg != NULL_PTR(uint8 *)) {
delete[] cfg;
}
if (body != NULL_PTR(uint8 *)) {
delete[] body;
}
}
TCPStreamJoin::TCPStreamJoin()
: Object(), TCPSStreamTapI(), TCPSStreamObserverI(), out(NULL_PTR(TCPSServiceStream *)),
observing(false), src(NULL_PTR(Source *)), numSrc(0u), master(0u), maxPayload(60000u),
active(false), configPublished(false), sizeLogged(false), outCounter(0u), emitted(0u),
scratch(NULL_PTR(uint8 *)), scratchCap(0u) {
}
TCPStreamJoin::~TCPStreamJoin() {
if (observing) {
service->RemoveObserver(this);
observing = false;
}
for (uint32 i = 0u; i < numSrc; i++) {
mtx.FastLock();
TCPSServiceStream *s = src[i].stream;
src[i].stream = NULL_PTR(TCPSServiceStream *);
mtx.FastUnLock();
if (s != NULL_PTR(TCPSServiceStream *)) {
s->RemoveTap(this);
}
}
if (out != NULL_PTR(TCPSServiceStream *)) {
delete out; // unregisters the merged stream
out = NULL_PTR(TCPSServiceStream *);
}
if (src != NULL_PTR(Source *)) {
delete[] src;
}
if (scratch != NULL_PTR(uint8 *)) {
delete[] scratch;
}
}
bool TCPStreamJoin::Initialise(StructuredDataI &data) {
bool ok = Object::Initialise(data);
StreamString serviceName;
if (ok && (!data.Read("Service", serviceName) || (serviceName.Size() == 0u))) {
REPORT_ERROR(ErrorManagement::ParametersError, "Parameter 'Service' is required.");
ok = false;
}
if (ok && (!data.Read("StreamName", outName) || (outName.Size() == 0u))) {
outName = GetName();
}
StreamString sources;
if (ok && (!data.Read("Sources", sources) || (sources.Size() == 0u))) {
REPORT_ERROR(ErrorManagement::ParametersError, "Parameter 'Sources' is required.");
ok = false;
}
StreamString masterName;
if (ok && !data.Read("Master", masterName)) {
masterName = "";
}
maxPayload = 60000u;
(void)data.Read("MaxPayloadSize", maxPayload);
if (ok) {
// Split "a, b ,c" into trimmed names.
src = new Source[TCPSJ_MAX_SOURCES];
const char8 *p = sources.Buffer();
while (ok && (p != NULL_PTR(const char8 *))) {
const char8 *comma = strchr(p, ',');
const char8 *end = (comma != NULL_PTR(const char8 *)) ? comma : (p + strlen(p));
while ((p < end) && (*p == ' ')) {
p++;
}
const char8 *e = end;
while ((e > p) && (e[-1] == ' ')) {
e--;
}
const uint32 len = static_cast<uint32>(e - p);
if ((len == 0u) || (len > TCPS_MAX_STREAM_NAME) || (numSrc >= TCPSJ_MAX_SOURCES)) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Sources must list 1..%u names of 1..%u characters.",
TCPSJ_MAX_SOURCES, TCPS_MAX_STREAM_NAME);
ok = false;
}
if (ok) {
StreamString name;
uint32 wlen = len;
(void)name.Write(p, wlen);
for (uint32 i = 0u; i < numSrc; i++) {
if (src[i].name == name) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Source '%s' is listed twice.", name.Buffer());
ok = false;
}
}
if (name == outName) {
REPORT_ERROR(ErrorManagement::ParametersError,
"The merged stream '%s' cannot be one of its own sources.",
name.Buffer());
ok = false;
}
src[numSrc].name = name;
numSrc++;
}
p = (comma != NULL_PTR(const char8 *)) ? (comma + 1) : NULL_PTR(const char8 *);
}
}
if (ok && (masterName.Size() > 0u)) {
const int32 m = FindByName(masterName.Buffer());
if (m < 0) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Master '%s' is not one of the Sources.", masterName.Buffer());
ok = false;
}
else {
master = static_cast<uint32>(m);
}
}
if (ok) {
service = ObjectRegistryDatabase::Instance()->Find(serviceName.Buffer());
if (!service.IsValid()) {
REPORT_ERROR(ErrorManagement::InitialisationError,
"No TCPStreamService named '%s' (declare it before the join).",
serviceName.Buffer());
ok = false;
}
}
if (ok) {
out = new TCPSServiceStream(serviceName.Buffer(), outName.Buffer());
ConfigurationDatabase scdb;
ok = scdb.Write("MaxPayloadSize", maxPayload) && scdb.MoveToRoot() && out->Initialise(scdb);
}
if (ok) {
// Last: the replay of already registered streams may complete the join right here.
observing = service->AddObserver(this);
if (!observing) {
REPORT_ERROR(ErrorManagement::InitialisationError,
"The service cannot take another observer.");
ok = false;
}
}
return ok;
}
int32 TCPStreamJoin::FindByName(const char8 *name) const {
int32 r = -1;
for (uint32 i = 0u; (i < numSrc) && (r < 0); i++) {
if (strcmp(src[i].name.Buffer(), name) == 0) {
r = static_cast<int32>(i);
}
}
return r;
}
int32 TCPStreamJoin::FindByStream(const TCPSServiceStream *s) const {
int32 r = -1;
for (uint32 i = 0u; (i < numSrc) && (r < 0); i++) {
if (src[i].stream == s) {
r = static_cast<int32>(i);
}
}
return r;
}
bool TCPStreamJoin::AllRegistered() const {
bool all = true;
for (uint32 i = 0u; i < numSrc; i++) {
all = all && (src[i].stream != NULL_PTR(TCPSServiceStream *));
}
return all;
}
bool TCPStreamJoin::IsActive() const {
return active;
}
bool TCPStreamJoin::HasConfig() const {
return configPublished;
}
uint64 TCPStreamJoin::GetFramesEmitted() const {
return emitted;
}
uint32 TCPStreamJoin::GetNumSources() const {
return numSrc;
}
void TCPStreamJoin::OnStreamRegistered(TCPSServiceStream *stream) {
bool mine = false;
int32 idx = -1;
mtx.FastLock();
idx = FindByName(stream->GetStreamName());
if ((idx >= 0) && (src[idx].stream == NULL_PTR(TCPSServiceStream *))) {
src[idx].stream = stream;
mine = true;
}
mtx.FastUnLock();
if (!mine) {
return;
}
// Replays the cached CONFIG into OnTapConfig; the join mutex must not be held.
if (!stream->AddTap(this)) {
REPORT_ERROR(ErrorManagement::InitialisationError,
"Stream '%s' cannot take another tap.", stream->GetStreamName());
mtx.FastLock();
src[idx].stream = NULL_PTR(TCPSServiceStream *);
mtx.FastUnLock();
return;
}
Evaluate();
}
void TCPStreamJoin::Evaluate() {
mtx.FastLock();
const bool start = !active && AllRegistered();
mtx.FastUnLock();
if (start) {
// Registering may call back into observers (including this one): no lock held.
const bool ok = out->Start();
mtx.FastLock();
if (ok) {
active = true;
outCounter = 0u;
PublishConfigLocked();
}
mtx.FastUnLock();
}
}
void TCPStreamJoin::OnStreamUnregistered(TCPSServiceStream *stream) {
mtx.FastLock();
const int32 idx = FindByStream(stream);
bool wasActive = false;
if (idx >= 0) {
Source &s = src[idx];
s.stream = NULL_PTR(TCPSServiceStream *);
s.configOk = false;
s.haveBody = false;
s.bodySize = 0u;
wasActive = active;
active = false;
configPublished = false;
}
mtx.FastUnLock();
if (idx < 0) {
return;
}
stream->RemoveTap(this);
if (wasActive) {
(void)out->Stop(); // subscribers of the merged stream are dropped
}
}
bool TCPStreamJoin::ParseConfig(Source &s, const uint8 *payload, uint32 n) {
bool ok = (n >= 5u);
uint32 numSigs = 0u;
if (ok) {
memcpy(&numSigs, payload, 4u);
const uint64 need = 4u + static_cast<uint64>(numSigs) * UDPS_SIGNAL_DESC_SIZE + 1u;
ok = (numSigs > 0u) && (need <= n);
}
if (ok) {
const uint32 off = 4u + numSigs * UDPS_SIGNAL_DESC_SIZE;
if (payload[off] == UDPS_PUBLISH_ACCUMULATE) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Source '%s' uses Accumulate publishing, which cannot be merged.",
s.name.Buffer());
ok = false;
}
else {
s.numSigs = numSigs;
s.hrt = 0u;
if (n >= (off + 1u + 8u)) {
memcpy(&s.hrt, &payload[off + 1u], 8u);
}
}
}
else {
REPORT_ERROR(ErrorManagement::ParametersError,
"Source '%s' sent a malformed CONFIG.", s.name.Buffer());
}
return ok;
}
void TCPStreamJoin::OnTapConfig(TCPSServiceStream *source, const uint8 *payload, uint32 payloadSize) {
mtx.FastLock();
const int32 idx = FindByStream(source);
if (idx >= 0) {
Source &s = src[idx];
s.haveBody = false;
s.bodySize = 0u;
configPublished = false;
sizeLogged = false;
s.configOk = ParseConfig(s, payload, payloadSize);
if (s.configOk) {
if (s.cfgBytes < payloadSize) {
if (s.cfg != NULL_PTR(uint8 *)) {
delete[] s.cfg;
}
s.cfg = new uint8[payloadSize];
}
memcpy(s.cfg, payload, payloadSize);
s.cfgBytes = payloadSize;
}
PublishConfigLocked();
}
mtx.FastUnLock();
}
/** Caller holds `mtx`. */
void TCPStreamJoin::PublishConfigLocked() {
configPublished = false;
bool ok = active;
uint64 totalSigs = 0u;
uint64 hrt = UDPS_HRT_FREQUENCY_UNKNOWN;
for (uint32 i = 0u; ok && (i < numSrc); i++) {
ok = src[i].configOk;
totalSigs += src[i].numSigs;
if (ok && (src[i].hrt != UDPS_HRT_FREQUENCY_UNKNOWN)) {
if ((hrt != UDPS_HRT_FREQUENCY_UNKNOWN) && (hrt != src[i].hrt)) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Join '%s': sources have different HRT frequencies, cannot merge.",
outName.Buffer());
ok = false;
}
hrt = src[i].hrt;
}
}
const uint64 cfgSize = 4u + totalSigs * UDPS_SIGNAL_DESC_SIZE + 1u + 8u;
if (ok && (cfgSize > maxPayload)) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Join '%s': merged CONFIG of %u bytes exceeds MaxPayloadSize.",
outName.Buffer(), static_cast<uint32>(cfgSize));
ok = false;
}
if (!ok) {
return;
}
uint8 *buf = new uint8[static_cast<uint32>(cfgSize)];
const uint32 nSigs = static_cast<uint32>(totalSigs);
memcpy(buf, &nSigs, 4u);
uint32 pos = 4u;
uint32 base = 0u;
for (uint32 i = 0u; ok && (i < numSrc); i++) {
const char8 *prefix = src[i].name.Buffer();
for (uint32 k = 0u; ok && (k < src[i].numSigs); k++) {
UDPSSignalDescriptor d;
memcpy(&d, &src[i].cfg[4u + k * UDPS_SIGNAL_DESC_SIZE], UDPS_SIGNAL_DESC_SIZE);
d.name[UDPS_MAX_SIGNAL_NAME - 1u] = '\0';
const uint32 len = static_cast<uint32>(strlen(prefix) + 1u + strlen(d.name));
if (len >= UDPS_MAX_SIGNAL_NAME) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Join '%s': signal name '%s_%s' is longer than %u characters.",
outName.Buffer(), prefix, d.name, UDPS_MAX_SIGNAL_NAME - 1u);
ok = false;
}
else {
char8 merged[UDPS_MAX_SIGNAL_NAME];
(void)snprintf(merged, sizeof(merged), "%s_%s", prefix, d.name);
memset(d.name, 0, sizeof(d.name));
memcpy(d.name, merged, strlen(merged));
if (d.timeSignalIdx != UDPS_NO_TIME_SIGNAL) {
d.timeSignalIdx += base;
}
memcpy(&buf[pos], &d, UDPS_SIGNAL_DESC_SIZE);
pos += UDPS_SIGNAL_DESC_SIZE;
}
}
base += src[i].numSigs;
}
if (ok) {
buf[pos] = UDPS_PUBLISH_STRICT;
pos += 1u;
memcpy(&buf[pos], &hrt, 8u);
pos += 8u;
ok = out->SendConfig(buf, pos);
}
configPublished = ok;
delete[] buf;
}
void TCPStreamJoin::OnTapData(TCPSServiceStream *source, uint32 counter, const uint8 *payload,
uint32 payloadSize) {
(void)counter;
mtx.FastLock();
const int32 idx = FindByStream(source);
if ((idx >= 0) && src[idx].configOk && (payloadSize >= 8u)) {
Source &s = src[idx];
const uint32 bl = payloadSize - 8u;
// A size change without a new CONFIG would corrupt the merged layout: ignore.
if (!s.haveBody || (s.bodySize == bl)) {
if (s.bodyCap < bl) {
if (s.body != NULL_PTR(uint8 *)) {
delete[] s.body;
}
s.body = new uint8[(bl > 0u) ? bl : 1u];
s.bodyCap = (bl > 0u) ? bl : 1u;
}
if (bl > 0u) {
memcpy(s.body, &payload[8], bl);
}
s.bodySize = bl;
s.haveBody = true;
if (active && configPublished && (static_cast<uint32>(idx) == master)) {
uint64 total = 8u;
bool ready = true;
for (uint32 i = 0u; i < numSrc; i++) {
ready = ready && src[i].haveBody;
total += src[i].bodySize;
}
if (ready && (total > maxPayload)) {
if (!sizeLogged) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Join '%s': merged frame of %u bytes exceeds MaxPayloadSize.",
outName.Buffer(), static_cast<uint32>(total));
sizeLogged = true;
}
ready = false;
}
if (ready) {
if (scratchCap < total) {
if (scratch != NULL_PTR(uint8 *)) {
delete[] scratch;
}
scratch = new uint8[static_cast<uint32>(total)];
scratchCap = static_cast<uint32>(total);
}
memcpy(scratch, payload, 8u); // master timestamp
uint32 pos = 8u;
for (uint32 i = 0u; i < numSrc; i++) {
if (src[i].bodySize > 0u) {
memcpy(&scratch[pos], src[i].body, src[i].bodySize);
}
pos += src[i].bodySize;
}
outCounter++;
if (out->SendData(outCounter, scratch, pos)) {
emitted = emitted + 1u;
}
}
}
}
}
mtx.FastUnLock();
}
CLASS_REGISTER(TCPStreamJoin, "1.0")
} /* namespace MARTe */
@@ -0,0 +1,139 @@
#ifndef TCPSTREAMJOIN_H_
#define TCPSTREAMJOIN_H_
/**
* @file TCPStreamJoin.h
* @brief Publishes one new stream of a TCPStreamService that merges several other
* streams of the same service.
*
* @code
* +Svc = { Class = TCPStreamService Port = 44500 }
* +Join = { Class = TCPStreamJoin Service = "Svc" StreamName = "all"
* Sources = "fast,slow" Master = "fast" }
* @endcode
* Declare the join after the service. Consumers subscribe to "all" like to any stream.
*
* The merged stream is emitted at the pace of the Master source: each Master DATA frame
* produces one merged frame holding the Master's signals and the last values received
* from every other source (sample-and-hold). Nothing is emitted until every source has
* delivered one DATA frame. No thread is added: the merged frame is built and queued on
* the Master producer's thread.
*
* @par CONFIG
* Concatenation of the source descriptors in Sources order, named
* "<stream>_<signal>" (at most 63 characters), time-signal indexes rebased, publish mode
* Strict. All sources must share the same HRT frequency (an unknown one matches any).
*
* @par DATA
* [master timestamp][source0 body][source1 body]... where a body is that source's last
* DATA payload without its 8-byte timestamp. A held value is therefore stamped with the
* Master's time unless the source carries its own time signal.
*
* @par Limits
* Only Strict and Decimate sources are accepted (Accumulate batches have varying
* length); a source whose frame size changes without a new CONFIG is ignored; the merged
* frame must fit MaxPayloadSize. The output stream is registered while every source is
* registered and removed as soon as one leaves; it is rebuilt when a source re-registers
* or changes its CONFIG.
*
* @par Parameters
* | Parameter | Type | Default | Description |
* |----------------|--------|-------------|-------------|
* | Service | string | (required) | Name of the TCPStreamService object. |
* | StreamName | string | object name | Name of the merged stream. |
* | Sources | string | (required) | Comma separated source stream names (1..16). |
* | Master | string | first source| Source whose frames pace the merged stream. |
* | MaxPayloadSize | uint32 | 60000 | Largest merged frame payload. |
*
* @par Locking
* Producer-side: source tapMutex, then the join mutex, then the output stream mutex, then
* the connection queue mutex. Service notifications run outside its topology lock and
* are serialised.
*/
#include "FastPollingMutexSem.h"
#include "Object.h"
#include "ReferenceT.h"
#include "StreamString.h"
#include "StructuredDataI.h"
#include "TCPSServiceStream.h"
#include "TCPSStreamTapI.h"
#include "TCPStreamService.h"
namespace MARTe {
class TCPStreamJoin : public Object, public TCPSStreamTapI, public TCPSStreamObserverI {
public:
CLASS_REGISTER_DECLARATION()
/** Most source streams one join can merge. */
static const uint32 TCPSJ_MAX_SOURCES = 16u;
TCPStreamJoin();
virtual ~TCPStreamJoin();
virtual bool Initialise(StructuredDataI &data);
virtual void OnTapConfig(TCPSServiceStream *source, const uint8 *payload, uint32 payloadSize);
virtual void OnTapData(TCPSServiceStream *source, uint32 counter, const uint8 *payload,
uint32 payloadSize);
virtual void OnStreamRegistered(TCPSServiceStream *stream);
virtual void OnStreamUnregistered(TCPSServiceStream *stream);
/** @return true while the merged stream is registered with the service. */
bool IsActive() const;
/** @return true once a merged CONFIG has been published for the current sources. */
bool HasConfig() const;
/** @return merged DATA frames emitted. */
uint64 GetFramesEmitted() const;
uint32 GetNumSources() const;
private:
struct Source {
Source();
~Source();
StreamString name;
TCPSServiceStream *stream; ///< non-NULL while registered and tapped
bool configOk;
uint8 *cfg;
uint32 cfgBytes;
uint32 numSigs;
uint64 hrt;
uint8 *body;
uint32 bodyCap;
uint32 bodySize;
bool haveBody;
};
int32 FindByName(const char8 *name) const;
int32 FindByStream(const TCPSServiceStream *s) const;
bool AllRegistered() const;
void Evaluate();
void PublishConfigLocked();
bool ParseConfig(Source &s, const uint8 *payload, uint32 n);
ReferenceT<TCPStreamService> service;
TCPSServiceStream *out;
bool observing;
StreamString outName;
Source *src;
uint32 numSrc;
uint32 master;
uint32 maxPayload;
FastPollingMutexSem mtx;
bool active;
bool configPublished;
bool sizeLogged;
uint32 outCounter;
volatile uint64 emitted;
uint8 *scratch;
uint32 scratchCap;
TCPStreamJoin(const TCPStreamJoin &);
TCPStreamJoin &operator=(const TCPStreamJoin &);
};
} // namespace MARTe
#endif // TCPSTREAMJOIN_H_
@@ -0,0 +1,502 @@
/**
* @file TCPStreamService.cpp
* @brief Source file for class TCPStreamService
* @date 06/11/2026
* @author Martino Ferrari
*
* @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
* the Development of Fusion Energy ('Fusion for Energy').
* Licensed under the EUPL, Version 1.1 or - as soon they will be approved
* by the European Commission - subsequent versions of the EUPL (the "Licence")
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
*
* @warning Unless required by applicable law or agreed to in writing,
* software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the Licence permissions and limitations under the Licence.
*/
#define DLL_API
#include "TCPStreamService.h"
#include "AdvancedErrorManagement.h"
#include "Atomic.h"
#include "HighResolutionTimer.h"
#include "TCPSConn.h"
#include "TCPSServiceStream.h"
#include "TCPSWorker.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace MARTe {
static const int TCPS_ACCEPT_SLICE_MS = 50;
TCPStreamService::TCPStreamService()
: Object(), EmbeddedServiceMethodBinderI(), port(44500u), boundPort(0u),
numWorkers(2u), maxClients(64u), maxStreams(32u), queueDepth(8u),
stallTimeoutS(5u), handshakeTimeoutS(5u), sendBufferSize(0u),
cpuMask(0xFFFFFFFFu), stackSize(65536u), stallTicks(0u), handshakeTicks(0u),
listenFd(-1), acceptThread(*this), acceptorStarted(false),
workers(NULL_PTR(TCPSWorker **)), workersCreated(0u),
numObservers(0u),
streams(NULL_PTR(TCPSServiceStream **)), numStreams(0u),
connCount(0), evictions(0), rejected(0) {
(void)notifyMutex.Create(true);
for (uint32 i = 0u; i < TCPS_MAX_OBSERVERS; i++) {
observers[i] = NULL_PTR(TCPSStreamObserverI *);
}
}
TCPStreamService::~TCPStreamService() {
Shutdown();
}
void TCPStreamService::Shutdown() {
if (acceptorStarted) {
(void)acceptThread.Stop();
acceptorStarted = false;
}
for (uint32 i = 0u; i < workersCreated; i++) {
workers[i]->Stop();
}
if (listenFd >= 0) {
(void)close(listenFd);
listenFd = -1;
}
for (uint32 i = 0u; i < workersCreated; i++) {
delete workers[i];
}
workersCreated = 0u;
if (workers != NULL_PTR(TCPSWorker **)) {
delete[] workers;
workers = NULL_PTR(TCPSWorker **);
}
if (streams != NULL_PTR(TCPSServiceStream **)) {
delete[] streams;
streams = NULL_PTR(TCPSServiceStream **);
}
numStreams = 0u;
}
bool TCPStreamService::Initialise(StructuredDataI &data) {
bool ok = Object::Initialise(data);
port = 44500u;
(void)data.Read("Port", port);
if (port > 65535u) {
REPORT_ERROR(ErrorManagement::ParametersError, "Port %u out of range.", port);
ok = false;
}
numWorkers = 2u;
(void)data.Read("Workers", numWorkers);
if ((numWorkers == 0u) || (numWorkers > 32u)) {
REPORT_ERROR(ErrorManagement::ParametersError, "Workers %u must be in 1..32.", numWorkers);
ok = false;
}
maxClients = 64u;
(void)data.Read("MaxClients", maxClients);
if ((maxClients == 0u) || (maxClients > 1024u)) {
REPORT_ERROR(ErrorManagement::ParametersError, "MaxClients %u must be in 1..1024.", maxClients);
ok = false;
}
maxStreams = 32u;
(void)data.Read("MaxStreams", maxStreams);
if ((maxStreams == 0u) || (maxStreams > 256u)) {
REPORT_ERROR(ErrorManagement::ParametersError, "MaxStreams %u must be in 1..256.", maxStreams);
ok = false;
}
queueDepth = 8u;
(void)data.Read("ClientQueueDepth", queueDepth);
if ((queueDepth == 0u) || (queueDepth > 4096u)) {
REPORT_ERROR(ErrorManagement::ParametersError, "ClientQueueDepth %u must be in 1..4096.", queueDepth);
ok = false;
}
stallTimeoutS = 5u;
(void)data.Read("ClientStallTimeout", stallTimeoutS);
handshakeTimeoutS = 5u;
(void)data.Read("HandshakeTimeout", handshakeTimeoutS);
if (handshakeTimeoutS == 0u) {
REPORT_ERROR(ErrorManagement::ParametersError, "HandshakeTimeout must be at least 1 second.");
ok = false;
}
sendBufferSize = 0u;
(void)data.Read("SendBufferSize", sendBufferSize);
(void)data.Read("CPUMask", cpuMask);
(void)data.Read("StackSize", stackSize);
stallTicks = static_cast<uint64>(stallTimeoutS) * HighResolutionTimer::Frequency();
handshakeTicks = static_cast<uint64>(handshakeTimeoutS) * HighResolutionTimer::Frequency();
if (!ok) {
return false;
}
/* Listening socket. */
int fd = socket(AF_INET, SOCK_STREAM, 0);
ok = (fd >= 0);
if (!ok) {
REPORT_ERROR(ErrorManagement::FatalError, "socket() failed: %s.", strerror(errno));
}
if (ok) {
int one = 1;
(void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(static_cast<uint16>(port));
if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) != 0) {
REPORT_ERROR(ErrorManagement::FatalError, "bind(%u) failed: %s.", port, strerror(errno));
ok = false;
}
}
if (ok && (listen(fd, 32) != 0)) {
REPORT_ERROR(ErrorManagement::FatalError, "listen() failed: %s.", strerror(errno));
ok = false;
}
if (ok) {
int flags = fcntl(fd, F_GETFL, 0);
ok = (flags >= 0) && (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
}
if (ok) {
struct sockaddr_in addr;
socklen_t len = static_cast<socklen_t>(sizeof(addr));
memset(&addr, 0, sizeof(addr));
boundPort = static_cast<uint16>(port);
if (getsockname(fd, reinterpret_cast<struct sockaddr *>(&addr), &len) == 0) {
boundPort = ntohs(addr.sin_port);
}
}
if (!ok) {
if (fd >= 0) {
(void)close(fd);
}
return false;
}
listenFd = fd;
streams = new TCPSServiceStream *[maxStreams];
workers = new TCPSWorker *[numWorkers];
for (uint32 i = 0u; (i < numWorkers) && ok; i++) {
workers[i] = new TCPSWorker(*this, maxClients);
workersCreated = i + 1u;
ok = workers[i]->Start(cpuMask, stackSize);
if (!ok) {
REPORT_ERROR(ErrorManagement::FatalError, "Could not start worker %u.", i);
}
}
if (ok) {
acceptThread.SetCPUMask(cpuMask);
acceptThread.SetStackSize(stackSize);
ok = (acceptThread.Start() == ErrorManagement::NoError);
acceptorStarted = ok;
if (!ok) {
REPORT_ERROR(ErrorManagement::FatalError, "Could not start the acceptor thread.");
}
}
if (!ok) {
Shutdown();
}
return ok;
}
ErrorManagement::ErrorType TCPStreamService::Execute(ExecutionInfo &info) {
if (info.GetStage() != ExecutionInfo::MainStage) {
return ErrorManagement::NoError;
}
struct pollfd p;
p.fd = listenFd;
p.events = POLLIN;
p.revents = 0;
if (poll(&p, 1, TCPS_ACCEPT_SLICE_MS) <= 0) {
return ErrorManagement::NoError;
}
for (;;) {
int fd = accept(listenFd, NULL_PTR(struct sockaddr *), NULL_PTR(socklen_t *));
if (fd < 0) {
break;
}
if (static_cast<uint32>(connCount) >= maxClients) {
REPORT_ERROR(ErrorManagement::Warning,
"MaxClients (%u) reached; connection refused.", maxClients);
(void)close(fd);
continue;
}
int flags = fcntl(fd, F_GETFL, 0);
if ((flags < 0) || (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0)) {
(void)close(fd);
continue;
}
int one = 1;
(void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
if (sendBufferSize > 0u) {
int sz = static_cast<int>(sendBufferSize);
(void)setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sz, sizeof(sz));
}
TCPSWorker *best = workers[0];
for (uint32 i = 1u; i < workersCreated; i++) {
if (workers[i]->Load() < best->Load()) {
best = workers[i];
}
}
TCPSConn *c = new TCPSConn(fd, best, queueDepth,
HighResolutionTimer::Counter() + handshakeTicks);
Atomic::Increment(&connCount);
if (!best->AddIncoming(c)) {
delete c;
Atomic::Decrement(&connCount);
}
}
return ErrorManagement::NoError;
}
uint16 TCPStreamService::GetBoundPort() const {
return boundPort;
}
uint32 TCPStreamService::GetClientCount() const {
uint32 n = 0u;
topology.FastLock();
for (uint32 i = 0u; i < numStreams; i++) {
n += streams[i]->GetClientCount();
}
topology.FastUnLock();
return n;
}
uint32 TCPStreamService::GetStreamCount() const {
return numStreams;
}
uint32 TCPStreamService::GetWorkerCount() const {
return workersCreated;
}
uint64 TCPStreamService::GetClientDrops() const {
uint64 n = 0u;
topology.FastLock();
for (uint32 i = 0u; i < numStreams; i++) {
n += streams[i]->GetClientDrops();
}
topology.FastUnLock();
return n;
}
uint32 TCPStreamService::GetStallEvictions() const {
return static_cast<uint32>(evictions);
}
uint32 TCPStreamService::GetRejectedSubscriptions() const {
return static_cast<uint32>(rejected);
}
bool TCPStreamService::RegisterStream(TCPSServiceStream *s) {
bool ok = true;
// Held across the registration so observers see (un)registrations in order.
(void)notifyMutex.Lock();
topology.FastLock();
if (numStreams >= maxStreams) {
REPORT_ERROR(ErrorManagement::ParametersError,
"Cannot register stream '%s': MaxStreams (%u) reached.",
s->GetStreamName(), maxStreams);
ok = false;
}
for (uint32 i = 0u; (i < numStreams) && ok; i++) {
if (strcmp(streams[i]->GetStreamName(), s->GetStreamName()) == 0) {
REPORT_ERROR(ErrorManagement::ParametersError,
"A stream named '%s' is already registered.", s->GetStreamName());
ok = false;
}
}
if (ok) {
streams[numStreams] = s;
numStreams++;
}
topology.FastUnLock();
if (ok) {
for (uint32 i = 0u; i < numObservers; i++) {
observers[i]->OnStreamRegistered(s);
}
}
(void)notifyMutex.UnLock();
return ok;
}
void TCPStreamService::UnregisterStream(TCPSServiceStream *s) {
(void)notifyMutex.Lock();
bool wasRegistered = false;
topology.FastLock();
for (uint32 i = 0u; i < numStreams; i++) {
if (streams[i] == s) {
streams[i] = streams[numStreams - 1u];
numStreams--;
wasRegistered = true;
break;
}
}
s->DropAllConns();
topology.FastUnLock();
if (wasRegistered) {
for (uint32 i = 0u; i < numObservers; i++) {
observers[i]->OnStreamUnregistered(s);
}
}
(void)notifyMutex.UnLock();
}
bool TCPStreamService::AddObserver(TCPSStreamObserverI *obs) {
bool ok = false;
(void)notifyMutex.Lock();
if (numObservers < TCPS_MAX_OBSERVERS) {
observers[numObservers] = obs;
numObservers++;
ok = true;
// Replay: streams cannot (un)register while notifyMutex is held.
topology.FastLock();
const uint32 n = numStreams;
TCPSServiceStream **snap = new TCPSServiceStream *[(n > 0u) ? n : 1u];
for (uint32 i = 0u; i < n; i++) {
snap[i] = streams[i];
}
topology.FastUnLock();
for (uint32 i = 0u; i < n; i++) {
obs->OnStreamRegistered(snap[i]);
}
delete[] snap;
}
(void)notifyMutex.UnLock();
return ok;
}
void TCPStreamService::RemoveObserver(TCPSStreamObserverI *obs) {
(void)notifyMutex.Lock();
for (uint32 i = 0u; i < numObservers; i++) {
if (observers[i] == obs) {
observers[i] = observers[numObservers - 1u];
numObservers--;
break;
}
}
(void)notifyMutex.UnLock();
}
bool TCPStreamService::Attach(TCPSConn *c, char8 *streamList) {
TCPSServiceStream *found[TCPS_MAX_CONN_STREAMS];
uint32 n = 0u;
bool ok = true;
topology.FastLock();
char8 *p = streamList;
while (ok) {
char8 *comma = strchr(p, ',');
if (comma != NULL_PTR(char8 *)) {
*comma = '\0';
}
const uint32 len = static_cast<uint32>(strlen(p));
TCPSServiceStream *match = NULL_PTR(TCPSServiceStream *);
if ((len == 0u) || (len > TCPS_MAX_STREAM_NAME) || (n >= TCPS_MAX_CONN_STREAMS)) {
ok = false;
}
for (uint32 i = 0u; ok && (i < numStreams) && (match == NULL_PTR(TCPSServiceStream *)); i++) {
if (strcmp(streams[i]->GetStreamName(), p) == 0) {
match = streams[i];
}
}
for (uint32 i = 0u; ok && (i < n); i++) {
if (found[i] == match) {
ok = false; // the same stream listed twice
}
}
if (ok && (match == NULL_PTR(TCPSServiceStream *))) {
ok = false;
}
if (ok) {
found[n] = match;
n++;
if (comma == NULL_PTR(char8 *)) {
break;
}
p = comma + 1;
}
}
if (ok) {
c->qMutex.FastLock();
c->q.Reserve(n);
c->qMutex.FastUnLock();
uint32 attached = 0u;
for (uint32 i = 0u; ok && (i < n); i++) {
ok = found[i]->AttachConn(c, static_cast<uint16>(i));
if (ok) {
attached++;
}
}
if (!ok) {
for (uint32 i = 0u; i < attached; i++) {
found[i]->DetachConn(c);
}
} else {
for (uint32 i = 0u; i < n; i++) {
c->streams[i] = found[i];
}
c->numStreams = n;
}
}
topology.FastUnLock();
return ok;
}
void TCPStreamService::Detach(TCPSConn *c) {
topology.FastLock();
for (uint32 i = 0u; i < c->numStreams; i++) {
if (c->streams[i] != NULL_PTR(TCPSServiceStream *)) {
c->streams[i]->DetachConn(c);
c->streams[i] = NULL_PTR(TCPSServiceStream *);
}
}
topology.FastUnLock();
}
void TCPStreamService::ConnClosed() {
Atomic::Decrement(&connCount);
}
void TCPStreamService::NoteEviction() {
Atomic::Increment(&evictions);
}
void TCPStreamService::NoteRejected() {
Atomic::Increment(&rejected);
}
uint32 TCPStreamService::QueueDepth() const {
return queueDepth;
}
uint64 TCPStreamService::StallTicks() const {
return stallTicks;
}
uint64 TCPStreamService::HandshakeTicks() const {
return handshakeTicks;
}
uint32 TCPStreamService::MaxClients() const {
return maxClients;
}
CLASS_REGISTER(TCPStreamService, "1.0")
} // namespace MARTe
@@ -0,0 +1,174 @@
#ifndef TCPSTREAMSERVICE_H_
#define TCPSTREAMSERVICE_H_
/**
* @file TCPStreamService.h
* @brief One in-process TCP streaming server shared by any number of
* TCPStreamer DataSources, served by a pool of worker threads.
*
* @details Declared once, at the root of the configuration:
* <pre>
* +StreamService = {
* Class = TCPStreamService
* Port = 44500
* Workers = 2
* }
* </pre>
* and referenced from any number of DataSources:
* <pre>
* +Fast = { Class = TCPStreamer Service = StreamService StreamName = Fast ... }
* +Slow = { Class = TCPStreamer Service = StreamService StreamName = Slow ... }
* </pre>
*
* Wire protocol: plain UDPS framing over TCP, exactly like TCPSServer, plus one
* client-to-server frame. Right after connecting, a client sends a SUBSCRIBE
* frame (UDPS_TYPE_SUBSCRIBE, payload = stream name, 1..255 bytes). The service
* then sends that stream's CONFIG followed by its DATA frames. One connection =
* one stream. A connection that does not subscribe within HandshakeTimeout
* seconds, or that names an unknown stream, is closed (clients retry).
*
* Threads: one acceptor plus `Workers` I/O threads. A connection lives on one
* worker. Producer threads never touch sockets: they copy each frame into every
* subscriber's bounded queue and poke the owning worker through a self-pipe, so
* a slow client only loses its own frames and never delays a producer or
* another client.
*
* @par Parameters (all optional)
* | Parameter | Type | Default | Description |
* |--------------------|--------|---------|-------------|
* | Port | uint32 | 44500 | TCP listen port; 0 = ephemeral (see GetBoundPort()). |
* | Workers | uint32 | 2 | I/O threads (1..32). |
* | MaxClients | uint32 | 64 | Simultaneous connections (1..1024). |
* | MaxStreams | uint32 | 32 | Registered streams (1..256). |
* | ClientQueueDepth | uint32 | 8 | DATA frames queued per client (1..4096). |
* | ClientStallTimeout | uint32 | 5 | Seconds without progress before eviction; 0 disables. |
* | HandshakeTimeout | uint32 | 5 | Seconds allowed to send SUBSCRIBE. |
* | SendBufferSize | uint32 | 0 | SO_SNDBUF for client sockets; 0 keeps the OS default. |
* | CPUMask | uint32 | 0xFFFFFFFF | Affinity of the service threads. |
* | StackSize | uint32 | 65536 | Stack of the service threads. |
*/
#include "EmbeddedServiceMethodBinderI.h"
#include "ExecutionInfo.h"
#include "FastPollingMutexSem.h"
#include "MutexSem.h"
#include "Object.h"
#include "SingleThreadService.h"
#include "StructuredDataI.h"
#include "TCPSStreamTapI.h"
#include "UDPSProtocol.h"
namespace MARTe {
class TCPSWorker;
class TCPSServiceStream;
struct TCPSConn;
/** Longest stream name accepted in a SUBSCRIBE frame. */
static const uint32 TCPS_MAX_STREAM_NAME = 255u;
/** Most streams one connection may multiplex. */
static const uint32 TCPS_MAX_CONN_STREAMS = UDPS_TCP_MAX_STREAMS;
/** Longest SUBSCRIBE payload: a comma separated list of stream names. */
static const uint32 TCPS_MAX_SUBSCRIBE_PAYLOAD = UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD;
class TCPStreamService : public Object, public EmbeddedServiceMethodBinderI {
public:
CLASS_REGISTER_DECLARATION()
TCPStreamService();
virtual ~TCPStreamService();
/** Reads the parameters, opens the listening socket and starts the threads. */
virtual bool Initialise(StructuredDataI &data);
/** Acceptor thread entry point; do not call directly. */
virtual ErrorManagement::ErrorType Execute(ExecutionInfo &info);
/** @return the port actually bound. */
uint16 GetBoundPort() const;
/** @return subscribed connections across all streams. */
uint32 GetClientCount() const;
uint32 GetStreamCount() const;
uint32 GetWorkerCount() const;
/** @return DATA frames dropped for slow clients, summed over registered streams. */
uint64 GetClientDrops() const;
/** @return connections closed by the stall timeout (all time). */
uint32 GetStallEvictions() const;
/** @return connections closed for a bad / unknown SUBSCRIBE (all time). */
uint32 GetRejectedSubscriptions() const;
/* ---- stream side ---- */
/** @return false if a stream with this name is already registered or the table is full. */
bool RegisterStream(TCPSServiceStream *s);
/** Remove the stream and make its subscribers close. */
void UnregisterStream(TCPSServiceStream *s);
/**
* Be told when streams register / unregister. The streams already registered are
* replayed to the observer before AddObserver returns. Notifications are serialised
* (and may nest on one thread), they never run under the topology lock, and once
* RemoveObserver returns no callback is running or will start.
* @return false if the observer table is full.
*/
bool AddObserver(TCPSStreamObserverI *obs);
void RemoveObserver(TCPSStreamObserverI *obs);
/* ---- worker side (internal) ---- */
/**
* Bind a connection to the streams named in @p streamList (comma separated,
* modified in place). The position in the list is the stream index stamped
* on every frame. All-or-nothing: @return false if any name is unknown,
* duplicated or malformed.
*/
bool Attach(TCPSConn *c, char8 *streamList);
void Detach(TCPSConn *c);
void ConnClosed();
void NoteEviction();
void NoteRejected();
uint32 QueueDepth() const;
uint64 StallTicks() const;
uint64 HandshakeTicks() const;
/** Max subscribers a stream may hold. */
uint32 MaxClients() const;
private:
void Shutdown();
uint32 port;
uint16 boundPort;
uint32 numWorkers;
uint32 maxClients;
uint32 maxStreams;
uint32 queueDepth;
uint32 stallTimeoutS;
uint32 handshakeTimeoutS;
uint32 sendBufferSize;
uint32 cpuMask;
uint32 stackSize;
uint64 stallTicks;
uint64 handshakeTicks;
int listenFd;
SingleThreadService acceptThread;
bool acceptorStarted;
TCPSWorker **workers;
uint32 workersCreated;
/** Most observers (TCPStreamJoin objects) one service can feed. */
static const uint32 TCPS_MAX_OBSERVERS = 16u;
MutexSem notifyMutex; ///< recursive; serialises observer calls with (un)registration
TCPSStreamObserverI *observers[TCPS_MAX_OBSERVERS];
uint32 numObservers;
mutable FastPollingMutexSem topology; ///< guards streams[] and every TCPSConn::stream
TCPSServiceStream **streams;
uint32 numStreams;
volatile int32 connCount;
volatile int32 evictions;
volatile int32 rejected;
};
} // namespace MARTe
#endif // TCPSTREAMSERVICE_H_
@@ -0,0 +1,353 @@
../../../..//Build/x86-linux/Components/Interfaces/TCPStreamService/TCPSFrameQueue.o: TCPSFrameQueue.cpp TCPSFrameQueue.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h
../../../..//Build/x86-linux/Components/Interfaces/TCPStreamService/TCPSServiceStream.o: TCPSServiceStream.cpp TCPSServiceStream.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
TCPStreamService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
TCPSConn.h TCPSFrameQueue.h TCPSWorker.h
../../../..//Build/x86-linux/Components/Interfaces/TCPStreamService/TCPStreamService.o: TCPStreamService.cpp TCPStreamService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Common/UDP/UDPSProtocol.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
TCPSConn.h TCPSFrameQueue.h TCPSServiceStream.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
TCPSWorker.h
../../../..//Build/x86-linux/Components/Interfaces/TCPStreamService/TCPSWorker.o: TCPSWorker.cpp TCPSWorker.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
TCPSConn.h TCPSFrameQueue.h TCPStreamService.h \
../../../..//Common/UDP/UDPSProtocol.h
@@ -0,0 +1,353 @@
TCPSFrameQueue.o: TCPSFrameQueue.cpp TCPSFrameQueue.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h
TCPSServiceStream.o: TCPSServiceStream.cpp TCPSServiceStream.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
TCPStreamService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Common/UDP/UDPSProtocol.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
TCPSConn.h TCPSFrameQueue.h TCPSWorker.h
TCPStreamService.o: TCPStreamService.cpp TCPStreamService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
../../../..//Common/UDP/UDPSProtocol.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
TCPSConn.h TCPSFrameQueue.h TCPSServiceStream.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamStringIOBuffer.h \
../../../..//Source/Components/Interfaces/UDPStream/UDPSTransportI.h \
TCPSWorker.h
TCPSWorker.o: TCPSWorker.cpp TCPSWorker.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ErrorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Architecture/x86_gcc/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TemplateParametersVerificator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitRange.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitBoolean.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/Threads.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ThreadsB.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/TypeCharacteristics.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L1Portability/ExceptionHandler.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CompilerTypes.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ProcessorType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BitSet.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/ExecutionInfo.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FastPollingMutexSem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/AtomicA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorInformation.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Architecture/x86_gcc/HighResolutionTimerA.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HighResolutionTimer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/HighResolutionTimerCalibrator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../GeneralDefinitions.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeStamp.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Sleep.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/SingleThreadService.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedServiceMethodBinderT.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThreadI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapManager.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItem.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/CString.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Introspection.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/IntrospectionEntry.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TypeDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/BasicType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/FractionalInteger.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/ZeroTerminatedArray.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/IteratorT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Iterator.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListable.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SortFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/SearchFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/LoadableLibrary.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StringHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectsDatabase.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/GlobalObjectI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/StandardHeap.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../../HeapI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Environment/Linux/../Generic/StandardHeap_Generic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticList.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StaticListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Matrix.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/Vector.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/MemoryOperationsHelper.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/CLASSREGISTER.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassRegistryItemT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ObjectBuilderT.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L0Types/LinkedListHolder.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Object.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/Reference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerFilter.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ReferenceContainerNode.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/TimeoutType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/StructuredDataI.h \
/home/martino/workspace/MARTe2/Source/Core/Scheduler/L3Services/EmbeddedThread.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/AdvancedErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/ClassProperties.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/ErrorManagement.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/StreamMemoryReference.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/BufferedStreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L2Objects/AnyType.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/FormatDescriptor.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/IOBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L3Streams/CharBuffer.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/StreamI.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/Atomic.h \
/home/martino/workspace/MARTe2/Source/Core/BareMetal/L1Portability/HighResolutionTimer.h \
TCPSConn.h TCPSFrameQueue.h TCPStreamService.h \
../../../..//Common/UDP/UDPSProtocol.h
@@ -1,7 +1,7 @@
#############################################################
# MARTe2 Integrated Components — UDPStream
#############################################################
OBJSX=UDPSServer.x UDPSClient.x
OBJSX=UDPSServer.x UDPSClient.x TCPSServer.x TCPSClient.x
PACKAGE=Components/Interfaces
@@ -0,0 +1,517 @@
/**
* @file TCPSClient.cpp
* @brief Implementation of TCPSClient — UDPS framing over TCP, consumer side.
*/
#include "TCPSClient.h"
#include "AdvancedErrorManagement.h"
#include "ErrorType.h"
#include "HighResolutionTimer.h"
#include "Sleep.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace MARTe {
const uint32 TCPSClient::TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S;
/** Longest single wait inside Execute(), so Stop() is prompt. */
static const int TCPS_CLIENT_SLICE_MS = 50;
/** Total time allowed for one connect() attempt. */
static const int TCPS_CLIENT_CONNECT_TIMEOUT_MS = 2000;
TCPSClient::TCPSClient()
: serverPort(0u), silenceTimeoutTicks(0u), reconnectDelayTicks(0u),
cpuMask(0xFFFFFFFFu), stackSize(65536u),
numStreams(1u), startRefs(0u), threadService(*this), fd(-1),
connected(false), stopping(false), lastDataTicks(0u), disconnectTick(0u),
connectionCount(0u), protocolErrors(0u), rxBuf(NULL_PTR(uint8 *)),
rxHave(0u), rxWant(UDPS_HEADER_SIZE), rxHeaderOk(false)
{
for (uint32 i = 0u; i < UDPS_TCP_MAX_STREAMS; i++) {
listeners[i] = NULL_PTR(UDPSClientListener *);
facades[i] = NULL_PTR(TCPSClientStream *);
lastDataCounter[i] = 0u;
lastDataCounterValid[i] = false;
lastDataGap[i] = 0u;
}
reconnectDelayTicks = static_cast<uint64>(TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S) *
HighResolutionTimer::Frequency();
}
TCPSClient::~TCPSClient() {
(void)Stop();
for (uint32 i = 0u; i < UDPS_TCP_MAX_STREAMS; i++) {
if (facades[i] != NULL_PTR(TCPSClientStream *)) {
delete facades[i];
facades[i] = NULL_PTR(TCPSClientStream *);
}
}
if (rxBuf != NULL_PTR(uint8 *)) {
delete[] rxBuf;
rxBuf = NULL_PTR(uint8 *);
}
}
bool TCPSClient::Initialise(StructuredDataI &data) {
bool ok = true;
if (!data.Read("ServerAddr", serverAddr) || (serverAddr.Size() == 0u)) {
serverAddr = "127.0.0.1";
}
if (!data.Read("Port", serverPort) || (serverPort == 0u) || (serverPort > 65535u)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSClient: a valid Port (1..65535) is required.");
ok = false;
}
streamName = "";
numStreams = 1u;
if (data.Read("StreamName", streamName)) {
ok = ParseStreamList();
}
float32 silence = 0.0f;
(void)data.Read("SilenceTimeout", silence);
if (silence < 0.0f) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSClient: SilenceTimeout must be >= 0.");
ok = false;
silence = 0.0f;
}
silenceTimeoutTicks = static_cast<uint64>(
static_cast<float64>(silence) * static_cast<float64>(HighResolutionTimer::Frequency()));
float32 delay = static_cast<float32>(TCPS_CLIENT_DEFAULT_RECONNECT_DELAY_S);
(void)data.Read("ReconnectDelay", delay);
if (delay < 0.0f) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSClient: ReconnectDelay must be >= 0.");
ok = false;
delay = 0.0f;
}
reconnectDelayTicks = static_cast<uint64>(
static_cast<float64>(delay) * static_cast<float64>(HighResolutionTimer::Frequency()));
(void)data.Read("CPUMask", cpuMask);
(void)data.Read("StackSize", stackSize);
return ok;
}
/** Validate streamName as "a" or "a,b,c" and set numStreams. */
bool TCPSClient::ParseStreamList() {
bool ok = (streamName.Size() <= UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD);
const char8 *s = streamName.Buffer();
uint32 n = 0u;
while (ok && (s != NULL_PTR(const char8 *)) && (streamName.Size() > 0u)) {
const char8 *comma = strchr(s, ',');
const uint32 len = (comma != NULL_PTR(const char8 *)) ? static_cast<uint32>(comma - s)
: static_cast<uint32>(strlen(s));
ok = (len > 0u) && (len <= 255u) && (n < UDPS_TCP_MAX_STREAMS);
// Duplicates would be refused by the server; catch them here.
const char8 *t = streamName.Buffer();
for (uint32 k = 0u; ok && (k < n); k++) {
const char8 *tc = strchr(t, ',');
const uint32 tl = (tc != NULL_PTR(const char8 *)) ? static_cast<uint32>(tc - t)
: static_cast<uint32>(strlen(t));
if ((tl == len) && (strncmp(t, s, len) == 0)) {
ok = false;
}
t = (tc != NULL_PTR(const char8 *)) ? (tc + 1) : t;
}
n++;
s = (comma != NULL_PTR(const char8 *)) ? (comma + 1) : NULL_PTR(const char8 *);
}
if (!ok) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSClient: StreamName must be 1..%u distinct names (1..255 chars each, "
"comma separated, %u bytes max).", UDPS_TCP_MAX_STREAMS,
UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD);
} else if (n > 0u) {
numStreams = n;
}
return ok;
}
void TCPSClient::SetListener(UDPSClientListener *newListener) {
listeners[0] = newListener;
}
void TCPSClient::SetStreamListener(uint32 index, UDPSClientListener *newListener) {
if (index < UDPS_TCP_MAX_STREAMS) {
listeners[index] = newListener;
}
}
uint32 TCPSClient::GetNumStreams() const {
return numStreams;
}
UDPSClientI *TCPSClient::GetStream(uint32 index) {
if (index >= numStreams) {
return NULL_PTR(UDPSClientI *);
}
if (facades[index] == NULL_PTR(TCPSClientStream *)) {
facades[index] = new TCPSClientStream(*this, index);
}
return facades[index];
}
uint32 TCPSClient::GetStreamDataGap(uint32 index) const {
return (index < UDPS_TCP_MAX_STREAMS) ? lastDataGap[index] : 0u;
}
bool TCPSClient::AcquireStart() {
bool ok = true;
refMutex.FastLock();
if (startRefs == 0u) {
ok = Start();
}
if (ok) {
startRefs++;
}
refMutex.FastUnLock();
return ok;
}
bool TCPSClient::ReleaseStop() {
bool ok = true;
refMutex.FastLock();
if (startRefs > 0u) {
startRefs--;
if (startRefs == 0u) {
ok = Stop();
}
}
refMutex.FastUnLock();
return ok;
}
TCPSClientStream::TCPSClientStream(TCPSClient &o, uint32 i) : owner(o), index(i), started(false) {
}
TCPSClientStream::~TCPSClientStream() {
(void)Stop();
}
bool TCPSClientStream::Initialise(StructuredDataI &data) {
(void)data;
return true;
}
void TCPSClientStream::SetListener(UDPSClientListener *newListener) {
owner.SetStreamListener(index, newListener);
}
bool TCPSClientStream::Start() {
bool ok = true;
if (!started) {
ok = owner.AcquireStart();
started = ok;
}
return ok;
}
bool TCPSClientStream::Stop() {
bool ok = true;
if (started) {
started = false;
ok = owner.ReleaseStop();
}
return ok;
}
uint32 TCPSClientStream::GetLastDataGap() const {
return owner.GetStreamDataGap(index);
}
bool TCPSClient::Start() {
if (rxBuf == NULL_PTR(uint8 *)) {
rxBuf = new uint8[UDPS_HEADER_SIZE + UDPSClient::UDPS_CLIENT_MAX_PACKET_BYTES];
}
stopping = false;
connectionCount = 0u;
disconnectTick = 0u;
threadService.SetCPUMask(cpuMask);
threadService.SetStackSize(stackSize);
ErrorManagement::ErrorType err = threadService.Start();
return (err == ErrorManagement::NoError);
}
bool TCPSClient::Stop() {
stopping = true;
ErrorManagement::ErrorType err = threadService.Stop();
Disconnect();
return (err == ErrorManagement::NoError);
}
bool TCPSClient::IsConnected() const {
return connected;
}
uint32 TCPSClient::GetLastDataGap() const {
return lastDataGap[0];
}
uint32 TCPSClient::GetConnectionCount() const {
return connectionCount;
}
uint32 TCPSClient::GetProtocolErrors() const {
return protocolErrors;
}
// ---------------------------------------------------------------------------
// Thread entry
// ---------------------------------------------------------------------------
ErrorManagement::ErrorType TCPSClient::Execute(ExecutionInfo &info) {
if (info.GetStage() == ExecutionInfo::TerminationStage) {
Disconnect();
return ErrorManagement::NoError;
}
if (info.GetStage() != ExecutionInfo::MainStage) {
return ErrorManagement::NoError;
}
if (!connected) {
const uint64 now = HighResolutionTimer::Counter();
if ((disconnectTick == 0u) || ((now - disconnectTick) >= reconnectDelayTicks)) {
if (!Connect()) {
disconnectTick = HighResolutionTimer::Counter();
}
} else {
Sleep::MSec(10u);
}
return ErrorManagement::NoError;
}
if (!ReceiveStep()) {
Disconnect();
return ErrorManagement::NoError;
}
if (silenceTimeoutTicks > 0u) {
const uint64 now = HighResolutionTimer::Counter();
if ((now > lastDataTicks) && ((now - lastDataTicks) >= silenceTimeoutTicks)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSClient: server silent; reconnecting.");
Disconnect();
}
}
return ErrorManagement::NoError;
}
// ---------------------------------------------------------------------------
// Connection management
// ---------------------------------------------------------------------------
bool TCPSClient::Connect() {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(static_cast<uint16>(serverPort));
if (inet_pton(AF_INET, serverAddr.Buffer(), &addr.sin_addr) != 1) {
struct addrinfo hints;
struct addrinfo *res = NULL_PTR(struct addrinfo *);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((getaddrinfo(serverAddr.Buffer(), NULL_PTR(const char8 *), &hints, &res) != 0) ||
(res == NULL_PTR(struct addrinfo *))) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSClient: cannot resolve '%s'.", serverAddr.Buffer());
return false;
}
addr.sin_addr = reinterpret_cast<struct sockaddr_in *>(res->ai_addr)->sin_addr;
freeaddrinfo(res);
}
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
return false;
}
int flags = fcntl(s, F_GETFL, 0);
if ((flags < 0) || (fcntl(s, F_SETFL, flags | O_NONBLOCK) != 0)) {
(void)close(s);
return false;
}
bool ok = true;
int r = connect(s, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
if ((r != 0) && (errno == EINPROGRESS)) {
ok = false;
for (int waited = 0; (waited < TCPS_CLIENT_CONNECT_TIMEOUT_MS) && !stopping;
waited += TCPS_CLIENT_SLICE_MS) {
struct pollfd p;
p.fd = s;
p.events = POLLOUT;
p.revents = 0;
int pr = poll(&p, 1, TCPS_CLIENT_SLICE_MS);
if (pr > 0) {
int soErr = 0;
socklen_t len = static_cast<socklen_t>(sizeof(soErr));
ok = (getsockopt(s, SOL_SOCKET, SO_ERROR, &soErr, &len) == 0) && (soErr == 0);
break;
}
if ((pr < 0) && (errno != EINTR)) {
break;
}
}
} else if (r != 0) {
ok = false;
}
if (!ok) {
(void)close(s);
return false;
}
if (streamName.Size() > 0u) {
// A few dozen bytes on a fresh socket: never blocks.
uint8 sub[UDPS_HEADER_SIZE + UDPS_TCP_MAX_SUBSCRIBE_PAYLOAD];
const uint32 n = static_cast<uint32>(streamName.Size());
UDPSBuildHeader(sub, UDPS_TYPE_SUBSCRIBE, 0u, 0u, 1u, n);
memcpy(&sub[UDPS_HEADER_SIZE], streamName.Buffer(), n);
if (send(s, sub, UDPS_HEADER_SIZE + n, MSG_NOSIGNAL) != static_cast<ssize_t>(UDPS_HEADER_SIZE + n)) {
(void)close(s);
return false;
}
}
fd = s;
rxHave = 0u;
rxWant = UDPS_HEADER_SIZE;
rxHeaderOk = false;
for (uint32 i = 0u; i < UDPS_TCP_MAX_STREAMS; i++) {
lastDataCounterValid[i] = false;
}
lastDataTicks = HighResolutionTimer::Counter();
connectionCount++;
connected = true;
for (uint32 i = 0u; i < numStreams; i++) {
if (listeners[i] != NULL_PTR(UDPSClientListener *)) {
listeners[i]->OnUDPSConnected();
}
}
return true;
}
void TCPSClient::Disconnect() {
const bool was = connected;
connected = false;
if (fd >= 0) {
(void)close(fd);
fd = -1;
}
rxHave = 0u;
rxWant = UDPS_HEADER_SIZE;
rxHeaderOk = false;
disconnectTick = HighResolutionTimer::Counter();
for (uint32 i = 0u; was && (i < numStreams); i++) {
if (listeners[i] != NULL_PTR(UDPSClientListener *)) {
listeners[i]->OnUDPSDisconnected();
}
}
}
// ---------------------------------------------------------------------------
// Frame reader
// ---------------------------------------------------------------------------
bool TCPSClient::ReceiveStep() {
struct pollfd p;
p.fd = fd;
p.events = POLLIN;
p.revents = 0;
int pr = poll(&p, 1, TCPS_CLIENT_SLICE_MS);
if (pr < 0) {
return (errno == EINTR);
}
if (pr == 0) {
return true;
}
ssize_t n = recv(fd, &rxBuf[rxHave], rxWant - rxHave, MSG_DONTWAIT);
if (n == 0) {
REPORT_ERROR_STATIC(ErrorManagement::Information,
"TCPSClient: server closed the connection.");
return false;
}
if (n < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) {
return true;
}
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSClient: recv failed: %s.", strerror(errno));
return false;
}
rxHave += static_cast<uint32>(n);
lastDataTicks = HighResolutionTimer::Counter();
if (!rxHeaderOk && (rxHave >= UDPS_HEADER_SIZE)) {
UDPSPacketHeader h;
memcpy(&h, rxBuf, UDPS_HEADER_SIZE);
if ((h.magic != UDPS_MAGIC) ||
(h.payloadBytes > UDPSClient::UDPS_CLIENT_MAX_PACKET_BYTES) ||
(h.totalFragments != 1u) || (h.fragmentIdx >= numStreams)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSClient: invalid frame header (magic 0x%x, %u payload bytes); reconnecting.",
h.magic, h.payloadBytes);
protocolErrors++;
return false;
}
rxHeaderOk = true;
rxWant = UDPS_HEADER_SIZE + h.payloadBytes;
}
if (rxHeaderOk && (rxHave == rxWant)) {
const bool ok = Dispatch();
rxHave = 0u;
rxWant = UDPS_HEADER_SIZE;
rxHeaderOk = false;
return ok;
}
return true;
}
bool TCPSClient::Dispatch() {
UDPSPacketHeader h;
memcpy(&h, rxBuf, UDPS_HEADER_SIZE);
const uint8 *payload = &rxBuf[UDPS_HEADER_SIZE];
const uint32 idx = h.fragmentIdx; // validated < numStreams
UDPSClientListener *listener = listeners[idx];
if (listener != NULL_PTR(UDPSClientListener *)) {
if (h.type == UDPS_TYPE_CONFIG) {
listener->OnUDPSConfig(payload, h.payloadBytes);
} else if (h.type == UDPS_TYPE_DATA) {
lastDataGap[idx] = 0u;
if (lastDataCounterValid[idx]) {
const int32 delta = static_cast<int32>(h.counter - lastDataCounter[idx]);
if (delta > 1) {
lastDataGap[idx] = static_cast<uint32>(delta) - 1u;
}
}
lastDataCounter[idx] = h.counter;
lastDataCounterValid[idx] = true;
listener->OnUDPSFragment(h.counter, rxWant, true);
listener->OnUDPSData(payload, h.payloadBytes);
} else {
// Unknown / client-to-server types are ignored (forward compatible).
}
}
return true;
}
} // namespace MARTe
@@ -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_
@@ -0,0 +1,606 @@
/**
* @file TCPSServer.cpp
* @brief Implementation of TCPSServer — UDPS framing over TCP.
*/
#include "TCPSServer.h"
#include "AdvancedErrorManagement.h"
#include "ErrorType.h"
#include "HighResolutionTimer.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace MARTe {
// Out-of-class definitions: the constants are passed by reference (gtest,
// error-report varargs templates), which odr-uses them.
const uint32 TCPSServer::TCPS_DEFAULT_PORT;
const uint32 TCPSServer::TCPS_DEFAULT_MAX_PAYLOAD;
const uint32 TCPSServer::TCPS_MAX_FRAME_PAYLOAD;
const uint32 TCPSServer::TCPS_DEFAULT_MAX_CLIENTS;
const uint32 TCPSServer::TCPS_MAX_CLIENTS_LIMIT;
const uint32 TCPSServer::TCPS_DEFAULT_QUEUE_DEPTH;
const uint32 TCPSServer::TCPS_QUEUE_DEPTH_LIMIT;
const uint32 TCPSServer::TCPS_DEFAULT_STALL_TIMEOUT_S;
// ---------------------------------------------------------------------------
// Per-client state
// ---------------------------------------------------------------------------
/** One queued frame (header + payload). The buffer is reused across frames. */
struct TCPSServer::Slot {
Slot() : buf(NULL_PTR(uint8 *)), cap(0u), len(0u), isConfig(false) {}
~Slot() {
if (buf != NULL_PTR(uint8 *)) {
delete[] buf;
}
}
uint8 *buf;
uint32 cap;
uint32 len;
bool isConfig;
};
/**
* Queue layout: slots[0..count) are pending in wire order; slots[count..cap)
* are free (their buffers are kept for reuse). When sent > 0, slots[0] is
* partially on the wire and must not be touched.
*
* Capacity: at most queueDepth DATA frames, one CONFIG that is on the wire
* and one CONFIG waiting behind it => queueDepth + 2.
*/
struct TCPSServer::Client {
Client() : fd(-1), slots(NULL_PTR(Slot *)), cap(0u), count(0u), sent(0u),
lastProgress(0u) {}
~Client() {
if (slots != NULL_PTR(Slot *)) {
delete[] slots;
}
if (fd >= 0) {
(void)close(fd);
}
}
int fd;
Slot *slots;
uint32 cap;
uint32 count;
uint32 sent; ///< bytes of slots[0] already written
uint64 lastProgress; ///< HRT ticks of the last byte written / queue-empty->non-empty
};
// ---------------------------------------------------------------------------
// Constructor / Destructor
// ---------------------------------------------------------------------------
TCPSServer::TCPSServer()
: port(TCPS_DEFAULT_PORT), boundPort(0u),
maxPayloadSize(TCPS_DEFAULT_MAX_PAYLOAD),
maxClients(TCPS_DEFAULT_MAX_CLIENTS),
queueDepth(TCPS_DEFAULT_QUEUE_DEPTH),
stallTimeoutS(TCPS_DEFAULT_STALL_TIMEOUT_S), sendBufferSize(0u),
listenFd(-1), started(false), clients(NULL_PTR(Client *)), numClients(0u),
cachedConfig(NULL_PTR(uint8 *)), cachedConfigSize(0u), configCounter(0u),
frameBuf(NULL_PTR(uint8 *)), frameCapacity(0u), frameSize(0u),
stallTicks(0u), totalDrops(0u), loggedDrops(0u), lastDropLogTicks(0u),
stallEvictions(0u) {
}
TCPSServer::~TCPSServer() {
(void)Stop();
}
// ---------------------------------------------------------------------------
// Initialise
// ---------------------------------------------------------------------------
bool TCPSServer::Initialise(StructuredDataI &data) {
bool ok = true;
port = TCPS_DEFAULT_PORT;
(void)data.Read("Port", port);
if (port > 65535u) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServer: Port %u out of range.", port);
ok = false;
}
maxPayloadSize = TCPS_DEFAULT_MAX_PAYLOAD;
(void)data.Read("MaxPayloadSize", maxPayloadSize);
if ((maxPayloadSize == 0u) || (maxPayloadSize > TCPS_MAX_FRAME_PAYLOAD)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServer: MaxPayloadSize %u must be in 1..%u.",
maxPayloadSize, TCPS_MAX_FRAME_PAYLOAD);
ok = false;
}
maxClients = TCPS_DEFAULT_MAX_CLIENTS;
(void)data.Read("MaxClients", maxClients);
if ((maxClients == 0u) || (maxClients > TCPS_MAX_CLIENTS_LIMIT)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServer: MaxClients %u must be in 1..%u.",
maxClients, TCPS_MAX_CLIENTS_LIMIT);
ok = false;
}
queueDepth = TCPS_DEFAULT_QUEUE_DEPTH;
(void)data.Read("ClientQueueDepth", queueDepth);
if ((queueDepth == 0u) || (queueDepth > TCPS_QUEUE_DEPTH_LIMIT)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServer: ClientQueueDepth %u must be in 1..%u.",
queueDepth, TCPS_QUEUE_DEPTH_LIMIT);
ok = false;
}
stallTimeoutS = TCPS_DEFAULT_STALL_TIMEOUT_S;
(void)data.Read("ClientStallTimeout", stallTimeoutS);
stallTicks = static_cast<uint64>(stallTimeoutS) * HighResolutionTimer::Frequency();
sendBufferSize = 0u;
(void)data.Read("SendBufferSize", sendBufferSize);
return ok;
}
// ---------------------------------------------------------------------------
// Start / Stop
// ---------------------------------------------------------------------------
bool TCPSServer::Start() {
if (started) {
return true;
}
int fd = socket(AF_INET, SOCK_STREAM, 0);
bool ok = (fd >= 0);
if (!ok) {
REPORT_ERROR_STATIC(ErrorManagement::FatalError,
"TCPSServer: socket() failed: %s.", strerror(errno));
}
if (ok) {
int one = 1;
(void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(static_cast<uint16>(port));
if (bind(fd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) != 0) {
REPORT_ERROR_STATIC(ErrorManagement::FatalError,
"TCPSServer: bind(%u) failed: %s.", port, strerror(errno));
ok = false;
}
}
if (ok && (listen(fd, 16) != 0)) {
REPORT_ERROR_STATIC(ErrorManagement::FatalError,
"TCPSServer: listen() failed: %s.", strerror(errno));
ok = false;
}
if (ok) {
int flags = fcntl(fd, F_GETFL, 0);
ok = (flags >= 0) && (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
}
if (ok) {
struct sockaddr_in addr;
socklen_t len = static_cast<socklen_t>(sizeof(addr));
memset(&addr, 0, sizeof(addr));
if (getsockname(fd, reinterpret_cast<struct sockaddr *>(&addr), &len) == 0) {
boundPort = ntohs(addr.sin_port);
} else {
boundPort = static_cast<uint16>(port);
}
}
if (ok) {
clients = new Client[maxClients];
listenFd = fd;
numClients = 0u;
started = true;
} else if (fd >= 0) {
(void)close(fd);
}
return ok;
}
bool TCPSServer::Stop() {
if (clients != NULL_PTR(Client *)) {
delete[] clients; // closes every client socket
clients = NULL_PTR(Client *);
}
numClients = 0u;
if (listenFd >= 0) {
(void)close(listenFd);
listenFd = -1;
}
if (cachedConfig != NULL_PTR(uint8 *)) {
delete[] cachedConfig;
cachedConfig = NULL_PTR(uint8 *);
}
cachedConfigSize = 0u;
if (frameBuf != NULL_PTR(uint8 *)) {
delete[] frameBuf;
frameBuf = NULL_PTR(uint8 *);
}
frameCapacity = 0u;
frameSize = 0u;
started = false;
return true;
}
// ---------------------------------------------------------------------------
// Frame building
// ---------------------------------------------------------------------------
bool TCPSServer::BuildFrame(uint8 type, uint32 counter, const uint8 *payload,
uint32 payloadSize) {
bool ok = (payloadSize <= TCPS_MAX_FRAME_PAYLOAD);
if (ok) {
uint32 need = UDPS_HEADER_SIZE + payloadSize;
if (frameCapacity < need) {
if (frameBuf != NULL_PTR(uint8 *)) {
delete[] frameBuf;
}
frameBuf = new uint8[need];
frameCapacity = need;
}
UDPSBuildHeader(frameBuf, type, counter, 0u, 1u, payloadSize);
if (payloadSize > 0u) {
memcpy(&frameBuf[UDPS_HEADER_SIZE], payload, payloadSize);
}
frameSize = need;
}
return ok;
}
// ---------------------------------------------------------------------------
// Queueing
// ---------------------------------------------------------------------------
bool TCPSServer::Enqueue(Client &c, bool isConfig, const uint8 *frame,
uint32 frameBytes) {
const uint32 firstFree = (c.sent > 0u) ? 1u : 0u; // slots below this are on the wire
if (isConfig) {
// Frames behind the one on the wire were encoded for the old layout.
while (c.count > firstFree) {
c.count--;
if (!c.slots[c.count].isConfig) {
totalDrops++;
}
}
} else {
uint32 dataCount = 0u;
for (uint32 i = 0u; i < c.count; i++) {
if (!c.slots[i].isConfig) {
dataCount++;
}
}
if (dataCount >= queueDepth) {
uint32 victim = c.count;
for (uint32 i = firstFree; (i < c.count) && (victim == c.count); i++) {
if (!c.slots[i].isConfig) {
victim = i;
}
}
if (victim == c.count) {
// Only the frame on the wire is queued: nothing may be discarded.
totalDrops++;
return false;
}
// Remove `victim`, keeping its buffer as the (new) free slot.
Slot tmp = c.slots[victim];
for (uint32 i = victim + 1u; i < c.count; i++) {
c.slots[i - 1u] = c.slots[i];
}
c.slots[c.count - 1u] = tmp;
// The array copies above moved raw pointers; make sure `tmp` going
// out of scope does not free the buffer.
tmp.buf = NULL_PTR(uint8 *);
c.count--;
totalDrops++;
}
}
if (c.count >= c.cap) {
// Cannot happen with the capacity argument above; refuse defensively.
totalDrops++;
return false;
}
Slot &s = c.slots[c.count];
if (s.cap < frameBytes) {
if (s.buf != NULL_PTR(uint8 *)) {
delete[] s.buf;
}
s.buf = new uint8[frameBytes];
s.cap = frameBytes;
}
memcpy(s.buf, frame, frameBytes);
s.len = frameBytes;
s.isConfig = isConfig;
if (c.count == 0u) {
c.sent = 0u;
c.lastProgress = HighResolutionTimer::Counter();
}
c.count++;
return true;
}
bool TCPSServer::Flush(Client &c) {
bool alive = true;
while (alive && (c.count > 0u)) {
Slot &s = c.slots[0];
ssize_t n = send(c.fd, &s.buf[c.sent], s.len - c.sent,
MSG_NOSIGNAL | MSG_DONTWAIT);
if (n > 0) {
c.sent += static_cast<uint32>(n);
c.lastProgress = HighResolutionTimer::Counter();
if (c.sent >= s.len) {
// Rotate the finished slot to the free area, keep its buffer.
Slot tmp = c.slots[0];
for (uint32 i = 1u; i < c.count; i++) {
c.slots[i - 1u] = c.slots[i];
}
c.slots[c.count - 1u] = tmp;
tmp.buf = NULL_PTR(uint8 *);
c.count--;
c.sent = 0u;
}
} else if ((n < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) {
break;
} else if ((n < 0) && (errno == EINTR)) {
continue;
} else {
alive = false;
}
}
return alive;
}
/** Detect a peer that closed (or sent garbage: clients never talk to us). */
bool TCPSServer::PeerAlive(Client &c) {
uint8 scratch[64];
bool alive = true;
for (;;) {
ssize_t n = recv(c.fd, scratch, sizeof(scratch), MSG_DONTWAIT);
if (n > 0) {
continue; // discard
}
if (n == 0) {
alive = false;
} else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
alive = true;
} else if (errno == EINTR) {
continue;
} else {
alive = false;
}
break;
}
return alive;
}
void TCPSServer::Evict(Client &c) {
if (c.fd >= 0) {
(void)close(c.fd);
c.fd = -1;
}
// Slots and their buffers are freed here: the slot may stay idle a long time.
if (c.slots != NULL_PTR(Slot *)) {
delete[] c.slots;
c.slots = NULL_PTR(Slot *);
}
c.cap = 0u;
c.count = 0u;
c.sent = 0u;
if (numClients > 0u) {
numClients--;
}
}
// ---------------------------------------------------------------------------
// Public operations
// ---------------------------------------------------------------------------
void TCPSServer::AcceptPending() {
for (;;) {
int fd = accept(listenFd, NULL_PTR(struct sockaddr *), NULL_PTR(socklen_t *));
if (fd < 0) {
break; // EAGAIN, or a transient error: retry next call
}
Client *slot = NULL_PTR(Client *);
for (uint32 i = 0u; (i < maxClients) && (slot == NULL_PTR(Client *)); i++) {
if (clients[i].fd < 0) {
slot = &clients[i];
}
}
if (slot == NULL_PTR(Client *)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSServer: MaxClients (%u) reached; connection refused.",
maxClients);
(void)close(fd);
continue;
}
int flags = fcntl(fd, F_GETFL, 0);
if ((flags < 0) || (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0)) {
(void)close(fd);
continue;
}
int one = 1;
(void)setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
if (sendBufferSize > 0u) {
int sz = static_cast<int>(sendBufferSize);
(void)setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sz, sizeof(sz));
}
slot->fd = fd;
slot->cap = queueDepth + 2u;
slot->slots = new Slot[slot->cap];
slot->count = 0u;
slot->sent = 0u;
slot->lastProgress = HighResolutionTimer::Counter();
numClients++;
// CONFIG first, so a client always decodes DATA against a CONFIG.
if (cachedConfig != NULL_PTR(uint8 *)) {
if (BuildFrame(UDPS_TYPE_CONFIG, configCounter, cachedConfig, cachedConfigSize)) {
(void)Enqueue(*slot, true, frameBuf, frameSize);
if (!Flush(*slot)) {
Evict(*slot);
}
}
}
}
}
void TCPSServer::ServiceClients() {
if (!started) {
return;
}
AcceptPending();
for (uint32 i = 0u; i < maxClients; i++) {
Client &c = clients[i];
if (c.fd < 0) {
continue;
}
if (!PeerAlive(c) || !Flush(c)) {
Evict(c);
continue;
}
// Read the clock after Flush(): it stamps lastProgress itself.
const uint64 now = HighResolutionTimer::Counter();
if ((stallTicks > 0u) && (c.count > 0u) && (now > c.lastProgress) &&
((now - c.lastProgress) > stallTicks)) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSServer: client stalled for more than %u s; disconnecting.",
stallTimeoutS);
stallEvictions++;
Evict(c);
}
}
ReportDrops();
}
bool TCPSServer::CacheConfig(const uint8 *payload, uint32 payloadSize) {
if (cachedConfig != NULL_PTR(uint8 *)) {
delete[] cachedConfig;
cachedConfig = NULL_PTR(uint8 *);
cachedConfigSize = 0u;
}
if (payloadSize > 0u) {
cachedConfig = new uint8[payloadSize];
memcpy(cachedConfig, payload, payloadSize);
cachedConfigSize = payloadSize;
}
return true;
}
bool TCPSServer::SendConfig(const uint8 *payload, uint32 payloadSize) {
if (!started) {
return false;
}
if (payloadSize > TCPS_MAX_FRAME_PAYLOAD) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServer: CONFIG of %u bytes exceeds the frame limit.",
payloadSize);
return false;
}
(void)CacheConfig(payload, payloadSize);
configCounter++;
if ((numClients == 0u) || !BuildFrame(UDPS_TYPE_CONFIG, configCounter, payload, payloadSize)) {
return true;
}
for (uint32 i = 0u; i < maxClients; i++) {
Client &c = clients[i];
if (c.fd < 0) {
continue;
}
(void)Enqueue(c, true, frameBuf, frameSize);
if (!Flush(c)) {
Evict(c);
}
}
return true;
}
bool TCPSServer::SendData(uint32 counter, const uint8 *payload, uint32 payloadSize) {
if (!started) {
return false;
}
if (numClients == 0u) {
return true;
}
if (!BuildFrame(UDPS_TYPE_DATA, counter, payload, payloadSize)) {
REPORT_ERROR_STATIC(ErrorManagement::ParametersError,
"TCPSServer: DATA of %u bytes exceeds the frame limit.",
payloadSize);
return false;
}
for (uint32 i = 0u; i < maxClients; i++) {
Client &c = clients[i];
if (c.fd < 0) {
continue;
}
(void)Enqueue(c, false, frameBuf, frameSize);
if (!Flush(c)) {
Evict(c);
}
}
return true;
}
/** Report queue drops at most once per second. */
void TCPSServer::ReportDrops() {
if (totalDrops != loggedDrops) {
const uint64 now = HighResolutionTimer::Counter();
if ((now - lastDropLogTicks) >= HighResolutionTimer::Frequency()) {
REPORT_ERROR_STATIC(ErrorManagement::Warning,
"TCPSServer: %u DATA frame(s) dropped for slow client(s) (total %u).",
static_cast<uint32>(totalDrops - loggedDrops),
static_cast<uint32>(totalDrops));
loggedDrops = totalDrops;
lastDropLogTicks = now;
}
}
}
bool TCPSServer::HasClients() const {
return numClients > 0u;
}
bool TCPSServer::IsMulticast() const {
return false;
}
uint16 TCPSServer::GetPort() const {
return started ? boundPort : static_cast<uint16>(port);
}
uint32 TCPSServer::GetClientCount() const {
return numClients;
}
uint64 TCPSServer::GetClientDrops() const {
return totalDrops;
}
uint32 TCPSServer::GetStallEvictions() const {
return stallEvictions;
}
uint32 TCPSServer::GetMaxPayloadSize() const {
return maxPayloadSize;
}
} // namespace MARTe
@@ -0,0 +1,160 @@
#ifndef TCPS_SERVER_H_
#define TCPS_SERVER_H_
/**
* @file TCPSServer.h
* @brief TCP transport for the UDPS wire format (producer side).
*
* TCPSServer carries the normal UDPS framing (17-byte header + CONFIG / DATA
* payload, totalFragments always 1) over TCP byte streams. It implements
* UDPSServerI so UDPStreamer can publish through it unchanged.
*
* Threading model: NOT thread-safe, exactly like UDPSServer. Every call must
* come from the owner's sender thread. There is no thread per client: sockets
* are non-blocking and everything is driven from ServiceClients() / SendData().
*
* Slow consumers: every client owns a bounded queue of ClientQueueDepth DATA
* frames. When it is full the oldest queued DATA frame that is not already
* (partially) on the wire is discarded and counted; other clients and the
* producer are never affected. A client that makes no progress for
* ClientStallTimeout seconds with data queued is disconnected.
*
* Ordering: a client always sees CONFIG before any DATA. A CONFIG is never
* dropped. When a new CONFIG is published, the frames queued behind the one
* currently on the wire are stale (encoded for the old layout) and are
* discarded, so DATA is never decoded against the wrong CONFIG.
*/
#include "StructuredDataI.h"
#include "UDPSProtocol.h"
#include "UDPSTransportI.h"
namespace MARTe {
class TCPSServer : public UDPSServerI {
public:
/** Default TCP listen port. */
static const uint32 TCPS_DEFAULT_PORT = 44500u;
/** Default maximum payload bytes per frame. */
static const uint32 TCPS_DEFAULT_MAX_PAYLOAD = 60000u;
/** Hard ceiling on a frame payload (matches UDPSClient's packet limit). */
static const uint32 TCPS_MAX_FRAME_PAYLOAD = 1048576u;
/** Default simultaneous clients. */
static const uint32 TCPS_DEFAULT_MAX_CLIENTS = 16u;
/** Upper bound accepted for MaxClients. */
static const uint32 TCPS_MAX_CLIENTS_LIMIT = 1024u;
/** Default DATA frames queued per client. */
static const uint32 TCPS_DEFAULT_QUEUE_DEPTH = 8u;
/** Upper bound accepted for ClientQueueDepth. */
static const uint32 TCPS_QUEUE_DEPTH_LIMIT = 4096u;
/** Default stall timeout (seconds); 0 disables. */
static const uint32 TCPS_DEFAULT_STALL_TIMEOUT_S = 5u;
TCPSServer();
virtual ~TCPSServer();
/**
* @brief Read configuration.
*
* Keys (all optional):
* - Port (uint32) TCP listen port, default 44500. 0 picks an
* ephemeral port (see GetPort() after Start()).
* - MaxPayloadSize (uint32) 1..1 MiB, default 60000. Sizes Accumulate
* batches in the owner; frames larger than 1 MiB are
* refused by SendData().
* - MaxClients (uint32) 1..1024, default 16. Extra connections
* are accepted and closed immediately.
* - ClientQueueDepth (uint32) 1..4096, default 8.
* - ClientStallTimeout (uint32) Seconds, default 5; 0 disables.
* - SendBufferSize (uint32) SO_SNDBUF for client sockets; 0 (default)
* keeps the OS default.
*/
virtual bool Initialise(StructuredDataI &data);
/** Open the listening socket (idempotent). */
virtual bool Start();
/** Close every socket and free all buffers (idempotent). */
virtual bool Stop();
/**
* Accept new clients, drop closed ones, flush queues, evict stalled
* clients. Never blocks.
*/
virtual void ServiceClients();
/**
* Cache the CONFIG and queue it on every connected client. New clients
* receive the cached CONFIG on accept.
*/
virtual bool SendConfig(const uint8 *payload, uint32 payloadSize);
/**
* Queue a DATA frame on every connected client and try to flush.
* @return false only if the frame is larger than TCPS_MAX_FRAME_PAYLOAD.
*/
virtual bool SendData(uint32 counter, const uint8 *payload, uint32 payloadSize);
virtual bool HasClients() const;
virtual bool IsMulticast() const;
/** @return the bound port once started, otherwise the configured port. */
virtual uint16 GetPort() const;
/** @return number of connected clients. */
uint32 GetClientCount() const;
/** @return DATA frames discarded (all clients, all time) because a client queue was full. */
uint64 GetClientDrops() const;
/** @return clients disconnected by the stall timeout (all time). */
uint32 GetStallEvictions() const;
uint32 GetMaxPayloadSize() const;
private:
struct Slot;
struct Client;
bool CacheConfig(const uint8 *payload, uint32 payloadSize);
void AcceptPending();
bool Enqueue(Client &c, bool isConfig, const uint8 *frame, uint32 frameSize);
bool Flush(Client &c);
bool PeerAlive(Client &c);
void Evict(Client &c);
bool BuildFrame(uint8 type, uint32 counter, const uint8 *payload, uint32 payloadSize);
void ReportDrops();
uint32 port;
uint16 boundPort;
uint32 maxPayloadSize;
uint32 maxClients;
uint32 queueDepth;
uint32 stallTimeoutS;
uint32 sendBufferSize;
int listenFd;
bool started;
Client *clients;
uint32 numClients;
uint8 *cachedConfig;
uint32 cachedConfigSize;
uint32 configCounter;
uint8 *frameBuf; ///< scratch: header + payload built once per call
uint32 frameCapacity;
uint32 frameSize;
uint64 stallTicks;
uint64 totalDrops;
uint64 loggedDrops;
uint64 lastDropLogTicks;
uint32 stallEvictions;
};
} // namespace MARTe
#endif // TCPS_SERVER_H_
@@ -27,6 +27,7 @@
#include "StreamString.h"
#include "StructuredDataI.h"
#include "UDPSProtocol.h"
#include "UDPSTransportI.h"
namespace MARTe {
@@ -72,7 +73,7 @@ public:
/**
* @brief UDPS receiver client with auto-reconnect and fragment reassembly.
*/
class UDPSClient : public EmbeddedServiceMethodBinderI {
class UDPSClient : public UDPSClientI, public EmbeddedServiceMethodBinderI {
public:
/** Maximum number of concurrent in-flight reassembly slots. */
@@ -23,6 +23,7 @@
#include "StreamString.h"
#include "StructuredDataI.h"
#include "UDPSProtocol.h"
#include "UDPSTransportI.h"
namespace MARTe {
@@ -43,7 +44,7 @@ namespace MARTe {
* server.Stop(); // in StopCurrentStateExecution()
* @endcode
*/
class UDPSServer {
class UDPSServer : public UDPSServerI {
public:
/** Maximum number of simultaneous unicast clients. */
@@ -0,0 +1,71 @@
#ifndef UDPS_TRANSPORT_I_H_
#define UDPS_TRANSPORT_I_H_
/**
* @file UDPSTransportI.h
* @brief Abstract transport seams used by the UDPStreamer / UDPStreamerClient
* DataSources.
*
* The DataSources only ever touch their transport through these few calls, so
* a different transport (TCP) can be plugged in without duplicating the
* serialisation, quantisation, publishing and decode logic.
*/
#include "CompilerTypes.h"
#include "StructuredDataI.h"
namespace MARTe {
class UDPSClientListener;
/**
* @brief Producer-side transport. NOT thread-safe: every call must come from
* the owner's sender thread.
*/
class UDPSServerI {
public:
virtual ~UDPSServerI() {}
/** Read the transport configuration. */
virtual bool Initialise(StructuredDataI &data) = 0;
/** Open sockets and start accepting clients (idempotent). */
virtual bool Start() = 0;
/** Close everything (idempotent). */
virtual bool Stop() = 0;
/** Non-blocking housekeeping: accept/evict clients, drain queues. */
virtual void ServiceClients() = 0;
/** Publish (and cache) a CONFIG payload. */
virtual bool SendConfig(const uint8 *payload, uint32 payloadSize) = 0;
/** Publish a DATA payload. */
virtual bool SendData(uint32 counter, const uint8 *payload, uint32 payloadSize) = 0;
/** @return true when at least one client is attached. */
virtual bool HasClients() const = 0;
/** @return true when the transport uses multicast. */
virtual bool IsMulticast() const = 0;
/** @return the (bound) port. */
virtual uint16 GetPort() const = 0;
};
/**
* @brief Consumer-side transport. Delivers through UDPSClientListener.
*/
class UDPSClientI {
public:
virtual ~UDPSClientI() {}
virtual bool Initialise(StructuredDataI &data) = 0;
/** Must be called before Start(). */
virtual void SetListener(UDPSClientListener *listener) = 0;
virtual bool Start() = 0;
virtual bool Stop() = 0;
/**
* @return Packets missing between the previous DATA packet and the one
* being delivered (valid inside OnUDPSData). 0 when the transport does
* not track it.
*/
virtual uint32 GetLastDataGap() const { return 0u; }
};
} // namespace MARTe
#endif // UDPS_TRANSPORT_I_H_