/*************************************** Auteur : Pierre Aubert Mail : pierre.aubert@lapp.in2p3.fr Licence : CeCILL-C ****************************************/ #ifndef __PGENERIC_SOCKET_H__ #define __PGENERIC_SOCKET_H__ #include "PSocketMode.h" #include "phoenix_mock_socket.h" ///@brief Abstract socket which has a mock mode to avoid heavy socket backend for unit tests template<typename _TBackend, typename _TMockBackend> class PGenericSocket{ public: PGenericSocket(PSocketMode::PSocketMode mode); virtual ~PGenericSocket(); bool createClientSocket(const typename _TBackend::Param & param, const typename _TMockBackend::Param & mockParam); bool createServerSocket(const typename _TBackend::Param & param, const typename _TMockBackend::Param & mockParam); ///Send message on the given socket /** @param data : data to be sent * @param flags : flags to be used to send the message (none, dontwait, sndmore, etc) * @return true on success, false otherwise */ template<typename U, typename _TFlag> bool sendData(const U & data, _TFlag flags){ size_t dataSize(data_size<U>(data)); bool b(true); if(p_mode != PSocketMode::NO_MOCK){ typename _TMockBackend::Message msg; _TMockBackend::msgResize(msg, dataSize); char* iter = _TMockBackend::msgData(msg); if(data_message_save<char*, U>(iter, data)){ //Save the message b &= _TMockBackend::send(p_mockSocket, msg, (typename _TMockBackend::SendFlag)flags); }else{ b = false; } } if(p_mode != PSocketMode::MOCK){ typename _TBackend::Message msg; _TBackend::msgResize(msg, dataSize); char* iter = _TBackend::msgData(msg); if(data_message_save<char*, U>(iter, data)){ //Save the message b &= _TBackend::send(p_socket, msg, (typename _TBackend::SendFlag)flags); }else{ b = false; } } return b; } ///Send message on the given socket /** @param msg : message to be sent * @param flags : flags to be used to send the message (none, dontwait, sndmore, etc) * @return true on success, false otherwise */ template<typename _TFlag> bool sendMsg(typename _TBackend::Message & msg, _TFlag flags){ size_t dataSize(msg.size()); bool b(true); if(p_mode != PSocketMode::NO_MOCK){ typename _TMockBackend::Message vecTmp; _TMockBackend::msgResize(vecTmp, dataSize); memcpy(_TMockBackend::msgData(vecTmp), _TBackend::msgData(msg), dataSize); b &= _TMockBackend::send(p_mockSocket, vecTmp, (typename _TMockBackend::SendFlag)flags); } if(p_mode != PSocketMode::MOCK){ b &= _TBackend::send(p_socket, msg, (typename _TBackend::SendFlag)flags); } return b; } ///Recieve message from the given socket /** @param data : data to be recieved * @param flags : flags to be used to send the message (none, dontwait, sndmore, etc) * @return true on success, false otherwise */ template<typename U, typename _TFlag> bool recvData(U & data, _TFlag flags){ bool b(true); if(p_mode == PSocketMode::NO_MOCK){ //Normal mode typename _TBackend::Message msg; b &= _TBackend::recv(p_socket, msg, (typename _TBackend::RecvFlag)flags); //If the message is empty we cannot initialise the given data, so, this is an error b &= _TBackend::msgSize(msg) != 0lu; if(b){ char* iter = _TBackend::msgData(msg); b &= data_message_load<U>(iter, data); } }else if(p_mode == PSocketMode::MOCK){ //Mock mode typename _TMockBackend::Message msg; b &= _TMockBackend::recv(p_mockSocket, msg, (typename _TMockBackend::RecvFlag)flags); //If the message is empty we cannot initialise the given data, so, this is an error b &= _TMockBackend::msgSize(msg) != 0lu; if(b){ char* iter = _TMockBackend::msgData(msg); b &= data_message_load<U>(iter, data); } }else{ //Mock record mode typename _TBackend::Message msg; b &= _TBackend::recv(p_socket, msg, (typename _TBackend::RecvFlag)flags); //If the message is empty we cannot initialise the given data, so, this is an error b &= _TBackend::msgSize(msg) != 0lu; if(b){ char* iter = _TBackend::msgData(msg); b &= data_message_load<U>(iter, data); if(b){ //Let's convert the message into the mock backend typename _TMockBackend::Message msgMock; size_t dataSize(_TBackend::msgSize(msg)); _TMockBackend::msgResize(msgMock, dataSize); memcpy(_TMockBackend::msgData(msgMock), _TBackend::msgData(msg), dataSize); b &= _TMockBackend::recv(p_mockSocket, msgMock, (typename _TMockBackend::RecvFlag)flags); } } } return b; } ///Recieve message from the given socket /** @param msg : message to be recieved * @param flags : flags to be used to send the message (none, dontwait, sndmore, etc) * @return true on success, false otherwise */ template<typename _TFlag> bool recvMsg(typename _TBackend::Message & msg, _TFlag flags){ bool b(true); if(p_mode == PSocketMode::NO_MOCK){ //Normal mode b &= _TBackend::recv(p_socket, msg, (typename _TBackend::RecvFlag)flags); }else if(p_mode == PSocketMode::MOCK){ //Mock mode typename _TMockBackend::Message msgMock; b &= _TMockBackend::recv(p_mockSocket, msgMock, (typename _TMockBackend::RecvFlag)flags); if(b){ size_t dataSize(_TMockBackend::msgSize(msgMock)); _TBackend::msgResize(msg, dataSize); memcpy(_TBackend::msgData(msg), _TMockBackend::msgData(msgMock), dataSize); } }else{ //Mock record mode b &= _TBackend::recv(p_socket, msg, (typename _TBackend::RecvFlag)flags); if(b){ typename _TMockBackend::Message msgMock; size_t dataSize(_TBackend::msgSize(msg)); _TMockBackend::msgResize(msgMock, dataSize); memcpy(_TMockBackend::msgData(msgMock), _TBackend::msgData(msg), dataSize); b &= _TMockBackend::recv(p_mockSocket, msgMock, (typename _TMockBackend::RecvFlag)flags); } } return b; } void close(); bool isConnected() const; private: void initialisationPGenericSocket(PSocketMode::PSocketMode mode); ///Mode of the Socket (no mock, mock, mock_record) PSocketMode::PSocketMode p_mode; ///Socket to be used with the classical backend typename _TBackend::Socket p_socket; ///Socket to be used with the mock backend typename _TMockBackend::Socket p_mockSocket; }; #include "PGenericSocket_impl.h" #endif