Files
MARTe-Integrated-Components/Source/Components/DataSources/TCPStreamerClient/TCPStreamerClient.cpp
T
Martino FerrariandClaude Opus 4.6 50d85363a3 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>
2026-11-06 13:41:27 +01:00

123 lines
4.3 KiB
C++

/**
* @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 */