diff --git a/bin/unit_tests/assets/html/eepp-ui-reddit-old-thread.webp b/bin/unit_tests/assets/html/eepp-ui-reddit-old-thread.webp index 8affeff14..31db9e495 100644 Binary files a/bin/unit_tests/assets/html/eepp-ui-reddit-old-thread.webp and b/bin/unit_tests/assets/html/eepp-ui-reddit-old-thread.webp differ diff --git a/include/eepp/graphics/base.hpp b/include/eepp/graphics/base.hpp index 8f28dd945..fa55652da 100644 --- a/include/eepp/graphics/base.hpp +++ b/include/eepp/graphics/base.hpp @@ -1,7 +1,7 @@ #ifndef EE_GRAPHICS_BASE #define EE_GRAPHICS_BASE -#include +#include #include #include diff --git a/include/eepp/graphics/drawableresource.hpp b/include/eepp/graphics/drawableresource.hpp index 9a2754284..0141912a5 100644 --- a/include/eepp/graphics/drawableresource.hpp +++ b/include/eepp/graphics/drawableresource.hpp @@ -1,9 +1,11 @@ #ifndef EE_GRAPHICS_DRAWABLERESOURCE_HPP #define EE_GRAPHICS_DRAWABLERESOURCE_HPP -#include +#include #include +#include #include +#include #include namespace EE { namespace Graphics { diff --git a/include/eepp/graphics/image.hpp b/include/eepp/graphics/image.hpp index 97afec088..bceaf6e60 100644 --- a/include/eepp/graphics/image.hpp +++ b/include/eepp/graphics/image.hpp @@ -1,7 +1,8 @@ #ifndef EE_GRAPHICSCIMAGE_HPP #define EE_GRAPHICSCIMAGE_HPP -#include +#include +#include #include #include @@ -315,11 +316,11 @@ class EE_API Image { /** Overload the assignment operator to ensure the image copy */ Image& operator=( const Image& right ); - /** @brief Move constructor */ - Image( Image&& other ) noexcept; + /** @brief Move constructor */ + Image( Image&& other ) noexcept; - /** @brief Move assignment operator */ - Image& operator=( Image&& other ) noexcept; + /** @brief Move assignment operator */ + Image& operator=( Image&& other ) noexcept; virtual ~Image(); diff --git a/include/eepp/graphics/ninepatch.hpp b/include/eepp/graphics/ninepatch.hpp index 6c7102b1d..7adec70fd 100644 --- a/include/eepp/graphics/ninepatch.hpp +++ b/include/eepp/graphics/ninepatch.hpp @@ -1,7 +1,7 @@ #ifndef EE_GRAPHICS_NINEPATCH_HPP #define EE_GRAPHICS_NINEPATCH_HPP -#include +#include #include #include diff --git a/include/eepp/graphics/resource.hpp b/include/eepp/graphics/resource.hpp index ac603e37e..407bf1354 100644 --- a/include/eepp/graphics/resource.hpp +++ b/include/eepp/graphics/resource.hpp @@ -7,7 +7,9 @@ #include #include -#include +#include +#include +#include namespace EE { namespace Graphics { diff --git a/include/eepp/graphics/shaderprogram.hpp b/include/eepp/graphics/shaderprogram.hpp index 901c48408..46c277e17 100644 --- a/include/eepp/graphics/shaderprogram.hpp +++ b/include/eepp/graphics/shaderprogram.hpp @@ -1,6 +1,7 @@ #ifndef EE_GRAPHICSCSHADERPROGRAM_H #define EE_GRAPHICSCSHADERPROGRAM_H +#include #include #include diff --git a/include/eepp/graphics/systemfontresolver.hpp b/include/eepp/graphics/systemfontresolver.hpp index 358f1e9d1..bfd7bf551 100644 --- a/include/eepp/graphics/systemfontresolver.hpp +++ b/include/eepp/graphics/systemfontresolver.hpp @@ -2,6 +2,8 @@ #define EE_GRAPHICS_SYSTEMFONTRESOLVER_HPP #include +#include +#include #include #include #include diff --git a/include/eepp/graphics/texture.hpp b/include/eepp/graphics/texture.hpp index e3395ee79..b1dc5ea6c 100644 --- a/include/eepp/graphics/texture.hpp +++ b/include/eepp/graphics/texture.hpp @@ -1,8 +1,9 @@ #ifndef EE_GRAPHICSCTEXTURE_H #define EE_GRAPHICSCTEXTURE_H -#include +#include #include +#include #include #include #include diff --git a/include/eepp/network/ftp.hpp b/include/eepp/network/ftp.hpp index 7582fc6d9..773ad285a 100644 --- a/include/eepp/network/ftp.hpp +++ b/include/eepp/network/ftp.hpp @@ -1,402 +1,402 @@ -#ifndef EE_NETWORKCFTP_HPP -#define EE_NETWORKCFTP_HPP - -#include -#include -#include -#include -#include -#include - -using namespace EE::System; - -namespace EE { namespace Network { - -class IpAddress; - -/** @brief A FTP client */ -class EE_API Ftp : NonCopyable { - public: - /** @brief Enumeration of transfer modes */ - enum TransferMode { - Binary, ///< Binary mode (file is transferred as a sequence of bytes) - Ascii, ///< Text mode using ASCII encoding - Ebcdic ///< Text mode using EBCDIC encoding - }; - - /** @brief Define a FTP response */ - class EE_API Response { - public: - /** @brief Status codes possibly returned by a FTP response */ - enum Status { - // 1xx: the requested action is being initiated, - // expect another reply before proceeding with a new command - RestartMarkerReply = 110, ///< Restart marker reply - ServiceReadySoon = 120, ///< Service ready in N minutes - DataConnectionAlreadyOpened = - 125, ///< Data connection already opened, transfer starting - OpeningDataConnection = 150, ///< File status ok, about to open data connection - - // 2xx: the requested action has been successfully completed - Ok = 200, ///< Command ok - PointlessCommand = 202, ///< Command not implemented - SystemStatus = 211, ///< System status, or system help reply - DirectoryStatus = 212, ///< Directory status - FileStatus = 213, ///< File status - HelpMessage = 214, ///< Help message - SystemType = 215, ///< NAME system type, where NAME is an official system name from the - ///< list in the Assigned Numbers document - ServiceReady = 220, ///< Service ready for new user - ClosingConnection = 221, ///< Service closing control connection - DataConnectionOpened = 225, ///< Data connection open, no transfer in progress - ClosingDataConnection = - 226, ///< Closing data connection, requested file action successful - EnteringPassiveMode = 227, ///< Entering passive mode - LoggedIn = 230, ///< User logged in, proceed. Logged out if appropriate - FileActionOk = 250, ///< Requested file action ok - DirectoryOk = 257, ///< PATHNAME created - - // 3xx: the command has been accepted, but the requested action - // is dormant, pending receipt of further information - NeedPassword = 331, ///< User name ok, need password - NeedAccountToLogIn = 332, ///< Need account for login - NeedInformation = 350, ///< Requested file action pending further information - - // 4xx: the command was not accepted and the requested action did not take place, - // but the error condition is temporary and the action may be requested again - ServiceUnavailable = 421, ///< Service not available, closing control connection - DataConnectionUnavailable = 425, ///< Can't open data connection - TransferAborted = 426, ///< Connection closed, transfer aborted - FileActionAborted = 450, ///< Requested file action not taken - LocalError = 451, ///< Requested action aborted, local error in processing - InsufficientStorageSpace = 452, ///< Requested action not taken; insufficient storage - ///< space in system, file unavailable - - // 5xx: the command was not accepted and - // the requested action did not take place - CommandUnknown = 500, ///< Syntax error, command unrecognized - ParametersUnknown = 501, ///< Syntax error in parameters or arguments - CommandNotImplemented = 502, ///< Command not implemented - BadCommandSequence = 503, ///< Bad sequence of commands - ParameterNotImplemented = 504, ///< Command not implemented for that parameter - NotLoggedIn = 530, ///< Not logged in - NeedAccountToStore = 532, ///< Need account for storing files - FileUnavailable = 550, ///< Requested action not taken, file unavailable - PageTypeUnknown = 551, ///< Requested action aborted, page type unknown - NotEnoughMemory = 552, ///< Requested file action aborted, exceeded storage allocation - FilenameNotAllowed = 553, ///< Requested action not taken, file name not allowed - - // 10xx: Custom codes - InvalidResponse = 1000, ///< Response is not a valid FTP one - ConnectionFailed = 1001, ///< Connection with server failed - ConnectionClosed = 1002, ///< Connection with server closed - InvalidFile = 1003 ///< Invalid file to upload / download - }; - - /** @brief Default constructor - ** - ** This constructor is used by the FTP client to build - ** the response. - ** - ** @param code Response status code - ** @param message Response message */ - explicit Response( Status code = InvalidResponse, const std::string& message = "" ); - - /** @brief Check if the status code means a success - ** - ** This function is defined for convenience, it is - ** equivalent to testing if the status code is < 400. - ** - ** @return True if the status is a success, false if it is a failure */ - bool isOk() const; - - /** @brief Get the status code of the response - ** - ** @return Status code */ - Status getStatus() const; - - /** @brief Get the full message contained in the response - ** @return The response message */ - const std::string& getMessage() const; - - private: - // Member data - Status mStatus; ///< Status code returned from the server - std::string mMessage; ///< Last message received from the server - }; - - /** @brief Specialization of FTP response returning a directory */ - class EE_API DirectoryResponse : public Response { - public: - /** @brief Default constructor - ** @param response Source response */ - DirectoryResponse( const Response& response ); - - /** @brief Get the directory returned in the response - ** @return Directory name */ - const std::string& getDirectory() const; - - private: - // Member data - std::string mDirectory; ///< Directory extracted from the response message - }; - - /** @brief Specialization of FTP response returning a filename listing */ - class EE_API ListingResponse : public Response { - public: - /** @brief Default constructor - ** - ** @param response Source response - ** @param data Data containing the raw listing */ - ListingResponse( const Response& response, const std::string& data ); - - /** @brief Return the array of directory/file names - ** - ** @return Array containing the requested listing */ - const std::vector& getListing() const; - - private: - // Member data - std::vector mListing; ///< Directory/file names extracted from the data - }; - - Ftp(); - - /** @brief Destructor - ** Automatically closes the connection with the server if - ** it is still opened. */ - ~Ftp(); - - /** @brief Connect to the specified FTP server - ** The port has a default value of 21, which is the standard - ** port used by the FTP protocol. You shouldn't use a different - ** value, unless you really know what you do. - ** This function tries to connect to the server so it may take - ** a while to complete, especially if the server is not - ** reachable. To avoid blocking your application for too long, - ** you can use a timeout. The default value, Time::Zero, means that the - ** system timeout will be used (which is usually pretty long). - ** @param server Hostname or address of the FTP server to connect to - ** @param port Port used for the connection - ** @param useTLS force TLS connection for FTPS. - ** @param validateCertificate Enables certificate validation for https request - ** @param validateHostname Enables hostname validation for https request - ** @param timeout Maximum time to wait - ** @return Server response to the request - ** @see disconnect */ - Response connect( const std::string& server, unsigned short port = 21, bool useTLS = false, - bool validateCertificate = true, bool validateHostname = true, - const Time& timeout = Time::Zero ); - - /** @brief Close the connection with the server - ** @return Server response to the request - ** @see connect */ - Response disconnect(); - - /** @brief Log in using an anonymous account - ** Logging in is mandatory after connecting to the server. - ** Users that are not logged in cannot perform any operation. - ** @return Server response to the request */ - Response login(); - - /** @brief Log in using a username and a password - ** Logging in is mandatory after connecting to the server. - ** Users that are not logged in cannot perform any operation. - ** @param name User name - ** @param password Password - ** @return Server response to the request */ - Response login( const std::string& name, const std::string& password ); - - /** @brief Send a null command to keep the connection alive - ** This command is useful because the server may close the - ** connection automatically if no command is sent. - ** @return Server response to the request */ - Response keepAlive(); - - /** @brief Get the current working directory - ** The working directory is the root path for subsequent - ** operations involving directories and/or filenames. - ** @return Server response to the request - ** @see getDirectoryListing, changeDirectory, parentDirectory */ - DirectoryResponse getWorkingDirectory(); - - /** @brief Get the contents of the given directory - ** This function retrieves the sub-directories and files - ** contained in the given directory. It is not recursive. - ** The @a directory parameter is relative to the current - ** working directory. - ** @param directory Directory to list - ** @return Server response to the request - ** @see getWorkingDirectory, changeDirectory, parentDirectory */ - ListingResponse getDirectoryListing( const std::string& directory = "" ); - - /** @brief Change the current working directory - ** The new directory must be relative to the current one. - ** @param directory New working directory - ** @return Server response to the request - ** @see getWorkingDirectory, getDirectoryListing, parentDirectory */ - Response changeDirectory( const std::string& directory ); - - /** @brief Go to the parent directory of the current one - ** @return Server response to the request - ** @see getWorkingDirectory, getDirectoryListing, changeDirectory */ - Response parentDirectory(); - - /** @brief Create a new directory - ** The new directory is created as a child of the current - ** working directory. - ** @param name Name of the directory to create - ** @return Server response to the request - ** @see deleteDirectory */ - Response createDirectory( const std::string& name ); - - /** @brief Remove an existing directory - ** The directory to remove must be relative to the - ** current working directory. - ** Use this function with caution, the directory will - ** be removed permanently! - ** @param name Name of the directory to remove - ** @return Server response to the request - ** @see createDirectory */ - Response deleteDirectory( const std::string& name ); - - /** @brief Rename an existing file - ** The filenames must be relative to the current working - ** directory. - ** @param file File to rename - ** @param newName New name of the file - ** @return Server response to the request - ** @see deleteFile */ - Response renameFile( const std::string& file, const std::string& newName ); - - /** @brief Remove an existing file - ** The file name must be relative to the current working - ** directory. - ** Use this function with caution, the file will be - ** removed permanently! - ** @param name File to remove - ** @return Server response to the request - ** @see RenameFile */ - Response deleteFile( const std::string& name ); - - /** @brief Download a file from the server - ** The filename of the distant file is relative to the - ** current working directory of the server, and the local - ** destination path is relative to the current directory - ** of your application. - ** If a file with the same filename as the distant file - ** already exists in the local destination path, it will - ** be overwritten. - ** @param remoteFile Filename of the distant file to download - ** @param localPath Where to put to file on the local computer - ** @param mode Transfer mode - ** @return Server response to the request - ** @see upload */ - Response download( const std::string& remoteFile, const std::string& localPath, - TransferMode mode = Binary ); - - /** @brief Upload a file to the server - ** The name of the local file is relative to the current - ** working directory of your application, and the - ** remote path is relative to the current directory of the - ** FTP server. - ** @param localFile Path of the local file to upload - ** @param remotePath Where to put to file on the server - ** @param mode Transfer mode - ** @param append Pass true to append to or false to overwrite the remote file if it already - *exists - ** @return Server response to the request - ** @see download */ - Response upload( const std::string& localFile, const std::string& remotePath, - TransferMode mode = Binary, bool append = false ); - - /** @return The server hostname (available only after connect). */ - const std::string& getHostname() const; - - /** @return True if connection is using TLS (available only after connect). */ - const bool& isTLS() const; - - private: - /** @brief Send a command to the FTP server - ** @param command Command to send - ** @param parameter Command parameter - ** @return Server response to the request */ - Response sendCommand( const std::string& command, const std::string& parameter = "" ); - - /** @brief Receive a response from the server - ** This function must be called after each call to - ** SendCommand that expects a response. - ** @return Server response to the request */ - Response getResponse(); - - /** @brief Utility class for exchanging data with the server on the data channel */ - class DataChannel; - friend class DataChannel; - - // Member data - TcpSocket* mCommandSocket; ///< Socket holding the control connection with the server - std::string mReceiveBuffer; ///< Received command data that is yet to be processed - std::string mHostName; - bool mConnected; - bool mIsTLS; -}; - -}} // namespace EE::Network - -#endif // EE_NETWORKCFTP_HPP - -/** -@class EE::Network::Ftp - -Ftp is a very simple FTP client that allows you -to communicate with a FTP server. The FTP protocol allows -you to manipulate a remote file system (list files, -upload, download, create, remove, ...). -Using the FTP client consists of 4 parts: -@li Connecting to the FTP server -@li Logging in (either as a registered user or anonymously) -@li Sending commands to the server -@li Disconnecting (this part can be done implicitly by the destructor) -Every command returns a FTP response, which contains the -status code as well as a message from the server. Some -commands such as getWorkingDirectory and getDirectoryListing -return additional data, and use a class derived from -Ftp::Response to provide this data. -All commands, especially upload and download, may take some -time to complete. This is important to know if you don't want -to block your application while the server is completing -the task. -Usage example: -@code -// Create a new FTP client -Ftp ftp; - -// Connect to the server -Ftp::Response response = ftp.connect("ftp://ftp.myserver.com"); -if (response.isOk()) - std::cout << "Connected" << std::endl; - -// Log in -response = ftp.login("laurent", "dF6Zm89D"); -if (response.isOk()) - std::cout << "Logged in" << std::endl; - -// Print the working directory -Ftp::DirectoryResponse directory = ftp.getWorkingDirectory(); -if (directory.isOk()) - std::cout << "Working directory: " << directory.getDirectory() << std::endl; - -// Create a new directory -response = ftp.createDirectory("files"); -if (response.isOk()) - std::cout << "Created new directory" << std::endl; - -// Upload a file to this new directory -response = ftp.upload("local-path/file.txt", "files", Ftp::Ascii); -if (response.isOk()) - std::cout << "File uploaded" << std::endl; - -// Disconnect from the server (optional) -ftp.disconnect(); -@endcode -*/ +#ifndef EE_NETWORKCFTP_HPP +#define EE_NETWORKCFTP_HPP + +#include +#include +#include +#include +#include +#include + +using namespace EE::System; + +namespace EE { namespace Network { + +class IpAddress; + +/** @brief A FTP client */ +class EE_API Ftp : NonCopyable { + public: + /** @brief Enumeration of transfer modes */ + enum TransferMode { + Binary, ///< Binary mode (file is transferred as a sequence of bytes) + Ascii, ///< Text mode using ASCII encoding + Ebcdic ///< Text mode using EBCDIC encoding + }; + + /** @brief Define a FTP response */ + class EE_API Response { + public: + /** @brief Status codes possibly returned by a FTP response */ + enum Status { + // 1xx: the requested action is being initiated, + // expect another reply before proceeding with a new command + RestartMarkerReply = 110, ///< Restart marker reply + ServiceReadySoon = 120, ///< Service ready in N minutes + DataConnectionAlreadyOpened = + 125, ///< Data connection already opened, transfer starting + OpeningDataConnection = 150, ///< File status ok, about to open data connection + + // 2xx: the requested action has been successfully completed + Ok = 200, ///< Command ok + PointlessCommand = 202, ///< Command not implemented + SystemStatus = 211, ///< System status, or system help reply + DirectoryStatus = 212, ///< Directory status + FileStatus = 213, ///< File status + HelpMessage = 214, ///< Help message + SystemType = 215, ///< NAME system type, where NAME is an official system name from the + ///< list in the Assigned Numbers document + ServiceReady = 220, ///< Service ready for new user + ClosingConnection = 221, ///< Service closing control connection + DataConnectionOpened = 225, ///< Data connection open, no transfer in progress + ClosingDataConnection = + 226, ///< Closing data connection, requested file action successful + EnteringPassiveMode = 227, ///< Entering passive mode + LoggedIn = 230, ///< User logged in, proceed. Logged out if appropriate + FileActionOk = 250, ///< Requested file action ok + DirectoryOk = 257, ///< PATHNAME created + + // 3xx: the command has been accepted, but the requested action + // is dormant, pending receipt of further information + NeedPassword = 331, ///< User name ok, need password + NeedAccountToLogIn = 332, ///< Need account for login + NeedInformation = 350, ///< Requested file action pending further information + + // 4xx: the command was not accepted and the requested action did not take place, + // but the error condition is temporary and the action may be requested again + ServiceUnavailable = 421, ///< Service not available, closing control connection + DataConnectionUnavailable = 425, ///< Can't open data connection + TransferAborted = 426, ///< Connection closed, transfer aborted + FileActionAborted = 450, ///< Requested file action not taken + LocalError = 451, ///< Requested action aborted, local error in processing + InsufficientStorageSpace = 452, ///< Requested action not taken; insufficient storage + ///< space in system, file unavailable + + // 5xx: the command was not accepted and + // the requested action did not take place + CommandUnknown = 500, ///< Syntax error, command unrecognized + ParametersUnknown = 501, ///< Syntax error in parameters or arguments + CommandNotImplemented = 502, ///< Command not implemented + BadCommandSequence = 503, ///< Bad sequence of commands + ParameterNotImplemented = 504, ///< Command not implemented for that parameter + NotLoggedIn = 530, ///< Not logged in + NeedAccountToStore = 532, ///< Need account for storing files + FileUnavailable = 550, ///< Requested action not taken, file unavailable + PageTypeUnknown = 551, ///< Requested action aborted, page type unknown + NotEnoughMemory = 552, ///< Requested file action aborted, exceeded storage allocation + FilenameNotAllowed = 553, ///< Requested action not taken, file name not allowed + + // 10xx: Custom codes + InvalidResponse = 1000, ///< Response is not a valid FTP one + ConnectionFailed = 1001, ///< Connection with server failed + ConnectionClosed = 1002, ///< Connection with server closed + InvalidFile = 1003 ///< Invalid file to upload / download + }; + + /** @brief Default constructor + ** + ** This constructor is used by the FTP client to build + ** the response. + ** + ** @param code Response status code + ** @param message Response message */ + explicit Response( Status code = InvalidResponse, const std::string& message = "" ); + + /** @brief Check if the status code means a success + ** + ** This function is defined for convenience, it is + ** equivalent to testing if the status code is < 400. + ** + ** @return True if the status is a success, false if it is a failure */ + bool isOk() const; + + /** @brief Get the status code of the response + ** + ** @return Status code */ + Status getStatus() const; + + /** @brief Get the full message contained in the response + ** @return The response message */ + const std::string& getMessage() const; + + private: + // Member data + Status mStatus; ///< Status code returned from the server + std::string mMessage; ///< Last message received from the server + }; + + /** @brief Specialization of FTP response returning a directory */ + class EE_API DirectoryResponse : public Response { + public: + /** @brief Default constructor + ** @param response Source response */ + DirectoryResponse( const Response& response ); + + /** @brief Get the directory returned in the response + ** @return Directory name */ + const std::string& getDirectory() const; + + private: + // Member data + std::string mDirectory; ///< Directory extracted from the response message + }; + + /** @brief Specialization of FTP response returning a filename listing */ + class EE_API ListingResponse : public Response { + public: + /** @brief Default constructor + ** + ** @param response Source response + ** @param data Data containing the raw listing */ + ListingResponse( const Response& response, const std::string& data ); + + /** @brief Return the array of directory/file names + ** + ** @return Array containing the requested listing */ + const std::vector& getListing() const; + + private: + // Member data + std::vector mListing; ///< Directory/file names extracted from the data + }; + + Ftp(); + + /** @brief Destructor + ** Automatically closes the connection with the server if + ** it is still opened. */ + ~Ftp(); + + /** @brief Connect to the specified FTP server + ** The port has a default value of 21, which is the standard + ** port used by the FTP protocol. You shouldn't use a different + ** value, unless you really know what you do. + ** This function tries to connect to the server so it may take + ** a while to complete, especially if the server is not + ** reachable. To avoid blocking your application for too long, + ** you can use a timeout. The default value, Time::Zero, means that the + ** system timeout will be used (which is usually pretty long). + ** @param server Hostname or address of the FTP server to connect to + ** @param port Port used for the connection + ** @param useTLS force TLS connection for FTPS. + ** @param validateCertificate Enables certificate validation for https request + ** @param validateHostname Enables hostname validation for https request + ** @param timeout Maximum time to wait + ** @return Server response to the request + ** @see disconnect */ + Response connect( const std::string& server, unsigned short port = 21, bool useTLS = false, + bool validateCertificate = true, bool validateHostname = true, + const Time& timeout = Time::Zero ); + + /** @brief Close the connection with the server + ** @return Server response to the request + ** @see connect */ + Response disconnect(); + + /** @brief Log in using an anonymous account + ** Logging in is mandatory after connecting to the server. + ** Users that are not logged in cannot perform any operation. + ** @return Server response to the request */ + Response login(); + + /** @brief Log in using a username and a password + ** Logging in is mandatory after connecting to the server. + ** Users that are not logged in cannot perform any operation. + ** @param name User name + ** @param password Password + ** @return Server response to the request */ + Response login( const std::string& name, const std::string& password ); + + /** @brief Send a null command to keep the connection alive + ** This command is useful because the server may close the + ** connection automatically if no command is sent. + ** @return Server response to the request */ + Response keepAlive(); + + /** @brief Get the current working directory + ** The working directory is the root path for subsequent + ** operations involving directories and/or filenames. + ** @return Server response to the request + ** @see getDirectoryListing, changeDirectory, parentDirectory */ + DirectoryResponse getWorkingDirectory(); + + /** @brief Get the contents of the given directory + ** This function retrieves the sub-directories and files + ** contained in the given directory. It is not recursive. + ** The @a directory parameter is relative to the current + ** working directory. + ** @param directory Directory to list + ** @return Server response to the request + ** @see getWorkingDirectory, changeDirectory, parentDirectory */ + ListingResponse getDirectoryListing( const std::string& directory = "" ); + + /** @brief Change the current working directory + ** The new directory must be relative to the current one. + ** @param directory New working directory + ** @return Server response to the request + ** @see getWorkingDirectory, getDirectoryListing, parentDirectory */ + Response changeDirectory( const std::string& directory ); + + /** @brief Go to the parent directory of the current one + ** @return Server response to the request + ** @see getWorkingDirectory, getDirectoryListing, changeDirectory */ + Response parentDirectory(); + + /** @brief Create a new directory + ** The new directory is created as a child of the current + ** working directory. + ** @param name Name of the directory to create + ** @return Server response to the request + ** @see deleteDirectory */ + Response createDirectory( const std::string& name ); + + /** @brief Remove an existing directory + ** The directory to remove must be relative to the + ** current working directory. + ** Use this function with caution, the directory will + ** be removed permanently! + ** @param name Name of the directory to remove + ** @return Server response to the request + ** @see createDirectory */ + Response deleteDirectory( const std::string& name ); + + /** @brief Rename an existing file + ** The filenames must be relative to the current working + ** directory. + ** @param file File to rename + ** @param newName New name of the file + ** @return Server response to the request + ** @see deleteFile */ + Response renameFile( const std::string& file, const std::string& newName ); + + /** @brief Remove an existing file + ** The file name must be relative to the current working + ** directory. + ** Use this function with caution, the file will be + ** removed permanently! + ** @param name File to remove + ** @return Server response to the request + ** @see RenameFile */ + Response deleteFile( const std::string& name ); + + /** @brief Download a file from the server + ** The filename of the distant file is relative to the + ** current working directory of the server, and the local + ** destination path is relative to the current directory + ** of your application. + ** If a file with the same filename as the distant file + ** already exists in the local destination path, it will + ** be overwritten. + ** @param remoteFile Filename of the distant file to download + ** @param localPath Where to put to file on the local computer + ** @param mode Transfer mode + ** @return Server response to the request + ** @see upload */ + Response download( const std::string& remoteFile, const std::string& localPath, + TransferMode mode = Binary ); + + /** @brief Upload a file to the server + ** The name of the local file is relative to the current + ** working directory of your application, and the + ** remote path is relative to the current directory of the + ** FTP server. + ** @param localFile Path of the local file to upload + ** @param remotePath Where to put to file on the server + ** @param mode Transfer mode + ** @param append Pass true to append to or false to overwrite the remote file if it already + *exists + ** @return Server response to the request + ** @see download */ + Response upload( const std::string& localFile, const std::string& remotePath, + TransferMode mode = Binary, bool append = false ); + + /** @return The server hostname (available only after connect). */ + const std::string& getHostname() const; + + /** @return True if connection is using TLS (available only after connect). */ + const bool& isTLS() const; + + private: + /** @brief Send a command to the FTP server + ** @param command Command to send + ** @param parameter Command parameter + ** @return Server response to the request */ + Response sendCommand( const std::string& command, const std::string& parameter = "" ); + + /** @brief Receive a response from the server + ** This function must be called after each call to + ** SendCommand that expects a response. + ** @return Server response to the request */ + Response getResponse(); + + /** @brief Utility class for exchanging data with the server on the data channel */ + class DataChannel; + friend class DataChannel; + + // Member data + TcpSocket* mCommandSocket; ///< Socket holding the control connection with the server + std::string mReceiveBuffer; ///< Received command data that is yet to be processed + std::string mHostName; + bool mConnected; + bool mIsTLS; +}; + +}} // namespace EE::Network + +#endif // EE_NETWORKCFTP_HPP + +/** +@class EE::Network::Ftp + +Ftp is a very simple FTP client that allows you +to communicate with a FTP server. The FTP protocol allows +you to manipulate a remote file system (list files, +upload, download, create, remove, ...). +Using the FTP client consists of 4 parts: +@li Connecting to the FTP server +@li Logging in (either as a registered user or anonymously) +@li Sending commands to the server +@li Disconnecting (this part can be done implicitly by the destructor) +Every command returns a FTP response, which contains the +status code as well as a message from the server. Some +commands such as getWorkingDirectory and getDirectoryListing +return additional data, and use a class derived from +Ftp::Response to provide this data. +All commands, especially upload and download, may take some +time to complete. This is important to know if you don't want +to block your application while the server is completing +the task. +Usage example: +@code +// Create a new FTP client +Ftp ftp; + +// Connect to the server +Ftp::Response response = ftp.connect("ftp://ftp.myserver.com"); +if (response.isOk()) + std::cout << "Connected" << std::endl; + +// Log in +response = ftp.login("laurent", "dF6Zm89D"); +if (response.isOk()) + std::cout << "Logged in" << std::endl; + +// Print the working directory +Ftp::DirectoryResponse directory = ftp.getWorkingDirectory(); +if (directory.isOk()) + std::cout << "Working directory: " << directory.getDirectory() << std::endl; + +// Create a new directory +response = ftp.createDirectory("files"); +if (response.isOk()) + std::cout << "Created new directory" << std::endl; + +// Upload a file to this new directory +response = ftp.upload("local-path/file.txt", "files", Ftp::Ascii); +if (response.isOk()) + std::cout << "File uploaded" << std::endl; + +// Disconnect from the server (optional) +ftp.disconnect(); +@endcode +*/ diff --git a/include/eepp/network/http.hpp b/include/eepp/network/http.hpp index b3d313a24..7082cd53c 100644 --- a/include/eepp/network/http.hpp +++ b/include/eepp/network/http.hpp @@ -2,8 +2,10 @@ #define EE_NETWORKCHTTP_HPP #include -#include +#include +#include #include +#include #include #include #include @@ -186,7 +188,7 @@ class EE_API Http : NonCopyable, public std::enable_shared_from_this { ///< target resource. Patch, ///< The PATCH method is used to apply partial modifications to a resource. Connect ///< The CONNECT method starts two-way communications with the requested - ///< resource. It can be used to open a tunnel. + ///< resource. It can be used to open a tunnel. }; /** @brief Enumerate the available states for a request */ diff --git a/include/eepp/network/ipaddress.hpp b/include/eepp/network/ipaddress.hpp index 7ae0db374..c901c1680 100644 --- a/include/eepp/network/ipaddress.hpp +++ b/include/eepp/network/ipaddress.hpp @@ -1,194 +1,194 @@ -#ifndef EE_NETWORKCIPADDRESS_HPP -#define EE_NETWORKCIPADDRESS_HPP - -#include -#include -using namespace EE::System; - -#include -#include -#include - -namespace EE { namespace Network { - -/** @brief Encapsulate an IPv4 network address */ -class EE_API IpAddress { - public: - /** @brief Default constructor - ** This constructor creates an empty (invalid) address */ - IpAddress(); - - /** @brief Construct the address from a string - ** Here @a address can be either a decimal address - ** (ex: "192.168.1.56") or a network name (ex: "localhost"). - ** @param address IP address or network name */ - IpAddress( const std::string& address ); - - /** @brief Construct the address from a string - ** Here @a address can be either a decimal address - ** (ex: "192.168.1.56") or a network name (ex: "localhost"). - ** This is equivalent to the constructor taking a std::string - ** parameter, it is defined for convenience so that the - ** implicit conversions from literal strings to IpAddress work. - ** @param address IP address or network name */ - IpAddress( const char* address ); - - /** @brief Construct the address from 4 bytes - ** Calling IpAddress(a, b, c, d) is equivalent to calling - ** IpAddress("a.b.c.d"), but safer as it doesn't have to - ** parse a string to get the address components. - ** @param byte0 First byte of the address - ** @param byte1 Second byte of the address - ** @param byte2 Third byte of the address - ** @param byte3 Fourth byte of the address */ - IpAddress( Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3 ); - - /** @brief Construct the address from a 32-bits integer - ** This constructor uses the internal representation of - ** the address directly. It should be used for optimization - ** purposes, and only if you got that representation from - ** IpAddress::toInteger(). - ** @param address 4 bytes of the address packed into a 32-bits integer - ** @see ToInteger */ - explicit IpAddress( Uint32 address ); - - /** @brief Get a string representation of the address - ** The returned string is the decimal representation of the - ** IP address (like "192.168.1.56"), even if it was constructed - ** from a host name. - ** @return String representation of the address - ** @see ToInteger */ - std::string toString() const; - - /** @brief Get an integer representation of the address - ** The returned number is the internal representation of the - ** address, and should be used for optimization purposes only - ** (like sending the address through a socket). - ** The integer produced by this function can then be converted - ** back to a IpAddress with the proper constructor. - ** @return 32-bits unsigned integer representation of the address - ** @see ToString */ - Uint32 toInteger() const; - - /** @brief Get the computer's local address - ** The local address is the address of the computer from the - ** LAN point of view, i.e. something like 192.168.1.56. It is - ** meaningful only for communications over the local network. - ** Unlike GetPublicAddress, this function is fast and may be - ** used safely anywhere. - ** @return Local IP address of the computer - ** @see GetPublicAddress */ - static IpAddress getLocalAddress(); - - /** @brief Get the computer's public address - ** The public address is the address of the computer from the - ** internet point of view, i.e. something like 89.54.1.169. - ** It is necessary for communications over the world wide web. - ** The only way to get a public address is to ask it to a - ** distant website; as a consequence, this function depends on - ** both your network connection and the server, and may be - ** very slow. You should use it as few as possible. Because - ** this function depends on the network connection and on a distant - ** server, you may use a time limit if you don't want your program - ** to be possibly stuck waiting in case there is a problem; this - ** limit is deactivated by default. - ** @param timeout Maximum time to wait - ** @return Public IP address of the computer - ** @see GetLocalAddress */ - static IpAddress getPublicAddress( Time timeout = Time::Zero ); - - // Static member data - static const IpAddress None; ///< Value representing an empty/invalid address - static const IpAddress Any; ///< Value representing any address (0.0.0.0) - static const IpAddress - LocalHost; ///< The "localhost" address (for connecting a computer to itself locally) - static const IpAddress Broadcast; ///< The "broadcast" address (for sending UDP messages to - ///< everyone on a local network) - private: - friend EE_API bool operator<( const IpAddress& left, const IpAddress& right ); - - /** @brief Resolve the given address string - ** @param address Address string */ - void resolve( const std::string& address ); - - // Member data - Uint32 mAddress; ///< Address stored as an unsigned 32 bits integer - bool mValid; ///< Is the address valid? -}; - -/** @brief Overload of == operator to compare two IP addresses -** @param left Left operand (a IP address) -** @param right Right operand (a IP address) -** @return True if both addresses are equal */ -EE_API bool operator==( const IpAddress& left, const IpAddress& right ); - -/** @brief Overload of != operator to compare two IP addresses -** @param left Left operand (a IP address) -** @param right Right operand (a IP address) -** @return True if both addresses are different */ -EE_API bool operator!=( const IpAddress& left, const IpAddress& right ); - -/** @brief Overload of < operator to compare two IP addresses -** @param left Left operand (a IP address) -** @param right Right operand (a IP address) -** @return True if @a left is lesser than @a right */ -EE_API bool operator<( const IpAddress& left, const IpAddress& right ); - -/** @brief Overload of > operator to compare two IP addresses -** @param left Left operand (a IP address) -** @param right Right operand (a IP address) -** @return True if @a left is greater than @a right */ -EE_API bool operator>( const IpAddress& left, const IpAddress& right ); - -/** @brief Overload of <= operator to compare two IP addresses -** @param left Left operand (a IP address) -** @param right Right operand (a IP address) -** @return True if @a left is lesser or equal than @a right */ -EE_API bool operator<=( const IpAddress& left, const IpAddress& right ); - -/** @brief Overload of >= operator to compare two IP addresses -** @param left Left operand (a IP address) -** @param right Right operand (a IP address) -** @return True if @a left is greater or equal than @a right */ -EE_API bool operator>=( const IpAddress& left, const IpAddress& right ); - -/** @brief Overload of >> operator to extract an IP address from an input stream -** @param stream Input stream -** @param address IP address to extract -** @return Reference to the input stream */ -EE_API std::istream& operator>>( std::istream& stream, IpAddress& address ); - -/** @brief Overload of << operator to print an IP address to an output stream -** @param stream Output stream -** @param address IP address to print -** @return Reference to the output stream */ -EE_API std::ostream& operator<<( std::ostream& stream, const IpAddress& address ); - -}} // namespace EE::Network - -#endif // EE_NETWORKCIPADDRESS_HPP - -/** -@class EE::Network::IpAddress - -IpAddress is a utility class for manipulating network -addresses. It provides a set a implicit constructors and -conversion functions to easily build or transform an IP -address from/to various representations. - -Usage example: -@code -IpAddress a0; // an invalid address -IpAddress a1 = IpAddress::None; // an invalid address (same as a0) -IpAddress a2("127.0.0.1"); // the local host address -IpAddress a3 = IpAddress::Broadcast; // the broadcast address -IpAddress a4(192, 168, 1, 56); // a local address -IpAddress a5("my_computer"); // a local address created from a network name -IpAddress a6("89.54.1.169"); // a distant address -IpAddress a7("www.google.com"); // a distant address created from a network name -IpAddress a8 = IpAddress::getLocalAddress(); // my address on the local network -IpAddress a9 = IpAddress::getPublicAddress(); // my address on the internet -@endcode -Note that IpAddress currently doesn't support IPv6 -nor other types of network addresses. -*/ +#ifndef EE_NETWORKCIPADDRESS_HPP +#define EE_NETWORKCIPADDRESS_HPP + +#include +#include +using namespace EE::System; + +#include +#include +#include + +namespace EE { namespace Network { + +/** @brief Encapsulate an IPv4 network address */ +class EE_API IpAddress { + public: + /** @brief Default constructor + ** This constructor creates an empty (invalid) address */ + IpAddress(); + + /** @brief Construct the address from a string + ** Here @a address can be either a decimal address + ** (ex: "192.168.1.56") or a network name (ex: "localhost"). + ** @param address IP address or network name */ + IpAddress( const std::string& address ); + + /** @brief Construct the address from a string + ** Here @a address can be either a decimal address + ** (ex: "192.168.1.56") or a network name (ex: "localhost"). + ** This is equivalent to the constructor taking a std::string + ** parameter, it is defined for convenience so that the + ** implicit conversions from literal strings to IpAddress work. + ** @param address IP address or network name */ + IpAddress( const char* address ); + + /** @brief Construct the address from 4 bytes + ** Calling IpAddress(a, b, c, d) is equivalent to calling + ** IpAddress("a.b.c.d"), but safer as it doesn't have to + ** parse a string to get the address components. + ** @param byte0 First byte of the address + ** @param byte1 Second byte of the address + ** @param byte2 Third byte of the address + ** @param byte3 Fourth byte of the address */ + IpAddress( Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3 ); + + /** @brief Construct the address from a 32-bits integer + ** This constructor uses the internal representation of + ** the address directly. It should be used for optimization + ** purposes, and only if you got that representation from + ** IpAddress::toInteger(). + ** @param address 4 bytes of the address packed into a 32-bits integer + ** @see ToInteger */ + explicit IpAddress( Uint32 address ); + + /** @brief Get a string representation of the address + ** The returned string is the decimal representation of the + ** IP address (like "192.168.1.56"), even if it was constructed + ** from a host name. + ** @return String representation of the address + ** @see ToInteger */ + std::string toString() const; + + /** @brief Get an integer representation of the address + ** The returned number is the internal representation of the + ** address, and should be used for optimization purposes only + ** (like sending the address through a socket). + ** The integer produced by this function can then be converted + ** back to a IpAddress with the proper constructor. + ** @return 32-bits unsigned integer representation of the address + ** @see ToString */ + Uint32 toInteger() const; + + /** @brief Get the computer's local address + ** The local address is the address of the computer from the + ** LAN point of view, i.e. something like 192.168.1.56. It is + ** meaningful only for communications over the local network. + ** Unlike GetPublicAddress, this function is fast and may be + ** used safely anywhere. + ** @return Local IP address of the computer + ** @see GetPublicAddress */ + static IpAddress getLocalAddress(); + + /** @brief Get the computer's public address + ** The public address is the address of the computer from the + ** internet point of view, i.e. something like 89.54.1.169. + ** It is necessary for communications over the world wide web. + ** The only way to get a public address is to ask it to a + ** distant website; as a consequence, this function depends on + ** both your network connection and the server, and may be + ** very slow. You should use it as few as possible. Because + ** this function depends on the network connection and on a distant + ** server, you may use a time limit if you don't want your program + ** to be possibly stuck waiting in case there is a problem; this + ** limit is deactivated by default. + ** @param timeout Maximum time to wait + ** @return Public IP address of the computer + ** @see GetLocalAddress */ + static IpAddress getPublicAddress( Time timeout = Time::Zero ); + + // Static member data + static const IpAddress None; ///< Value representing an empty/invalid address + static const IpAddress Any; ///< Value representing any address (0.0.0.0) + static const IpAddress + LocalHost; ///< The "localhost" address (for connecting a computer to itself locally) + static const IpAddress Broadcast; ///< The "broadcast" address (for sending UDP messages to + ///< everyone on a local network) + private: + friend EE_API bool operator<( const IpAddress& left, const IpAddress& right ); + + /** @brief Resolve the given address string + ** @param address Address string */ + void resolve( const std::string& address ); + + // Member data + Uint32 mAddress; ///< Address stored as an unsigned 32 bits integer + bool mValid; ///< Is the address valid? +}; + +/** @brief Overload of == operator to compare two IP addresses +** @param left Left operand (a IP address) +** @param right Right operand (a IP address) +** @return True if both addresses are equal */ +EE_API bool operator==( const IpAddress& left, const IpAddress& right ); + +/** @brief Overload of != operator to compare two IP addresses +** @param left Left operand (a IP address) +** @param right Right operand (a IP address) +** @return True if both addresses are different */ +EE_API bool operator!=( const IpAddress& left, const IpAddress& right ); + +/** @brief Overload of < operator to compare two IP addresses +** @param left Left operand (a IP address) +** @param right Right operand (a IP address) +** @return True if @a left is lesser than @a right */ +EE_API bool operator<( const IpAddress& left, const IpAddress& right ); + +/** @brief Overload of > operator to compare two IP addresses +** @param left Left operand (a IP address) +** @param right Right operand (a IP address) +** @return True if @a left is greater than @a right */ +EE_API bool operator>( const IpAddress& left, const IpAddress& right ); + +/** @brief Overload of <= operator to compare two IP addresses +** @param left Left operand (a IP address) +** @param right Right operand (a IP address) +** @return True if @a left is lesser or equal than @a right */ +EE_API bool operator<=( const IpAddress& left, const IpAddress& right ); + +/** @brief Overload of >= operator to compare two IP addresses +** @param left Left operand (a IP address) +** @param right Right operand (a IP address) +** @return True if @a left is greater or equal than @a right */ +EE_API bool operator>=( const IpAddress& left, const IpAddress& right ); + +/** @brief Overload of >> operator to extract an IP address from an input stream +** @param stream Input stream +** @param address IP address to extract +** @return Reference to the input stream */ +EE_API std::istream& operator>>( std::istream& stream, IpAddress& address ); + +/** @brief Overload of << operator to print an IP address to an output stream +** @param stream Output stream +** @param address IP address to print +** @return Reference to the output stream */ +EE_API std::ostream& operator<<( std::ostream& stream, const IpAddress& address ); + +}} // namespace EE::Network + +#endif // EE_NETWORKCIPADDRESS_HPP + +/** +@class EE::Network::IpAddress + +IpAddress is a utility class for manipulating network +addresses. It provides a set a implicit constructors and +conversion functions to easily build or transform an IP +address from/to various representations. + +Usage example: +@code +IpAddress a0; // an invalid address +IpAddress a1 = IpAddress::None; // an invalid address (same as a0) +IpAddress a2("127.0.0.1"); // the local host address +IpAddress a3 = IpAddress::Broadcast; // the broadcast address +IpAddress a4(192, 168, 1, 56); // a local address +IpAddress a5("my_computer"); // a local address created from a network name +IpAddress a6("89.54.1.169"); // a distant address +IpAddress a7("www.google.com"); // a distant address created from a network name +IpAddress a8 = IpAddress::getLocalAddress(); // my address on the local network +IpAddress a9 = IpAddress::getPublicAddress(); // my address on the internet +@endcode +Note that IpAddress currently doesn't support IPv6 +nor other types of network addresses. +*/ diff --git a/include/eepp/network/socket.hpp b/include/eepp/network/socket.hpp index a7603a5ad..89691e655 100644 --- a/include/eepp/network/socket.hpp +++ b/include/eepp/network/socket.hpp @@ -1,125 +1,125 @@ -#ifndef EE_NETWORKCSOCKET_HPP -#define EE_NETWORKCSOCKET_HPP - -#include -#include -#include - -namespace EE { namespace Network { -class SocketSelector; - -/** @brief Base class for all the socket types */ -class EE_API Socket : NonCopyable { - public: - /** @brief Status codes that may be returned by socket functions */ - enum Status { - Done, ///< The socket has sent / received the data - NotReady, ///< The socket is not ready to send / receive data yet - Partial, ///< The socket sent a part of the data - Disconnected, ///< The TCP socket has been disconnected - Error ///< An unexpected error happened - }; - - /** @brief Some special values used by sockets */ - enum { - AnyPort = 0 ///< Special value that tells the system to pick any available port - }; - - /** @brief Destructor */ - virtual ~Socket(); - - /** @brief Set the blocking state of the socket - ** In blocking mode, calls will not return until they have - ** completed their task. For example, a call to Receive in - ** blocking mode won't return until some data was actually - ** received. - ** In non-blocking mode, calls will always return immediately, - ** using the return code to signal whether there was data - ** available or not. - ** By default, all sockets are blocking. - ** @param blocking True to set the socket as blocking, false for non-blocking - ** @see IsBlocking */ - void setBlocking( bool blocking ); - - /** @brief Tell whether the socket is in blocking or non-blocking mode - ** @return True if the socket is blocking, false otherwise - ** @see SetBlocking */ - bool isBlocking() const; - - protected: - /** @brief Types of protocols that the socket can use */ - enum Type { - Tcp, ///< TCP protocol - Udp ///< UDP protocol - }; - - /** @brief Default constructor - ** This constructor can only be accessed by derived classes. - ** @param type Type of the socket (TCP or UDP) */ - Socket( Type type ); - - /** @brief Return the internal handle of the socket - ** The returned handle may be invalid if the socket - ** was not created yet (or already destroyed). - ** This function can only be accessed by derived classes. - ** @return The internal (OS-specific) handle of the socket */ - SocketHandle getHandle() const; - +#ifndef EE_NETWORKCSOCKET_HPP +#define EE_NETWORKCSOCKET_HPP + +#include +#include +#include + +namespace EE { namespace Network { +class SocketSelector; + +/** @brief Base class for all the socket types */ +class EE_API Socket : NonCopyable { + public: + /** @brief Status codes that may be returned by socket functions */ + enum Status { + Done, ///< The socket has sent / received the data + NotReady, ///< The socket is not ready to send / receive data yet + Partial, ///< The socket sent a part of the data + Disconnected, ///< The TCP socket has been disconnected + Error ///< An unexpected error happened + }; + + /** @brief Some special values used by sockets */ + enum { + AnyPort = 0 ///< Special value that tells the system to pick any available port + }; + + /** @brief Destructor */ + virtual ~Socket(); + + /** @brief Set the blocking state of the socket + ** In blocking mode, calls will not return until they have + ** completed their task. For example, a call to Receive in + ** blocking mode won't return until some data was actually + ** received. + ** In non-blocking mode, calls will always return immediately, + ** using the return code to signal whether there was data + ** available or not. + ** By default, all sockets are blocking. + ** @param blocking True to set the socket as blocking, false for non-blocking + ** @see IsBlocking */ + void setBlocking( bool blocking ); + + /** @brief Tell whether the socket is in blocking or non-blocking mode + ** @return True if the socket is blocking, false otherwise + ** @see SetBlocking */ + bool isBlocking() const; + + protected: + /** @brief Types of protocols that the socket can use */ + enum Type { + Tcp, ///< TCP protocol + Udp ///< UDP protocol + }; + + /** @brief Default constructor + ** This constructor can only be accessed by derived classes. + ** @param type Type of the socket (TCP or UDP) */ + Socket( Type type ); + + /** @brief Return the internal handle of the socket + ** The returned handle may be invalid if the socket + ** was not created yet (or already destroyed). + ** This function can only be accessed by derived classes. + ** @return The internal (OS-specific) handle of the socket */ + SocketHandle getHandle() const; + /** @brief Create the internal representation of the socket /// ** This function can only be accessed by derived classes. ** @return True when a valid socket exists, false when socket creation failed. */ bool create(); - - /** @brief Create the internal representation of the socket from a socket handle - ** This function can only be accessed by derived classes. - ** @param handle OS-specific handle of the socket to wrap */ - void create( SocketHandle handle ); - - /** @brief Close the socket gracefully - ** This function can only be accessed by derived classes. */ - void close(); - - protected: - friend class SocketSelector; - // Member data - Type mType; ///< Type of the socket (TCP or UDP) - SocketHandle mSocket; ///< Socket descriptor - bool mIsBlocking; ///< Current blocking mode of the socket -}; - -}} // namespace EE::Network - -#endif // EE_NETWORKCSOCKET_HPP - -/** -@class EE::Network::Socket - -This class mainly defines internal stuff to be used by -derived classes. - -The only public features that it defines, and which -is therefore common to all the socket classes, is the -blocking state. All sockets can be set as blocking or -non-blocking. - -In blocking mode, socket functions will hang until -the operation completes, which means that the entire -program (well, in fact the current thread if you use -multiple ones) will be stuck waiting for your socket -operation to complete. - -In non-blocking mode, all the socket functions will -return immediately. If the socket is not ready to complete -the requested operation, the function simply returns -the proper status code (Socket::NotReady). -The default mode, which is blocking, is the one that is -generally used, in combination with threads or selectors. - -The non-blocking mode is rather used in real-time -applications that run an endless loop that can poll -the socket often enough, and cannot afford blocking -this loop. - -@see EE::Network::TcpListener, EE::Network::TcpSocket, EE::Network::UdpSocket -*/ + + /** @brief Create the internal representation of the socket from a socket handle + ** This function can only be accessed by derived classes. + ** @param handle OS-specific handle of the socket to wrap */ + void create( SocketHandle handle ); + + /** @brief Close the socket gracefully + ** This function can only be accessed by derived classes. */ + void close(); + + protected: + friend class SocketSelector; + // Member data + Type mType; ///< Type of the socket (TCP or UDP) + SocketHandle mSocket; ///< Socket descriptor + bool mIsBlocking; ///< Current blocking mode of the socket +}; + +}} // namespace EE::Network + +#endif // EE_NETWORKCSOCKET_HPP + +/** +@class EE::Network::Socket + +This class mainly defines internal stuff to be used by +derived classes. + +The only public features that it defines, and which +is therefore common to all the socket classes, is the +blocking state. All sockets can be set as blocking or +non-blocking. + +In blocking mode, socket functions will hang until +the operation completes, which means that the entire +program (well, in fact the current thread if you use +multiple ones) will be stuck waiting for your socket +operation to complete. + +In non-blocking mode, all the socket functions will +return immediately. If the socket is not ready to complete +the requested operation, the function simply returns +the proper status code (Socket::NotReady). +The default mode, which is blocking, is the one that is +generally used, in combination with threads or selectors. + +The non-blocking mode is rather used in real-time +applications that run an endless loop that can poll +the socket often enough, and cannot afford blocking +this loop. + +@see EE::Network::TcpListener, EE::Network::TcpSocket, EE::Network::UdpSocket +*/ diff --git a/include/eepp/network/socketselector.hpp b/include/eepp/network/socketselector.hpp index 71981acc6..b21e707cf 100644 --- a/include/eepp/network/socketselector.hpp +++ b/include/eepp/network/socketselector.hpp @@ -1,168 +1,168 @@ -#ifndef EE_NETWORKCSOCKETSELECTOR_HPP -#define EE_NETWORKCSOCKETSELECTOR_HPP - -#include -#include -using namespace EE::System; - -namespace EE { namespace Network { - -class Socket; - -/** Multiplexer that allows to read from multiple sockets */ -class EE_API SocketSelector { - public: - /** @brief Default constructor */ - SocketSelector(); - - /** @brief Copy constructor - ** @param copy Instance to copy */ - SocketSelector( const SocketSelector& copy ); - - /** @brief Destructor */ - ~SocketSelector(); - - /** @brief Add a new socket to the selector - ** This function keeps a weak reference to the socket, - ** so you have to make sure that the socket is not destroyed - ** while it is stored in the selector. - ** This function does nothing if the socket is not valid. - ** @param socket Reference to the socket to add - ** @see Remove, Clear */ - void add( Socket& socket ); - - /** @brief Remove a socket from the selector - ** This function doesn't destroy the socket, it simply - ** removes the reference that the selector has to it. - ** @param socket Reference to the socket to remove - ** @see Add, Clear */ - void remove( Socket& socket ); - - /** @brief Remove all the sockets stored in the selector - ** This function doesn't destroy any instance, it simply - ** removes all the references that the selector has to - ** external sockets. - ** @see Add, Remove */ - void clear(); - - /** @brief Wait until one or more sockets are ready to receive - ** This function returns as soon as at least one socket has - ** some data available to be received. To know which sockets are - ** ready, use the isReady function. - ** If you use a timeout and no socket is ready before the timeout - ** is over, the function returns false. - ** @param timeout Maximum time to wait, (use Time::Zero for infinity) - ** @return True if there are sockets ready, false otherwise - ** @see IsReady */ - bool wait( Time timeout = Time::Zero ); - - /** @brief Test a socket to know if it is ready to receive data - ** This function must be used after a call to Wait, to know - ** which sockets are ready to receive data. If a socket is - ** ready, a call to receive will never block because we know - ** that there is data available to read. - ** Note that if this function returns true for a TcpListener, - ** this means that it is ready to accept a new connection. - ** @param socket Socket to test - ** @return True if the socket is ready to read, false otherwise - ** @see IsReady */ - bool isReady( Socket& socket ) const; - - /** @brief Overload of assignment operator - ** @param right Instance to assign - ** @return Reference to self */ - SocketSelector& operator=( const SocketSelector& right ); - - private: - struct SocketSelectorImpl; - - // Member data - SocketSelectorImpl* - mImpl; ///< Opaque pointer to the implementation (which requires OS-specific types) -}; - -}} // namespace EE::Network - -#endif // EE_NETWORKCSOCKETSELECTOR_HPP - -/** -@class EE::Network::SocketSelector - -Socket selectors provide a way to wait until some data is -available on a set of sockets, instead of just one. This -is convenient when you have multiple sockets that may -possibly receive data, but you don't know which one will -be ready first. In particular, it avoids to use a thread -for each socket; with selectors, a single thread can handle -all the sockets. - -All types of sockets can be used in a selector: -@li EE::NetworkTcpListener -@li EE::NetworkTcpSocket -@li EE::NetworkUdpSocket - -A selector doesn't store its own copies of the sockets -(socket classes are not copyable anyway), it simply keeps -a reference to the original sockets that you pass to the -"add" function. Therefore, you can't use the selector as a -socket container, you must store them outside and make sure -that they are alive as long as they are used in the selector. - -Using a selector is simple: -@li populate the selector with all the sockets that you want to observe -@li make it wait until there is data available on any of the sockets -@li test each socket to find out which ones are ready - -Usage example: -@code -// Create a socket to listen to new connections -TcpListener listener; -listener.listen(55001); - -// Create a list to store the future clients -std::vector clients; - -// Create a selector -SocketSelector selector; - -// Add the listener to the selector -selector.add(listener); - -// Endless loop that waits for new connections -while (running) { - // Make the selector wait for data on any socket - if (selector.wait()) { - // Test the listener - if (selector.isReady(listener)) { - // The listener is ready: there is a pending connection - TcpSocket* client = new TcpSocket; - if (listener.accept(*client) == Socket::Done) { - // Add the new client to the clients list - clients.push_back(client); - - // Add the new client to the selector so that we will - // be notified when he sends something - selector.add(*client); - } else { - // Error, we won't get a new connection, delete the socket - delete client; - } - } else { - // The listener socket is not ready, test all other sockets (the clients) - for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) { - TcpSocket& client = **it; - if (selector.isReady(client)) { - // The client has sent some data, we can receive it - Packet packet; - if (client.Receive(packet) == Socket::Done) { - ... - } - } - } - } - } -} -@endcode - -@see EE::Network::Socket -*/ +#ifndef EE_NETWORKCSOCKETSELECTOR_HPP +#define EE_NETWORKCSOCKETSELECTOR_HPP + +#include +#include +#include +using namespace EE::System; + +namespace EE { namespace Network { + +class Socket; + +/** Multiplexer that allows to read from multiple sockets */ +class EE_API SocketSelector { + public: + /** @brief Default constructor */ + SocketSelector(); + + /** @brief Copy constructor + ** @param copy Instance to copy */ + SocketSelector( const SocketSelector& copy ); + + /** @brief Destructor */ + ~SocketSelector(); + + /** @brief Add a new socket to the selector + ** This function keeps a weak reference to the socket, + ** so you have to make sure that the socket is not destroyed + ** while it is stored in the selector. + ** This function does nothing if the socket is not valid. + ** @param socket Reference to the socket to add + ** @see Remove, Clear */ + void add( Socket& socket ); + + /** @brief Remove a socket from the selector + ** This function doesn't destroy the socket, it simply + ** removes the reference that the selector has to it. + ** @param socket Reference to the socket to remove + ** @see Add, Clear */ + void remove( Socket& socket ); + + /** @brief Remove all the sockets stored in the selector + ** This function doesn't destroy any instance, it simply + ** removes all the references that the selector has to + ** external sockets. + ** @see Add, Remove */ + void clear(); + + /** @brief Wait until one or more sockets are ready to receive + ** This function returns as soon as at least one socket has + ** some data available to be received. To know which sockets are + ** ready, use the isReady function. + ** If you use a timeout and no socket is ready before the timeout + ** is over, the function returns false. + ** @param timeout Maximum time to wait, (use Time::Zero for infinity) + ** @return True if there are sockets ready, false otherwise + ** @see IsReady */ + bool wait( Time timeout = Time::Zero ); + + /** @brief Test a socket to know if it is ready to receive data + ** This function must be used after a call to Wait, to know + ** which sockets are ready to receive data. If a socket is + ** ready, a call to receive will never block because we know + ** that there is data available to read. + ** Note that if this function returns true for a TcpListener, + ** this means that it is ready to accept a new connection. + ** @param socket Socket to test + ** @return True if the socket is ready to read, false otherwise + ** @see IsReady */ + bool isReady( Socket& socket ) const; + + /** @brief Overload of assignment operator + ** @param right Instance to assign + ** @return Reference to self */ + SocketSelector& operator=( const SocketSelector& right ); + + private: + struct SocketSelectorImpl; + + // Member data + SocketSelectorImpl* + mImpl; ///< Opaque pointer to the implementation (which requires OS-specific types) +}; + +}} // namespace EE::Network + +#endif // EE_NETWORKCSOCKETSELECTOR_HPP + +/** +@class EE::Network::SocketSelector + +Socket selectors provide a way to wait until some data is +available on a set of sockets, instead of just one. This +is convenient when you have multiple sockets that may +possibly receive data, but you don't know which one will +be ready first. In particular, it avoids to use a thread +for each socket; with selectors, a single thread can handle +all the sockets. + +All types of sockets can be used in a selector: +@li EE::NetworkTcpListener +@li EE::NetworkTcpSocket +@li EE::NetworkUdpSocket + +A selector doesn't store its own copies of the sockets +(socket classes are not copyable anyway), it simply keeps +a reference to the original sockets that you pass to the +"add" function. Therefore, you can't use the selector as a +socket container, you must store them outside and make sure +that they are alive as long as they are used in the selector. + +Using a selector is simple: +@li populate the selector with all the sockets that you want to observe +@li make it wait until there is data available on any of the sockets +@li test each socket to find out which ones are ready + +Usage example: +@code +// Create a socket to listen to new connections +TcpListener listener; +listener.listen(55001); + +// Create a list to store the future clients +std::vector clients; + +// Create a selector +SocketSelector selector; + +// Add the listener to the selector +selector.add(listener); + +// Endless loop that waits for new connections +while (running) { + // Make the selector wait for data on any socket + if (selector.wait()) { + // Test the listener + if (selector.isReady(listener)) { + // The listener is ready: there is a pending connection + TcpSocket* client = new TcpSocket; + if (listener.accept(*client) == Socket::Done) { + // Add the new client to the clients list + clients.push_back(client); + + // Add the new client to the selector so that we will + // be notified when he sends something + selector.add(*client); + } else { + // Error, we won't get a new connection, delete the socket + delete client; + } + } else { + // The listener socket is not ready, test all other sockets (the clients) + for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) +{ TcpSocket& client = **it; if (selector.isReady(client)) { + // The client has sent some data, we can receive it + Packet packet; + if (client.Receive(packet) == Socket::Done) { + ... + } + } + } + } + } +} +@endcode + +@see EE::Network::Socket +*/ diff --git a/include/eepp/network/tcpsocket.hpp b/include/eepp/network/tcpsocket.hpp index 3e90d6a70..2375d461c 100644 --- a/include/eepp/network/tcpsocket.hpp +++ b/include/eepp/network/tcpsocket.hpp @@ -1,227 +1,229 @@ -#ifndef EE_NETWORKCTCPSOCKET_HPP -#define EE_NETWORKCTCPSOCKET_HPP - -#include -#include -#include -using namespace EE::System; - -namespace EE { namespace Network { - -class TcpListener; -class IpAddress; -class Packet; - -/** @brief Specialized socket using the TCP protocol */ -class EE_API TcpSocket : public Socket { - public: - static TcpSocket* New(); - - /** @brief Default constructor */ - TcpSocket(); - - virtual ~TcpSocket(); - - /** @brief Get the port to which the socket is bound locally - ** If the socket is not connected, this function returns 0. - ** @return Port to which the socket is bound - ** @see Connect, GetRemotePort */ - unsigned short getLocalPort() const; - - /** @brief Get the address of the connected peer - ** It the socket is not connected, this function returns - ** IpAddress::None. - ** @return Address of the remote peer - ** @see GetRemotePort */ - IpAddress getRemoteAddress() const; - - /** @brief Get the port of the connected peer to which - the socket is connected - ** If the socket is not connected, this function returns 0. - ** @return Remote port to which the socket is connected - ** @see GetRemoteAddress */ - unsigned short getRemotePort() const; - - /** @brief Connect the socket to a remote peer - ** In blocking mode, this function may take a while, especially - ** if the remote peer is not reachable. The last parameter allows - ** you to stop trying to connect after a given timeout. - ** If the socket was previously connected, it is first disconnected. - ** @param remoteAddress Address of the remote peer - ** @param remotePort Port of the remote peer - ** @param timeout Optional maximum time to wait - ** @return Status code - ** @see Disconnect */ - virtual Status connect( const IpAddress& remoteAddress, unsigned short remotePort, - Time timeout = Time::Zero ); - - /** @brief Disconnect the socket from its remote peer - ** This function gracefully closes the connection. If the - ** socket is not connected, this function has no effect. - ** @see Connect */ - virtual void disconnect(); - - /** @brief Send raw data to the remote peer - ** To be able to handle partial sends over non-blocking - ** sockets, use the send(const void*, std::size_t, std::size_t&) - ** overload instead. - ** - ** This function will fail if the socket is not connected. - ** - ** @param data Pointer to the sequence of bytes to send - ** @param size Number of bytes to send - ** @return Status code - ** @see Receive */ - virtual Status send( const void* data, std::size_t size ); - - /** @brief Send raw data to the remote peer - ** This function will fail if the socket is not connected. - ** @param data Pointer to the sequence of bytes to send - ** @param size Number of bytes to send - ** @param sent The number of bytes sent will be written here - ** @return Status code - ** @see receive */ - virtual Status send( const void* data, std::size_t size, std::size_t& sent ); - - /** @brief Receive raw data from the remote peer - ** In blocking mode, this function will wait until some - ** bytes are actually received. - ** This function will fail if the socket is not connected. - ** @param data Pointer to the array to fill with the received bytes - ** @param size Maximum number of bytes that can be received - ** @param received This variable is filled with the actual number of bytes received - ** @return Status code - ** @see Send */ - virtual Status receive( void* data, std::size_t size, std::size_t& received ); - - /** @brief Send a formatted packet of data to the remote peer - * - ** In non-blocking mode, if this function returns sf::Socket::Partial, - ** you \em must retry sending the same unmodified packet before sending - ** anything else in order to guarantee the packet arrives at the remote - ** peer uncorrupted. - ** - ** This function will fail if the socket is not connected. - ** @param packet Packet to send - ** @return Status code - ** @see Receive */ - virtual Status send( Packet& packet ); - - /** @brief Receive a formatted packet of data from the remote peer - ** In blocking mode, this function will wait until the whole packet - ** has been received. - ** This function will fail if the socket is not connected. - ** @param packet Packet to fill with the received data - ** @return Status code - ** @see Send */ - virtual Status receive( Packet& packet ); - - /** Set the send timeout. Only callable after connect ( after the socket - ** has been initialized ). */ - void setSendTimeout( const Time& timeout ); - - /** Set the receive timeout Only callable after connect ( after the socket - ** has been initialized ). */ - void setReceiveTimeout( const Time& timeout ); - - typedef std::function ReadFn; - - /** @brief Starts a new thread to receive all stdout and stderr data */ - void startAsyncRead( ReadFn readFn = nullptr ); - - private: - friend class TcpListener; - - /** @brief Structure holding the data of a pending packet */ - struct PendingPacket { - PendingPacket(); - - Uint32 Size; ///< Data of packet size - std::size_t SizeReceived; ///< Number of size bytes received so far - std::vector Data; ///< Data of the packet - }; - - // Member data - PendingPacket mPendingPacket; ///< Temporary data of the packet currently being received - std::thread mReadThread; -}; - -}} // namespace EE::Network - -#endif // EE_NETWORKCTCPSOCKET_HPP - -/** -@class EE::Network::TcpSocket - -TCP is a connected protocol, which means that a TCP -socket can only communicate with the host it is connected -to. It can't send or receive anything if it is not connected. - -The TCP protocol is reliable but adds a slight overhead. -It ensures that your data will always be received in order -and without errors (no data corrupted, lost or duplicated). - -When a socket is connected to a remote host, you can -retrieve information about this host with the -GetRemoteAddress and GetRemotePort functions. You can -also get the local port to which the socket is bound -(which is automatically chosen when the socket is connected), -with the GetLocalPort function. - -Sending and receiving data can use either the low-level -or the high-level functions. The low-level functions -process a raw sequence of bytes, and cannot ensure that -one call to Send will exactly match one call to Receive -at the other end of the socket. - -The high-level interface uses packets (see Packet), -which are easier to use and provide more safety regarding -the data that is exchanged. You can look at the Packet -class to get more details about how they work. - -The socket is automatically disconnected when it is destroyed, -but if you want to explicitly close the connection while -the socket instance is still alive, you can call disconnect. - -Usage example: -@code -// ----- The client ----- - -// Create a socket and connect it to 192.168.1.50 on port 55001 -TcpSocket socket; -socket.connect("192.168.1.50", 55001); - -// Send a message to the connected host -std::string message = "Hi, I am a client"; -socket.send(message.c_str(), message.size() + 1); - -// Receive an answer from the server -char buffer[1024]; -std::size_t received = 0; -socket.receive(buffer, sizeof(buffer), received); -std::cout << "The server said: " << buffer << std::endl; - -// ----- The server ----- - -// Create a listener to wait for incoming connections on port 55001 -TcpListener listener; -listener.listen(55001); - -// Wait for a connection -TcpSocket socket; -listener.accept(socket); -std::cout << "New client connected: " << socket.getRemoteAddress() << std::endl; - -// Receive a message from the client -char buffer[1024]; -std::size_t received = 0; -socket.receive(buffer, sizeof(buffer), received); -std::cout << "The client said: " << buffer << std::endl; - -// Send an answer -std::string message = "Welcome, client"; -socket.send(message.c_str(), message.size() + 1); -@endcode - -@see EE::Network::Socket, EE::Network::UdpSocket, EE::Network::Packet -*/ +#ifndef EE_NETWORKCTCPSOCKET_HPP +#define EE_NETWORKCTCPSOCKET_HPP + +#include +#include +#include +#include +#include +using namespace EE::System; + +namespace EE { namespace Network { + +class TcpListener; +class IpAddress; +class Packet; + +/** @brief Specialized socket using the TCP protocol */ +class EE_API TcpSocket : public Socket { + public: + static TcpSocket* New(); + + /** @brief Default constructor */ + TcpSocket(); + + virtual ~TcpSocket(); + + /** @brief Get the port to which the socket is bound locally + ** If the socket is not connected, this function returns 0. + ** @return Port to which the socket is bound + ** @see Connect, GetRemotePort */ + unsigned short getLocalPort() const; + + /** @brief Get the address of the connected peer + ** It the socket is not connected, this function returns + ** IpAddress::None. + ** @return Address of the remote peer + ** @see GetRemotePort */ + IpAddress getRemoteAddress() const; + + /** @brief Get the port of the connected peer to which + the socket is connected + ** If the socket is not connected, this function returns 0. + ** @return Remote port to which the socket is connected + ** @see GetRemoteAddress */ + unsigned short getRemotePort() const; + + /** @brief Connect the socket to a remote peer + ** In blocking mode, this function may take a while, especially + ** if the remote peer is not reachable. The last parameter allows + ** you to stop trying to connect after a given timeout. + ** If the socket was previously connected, it is first disconnected. + ** @param remoteAddress Address of the remote peer + ** @param remotePort Port of the remote peer + ** @param timeout Optional maximum time to wait + ** @return Status code + ** @see Disconnect */ + virtual Status connect( const IpAddress& remoteAddress, unsigned short remotePort, + Time timeout = Time::Zero ); + + /** @brief Disconnect the socket from its remote peer + ** This function gracefully closes the connection. If the + ** socket is not connected, this function has no effect. + ** @see Connect */ + virtual void disconnect(); + + /** @brief Send raw data to the remote peer + ** To be able to handle partial sends over non-blocking + ** sockets, use the send(const void*, std::size_t, std::size_t&) + ** overload instead. + ** + ** This function will fail if the socket is not connected. + ** + ** @param data Pointer to the sequence of bytes to send + ** @param size Number of bytes to send + ** @return Status code + ** @see Receive */ + virtual Status send( const void* data, std::size_t size ); + + /** @brief Send raw data to the remote peer + ** This function will fail if the socket is not connected. + ** @param data Pointer to the sequence of bytes to send + ** @param size Number of bytes to send + ** @param sent The number of bytes sent will be written here + ** @return Status code + ** @see receive */ + virtual Status send( const void* data, std::size_t size, std::size_t& sent ); + + /** @brief Receive raw data from the remote peer + ** In blocking mode, this function will wait until some + ** bytes are actually received. + ** This function will fail if the socket is not connected. + ** @param data Pointer to the array to fill with the received bytes + ** @param size Maximum number of bytes that can be received + ** @param received This variable is filled with the actual number of bytes received + ** @return Status code + ** @see Send */ + virtual Status receive( void* data, std::size_t size, std::size_t& received ); + + /** @brief Send a formatted packet of data to the remote peer + * + ** In non-blocking mode, if this function returns sf::Socket::Partial, + ** you \em must retry sending the same unmodified packet before sending + ** anything else in order to guarantee the packet arrives at the remote + ** peer uncorrupted. + ** + ** This function will fail if the socket is not connected. + ** @param packet Packet to send + ** @return Status code + ** @see Receive */ + virtual Status send( Packet& packet ); + + /** @brief Receive a formatted packet of data from the remote peer + ** In blocking mode, this function will wait until the whole packet + ** has been received. + ** This function will fail if the socket is not connected. + ** @param packet Packet to fill with the received data + ** @return Status code + ** @see Send */ + virtual Status receive( Packet& packet ); + + /** Set the send timeout. Only callable after connect ( after the socket + ** has been initialized ). */ + void setSendTimeout( const Time& timeout ); + + /** Set the receive timeout Only callable after connect ( after the socket + ** has been initialized ). */ + void setReceiveTimeout( const Time& timeout ); + + typedef std::function ReadFn; + + /** @brief Starts a new thread to receive all stdout and stderr data */ + void startAsyncRead( ReadFn readFn = nullptr ); + + private: + friend class TcpListener; + + /** @brief Structure holding the data of a pending packet */ + struct PendingPacket { + PendingPacket(); + + Uint32 Size; ///< Data of packet size + std::size_t SizeReceived; ///< Number of size bytes received so far + std::vector Data; ///< Data of the packet + }; + + // Member data + PendingPacket mPendingPacket; ///< Temporary data of the packet currently being received + std::thread mReadThread; +}; + +}} // namespace EE::Network + +#endif // EE_NETWORKCTCPSOCKET_HPP + +/** +@class EE::Network::TcpSocket + +TCP is a connected protocol, which means that a TCP +socket can only communicate with the host it is connected +to. It can't send or receive anything if it is not connected. + +The TCP protocol is reliable but adds a slight overhead. +It ensures that your data will always be received in order +and without errors (no data corrupted, lost or duplicated). + +When a socket is connected to a remote host, you can +retrieve information about this host with the +GetRemoteAddress and GetRemotePort functions. You can +also get the local port to which the socket is bound +(which is automatically chosen when the socket is connected), +with the GetLocalPort function. + +Sending and receiving data can use either the low-level +or the high-level functions. The low-level functions +process a raw sequence of bytes, and cannot ensure that +one call to Send will exactly match one call to Receive +at the other end of the socket. + +The high-level interface uses packets (see Packet), +which are easier to use and provide more safety regarding +the data that is exchanged. You can look at the Packet +class to get more details about how they work. + +The socket is automatically disconnected when it is destroyed, +but if you want to explicitly close the connection while +the socket instance is still alive, you can call disconnect. + +Usage example: +@code +// ----- The client ----- + +// Create a socket and connect it to 192.168.1.50 on port 55001 +TcpSocket socket; +socket.connect("192.168.1.50", 55001); + +// Send a message to the connected host +std::string message = "Hi, I am a client"; +socket.send(message.c_str(), message.size() + 1); + +// Receive an answer from the server +char buffer[1024]; +std::size_t received = 0; +socket.receive(buffer, sizeof(buffer), received); +std::cout << "The server said: " << buffer << std::endl; + +// ----- The server ----- + +// Create a listener to wait for incoming connections on port 55001 +TcpListener listener; +listener.listen(55001); + +// Wait for a connection +TcpSocket socket; +listener.accept(socket); +std::cout << "New client connected: " << socket.getRemoteAddress() << std::endl; + +// Receive a message from the client +char buffer[1024]; +std::size_t received = 0; +socket.receive(buffer, sizeof(buffer), received); +std::cout << "The client said: " << buffer << std::endl; + +// Send an answer +std::string message = "Welcome, client"; +socket.send(message.c_str(), message.size() + 1); +@endcode + +@see EE::Network::Socket, EE::Network::UdpSocket, EE::Network::Packet +*/ diff --git a/include/eepp/network/uri.hpp b/include/eepp/network/uri.hpp index ef8bce336..66c248d9d 100644 --- a/include/eepp/network/uri.hpp +++ b/include/eepp/network/uri.hpp @@ -1,7 +1,11 @@ #ifndef EE_NETWORK_URI_HPP #define EE_NETWORK_URI_HPP -#include +#include +#include +#include +#include +#include #include namespace EE { namespace Network { diff --git a/include/eepp/system/condition.hpp b/include/eepp/system/condition.hpp index 85e8e26de..fa8612f55 100644 --- a/include/eepp/system/condition.hpp +++ b/include/eepp/system/condition.hpp @@ -1,7 +1,7 @@ #ifndef EE_SYSTEMCCONDITION_HPP #define EE_SYSTEMCCONDITION_HPP -#include +#include #include namespace EE { namespace System { diff --git a/include/eepp/system/filesystem.hpp b/include/eepp/system/filesystem.hpp index e4a1c5e46..18c31a5e5 100644 --- a/include/eepp/system/filesystem.hpp +++ b/include/eepp/system/filesystem.hpp @@ -1,9 +1,11 @@ #ifndef EE_SYSTEM_FILESYSTEM_HPP #define EE_SYSTEM_FILESYSTEM_HPP -#include +#include +#include #include #include +#include #include #include diff --git a/include/eepp/system/log.hpp b/include/eepp/system/log.hpp index 324774f1c..213442b3e 100644 --- a/include/eepp/system/log.hpp +++ b/include/eepp/system/log.hpp @@ -1,6 +1,7 @@ #ifndef EE_SYSTEM_LOG_H #define EE_SYSTEM_LOG_H +#include #include #include #include @@ -87,8 +88,7 @@ class EE_API Log : protected Mutex { } /** @brief Writes a formatted string to the log */ - template - void writef( std::string_view format, Args&&... args ) { + template void writef( std::string_view format, Args&&... args ) { auto result = String::format( format, FormatArg>::get( std::forward( args ) )... ); write( result ); diff --git a/include/eepp/system/md5.hpp b/include/eepp/system/md5.hpp index dc3daa171..c325bc3f6 100644 --- a/include/eepp/system/md5.hpp +++ b/include/eepp/system/md5.hpp @@ -1,9 +1,10 @@ #ifndef EE_SYSTEM_MD5_HPP #define EE_SYSTEM_MD5_HPP -#include -#include #include +#include +#include +#include namespace EE { namespace System { diff --git a/include/eepp/system/mutex.hpp b/include/eepp/system/mutex.hpp index 851eaa3a1..37247b45d 100644 --- a/include/eepp/system/mutex.hpp +++ b/include/eepp/system/mutex.hpp @@ -1,7 +1,7 @@ #ifndef EE_SYSTEMCMUTEX_H #define EE_SYSTEMCMUTEX_H -#include +#include #include #include diff --git a/include/eepp/system/pack.hpp b/include/eepp/system/pack.hpp index 552d27405..261157e7a 100644 --- a/include/eepp/system/pack.hpp +++ b/include/eepp/system/pack.hpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace EE { namespace System { diff --git a/include/eepp/system/resourceloader.hpp b/include/eepp/system/resourceloader.hpp index 108f02afd..791889179 100644 --- a/include/eepp/system/resourceloader.hpp +++ b/include/eepp/system/resourceloader.hpp @@ -2,8 +2,9 @@ #define EE_SYSTEMCRESOURCELOADER #include -#include +#include #include +#include #include #include diff --git a/include/eepp/system/singleton.hpp b/include/eepp/system/singleton.hpp index f0843916e..2010b75dc 100644 --- a/include/eepp/system/singleton.hpp +++ b/include/eepp/system/singleton.hpp @@ -2,9 +2,12 @@ #define EE_SYSTEMSINGLETON_H #include -#include +#include +#include +#include #include #include +#include /** Internally we gonna use the macro singleton because it works with the engine compiled as dynamic * libraries. @@ -21,20 +24,6 @@ * creates one internal-linkage singleton per translation unit. */ -#define SINGLETON_DECLARE_HEADERS( T ) \ - public: \ - static T* createSingleton(); \ - \ - static T* existsSingleton(); \ - \ - static bool isShuttingDown(); \ - \ - static T* instance(); \ - \ - static void destroySingleton(); \ - \ - static void detachSingleton(); - #define SINGLETON_DECLARE_IMPLEMENTATION( T ) \ \ static std::atomic ms_singleton{ NULL }; \ diff --git a/include/eepp/system/singletondeclarations.hpp b/include/eepp/system/singletondeclarations.hpp new file mode 100644 index 000000000..0e8c015f7 --- /dev/null +++ b/include/eepp/system/singletondeclarations.hpp @@ -0,0 +1,24 @@ +#ifndef EE_SYSTEMSINGLETONDECLARATIONS_HPP +#define EE_SYSTEMSINGLETONDECLARATIONS_HPP + +/** Declarations shared by the macro-based singleton implementations. + * + * Keep this header lightweight. The implementation macro and the Singleton template + * require the allocation and synchronization machinery from singleton.hpp, while + * singleton-owning public headers only need these declarations. + */ +#define SINGLETON_DECLARE_HEADERS( T ) \ + public: \ + static T* createSingleton(); \ + \ + static T* existsSingleton(); \ + \ + static bool isShuttingDown(); \ + \ + static T* instance(); \ + \ + static void destroySingleton(); \ + \ + static void detachSingleton(); + +#endif diff --git a/include/eepp/system/threadlocal.hpp b/include/eepp/system/threadlocal.hpp index a3cf2b7f9..a68dbaa47 100644 --- a/include/eepp/system/threadlocal.hpp +++ b/include/eepp/system/threadlocal.hpp @@ -1,7 +1,7 @@ #ifndef EE_SYSTEMCTHREADLOCAL_HPP #define EE_SYSTEMCTHREADLOCAL_HPP -#include +#include #include namespace EE { namespace System { namespace Private { diff --git a/include/eepp/system/translator.hpp b/include/eepp/system/translator.hpp index 930af796f..cfe2857cc 100644 --- a/include/eepp/system/translator.hpp +++ b/include/eepp/system/translator.hpp @@ -1,7 +1,11 @@ #ifndef EE_SYSTEM_STRINGLOCALERESOURCE_HPP #define EE_SYSTEM_STRINGLOCALERESOURCE_HPP -#include +#include +#include + +#include +#include namespace pugi { class xml_node; diff --git a/include/eepp/ui/doc/syntaxcolorscheme.hpp b/include/eepp/ui/doc/syntaxcolorscheme.hpp index 417ab1620..428a86699 100644 --- a/include/eepp/ui/doc/syntaxcolorscheme.hpp +++ b/include/eepp/ui/doc/syntaxcolorscheme.hpp @@ -2,10 +2,15 @@ #define EE_UI_DOC_SYNTAXCOLORSCHEME_HPP #include -#include -#include #include +namespace EE { namespace System { + +class IOStream; +class Pack; + +}} // namespace EE::System + using namespace EE::System; namespace EE { namespace UI { namespace Doc { diff --git a/include/eepp/ui/doc/syntaxdefinition.hpp b/include/eepp/ui/doc/syntaxdefinition.hpp index a3ea5f077..f835d83eb 100644 --- a/include/eepp/ui/doc/syntaxdefinition.hpp +++ b/include/eepp/ui/doc/syntaxdefinition.hpp @@ -2,11 +2,13 @@ #define EE_UI_DOC_DEFINITION_HPP #include +#include #include #include #include #include +#include #include #include #include diff --git a/include/eepp/ui/doc/syntaxdefinitionmanager.hpp b/include/eepp/ui/doc/syntaxdefinitionmanager.hpp index 4bbcae8a8..328807d7f 100644 --- a/include/eepp/ui/doc/syntaxdefinitionmanager.hpp +++ b/include/eepp/ui/doc/syntaxdefinitionmanager.hpp @@ -2,14 +2,21 @@ #define EE_UI_DOC_SYNTAXSTYLEMANAGER_HPP #include -#include -#include -#include +#include +#include +#include #include #include #include #include +namespace EE { namespace System { + +class IOStream; +class Pack; + +}} // namespace EE::System + using namespace EE::System; namespace EE { namespace UI { namespace Doc { diff --git a/include/eepp/window/cursor.hpp b/include/eepp/window/cursor.hpp index bf3867526..1ed36a130 100644 --- a/include/eepp/window/cursor.hpp +++ b/include/eepp/window/cursor.hpp @@ -1,7 +1,8 @@ #ifndef EE_WINDOWCCURSOR_HPP #define EE_WINDOWCCURSOR_HPP -#include +#include +#include #include #include using namespace EE::Math; diff --git a/include/eepp/window/platformimpl.hpp b/include/eepp/window/platformimpl.hpp index 16fa0c1ed..25270ebba 100644 --- a/include/eepp/window/platformimpl.hpp +++ b/include/eepp/window/platformimpl.hpp @@ -1,7 +1,7 @@ #ifndef EE_WINDOWCPLATFORMIMPL_HPP #define EE_WINDOWCPLATFORMIMPL_HPP -#include +#include #include using namespace EE::Math; diff --git a/src/eepp/graphics/textureatlas.cpp b/src/eepp/graphics/textureatlas.cpp index 843b8fa40..e06c9df96 100644 --- a/src/eepp/graphics/textureatlas.cpp +++ b/src/eepp/graphics/textureatlas.cpp @@ -1,3 +1,4 @@ +#include #include #include diff --git a/src/eepp/graphics/texturepackernode.cpp b/src/eepp/graphics/texturepackernode.cpp index 1289fb15f..1feb5a6ba 100644 --- a/src/eepp/graphics/texturepackernode.cpp +++ b/src/eepp/graphics/texturepackernode.cpp @@ -1,3 +1,4 @@ +#include #include namespace EE { namespace Graphics { namespace Private { diff --git a/src/eepp/network/uri.cpp b/src/eepp/network/uri.cpp index cf8fe1ba1..ff71993f5 100644 --- a/src/eepp/network/uri.cpp +++ b/src/eepp/network/uri.cpp @@ -1,3 +1,4 @@ +#include #include #include diff --git a/src/eepp/system/threadpool.cpp b/src/eepp/system/threadpool.cpp index d1cf57b47..ae203a233 100644 --- a/src/eepp/system/threadpool.cpp +++ b/src/eepp/system/threadpool.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace EE { namespace System { diff --git a/src/eepp/system/virtualfilesystem.cpp b/src/eepp/system/virtualfilesystem.cpp index eb74bdfb8..3a771ffed 100644 --- a/src/eepp/system/virtualfilesystem.cpp +++ b/src/eepp/system/virtualfilesystem.cpp @@ -1,3 +1,4 @@ +#include #include namespace EE { namespace System { diff --git a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp index e6caa7b72..a02a32547 100644 --- a/src/eepp/ui/doc/syntaxdefinitionmanager.cpp +++ b/src/eepp/ui/doc/syntaxdefinitionmanager.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/eepp/ui/uiborderdrawable.cpp b/src/eepp/ui/uiborderdrawable.cpp index 4d0eebbe8..a72d73507 100644 --- a/src/eepp/ui/uiborderdrawable.cpp +++ b/src/eepp/ui/uiborderdrawable.cpp @@ -73,23 +73,34 @@ void UIBorderDrawable::draw( const Vector2f& position, const Sizef& size ) { if ( border.width <= 0 || ( border.style != BorderStyle::Dotted && border.style != BorderStyle::Dashed ) ) return; + // These are axis-aligned physical-pixel primitives. A centered odd-width pattern on an + // even-length side otherwise starts at a half pixel, whose coverage is + // driver-dependent. Snap the side bounds and choose the lower integer for an + // unavoidable asymmetric remainder so every backend rasterizes the same pixels. + const Float snappedStart = std::round( start ); + const Float snappedLimit = std::round( start + length ); + const Float snappedFixed = std::round( fixed ); + const Float snappedLength = snappedLimit - snappedStart; const Float segment = border.style == BorderStyle::Dotted ? border.width : border.width * 3.f; const Float step = segment * 2.f; - if ( segment <= 0.f || length <= 0.f ) + if ( segment <= 0.f || snappedLength <= 0.f ) return; const Uint32 count = - eemax( 1, static_cast( std::ceil( length / step ) ) ); + eemax( 1, static_cast( std::ceil( snappedLength / step ) ) ); const Float used = ( count - 1 ) * step + segment; - Float cursor = start + eemax( 0.f, ( length - used ) * 0.5f ); + Float cursor = + std::floor( snappedStart + eemax( 0.f, ( snappedLength - used ) * 0.5f ) ); Primitives primitive; primitive.setColor( border.color ); - for ( Uint32 i = 0; i < count && cursor < start + length; ++i, cursor += step ) { - const Float end = eemin( cursor + segment, start + length ); + for ( Uint32 i = 0; i < count && cursor < snappedLimit; ++i, cursor += step ) { + const Float end = eemin( cursor + segment, snappedLimit ); if ( horizontal ) { - primitive.drawRectangle( Rectf( cursor, fixed, end, fixed + border.width ) ); + primitive.drawRectangle( + Rectf( cursor, snappedFixed, end, snappedFixed + border.width ) ); } else { - primitive.drawRectangle( Rectf( fixed, cursor, fixed + border.width, end ) ); + primitive.drawRectangle( + Rectf( snappedFixed, cursor, snappedFixed + border.width, end ) ); } } }; diff --git a/src/eepp/window/backend.hpp b/src/eepp/window/backend.hpp index 7fa20f1f4..73e8b8c9b 100644 --- a/src/eepp/window/backend.hpp +++ b/src/eepp/window/backend.hpp @@ -1,7 +1,7 @@ #ifndef EE_WINDOWCBACKEND_HPP #define EE_WINDOWCBACKEND_HPP -#include +#include namespace EE { namespace Window { namespace Backend {