added Server class usable for all detectors

This commit is contained in:
2026-04-20 12:25:11 +02:00
parent 8511064640
commit ba48329cd4
8 changed files with 225 additions and 180 deletions
@@ -1,6 +1,8 @@
#pragma once
#include "DetectorServer.h"
#include "TCPInterface.h"
#include "communication_funcs.h"
#include "fmt/format.h"
#include "sls/logger.h"
#include "sls/network_utils.h"
#include "sls/sls_detector_defs.h"
@@ -14,19 +16,11 @@
namespace sls {
/// @brief struct saving udp details (one UDP port per module)
struct UDPInfo {
uint16_t srcport{};
uint16_t dstport{};
uint64_t srcmac{};
uint64_t dstmac{};
uint32_t srcip{};
uint32_t dstip{};
};
/// @brief Base class for Matterhorn Server, can be used to implement a virtual
/// server for testing and actual server
template <typename DerivedServer> class BaseMatterhornServer {
template <typename DerivedServer>
class BaseMatterhornServer
: public DetectorServer<BaseMatterhornServer<DerivedServer>> {
public:
/**
@@ -36,7 +30,8 @@ template <typename DerivedServer> class BaseMatterhornServer {
* throws an exception in case of failure
* @param port TCP/IP port number
*/
explicit BaseMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
explicit BaseMatterhornServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO)
: DetectorServer<BaseMatterhornServer<DerivedServer>>(port) {}
~BaseMatterhornServer() = default;
@@ -46,95 +41,30 @@ template <typename DerivedServer> class BaseMatterhornServer {
ReturnCode initial_checks(ServerInterface &socket);
ReturnCode get_num_udp_interfaces(ServerInterface &socket);
ReturnCode get_update_mode(ServerInterface &socket);
ReturnCode get_source_udp_mac(ServerInterface &socket);
ReturnCode get_source_udp_ip(ServerInterface &socket);
ReturnCode get_source_udp_port(ServerInterface &socket);
ReturnCode get_destination_udp_mac(ServerInterface &socket);
ReturnCode get_destination_udp_ip(ServerInterface &socket);
ReturnCode get_destination_udp_port(ServerInterface &socket);
protected:
size_t num_udp_interfaces() const;
/// @brief TODO what is this?
bool updateMode{true};
/// @brief TCP/IP interface for communication with the client
std::unique_ptr<TCPInterface> tcpInterface;
std::array<UDPInfo, 1>
udpDetails{}; // TODO: for now only one receiver per module
/**
* @brief call function corresponding to the function ID received from the
* client and send back the result
* @param function_id the function ID received from the client
* @param socket the socket to send the result back to the client
*/
ReturnCode processFunction(const detFuncs function_id,
ServerInterface &socket);
private:
static std::string getMatterhornServerVersion();
private:
/// @brief map of function IDs and corresponding functions
// maybe load from additional file cleaner
std::unordered_map<detFuncs, std::function<ReturnCode(ServerInterface &)>>
function_table = {
{detFuncs::F_GET_SERVER_VERSION,
[this](ServerInterface &si) { return this->get_version(si); }},
{detFuncs::F_GET_DETECTOR_TYPE,
[this](ServerInterface &si) {
return this->get_detector_type(si);
}},
{detFuncs::F_INITIAL_CHECKS,
[this](ServerInterface &si) {
return static_cast<DerivedServer *>(this)->initial_checks(si);
}},
{detFuncs::F_GET_NUM_INTERFACES,
[this](ServerInterface &si) {
return this->get_num_udp_interfaces(si);
}},
{detFuncs::F_GET_UPDATE_MODE,
[this](ServerInterface &si) {
return static_cast<DerivedServer *>(this)->get_update_mode(si);
}},
{detFuncs::F_GET_SOURCE_UDP_MAC,
[this](ServerInterface &si) {
return this->get_source_udp_mac(si);
}},
{detFuncs::F_GET_SOURCE_UDP_IP,
[this](ServerInterface &si) {
return this->get_source_udp_ip(si);
}},
{detFuncs::F_GET_DEST_UDP_MAC,
[this](ServerInterface &si) {
return this->get_destination_udp_mac(si);
}},
{detFuncs::F_GET_DEST_UDP_IP,
[this](ServerInterface &si) {
return this->get_destination_udp_ip(si);
}},
{detFuncs::F_GET_DEST_UDP_PORT, [this](ServerInterface &si) {
return this->get_destination_udp_port(si);
}}};
};
template <typename DerivedServer>
BaseMatterhornServer<DerivedServer>::BaseMatterhornServer(uint16_t port) {
ReturnCode
BaseMatterhornServer<DerivedServer>::processFunction(const detFuncs function_id,
ServerInterface &socket) {
validatePortNumber(port);
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
// TODO: when do i set the udp mac and ip ?
tcpInterface = std::make_unique<TCPInterface>(
function_table, port); // TODO: need a tcp and udp interface
// need a function to setup detector - e.g. set all registers etc.
switch (function_id) {
default:
throw RuntimeError(
fmt::format("Function {} not implemented",
getFunctionNameFromEnum((enum detFuncs)function_id)));
}
}
template <typename DerivedServer>
@@ -162,52 +92,10 @@ std::string BaseMatterhornServer<DerivedServer>::getMatterhornServerVersion() {
}
template <typename DerivedServer>
size_t BaseMatterhornServer<DerivedServer>::num_udp_interfaces() const {
return udpDetails.size();
}
ReturnCode
BaseMatterhornServer<DerivedServer>::initial_checks(ServerInterface &socket) {
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_num_udp_interfaces(
ServerInterface &socket) {
int numUDPInterfaces = static_cast<int>(num_udp_interfaces());
return static_cast<ReturnCode>(socket.sendResult(numUDPInterfaces));
return static_cast<DerivedServer *>(this)->initial_checks(socket);
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_source_udp_mac(
ServerInterface &socket) {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcmac));
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_source_udp_ip(
ServerInterface &socket) {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcip));
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_source_udp_port(
ServerInterface &socket) {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(udpDetails[0].srcport)));
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_destination_udp_mac(
ServerInterface &socket) {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstmac));
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_destination_udp_ip(
ServerInterface &socket) {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstip));
}
template <typename DerivedServer>
ReturnCode BaseMatterhornServer<DerivedServer>::get_destination_udp_port(
ServerInterface &socket) {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstport));
};
} // namespace sls
@@ -22,8 +22,6 @@ class MatterhornServer : public BaseMatterhornServer<MatterhornServer> {
~MatterhornServer() = default;
ReturnCode initial_checks(ServerInterface &socket);
ReturnCode get_update_mode(ServerInterface &socket);
};
} // namespace sls
@@ -1,14 +0,0 @@
#include "MatterhornServer.h"
#include <cstdint>
namespace sls {
// TODO: should this inherit from MatterhornServer or a base class - depending on virtual or not
class StopServer : public MatterhornServer {
public:
StopServer(uint16_t port);
~StopServer() = default;
};
} // namespace sls
@@ -19,8 +19,6 @@ class VirtualMatterhornServer
~VirtualMatterhornServer() = default;
ReturnCode initial_checks(ServerInterface &socket);
ReturnCode get_update_mode(ServerInterface &socket);
};
} // namespace sls
@@ -21,9 +21,4 @@ ReturnCode VirtualMatterhornServer::initial_checks(ServerInterface &socket) {
return static_cast<ReturnCode>(socket.sendResult(initial_checks_passed));
}
ReturnCode VirtualMatterhornServer::get_update_mode(ServerInterface &socket) {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(updateMode)));
}
} // namespace sls
@@ -0,0 +1,190 @@
#pragma once
#include "TCPInterface.h"
#include "communication_funcs.h"
#include "sls/logger.h"
#include "sls/network_utils.h"
#include "sls/sls_detector_defs.h"
#include "sls/versionAPI.h"
#include <array>
#include <cstring>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
namespace sls {
// TODO move to defs?
/// @brief struct saving udp details (one UDP port per module)
struct UDPInfo {
uint16_t srcport{};
uint16_t srcport2{};
uint16_t dstport{};
uint16_t dstport2{};
uint64_t srcmac{};
uint64_t srcmac2{};
uint64_t dstmac{};
uint64_t dstmac2{};
uint32_t srcip{};
uint32_t srcip2{};
uint32_t dstip{};
uint32_t dstip2{};
};
template <typename DerivedDetectorServer> class DetectorServer {
public:
/**
* Constructor
* Creates a detector server.
* Assembles a detector server using TCP and UDP detector interfaces
* throws an exception in case of failure
* @param port TCP/IP port number
*/
explicit DetectorServer(uint16_t port = DEFAULT_TCP_CNTRL_PORTNO);
protected:
/// @brief TCP/IP interface for communication with the client
std::unique_ptr<TCPInterface> tcpInterface;
std::array<UDPInfo, 1>
udpDetails{}; // TODO: for now only one receiver per module
/// @brief TODO what is this?
bool updateMode{true};
private:
ReturnCode processFunction(const detFuncs function_id,
ServerInterface &socket);
size_t num_udp_interfaces() const;
ReturnCode get_num_udp_interfaces(ServerInterface &socket) const;
// TODO dont know what this does?
ReturnCode get_update_mode(ServerInterface &socket) const;
ReturnCode get_source_udp_mac(ServerInterface &socket) const;
ReturnCode get_source_udp_ip(ServerInterface &socket) const;
ReturnCode get_source_udp_port(ServerInterface &socket) const;
ReturnCode get_destination_udp_mac(ServerInterface &socket) const;
ReturnCode get_destination_udp_ip(ServerInterface &socket) const;
ReturnCode get_destination_udp_port(ServerInterface &socket) const;
};
template <typename DerivedDetectorServer>
DetectorServer<DerivedDetectorServer>::DetectorServer(uint16_t port) {
validatePortNumber(port);
udpDetails[0].srcport = DEFAULT_UDP_SRC_PORTNO;
udpDetails[0].dstport = DEFAULT_UDP_DST_PORTNO;
std::function<ReturnCode(const detFuncs &, ServerInterface &)> fn =
[this](const detFuncs &function_id, ServerInterface &socket) {
return this->processFunction(function_id, socket);
};
tcpInterface = std::make_unique<TCPInterface>(fn, port);
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::processFunction(
const detFuncs function_id, ServerInterface &socket) {
switch (function_id) {
case detFuncs::F_GET_SERVER_VERSION:
return static_cast<DerivedDetectorServer *>(this)->get_version(socket);
case detFuncs::F_GET_DETECTOR_TYPE:
return static_cast<DerivedDetectorServer *>(this)->get_detector_type(
socket);
case detFuncs::F_INITIAL_CHECKS:
return static_cast<DerivedDetectorServer *>(this)->initial_checks(
socket);
case detFuncs::F_GET_NUM_INTERFACES:
return static_cast<DerivedDetectorServer *>(this)
->get_num_udp_interfaces(socket);
case detFuncs::F_GET_UPDATE_MODE:
return get_update_mode(socket);
case detFuncs::F_GET_SOURCE_UDP_MAC:
return get_source_udp_mac(socket);
case detFuncs::F_GET_SOURCE_UDP_IP:
return get_source_udp_ip(socket);
case detFuncs::F_GET_DEST_UDP_MAC:
return get_destination_udp_mac(socket);
case detFuncs::F_GET_DEST_UDP_IP:
return get_destination_udp_ip(socket);
case detFuncs::F_GET_DEST_UDP_PORT:
return get_destination_udp_port(socket);
default:
LOG(logDEBUG) << "Checking specific server functions for function ID: "
<< function_id;
// process detector specific functions
static_cast<DerivedDetectorServer *>(this)->processFunction(function_id,
socket);
}
return ReturnCode::FAIL;
}
template <typename DerivedDetectorServer>
size_t DetectorServer<DerivedDetectorServer>::num_udp_interfaces() const {
return udpDetails.size();
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_num_udp_interfaces(
ServerInterface &socket) const {
int numUDPInterfaces = static_cast<int>(num_udp_interfaces());
return static_cast<ReturnCode>(socket.sendResult(numUDPInterfaces));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_update_mode(
ServerInterface &socket) const {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(updateMode)));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_mac(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcmac));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_ip(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].srcip));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_source_udp_port(
ServerInterface &socket) const {
return static_cast<ReturnCode>(
socket.sendResult(static_cast<int>(udpDetails[0].srcport)));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_mac(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstmac));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_ip(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstip));
}
template <typename DerivedDetectorServer>
ReturnCode DetectorServer<DerivedDetectorServer>::get_destination_udp_port(
ServerInterface &socket) const {
return static_cast<ReturnCode>(socket.sendResult(udpDetails[0].dstport));
};
} // namespace sls
@@ -18,9 +18,8 @@ class TCPInterface {
public:
~TCPInterface();
TCPInterface(std::unordered_map<
detFuncs, std::function<ReturnCode(ServerInterface &)>>
&functionTable_,
TCPInterface(std::function<ReturnCode(const detFuncs &, ServerInterface &)>
&processFunction_,
const uint16_t portNumber = DEFAULT_TCP_CNTRL_PORTNO);
/// @brief starts the TCP/IP server to listen for client commands
@@ -36,8 +35,8 @@ class TCPInterface {
ServerInterface &socket);
/// @brief map of function IDs and corresponding functions
std::unordered_map<detFuncs, std::function<ReturnCode(ServerInterface &)>>
functionTable{};
std::function<ReturnCode(const detFuncs &, ServerInterface &)>
processFunction;
uint16_t portNumber{};
@@ -8,10 +8,10 @@
namespace sls {
TCPInterface::TCPInterface(
std::unordered_map<detFuncs, std::function<ReturnCode(ServerInterface &)>>
&functionTable_,
std::function<ReturnCode(const detFuncs &, ServerInterface &)>
&processFunction_,
const uint16_t portNumber)
: functionTable(functionTable_), portNumber(portNumber),
: processFunction(processFunction_), portNumber(portNumber),
server(portNumber) {
validatePortNumber(portNumber);
}
@@ -67,21 +67,12 @@ void TCPInterface::startTCPServer() {
ReturnCode TCPInterface::processReceivedData(const detFuncs function_id,
ServerInterface &socket) {
// TODO: is NUM_DET_FUNCTIONS correct?
LOG(logDEBUG1) << "calling function fnum: " << function_id << " ("
<< getFunctionNameFromEnum((enum detFuncs)function_id)
<< ")";
auto function = functionTable.find(function_id);
if (function == functionTable.end()) {
throw RuntimeError(
fmt::format("Function {} not found not implemented",
getFunctionNameFromEnum((enum detFuncs)function_id)));
}
ReturnCode returncode =
function->second(socket); // how does it pass input arguments?
ReturnCode returncode = processFunction(function_id, socket);
LOG(logDEBUG1) << "Function "
<< getFunctionNameFromEnum((enum detFuncs)function_id)