2021-03-21 00:30:33 +01:00
|
|
|
#include "UdpTcPollingTask.h"
|
2021-03-12 02:15:21 +01:00
|
|
|
#include "tcpipHelpers.h"
|
2021-05-12 16:47:53 +02:00
|
|
|
#include "../../platform.h"
|
2020-09-06 15:46:49 +02:00
|
|
|
#include "../../globalfunctions/arrayprinter.h"
|
2021-06-05 19:52:38 +02:00
|
|
|
#include "../../serviceinterface/ServiceInterface.h"
|
|
|
|
#include "../../objectmanager/ObjectManager.h"
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-05-12 16:47:53 +02:00
|
|
|
#ifdef PLATFORM_WIN
|
2020-09-06 15:46:49 +02:00
|
|
|
#include <winsock2.h>
|
2021-05-12 16:47:53 +02:00
|
|
|
#elif defined(PLATFORM_UNIX)
|
2021-03-21 12:51:28 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
|
2021-03-15 13:06:13 +01:00
|
|
|
//! Debugging preprocessor define.
|
2021-04-11 14:54:02 +02:00
|
|
|
#define FSFW_UDP_RECV_WIRETAPPING_ENABLED 0
|
2021-03-15 13:06:13 +01:00
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
UdpTcPollingTask::UdpTcPollingTask(object_id_t objectId,
|
2021-05-05 12:59:42 +02:00
|
|
|
object_id_t tmtcUdpBridge, size_t maxRecvSize,
|
2021-03-21 13:02:14 +01:00
|
|
|
double timeoutSeconds): SystemObject(objectId),
|
2021-05-05 12:59:42 +02:00
|
|
|
tmtcBridgeId(tmtcUdpBridge) {
|
2021-03-21 13:02:14 +01:00
|
|
|
if(frameSize > 0) {
|
|
|
|
this->frameSize = frameSize;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->frameSize = DEFAULT_MAX_RECV_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up reception buffer with specified frame size.
|
2021-03-08 23:00:53 +01:00
|
|
|
For now, it is assumed that only one frame is held in the buffer! */
|
2021-03-21 13:02:14 +01:00
|
|
|
receptionBuffer.reserve(this->frameSize);
|
|
|
|
receptionBuffer.resize(this->frameSize);
|
|
|
|
|
|
|
|
if(timeoutSeconds == -1) {
|
|
|
|
receptionTimeout = DEFAULT_TIMEOUT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
|
|
|
|
}
|
2020-09-06 15:46:49 +02:00
|
|
|
}
|
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
UdpTcPollingTask::~UdpTcPollingTask() {}
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
ReturnValue_t UdpTcPollingTask::performOperation(uint8_t opCode) {
|
2021-03-12 02:15:21 +01:00
|
|
|
/* Sender Address is cached here. */
|
2021-03-21 12:51:28 +01:00
|
|
|
struct sockaddr senderAddress;
|
|
|
|
socklen_t senderAddressSize = sizeof(senderAddress);
|
2021-03-12 02:15:21 +01:00
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
/* Poll for new UDP datagrams in permanent loop. */
|
|
|
|
while(true) {
|
|
|
|
int bytesReceived = recvfrom(
|
|
|
|
this->serverSocket,
|
|
|
|
reinterpret_cast<char*>(receptionBuffer.data()),
|
|
|
|
frameSize,
|
|
|
|
receptionFlags,
|
|
|
|
&senderAddress,
|
|
|
|
&senderAddressSize
|
|
|
|
);
|
|
|
|
if(bytesReceived == SOCKET_ERROR) {
|
|
|
|
/* Handle error */
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::error << "UdpTcPollingTask::performOperation: Reception error." << std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2021-03-21 13:02:14 +01:00
|
|
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
|
|
|
|
continue;
|
|
|
|
}
|
2021-04-11 14:54:02 +02:00
|
|
|
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::debug << "UdpTcPollingTask::performOperation: " << bytesReceived <<
|
|
|
|
" bytes received" << std::endl;
|
2021-04-11 14:54:02 +02:00
|
|
|
#else
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2021-04-11 14:54:02 +02:00
|
|
|
#endif /* FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1 */
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
}
|
|
|
|
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
|
|
|
}
|
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2020-09-06 15:46:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
ReturnValue_t UdpTcPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
2021-03-21 13:02:14 +01:00
|
|
|
store_address_t storeId;
|
2021-03-12 02:15:21 +01:00
|
|
|
|
2021-04-11 14:54:02 +02:00
|
|
|
#if FSFW_UDP_RECV_WIRETAPPING_ENABLED == 1
|
2021-03-12 02:15:21 +01:00
|
|
|
arrayprinter::print(receptionBuffer.data(), bytesRead);
|
2021-03-08 23:00:53 +01:00
|
|
|
#endif
|
2021-03-12 02:15:21 +01:00
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
|
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
2021-03-12 02:15:21 +01:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::warning<< "UdpTcPollingTask::transferPusToSoftwareBus: Data storage failed." <<
|
|
|
|
std::endl;
|
|
|
|
sif::warning << "Packet size: " << bytesRead << std::endl;
|
2021-03-12 02:15:21 +01:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2021-03-21 13:02:14 +01:00
|
|
|
return HasReturnvaluesIF::RETURN_FAILED;
|
|
|
|
}
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
TmTcMessage message(storeId);
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
|
|
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
2021-03-12 02:15:21 +01:00
|
|
|
#if FSFW_VERBOSE_LEVEL >= 1
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::warning << "UdpTcPollingTask::handleSuccessfullTcRead: "
|
|
|
|
" Sending message to queue failed" << std::endl;
|
2021-03-12 02:15:21 +01:00
|
|
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
|
|
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
2021-03-21 13:02:14 +01:00
|
|
|
tcStore->deleteData(storeId);
|
|
|
|
}
|
|
|
|
return result;
|
2020-09-06 15:46:49 +02:00
|
|
|
}
|
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
ReturnValue_t UdpTcPollingTask::initialize() {
|
2021-06-05 19:52:38 +02:00
|
|
|
tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
2021-03-21 13:02:14 +01:00
|
|
|
if (tcStore == nullptr) {
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::error << "UdpTcPollingTask::initialize: TC store uninitialized!" << std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2021-03-21 13:02:14 +01:00
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
}
|
2020-09-06 15:46:49 +02:00
|
|
|
|
2021-06-05 19:52:38 +02:00
|
|
|
tmtcBridge = ObjectManager::instance()->get<UdpTmTcBridge>(tmtcBridgeId);
|
2021-03-21 13:02:14 +01:00
|
|
|
if(tmtcBridge == nullptr) {
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::error << "UdpTcPollingTask::initialize: Invalid TMTC bridge object!" <<
|
|
|
|
std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2021-03-21 13:02:14 +01:00
|
|
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
|
|
|
}
|
2021-03-21 00:30:33 +01:00
|
|
|
|
|
|
|
ReturnValue_t result = TcpIpBase::initialize();
|
|
|
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-21 13:02:14 +01:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2020-09-06 15:46:49 +02:00
|
|
|
}
|
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
ReturnValue_t UdpTcPollingTask::initializeAfterTaskCreation() {
|
2021-03-21 13:02:14 +01:00
|
|
|
/* Initialize the destination after task creation. This ensures
|
2021-03-12 00:45:32 +01:00
|
|
|
that the destination has already been set in the TMTC bridge. */
|
2021-03-21 13:02:14 +01:00
|
|
|
targetTcDestination = tmtcBridge->getRequestQueue();
|
|
|
|
/* The server socket is set up in the bridge intialization. Calling this function here
|
2021-03-21 00:30:33 +01:00
|
|
|
ensures that it is set up regardless of which class was initialized first */
|
2021-03-21 12:51:28 +01:00
|
|
|
this->serverSocket = tmtcBridge->serverSocket;
|
2021-03-21 13:02:14 +01:00
|
|
|
return HasReturnvaluesIF::RETURN_OK;
|
2020-09-06 15:46:49 +02:00
|
|
|
}
|
|
|
|
|
2021-03-21 00:30:33 +01:00
|
|
|
void UdpTcPollingTask::setTimeout(double timeoutSeconds) {
|
2021-05-12 16:47:53 +02:00
|
|
|
#ifdef PLATFORM_WIN
|
2021-03-21 13:02:14 +01:00
|
|
|
DWORD timeoutMs = timeoutSeconds * 1000.0;
|
2021-03-21 14:38:28 +01:00
|
|
|
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
|
2021-03-21 13:02:14 +01:00
|
|
|
reinterpret_cast<const char*>(&timeoutMs), sizeof(DWORD));
|
|
|
|
if(result == -1) {
|
2021-01-03 14:16:52 +01:00
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
2021-03-21 13:02:14 +01:00
|
|
|
sif::error << "TcWinUdpPollingTask::TcSocketPollingTask: Setting "
|
|
|
|
"receive timeout failed with " << strerror(errno) << std::endl;
|
2021-01-03 13:58:18 +01:00
|
|
|
#endif
|
2021-03-21 13:02:14 +01:00
|
|
|
}
|
2021-05-12 16:47:53 +02:00
|
|
|
#elif defined(PLATFORM_UNIX)
|
2021-03-21 13:02:14 +01:00
|
|
|
timeval tval;
|
|
|
|
tval = timevalOperations::toTimeval(timeoutSeconds);
|
|
|
|
int result = setsockopt(serverSocket, SOL_SOCKET, SO_RCVTIMEO,
|
|
|
|
&tval, sizeof(receptionTimeout));
|
|
|
|
if(result == -1) {
|
|
|
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
|
|
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
|
|
|
|
"receive timeout failed with " << strerror(errno) << std::endl;
|
|
|
|
#endif
|
|
|
|
}
|
2021-03-21 00:30:33 +01:00
|
|
|
#endif
|
2020-09-06 15:46:49 +02:00
|
|
|
}
|