Merge pull request 'TCP/IP module updates for Linux and Windows' (#387) from mueller/tcpip-updates into development
Reviewed-on: fsfw/fsfw#387
This commit is contained in:
commit
b757c5523c
@ -32,3 +32,5 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(common)
|
3
osal/common/CMakeLists.txt
Normal file
3
osal/common/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
tcpipCommon.cpp
|
||||||
|
)
|
36
osal/common/tcpipCommon.cpp
Normal file
36
osal/common/tcpipCommon.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "tcpipCommon.h"
|
||||||
|
|
||||||
|
void tcpip::determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string &protStr,
|
||||||
|
std::string &srcString) {
|
||||||
|
if(protocol == Protocol::TCP) {
|
||||||
|
protStr = "TCP";
|
||||||
|
}
|
||||||
|
else if(protocol == Protocol::UDP) {
|
||||||
|
protStr = "UDP";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
protStr = "Unknown protocol";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(errorSrc == ErrorSources::SETSOCKOPT_CALL) {
|
||||||
|
srcString = "setsockopt call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::SOCKET_CALL) {
|
||||||
|
srcString = "socket call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::LISTEN_CALL) {
|
||||||
|
srcString = "listen call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::ACCEPT_CALL) {
|
||||||
|
srcString = "accept call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::RECVFROM_CALL) {
|
||||||
|
srcString = "recvfrom call";
|
||||||
|
}
|
||||||
|
else if(errorSrc == ErrorSources::GETADDRINFO_CALL) {
|
||||||
|
srcString = "getaddrinfo call";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
srcString = "unknown call";
|
||||||
|
}
|
||||||
|
}
|
36
osal/common/tcpipCommon.h
Normal file
36
osal/common/tcpipCommon.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef FSFW_OSAL_COMMON_TCPIPCOMMON_H_
|
||||||
|
#define FSFW_OSAL_COMMON_TCPIPCOMMON_H_
|
||||||
|
|
||||||
|
#include "../../timemanager/clockDefinitions.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace tcpip {
|
||||||
|
|
||||||
|
const char* const DEFAULT_UDP_SERVER_PORT = "7301";
|
||||||
|
const char* const DEFAULT_TCP_SERVER_PORT = "7303";
|
||||||
|
|
||||||
|
enum class Protocol {
|
||||||
|
UDP,
|
||||||
|
TCP
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ErrorSources {
|
||||||
|
GETADDRINFO_CALL,
|
||||||
|
SOCKET_CALL,
|
||||||
|
SETSOCKOPT_CALL,
|
||||||
|
BIND_CALL,
|
||||||
|
RECV_CALL,
|
||||||
|
RECVFROM_CALL,
|
||||||
|
LISTEN_CALL,
|
||||||
|
ACCEPT_CALL,
|
||||||
|
SENDTO_CALL
|
||||||
|
};
|
||||||
|
|
||||||
|
void determineErrorStrings(Protocol protocol, ErrorSources errorSrc, std::string& protStr,
|
||||||
|
std::string& srcString);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_COMMON_TCPIPCOMMON_H_ */
|
@ -24,5 +24,7 @@ MutexIF* MutexFactory::createMutex() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MutexFactory::deleteMutex(MutexIF* mutex) {
|
void MutexFactory::deleteMutex(MutexIF* mutex) {
|
||||||
delete mutex;
|
if(mutex != nullptr) {
|
||||||
|
delete mutex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ target_sources(${LIB_FSFW_NAME}
|
|||||||
TcUnixUdpPollingTask.cpp
|
TcUnixUdpPollingTask.cpp
|
||||||
TmTcUnixUdpBridge.cpp
|
TmTcUnixUdpBridge.cpp
|
||||||
Timer.cpp
|
Timer.cpp
|
||||||
|
tcpipHelpers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#include "TcUnixUdpPollingTask.h"
|
#include "TcUnixUdpPollingTask.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
|
|
||||||
#include "../../globalfunctions/arrayprinter.h"
|
#include "../../globalfunctions/arrayprinter.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#define FSFW_UDP_RCV_WIRETAPPING_ENABLED 0
|
||||||
|
|
||||||
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
|
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
|
||||||
object_id_t tmtcUnixUdpBridge, size_t frameSize,
|
object_id_t tmtcUnixUdpBridge, size_t frameSize,
|
||||||
@ -15,8 +17,8 @@ TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
|
|||||||
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
|
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up reception buffer with specified frame size.
|
/* Set up reception buffer with specified frame size.
|
||||||
// For now, it is assumed that only one frame is held in the buffer!
|
For now, it is assumed that only one frame is held in the buffer! */
|
||||||
receptionBuffer.reserve(this->frameSize);
|
receptionBuffer.reserve(this->frameSize);
|
||||||
receptionBuffer.resize(this->frameSize);
|
receptionBuffer.resize(this->frameSize);
|
||||||
|
|
||||||
@ -31,34 +33,37 @@ TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
|
|||||||
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
|
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
|
||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
|
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
|
||||||
// Poll for new UDP datagrams in permanent loop.
|
/* Sender Address is cached here. */
|
||||||
while(1) {
|
struct sockaddr_in senderAddress;
|
||||||
//! Sender Address is cached here.
|
socklen_t senderAddressSize = sizeof(senderAddress);
|
||||||
struct sockaddr_in senderAddress;
|
|
||||||
socklen_t senderSockLen = sizeof(senderAddress);
|
|
||||||
ssize_t bytesReceived = recvfrom(serverUdpSocket,
|
|
||||||
receptionBuffer.data(), frameSize, receptionFlags,
|
|
||||||
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
|
|
||||||
if(bytesReceived < 0) {
|
|
||||||
// handle error
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcSocketPollingTask::performOperation: Reception"
|
|
||||||
"error." << std::endl;
|
|
||||||
#endif
|
|
||||||
handleReadError();
|
|
||||||
|
|
||||||
|
/* Poll for new UDP datagrams in permanent loop. */
|
||||||
|
while(true) {
|
||||||
|
ssize_t bytesReceived = recvfrom(
|
||||||
|
serverUdpSocket,
|
||||||
|
receptionBuffer.data(),
|
||||||
|
frameSize,
|
||||||
|
receptionFlags,
|
||||||
|
reinterpret_cast<sockaddr*>(&senderAddress),
|
||||||
|
&senderAddressSize
|
||||||
|
);
|
||||||
|
if(bytesReceived < 0) {
|
||||||
|
/* Handle error */
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TcSocketPollingTask::performOperation: Reception error." << std::endl;
|
||||||
|
#endif
|
||||||
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 500);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
|
sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
|
||||||
// << " bytes received" << std::endl;
|
<< " bytes received" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
|
||||||
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||||
|
|
||||||
}
|
}
|
||||||
tmtcBridge->registerCommConnect();
|
|
||||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
@ -67,15 +72,21 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
|
|||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
ReturnValue_t result = tcStore->addData(&storeId,
|
|
||||||
receptionBuffer.data(), bytesRead);
|
#if FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
// arrayprinter::print(receptionBuffer.data(), bytesRead);
|
arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
|
sif::error << "TcUnixUdpPollingTask::handleSuccessfullTcRead: Data "
|
||||||
"storage failed" << std::endl;
|
"storage failed" << std::endl;
|
||||||
sif::error << "Packet size: " << bytesRead << std::endl;
|
sif::error << "Packet size: " << bytesRead << std::endl;
|
||||||
#endif
|
#else
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,10 +94,13 @@ ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
|||||||
|
|
||||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "Serial Polling: Sending message to queue failed"
|
sif::error << "TcUnixUdpPollingTask::handleSuccessfullTcRead: Sending message to queue "
|
||||||
<< std::endl;
|
"failed" << std::endl;
|
||||||
#endif
|
#else
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
tcStore->deleteData(storeId);
|
tcStore->deleteData(storeId);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -111,15 +125,16 @@ ReturnValue_t TcUnixUdpPollingTask::initialize() {
|
|||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverUdpSocket = tmtcBridge->serverSocket;
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
|
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
|
||||||
// Initialize the destination after task creation. This ensures
|
/* Initialize the destination after task creation. This ensures
|
||||||
// that the destination will be set in the TMTC bridge.
|
that the destination has already been set in the TMTC bridge. */
|
||||||
targetTcDestination = tmtcBridge->getRequestQueue();
|
targetTcDestination = tmtcBridge->getRequestQueue();
|
||||||
|
/* The server socket is set up in the bridge intialization. Calling this function here
|
||||||
|
ensures that it is set up properly in any case*/
|
||||||
|
serverUdpSocket = tmtcBridge->serverSocket;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,24 +150,3 @@ void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: sleep after error detection to prevent spam
|
|
||||||
void TcUnixUdpPollingTask::handleReadError() {
|
|
||||||
switch(errno) {
|
|
||||||
case(EAGAIN): {
|
|
||||||
// todo: When working in timeout mode, this will occur more often
|
|
||||||
// and is not an error.
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TcUnixUdpPollingTask::handleReadError: "
|
|
||||||
<< strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -48,6 +48,7 @@ private:
|
|||||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||||
TmTcUnixUdpBridge* tmtcBridge = nullptr;
|
TmTcUnixUdpBridge* tmtcBridge = nullptr;
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
|
|
||||||
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
||||||
int receptionFlags = 0;
|
int receptionFlags = 0;
|
||||||
|
|
||||||
@ -61,7 +62,6 @@ private:
|
|||||||
timeval receptionTimeout;
|
timeval receptionTimeout;
|
||||||
|
|
||||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||||
void handleReadError();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
||||||
|
@ -1,206 +1,169 @@
|
|||||||
#include "TmTcUnixUdpBridge.h"
|
#include "TmTcUnixUdpBridge.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
#include "../../serviceinterface/ServiceInterface.h"
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
#include "../../ipc/MutexGuard.h"
|
#include "../../ipc/MutexGuard.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
|
//! Debugging preprocessor define.
|
||||||
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
|
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
|
||||||
uint16_t serverPort, uint16_t clientPort):
|
|
||||||
|
const std::string TmTcUnixUdpBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_UDP_SERVER_PORT;
|
||||||
|
|
||||||
|
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
|
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort):
|
||||||
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
if(udpServerPort == "") {
|
||||||
|
this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->udpServerPort = udpServerPort;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
if(serverPort != 0xFFFF) {
|
communicationLinkUp = false;
|
||||||
setServerPort = serverPort;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
|
ReturnValue_t TmTcUnixUdpBridge::initialize() {
|
||||||
if(clientPort != 0xFFFF) {
|
using namespace tcpip;
|
||||||
setClientPort = clientPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
|
ReturnValue_t result = TmTcBridge::initialize();
|
||||||
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
||||||
if(serverSocket < 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
|
sif::error << "TmTcUnixUdpBridge::initialize: TmTcBridge initialization failed!"
|
||||||
" UDP socket!" << std::endl;
|
<< std::endl;
|
||||||
#endif
|
#endif
|
||||||
handleSocketError();
|
return result;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
serverAddress.sin_family = AF_INET;
|
struct addrinfo *addrResult = nullptr;
|
||||||
|
struct addrinfo hints;
|
||||||
|
|
||||||
// Accept packets from any interface.
|
std::memset(&hints, 0, sizeof(hints));
|
||||||
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
|
hints.ai_family = AF_INET;
|
||||||
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
serverAddress.sin_port = htons(setServerPort);
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
serverAddressLen = sizeof(serverAddress);
|
hints.ai_flags = AI_PASSIVE;
|
||||||
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
|
|
||||||
sizeof(serverSocketOptions));
|
|
||||||
|
|
||||||
clientAddress.sin_family = AF_INET;
|
/* Set up UDP socket:
|
||||||
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
https://man7.org/linux/man-pages/man3/getaddrinfo.3.html
|
||||||
clientAddress.sin_port = htons(setClientPort);
|
Passing nullptr as the first parameter and specifying AI_PASSIVE in hints will cause
|
||||||
clientAddressLen = sizeof(clientAddress);
|
getaddrinfo to assign the address 0.0.0.0 (any address) */
|
||||||
|
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
|
||||||
int result = bind(serverSocket,
|
if (retval != 0) {
|
||||||
reinterpret_cast<struct sockaddr*>(&serverAddress),
|
|
||||||
serverAddressLen);
|
|
||||||
if(result == -1) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
|
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Retrieving address info failed!" <<
|
||||||
"local port " << setServerPort << " to server socket!"
|
std::endl;
|
||||||
<< std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
handleBindError();
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
/* Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html */
|
||||||
|
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
|
||||||
|
if(serverSocket < 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open UDP socket!" <<
|
||||||
|
std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open UDP socket!\n");
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
handleError(Protocol::UDP, ErrorSources::SOCKET_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||||
|
if(retval != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
||||||
|
"local port (" << udpServerPort << ") to server socket!" << std::endl;
|
||||||
|
#endif
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
handleError(Protocol::UDP, ErrorSources::BIND_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
|
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
|
||||||
|
if(mutex != nullptr) {
|
||||||
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
|
}
|
||||||
|
close(serverSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
MutexGuard lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||||
|
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
|
||||||
if(ipAddrAnySet){
|
if(ipAddrAnySet){
|
||||||
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
||||||
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
|
clientAddressLen = sizeof(clientAddress);
|
||||||
clientAddressLen = sizeof(serverAddress);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// char ipAddress [15];
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
char ipAddress [15];
|
||||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
sif::debug << "IP Address Sender: "<<
|
||||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
inet_ntop(AF_INET,&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
|
ssize_t bytesSent = sendto(
|
||||||
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
|
serverSocket,
|
||||||
if(bytesSent < 0) {
|
data,
|
||||||
|
dataLen,
|
||||||
|
flags,
|
||||||
|
reinterpret_cast<sockaddr*>(&clientAddress),
|
||||||
|
clientAddressLen
|
||||||
|
);
|
||||||
|
if(bytesSent < 0) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
|
sif::warning << "TmTcUnixUdpBridge::sendTm: Send operation failed." << std::endl;
|
||||||
<< std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
handleSendError();
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
|
||||||
}
|
}
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
// " sent." << std::endl;
|
sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||||
|
" sent." << std::endl;
|
||||||
#endif
|
#endif
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
|
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
|
||||||
MutexGuard lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||||
|
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
|
||||||
// char ipAddress [15];
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
char ipAddress [15];
|
||||||
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
|
||||||
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
&newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
|
||||||
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
registerCommConnect();
|
||||||
|
|
||||||
// Set new IP address if it has changed.
|
/* Set new IP address if it has changed. */
|
||||||
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
||||||
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
|
clientAddress = newAddress;
|
||||||
clientAddressLen = sizeof(clientAddress);
|
clientAddressLen = sizeof(clientAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TmTcUnixUdpBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
|
||||||
void TmTcUnixUdpBridge::handleSocketError() {
|
dur_millis_t timeoutMs) {
|
||||||
// See: https://man7.org/linux/man-pages/man2/socket.2.html
|
this->timeoutType = timeoutType;
|
||||||
switch(errno) {
|
this->mutexTimeoutMs = timeoutMs;
|
||||||
case(EACCES):
|
|
||||||
case(EINVAL):
|
|
||||||
case(EMFILE):
|
|
||||||
case(ENFILE):
|
|
||||||
case(EAFNOSUPPORT):
|
|
||||||
case(ENOBUFS):
|
|
||||||
case(ENOMEM):
|
|
||||||
case(EPROTONOSUPPORT):
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
|
|
||||||
<< " with " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::handleBindError() {
|
|
||||||
// See: https://man7.org/linux/man-pages/man2/bind.2.html
|
|
||||||
switch(errno) {
|
|
||||||
case(EACCES): {
|
|
||||||
/*
|
|
||||||
Ephermeral ports can be shown with following command:
|
|
||||||
sysctl -A | grep ip_local_port_range
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
|
|
||||||
"Ports 1-1024 are reserved on UNIX systems and require root "
|
|
||||||
"rights while ephermeral ports should not be used as well."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case(EADDRINUSE):
|
|
||||||
case(EBADF):
|
|
||||||
case(EINVAL):
|
|
||||||
case(ENOTSOCK):
|
|
||||||
case(EADDRNOTAVAIL):
|
|
||||||
case(EFAULT):
|
|
||||||
case(ELOOP):
|
|
||||||
case(ENAMETOOLONG):
|
|
||||||
case(ENOENT):
|
|
||||||
case(ENOMEM):
|
|
||||||
case(ENOTDIR):
|
|
||||||
case(EROFS): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
|
|
||||||
<< " with " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::handleSendError() {
|
|
||||||
switch(errno) {
|
|
||||||
default: {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::error << "TmTcUnixBridge::handleSendError: "
|
|
||||||
<< strerror(errno) << std::endl;
|
|
||||||
#else
|
|
||||||
sif::printError("TmTcUnixBridge::handleSendError: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
|
void TmTcUnixUdpBridge::setClientAddressToAny(bool ipAddrAnySet){
|
||||||
this->ipAddrAnySet = ipAddrAnySet;
|
this->ipAddrAnySet = ipAddrAnySet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,45 +7,47 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
class TmTcUnixUdpBridge: public TmTcBridge {
|
class TmTcUnixUdpBridge:
|
||||||
friend class TcUnixUdpPollingTask;
|
public TmTcBridge {
|
||||||
|
friend class TcUnixUdpPollingTask;
|
||||||
public:
|
public:
|
||||||
// The ports chosen here should not be used by any other process.
|
|
||||||
// List of used ports on Linux: /etc/services
|
|
||||||
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
|
|
||||||
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
|
|
||||||
|
|
||||||
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
/* The ports chosen here should not be used by any other process.
|
||||||
object_id_t tmStoreId, object_id_t tcStoreId,
|
List of used ports on Linux: /etc/services */
|
||||||
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
|
static const std::string DEFAULT_UDP_SERVER_PORT;
|
||||||
virtual~ TmTcUnixUdpBridge();
|
|
||||||
|
|
||||||
void checkAndSetClientAddress(sockaddr_in& clientAddress);
|
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
|
object_id_t tmStoreId, object_id_t tcStoreId,
|
||||||
|
std::string serverPort = "");
|
||||||
|
virtual~ TmTcUnixUdpBridge();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set properties of internal mutex.
|
||||||
|
*/
|
||||||
|
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
|
void checkAndSetClientAddress(sockaddr_in& clientAddress);
|
||||||
|
|
||||||
|
void setClientAddressToAny(bool ipAddrAnySet);
|
||||||
|
|
||||||
void setClientAddressToAny(bool ipAddrAnySet);
|
|
||||||
protected:
|
protected:
|
||||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int serverSocket = 0;
|
int serverSocket = 0;
|
||||||
|
std::string udpServerPort;
|
||||||
|
|
||||||
const int serverSocketOptions = 0;
|
struct sockaddr_in clientAddress;
|
||||||
|
socklen_t clientAddressLen = 0;
|
||||||
|
|
||||||
struct sockaddr_in clientAddress;
|
bool ipAddrAnySet = false;
|
||||||
socklen_t clientAddressLen = 0;
|
|
||||||
|
|
||||||
struct sockaddr_in serverAddress;
|
//! Access to the client address is mutex protected as it is set by another task.
|
||||||
socklen_t serverAddressLen = 0;
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
|
dur_millis_t mutexTimeoutMs = 20;
|
||||||
bool ipAddrAnySet = false;
|
MutexIF* mutex;
|
||||||
|
|
||||||
//! Access to the client address is mutex protected as it is set
|
|
||||||
//! by another task.
|
|
||||||
MutexIF* mutex;
|
|
||||||
|
|
||||||
void handleSocketError();
|
|
||||||
void handleBindError();
|
|
||||||
void handleSendError();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */
|
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */
|
||||||
|
108
osal/linux/tcpipHelpers.cpp
Normal file
108
osal/linux/tcpipHelpers.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "tcpipHelpers.h"
|
||||||
|
|
||||||
|
#include "../../tasks/TaskFactory.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
|
||||||
|
int errCode = errno;
|
||||||
|
std::string protocolString;
|
||||||
|
std::string errorSrcString;
|
||||||
|
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
|
||||||
|
std::string infoString;
|
||||||
|
switch(errCode) {
|
||||||
|
case(EACCES): {
|
||||||
|
infoString = "EACCES";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EINVAL): {
|
||||||
|
infoString = "EINVAL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EAGAIN): {
|
||||||
|
infoString = "EAGAIN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EMFILE): {
|
||||||
|
infoString = "EMFILE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENFILE): {
|
||||||
|
infoString = "ENFILE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EAFNOSUPPORT): {
|
||||||
|
infoString = "EAFNOSUPPORT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOBUFS): {
|
||||||
|
infoString = "ENOBUFS";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOMEM): {
|
||||||
|
infoString = "ENOMEM";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EPROTONOSUPPORT): {
|
||||||
|
infoString = "EPROTONOSUPPORT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EADDRINUSE): {
|
||||||
|
infoString = "EADDRINUSE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EBADF): {
|
||||||
|
infoString = "EBADF";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOTSOCK): {
|
||||||
|
infoString = "ENOTSOCK";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EADDRNOTAVAIL): {
|
||||||
|
infoString = "EADDRNOTAVAIL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EFAULT): {
|
||||||
|
infoString = "EFAULT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ELOOP): {
|
||||||
|
infoString = "ELOOP";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENAMETOOLONG): {
|
||||||
|
infoString = "ENAMETOOLONG";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOENT): {
|
||||||
|
infoString = "ENOENT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(ENOTDIR): {
|
||||||
|
infoString = "ENOTDIR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(EROFS): {
|
||||||
|
infoString = "EROFS";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
infoString = "Error code: " + std::to_string(errCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
|
||||||
|
" | " << infoString << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString,
|
||||||
|
errorSrcString, infoString);
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
|
if(sleepDuration > 0) {
|
||||||
|
TaskFactory::instance()->delayTask(sleepDuration);
|
||||||
|
}
|
||||||
|
}
|
14
osal/linux/tcpipHelpers.h
Normal file
14
osal/linux/tcpipHelpers.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef FSFW_OSAL_LINUX_TCPIPHELPERS_H_
|
||||||
|
#define FSFW_OSAL_LINUX_TCPIPHELPERS_H_
|
||||||
|
|
||||||
|
#include "../../timemanager/clockDefinitions.h"
|
||||||
|
#include "../common/tcpipCommon.h"
|
||||||
|
|
||||||
|
namespace tcpip {
|
||||||
|
|
||||||
|
|
||||||
|
void handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration = 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_LINUX_TCPIPHELPERS_H_ */
|
@ -1,6 +1,8 @@
|
|||||||
target_sources(${LIB_FSFW_NAME} PRIVATE
|
target_sources(${LIB_FSFW_NAME} PRIVATE
|
||||||
TcWinUdpPollingTask.cpp
|
TcWinUdpPollingTask.cpp
|
||||||
TmTcWinUdpBridge.cpp
|
TmTcWinUdpBridge.cpp
|
||||||
|
TcWinTcpServer.cpp
|
||||||
|
tcpipHelpers.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
target_link_libraries(${LIB_FSFW_NAME} PRIVATE
|
||||||
|
129
osal/windows/TcWinTcpServer.cpp
Normal file
129
osal/windows/TcWinTcpServer.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include "TcWinTcpServer.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
const std::string TcWinTcpServer::DEFAULT_TCP_SERVER_PORT = "7301";
|
||||||
|
const std::string TcWinTcpServer::DEFAULT_TCP_CLIENT_PORT = "7302";
|
||||||
|
|
||||||
|
TcWinTcpServer::TcWinTcpServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||||
|
std::string customTcpServerPort):
|
||||||
|
SystemObject(objectId), tcpPort(customTcpServerPort) {
|
||||||
|
if(tcpPort == "") {
|
||||||
|
tcpPort = DEFAULT_TCP_SERVER_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcWinTcpServer::initialize() {
|
||||||
|
using namespace tcpip;
|
||||||
|
int retval = 0;
|
||||||
|
struct addrinfo *addrResult = nullptr;
|
||||||
|
struct addrinfo hints;
|
||||||
|
/* Initiates Winsock DLL. */
|
||||||
|
WSAData wsaData;
|
||||||
|
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||||
|
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
|
if (err != 0) {
|
||||||
|
/* Tell the user that we could not find a usable Winsock DLL. */
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
|
||||||
|
err << std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&hints, sizeof (hints));
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
|
retval = getaddrinfo(nullptr, tcpPort.c_str(), &hints, &addrResult);
|
||||||
|
if (retval != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TcWinTcpServer::TcWinTcpServer: Retrieving address info failed!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
handleError(Protocol::TCP, ErrorSources::GETADDRINFO_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open TCP (stream) socket */
|
||||||
|
listenerTcpSocket = socket(addrResult->ai_family, addrResult->ai_socktype,
|
||||||
|
addrResult->ai_protocol);
|
||||||
|
if(listenerTcpSocket == INVALID_SOCKET) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TcWinTcpServer::TcWinTcpServer: Socket creation failed!" << std::endl;
|
||||||
|
#endif
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
handleError(Protocol::TCP, ErrorSources::SOCKET_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||||
|
if(retval == SOCKET_ERROR) {
|
||||||
|
sif::warning << "TcWinTcpServer::TcWinTcpServer: Binding socket failed!" <<
|
||||||
|
std::endl;
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
handleError(Protocol::TCP, ErrorSources::BIND_CALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TcWinTcpServer::~TcWinTcpServer() {
|
||||||
|
closesocket(listenerTcpSocket);
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TcWinTcpServer::performOperation(uint8_t opCode) {
|
||||||
|
using namespace tcpip;
|
||||||
|
/* If a connection is accepted, the corresponding socket will be assigned to the new socket */
|
||||||
|
SOCKET clientSocket;
|
||||||
|
sockaddr_in clientSockAddr;
|
||||||
|
int connectorSockAddrLen = 0;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
/* Listen for connection requests permanently for lifetime of program */
|
||||||
|
while(true) {
|
||||||
|
retval = listen(listenerTcpSocket, currentBacklog);
|
||||||
|
if(retval == SOCKET_ERROR) {
|
||||||
|
handleError(Protocol::TCP, ErrorSources::LISTEN_CALL, 500);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSocket = accept(listenerTcpSocket, reinterpret_cast<sockaddr*>(&clientSockAddr),
|
||||||
|
&connectorSockAddrLen);
|
||||||
|
|
||||||
|
if(clientSocket == INVALID_SOCKET) {
|
||||||
|
handleError(Protocol::TCP, ErrorSources::ACCEPT_CALL, 500);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
retval = recv(clientSocket, reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
|
receptionBuffer.size(), 0);
|
||||||
|
if(retval > 0) {
|
||||||
|
#if FSFW_TCP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
|
sif::info << "TcWinTcpServer::performOperation: Received " << retval << " bytes."
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
handleError(Protocol::TCP, ErrorSources::RECV_CALL, 500);
|
||||||
|
}
|
||||||
|
else if(retval == 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Done, shut down connection */
|
||||||
|
retval = shutdown(clientSocket, SD_SEND);
|
||||||
|
}
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
47
osal/windows/TcWinTcpServer.h
Normal file
47
osal/windows/TcWinTcpServer.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_
|
||||||
|
|
||||||
|
#include "../../objectmanager/SystemObject.h"
|
||||||
|
#include "../../tasks/ExecutableObjectIF.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
//! Debugging preprocessor define.
|
||||||
|
#define FSFW_TCP_RCV_WIRETAPPING_ENABLED 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Windows TCP server used to receive telecommands on a Windows Host
|
||||||
|
* @details
|
||||||
|
* Based on: https://docs.microsoft.com/en-us/windows/win32/winsock/complete-server-code
|
||||||
|
*/
|
||||||
|
class TcWinTcpServer:
|
||||||
|
public SystemObject,
|
||||||
|
public ExecutableObjectIF {
|
||||||
|
public:
|
||||||
|
/* The ports chosen here should not be used by any other process. */
|
||||||
|
static const std::string DEFAULT_TCP_SERVER_PORT;
|
||||||
|
static const std::string DEFAULT_TCP_CLIENT_PORT;
|
||||||
|
|
||||||
|
TcWinTcpServer(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
|
||||||
|
std::string customTcpServerPort = "");
|
||||||
|
virtual~ TcWinTcpServer();
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string tcpPort;
|
||||||
|
SOCKET listenerTcpSocket = 0;
|
||||||
|
struct sockaddr_in tcpAddress;
|
||||||
|
int tcpAddrLen = sizeof(tcpAddress);
|
||||||
|
int currentBacklog = 3;
|
||||||
|
|
||||||
|
std::vector<uint8_t> receptionBuffer;
|
||||||
|
int tcpSockOpt = 0;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_WINDOWS_TCWINTCPSERVER_H_ */
|
@ -1,4 +1,5 @@
|
|||||||
#include "TcWinUdpPollingTask.h"
|
#include "TcWinUdpPollingTask.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
#include "../../globalfunctions/arrayprinter.h"
|
#include "../../globalfunctions/arrayprinter.h"
|
||||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
|
|
||||||
@ -31,25 +32,29 @@ TcWinUdpPollingTask::TcWinUdpPollingTask(object_id_t objectId,
|
|||||||
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
|
TcWinUdpPollingTask::~TcWinUdpPollingTask() {}
|
||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
||||||
|
/* Sender Address is cached here. */
|
||||||
|
struct sockaddr_in senderAddress;
|
||||||
|
int senderAddressSize = sizeof(senderAddress);
|
||||||
|
|
||||||
/* Poll for new UDP datagrams in permanent loop. */
|
/* Poll for new UDP datagrams in permanent loop. */
|
||||||
while(true) {
|
while(true) {
|
||||||
//! Sender Address is cached here.
|
int bytesReceived = recvfrom(
|
||||||
struct sockaddr_in senderAddress;
|
serverUdpSocket,
|
||||||
int senderAddressSize = sizeof(senderAddress);
|
reinterpret_cast<char*>(receptionBuffer.data()),
|
||||||
int bytesReceived = recvfrom(serverUdpSocket,
|
frameSize,
|
||||||
reinterpret_cast<char*>(receptionBuffer.data()), frameSize,
|
receptionFlags,
|
||||||
receptionFlags, reinterpret_cast<sockaddr*>(&senderAddress),
|
reinterpret_cast<sockaddr*>(&senderAddress),
|
||||||
&senderAddressSize);
|
&senderAddressSize
|
||||||
|
);
|
||||||
if(bytesReceived == SOCKET_ERROR) {
|
if(bytesReceived == SOCKET_ERROR) {
|
||||||
/* Handle error */
|
/* Handle error */
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TcWinUdpPollingTask::performOperation: Reception"
|
sif::error << "TcWinUdpPollingTask::performOperation: Reception error." << std::endl;
|
||||||
" error." << std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
handleReadError();
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::RECVFROM_CALL, 1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_WIRETAPPING_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived <<
|
sif::debug << "TcWinUdpPollingTask::performOperation: " << bytesReceived <<
|
||||||
" bytes received" << std::endl;
|
" bytes received" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -58,7 +63,6 @@ ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
|||||||
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
if(result != HasReturnvaluesIF::RETURN_FAILED) {
|
||||||
|
|
||||||
}
|
}
|
||||||
tmtcBridge->registerCommConnect();
|
|
||||||
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
tmtcBridge->checkAndSetClientAddress(senderAddress);
|
||||||
}
|
}
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
@ -67,17 +71,20 @@ ReturnValue_t TcWinUdpPollingTask::performOperation(uint8_t opCode) {
|
|||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
||||||
store_address_t storeId;
|
store_address_t storeId;
|
||||||
ReturnValue_t result = tcStore->addData(&storeId,
|
|
||||||
receptionBuffer.data(), bytesRead);
|
#if FSFW_UDP_RCV_WIRETAPPING_ENABLED == 1
|
||||||
#if FSFW_UDP_WIRETAPPING_ENABLED == 1
|
arrayprinter::print(receptionBuffer.data(), bytesRead);
|
||||||
arrayprinter::print(receptionBuffer.data(), bytesRead);#
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning<< "TcSerialPollingTask::transferPusToSoftwareBus: Data "
|
sif::warning<< "TcWinUdpPollingTask::transferPusToSoftwareBus: Data storage failed." <<
|
||||||
"storage failed" << std::endl;
|
std::endl;
|
||||||
sif::warning << "Packet size: " << bytesRead << std::endl;
|
sif::warning << "Packet size: " << bytesRead << std::endl;
|
||||||
#endif
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
return HasReturnvaluesIF::RETURN_FAILED;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,9 +92,12 @@ ReturnValue_t TcWinUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
|
|||||||
|
|
||||||
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
|
||||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "Serial Polling: Sending message to queue failed" << std::endl;
|
sif::warning << "TcWinUdpPollingTask::handleSuccessfullTcRead: "
|
||||||
#endif
|
" Sending message to queue failed" << std::endl;
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
tcStore->deleteData(storeId);
|
tcStore->deleteData(storeId);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -97,8 +107,7 @@ ReturnValue_t TcWinUdpPollingTask::initialize() {
|
|||||||
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
|
||||||
if (tcStore == nullptr) {
|
if (tcStore == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
|
sif::error << "TcWinUdpPollingTask::initialize: TC store uninitialized!" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
}
|
}
|
||||||
@ -106,25 +115,21 @@ ReturnValue_t TcWinUdpPollingTask::initialize() {
|
|||||||
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
|
tmtcBridge = objectManager->get<TmTcWinUdpBridge>(tmtcBridgeId);
|
||||||
if(tmtcBridge == nullptr) {
|
if(tmtcBridge == nullptr) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
|
sif::error << "TcWinUdpPollingTask::initialize: Invalid TMTC bridge object!" <<
|
||||||
" TMTC bridge object!" << std::endl;
|
std::endl;
|
||||||
#endif
|
#endif
|
||||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverUdpSocket = tmtcBridge->serverSocket;
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_WIRETAPPING_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::initialize: Server UDP socket " << serverUdpSocket <<
|
|
||||||
std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
|
ReturnValue_t TcWinUdpPollingTask::initializeAfterTaskCreation() {
|
||||||
// Initialize the destination after task creation. This ensures
|
/* Initialize the destination after task creation. This ensures
|
||||||
// that the destination has already been set in the TMTC bridge.
|
that the destination has already been set in the TMTC bridge. */
|
||||||
targetTcDestination = tmtcBridge->getRequestQueue();
|
targetTcDestination = tmtcBridge->getRequestQueue();
|
||||||
|
/* The server socket is set up in the bridge intialization. Calling this function here
|
||||||
|
ensures that it is set up properly in any case*/
|
||||||
|
serverUdpSocket = tmtcBridge->serverSocket;
|
||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,39 +144,3 @@ void TcWinUdpPollingTask::setTimeout(double timeoutSeconds) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TcWinUdpPollingTask::handleReadError() {
|
|
||||||
int error = WSAGetLastError();
|
|
||||||
switch(error) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup(...) call " << "necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEFAULT): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: WSADEFAULT: "
|
|
||||||
<< "Bad address " << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEINVAL): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: WSAEINVAL: "
|
|
||||||
<< "Invalid input parameters. " << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TcWinUdpPollingTask::handleReadError: Error code: "
|
|
||||||
<< error << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// to prevent spam.
|
|
||||||
Sleep(1000);
|
|
||||||
}
|
|
||||||
|
@ -51,10 +51,12 @@ private:
|
|||||||
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
object_id_t tmtcBridgeId = objects::NO_OBJECT;
|
||||||
TmTcWinUdpBridge* tmtcBridge = nullptr;
|
TmTcWinUdpBridge* tmtcBridge = nullptr;
|
||||||
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
|
||||||
//! Reception flags: https://linux.die.net/man/2/recvfrom.
|
|
||||||
|
//! See: https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recvfrom
|
||||||
int receptionFlags = 0;
|
int receptionFlags = 0;
|
||||||
|
|
||||||
//! Server socket, which is member of TMTC bridge and is assigned in constructor
|
//! Server socket, which is member of TMTC bridge.
|
||||||
|
//! Will be cached shortly after SW intialization.
|
||||||
SOCKET serverUdpSocket = 0;
|
SOCKET serverUdpSocket = 0;
|
||||||
|
|
||||||
std::vector<uint8_t> receptionBuffer;
|
std::vector<uint8_t> receptionBuffer;
|
||||||
@ -63,7 +65,6 @@ private:
|
|||||||
timeval receptionTimeout;
|
timeval receptionTimeout;
|
||||||
|
|
||||||
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
|
||||||
void handleReadError();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */
|
||||||
|
@ -1,18 +1,38 @@
|
|||||||
#include "TmTcWinUdpBridge.h"
|
#include "TmTcWinUdpBridge.h"
|
||||||
|
#include "tcpipHelpers.h"
|
||||||
|
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterface.h>
|
||||||
#include <fsfw/ipc/MutexGuard.h>
|
#include <fsfw/ipc/MutexGuard.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
//! Debugging preprocessor define.
|
||||||
#include <BaseTsd.h>
|
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
|
||||||
typedef SSIZE_T ssize_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
|
const std::string TmTcWinUdpBridge::DEFAULT_UDP_SERVER_PORT = tcpip::DEFAULT_UDP_SERVER_PORT;
|
||||||
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
|
|
||||||
uint16_t serverPort, uint16_t clientPort):
|
TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
|
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort):
|
||||||
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
|
||||||
|
if(udpServerPort == "") {
|
||||||
|
this->udpServerPort = DEFAULT_UDP_SERVER_PORT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->udpServerPort = udpServerPort;
|
||||||
|
}
|
||||||
|
|
||||||
mutex = MutexFactory::instance()->createMutex();
|
mutex = MutexFactory::instance()->createMutex();
|
||||||
communicationLinkUp = false;
|
communicationLinkUp = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TmTcWinUdpBridge::initialize() {
|
||||||
|
ReturnValue_t result = TmTcBridge::initialize();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::error << "TmTcWinUdpBridge::initialize: TmTcBridge initialization failed!"
|
||||||
|
<< std::endl;
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initiates Winsock DLL. */
|
/* Initiates Winsock DLL. */
|
||||||
WSAData wsaData;
|
WSAData wsaData;
|
||||||
@ -22,71 +42,65 @@ TmTcWinUdpBridge::TmTcWinUdpBridge(object_id_t objectId,
|
|||||||
/* Tell the user that we could not find a usable */
|
/* Tell the user that we could not find a usable */
|
||||||
/* Winsock DLL. */
|
/* Winsock DLL. */
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge:"
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: " <<
|
||||||
"WSAStartup failed with error: " << err << std::endl;
|
err << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printError("TmTcWinUdpBridge::TmTcWinUdpBridge: WSAStartup failed with error: %d\n",
|
||||||
|
err);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
|
struct addrinfo *addrResult = nullptr;
|
||||||
if(serverPort != 0xFFFF) {
|
struct addrinfo hints;
|
||||||
setServerPort = serverPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
|
ZeroMemory(&hints, sizeof (hints));
|
||||||
if(clientPort != 0xFFFF) {
|
hints.ai_family = AF_INET;
|
||||||
setClientPort = clientPort;
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
}
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
/* Set up UDP socket:
|
/* Set up UDP socket:
|
||||||
https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
|
https://en.wikipedia.org/wiki/Getaddrinfo
|
||||||
*/
|
Passing nullptr as the first parameter and specifying AI_PASSIVE in hints will cause
|
||||||
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
getaddrinfo to assign the address 0.0.0.0 (any address) */
|
||||||
|
int retval = getaddrinfo(nullptr, udpServerPort.c_str(), &hints, &addrResult);
|
||||||
|
if (retval != 0) {
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Retrieving address info failed!" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverSocket = socket(addrResult->ai_family, addrResult->ai_socktype, addrResult->ai_protocol);
|
||||||
if(serverSocket == INVALID_SOCKET) {
|
if(serverSocket == INVALID_SOCKET) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open UDP socket!" <<
|
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not open UDP socket!" <<
|
||||||
std::endl;
|
std::endl;
|
||||||
#endif
|
#endif
|
||||||
handleSocketError();
|
freeaddrinfo(addrResult);
|
||||||
return;
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SOCKET_CALL);
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverAddress.sin_family = AF_INET;
|
retval = bind(serverSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||||
|
if(retval != 0) {
|
||||||
/* Accept packets from any interface. (potentially insecure). */
|
|
||||||
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
serverAddress.sin_port = htons(setServerPort);
|
|
||||||
serverAddressLen = sizeof(serverAddress);
|
|
||||||
int result = setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,
|
|
||||||
reinterpret_cast<const char*>(&serverSocketOptions),
|
|
||||||
sizeof(serverSocketOptions));
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not set socket options!" <<
|
|
||||||
std::endl;
|
|
||||||
#endif
|
|
||||||
handleSocketError();
|
|
||||||
}
|
|
||||||
|
|
||||||
clientAddress.sin_family = AF_INET;
|
|
||||||
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
clientAddress.sin_port = htons(setClientPort);
|
|
||||||
clientAddressLen = sizeof(clientAddress);
|
|
||||||
|
|
||||||
result = bind(serverSocket,
|
|
||||||
reinterpret_cast<struct sockaddr*>(&serverAddress),
|
|
||||||
serverAddressLen);
|
|
||||||
if(result != 0) {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
sif::error << "TmTcWinUdpBridge::TmTcWinUdpBridge: Could not bind "
|
||||||
"local port " << setServerPort << " to server socket!"
|
"local port (" << udpServerPort << ") to server socket!" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
handleBindError();
|
freeaddrinfo(addrResult);
|
||||||
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::BIND_CALL);
|
||||||
}
|
}
|
||||||
|
freeaddrinfo(addrResult);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
||||||
|
if(mutex != nullptr) {
|
||||||
|
MutexFactory::instance()->deleteMutex(mutex);
|
||||||
|
}
|
||||||
closesocket(serverSocket);
|
closesocket(serverSocket);
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
@ -94,6 +108,9 @@ TmTcWinUdpBridge::~TmTcWinUdpBridge() {
|
|||||||
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
|
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||||
|
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
|
||||||
clientAddressLen = sizeof(serverAddress);
|
clientAddressLen = sizeof(serverAddress);
|
||||||
@ -102,15 +119,19 @@ ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
|||||||
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
&clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ssize_t bytesSent = sendto(serverSocket,
|
int bytesSent = sendto(
|
||||||
reinterpret_cast<const char*>(data), dataLen, flags,
|
serverSocket,
|
||||||
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
|
reinterpret_cast<const char*>(data),
|
||||||
|
dataLen,
|
||||||
|
flags,
|
||||||
|
reinterpret_cast<sockaddr*>(&clientAddress),
|
||||||
|
clientAddressLen
|
||||||
|
);
|
||||||
if(bytesSent == SOCKET_ERROR) {
|
if(bytesSent == SOCKET_ERROR) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
sif::error << "TmTcWinUdpBridge::sendTm: Send operation failed."
|
sif::warning << "TmTcWinUdpBridge::sendTm: Send operation failed." << std::endl;
|
||||||
<< std::endl;
|
|
||||||
#endif
|
#endif
|
||||||
handleSendError();
|
tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL);
|
||||||
}
|
}
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
|
||||||
@ -119,8 +140,9 @@ ReturnValue_t TmTcWinUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
|
|||||||
return HasReturnvaluesIF::RETURN_OK;
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
|
void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in& newAddress) {
|
||||||
MutexGuard lock(mutex, MutexIF::TimeoutType::WAITING, 10);
|
/* The target address can be set by different threads so this lock ensures thread-safety */
|
||||||
|
MutexGuard lock(mutex, timeoutType, mutexTimeoutMs);
|
||||||
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1
|
||||||
char ipAddress [15];
|
char ipAddress [15];
|
||||||
@ -133,93 +155,13 @@ void TmTcWinUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
|
|||||||
|
|
||||||
/* Set new IP address if it has changed. */
|
/* Set new IP address if it has changed. */
|
||||||
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
|
||||||
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
|
clientAddress = newAddress;
|
||||||
clientAddressLen = sizeof(clientAddress);
|
clientAddressLen = sizeof(clientAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TmTcWinUdpBridge::handleSocketError() {
|
void TmTcWinUdpBridge::setMutexProperties(MutexIF::TimeoutType timeoutType,
|
||||||
int errCode = WSAGetLastError();
|
dur_millis_t timeoutMs) {
|
||||||
switch(errCode) {
|
this->timeoutType = timeoutType;
|
||||||
case(WSANOTINITIALISED): {
|
this->mutexTimeoutMs = timeoutMs;
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "TmTcWinUdpBridge::handleSocketError: WSANOTINITIALISED: WSAStartup"
|
|
||||||
" call necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
/*
|
|
||||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
|
||||||
windows-sockets-error-codes-2
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "TmTcWinUdpBridge::handleSocketError: Error code: " << errCode << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TmTcWinUdpBridge::handleBindError() {
|
|
||||||
int errCode = WSAGetLastError();
|
|
||||||
switch(errCode) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleBindError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup call necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEADDRINUSE): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::warning << "TmTcWinUdpBridge::handleBindError: WSAEADDRINUSE: "
|
|
||||||
"Port is already in use!" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
/*
|
|
||||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
|
||||||
windows-sockets-error-codes-2
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleBindError: Error code: "
|
|
||||||
<< errCode << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmTcWinUdpBridge::handleSendError() {
|
|
||||||
int errCode = WSAGetLastError();
|
|
||||||
switch(errCode) {
|
|
||||||
case(WSANOTINITIALISED): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSendError: WSANOTINITIALISED: "
|
|
||||||
<< "WSAStartup(...) call necessary" << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case(WSAEADDRNOTAVAIL): {
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSendError: WSAEADDRNOTAVAIL: "
|
|
||||||
<< "Check target address. " << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
/*
|
|
||||||
https://docs.microsoft.com/en-us/windows/win32/winsock/
|
|
||||||
windows-sockets-error-codes-2
|
|
||||||
*/
|
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
|
||||||
sif::info << "TmTcWinUdpBridge::handleSendError: Error code: "
|
|
||||||
<< errCode << std::endl;
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -4,54 +4,41 @@
|
|||||||
#include "../../tmtcservices/TmTcBridge.h"
|
#include "../../tmtcservices/TmTcBridge.h"
|
||||||
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
//! Debugging preprocessor define.
|
|
||||||
#define FSFW_UDP_SEND_WIRETAPPING_ENABLED 0
|
|
||||||
|
|
||||||
class TmTcWinUdpBridge: public TmTcBridge {
|
class TmTcWinUdpBridge: public TmTcBridge {
|
||||||
friend class TcWinUdpPollingTask;
|
friend class TcWinUdpPollingTask;
|
||||||
public:
|
public:
|
||||||
/* The ports chosen here should not be used by any other process. */
|
/* The ports chosen here should not be used by any other process. */
|
||||||
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
|
static const std::string DEFAULT_UDP_SERVER_PORT;
|
||||||
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
|
|
||||||
|
|
||||||
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
TmTcWinUdpBridge(object_id_t objectId, object_id_t tcDestination,
|
||||||
object_id_t tmStoreId, object_id_t tcStoreId,
|
object_id_t tmStoreId, object_id_t tcStoreId, std::string udpServerPort = "");
|
||||||
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
|
|
||||||
virtual~ TmTcWinUdpBridge();
|
virtual~ TmTcWinUdpBridge();
|
||||||
|
|
||||||
void checkAndSetClientAddress(sockaddr_in clientAddress);
|
/**
|
||||||
|
* Set properties of internal mutex.
|
||||||
|
*/
|
||||||
|
void setMutexProperties(MutexIF::TimeoutType timeoutType, dur_millis_t timeoutMs);
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
|
void checkAndSetClientAddress(sockaddr_in& clientAddress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SOCKET serverSocket = 0;
|
SOCKET serverSocket = 0;
|
||||||
|
std::string udpServerPort;
|
||||||
const int serverSocketOptions = 0;
|
|
||||||
|
|
||||||
struct sockaddr_in clientAddress;
|
struct sockaddr_in clientAddress;
|
||||||
int clientAddressLen = 0;
|
int clientAddressLen = 0;
|
||||||
|
|
||||||
struct sockaddr_in serverAddress;
|
//! Access to the client address is mutex protected as it is set by another task.
|
||||||
int serverAddressLen = 0;
|
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||||
|
dur_millis_t mutexTimeoutMs = 20;
|
||||||
//! Access to the client address is mutex protected as it is set
|
|
||||||
//! by another task.
|
|
||||||
MutexIF* mutex;
|
MutexIF* mutex;
|
||||||
|
|
||||||
enum class ErrorSources {
|
|
||||||
SOCKET_CALL,
|
|
||||||
SETSOCKOPT_CALL
|
|
||||||
};
|
|
||||||
|
|
||||||
void handleSocketError();
|
|
||||||
void handleBindError();
|
|
||||||
void handleSendError();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */
|
#endif /* FSFW_OSAL_HOST_TMTCWINUDPBRIDGE_H_ */
|
||||||
|
|
||||||
|
63
osal/windows/tcpipHelpers.cpp
Normal file
63
osal/windows/tcpipHelpers.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "tcpipHelpers.h"
|
||||||
|
#include <FSFWConfig.h>
|
||||||
|
|
||||||
|
#include "../../tasks/TaskFactory.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void tcpip::handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration) {
|
||||||
|
#if FSFW_VERBOSE_LEVEL >= 1
|
||||||
|
int errCode = WSAGetLastError();
|
||||||
|
std::string protocolString;
|
||||||
|
std::string errorSrcString;
|
||||||
|
determineErrorStrings(protocol, errorSrc, protocolString, errorSrcString);
|
||||||
|
|
||||||
|
std::string infoString;
|
||||||
|
switch(errCode) {
|
||||||
|
case(WSANOTINITIALISED): {
|
||||||
|
infoString = "WSANOTINITIALISED";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEADDRINUSE): {
|
||||||
|
infoString = "WSAEADDRINUSE";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEFAULT): {
|
||||||
|
infoString = "WSAEFAULT";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEADDRNOTAVAIL): {
|
||||||
|
infoString = "WSAEADDRNOTAVAIL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case(WSAEINVAL): {
|
||||||
|
infoString = "WSAEINVAL";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
/*
|
||||||
|
https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
|
||||||
|
*/
|
||||||
|
infoString = "Error code: " + std::to_string(errCode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
sif::warning << "tcpip::handleError: " << protocolString << " | " << errorSrcString <<
|
||||||
|
" | " << infoString << std::endl;
|
||||||
|
#else
|
||||||
|
sif::printWarning("tcpip::handleError: %s | %s | %s\n", protocolString,
|
||||||
|
errorSrcString, infoString);
|
||||||
|
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||||
|
|
||||||
|
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||||
|
|
||||||
|
if(sleepDuration > 0) {
|
||||||
|
TaskFactory::instance()->delayTask(sleepDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
osal/windows/tcpipHelpers.h
Normal file
15
osal/windows/tcpipHelpers.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
|
||||||
|
#define FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_
|
||||||
|
|
||||||
|
#include "../../timemanager/clockDefinitions.h"
|
||||||
|
#include "../common/tcpipCommon.h"
|
||||||
|
|
||||||
|
namespace tcpip {
|
||||||
|
|
||||||
|
void handleError(Protocol protocol, ErrorSources errorSrc, dur_millis_t sleepDuration = 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_OSAL_WINDOWS_TCPIPHELPERS_H_ */
|
@ -173,6 +173,9 @@ ReturnValue_t TmTcBridge::handleTmQueue() {
|
|||||||
|
|
||||||
ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) {
|
ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) {
|
||||||
store_address_t storeId = 0;
|
store_address_t storeId = 0;
|
||||||
|
if(tmFifo == nullptr) {
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if(tmFifo->full()) {
|
if(tmFifo->full()) {
|
||||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||||
|
@ -275,7 +275,6 @@ TEST_CASE("DataSetTest" , "[DataSetTest]") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sharedSet.setReadCommitProtectionBehaviour(true);
|
sharedSet.setReadCommitProtectionBehaviour(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we need to reset the subscription list because the pool owner
|
/* we need to reset the subscription list because the pool owner
|
||||||
|
@ -206,7 +206,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") {
|
|||||||
CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1));
|
CHECK(cdsShort.msDay_ll == Catch::Approx(timeCdsNow.msDay_ll).margin(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("VariableUpdateTest") {
|
SECTION("VariableNotificationTest") {
|
||||||
/* Acquire subscription interface */
|
/* Acquire subscription interface */
|
||||||
ProvidesDataPoolSubscriptionIF* subscriptionIF = poolOwner->getSubscriptionInterface();
|
ProvidesDataPoolSubscriptionIF* subscriptionIF = poolOwner->getSubscriptionInterface();
|
||||||
REQUIRE(subscriptionIF != nullptr);
|
REQUIRE(subscriptionIF != nullptr);
|
||||||
|
Loading…
Reference in New Issue
Block a user