#pragma once #include #include namespace sp { namespace io { using SocketHandle = int; struct TcpTag {}; class SocketError : public std::exception { private: std::string m_Error; public: SocketError(std::string&& a_Msg) : m_Error(std::move(a_Msg)) {} virtual const char* what() const noexcept override { return m_Error.c_str(); } }; template <> class IOInterface : private NonCopyable { public: /** * \enum Status * \brief Describes the state of a socket */ enum class Status { /** The socket is connected */ Connected, /** The socket is not connected */ Disconnected, /** Something bad happened */ Error, }; IOInterface(); IOInterface(const std::string& a_Host, std::uint16_t a_Port); IOInterface(IOInterface&& a_Other); virtual ~IOInterface(); DataBuffer Read(std::size_t a_Amount); void Write(const sp::DataBuffer& a_Data); /** * \brief Allows to set the socket in non blocking/blocking mode * \param a_Block If set to true, every call to Read will wait until the socket receives something * \return true if the operation was successful */ bool SetBlocking(bool a_Block); /** * \brief Getter of the m_Status member * \return The TcpSocket::Status of this socket */ Status GetStatus() const; /** * \brief Disconnects the socket from the remote * \note Does nothing if the socket is not connected. \n * This function is also called by the destructor. */ void Disconnect(); private: SocketHandle m_Handle; Status m_Status; void Connect(const std::string& a_Host, std::uint16_t a_Port); friend class TcpListener; }; /** * \typedef TcpSocket */ using TcpSocket = IOInterface; } // namespace io } // namespace sp