init
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
PROJECT(openvibe-module-communication)
|
||||
|
||||
INCLUDE_DIRECTORIES("include/communication/")
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.hpp include/*.h include/*.hpp)
|
||||
|
||||
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
|
||||
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${MODULES_FOLDER}
|
||||
COMPILE_FLAGS "-DCommunication_Shared -DCommunication_Exports")
|
||||
|
||||
ADD_LIBRARY(${PROJECT_NAME}-static STATIC ${SRC_FILES})
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${MODULES_FOLDER}
|
||||
COMPILE_FLAGS "-DCommunication_Static -DCommunication_Exports")
|
||||
|
||||
IF(UNIX)
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES COMPILE_FLAGS "-fPIC")
|
||||
ENDIF(UNIX)
|
||||
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEModuleSocket")
|
||||
|
||||
SET_BUILD_PLATFORM()
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
INSTALL(TARGETS ${PROJECT_NAME}-static
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
|
||||
INSTALL(DIRECTORY include/ DESTINATION ${DIST_INCLUDEDIR})
|
||||
|
||||
# Link the socket library to the static version of lib-communication
|
||||
|
||||
SET(PROJECT_NAME ${PROJECT_NAME}-static)
|
||||
SET(DYNAMIC_LINK_OPENVIBE_SDK false)
|
||||
INCLUDE("FindOpenViBEModuleSocket")
|
||||
|
||||
|
||||
#add_subdirectory(test)
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <ov_common_defines.h>
|
||||
|
||||
#if defined Communication_Shared
|
||||
# if defined TARGET_OS_Windows
|
||||
# define Communication_API_Export __declspec(dllexport)
|
||||
# define Communication_API_Import __declspec(dllimport)
|
||||
# elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
# define Communication_API_Export __attribute__((visibility("default")))
|
||||
# define Communication_API_Import __attribute__((visibility("default")))
|
||||
# else
|
||||
# define Communication_API_Export
|
||||
# define Communication_API_Import
|
||||
# endif
|
||||
#else
|
||||
# define Communication_API_Export
|
||||
# define Communication_API_Import
|
||||
#endif
|
||||
|
||||
#if defined Communication_Exports
|
||||
# define Communication_API Communication_API_Export
|
||||
#else
|
||||
# define Communication_API Communication_API_Import
|
||||
#endif
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
#pragma once
|
||||
|
||||
#include <socket/IConnection.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "ovCMessagingProtocol.h"
|
||||
|
||||
namespace Communication {
|
||||
/**
|
||||
* \brief The purpose of this class is to provide a communication protocol to exchange EBML between a client and a server.
|
||||
*/
|
||||
class Communication_API CMessaging
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Library error codes
|
||||
*/
|
||||
enum ELibraryError
|
||||
{
|
||||
NoError = 0,
|
||||
Socket_NotConnected = 1,
|
||||
Socket_FailedToConnect = 2,
|
||||
Socket_ReceiveBufferFail = 3,
|
||||
Socket_SendBufferFail = 4,
|
||||
Socket_NoIncomingClientConnection = 6,
|
||||
Socket_NotReadyToSend = 7,
|
||||
Socket_NoDataReceived = 8,
|
||||
Socket_FailedCloseClientConnection = 10,
|
||||
Socket_FailedToCloseConnection = 11,
|
||||
Socket_FailedConnectClient = 12,
|
||||
Socket_ClientAlreadyConnected = 13,
|
||||
Deserialize_BufferTooSmall = 30,
|
||||
Deserialize_Header = 31,
|
||||
Deserialize_ProtocolVersionMessage = 32,
|
||||
Deserialize_BoxDescriptionMessage = 33,
|
||||
Deserialize_EBMLMessage = 34,
|
||||
Deserialize_EndMessage = 35,
|
||||
Deserialize_ErrorMessage = 36,
|
||||
Deserialize_LogMessage = 37,
|
||||
Deserialize_AuthenticationMessage = 38,
|
||||
Deserialize_MessageTypeNotSupported = 39,
|
||||
BoxDescriptionAlreadyReceived = 60,
|
||||
BoxDescriptionNotReceived = 61,
|
||||
BadAuthenticationReceived = 70,
|
||||
NoAuthenticationReceived = 71,
|
||||
ThreadJoinFailed = 80
|
||||
};
|
||||
|
||||
CMessaging();
|
||||
virtual ~CMessaging();
|
||||
|
||||
/**
|
||||
* \brief Get the code of the last error produced by the API
|
||||
*
|
||||
* \retval Error code
|
||||
*/
|
||||
ELibraryError getLastError() const;
|
||||
|
||||
/**
|
||||
* \brief Give a short description of an error.
|
||||
*
|
||||
* \param error the error code
|
||||
*
|
||||
* \return Description of the error.
|
||||
*/
|
||||
static std::string getErrorString(ELibraryError error);
|
||||
|
||||
/**
|
||||
* \brief Check that the socket is connected.
|
||||
*
|
||||
* \retval True if the socket is connected.
|
||||
* \retval False if the socket is not connected.
|
||||
*/
|
||||
bool isConnected() const;
|
||||
|
||||
/**
|
||||
* \brief Check that the synchronization is in error state.
|
||||
*
|
||||
* \retval True if the synchronization is in error state.
|
||||
* \retval False if the synchronization is ok.
|
||||
*/
|
||||
bool isInErrorState() const;
|
||||
|
||||
/**
|
||||
* \brief Set the connection ID to a new value
|
||||
* \param connectionID The connection Id to set
|
||||
*/
|
||||
void setConnectionID(const std::string& connectionID) const;
|
||||
|
||||
/**
|
||||
* \brief Check that a End message was received.
|
||||
*
|
||||
* \retval True if the end message from the client is received.
|
||||
* \retval False if the end message from the client is not received.
|
||||
*/
|
||||
virtual bool isEndReceived();
|
||||
|
||||
/**
|
||||
* \brief Get the time.
|
||||
*/
|
||||
virtual uint64_t getTime();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief Push a message to the send buffer.
|
||||
* The message will be really sent in the socket in the next synchronization.
|
||||
*
|
||||
* \param message The message to send.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if library is in error state.
|
||||
*/
|
||||
bool pushMessage(const Message& message) const;
|
||||
|
||||
/**
|
||||
* \brief Set the last error code.
|
||||
*
|
||||
* \param libraryError The error
|
||||
*
|
||||
* \sa getLastError
|
||||
*/
|
||||
void setLastError(ELibraryError libraryError) const;
|
||||
|
||||
/**
|
||||
* \brief Provide the connection to the base class to communicate.
|
||||
*
|
||||
* \param connection The connection
|
||||
*/
|
||||
void setConnection(Socket::IConnection* connection) const;
|
||||
|
||||
/**
|
||||
* \brief Start a thread that will push the outgoing data, pull and process the incoming data.
|
||||
* This sync will be stopped in cases:
|
||||
* - An error raised
|
||||
* - stopSyncing() function was called.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
*
|
||||
* \sa stopSyncing
|
||||
*/
|
||||
bool startSyncing();
|
||||
|
||||
/**
|
||||
* \brief Request to stop the sync and stop the thread.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
*
|
||||
* \sa startSyncing
|
||||
*/
|
||||
bool stopSyncing() const;
|
||||
|
||||
/**
|
||||
* @brief Get the oldest authentication message
|
||||
* @param id[out] Identifier of the message
|
||||
* @param connectionID[out] Connection Id
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popAuthentication(uint64_t& id, std::string& connectionID);
|
||||
|
||||
/**
|
||||
* @brief Get the oldest box description message
|
||||
* @param id[out] Identifier of the message
|
||||
* @param boxDescription[out] Descriptor of the box
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popBoxDescriptions(uint64_t& id, BoxDescriptionMessage& boxDescription);
|
||||
|
||||
/**
|
||||
* @brief popCommunicationProtocolVersion
|
||||
* @param id[out] Identifier of the message
|
||||
* @param majorVersion[out] major version of the protocol
|
||||
* @param minorVersion[out] minor version of the protocol
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popCommunicationProtocolVersion(uint64_t& id, uint8_t& majorVersion, uint8_t& minorVersion);
|
||||
|
||||
/**
|
||||
* @brief Pop the oldest EBML message from the queue
|
||||
* @param id[out] Identifier of the message
|
||||
* @param index[out] Input index to which the EBML should be directed
|
||||
* @param startTime[out] Start time of the buffer
|
||||
* @param endTime[out] End time of the buffer
|
||||
* @param ebml[out] The encoded EBML buffer
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popEBML(uint64_t& id, size_t& index, uint64_t& startTime, uint64_t& endTime, std::shared_ptr<const std::vector<uint8_t>>& ebml);
|
||||
|
||||
/**
|
||||
* @brief Pop the oldest log message from the queue
|
||||
* @param id[out] Identifier of the message
|
||||
* @param type[out] Log level of the message
|
||||
* @param message[out] Message text
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popLog(uint64_t& id, ELogLevel& type, std::string& message);
|
||||
|
||||
/**
|
||||
* @brief Pop the oldest error message from the queue
|
||||
* @param id[out] Identifier of the message
|
||||
* @param type[out] Error code
|
||||
* @param guiltyId[out] If of the sent message that caused this error
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popError(uint64_t& id, EError& type, uint64_t& guiltyId);
|
||||
|
||||
/**
|
||||
* @brief Get the oldes End message
|
||||
* @param id[out] Identifier of the message
|
||||
* @return true if a message was popped, false if the queue is empty
|
||||
*/
|
||||
virtual bool popEnd(uint64_t& id);
|
||||
|
||||
/**
|
||||
* @brief Reset the library state. Stop sending and receiving buffers, disconnect
|
||||
* and empty all buffers.
|
||||
*/
|
||||
void reset() const;
|
||||
|
||||
/**
|
||||
* \brief Checks if a sync message was received and reset it if it was.
|
||||
*
|
||||
* This method should be used in a busy loop to check if the other
|
||||
* party has finished processing all of the data.
|
||||
*
|
||||
* From the external program standpoint this method will return true
|
||||
* when the box has finished sending all of the data that has to be
|
||||
* processed in one bulk.
|
||||
*
|
||||
* From the box standpoint, this means that the external program has
|
||||
* finished processing and sending all of the data that the box has
|
||||
* sent.
|
||||
*
|
||||
* \retval True if a sync message is received.
|
||||
* \retval False if no sync message was received.
|
||||
*/
|
||||
virtual bool waitForSyncMessage();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* \brief Receive all the available data from the socket and insert it in the rcv buffer.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
* Library errors: TODO
|
||||
*
|
||||
* \sa push
|
||||
*/
|
||||
bool pull() const;
|
||||
|
||||
/**
|
||||
* \brief Send all the data to the socket.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
* Library errors:
|
||||
* - Socket_NotConnected
|
||||
*
|
||||
*
|
||||
* \sa push
|
||||
*/
|
||||
bool push() const;
|
||||
|
||||
/**
|
||||
* \brief Process incoming data, unpack it and put messages in queues.
|
||||
* It use processBuffer.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
* Library errors: Error from processBuffer
|
||||
*
|
||||
* \sa processBuffer
|
||||
*/
|
||||
bool processIncomingMessages() const;
|
||||
|
||||
/**
|
||||
* \brief Process buffer, pack it and put messages in queues.
|
||||
*
|
||||
* \param buffer Buffer with the incoming serialized data.
|
||||
* \param[out] byteRead Number of bytes read and processed.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
* Library errors:
|
||||
* - Deserialize_Header
|
||||
* - Deserialize_AuthenticationMessage
|
||||
* - Deserialize_ProtocolVersionMessage
|
||||
* - Deserialize_BoxDescriptionMessage
|
||||
* - Deserialize_EBMLMessage
|
||||
* - Deserialize_LogMessage
|
||||
* - Deserialize_ErrorMessage
|
||||
* - Deserialize_MessageTypeNotSupported
|
||||
*
|
||||
* \sa processIncomingMessages
|
||||
*/
|
||||
bool processBuffer(const std::vector<uint8_t>& buffer, size_t& byteRead) const;
|
||||
|
||||
/**
|
||||
* \brief Sync fucntion that is used in a thread to pull, push and process the incoming data.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an error occured.
|
||||
* Library errors: Errors from processIncomingMessages(), push() or pull()
|
||||
*
|
||||
* \sa pull
|
||||
* \sa push
|
||||
* \sa processIncomingMessages
|
||||
*/
|
||||
void sync() const;
|
||||
|
||||
public:
|
||||
static const uint8_t s_CommunicationProtocol_MajorVersion = 1;
|
||||
static const uint8_t s_CommunicationProtocol_MinorVersion = 1;
|
||||
|
||||
protected:
|
||||
struct SMessagingImpl;
|
||||
SMessagingImpl* impl = nullptr;
|
||||
};
|
||||
} // namespace Communication
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
#pragma once
|
||||
|
||||
#include "defines.h"
|
||||
#include "ovCMessaging.h"
|
||||
|
||||
#include "socket/IConnectionClient.h"
|
||||
|
||||
namespace Communication {
|
||||
class Communication_API MessagingClient : public CMessaging
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
*/
|
||||
MessagingClient();
|
||||
|
||||
/**
|
||||
* \brief Destructor.
|
||||
*/
|
||||
~MessagingClient() override;
|
||||
|
||||
/**
|
||||
* \brief Connect to a server.
|
||||
*
|
||||
* \param uri URI of the server.
|
||||
* \param port The port.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
* Library errors:
|
||||
* - FailedToConnect
|
||||
* - NotConnected
|
||||
* - NotReadyToSend
|
||||
*
|
||||
* \sa close
|
||||
*/
|
||||
bool connect(const std::string& uri, const size_t port);
|
||||
|
||||
/**
|
||||
* \brief Closes the connection to the server.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
* Library errors:
|
||||
* - NotConnected
|
||||
* - FailedToCloseConnection
|
||||
*
|
||||
* \sa getLastError
|
||||
*/
|
||||
bool close() const;
|
||||
|
||||
/**
|
||||
* \brief Return the number of box information's parameters available.
|
||||
*
|
||||
* \return The number of parameters available.
|
||||
*
|
||||
* \sa getParameter
|
||||
*/
|
||||
size_t getParameterCount() const;
|
||||
|
||||
/**
|
||||
* \brief Return the number of box information's input available.
|
||||
*
|
||||
* \return The number of input available.
|
||||
*
|
||||
* \sa getInput
|
||||
*/
|
||||
size_t getInputCount() const;
|
||||
|
||||
/**
|
||||
* \brief Return the number of output of the box information, available.
|
||||
*
|
||||
* \return The number of output available.
|
||||
*
|
||||
* \sa getOutput
|
||||
*/
|
||||
size_t getOutputCount() const;
|
||||
|
||||
/**
|
||||
* \brief Get parameter information.
|
||||
*
|
||||
* \param i The index.
|
||||
* \param[out] id The id
|
||||
* \param[out] type The type (corresponding to the OpenViBE CIdentifier)
|
||||
* \param[out] name Name
|
||||
* \param[out] value Value (to convert accordinf to the type)
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the index is out of range.
|
||||
*/
|
||||
bool getParameter(size_t i, uint64_t& id, uint64_t& type, std::string& name, std::string& value) const;
|
||||
|
||||
/**
|
||||
* \brief Get input information.
|
||||
*
|
||||
* \param i The index.
|
||||
* \param[out] id The id
|
||||
* \param[out] type The type (corresponding to the OpenViBE CIdentifier)
|
||||
* \param[out] name Name
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the index is out of range.
|
||||
*
|
||||
* \sa getInputCount
|
||||
*/
|
||||
bool getInput(size_t i, uint64_t& id, uint64_t& type, std::string& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get input information.
|
||||
*
|
||||
* \param i The index.
|
||||
* \param[out] id The id
|
||||
* \param[out] type The type (corresponding to the OpenViBE CIdentifier)
|
||||
* \param[out] name Name
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the index is out of range.
|
||||
*
|
||||
* \sa getOutputCount
|
||||
*/
|
||||
bool getOutput(size_t i, uint64_t& id, uint64_t& type, std::string& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get the oldest error message, if available.
|
||||
*
|
||||
* \param packetId
|
||||
* \param[out] type The error's type.
|
||||
* \param[out] guiltyId Identifier of the guilty message
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
*/
|
||||
bool popError(uint64_t& packetId, EError& type, uint64_t& guiltyId) override;
|
||||
|
||||
/**
|
||||
* \brief Get the oldest EBML message, if available.
|
||||
*
|
||||
* \param packetId
|
||||
* \param[out] index Box input index.
|
||||
* \param[out] startTime The start time.
|
||||
* \param[out] endTime The end time.
|
||||
* \param[out] ebml The EBML vector.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
*/
|
||||
bool popEBML(uint64_t& packetId, size_t& index, uint64_t& startTime, uint64_t& endTime, std::shared_ptr<const std::vector<uint8_t>>& ebml) override;
|
||||
|
||||
/**
|
||||
* \brief Push a log message to the server.
|
||||
*
|
||||
* \param logLevel The log level.
|
||||
* \param log The log string message.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
* Library errors:
|
||||
* - NotConnected
|
||||
* - NotReadyToSend
|
||||
*
|
||||
* \sa getLastError
|
||||
*/
|
||||
bool pushLog(ELogLevel logLevel, const std::string& log) const;
|
||||
|
||||
/**
|
||||
* \brief Pushes an ebml.
|
||||
*
|
||||
* \param index Index of the box output.
|
||||
* \param startTime The start time.
|
||||
* \param endTime The endtime.
|
||||
* \param ebml The ebml vector.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
* Library errors:
|
||||
* - NotConnected
|
||||
* - NotReadyToSend
|
||||
*
|
||||
* \sa getLastError
|
||||
*/
|
||||
bool pushEBML(size_t index, uint64_t startTime, uint64_t endTime, const std::shared_ptr<const std::vector<uint8_t>>& ebml) const;
|
||||
|
||||
/**
|
||||
* \brief Push Sync message to the server.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool pushSync() const;
|
||||
|
||||
/**
|
||||
* \brief Check if a sync message is received.
|
||||
*
|
||||
* \retval True if a sync message is received.
|
||||
* \retval False if no sync message was received.
|
||||
*/
|
||||
bool waitForSyncMessage() override;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* \brief Pushes an authentication message).
|
||||
*
|
||||
* \param connectionID The connection identifier.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False there is no available error.
|
||||
* Library errors:
|
||||
* - NotConnected
|
||||
* - NotReadyToSend
|
||||
*/
|
||||
bool pushAuthentication(const std::string& connectionID) const;
|
||||
|
||||
Socket::IConnectionClient* m_Client = nullptr;
|
||||
bool m_BoxDescriptionReceived = false;
|
||||
};
|
||||
} // namespace Communication
|
||||
+424
@@ -0,0 +1,424 @@
|
||||
#pragma once
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <limits>
|
||||
|
||||
namespace Communication {
|
||||
/**
|
||||
* \brief Log level used by the client to log information in the server side
|
||||
*/
|
||||
enum ELogLevel : uint8_t
|
||||
{
|
||||
LogLevel_Info = 1,
|
||||
LogLevel_Warning = 2,
|
||||
LogLevel_Error = 3,
|
||||
LogLevel_Fatal = 4,
|
||||
LogLevel_Max = 5,
|
||||
LogLevel_Unknown = 0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Values that represent errors.
|
||||
*/
|
||||
enum EError : uint16_t
|
||||
{
|
||||
Error_AuthenticationFail = 1,
|
||||
Error_AuthenticationRequested = 2,
|
||||
Error_InvalidOutputIndex = 3,
|
||||
Error_BadCommunicationProtocol = 4,
|
||||
Error_InvalidEBML = 5,
|
||||
Error_InvalidLogLevel = 6,
|
||||
Error_InvalidMessageType = 7,
|
||||
Error_BadMessage = 8,
|
||||
Error_Max = 9,
|
||||
Error_Unknown = 0xFF
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Message type
|
||||
*/
|
||||
enum EMessageType : uint8_t
|
||||
{
|
||||
MessageType_Authentication = 0,
|
||||
MessageType_ProtocolVersion = 1,
|
||||
MessageType_BoxInformation = 2,
|
||||
MessageType_EBML = 3,
|
||||
MessageType_Log = 4,
|
||||
MessageType_End = 5,
|
||||
MessageType_Error = 6,
|
||||
MessageType_Time = 7,
|
||||
MessageType_Sync = 8,
|
||||
MessageType_Max = 9,
|
||||
|
||||
MessageType_Unknown = 0xFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A packet part is a part of a packet compound by an Header and a Message.
|
||||
*/
|
||||
class Communication_API CPacketPart
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CPacketPart() {}
|
||||
|
||||
/**
|
||||
* \brief Provide array of bytes that represent the object.
|
||||
*
|
||||
* \return A vector with the serialized information of the message that respect the communication protocol.
|
||||
*
|
||||
* \sa fromBytes
|
||||
*/
|
||||
virtual std::vector<uint8_t> toBytes() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Transform bytes vector into an object.
|
||||
*
|
||||
* \param buffer The buffer.
|
||||
* \param [in,out] bufferIndex Zero-based index of the buffer.
|
||||
*
|
||||
* \retval True if it succeeds
|
||||
* \retval False if it fails.
|
||||
*
|
||||
* \sa toBytes
|
||||
*/
|
||||
virtual bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) = 0;
|
||||
|
||||
/**
|
||||
* \brief Query if this object is valid.
|
||||
*
|
||||
* \retval True if it is valid.
|
||||
* \retval False if it is invalid.
|
||||
*/
|
||||
bool isValid() const { return m_isValid; }
|
||||
|
||||
protected:
|
||||
bool m_isValid = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A message is the second part of a packet after the header.
|
||||
*/
|
||||
class Message : public CPacketPart
|
||||
{
|
||||
public:
|
||||
virtual EMessageType getMessageType() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A header is associated to a message. It give information about the message, like the type and the size.
|
||||
*/
|
||||
class Header final : CPacketPart
|
||||
{
|
||||
public:
|
||||
Header();
|
||||
Header(EMessageType type, uint64_t id, size_t size);
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
void setId(const uint64_t id) { m_id = id; }
|
||||
uint64_t getId() const { return m_id; }
|
||||
EMessageType getType() const { return m_type; }
|
||||
size_t getSize() const { return m_size; }
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
|
||||
private:
|
||||
EMessageType m_type;
|
||||
uint64_t m_id = 0;
|
||||
size_t m_size = 0;
|
||||
|
||||
static const size_t TYPE_SIZE = sizeof(EMessageType);
|
||||
static const size_t ID_SIZE = sizeof(uint64_t);
|
||||
static const size_t SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t TYPE_INDEX = 0;
|
||||
static const size_t ID_INDEX = TYPE_INDEX + TYPE_SIZE;
|
||||
static const size_t SIZE_INDEX = ID_INDEX + ID_SIZE;
|
||||
static const size_t MINIMUM_SIZE = TYPE_SIZE + ID_SIZE + SIZE_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Represent an Authentication message.
|
||||
*/
|
||||
class AuthenticationMessage final : public Message
|
||||
{
|
||||
public:
|
||||
AuthenticationMessage() { m_isValid = false; }
|
||||
AuthenticationMessage(const std::string& connectionID) : m_connectionID(connectionID) { m_isValid = true; }
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
EMessageType getMessageType() const override { return MessageType_Authentication; }
|
||||
std::string getConnectionID() const { return m_connectionID; }
|
||||
|
||||
private:
|
||||
static const size_t SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t SIZE_INDEX = 0;
|
||||
static const size_t CONNECTION_ID_INDEX = SIZE_INDEX + SIZE_SIZE;
|
||||
static const size_t MINIMUM_SIZE = SIZE_SIZE;
|
||||
|
||||
std::string m_connectionID;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief This message is used to inform the server or the client about the current communication protocol version used.
|
||||
*/
|
||||
class CommunicationProtocolVersionMessage final : public Message
|
||||
{
|
||||
public:
|
||||
|
||||
CommunicationProtocolVersionMessage() { m_isValid = false; }
|
||||
|
||||
CommunicationProtocolVersionMessage(const uint8_t majorVersion, const uint8_t minorVersion) : m_minorVersion(minorVersion), m_majorVersion(majorVersion)
|
||||
{
|
||||
m_isValid = true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
EMessageType getMessageType() const override { return MessageType_ProtocolVersion; }
|
||||
uint8_t getMajorVersion() const { return m_majorVersion; }
|
||||
uint8_t getMinorVersion() const { return m_minorVersion; }
|
||||
|
||||
private:
|
||||
uint8_t m_minorVersion = 0;
|
||||
uint8_t m_majorVersion = 0;
|
||||
|
||||
static const size_t MAJOR_SIZE = sizeof(uint8_t);
|
||||
static const size_t MINOR_SIZE = sizeof(uint8_t);
|
||||
static const size_t MAJOR_INDEX = 0;
|
||||
static const size_t MINOR_INDEX = MAJOR_INDEX + MAJOR_SIZE;
|
||||
static const size_t MINIMUM_SIZE = MAJOR_SIZE + MINOR_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief InputOutput class describes the input or output of a box.
|
||||
*/
|
||||
class InputOutput final : public CPacketPart
|
||||
{
|
||||
public:
|
||||
InputOutput();
|
||||
InputOutput(uint64_t id, size_t type, const std::string& name);
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
uint64_t getId() const { return m_id; }
|
||||
size_t getType() const { return m_type; }
|
||||
std::string getName() const { return m_name; }
|
||||
|
||||
private:
|
||||
uint64_t m_id = 0;
|
||||
size_t m_type = 0;
|
||||
std::string m_name;
|
||||
|
||||
static const size_t ID_SIZE = sizeof(uint64_t);
|
||||
static const size_t TYPE_SIZE = sizeof(size_t);
|
||||
static const size_t NAME_SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t ID_INDEX = 0;
|
||||
static const size_t TYPE_INDEX = ID_INDEX + ID_SIZE;
|
||||
static const size_t NAME_SIZE_INDEX = TYPE_INDEX + TYPE_SIZE;
|
||||
static const size_t NAME_INDEX = NAME_SIZE_INDEX + NAME_SIZE_SIZE;
|
||||
static const size_t MINIMUM_SIZE = ID_SIZE + TYPE_SIZE + NAME_SIZE_SIZE;
|
||||
};
|
||||
|
||||
class Parameter final : public CPacketPart
|
||||
{
|
||||
public:
|
||||
Parameter();
|
||||
Parameter(uint64_t id, size_t type, const std::string& name, const std::string& value);
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
|
||||
uint64_t getId() const { return m_id; }
|
||||
size_t getType() const { return m_type; }
|
||||
std::string getName() const { return m_name; }
|
||||
std::string getValue() const { return m_value; }
|
||||
|
||||
private:
|
||||
uint64_t m_id = 0;
|
||||
size_t m_type = 0;
|
||||
std::string m_name;
|
||||
std::string m_value;
|
||||
|
||||
static const size_t ID_SIZE = sizeof(uint64_t);
|
||||
static const size_t TYPE_SIZE = sizeof(size_t);
|
||||
static const size_t NAME_SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t VALUE_SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t ID_INDEX = 0;
|
||||
static const size_t TYPE_INDEX = ID_INDEX + ID_SIZE;
|
||||
static const size_t NAME_SIZE_INDEX = TYPE_INDEX + TYPE_SIZE;
|
||||
static const size_t VALUE_SIZE_INDEX = NAME_SIZE_INDEX + NAME_SIZE_SIZE;
|
||||
static const size_t NAME_INDEX = VALUE_SIZE_INDEX + VALUE_SIZE_SIZE;
|
||||
static const size_t MINIMUM_SIZE = ID_SIZE + TYPE_SIZE + NAME_SIZE_SIZE + VALUE_SIZE_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief This message contains information about the box used in the NeuroRT pipeline.
|
||||
* This message is sent by the server and received by the client.
|
||||
*/
|
||||
class BoxDescriptionMessage final : public Message
|
||||
{
|
||||
public:
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
EMessageType getMessageType() const override;
|
||||
bool addInput(uint64_t id, size_t type, const std::string& name);
|
||||
bool addOutput(uint64_t id, size_t type, const std::string& name);
|
||||
bool addParameter(uint64_t id, size_t type, const std::string& name, const std::string& value);
|
||||
|
||||
const std::vector<InputOutput>* getInputs() const { return &m_inputs; }
|
||||
const std::vector<InputOutput>* getOutputs() const { return &m_outputs; }
|
||||
const std::vector<Parameter>* getParameters() const { return &m_parameters; }
|
||||
|
||||
private:
|
||||
std::vector<InputOutput> m_inputs;
|
||||
std::vector<InputOutput> m_outputs;
|
||||
std::vector<Parameter> m_parameters;
|
||||
|
||||
static const size_t N_INPUT_SIZE = sizeof(size_t);
|
||||
static const size_t N_OUTPUT_SIZE = sizeof(size_t);
|
||||
static const size_t N_PARAMETER_SIZE = sizeof(size_t);
|
||||
static const size_t N_INPUT_INDEX = 0;
|
||||
static const size_t N_OUTPUT_INDEX = N_INPUT_INDEX + N_INPUT_SIZE;
|
||||
static const size_t N_PARAMETER_INDEX = N_OUTPUT_INDEX + N_OUTPUT_SIZE;
|
||||
static const size_t MINIMUM_SIZE = N_INPUT_SIZE + N_OUTPUT_SIZE + N_PARAMETER_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Log message is a way to communicate information from the client to the server.
|
||||
*/
|
||||
class LogMessage final : public Message
|
||||
{
|
||||
public:
|
||||
LogMessage();
|
||||
LogMessage(ELogLevel type, const std::string& message);
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
|
||||
EMessageType getMessageType() const override { return MessageType_Log; }
|
||||
ELogLevel getType() const { return m_type; }
|
||||
std::string getMessage() const { return m_message; }
|
||||
|
||||
private:
|
||||
ELogLevel m_type;
|
||||
std::string m_message;
|
||||
|
||||
static const size_t TYPE_SIZE = sizeof(ELogLevel);
|
||||
static const size_t SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t TYPE_INDEX = 0;
|
||||
static const size_t SIZE_INDEX = TYPE_INDEX + TYPE_SIZE;
|
||||
static const size_t NAME_INDEX = SIZE_INDEX + SIZE_SIZE;
|
||||
static const size_t MINIMUM_SIZE = TYPE_SIZE + SIZE_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief EBML message is used to send EBML data.
|
||||
*/
|
||||
class EBMLMessage final : public Message
|
||||
{
|
||||
public:
|
||||
EBMLMessage();
|
||||
|
||||
EBMLMessage(size_t index, uint64_t startTime, uint64_t endTime, const std::shared_ptr<const std::vector<uint8_t>>& ebml);
|
||||
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
|
||||
EMessageType getMessageType() const override { return MessageType_EBML; }
|
||||
size_t getIndex() const { return m_ioIdx; }
|
||||
uint64_t getStartTime() const { return m_startTime; }
|
||||
uint64_t getEndTime() const { return m_endTime; }
|
||||
std::shared_ptr<const std::vector<uint8_t>> getEBML() const { return m_EBML; }
|
||||
|
||||
private:
|
||||
size_t m_ioIdx = 0;
|
||||
uint64_t m_startTime = 0;
|
||||
uint64_t m_endTime = 0;
|
||||
|
||||
std::shared_ptr<const std::vector<uint8_t>> m_EBML;
|
||||
|
||||
static const size_t IO_INDEX_SIZE = sizeof(size_t);
|
||||
static const size_t START_TIME_SIZE = sizeof(uint64_t);
|
||||
static const size_t END_TIME_SIZE = sizeof(uint64_t);
|
||||
static const size_t SIZE_SIZE = sizeof(size_t);
|
||||
static const size_t IO_INDEX_INDEX = 0;
|
||||
static const size_t START_TIME_INDEX = IO_INDEX_INDEX + IO_INDEX_SIZE;
|
||||
static const size_t END_TIME_INDEX = START_TIME_INDEX + START_TIME_SIZE;
|
||||
static const size_t SIZE_INDEX = END_TIME_INDEX + END_TIME_SIZE;
|
||||
static const size_t EBML_INDEX = SIZE_INDEX + SIZE_SIZE;
|
||||
static const size_t MINIMUM_SIZE = IO_INDEX_SIZE + START_TIME_SIZE + END_TIME_SIZE + SIZE_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Error message is used to alert the client that the server raise an error due to a message by the client.
|
||||
*/
|
||||
class ErrorMessage final : public Message
|
||||
{
|
||||
public:
|
||||
ErrorMessage() : m_type(Error_Unknown), m_guiltyId(std::numeric_limits<decltype(m_guiltyId)>::max()) {}
|
||||
ErrorMessage(const EError error, const uint64_t guiltyId) : m_type(error), m_guiltyId(guiltyId) {}
|
||||
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
|
||||
EMessageType getMessageType() const override { return MessageType_Error; }
|
||||
EError getType() const { return m_type; }
|
||||
uint64_t getGuiltyId() const { return m_guiltyId; }
|
||||
|
||||
private:
|
||||
EError m_type;
|
||||
uint64_t m_guiltyId = 0;
|
||||
|
||||
static const size_t TYPE_SIZE = sizeof(EError);
|
||||
static const size_t GUILTY_ID_SIZE = sizeof(uint64_t);
|
||||
static const size_t TYPE_INDEX = 0;
|
||||
static const size_t GUILTY_ID_INDEX = TYPE_INDEX + TYPE_SIZE;
|
||||
static const size_t MINIMUM_SIZE = GUILTY_ID_SIZE + TYPE_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief End message can be sent by the server or/and by the client to inform that the processing is stopped and the connection will be closed.
|
||||
*/
|
||||
class EndMessage final : public Message
|
||||
{
|
||||
public:
|
||||
EndMessage() {}
|
||||
std::vector<uint8_t> toBytes() const override { return std::vector<uint8_t>(); }
|
||||
bool fromBytes(const std::vector<uint8_t>& /*buffer*/, size_t& /*index*/) override { return false; }
|
||||
EMessageType getMessageType() const override { return MessageType_End; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Time messages are only sent by the server to inform the client about the current time of the pipeline.
|
||||
*/
|
||||
class TimeMessage final : public Message
|
||||
{
|
||||
public:
|
||||
TimeMessage(const uint64_t time = 0) : m_time(time) {}
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
bool fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex) override;
|
||||
|
||||
EMessageType getMessageType() const override { return MessageType_Time; }
|
||||
uint64_t getTime() const { return m_time; }
|
||||
|
||||
private:
|
||||
uint64_t m_time = 0;
|
||||
|
||||
static const size_t TIME_SIZE = sizeof(uint64_t);
|
||||
static const size_t TIME_INDEX = 0;
|
||||
static const size_t MINIMUM_SIZE = TIME_SIZE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sync message can be sent by the server or/and by the client to inform that it's waiting the other part.
|
||||
*/
|
||||
class SyncMessage final : public Message
|
||||
{
|
||||
public:
|
||||
SyncMessage() {}
|
||||
std::vector<uint8_t> toBytes() const override { return std::vector<uint8_t>(); }
|
||||
bool fromBytes(const std::vector<uint8_t>& /*buffer*/, size_t& /*index*/) override { return false; }
|
||||
EMessageType getMessageType() const override { return MessageType_Sync; }
|
||||
};
|
||||
} // namespace Communication
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
#pragma once
|
||||
|
||||
#include "defines.h"
|
||||
#include "ovCMessaging.h"
|
||||
|
||||
#include "socket/IConnectionServer.h"
|
||||
|
||||
namespace Communication {
|
||||
class Communication_API MessagingServer : public CMessaging
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Default constructor.
|
||||
*/
|
||||
MessagingServer() : CMessaging(), m_Server(Socket::createConnectionServer()) {}
|
||||
|
||||
/**
|
||||
* \brief Destructor.
|
||||
*/
|
||||
~MessagingServer() override;
|
||||
|
||||
/**
|
||||
* \brief Start listening on the given port.
|
||||
*
|
||||
* \param port The port.
|
||||
*
|
||||
* \retval True if listenning
|
||||
* \retval False if not.
|
||||
*
|
||||
* \sa close
|
||||
*/
|
||||
bool listen(const size_t port) const { return m_Server->listen(port); }
|
||||
|
||||
/**
|
||||
* \brief Close the connection
|
||||
* *
|
||||
* \retval True if it succeeds
|
||||
* \retval False if it fails.
|
||||
*/
|
||||
bool close();
|
||||
|
||||
/**
|
||||
* \brief Accepts one incoming connection.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if it fails.
|
||||
*/
|
||||
bool accept();
|
||||
|
||||
/**
|
||||
* \brief Returns the port on the one the server is listening.
|
||||
* This is useful if you set the port to '0'.
|
||||
* \param port [out]: port on the one the server is listening
|
||||
*/
|
||||
bool getSocketPort(size_t& port) const { return m_Server->getSocketPort(port); }
|
||||
|
||||
|
||||
/**
|
||||
* \brief Adds a parameter in the Box Information.
|
||||
*
|
||||
* \param id The parameter's identifier.
|
||||
* \param type The parameter's type. Use OpenViBE::CIdentifier.
|
||||
* \param name The parameter's name.
|
||||
* \param value The parameter's value. A string.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an output with the given id already exists.
|
||||
*
|
||||
* \sa addInput
|
||||
* \sa addOutput
|
||||
*/
|
||||
bool addParameter(uint64_t id, size_t type, const std::string& name, const std::string& value) const;
|
||||
|
||||
/**
|
||||
* \brief Adds an input in the box Information.
|
||||
*
|
||||
* \param id The input's identifier.
|
||||
* \param type The input's type. Use OpenViBE::CIdentifier.
|
||||
* \param name The input's name.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an output with the given id already exists.
|
||||
*
|
||||
* \sa addParameter
|
||||
* \sa addOutput
|
||||
*/
|
||||
bool addInput(uint64_t id, size_t type, const std::string& name) const;
|
||||
|
||||
/**
|
||||
* \brief Adds an output in the box information.
|
||||
*
|
||||
* \param id The output's identifier.
|
||||
* \param type The output's type. Use OpenViBE::CIdentifier.
|
||||
* \param name The output's name.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if an output with the given id already exists.
|
||||
*
|
||||
* \sa addParameter
|
||||
* \sa addInput
|
||||
*/
|
||||
bool addOutput(uint64_t id, size_t type, const std::string& name) const;
|
||||
|
||||
/**
|
||||
* \brief Get the log message received from the client.
|
||||
*
|
||||
* \param[out] packetId Packet id
|
||||
* \param[out] type Level of the log
|
||||
* \param[out] message Log message
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool popLog(uint64_t& packetId, ELogLevel& type, std::string& message) override;
|
||||
|
||||
/**
|
||||
* \brief Get the EBML data received from the client.
|
||||
*
|
||||
* \param[out] packetId Packet id
|
||||
* \param[out] index Output index
|
||||
* \param[out] startTime Chunk time in OpenViBE 32:32 format
|
||||
* \param[out] endTime Chunk time in OpenViBE 32:32 format
|
||||
* \param[out] ebml EBML data
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool popEBML(uint64_t& packetId, size_t& index, uint64_t& startTime, uint64_t& endTime, std::shared_ptr<const std::vector<uint8_t>>& ebml) override;
|
||||
|
||||
/**
|
||||
* \brief Push Error message to the client
|
||||
*
|
||||
* \param error Error code
|
||||
* \param guiltyId Id of the received message that raised the error.
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool pushError(EError error, uint64_t guiltyId) const;
|
||||
|
||||
/**
|
||||
* \brief Push EBML message to the client
|
||||
*
|
||||
* \param index Index of the input.
|
||||
* \param startTime Chunk time in OpenViBE 32:32 format
|
||||
* \param endTime Chunk time in OpenViBE 32:32 format
|
||||
* \param ebml EBML data
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool pushEBML(size_t index, uint64_t startTime, uint64_t endTime, const std::shared_ptr<const std::vector<uint8_t>>& ebml) const;
|
||||
|
||||
/**
|
||||
* \brief Push Time message to the client
|
||||
*
|
||||
* \param time Time in OpenViBE 32:32 format
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool pushTime(uint64_t time) { return this->pushMessage(TimeMessage(time)); }
|
||||
|
||||
/**
|
||||
* \brief Push Sync message to the client
|
||||
*
|
||||
* \retval True if it succeeds.
|
||||
* \retval False if the library is in error state.
|
||||
*/
|
||||
bool pushSync() { return this->pushMessage(SyncMessage()); }
|
||||
|
||||
/**
|
||||
* \brief Check if a sync message is received.
|
||||
*
|
||||
* \retval True if a sync message is received.
|
||||
* \retval False if no sync message was received.
|
||||
*/
|
||||
bool waitForSyncMessage() override { return CMessaging::waitForSyncMessage(); }
|
||||
|
||||
private:
|
||||
Socket::IConnectionServer* m_Server = nullptr; //< Server connection
|
||||
Socket::IConnection* m_Client = nullptr;
|
||||
};
|
||||
} // namespace Communication
|
||||
@@ -0,0 +1,494 @@
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#include "ovCMessaging.h"
|
||||
#include "ovCMessagingImpl.hpp"
|
||||
|
||||
namespace Communication {
|
||||
|
||||
static const std::map<CMessaging::ELibraryError, std::string> ERRORS_STRING =
|
||||
{
|
||||
{ CMessaging::NoError, "No error" },
|
||||
{ CMessaging::Socket_NotConnected, "Not connected" },
|
||||
{ CMessaging::Socket_FailedToConnect, "Failed to connect" },
|
||||
{ CMessaging::Socket_ReceiveBufferFail, "Failed to receive the buffer" },
|
||||
{ CMessaging::Socket_SendBufferFail, "Failed to send the buffer" },
|
||||
{ CMessaging::Socket_NoIncomingClientConnection, "No incoming client connection before the timeout" },
|
||||
{ CMessaging::Socket_NotReadyToSend, "Socket not ready to send the buffer" },
|
||||
{ CMessaging::Socket_NoDataReceived, "No data received by the socket" },
|
||||
{ CMessaging::Socket_FailedCloseClientConnection, "Failed to close the client connection" },
|
||||
{ CMessaging::Socket_FailedToCloseConnection, "Failed to close the server connection" },
|
||||
{ CMessaging::Socket_FailedConnectClient, "Failed to connect the client" },
|
||||
{ CMessaging::Socket_ClientAlreadyConnected, "A client is already connected" },
|
||||
{ CMessaging::Deserialize_BufferTooSmall, "Buffer received is too small to be unpacked" },
|
||||
{ CMessaging::Deserialize_Header, "Fail to unpack the buffer to a Header" },
|
||||
{ CMessaging::Deserialize_ProtocolVersionMessage, "Fail to unpack Protocol Version message" },
|
||||
{ CMessaging::Deserialize_BoxDescriptionMessage, "Fail to unpack Box description message" },
|
||||
{ CMessaging::Deserialize_EBMLMessage, "Fail to unpack EBML message" },
|
||||
{ CMessaging::Deserialize_EndMessage, "Fail to unpack End message" },
|
||||
{ CMessaging::Deserialize_ErrorMessage, "Fail to unpack error message" },
|
||||
{ CMessaging::Deserialize_LogMessage, "Fail to unpack log message" },
|
||||
{ CMessaging::Deserialize_AuthenticationMessage, "Fail to unpack Authentication message" },
|
||||
{ CMessaging::Deserialize_MessageTypeNotSupported, "Message type not supported" },
|
||||
{ CMessaging::BoxDescriptionAlreadyReceived, "Box Description already received" },
|
||||
{ CMessaging::BoxDescriptionNotReceived, "Box description not received" },
|
||||
{ CMessaging::BadAuthenticationReceived, "Authentication received is invalid" },
|
||||
{ CMessaging::NoAuthenticationReceived, "No authentication received before the timeout" },
|
||||
{ CMessaging::ThreadJoinFailed, "Failed to terminate the thread" }
|
||||
};
|
||||
|
||||
CMessaging::CMessaging()
|
||||
{
|
||||
impl = new SMessagingImpl();
|
||||
impl->m_nMessage = 0;
|
||||
impl->m_Connection = nullptr;
|
||||
impl->m_LastLibraryError = NoError;
|
||||
impl->m_IsStopRequested = false;
|
||||
impl->m_IsInErrorState = false;
|
||||
impl->m_IsEndMessageReceived = false;
|
||||
}
|
||||
|
||||
CMessaging::~CMessaging()
|
||||
{
|
||||
this->reset();
|
||||
delete impl;
|
||||
}
|
||||
|
||||
void CMessaging::reset() const
|
||||
{
|
||||
this->stopSyncing();
|
||||
|
||||
impl->m_nMessage = 0;
|
||||
impl->m_IsInErrorState = false;
|
||||
impl->m_IsStopRequested = false;
|
||||
impl->m_LastLibraryError = NoError;
|
||||
|
||||
std::queue<std::pair<uint64_t, AuthenticationMessage>>().swap(impl->m_IncomingAuthentications);
|
||||
std::queue<std::pair<uint64_t, CommunicationProtocolVersionMessage>>().swap(impl->m_IncomingCommunicationProtocolVersions);
|
||||
std::queue<std::pair<uint64_t, BoxDescriptionMessage>>().swap(impl->m_IncomingBoxDescriptions);
|
||||
std::queue<std::pair<uint64_t, EBMLMessage>>().swap(impl->m_IncomingEBMLs);
|
||||
std::queue<std::pair<uint64_t, LogMessage>>().swap(impl->m_IncomingLogs);
|
||||
std::queue<std::pair<uint64_t, ErrorMessage>>().swap(impl->m_IncomingErrors);
|
||||
|
||||
impl->m_RcvBuffer.clear();
|
||||
impl->m_SendBuffer.clear();
|
||||
impl->m_SendBuffer.reserve(impl->s_BufferSize);
|
||||
|
||||
impl->m_Connection = nullptr;
|
||||
}
|
||||
|
||||
CMessaging::ELibraryError CMessaging::getLastError() const { return impl->m_LastLibraryError; }
|
||||
void CMessaging::setLastError(const ELibraryError libraryError) const { impl->m_LastLibraryError = libraryError; }
|
||||
|
||||
bool CMessaging::push() const
|
||||
{
|
||||
if (!impl->m_SendBuffer.empty() && impl->m_Connection->isReadyToSend(1))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_SendBufferMutex);
|
||||
const uint_fast32_t result = impl->m_Connection->sendBufferBlocking(impl->m_SendBuffer.data(), impl->m_SendBuffer.size());
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
this->setLastError(Socket_SendBufferFail);
|
||||
return false;
|
||||
}
|
||||
|
||||
impl->m_SendBuffer.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::pull() const
|
||||
{
|
||||
if (impl->m_Connection == nullptr)
|
||||
{
|
||||
this->setLastError(Socket_NotConnected);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (impl->m_Connection->isReadyToReceive(1))
|
||||
{
|
||||
const uint_fast32_t bytesReceived = uint_fast32_t(impl->m_Connection->receiveBuffer(impl->m_TempRcvBuffer.data(), impl->m_TempRcvBuffer.size()));
|
||||
|
||||
if (bytesReceived == 0)
|
||||
{
|
||||
this->setLastError(Socket_ReceiveBufferFail);
|
||||
return false;
|
||||
}
|
||||
|
||||
impl->m_RcvBuffer.insert(impl->m_RcvBuffer.end(), impl->m_TempRcvBuffer.cbegin(), impl->m_TempRcvBuffer.cbegin() + int(bytesReceived));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::processIncomingMessages() const
|
||||
{
|
||||
size_t byteRead = 0;
|
||||
|
||||
while (!impl->m_RcvBuffer.empty())
|
||||
{
|
||||
if (!this->processBuffer(impl->m_RcvBuffer, byteRead))
|
||||
{
|
||||
impl->m_RcvBuffer.clear();
|
||||
// Error set in the function
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the processing succeed, we erase the buffer part processed.
|
||||
if (byteRead != 0) { impl->m_RcvBuffer.erase(impl->m_RcvBuffer.begin(), impl->m_RcvBuffer.begin() + static_cast<const long>(byteRead)); }
|
||||
else
|
||||
{
|
||||
// The processing succeed but the byte count read is 0 so more data is waited.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::processBuffer(const std::vector<uint8_t>& buffer, size_t& byteRead) const
|
||||
{
|
||||
byteRead = 0;
|
||||
|
||||
if (buffer.empty()) { return true; }
|
||||
|
||||
// First, we try to fromBytes the buffer to found header information
|
||||
Header header;
|
||||
|
||||
if (!header.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->setLastError(Deserialize_Header);
|
||||
byteRead = size_t(header.getSize());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer.size() < header.getSize())
|
||||
{
|
||||
byteRead = 0;
|
||||
return true; // Just wait for more data
|
||||
}
|
||||
|
||||
// Try to unpack the object according to the type given by the header.
|
||||
switch (header.getType())
|
||||
{
|
||||
case MessageType_Authentication:
|
||||
{
|
||||
AuthenticationMessage authentication;
|
||||
|
||||
if (!authentication.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_AuthenticationMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncAuthMutex);
|
||||
impl->m_IncomingAuthentications.emplace(header.getId(), authentication);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_ProtocolVersion:
|
||||
{
|
||||
CommunicationProtocolVersionMessage communicationProtocolVersion;
|
||||
|
||||
if (!communicationProtocolVersion.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_ProtocolVersionMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncCommProVerMutex);
|
||||
impl->m_IncomingCommunicationProtocolVersions.emplace(header.getId(), communicationProtocolVersion);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_BoxInformation:
|
||||
{
|
||||
BoxDescriptionMessage boxDescription;
|
||||
|
||||
if (!boxDescription.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_BoxDescriptionMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncBoxDescriptionMutex);
|
||||
impl->m_IncomingBoxDescriptions.emplace(header.getId(), boxDescription);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_EBML:
|
||||
{
|
||||
EBMLMessage ebml;
|
||||
|
||||
if (!ebml.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_EBMLMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ebml.getIndex() >= impl->m_BoxDesc.getOutputs()->size()) { this->pushMessage(ErrorMessage(Error_InvalidOutputIndex, header.getId())); }
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncEBMLMutex);
|
||||
impl->m_IncomingEBMLs.emplace(header.getId(), ebml);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_Log:
|
||||
{
|
||||
LogMessage log;
|
||||
|
||||
if (!log.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_LogMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncLogMutex);
|
||||
impl->m_IncomingLogs.emplace(header.getId(), log);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_End: { impl->m_IsEndMessageReceived = true; }
|
||||
break;
|
||||
|
||||
case MessageType_Error:
|
||||
{
|
||||
ErrorMessage error;
|
||||
|
||||
if (!error.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_ErrorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncErrorsMutex);
|
||||
impl->m_IncomingErrors.emplace(header.getId(), error);
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_Time:
|
||||
{
|
||||
TimeMessage timeMessage;
|
||||
|
||||
if (!timeMessage.fromBytes(buffer, byteRead))
|
||||
{
|
||||
this->pushMessage(ErrorMessage(Error_BadMessage, header.getId()));
|
||||
this->setLastError(Deserialize_ErrorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
impl->m_Time = timeMessage.getTime();
|
||||
}
|
||||
break;
|
||||
|
||||
case MessageType_Sync: { impl->m_WasSyncMessageReceived = true; }
|
||||
break;
|
||||
|
||||
case MessageType_Unknown:
|
||||
case MessageType_Max:
|
||||
this->pushMessage(ErrorMessage(Error_InvalidMessageType, header.getId()));
|
||||
this->setLastError(Deserialize_MessageTypeNotSupported);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::isInErrorState() const { return impl->m_IsInErrorState.load(); }
|
||||
|
||||
bool CMessaging::isEndReceived() { return impl->m_IsEndMessageReceived; }
|
||||
|
||||
uint64_t CMessaging::getTime() { return impl->m_Time; }
|
||||
|
||||
bool CMessaging::pushMessage(const Message& message) const
|
||||
{
|
||||
if (this->isInErrorState()) { return false; }
|
||||
|
||||
std::vector<uint8_t> messageBuffer = message.toBytes();
|
||||
const Header header(message.getMessageType(), impl->m_nMessage++, messageBuffer.size());
|
||||
std::vector<uint8_t> headerBuffer = header.toBytes();
|
||||
|
||||
std::lock_guard<std::mutex> lock(impl->m_SendBufferMutex);
|
||||
impl->m_SendBuffer.insert(impl->m_SendBuffer.end(), headerBuffer.begin(), headerBuffer.end());
|
||||
impl->m_SendBuffer.insert(impl->m_SendBuffer.end(), messageBuffer.begin(), messageBuffer.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CMessaging::getErrorString(const ELibraryError error) { return ERRORS_STRING.at(error); }
|
||||
|
||||
bool CMessaging::isConnected() const
|
||||
{
|
||||
if (impl->m_Connection == nullptr) { return false; }
|
||||
|
||||
return impl->m_Connection->isConnected();
|
||||
}
|
||||
|
||||
void CMessaging::sync() const
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!this->push())
|
||||
{
|
||||
impl->m_IsInErrorState = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this->pull())
|
||||
{
|
||||
impl->m_IsInErrorState = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!this->processIncomingMessages())
|
||||
{
|
||||
impl->m_IsInErrorState = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (impl->m_IsStopRequested)
|
||||
{
|
||||
// Used to be sure to send the end message
|
||||
this->pull();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMessaging::setConnection(Socket::IConnection* connection) const { impl->m_Connection = connection; }
|
||||
|
||||
bool CMessaging::startSyncing()
|
||||
{
|
||||
impl->m_IsEndMessageReceived = false;
|
||||
impl->m_SyncThread = std::thread(&CMessaging::sync, this);
|
||||
impl->m_IsStopRequested = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::stopSyncing() const
|
||||
{
|
||||
impl->m_IsStopRequested = true;
|
||||
|
||||
if (impl->m_SyncThread.joinable()) { impl->m_SyncThread.join(); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popAuthentication(uint64_t& id, std::string& connectionID)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncAuthMutex);
|
||||
|
||||
if (impl->m_IncomingAuthentications.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingAuthentications.front().first;
|
||||
connectionID = impl->m_IncomingAuthentications.front().second.getConnectionID();
|
||||
impl->m_IncomingAuthentications.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popBoxDescriptions(uint64_t& id, BoxDescriptionMessage& boxDescription)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncBoxDescriptionMutex);
|
||||
|
||||
if (impl->m_IncomingBoxDescriptions.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingBoxDescriptions.front().first;
|
||||
boxDescription = impl->m_IncomingBoxDescriptions.front().second;
|
||||
impl->m_IncomingBoxDescriptions.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popCommunicationProtocolVersion(uint64_t& id, uint8_t& majorVersion, uint8_t& minorVersion)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncCommProVerMutex);
|
||||
|
||||
if (impl->m_IncomingCommunicationProtocolVersions.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingCommunicationProtocolVersions.front().first;
|
||||
majorVersion = impl->m_IncomingCommunicationProtocolVersions.front().second.getMajorVersion();
|
||||
minorVersion = impl->m_IncomingCommunicationProtocolVersions.front().second.getMinorVersion();
|
||||
impl->m_IncomingEBMLs.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popLog(uint64_t& id, ELogLevel& type, std::string& message)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncLogMutex);
|
||||
|
||||
if (impl->m_IncomingLogs.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingLogs.front().first;
|
||||
type = impl->m_IncomingLogs.front().second.getType();
|
||||
message = impl->m_IncomingLogs.front().second.getMessage();
|
||||
impl->m_IncomingLogs.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popError(uint64_t& id, EError& type, uint64_t& guiltyId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncErrorsMutex);
|
||||
|
||||
if (impl->m_IncomingErrors.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingErrors.front().first;
|
||||
type = impl->m_IncomingErrors.front().second.getType();
|
||||
guiltyId = impl->m_IncomingErrors.front().second.getGuiltyId();
|
||||
|
||||
impl->m_IncomingErrors.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popEBML(uint64_t& id, size_t& index, uint64_t& startTime, uint64_t& endTime, std::shared_ptr<const std::vector<uint8_t>>& ebml)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncEBMLMutex);
|
||||
|
||||
if (impl->m_IncomingEBMLs.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingEBMLs.front().first;
|
||||
index = impl->m_IncomingEBMLs.front().second.getIndex();
|
||||
startTime = impl->m_IncomingEBMLs.front().second.getStartTime();
|
||||
endTime = impl->m_IncomingEBMLs.front().second.getEndTime();
|
||||
ebml = impl->m_IncomingEBMLs.front().second.getEBML();
|
||||
impl->m_IncomingEBMLs.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMessaging::popEnd(uint64_t& id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(impl->m_IncEndMutex);
|
||||
|
||||
if (impl->m_IncomingEnds.empty()) { return false; }
|
||||
|
||||
id = impl->m_IncomingEnds.front().first;
|
||||
impl->m_IncomingEnds.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMessaging::setConnectionID(const std::string& connectionID) const { impl->m_ConnectionID = connectionID; }
|
||||
|
||||
bool CMessaging::waitForSyncMessage()
|
||||
{
|
||||
if (impl->m_WasSyncMessageReceived)
|
||||
{
|
||||
impl->m_WasSyncMessageReceived = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace Communication
|
||||
@@ -0,0 +1,172 @@
|
||||
#include "ovCMessagingClient.h"
|
||||
#include "ovCMessagingImpl.hpp"
|
||||
|
||||
namespace Communication {
|
||||
|
||||
MessagingClient::MessagingClient() : CMessaging(), m_Client(Socket::createConnectionClient()) {}
|
||||
|
||||
MessagingClient::~MessagingClient()
|
||||
{
|
||||
this->close();
|
||||
m_Client->release();
|
||||
}
|
||||
|
||||
bool MessagingClient::connect(const std::string& uri, const size_t port)
|
||||
{
|
||||
this->reset();
|
||||
|
||||
if (!m_Client->connect(uri.c_str(), port))
|
||||
{
|
||||
this->setLastError(Socket_FailedToConnect);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->setConnection(m_Client);
|
||||
|
||||
// Once the connection is done, the client push an authentication message to the server
|
||||
if (!this->pushAuthentication(impl->m_ConnectionID))
|
||||
{
|
||||
// Error set in the function
|
||||
const ELibraryError error = this->getLastError();
|
||||
this->close();
|
||||
this->setLastError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->startSyncing())
|
||||
{
|
||||
this->close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// To work, the client need to receive box information message. So we wait to receive the box information message.
|
||||
// A timeout of 10 seconds is set.
|
||||
const std::chrono::time_point<std::chrono::system_clock> startClock = std::chrono::system_clock::now();
|
||||
uint64_t packetId;
|
||||
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - startClock).count() < 10)
|
||||
{
|
||||
if (this->popBoxDescriptions(packetId, impl->m_BoxDesc))
|
||||
{
|
||||
m_BoxDescriptionReceived = true;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
if (!m_BoxDescriptionReceived)
|
||||
{
|
||||
this->close();
|
||||
this->setLastError(BoxDescriptionNotReceived);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessagingClient::close() const
|
||||
{
|
||||
this->pushMessage(EndMessage());
|
||||
|
||||
this->stopSyncing();
|
||||
|
||||
if (m_Client != nullptr)
|
||||
{
|
||||
if (!m_Client->close())
|
||||
{
|
||||
this->setLastError(Socket_FailedToCloseConnection);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t MessagingClient::getParameterCount() const
|
||||
{
|
||||
if (!m_BoxDescriptionReceived) { return 0; }
|
||||
return impl->m_BoxDesc.getParameters()->size();
|
||||
}
|
||||
|
||||
size_t MessagingClient::getInputCount() const
|
||||
{
|
||||
if (!m_BoxDescriptionReceived) { return 0; }
|
||||
return impl->m_BoxDesc.getInputs()->size();
|
||||
}
|
||||
|
||||
size_t MessagingClient::getOutputCount() const
|
||||
{
|
||||
if (!m_BoxDescriptionReceived) { return 0; }
|
||||
return impl->m_BoxDesc.getOutputs()->size();
|
||||
}
|
||||
|
||||
bool MessagingClient::getParameter(const size_t i, uint64_t& id, uint64_t& type, std::string& name, std::string& value) const
|
||||
{
|
||||
if (!m_BoxDescriptionReceived) { return false; }
|
||||
|
||||
const std::vector<Parameter>* parameters = impl->m_BoxDesc.getParameters();
|
||||
|
||||
if (parameters->size() <= i) { return false; }
|
||||
|
||||
id = parameters->at(i).getId();
|
||||
type = parameters->at(i).getType();
|
||||
name = parameters->at(i).getName();
|
||||
value = parameters->at(i).getValue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessagingClient::getInput(const size_t i, uint64_t& id, uint64_t& type, std::string& name) const
|
||||
{
|
||||
if (!m_BoxDescriptionReceived) { return false; }
|
||||
|
||||
const std::vector<InputOutput>* inputs = impl->m_BoxDesc.getInputs();
|
||||
|
||||
if (inputs->size() <= i) { return false; }
|
||||
|
||||
id = inputs->at(i).getId();
|
||||
type = inputs->at(i).getType();
|
||||
name = inputs->at(i).getName();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessagingClient::getOutput(const size_t i, uint64_t& id, uint64_t& type, std::string& name) const
|
||||
{
|
||||
if (!m_BoxDescriptionReceived)
|
||||
{
|
||||
const_cast<MessagingClient*>(this)->setLastError(BoxDescriptionNotReceived);
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<InputOutput>* outputs = impl->m_BoxDesc.getOutputs();
|
||||
|
||||
if (outputs->size() <= i) { return false; }
|
||||
|
||||
id = outputs->at(i).getId();
|
||||
type = outputs->at(i).getType();
|
||||
name = outputs->at(i).getName();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessagingClient::popError(uint64_t& packetId, EError& type, uint64_t& guiltyId) { return CMessaging::popError(packetId, type, guiltyId); }
|
||||
|
||||
bool MessagingClient::popEBML(uint64_t& packetId, size_t& index, uint64_t& startTime, uint64_t& endTime, std::shared_ptr<const std::vector<uint8_t>>& ebml)
|
||||
{
|
||||
return CMessaging::popEBML(packetId, index, startTime, endTime, ebml);
|
||||
}
|
||||
|
||||
bool MessagingClient::pushAuthentication(const std::string& connectionID) const { return this->pushMessage(AuthenticationMessage(connectionID)); }
|
||||
bool MessagingClient::pushLog(const ELogLevel logLevel, const std::string& log) const { return this->pushMessage(LogMessage(logLevel, log)); }
|
||||
|
||||
bool MessagingClient::pushEBML(const size_t index, const uint64_t startTime, const uint64_t endTime,
|
||||
const std::shared_ptr<const std::vector<uint8_t>>& ebml) const
|
||||
{
|
||||
return this->pushMessage(EBMLMessage(index, startTime, endTime, ebml));
|
||||
}
|
||||
|
||||
bool MessagingClient::pushSync() const { return this->pushMessage(SyncMessage()); }
|
||||
bool MessagingClient::waitForSyncMessage() { return CMessaging::waitForSyncMessage(); }
|
||||
|
||||
} // namespace Communication
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "ovCMessaging.h"
|
||||
#include "ovCMessagingProtocol.h"
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <atomic>
|
||||
|
||||
namespace Communication {
|
||||
struct CMessaging::SMessagingImpl
|
||||
{
|
||||
std::string m_ConnectionID;
|
||||
BoxDescriptionMessage m_BoxDesc;
|
||||
std::atomic<uint64_t> m_Time;
|
||||
|
||||
uint64_t m_nMessage = 0;
|
||||
|
||||
std::mutex m_IncAuthMutex;
|
||||
std::queue<std::pair<uint64_t, AuthenticationMessage>> m_IncomingAuthentications;
|
||||
|
||||
std::mutex m_IncCommProVerMutex;
|
||||
std::queue<std::pair<uint64_t, CommunicationProtocolVersionMessage>> m_IncomingCommunicationProtocolVersions;
|
||||
|
||||
std::mutex m_IncBoxDescriptionMutex;
|
||||
std::queue<std::pair<uint64_t, BoxDescriptionMessage>> m_IncomingBoxDescriptions;
|
||||
|
||||
std::mutex m_IncEBMLMutex;
|
||||
std::queue<std::pair<uint64_t, EBMLMessage>> m_IncomingEBMLs;
|
||||
|
||||
std::mutex m_IncLogMutex;
|
||||
std::queue<std::pair<uint64_t, LogMessage>> m_IncomingLogs;
|
||||
|
||||
std::mutex m_IncErrorsMutex;
|
||||
std::queue<std::pair<uint64_t, ErrorMessage>> m_IncomingErrors;
|
||||
|
||||
std::mutex m_IncEndMutex;
|
||||
std::queue<std::pair<uint64_t, EndMessage>> m_IncomingEnds;
|
||||
|
||||
static const size_t s_BufferSize = 1024 * 64; //< Empirical value
|
||||
|
||||
std::vector<uint8_t> m_RcvBuffer;
|
||||
std::array<uint8_t, s_BufferSize> m_TempRcvBuffer;
|
||||
|
||||
std::mutex m_SendBufferMutex;
|
||||
std::vector<uint8_t> m_SendBuffer;
|
||||
|
||||
Socket::IConnection* m_Connection = nullptr;
|
||||
|
||||
mutable std::atomic<ELibraryError> m_LastLibraryError;
|
||||
|
||||
std::thread m_SyncThread;
|
||||
|
||||
std::atomic<bool> m_IsStopRequested;
|
||||
std::atomic<bool> m_IsInErrorState;
|
||||
std::atomic<bool> m_IsEndMessageReceived;
|
||||
|
||||
std::atomic<bool> m_WasSyncMessageReceived;
|
||||
};
|
||||
} // namespace Communication
|
||||
@@ -0,0 +1,565 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "ovCMessaging.h"
|
||||
|
||||
namespace Communication {
|
||||
|
||||
/**
|
||||
* \brief Copy a string to buffer
|
||||
*
|
||||
* \param [out] dest The buffer destination
|
||||
* \param [out] bufferIndex The index of the buffer where the beginning of the string must be copied.
|
||||
* \param value The string to copy.
|
||||
*
|
||||
* \retval True if it succeeds
|
||||
* \retval False if it fails.
|
||||
*/
|
||||
static bool copyTobuffer(std::vector<uint8_t>& dest, size_t& bufferIndex, const std::string& value)
|
||||
{
|
||||
if (dest.size() < bufferIndex + value.size()) { return false; }
|
||||
memcpy(dest.data() + bufferIndex, value.data(), value.size());
|
||||
bufferIndex += value.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Copy a value to a buffer.
|
||||
*
|
||||
* \param [out] dest Destination for the.
|
||||
* \param [out] bufferIndex Zero-based index of the buffer.
|
||||
* \param value The value.
|
||||
*
|
||||
* \return True if it succeeds, false if it fails.
|
||||
*/
|
||||
template <class T>
|
||||
static bool copyTobuffer(std::vector<uint8_t>& dest, size_t& bufferIndex, const T& value)
|
||||
{
|
||||
if (dest.size() < bufferIndex + sizeof(value)) { return false; }
|
||||
memcpy(dest.data() + bufferIndex, &value, sizeof(value));
|
||||
bufferIndex += sizeof(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static bool copyToVariable(const std::vector<uint8_t>& src, const size_t bufferIndex, T& destVariable)
|
||||
{
|
||||
if (src.size() < bufferIndex + sizeof(destVariable)) { return false; }
|
||||
memcpy(&destVariable, src.data() + bufferIndex, sizeof(destVariable));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convert a buffer to a string
|
||||
*
|
||||
* \param src The buffer
|
||||
* \param bufferIndex The index where to start the convertion.
|
||||
* \param size The size of the string.
|
||||
* \param [out] string The string.
|
||||
*
|
||||
* \retval True if it succeeds
|
||||
* \retval False if it fails.
|
||||
*
|
||||
* \sa copyToVariable
|
||||
*/
|
||||
static bool copyToString(const std::vector<uint8_t>& src, const size_t bufferIndex, const size_t size, std::string& string)
|
||||
{
|
||||
if (src.size() < bufferIndex + size) { return false; }
|
||||
|
||||
string = std::string(src.begin() + static_cast<const long>(bufferIndex),
|
||||
src.begin() + static_cast<const long>(bufferIndex) + static_cast<const long>(size));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Header
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
Header::Header() : m_type(MessageType_Unknown), m_id(std::numeric_limits<decltype(m_id)>::max()) { m_isValid = false; }
|
||||
Header::Header(const EMessageType type, const uint64_t id, const size_t size) : m_type(type), m_id(id), m_size(size) { m_isValid = true; }
|
||||
|
||||
std::vector<uint8_t> Header::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE);
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_type);
|
||||
copyTobuffer(buffer, bufferIndex, m_id);
|
||||
copyTobuffer(buffer, bufferIndex, m_size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool Header::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
uint8_t typeInt;
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + TYPE_INDEX, typeInt)) { return false; }
|
||||
|
||||
if (typeInt >= MessageType_Max) { return false; }
|
||||
|
||||
m_type = EMessageType(typeInt);
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + ID_INDEX, m_id)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + SIZE_INDEX, m_size)) { return false; }
|
||||
|
||||
bufferIndex += MINIMUM_SIZE;
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Authentication
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::vector<uint8_t> AuthenticationMessage::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE + m_connectionID.size());
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
const size_t size = m_connectionID.size();
|
||||
copyTobuffer(buffer, bufferIndex, size);
|
||||
copyTobuffer(buffer, bufferIndex, m_connectionID);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool AuthenticationMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
size_t passPhraseSize;
|
||||
if (!copyToVariable(buffer, bufferIndex + SIZE_INDEX, passPhraseSize)) { return false; }
|
||||
if (!copyToString(buffer, bufferIndex + CONNECTION_ID_INDEX, passPhraseSize, m_connectionID)) { return false; }
|
||||
|
||||
m_isValid = true;
|
||||
bufferIndex += MINIMUM_SIZE + passPhraseSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Communication protocol version
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::vector<uint8_t> CommunicationProtocolVersionMessage::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE);
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_majorVersion);
|
||||
copyTobuffer(buffer, bufferIndex, m_minorVersion);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool CommunicationProtocolVersionMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + MAJOR_INDEX, m_majorVersion)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + MINOR_INDEX, m_minorVersion)) { return false; }
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
bufferIndex += MINIMUM_SIZE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Inout and output
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
InputOutput::InputOutput()
|
||||
: m_id(std::numeric_limits<decltype(m_id)>::max()), m_type(std::numeric_limits<decltype(m_type)>::max()), m_name(std::string()) { m_isValid = false; }
|
||||
|
||||
InputOutput::InputOutput(const uint64_t id, const size_t type, const std::string& name) : m_id(id), m_type(type), m_name(name) { m_isValid = true; }
|
||||
|
||||
std::vector<uint8_t> InputOutput::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE + m_name.size());
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_id);
|
||||
copyTobuffer(buffer, bufferIndex, m_type);
|
||||
copyTobuffer(buffer, bufferIndex, m_name.size());
|
||||
copyTobuffer(buffer, bufferIndex, m_name);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool InputOutput::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + ID_INDEX, m_id)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + TYPE_INDEX, m_type)) { return false; }
|
||||
|
||||
size_t nameSize;
|
||||
if (!copyToVariable(buffer, bufferIndex + NAME_SIZE_INDEX, nameSize)) { return false; }
|
||||
if (!copyToString(buffer, bufferIndex + NAME_INDEX, nameSize, m_name)) { return false; }
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
bufferIndex += MINIMUM_SIZE + nameSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Parameter
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
Parameter::Parameter()
|
||||
: m_id(std::numeric_limits<decltype(m_id)>::max()), m_type(std::numeric_limits<decltype(m_type)>::max()), m_name(std::string()), m_value(std::string())
|
||||
{
|
||||
m_isValid = false;
|
||||
}
|
||||
|
||||
Parameter::Parameter(const uint64_t id, const size_t type, const std::string& name, const std::string& value)
|
||||
: m_id(id), m_type(type), m_name(name), m_value(value) { m_isValid = true; }
|
||||
|
||||
std::vector<uint8_t> Parameter::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE + m_name.size() + m_value.size());
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_id);
|
||||
copyTobuffer(buffer, bufferIndex, m_type);
|
||||
copyTobuffer(buffer, bufferIndex, m_name.size());
|
||||
copyTobuffer(buffer, bufferIndex, m_value.size());
|
||||
copyTobuffer(buffer, bufferIndex, m_name);
|
||||
copyTobuffer(buffer, bufferIndex, m_value);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool Parameter::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + ID_INDEX, m_id)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + TYPE_INDEX, m_type)) { return false; }
|
||||
|
||||
size_t nameSize;
|
||||
if (!copyToVariable(buffer, bufferIndex + NAME_SIZE_INDEX, nameSize)) { return false; }
|
||||
|
||||
size_t valueSize;
|
||||
if (!copyToVariable(buffer, bufferIndex + VALUE_SIZE_INDEX, valueSize)) { return false; }
|
||||
if (!copyToString(buffer, bufferIndex + NAME_INDEX, nameSize, m_name)) { return false; }
|
||||
if (!copyToString(buffer, bufferIndex + NAME_INDEX + nameSize, valueSize, m_value)) { return false; }
|
||||
|
||||
bufferIndex += MINIMUM_SIZE + nameSize + valueSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Box description
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::vector<uint8_t> BoxDescriptionMessage::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE);
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_inputs.size());
|
||||
copyTobuffer(buffer, bufferIndex, m_outputs.size());
|
||||
copyTobuffer(buffer, bufferIndex, m_parameters.size());
|
||||
|
||||
for (const InputOutput& input : m_inputs)
|
||||
{
|
||||
std::vector<uint8_t> inputBuffer = input.toBytes();
|
||||
buffer.insert(buffer.end(), inputBuffer.begin(), inputBuffer.end());
|
||||
}
|
||||
|
||||
for (const InputOutput& output : m_outputs)
|
||||
{
|
||||
std::vector<uint8_t> outputBuffer = output.toBytes();
|
||||
buffer.insert(buffer.end(), outputBuffer.begin(), outputBuffer.end());
|
||||
}
|
||||
|
||||
for (const Parameter& parameter : m_parameters)
|
||||
{
|
||||
std::vector<uint8_t> parameterBuffer = parameter.toBytes();
|
||||
buffer.insert(buffer.end(), parameterBuffer.begin(), parameterBuffer.end());
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool BoxDescriptionMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
size_t inputCount;
|
||||
size_t outputCount;
|
||||
size_t parameterCount;
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + N_INPUT_INDEX, inputCount)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + N_OUTPUT_INDEX, outputCount)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + N_PARAMETER_INDEX, parameterCount)) { return false; }
|
||||
|
||||
bufferIndex += MINIMUM_SIZE;
|
||||
|
||||
m_inputs.clear();
|
||||
m_outputs.clear();
|
||||
m_parameters.clear();
|
||||
|
||||
for (size_t i = 0; i < inputCount; ++i)
|
||||
{
|
||||
InputOutput input;
|
||||
if (!input.fromBytes(buffer, bufferIndex)) { return false; }
|
||||
m_inputs.push_back(input);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < outputCount; ++i)
|
||||
{
|
||||
InputOutput output;
|
||||
if (!output.fromBytes(buffer, bufferIndex)) { return false; }
|
||||
m_outputs.push_back(output);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < parameterCount; ++i)
|
||||
{
|
||||
Parameter parameter;
|
||||
if (!parameter.fromBytes(buffer, bufferIndex)) { return false; }
|
||||
m_parameters.push_back(parameter);
|
||||
}
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EMessageType BoxDescriptionMessage::getMessageType() const { return MessageType_BoxInformation; }
|
||||
|
||||
bool BoxDescriptionMessage::addInput(const uint64_t id, const size_t type, const std::string& name)
|
||||
{
|
||||
const auto it = std::find_if(m_inputs.begin(), m_inputs.end(), [&id](const InputOutput& obj) { return obj.getId() == id; });
|
||||
if (it != m_inputs.end()) { return false; }
|
||||
m_inputs.emplace_back(id, type, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BoxDescriptionMessage::addOutput(const uint64_t id, const size_t type, const std::string& name)
|
||||
{
|
||||
const auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [&id](const InputOutput& obj) { return obj.getId() == id; });
|
||||
if (it != m_outputs.end()) { return false; }
|
||||
m_outputs.emplace_back(id, type, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BoxDescriptionMessage::addParameter(const uint64_t id, const size_t type, const std::string& name, const std::string& value)
|
||||
{
|
||||
const auto it = std::find_if(m_parameters.begin(), m_parameters.end(), [&id](const Parameter& obj) { return obj.getId() == id; });
|
||||
if (it != m_parameters.end()) { return false; }
|
||||
m_parameters.emplace_back(id, type, name, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Packet part
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Log
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
LogMessage::LogMessage() : m_type(LogLevel_Unknown) { m_isValid = false; }
|
||||
LogMessage::LogMessage(const ELogLevel type, const std::string& message) : m_type(type), m_message(message) { m_isValid = true; }
|
||||
|
||||
std::vector<uint8_t> LogMessage::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE + m_message.size());
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_type);
|
||||
copyTobuffer(buffer, bufferIndex, m_message.size());
|
||||
copyTobuffer(buffer, bufferIndex, m_message);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool LogMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
// Type
|
||||
uint8_t typeInt;
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + TYPE_INDEX, typeInt)) { return false; }
|
||||
|
||||
if (typeInt >= LogLevel_Max) { return false; }
|
||||
|
||||
m_type = ELogLevel(typeInt);
|
||||
|
||||
// Message size
|
||||
size_t messageSize;
|
||||
if (!copyToVariable(buffer, bufferIndex + SIZE_INDEX, messageSize)) { return false; }
|
||||
if (!copyToString(buffer, bufferIndex + NAME_INDEX, messageSize, m_message)) { return false; }
|
||||
|
||||
bufferIndex += MINIMUM_SIZE + messageSize;
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* EBML
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
EBMLMessage::EBMLMessage()
|
||||
: m_ioIdx(std::numeric_limits<decltype(m_ioIdx)>::max()), m_startTime(std::numeric_limits<decltype(m_startTime)>::max()),
|
||||
m_endTime(std::numeric_limits<decltype(m_endTime)>::max()) { m_isValid = false; }
|
||||
|
||||
EBMLMessage::EBMLMessage(const size_t index, const uint64_t startTime, const uint64_t endTime, const std::shared_ptr<const std::vector<uint8_t>>& ebml)
|
||||
: m_ioIdx(index), m_startTime(startTime), m_endTime(endTime), m_EBML(ebml) { m_isValid = true; }
|
||||
|
||||
std::vector<uint8_t> EBMLMessage::toBytes() const
|
||||
{
|
||||
if (!m_isValid) { return std::vector<uint8_t>(); }
|
||||
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE);
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_ioIdx);
|
||||
copyTobuffer(buffer, bufferIndex, m_startTime);
|
||||
copyTobuffer(buffer, bufferIndex, m_endTime);
|
||||
copyTobuffer(buffer, bufferIndex, size_t(m_EBML->size()));
|
||||
|
||||
if (!m_EBML->empty()) { buffer.insert(buffer.end(), m_EBML->begin(), m_EBML->end()); }
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool EBMLMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + IO_INDEX_INDEX, m_ioIdx)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + START_TIME_INDEX, m_startTime)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + END_TIME_INDEX, m_endTime)) { return false; }
|
||||
|
||||
size_t EBMLsize;
|
||||
if (!copyToVariable(buffer, bufferIndex + SIZE_INDEX, EBMLsize)) { return false; }
|
||||
|
||||
if (buffer.size() < bufferIndex + EBML_INDEX + EBMLsize) { return false; }
|
||||
|
||||
m_EBML.reset(new std::vector<uint8_t>(buffer.begin() + static_cast<const long>(bufferIndex) + EBML_INDEX,
|
||||
buffer.begin() + static_cast<const long>(bufferIndex) + EBML_INDEX + EBMLsize));
|
||||
|
||||
bufferIndex += MINIMUM_SIZE + EBMLsize;
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Error
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::vector<uint8_t> ErrorMessage::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE);
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_type);
|
||||
copyTobuffer(buffer, bufferIndex, m_guiltyId);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool ErrorMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
|
||||
if (!copyToVariable(buffer, bufferIndex + TYPE_INDEX, m_type)) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + GUILTY_ID_INDEX, m_guiltyId)) { return false; }
|
||||
|
||||
bufferIndex += MINIMUM_SIZE;
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Time
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::vector<uint8_t> TimeMessage::toBytes() const
|
||||
{
|
||||
std::vector<uint8_t> buffer(MINIMUM_SIZE);
|
||||
size_t bufferIndex = 0;
|
||||
|
||||
copyTobuffer(buffer, bufferIndex, m_time);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool TimeMessage::fromBytes(const std::vector<uint8_t>& buffer, size_t& bufferIndex)
|
||||
{
|
||||
m_isValid = false;
|
||||
|
||||
if (buffer.size() < bufferIndex + MINIMUM_SIZE) { return false; }
|
||||
if (!copyToVariable(buffer, bufferIndex + TIME_INDEX, m_time)) { return false; }
|
||||
|
||||
bufferIndex += MINIMUM_SIZE;
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Communication
|
||||
@@ -0,0 +1,150 @@
|
||||
#include "ovCMessagingServer.h"
|
||||
#include "ovCMessagingImpl.hpp"
|
||||
|
||||
namespace Communication {
|
||||
|
||||
MessagingServer::~MessagingServer()
|
||||
{
|
||||
this->close();
|
||||
m_Server->release();
|
||||
}
|
||||
|
||||
|
||||
bool MessagingServer::accept()
|
||||
{
|
||||
this->reset();
|
||||
|
||||
if (this->isConnected())
|
||||
{
|
||||
// A connection is already done to a client
|
||||
this->setLastError(Socket_ClientAlreadyConnected);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_Server->isReadyToReceive())
|
||||
{
|
||||
this->setLastError(Socket_NoIncomingClientConnection);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Client = m_Server->accept();
|
||||
|
||||
if (m_Client == nullptr)
|
||||
{
|
||||
this->setLastError(Socket_NoIncomingClientConnection);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->setConnection(m_Client);
|
||||
|
||||
this->startSyncing();
|
||||
|
||||
if (!impl->m_ConnectionID.empty())
|
||||
{
|
||||
// The server has to verify that the client is the one that is waited. So the server wait the authentication packet.
|
||||
const std::chrono::time_point<std::chrono::system_clock> startClock = std::chrono::system_clock::now();
|
||||
|
||||
std::string connectionID;
|
||||
uint64_t id = 0;
|
||||
bool isAuthReceived = false;
|
||||
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - startClock).count() < 10)
|
||||
{
|
||||
if (this->popAuthentication(id, connectionID))
|
||||
{
|
||||
isAuthReceived = true;
|
||||
|
||||
if (connectionID != impl->m_ConnectionID)
|
||||
{
|
||||
this->pushError(Error_AuthenticationFail, id);
|
||||
this->close();
|
||||
this->setLastError(BadAuthenticationReceived);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
if (!isAuthReceived)
|
||||
{
|
||||
this->pushError(Error_AuthenticationRequested, id);
|
||||
this->close();
|
||||
this->setLastError(NoAuthenticationReceived);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->pushMessage(CommunicationProtocolVersionMessage(s_CommunicationProtocol_MajorVersion, s_CommunicationProtocol_MinorVersion)))
|
||||
{
|
||||
// Error set in the function
|
||||
const ELibraryError error = this->getLastError();
|
||||
this->close();
|
||||
this->setLastError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this->pushMessage(impl->m_BoxDesc))
|
||||
{
|
||||
// Error set in the function
|
||||
const ELibraryError error = this->getLastError();
|
||||
this->close();
|
||||
this->setLastError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessagingServer::close()
|
||||
{
|
||||
this->pushMessage(EndMessage());
|
||||
|
||||
this->stopSyncing();
|
||||
|
||||
bool errorRaised = false;
|
||||
|
||||
if (m_Client != nullptr)
|
||||
{
|
||||
if (!m_Client->close())
|
||||
{
|
||||
errorRaised = true;
|
||||
this->setLastError(Socket_FailedToCloseConnection);
|
||||
}
|
||||
|
||||
m_Client->release();
|
||||
m_Client = nullptr;
|
||||
}
|
||||
|
||||
if (!m_Server->close())
|
||||
{
|
||||
this->setLastError(Socket_FailedToCloseConnection);
|
||||
errorRaised = true;
|
||||
}
|
||||
|
||||
return !errorRaised;
|
||||
}
|
||||
|
||||
bool MessagingServer::addParameter(const uint64_t id, const size_t type, const std::string& name, const std::string& value) const
|
||||
{
|
||||
return impl->m_BoxDesc.addParameter(id, type, name, value);
|
||||
}
|
||||
|
||||
bool MessagingServer::addInput(const uint64_t id, const size_t type, const std::string& name) const { return impl->m_BoxDesc.addInput(id, type, name); }
|
||||
bool MessagingServer::addOutput(const uint64_t id, const size_t type, const std::string& name) const { return impl->m_BoxDesc.addOutput(id, type, name); }
|
||||
bool MessagingServer::popLog(uint64_t& packetId, ELogLevel& type, std::string& message) { return CMessaging::popLog(packetId, type, message); }
|
||||
|
||||
bool MessagingServer::popEBML(uint64_t& packetId, size_t& index, uint64_t& startTime, uint64_t& endTime, std::shared_ptr<const std::vector<uint8_t>>& ebml)
|
||||
{
|
||||
return CMessaging::popEBML(packetId, index, startTime, endTime, ebml);
|
||||
}
|
||||
|
||||
bool MessagingServer::pushError(const EError error, const uint64_t guiltyId) const { return this->pushMessage(ErrorMessage(error, guiltyId)); }
|
||||
|
||||
bool MessagingServer::pushEBML(const size_t index, const uint64_t startTime, const uint64_t endTime,
|
||||
const std::shared_ptr<const std::vector<uint8_t>>& ebml) const
|
||||
{
|
||||
return this->pushMessage(EBMLMessage(index, startTime, endTime, ebml));
|
||||
}
|
||||
|
||||
} // namespace Communication
|
||||
Reference in New Issue
Block a user