Skip to content
Snippets Groups Projects
PGenericSocket.h 6.25 KiB
Newer Older
Pierre Aubert's avatar
Pierre Aubert committed
/***************************************
	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);
Pierre Aubert's avatar
Pierre Aubert committed
				}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);
Pierre Aubert's avatar
Pierre Aubert committed
				}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);
Pierre Aubert's avatar
Pierre Aubert committed
			}
			if(p_mode != PSocketMode::MOCK){
				b &= _TBackend::send(p_socket, msg, (typename _TBackend::SendFlag)flags);
Pierre Aubert's avatar
Pierre Aubert committed
			}
			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);
Pierre Aubert's avatar
Pierre Aubert committed
				//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);
Pierre Aubert's avatar
Pierre Aubert committed
				//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);
Pierre Aubert's avatar
Pierre Aubert committed
				//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);
Pierre Aubert's avatar
Pierre Aubert committed
					}
				}
			}
			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);
Pierre Aubert's avatar
Pierre Aubert committed
			}else if(p_mode == PSocketMode::MOCK){	//Mock mode
				typename _TMockBackend::Message msgMock;
				b &= _TMockBackend::recv(p_mockSocket, msgMock, (typename _TMockBackend::RecvFlag)flags);
Pierre Aubert's avatar
Pierre Aubert committed
				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);
Pierre Aubert's avatar
Pierre Aubert committed
				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);
Pierre Aubert's avatar
Pierre Aubert committed
				}
			}
			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