mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-07-09 04:39:32 +02:00
added cpp TCP Interface to slsDetectorServer
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
set(SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ClientInterface.cpp
|
||||
)
|
||||
|
||||
add_library(slsServerObject OBJECT
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(slsServerObject PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
|
||||
target_link_libraries(slsServerObject
|
||||
PUBLIC
|
||||
slsProjectOptions
|
||||
slsSupportStatic
|
||||
slsDetectorObject
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
)
|
||||
|
||||
set(DETECTOR_LIBRARY_TARGETS slsServerObject)
|
||||
|
||||
set(PUBLICHEADERS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/ClientInterface.h
|
||||
)
|
||||
|
||||
#Shared library
|
||||
if(SLS_BUILD_SHARED_LIBRARIES)
|
||||
add_library(slsServerShared SHARED $<TARGET_OBJECTS:slsServerObject>)
|
||||
target_link_libraries(slsServerShared PUBLIC slsServerObject)
|
||||
set_target_properties(slsServerShared PROPERTIES
|
||||
VERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}
|
||||
SOVERSION ${PACKAGE_VERSION_MAJOR}
|
||||
LIBRARY_OUTPUT_NAME SlsServer
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
PUBLIC_HEADER "${PUBLICHEADERS}"
|
||||
)
|
||||
list(APPEND DETECTOR_LIBRARY_TARGETS slsServerShared)
|
||||
endif(SLS_BUILD_SHARED_LIBRARIES)
|
||||
|
||||
#Static library
|
||||
add_library(slsServerStatic STATIC $<TARGET_OBJECTS:slsServerObject>)
|
||||
target_link_libraries(slsServerStatic PUBLIC slsServerObject)
|
||||
|
||||
set_target_properties(slsServerStatic PROPERTIES
|
||||
ARCHIVE_OUTPUT_NAME SlsServerStatic
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
PUBLIC_HEADER "${PUBLICHEADERS}"
|
||||
)
|
||||
list(APPEND DETECTOR_LIBRARY_TARGETS slsServerStatic)
|
||||
|
||||
if((CMAKE_BUILD_TYPE STREQUAL "Release") AND SLS_LTO_AVAILABLE)
|
||||
set_property(TARGET ${DETECTOR_LIBRARY_TARGETS} PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${DETECTOR_LIBRARY_TARGETS}
|
||||
EXPORT "${TARGETS_EXPORT_NAME}"
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sls
|
||||
)
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include "sls/ServerSocket.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/sls_detector_funcs.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sls {
|
||||
|
||||
/**
|
||||
* @brief ClientInterface class handles communication and processing of commands
|
||||
* from Client to Server.
|
||||
*/
|
||||
class ClientInterface : private virtual slsDetectorDefs {
|
||||
|
||||
protected:
|
||||
// TODO probably requires std::variant
|
||||
/// @brief map of function IDs and corresponding functions
|
||||
std::unordered_map<detFuncs, std::function<ReturnCode(ServerInterface &)>>
|
||||
functionTable{}; // set in constructor of child process
|
||||
|
||||
private:
|
||||
/// @brief listener thread for TCP/IP communication with the client
|
||||
std::unique_ptr<std::thread> tcpThread;
|
||||
|
||||
/// @brief flag to signal the TCP/IP listener thread to stop
|
||||
std::atomic<bool> killTcpThread{false};
|
||||
|
||||
/// @brief flag to indicate if the receiver is currently locked by a client
|
||||
bool lockedByClient{false}; // TODO should it be atomic?
|
||||
|
||||
uint16_t portNumber{};
|
||||
|
||||
/// @brief socket for TCP/IP communication with the client
|
||||
ServerSocket server;
|
||||
|
||||
public:
|
||||
~ClientInterface();
|
||||
|
||||
explicit ClientInterface(
|
||||
const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO);
|
||||
|
||||
// std::string getReceiverVersion();
|
||||
|
||||
private:
|
||||
/// @brief starts the TCP/IP server to listen for client commands
|
||||
void startTCPServer();
|
||||
|
||||
/**
|
||||
* @brief decodes the received command and calls the corresponding function
|
||||
* @param function_id The ID of the function recived by the server and to
|
||||
* be executed
|
||||
*/
|
||||
ReturnCode processReceivedData(const detFuncs function_id,
|
||||
ServerInterface &socket);
|
||||
|
||||
bool checkifReceiverLocked();
|
||||
};
|
||||
|
||||
} // namespace sls
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "ClientInterface.h"
|
||||
|
||||
#include "sls/logger.h"
|
||||
#include "sls/string_utils.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
ClientInterface::ClientInterface(const uint16_t portNumber)
|
||||
: portNumber(portNumber), server(portNumber) {
|
||||
validatePortNumber(portNumber);
|
||||
// parentThreadId = gettid();
|
||||
tcpThread =
|
||||
std::make_unique<std::thread>(&ClientInterface::startTCPServer, this);
|
||||
}
|
||||
|
||||
ClientInterface::~ClientInterface() {
|
||||
killTcpThread = true;
|
||||
LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber;
|
||||
server.shutdown();
|
||||
LOG(logDEBUG) << "TCP Socket closed on port " << portNumber;
|
||||
|
||||
/*
|
||||
if (receiver) {
|
||||
receiver->shutDownUDPSockets();
|
||||
}
|
||||
*/
|
||||
|
||||
tcpThread->join();
|
||||
}
|
||||
|
||||
void ClientInterface::startTCPServer() {
|
||||
const pid_t tcpThreadId = gettid();
|
||||
LOG(logINFOBLUE) << "Created [ TCP server Tid: " << tcpThreadId << "]";
|
||||
LOG(logINFO) << "SLS Receiver starting TCP Server on port " << portNumber
|
||||
<< '\n';
|
||||
|
||||
int function_id{}; // TODO should it be an enum type
|
||||
while (!killTcpThread) {
|
||||
LOG(logDEBUG1) << "Start accept loop";
|
||||
try {
|
||||
auto socket = server.accept();
|
||||
try {
|
||||
// is this to check if I can process a command? or what is that?
|
||||
if (checkifReceiverLocked()) {
|
||||
throw SocketError("Receiver locked\n");
|
||||
}
|
||||
socket.Receive(function_id);
|
||||
processReceivedData(static_cast<detFuncs>(function_id), socket);
|
||||
|
||||
} catch (const RuntimeError &e) {
|
||||
// We had an error needs to be sent to client
|
||||
char mess[MAX_STR_LENGTH]{};
|
||||
strcpy_safe(mess, e.what());
|
||||
socket.Send(FAIL);
|
||||
socket.Send(mess);
|
||||
}
|
||||
// TODO handle exiting server if tcp command was to exit server
|
||||
} catch (const RuntimeError &e) {
|
||||
LOG(logERROR) << "Accept failed";
|
||||
}
|
||||
}
|
||||
|
||||
LOG(logINFOBLUE) << "Exiting [ TCP server Tid: " << tcpThreadId << "]";
|
||||
}
|
||||
|
||||
ReturnCode ClientInterface::processReceivedData(const detFuncs function_id,
|
||||
ServerInterface &socket) {
|
||||
// TODO: is NUM_DET_FUNCTIONS correct?
|
||||
if (function_id < 0 || function_id >= NUM_DET_FUNCTIONS) {
|
||||
throw RuntimeError(UNRECOGNIZED_FNUM_ENUM +
|
||||
std::to_string(function_id));
|
||||
}
|
||||
LOG(logDEBUG1) << "calling function fnum: " << function_id << " ("
|
||||
<< getFunctionNameFromEnum((enum detFuncs)function_id)
|
||||
<< ")";
|
||||
ReturnCode returncode = (functionTable[function_id])(
|
||||
socket); // how does it pass input arguments?
|
||||
LOG(logDEBUG1) << "Function "
|
||||
<< getFunctionNameFromEnum((enum detFuncs)function_id)
|
||||
<< " finished";
|
||||
|
||||
return returncode;
|
||||
}
|
||||
|
||||
bool ClientInterface::checkifReceiverLocked() {
|
||||
return lockedByClient && server.getThisClient() != server.getLockedBy();
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
Reference in New Issue
Block a user