remove unused files (#7)

This commit is contained in:
tompzf
2026-03-27 14:24:52 +01:00
committed by GitHub
parent aefefd52f7
commit 6ed5fdb951
74 changed files with 0 additions and 8898 deletions

View File

@@ -1,24 +0,0 @@
if(WIN32)
# Define project
project(ipc_sockets VERSION 1.0 LANGUAGES CXX)
# Define target
add_library(ipc_sockets SHARED
"channel_mgnt.h"
"channel_mgnt.cpp"
"connection.h"
"connection.cpp")
target_link_libraries(ipc_sockets ${CMAKE_THREAD_LIBS_INIT} Ws2_32.lib)
target_link_options(ipc_sockets PRIVATE)
target_include_directories(ipc_sockets PRIVATE ./include/)
set_target_properties(ipc_sockets PROPERTIES PREFIX "")
set_target_properties(ipc_sockets PROPERTIES SUFFIX ".sdv")
# Build dependencies
add_dependencies(ipc_sockets CompileCoreIDL)
# Appending the service in the service list
set(SDV_Service_List ${SDV_Service_List} ipc_sockets PARENT_SCOPE)
endif()

View File

@@ -1,356 +0,0 @@
#include "channel_mgnt.h"
#include "connection.h"
#include "../../global/base64.h"
#include <support/toml.h>
#include <interfaces/process.h>
#include <future>
#pragma push_macro("interface")
#undef interface
#pragma push_macro("GetObject")
#undef GetObject
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <WinSock2.h>
#include <Windows.h>
#include <array>
// Resolve conflict
#pragma pop_macro("GetObject")
#pragma pop_macro("interface")
#ifdef GetClassInfo
#undef GetClassInfo
#endif
/**
* Define for the connection string
*/
#define SHARED_SOCKET "SHARED_SOCKET"
void CSocketsChannelMgnt::Initialize(const sdv::u8string& /*ssObjectConfig*/)
{
if (m_eObjectStatus != sdv::EObjectStatus::initialization_pending)
m_eObjectStatus = sdv::EObjectStatus::initialization_failure;
else
m_eObjectStatus = sdv::EObjectStatus::initialized;
}
sdv::EObjectStatus CSocketsChannelMgnt::GetStatus() const
{
return m_eObjectStatus;
}
void CSocketsChannelMgnt::SetOperationMode(sdv::EOperationMode eMode)
{
switch (eMode)
{
case sdv::EOperationMode::configuring:
if (m_eObjectStatus == sdv::EObjectStatus::running || m_eObjectStatus == sdv::EObjectStatus::initialized)
m_eObjectStatus = sdv::EObjectStatus::configuring;
break;
case sdv::EOperationMode::running:
if (m_eObjectStatus == sdv::EObjectStatus::configuring || m_eObjectStatus == sdv::EObjectStatus::initialized)
m_eObjectStatus = sdv::EObjectStatus::running;
break;
default:
break;
}
}
void CSocketsChannelMgnt::Shutdown()
{
//m_eObjectStatus = sdv::EObjectStatus::shutdown_in_progress;
//...
m_eObjectStatus = sdv::EObjectStatus::destruction_pending;
}
sdv::ipc::SChannelEndpoint CSocketsChannelMgnt::CreateEndpoint(const sdv::u8string& /*ssChannelConfig*/)
{
StartUpWinSock();
addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
SOCKET listenSocket = CreateSocket(hints);
if (listenSocket == INVALID_SOCKET)
{
SDV_LOG_ERROR("CreateSocket failed (could not create endpoint)");
sdv::ipc::SChannelEndpoint connectionEndpoint{};
return connectionEndpoint;
}
CConnection* pRemoteIPCConnection = new CConnection(listenSocket, true);
uint16_t port = GetPort(listenSocket);
std::string ipcCompleteConfig = "localhost";
ipcCompleteConfig.append(";");
ipcCompleteConfig.append(std::to_string(port));
SDV_LOG_INFO("IPC command param: '", ipcCompleteConfig, "'");
sdv::ipc::SChannelEndpoint connectionEndpoint{};
connectionEndpoint.pConnection = static_cast<IInterfaceAccess*>(pRemoteIPCConnection);
connectionEndpoint.ssConnectString = ipcCompleteConfig;
return connectionEndpoint;
}
sdv::IInterfaceAccess* CSocketsChannelMgnt::Access(const sdv::u8string& ssConnectString)
{
bool sharedSocketRequired = ssConnectString.find(SHARED_SOCKET) != std::string::npos ? true : false;
if (sharedSocketRequired)
{
std::string base64Data(ssConnectString);
const std::string ext(SHARED_SOCKET);
base64Data = base64Data.substr(0, base64Data.size() - ext.size());
WSAPROTOCOL_INFO socketInfo = DecodeBase64<WSAPROTOCOL_INFO>(base64Data);
SOCKET sharedSocket = WSASocket(0, 0, 0, &socketInfo, 0, 0);
std::string success = "Socket sharing success";
if (sharedSocket == INVALID_SOCKET)
{
success = "Socket sharing did not work!";
}
return static_cast<IInterfaceAccess*>(new CConnection(sharedSocket, false));
}
StartUpWinSock();
addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
std::string host{"localhost"};
std::string param{ssConnectString};
auto it = param.find(";");
if (it != std::string::npos)
{
host = param.substr(0, it);
param = param.substr(it + 1, param.size() - it - 1);
}
SOCKET socket = CreateAndConnectToExistingSocket(hints, host.c_str(), param.c_str());
if (socket == INVALID_SOCKET)
{
SDV_LOG_ERROR("Could not create my socket and connect to the existing socket.");
}
return static_cast<IInterfaceAccess*>(new CConnection(socket, false));
}
uint16_t CSocketsChannelMgnt::GetPort(SOCKET socket) const
{
sockaddr_in sockAddr;
sockAddr.sin_port = 0;
int nameLength = sizeof(sockAddr);
getsockname(socket, reinterpret_cast<sockaddr*>(&sockAddr), &nameLength);
return ntohs(sockAddr.sin_port);
}
SOCKET CSocketsChannelMgnt::CreateAndConnectToExistingSocket(const addrinfo& hints,
const char* hostName,
const char* portName)
{
SOCKET invalidSocket{INVALID_SOCKET};
// Resolve the server address and port
CAddrInfo result;
int error = getaddrinfo(hostName, portName, &hints, &result.AddressInfo);
if (error != 0)
{
SDV_LOG_ERROR("getaddrinfo failed with error: ",
std::to_string(error),
" host: ",
hostName,
" port: ",
portName);
return invalidSocket;
}
SOCKET connectSocket{INVALID_SOCKET};
// Attempt to connect to an address until one succeeds
for (addrinfo* ptr = result.AddressInfo; ptr != NULL; ptr = ptr->ai_next)
{
// Create a SOCKET for connecting to server
connectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (connectSocket == INVALID_SOCKET)
{
SDV_LOG_ERROR("socket failed with error: ", std::to_string(error));
return invalidSocket;
}
// Connect to server.
error = connect(connectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (error == SOCKET_ERROR)
{
SDV_LOG_ERROR("connect failed with error: ", std::to_string(error));
closesocket(connectSocket);
connectSocket = INVALID_SOCKET;
continue;
}
break;
}
return connectSocket;
}
SOCKET CSocketsChannelMgnt::CreateSocket(const addrinfo& hints)
{
static constexpr const char* defaultPort_0{"0"}; // In case a defined port is required
SOCKET invalidSocket{INVALID_SOCKET};
CAddrInfo result;
int error = getaddrinfo(NULL, defaultPort_0, &hints, &result.AddressInfo);
if (error != 0)
{
SDV_LOG_ERROR("getaddrinfo failed with error: ", std::to_string(error));
return invalidSocket;
}
SOCKET connectSocket{INVALID_SOCKET};
connectSocket =
socket(result.AddressInfo->ai_family, result.AddressInfo->ai_socktype, result.AddressInfo->ai_protocol);
if (connectSocket == INVALID_SOCKET)
{
SDV_LOG_ERROR("error at socket(): ", std::to_string(error));
return invalidSocket;
}
error = bind(connectSocket, result.AddressInfo->ai_addr, (int)result.AddressInfo->ai_addrlen);
if (error == SOCKET_ERROR)
{
closesocket(connectSocket);
SDV_LOG_ERROR("bind failed with error: ", std::to_string(error));
return invalidSocket;
}
if (listen(connectSocket, SOMAXCONN) == SOCKET_ERROR)
{
closesocket(connectSocket);
SDV_LOG_ERROR("listen failed with error: ", std::to_string(WSAGetLastError()));
return invalidSocket;
}
// Change the socket mode on the listening socket from blocking to
// non-block so the application will not block waiting for requests
u_long NonBlock = 1;
if (ioctlsocket(connectSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
closesocket(connectSocket);
SDV_LOG_ERROR("ioctlsocket failed with error: ", std::to_string(WSAGetLastError()));
return invalidSocket;
}
return connectSocket;
}
SOCKET CSocketsChannelMgnt::CreateAndConnectToSocket(const addrinfo& hints, const char* defaultHost, const char* defaultPort)
{
SOCKET ConnectSocket{ INVALID_SOCKET };
// Resolve the server address and port
CAddrInfo result;
if (getaddrinfo(defaultHost, defaultPort, &hints, &result.AddressInfo) != 0)
{
SDV_LOG_ERROR("getaddrinfo() failed: ", std::to_string(WSAGetLastError()));
return ConnectSocket;
}
// Attempt to connect to an address until one succeeds
for (addrinfo* ptr = result.AddressInfo; ptr != NULL; ptr = ptr->ai_next)
{
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET)
{
SDV_LOG_ERROR("creating SOCKET for connecting failed: ", std::to_string(WSAGetLastError()));
break;
}
// Connect to server.
if (connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen) == SOCKET_ERROR)
{
SDV_LOG_ERROR("connect to servcer failed: ", std::to_string(WSAGetLastError()));
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
if (ConnectSocket == INVALID_SOCKET)
{
SDV_LOG_ERROR("Failed to create valid sockaet in CreateAndConnectToSocket()");
}
return ConnectSocket;
}
SOCKET CSocketsChannelMgnt::Listen(const addrinfo& hints, uint32_t port)
{
SOCKET listenSocket = INVALID_SOCKET;
CAddrInfo result;
int error = getaddrinfo(NULL, std::to_string(port).c_str(), &hints, &result.AddressInfo);
if (error != 0)
{
SDV_LOG_ERROR("getaddrinfo() failed: ", std::to_string(WSAGetLastError()));
return listenSocket;
}
listenSocket = socket(result.AddressInfo->ai_family, result.AddressInfo->ai_socktype, result.AddressInfo->ai_protocol);
if (listenSocket == INVALID_SOCKET)
{
SDV_LOG_ERROR("2creating SOCKET for connecting failed: failed: ", std::to_string(WSAGetLastError()));
return listenSocket;
}
error = bind(listenSocket, result.AddressInfo->ai_addr, (int)result.AddressInfo->ai_addrlen);
if (error == SOCKET_ERROR)
{
SDV_LOG_ERROR("bind failed with error: ", std::to_string(WSAGetLastError()));
closesocket(listenSocket);
listenSocket = INVALID_SOCKET;
return listenSocket;
}
if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR)
{
SDV_LOG_ERROR("listen to SOCKET failed: ", std::to_string(WSAGetLastError()));
closesocket(listenSocket);
listenSocket = INVALID_SOCKET;
return listenSocket;
}
return listenSocket;
}
SocketConnection CSocketsChannelMgnt::CreateConnectedSocketPair()
{
SocketConnection connection;
uint32_t port = 0;
SOCKET listenSocket = Listen(getHints, port);
uint16_t portOfListenSocket = GetPort(listenSocket);
auto future = std::async([listenSocket]() { return accept(listenSocket, NULL, NULL); });
connection.From = CreateAndConnectToSocket(getHints, "localhost", std::to_string(portOfListenSocket).c_str());
// Future::Get has to be called after the CreateAndConnect-Function
connection.To = future.get();
return connection;
}

View File

@@ -1,198 +0,0 @@
#ifndef CHANNEL_MGNT_H
#define CHANNEL_MGNT_H
#include <support/component_impl.h>
#include <interfaces/ipc.h>
#ifdef _WIN32
#include <ws2tcpip.h>
#endif
/**
* @brief The CAddrInfo structure is used by the getaddrinfo function to hold host address information.
*/
struct CAddrInfo
{
/**
* @brief Constructor
*/
CAddrInfo() = default;
/**
* @brief Constructor
*/
CAddrInfo(const CAddrInfo&) = delete;
/**
* @brief Copy constructor
*/
CAddrInfo& operator=(const CAddrInfo&) = delete;
/**
* @brief Move constructor
* @param[in] other Reference to the structure to move.
*/
CAddrInfo(CAddrInfo&& other) = delete;
/**
* @brief Move operator.
* @param[in] other Reference to the structure to move.
* @return Returns reference to CAddrInfo structure
*/
CAddrInfo& operator=(CAddrInfo&& other) = delete;
~CAddrInfo()
{
freeaddrinfo(AddressInfo);
}
addrinfo* AddressInfo{nullptr}; ///< The CAddrInfo structure holding host address information.
};
/**
* @brief Initial startup of winSock
* @return Returns 0 in case of no error, otherwise the error code
*/
inline int StartUpWinSock()
{
static bool isInitialized = false;
if (isInitialized)
{
return 0;
}
WSADATA wsaData;
int error = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (error != 0)
{
SDV_LOG_ERROR("WSAStartup failed with error: ", std::to_string(error));
}
else
{
SDV_LOG_INFO("WSAStartup initialized");
isInitialized = true;
}
return error;
}
/**
* @brief Holds to sockets.
* Used by the core process to create a connection between to shild processes
*/
struct SocketConnection
{
SOCKET From{ INVALID_SOCKET }; ///< socket from child process
SOCKET To{ INVALID_SOCKET }; ///< socket to child process
};
/**
* @brief IPC channel management class for the shared memory communication.
*/
class CSocketsChannelMgnt : public sdv::CSdvObject, public sdv::IObjectControl, public sdv::ipc::ICreateEndpoint,
public sdv::ipc::IChannelAccess
{
public:
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(sdv::IObjectControl)
SDV_INTERFACE_ENTRY(sdv::ipc::IChannelAccess)
SDV_INTERFACE_ENTRY(sdv::ipc::ICreateEndpoint)
END_SDV_INTERFACE_MAP()
// Object declarations
DECLARE_OBJECT_CLASS_TYPE(sdv::EObjectType::SystemObject)
DECLARE_OBJECT_CLASS_NAME("DefaultSocketsChannelControl")
DECLARE_OBJECT_CLASS_ALIAS("RemoteChannelControl")
DECLARE_DEFAULT_OBJECT_NAME("RemoteChannelControl")
DECLARE_OBJECT_SINGLETON()
/**
* @brief Initialize the object. Overload of sdv::IObjectControl::Initialize.
* @param[in] ssObjectConfig Optional configuration string.
*/
void Initialize(const sdv::u8string& ssObjectConfig) override;
/**
* @brief Get the current status of the object. Overload of sdv::IObjectControl::GetStatus.
* @return Return the current status of the object.
*/
sdv::EObjectStatus GetStatus() const override;
/**
* @brief Set the component operation mode. Overload of sdv::IObjectControl::SetOperationMode.
* @param[in] eMode The operation mode, the component should run in.
*/
void SetOperationMode(sdv::EOperationMode eMode) override;
/**
* @brief Shutdown called before the object is destroyed. Overload of sdv::IObjectControl::Shutdown.
*/
void Shutdown() override;
/**
* @brief Create IPC connection object and return the endpoint information. Overload of
* sdv::ipc::ICreateEndpoint::CreateEndpoint.
* @details The endpoints are generated using either a size and a name based on the interface and port number provided through
* the channel configuration or if no configuration is supplied a randomly generated size and name. The following configuration
* can be supplied:
* @code
* [IpcChannel]
* Interface = "127.0.0.1"
* Port = 2000
* @endcode
* @param[in] ssChannelConfig Optional channel type specific endpoint configuration.
* @return IPC connection object
*/
sdv::ipc::SChannelEndpoint CreateEndpoint(/*in*/ const sdv::u8string& ssChannelConfig) override;
/**
* @brief Create a connection object from the channel connection parameters string
* @param[in] ssConnectString Reference to the string containing the channel connection parameters.
* @return Pointer to IInterfaceAccess interface of the connection object or NULL when the object cannot be created.
*/
sdv::IInterfaceAccess* Access(const sdv::u8string& ssConnectString) override;
private:
/**
* @brief Creates a listen socket without setting the port and configured the socket to return directly without
* blocking. No blocking access when data is received. Therefore any receive function must use polling
* @return Returns the listen socket
*/
SOCKET CreateSocket(const addrinfo& hints);
/**
* @brief get port number of a given socket
* @param[in] socket the port number is requested
* @return Returns the port number of the socket
*/
uint16_t GetPort(SOCKET socket) const;
SocketConnection CreateConnectedSocketPair();
SOCKET Listen(const addrinfo& hints, uint32_t port);
SOCKET CreateAndConnectToSocket(const addrinfo& hints, const char* defaultHost, const char* defaultPort);
/**
* @brief Creates an own socket and connects to an existing socket
* @param[in] hints The CAddrInfo structure to create the socket.
* @param[in] hostName host name.
* @param[in] portName port name.
* @return Returns an socket
*/
SOCKET CreateAndConnectToExistingSocket(const addrinfo& hints, const char* hostName, const char* portName);
inline static const addrinfo getHints
{
[]() constexpr {
addrinfo hints{0, 0, 0, 0, 0, nullptr, nullptr, nullptr};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
hints.ai_next = nullptr;
return hints;
}()
};
sdv::EObjectStatus m_eObjectStatus = sdv::EObjectStatus::initialization_pending; ///< Object status.
};
DEFINE_SDV_OBJECT(CSocketsChannelMgnt)
#endif // ! defined CHANNEL_MGNT_H

View File

@@ -1,353 +0,0 @@
#include "connection.h"
CConnection::CConnection(SOCKET preconfiguredSocket, bool acceptConnectionRequired)
{
std::fill(std::begin(m_SendBuffer), std::end(m_SendBuffer), '\0');
std::fill(std::begin(m_ReceiveBuffer), std::end(m_ReceiveBuffer), '\0');
m_ConnectionStatus = sdv::ipc::EConnectStatus::uninitialized;
m_ConnectionSocket = preconfiguredSocket;
m_AcceptConnectionRequired = acceptConnectionRequired;
}
int32_t CConnection::Send(const char* data, int32_t dataLength)
{
int32_t bytesSent = send(m_ConnectionSocket, data, dataLength, 0);
if (bytesSent == SOCKET_ERROR)
{
SDV_LOG_ERROR("send failed with error: ", std::to_string(WSAGetLastError()));
m_ConnectionStatus = sdv::ipc::EConnectStatus::communication_error;
m_ConnectionSocket = INVALID_SOCKET;
}
return bytesSent;
}
bool CConnection::SendData(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqData)
{
static uint32_t msgId = 0;
msgId++;
size_t requiredSize = 0;
std::for_each(seqData.cbegin(),
seqData.cend(),
[&](const sdv::pointer<uint8_t>& rBuffer) { requiredSize += rBuffer.size(); });
std::unique_lock<std::recursive_mutex> lock(m_SendMutex);
uint32_t packageNumber = 1;
SMsgHeader msgHeader;
msgHeader.msgStart = m_MsgStart;
msgHeader.msgEnd = m_MsgEnd;
msgHeader.msgId = msgId;
msgHeader.msgSize = static_cast<uint32_t>(requiredSize);
msgHeader.packetNumber = packageNumber;
msgHeader.totalPacketCount = static_cast<uint32_t>((requiredSize + m_SendMessageSize - 1) / m_SendMessageSize);
memcpy_s(&m_SendBuffer[0], m_SendBufferSize, &msgHeader, sizeof(msgHeader));
uint32_t offsetBuffer = sizeof(SMsgHeader);
std::for_each(seqData.cbegin(),
seqData.cend(),
[&](const sdv::pointer<uint8_t>& rBuffer)
{
uint32_t offsetData = 0;
while (rBuffer.size() > offsetData)
{
if (offsetBuffer == 0)
{
msgHeader.packetNumber = packageNumber;
memcpy_s(&m_SendBuffer[0], m_SendBufferSize, &msgHeader, sizeof(msgHeader));
offsetBuffer = sizeof(SMsgHeader);
}
auto availableBufferSize = m_SendBufferSize - offsetBuffer;
if (availableBufferSize > (rBuffer.size() - offsetData))
{
// fragments fits in buffer, go to next fragment without sending
memcpy_s(&m_SendBuffer[offsetBuffer],
availableBufferSize,
rBuffer.get() + offsetData,
rBuffer.size() - offsetData);
offsetBuffer += (static_cast<uint32_t>(rBuffer.size()) - offsetData);
break;
}
else
{
// fragments exceeds buffer, fill buffer, send buffer, keep fragment
memcpy_s(&m_SendBuffer[offsetBuffer],
availableBufferSize,
rBuffer.get() + offsetData,
availableBufferSize);
Send(m_SendBuffer, static_cast<int>(m_SendBufferSize));
offsetData += (static_cast<uint32_t>(availableBufferSize));
offsetBuffer = 0;
packageNumber++;
}
}
});
if (0 != offsetBuffer)
{
Send(m_SendBuffer, static_cast<int>(offsetBuffer));
}
return true;
}
SOCKET CConnection::AcceptConnection()
{
SOCKET clientSocket{INVALID_SOCKET};
int32_t attempt = 0;
while (clientSocket == INVALID_SOCKET)
{
clientSocket = accept(m_ConnectionSocket, NULL, NULL);
if (clientSocket == INVALID_SOCKET)
{
Sleep(2);
}
attempt++;
if (attempt > 2000)
{
SDV_LOG_ERROR("Accept socket failed, loop exeeded.");
m_ConnectionStatus = sdv::ipc::EConnectStatus::connection_error;
m_ConnectionSocket = INVALID_SOCKET;
break;
}
}
return clientSocket;
}
bool CConnection::AsyncConnect(sdv::IInterfaceAccess* pReceiver)
{
m_ConnectionStatus = sdv::ipc::EConnectStatus::initializing;
if (m_AcceptConnectionRequired)
{
m_ConnectionSocket = AcceptConnection();
}
if (m_ConnectionSocket == INVALID_SOCKET)
{
m_ConnectionStatus = sdv::ipc::EConnectStatus::connection_error;
return false;
}
m_pReceiver = sdv::TInterfaceAccessPtr(pReceiver).GetInterface<sdv::ipc::IDataReceiveCallback>();
m_pEvent = sdv::TInterfaceAccessPtr(pReceiver).GetInterface<sdv::ipc::IConnectEventCallback>();
m_ReceiveThread = std::thread(std::bind(&CConnection::ReceiveMessages, this));
m_ConnectionStatus = sdv::ipc::EConnectStatus::connected;
// TODO: Connection negotiation didn't take place... implement this!
return true;
}
bool CConnection::WaitForConnection(/*in*/ uint32_t /*uiWaitMs*/)
{
if (m_ConnectionStatus == sdv::ipc::EConnectStatus::connected) return true;
// TODO: Implementation here!
// TODO: Suppress static code analysis while there is no implementation yet.
// cppcheck-suppress identicalConditionAfterEarlyExit
return m_ConnectionStatus == sdv::ipc::EConnectStatus::connected;
}
void CConnection::CancelWait()
{
// TODO: Implementation here!
}
void CConnection::Disconnect()
{
// TODO: Implementation here!
}
uint64_t CConnection::RegisterStatusEventCallback(/*in*/ sdv::IInterfaceAccess* /*pEventCallback*/)
{
// TODO: Implementation here!
return 0;
}
void CConnection::UnregisterStatusEventCallback(/*in*/ uint64_t /*uiCookie*/)
{
// TODO: Implementation here!
}
sdv::ipc::EConnectStatus CConnection::GetStatus() const
{
return m_ConnectionStatus;
}
void CConnection::DestroyObject()
{
m_StopReceiveThread = true;
if (m_ReceiveThread.joinable())
{
m_ReceiveThread.join();
}
closesocket(m_ConnectionSocket);
m_ConnectionSocket = INVALID_SOCKET;
m_ConnectionStatus = sdv::ipc::EConnectStatus::disconnected;
delete this;
}
bool CConnection::ValidateHeader(const SMsgHeader& msgHeader)
{
if ((msgHeader.msgStart == m_MsgStart) && (msgHeader.msgEnd == m_MsgEnd))
{
if (msgHeader.msgSize != 0)
{
return true;
}
}
return false;
}
bool CConnection::ReadNumberOfBytes(char* buffer, uint32_t bufferLength)
{
uint32_t bytesReceived = 0;
while (!m_StopReceiveThread && (bufferLength > bytesReceived))
{
bytesReceived += recv(m_ConnectionSocket, buffer + bytesReceived, bufferLength - bytesReceived, 0);
if (bytesReceived == static_cast<uint32_t>(SOCKET_ERROR))
{
auto error = WSAGetLastError();
if (error != WSAEWOULDBLOCK)
{
if(error == WSAECONNRESET)
{
SDV_LOG_INFO("Reset SOCKET, recv() failed with error: ", error, " ", m_StopReceiveThread);
m_ConnectionStatus = sdv::ipc::EConnectStatus::disconnected;
m_ConnectionSocket = INVALID_SOCKET;
break;
}
else if (!m_StopReceiveThread)
{
SDV_LOG_ERROR("SOCKET_ERROR, recv() failed with error: ", error);
m_ConnectionStatus = sdv::ipc::EConnectStatus::communication_error;
m_ConnectionSocket = INVALID_SOCKET;
break;
}
}
bytesReceived = 0;
}
}
if (bufferLength != bytesReceived)
{
if (!m_StopReceiveThread || (m_ConnectionStatus == sdv::ipc::EConnectStatus::disconnected))
{
SDV_LOG_INFO("The expected bytes could not be received.");
}
return false;
}
return true;
}
bool CConnection::ReadMessageHeader(uint32_t& msgSize, uint32_t& msgId, uint32_t& packageNumber, uint32_t& totalPackageCount, bool verifyHeader)
{
SMsgHeader msgHeader;
if (ReadNumberOfBytes(reinterpret_cast<char*>(&msgHeader), sizeof(SMsgHeader)))
{
if (ValidateHeader(msgHeader))
{
if (!verifyHeader)
{
if (msgHeader.msgSize == 0)
{
return false;
}
msgSize = msgHeader.msgSize;
msgId = msgHeader.msgId;
packageNumber = msgHeader.packetNumber;
totalPackageCount = msgHeader.totalPacketCount;
return true;
}
else
{
if ((msgId == msgHeader.msgId) && (packageNumber == msgHeader.packetNumber))
{
return true;
}
else
{
SDV_LOG_WARNING("Received wrong message, Id = ", std::to_string(msgHeader.msgId), " package = ",
std::to_string(packageNumber), " (expected id = ", std::to_string(msgId), " package = ", std::to_string(packageNumber), ")");
}
}
}
else
{
if (!m_StopReceiveThread)
{
SDV_LOG_WARNING("Could not read message header");
}
}
}
return false;
}
void CConnection::ReceiveMessages()
{
while (!m_StopReceiveThread && (m_ConnectionSocket != INVALID_SOCKET))
{
uint32_t messageSize{ 0 };
uint32_t msgId{ 0 };
uint32_t packageNumber{ 0 };
uint32_t totalPackageCount{ 0 };
if (ReadMessageHeader(messageSize, msgId, packageNumber, totalPackageCount, false))
{
uint32_t dataOffset{ 0 };
sdv::pointer<uint8_t> message;
message.resize(messageSize);
for (uint32_t package = 1; package <= totalPackageCount; package++)
{
uint32_t bytesToBeRead = m_SendMessageSize;
if (package == totalPackageCount)
{
bytesToBeRead = messageSize - dataOffset; // last package
}
if (package != 1)
{
if (!ReadMessageHeader(messageSize, msgId, package, totalPackageCount, true))
{
m_ConnectionStatus = sdv::ipc::EConnectStatus::communication_error;
m_ConnectionSocket = INVALID_SOCKET;
break;
}
}
if (!ReadNumberOfBytes(reinterpret_cast<char*>(message.get()) + dataOffset, bytesToBeRead))
{
m_ConnectionStatus = sdv::ipc::EConnectStatus::communication_error;
m_ConnectionSocket = INVALID_SOCKET;
break;
}
dataOffset += bytesToBeRead;
}
if (!m_StopReceiveThread && (m_pReceiver != nullptr) && (m_ConnectionSocket != INVALID_SOCKET)) // In case of shutdown the message maybe invalid/incomplete
{
//m_pReceiver->ReceiveData(message);
}
}
else
{
Sleep(1);
}
}
}

View File

@@ -1,204 +0,0 @@
/**
* @file connection.h
* @author Sudipta Babu Durjoy FRD DISS21 (mailto:sudipta.durjoy@zf.com)
* @brief
* @version 1.0
* @date 2023-04-18
*
* @copyright Copyright ZF Friedrichshafen AG (c) 2023
*
*/
#ifndef CHANNEL_H
#define CHANNEL_H
#include <thread>
#include <algorithm>
#include <interfaces/ipc.h>
#include <support/interface_ptr.h>
#include <support/local_service_access.h>
#include <support/component_impl.h>
#ifdef _MSC_VER
#pragma comment(lib, "Ws2_32.lib")
#endif
constexpr uint32_t m_MsgStart = 0x01020304; ///< value to mark the start of the message header
constexpr uint32_t m_MsgEnd = 0x05060708; ///< value to mark the end of the message header
/**
* @brief Message header which will be put before a message.
* Can be used for validation and includes complete size of the message. Other values are not used yet
*/
struct SMsgHeader
{
uint32_t msgStart = 0; ///< marker for the start of the header
uint32_t msgId = 0; ///< message Id, must match for all message packages
uint32_t msgSize = 0; ///< size of the message without the header
uint32_t packetNumber = 0; ///< number of the package starting with 1
uint32_t totalPacketCount = 0; ///< total number of paackes required for the message
uint32_t msgEnd = 0; ///< marker for the end of the header
};
/**
* Class for remote IPC connection
* Created and managed by IPCAccess::AccessRemoveIPCConnection(best use unique_ptr to store, so memory address stays
* valid)
*/
class CConnection : public sdv::IInterfaceAccess, public sdv::ipc::IDataSend, public sdv::ipc::IConnect, public sdv::IObjectDestroy
{
public:
/**
* @brief default constructor used by create endpoint - allocates new buffers m_Sender and m_Receiver
*/
CConnection();
/**
* @brief access existing connection
* @param[in] preconfiguredSocket Prepared socket for the connection.
* @param[in] acceptConnectionRequired If true connection has to be accepted before receive thread can be started.
*/
CConnection(SOCKET preconfiguredSocket, bool acceptConnectionRequired);
/**
* @brief Virtual destructor needed for "delete this;".
*/
virtual ~CConnection() = default;
BEGIN_SDV_INTERFACE_MAP()
SDV_INTERFACE_ENTRY(sdv::ipc::IDataSend)
SDV_INTERFACE_ENTRY(sdv::ipc::IConnect)
SDV_INTERFACE_ENTRY(sdv::IObjectDestroy)
END_SDV_INTERFACE_MAP()
/**
* @brief Sends data consisting of multiple data chunks via the IPC connection.
* Overload of sdv::ipc::IDataSend::SendData.
* @param[inout] seqData Sequence of data buffers to be sent. The sequence might be changed to optimize the communication
* without having to copy the data.
* @return Return 'true' if all data could be sent; 'false' otherwise.
*/
virtual bool SendData(/*inout*/ sdv::sequence<sdv::pointer<uint8_t>>& seqData) override;
/**
* @brief Establish a connection and start sending/receiving messages. Overload of
* sdv::ipc::IConnect::AsyncConnect.
* @param[in] pReceiver The message has to be forwarded.
* @return Returns 'true' when a connection could be established. Use IConnectStatus or IConnectEventCallback to check the
* connection state.
*/
virtual bool AsyncConnect(/*in*/ sdv::IInterfaceAccess* pReceiver) override;
/**
* @brief Wait for a connection to take place. Overload of sdv::ipc::IConnect::WaitForConnection.
* @param[in] uiWaitMs Wait for a connection to take place. A value of 0 doesn't wait at all, a value of 0xffffffff
* waits for infinite time.
* @return Returns 'true' when a connection took place.
*/
virtual bool WaitForConnection(/*in*/ uint32_t uiWaitMs) override;
/**
* @brief Cancel a wait for connection. Overload of sdv::ipc::IConnect::CancelWait.
*/
virtual void CancelWait() override;
/**
* @brief Disconnect from a connection. This will set the connect status to disconnected and release the interface
* used for the status events.
*/
virtual void Disconnect() override;
/**
* @brief Register event callback interface. Overload of sdv::ipc::IConnect::RegisterStatusEventCallback.
* @details Register a connection status event callback interface. The exposed interface must be of type
* IConnectEventCallback. The registration will exist until a call to the unregister function with the returned cookie
* or until the connection is terminated.
* @param[in] pEventCallback Pointer to the object exposing the IConnectEventCallback interface.
* @return The cookie assigned to the registration.
*/
virtual uint64_t RegisterStatusEventCallback(/*in*/ sdv::IInterfaceAccess* pEventCallback) override;
/**
* @brief Unregister the status event callback with the returned cookie from the registration. Overload of
* sdv::ipc::IConnect::UnregisterStatusEventCallback.
* @param[in] uiCookie The cookie returned by a previous call to the registration function.
*/
virtual void UnregisterStatusEventCallback(/*in*/ uint64_t uiCookie) override;
/**
* @brief Get status of the connection
* @return Returns the ipc::EConnectStatus struct
*/
virtual sdv::ipc::EConnectStatus GetStatus() const override;
/**
* @brief Destroy the object. Overload of IObjectDestroy::DestroyObject.
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
*/
virtual void DestroyObject() override;
private:
std::thread m_ReceiveThread; ///< Thread which receives data from the socket
std::atomic<bool> m_StopReceiveThread = false; ///< bool variable to stop thread
std::atomic<sdv::ipc::EConnectStatus> m_ConnectionStatus; ///< the status of the connection
SOCKET m_ConnectionSocket; ///< The socket to send and receive data
sdv::ipc::IDataReceiveCallback* m_pReceiver = nullptr; ///< Receiver to pass the messages if available
sdv::ipc::IConnectEventCallback* m_pEvent = nullptr; ///< Event receiver.
bool m_AcceptConnectionRequired; ///< if true connection has to be accepted before receive thread can be started
mutable std::recursive_mutex m_SendMutex; ///< Synchronize all packages to be send.
static constexpr uint32_t m_SendMessageSize{ 1024 }; ///< size for the message to be send.
static constexpr uint32_t m_SendBufferSize = sizeof(SMsgHeader) + m_SendMessageSize; ///< Initial size of the send buffer.
char m_SendBuffer[m_SendBufferSize]; ///< send buffer length
char m_ReceiveBuffer[sizeof(SMsgHeader)]; ///< receive buffer, just for reading the message header
uint32_t m_ReceiveBufferLength = sizeof(SMsgHeader); ///< receive buffer length
/**
* @brief Function to accept the connection to the client.
* @return Returns the socket to receive data
*/
SOCKET AcceptConnection();
/**
* @brief Send data function via socket.
* @param[in] data to be send
* @param[in] dataLength size of the data to be sent
* @return Returns number of bytes which has been sent
*/
int32_t Send(const char* data, int32_t dataLength);
/**
* @brief Function to receive data, runs in a thread
*/
void ReceiveMessages();
/**
* @brief Validates the header of the message to determine if message is valid
* @param[in] msgHeader filled message header structure
* @return true if valid header was found, otherwise false
*/
bool ValidateHeader(const SMsgHeader& msgHeader);
/**
* @brief read header and get the values from the header. In case verify == true validate the input values
* @param[in] msgSize size of the message without headers
* @param[in] msgId message id of the message
* @param[in] packageNumber package number of the message
* @param[in] totalPackageCount number of packages the message requires
* @param[in] verifyHeader If true verify that the input of msgId and packageNumber match the header values
* @return if verify == false, return true if a valid header can be read.
* if verify == true input values of msdId and package number must match with the header values.
*/
bool ReadMessageHeader(uint32_t &msgSize, uint32_t &msgId, uint32_t &packageNumber, uint32_t &totalPackageCount, bool verifyHeader);
/**
* @brief read number of bytes and write them to the given buffer
* @param[in] buffer Buffer the data is stored
* @param[in] length of the buffer to be filled
* @return return true if the number of bytes can be read, otherwise false
*/
bool ReadNumberOfBytes(char* buffer, uint32_t length);
};
#endif // !define CHANNEL_H