diff --git a/Externals/SFML/build/vc2008/sfml-network.vcproj b/Externals/SFML/build/vc2008/sfml-network.vcproj new file mode 100644 index 0000000000..0562381715 --- /dev/null +++ b/Externals/SFML/build/vc2008/sfml-network.vcproj @@ -0,0 +1,395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Externals/SFML/include/SFML/Config.hpp b/Externals/SFML/include/SFML/Config.hpp new file mode 100644 index 0000000000..86800e42aa --- /dev/null +++ b/Externals/SFML/include/SFML/Config.hpp @@ -0,0 +1,160 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CONFIG_HPP +#define SFML_CONFIG_HPP + +//////////////////////////////////////////////////////////// +// Identify the operating system +//////////////////////////////////////////////////////////// +#if defined(_WIN32) || defined(__WIN32__) + + // Windows + #define SFML_SYSTEM_WINDOWS + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #endif + #ifndef NOMINMAX + #define NOMINMAX + #endif + +#elif defined(linux) || defined(__linux) + + // Linux + #define SFML_SYSTEM_LINUX + +#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh) + + // MacOS + #define SFML_SYSTEM_MACOS + +#else + + // Unsupported system + #error This operating system is not supported by SFML library + +#endif + + +//////////////////////////////////////////////////////////// +// Define a portable debug macro +//////////////////////////////////////////////////////////// +#if !defined(NDEBUG) + + #define SFML_DEBUG + +#endif + + +//////////////////////////////////////////////////////////// +// Define portable import / export macros +//////////////////////////////////////////////////////////// +#if defined(SFML_SYSTEM_WINDOWS) + + #ifdef SFML_DYNAMIC + + // Windows platforms + #ifdef SFML_EXPORTS + + // From DLL side, we must export + #define SFML_API __declspec(dllexport) + + #else + + // From client application side, we must import + #define SFML_API __declspec(dllimport) + + #endif + + // For Visual C++ compilers, we also need to turn off this annoying C4251 warning. + // You can read lots ot different things about it, but the point is the code will + // just work fine, and so the simplest way to get rid of this warning is to disable it + #ifdef _MSC_VER + + #pragma warning(disable : 4251) + + #endif + + #else + + // No specific directive needed for static build + #define SFML_API + + #endif + +#else + + // Other platforms don't need to define anything + #define SFML_API + +#endif + + +//////////////////////////////////////////////////////////// +// Define portable fixed-size types +//////////////////////////////////////////////////////////// +#include + +namespace sf +{ + // 8 bits integer types + #if UCHAR_MAX == 0xFF + typedef signed char Int8; + typedef unsigned char Uint8; + #else + #error No 8 bits integer type for this platform + #endif + + // 16 bits integer types + #if USHRT_MAX == 0xFFFF + typedef signed short Int16; + typedef unsigned short Uint16; + #elif UINT_MAX == 0xFFFF + typedef signed int Int16; + typedef unsigned int Uint16; + #elif ULONG_MAX == 0xFFFF + typedef signed long Int16; + typedef unsigned long Uint16; + #else + #error No 16 bits integer type for this platform + #endif + + // 32 bits integer types + #if USHRT_MAX == 0xFFFFFFFF + typedef signed short Int32; + typedef unsigned short Uint32; + #elif UINT_MAX == 0xFFFFFFFF + typedef signed int Int32; + typedef unsigned int Uint32; + #elif ULONG_MAX == 0xFFFFFFFF + typedef signed long Int32; + typedef unsigned long Uint32; + #else + #error No 32 bits integer type for this platform + #endif + +} // namespace sf + + +#endif // SFML_CONFIG_HPP diff --git a/Externals/SFML/include/SFML/Network.hpp b/Externals/SFML/include/SFML/Network.hpp new file mode 100644 index 0000000000..fe1730ad62 --- /dev/null +++ b/Externals/SFML/include/SFML/Network.hpp @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_NETWORK_HPP +#define SFML_NETWORK_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif // SFML_NETWORK_HPP diff --git a/Externals/SFML/include/SFML/Network/Ftp.hpp b/Externals/SFML/include/SFML/Network/Ftp.hpp new file mode 100644 index 0000000000..673b9048c9 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Ftp.hpp @@ -0,0 +1,448 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_FTP_HPP +#define SFML_FTP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +class IPAddress; + +//////////////////////////////////////////////////////////// +/// This class provides methods for manipulating the FTP +/// protocol (described in RFC 959). +/// It provides easy access and transfers to remote +/// directories and files on a FTP server +//////////////////////////////////////////////////////////// +class SFML_API Ftp : NonCopyable +{ +public : + + //////////////////////////////////////////////////////////// + /// Enumeration of transfer modes + //////////////////////////////////////////////////////////// + enum TransferMode + { + Binary, ///< Binary mode (file is transfered as a sequence of bytes) + Ascii, ///< Text mode using ASCII encoding + Ebcdic ///< Text mode using EBCDIC encoding + }; + + //////////////////////////////////////////////////////////// + /// This class wraps a FTP response, which is basically : + /// - a status code + /// - a message + //////////////////////////////////////////////////////////// + class SFML_API Response + { + public : + + //////////////////////////////////////////////////////////// + /// Enumerate all the valid status codes returned in + /// 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: SFML 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 + }; + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + /// \param Code : Response status code (InvalidResponse by default) + /// \param Message : Response message (empty by default) + /// + //////////////////////////////////////////////////////////// + Response(Status Code = InvalidResponse, const std::string& Message = ""); + + //////////////////////////////////////////////////////////// + /// Convenience function to check if the response status code + /// means a success + /// + /// \return True if status is success (code < 400) + /// + //////////////////////////////////////////////////////////// + bool IsOk() const; + + //////////////////////////////////////////////////////////// + /// Get the response status code + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Status GetStatus() const; + + //////////////////////////////////////////////////////////// + /// Get the full message contained in the response + /// + /// \return The response message + /// + //////////////////////////////////////////////////////////// + const std::string& GetMessage() const; + + private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Status myStatus; ///< Status code returned from the server + std::string myMessage; ///< Last message received from the server + }; + + //////////////////////////////////////////////////////////// + /// Specialization of FTP response returning a directory + //////////////////////////////////////////////////////////// + class SFML_API DirectoryResponse : public Response + { + public : + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + /// \param Resp : Source response + /// + //////////////////////////////////////////////////////////// + DirectoryResponse(Response Resp); + + //////////////////////////////////////////////////////////// + /// Get the directory returned in the response + /// + /// \return Directory name + /// + //////////////////////////////////////////////////////////// + const std::string& GetDirectory() const; + + private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::string myDirectory; ///< Directory extracted from the response message + }; + + + //////////////////////////////////////////////////////////// + /// Specialization of FTP response returning a filename lisiting + //////////////////////////////////////////////////////////// + class SFML_API ListingResponse : public Response + { + public : + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + /// \param Resp : Source response + /// \param Data : Data containing the raw listing + /// + //////////////////////////////////////////////////////////// + ListingResponse(Response Resp, const std::vector& Data); + + //////////////////////////////////////////////////////////// + /// Get the number of filenames in the listing + /// + /// \return Total number of filenames + /// + //////////////////////////////////////////////////////////// + std::size_t GetCount() const; + + //////////////////////////////////////////////////////////// + /// Get the Index-th filename in the directory + /// + /// \param Index : Index of the filename to get + /// + /// \return Index-th filename + /// + //////////////////////////////////////////////////////////// + const std::string& GetFilename(std::size_t Index) const; + + private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector myFilenames; ///< Filenames extracted from the data + }; + + + //////////////////////////////////////////////////////////// + /// Destructor -- close the connection with the server + /// + //////////////////////////////////////////////////////////// + ~Ftp(); + + //////////////////////////////////////////////////////////// + /// Connect to the specified FTP server + /// + /// \param Server : FTP server to connect to + /// \param Port : Port used for connection (21 by default, standard FTP port) + /// \param Timeout : Maximum time to wait, in seconds (0 by default, means no timeout) + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response Connect(const IPAddress& Server, unsigned short Port = 21, float Timeout = 0.f); + + //////////////////////////////////////////////////////////// + /// Log in using anonymous account + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response Login(); + + //////////////////////////////////////////////////////////// + /// Log in using a username and a password + /// + /// \param UserName : User name + /// \param Password : Password + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response Login(const std::string& UserName, const std::string& Password); + + //////////////////////////////////////////////////////////// + /// Close the connection with FTP server + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response Disconnect(); + + //////////////////////////////////////////////////////////// + /// Send a null command just to prevent from being disconnected + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response KeepAlive(); + + //////////////////////////////////////////////////////////// + /// Get the current working directory + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + DirectoryResponse GetWorkingDirectory(); + + //////////////////////////////////////////////////////////// + /// Get the contents of the given directory + /// (subdirectories and files) + /// + /// \param Directory : Directory to list ("" by default, the current one) + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + ListingResponse GetDirectoryListing(const std::string& Directory = ""); + + //////////////////////////////////////////////////////////// + /// Change the current working directory + /// + /// \param Directory : New directory, relative to the current one + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response ChangeDirectory(const std::string& Directory); + + //////////////////////////////////////////////////////////// + /// Go to the parent directory of the current one + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response ParentDirectory(); + + //////////////////////////////////////////////////////////// + /// Create a new directory + /// + /// \param Name : Name of the directory to create + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response MakeDirectory(const std::string& Name); + + //////////////////////////////////////////////////////////// + /// Remove an existing directory + /// + /// \param Name : Name of the directory to remove + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response DeleteDirectory(const std::string& Name); + + //////////////////////////////////////////////////////////// + /// Rename a file + /// + /// \param File : File to rename + /// \param NewName : New name + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response RenameFile(const std::string& File, const std::string& NewName); + + //////////////////////////////////////////////////////////// + /// Remove an existing file + /// + /// \param Name : File to remove + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response DeleteFile(const std::string& Name); + + //////////////////////////////////////////////////////////// + /// Download a file from the server + /// + /// \param DistantFile : Path of the distant file to download + /// \param DestPath : Where to put to file on the local computer + /// \param Mode : Transfer mode (binary by default) + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode = Binary); + + //////////////////////////////////////////////////////////// + /// Upload a file to the server + /// + /// \param LocalFile : Path of the local file to upload + /// \param DestPath : Where to put to file on the server + /// \param Mode : Transfer mode (binary by default) + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode = Binary); + +private : + + //////////////////////////////////////////////////////////// + /// Send a command to the FTP server + /// + /// \param Command : Command to send + /// \param Parameter : Command parameter ("" by default) + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response SendCommand(const std::string& Command, const std::string& Parameter = ""); + + //////////////////////////////////////////////////////////// + /// Receive a response from the server + /// (usually after a command has been sent) + /// + /// \return Server response to the request + /// + //////////////////////////////////////////////////////////// + Response GetResponse(); + + //////////////////////////////////////////////////////////// + /// Utility class for exchanging datas with the server + /// on the data channel + //////////////////////////////////////////////////////////// + class DataChannel; + + friend class DataChannel; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketTCP myCommandSocket; ///< Socket holding the control connection with the server +}; + +} // namespace sf + + +#endif // SFML_FTP_HPP diff --git a/Externals/SFML/include/SFML/Network/Http.hpp b/Externals/SFML/include/SFML/Network/Http.hpp new file mode 100644 index 0000000000..3e02531fb8 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Http.hpp @@ -0,0 +1,339 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_HTTP_HPP +#define SFML_HTTP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// This class provides methods for manipulating the HTTP +/// protocol (described in RFC 1945). +/// It can connect to a website, get its files, send requests, etc. +//////////////////////////////////////////////////////////// +class SFML_API Http : NonCopyable +{ +public : + + //////////////////////////////////////////////////////////// + /// This class wraps an HTTP request, which is basically : + /// - a header with a method, a target URI, and a set of field/value pairs + /// - an optional body (for POST requests) + //////////////////////////////////////////////////////////// + class SFML_API Request + { + public : + + //////////////////////////////////////////////////////////// + /// Enumerate the available HTTP methods for a request + //////////////////////////////////////////////////////////// + enum Method + { + Get, ///< Request in get mode, standard method to retrieve a page + Post, ///< Request in post mode, usually to send data to a page + Head ///< Request a page's header only + }; + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + /// \param RequestMethod : Method to use for the request (Get by default) + /// \param URI : Target URI ("/" by default -- index page) + /// \param Body : Content of the request's body (empty by default) + /// + //////////////////////////////////////////////////////////// + Request(Method RequestMethod = Get, const std::string& URI = "/", const std::string& Body = ""); + + //////////////////////////////////////////////////////////// + /// Set the value of a field; the field is added if it doesn't exist + /// + /// \param Field : Name of the field to set (case-insensitive) + /// \param Value : Value of the field + /// + //////////////////////////////////////////////////////////// + void SetField(const std::string& Field, const std::string& Value); + + //////////////////////////////////////////////////////////// + /// Set the request method. + /// This parameter is Http::Request::Get by default + /// + /// \param RequestMethod : Method to use for the request + /// + //////////////////////////////////////////////////////////// + void SetMethod(Method RequestMethod); + + //////////////////////////////////////////////////////////// + /// Set the target URI of the request. + /// This parameter is "/" by default + /// + /// \param URI : URI to request, local to the host + /// + //////////////////////////////////////////////////////////// + void SetURI(const std::string& URI); + + //////////////////////////////////////////////////////////// + /// Set the HTTP version of the request. + /// This parameter is 1.0 by default + /// + /// \param Major : Major version number + /// \param Minor : Minor version number + /// + //////////////////////////////////////////////////////////// + void SetHttpVersion(unsigned int Major, unsigned int Minor); + + //////////////////////////////////////////////////////////// + /// Set the body of the request. This parameter is optional and + /// makes sense only for POST requests. + /// This parameter is empty by default + /// + /// \param Body : Content of the request body + /// + //////////////////////////////////////////////////////////// + void SetBody(const std::string& Body); + + private : + + friend class Http; + + //////////////////////////////////////////////////////////// + /// Get the string representation of the request header + /// + /// \return String containing the request + /// + //////////////////////////////////////////////////////////// + std::string ToString() const; + + //////////////////////////////////////////////////////////// + /// Check if the given field has been defined + /// + /// \param Field : Name of the field to check (case-insensitive) + /// + /// \return True if the field exists + /// + //////////////////////////////////////////////////////////// + bool HasField(const std::string& Field) const; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map FieldTable; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + FieldTable myFields; ///< Fields of the header + Method myMethod; ///< Method to use for the request + std::string myURI; ///< Target URI of the request + unsigned int myMajorVersion; ///< Major HTTP version + unsigned int myMinorVersion; ///< Minor HTTP version + std::string myBody; ///< Body of the request + }; + + //////////////////////////////////////////////////////////// + /// This class wraps an HTTP response, which is basically : + /// - a header with a status code and a set of field/value pairs + /// - a body (the content of the requested resource) + //////////////////////////////////////////////////////////// + class SFML_API Response + { + public : + + //////////////////////////////////////////////////////////// + /// Enumerate all the valid status codes returned in + /// a HTTP response + //////////////////////////////////////////////////////////// + enum Status + { + // 2xx: success + Ok = 200, ///< Most common code returned when operation was successful + Created = 201, ///< The resource has successfully been created + Accepted = 202, ///< The request has been accepted, but will be processed later by the server + NoContent = 204, ///< Sent when the server didn't send any data in return + + // 3xx: redirection + MultipleChoices = 300, ///< The requested page can be accessed from several locations + MovedPermanently = 301, ///< The requested page has permanently moved to a new location + MovedTemporarily = 302, ///< The requested page has temporarily moved to a new location + NotModified = 304, ///< For conditionnal requests, means the requested page hasn't changed and doesn't need to be refreshed + + // 4xx: client error + BadRequest = 400, ///< The server couldn't understand the request (syntax error) + Unauthorized = 401, ///< The requested page needs an authentification to be accessed + Forbidden = 403, ///< The requested page cannot be accessed at all, even with authentification + NotFound = 404, ///< The requested page doesn't exist + + // 5xx: server error + InternalServerError = 500, ///< The server encountered an unexpected error + NotImplemented = 501, ///< The server doesn't implement a requested feature + BadGateway = 502, ///< The gateway server has received an error from the source server + ServiceNotAvailable = 503, ///< The server is temporarily unavailable (overloaded, in maintenance, ...) + + // 10xx: SFML custom codes + InvalidResponse = 1000, ///< Response is not a valid HTTP one + ConnectionFailed = 1001 ///< Connection with server failed + }; + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + //////////////////////////////////////////////////////////// + Response(); + + //////////////////////////////////////////////////////////// + /// Get the value of a field + /// + /// \param Field : Name of the field to get (case-insensitive) + /// + /// \return Value of the field, or empty string if not found + /// + //////////////////////////////////////////////////////////// + const std::string& GetField(const std::string& Field) const; + + //////////////////////////////////////////////////////////// + /// Get the header's status code + /// + /// \return Header's status code + /// + //////////////////////////////////////////////////////////// + Status GetStatus() const; + + //////////////////////////////////////////////////////////// + /// Get the major HTTP version number of the response + /// + /// \return Major version number + /// + //////////////////////////////////////////////////////////// + unsigned int GetMajorHttpVersion() const; + + //////////////////////////////////////////////////////////// + /// Get the major HTTP version number of the response + /// + /// \return Major version number + /// + //////////////////////////////////////////////////////////// + unsigned int GetMinorHttpVersion() const; + + //////////////////////////////////////////////////////////// + /// Get the body of the response. The body can contain : + /// - the requested page (for GET requests) + /// - a response from the server (for POST requests) + /// - nothing (for HEAD requests) + /// - an error message (in case of an error) + /// + /// \return The response body + /// + //////////////////////////////////////////////////////////// + const std::string& GetBody() const; + + private : + + friend class Http; + + //////////////////////////////////////////////////////////// + /// Construct the header from a response string + /// + /// \param Data : Content of the response's header to parse + /// + //////////////////////////////////////////////////////////// + void FromString(const std::string& Data); + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map FieldTable; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + FieldTable myFields; ///< Fields of the header + Status myStatus; ///< Status code + unsigned int myMajorVersion; ///< Major HTTP version + unsigned int myMinorVersion; ///< Minor HTTP version + std::string myBody; ///< Body of the response + }; + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + //////////////////////////////////////////////////////////// + Http(); + + //////////////////////////////////////////////////////////// + /// Construct the Http instance with the target host + /// + /// \param Host : Web server to connect to + /// \param Port : Port to use for connection (0 by default -- use the standard port of the protocol used) + /// + //////////////////////////////////////////////////////////// + Http(const std::string& Host, unsigned short Port = 0); + + //////////////////////////////////////////////////////////// + /// Set the target host + /// + /// \param Host : Web server to connect to + /// \param Port : Port to use for connection (0 by default -- use the standard port of the protocol used) + /// + //////////////////////////////////////////////////////////// + void SetHost(const std::string& Host, unsigned short Port = 0); + + //////////////////////////////////////////////////////////// + /// Send a HTTP request and return the server's response. + /// You must be connected to a host before sending requests. + /// Any missing mandatory header field will be added with an appropriate value. + /// Warning : this function waits for the server's response and may + /// not return instantly; use a thread if you don't want to block your + /// application. + /// + /// \param Req : Request to send + /// + /// \return Server's response + /// + //////////////////////////////////////////////////////////// + Response SendRequest(const Request& Req); + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketTCP myConnection; ///< Connection to the host + IPAddress myHost; ///< Web host address + std::string myHostName; ///< Web host name + unsigned short myPort; ///< Port used for connection with host +}; + +} // namespace sf + + +#endif // SFML_HTTP_HPP diff --git a/Externals/SFML/include/SFML/Network/IPAddress.hpp b/Externals/SFML/include/SFML/Network/IPAddress.hpp new file mode 100644 index 0000000000..8373315228 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/IPAddress.hpp @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_IPADDRESS_HPP +#define SFML_IPADDRESS_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// IPAddress provides easy manipulation of IP v4 addresses +//////////////////////////////////////////////////////////// +class SFML_API IPAddress +{ +public : + + //////////////////////////////////////////////////////////// + /// Default constructor -- constructs an invalid address + /// + //////////////////////////////////////////////////////////// + IPAddress(); + + //////////////////////////////////////////////////////////// + /// Construct the address from a string + /// + /// \param Address : IP address ("xxx.xxx.xxx.xxx") or network name + /// + //////////////////////////////////////////////////////////// + IPAddress(const std::string& Address); + + //////////////////////////////////////////////////////////// + /// Construct the address from a C-style string ; + /// Needed for implicit conversions from literal strings to IPAddress to work + /// + /// \param Address : IP address ("xxx.xxx.xxx.xxx") or network name + /// + //////////////////////////////////////////////////////////// + IPAddress(const char* Address); + + //////////////////////////////////////////////////////////// + /// Construct the address from 4 bytes + /// + /// \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); + + //////////////////////////////////////////////////////////// + /// Construct the address from a 32-bits integer + /// + /// \param Address : 4 bytes of the address packed into a 32-bits integer + /// + //////////////////////////////////////////////////////////// + IPAddress(Uint32 Address); + + //////////////////////////////////////////////////////////// + /// Tell if the address is a valid one + /// + /// \return True if address has a valid syntax + /// + //////////////////////////////////////////////////////////// + bool IsValid() const; + + //////////////////////////////////////////////////////////// + /// Get a string representation of the address + /// + /// \return String representation of the IP address ("xxx.xxx.xxx.xxx") + /// + //////////////////////////////////////////////////////////// + std::string ToString() const; + + //////////////////////////////////////////////////////////// + /// Get an integer representation of the address + /// + /// \return 32-bits integer containing the 4 bytes of the address, in system endianness + /// + //////////////////////////////////////////////////////////// + Uint32 ToInteger() const; + + //////////////////////////////////////////////////////////// + /// Get the computer's local IP address (from the LAN point of view) + /// + /// \return Local IP address + /// + //////////////////////////////////////////////////////////// + static IPAddress GetLocalAddress(); + + //////////////////////////////////////////////////////////// + /// Get the computer's public IP address (from the web point of view). + /// The only way to get a public address is to ask it to a + /// distant website ; as a consequence, this function may be + /// very slow -- use it as few as possible ! + /// + /// \return Public IP address + /// + //////////////////////////////////////////////////////////// + static IPAddress GetPublicAddress(); + + //////////////////////////////////////////////////////////// + /// Comparison operator == + /// + /// \param Other : Address to compare + /// + /// \return True if *this == Other + /// + //////////////////////////////////////////////////////////// + bool operator ==(const IPAddress& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator != + /// + /// \param Other : Address to compare + /// + /// \return True if *this != Other + /// + //////////////////////////////////////////////////////////// + bool operator !=(const IPAddress& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator < + /// + /// \param Other : Address to compare + /// + /// \return True if *this < Other + /// + //////////////////////////////////////////////////////////// + bool operator <(const IPAddress& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator > + /// + /// \param Other : Address to compare + /// + /// \return True if *this > Other + /// + //////////////////////////////////////////////////////////// + bool operator >(const IPAddress& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator <= + /// + /// \param Other : Address to compare + /// + /// \return True if *this <= Other + /// + //////////////////////////////////////////////////////////// + bool operator <=(const IPAddress& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator >= + /// + /// \param Other : Address to compare + /// + /// \return True if *this >= Other + /// + //////////////////////////////////////////////////////////// + bool operator >=(const IPAddress& Other) const; + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const IPAddress LocalHost; ///< Local host address (to connect to the same computer) + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Uint32 myAddress; ///< Address stored as an unsigned 32 bits integer +}; + +//////////////////////////////////////////////////////////// +/// Operator >> overload to extract an address from an input stream +/// +/// \param Stream : Input stream +/// \param Address : Address to extract +/// +/// \return Reference to the input stream +/// +//////////////////////////////////////////////////////////// +SFML_API std::istream& operator >>(std::istream& Stream, IPAddress& Address); + +//////////////////////////////////////////////////////////// +/// Operator << overload to print an address to an output stream +/// +/// \param Stream : Output stream +/// \param Address : Address to print +/// +/// \return Reference to the output stream +/// +//////////////////////////////////////////////////////////// +SFML_API std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address); + +} // namespace sf + + +#endif // SFML_IPADDRESS_HPP diff --git a/Externals/SFML/include/SFML/Network/Packet.hpp b/Externals/SFML/include/SFML/Network/Packet.hpp new file mode 100644 index 0000000000..3add17ffcc --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Packet.hpp @@ -0,0 +1,187 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_PACKET_HPP +#define SFML_PACKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Packet wraps data to send / to receive through the network +//////////////////////////////////////////////////////////// +class SFML_API Packet +{ +public : + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + //////////////////////////////////////////////////////////// + Packet(); + + //////////////////////////////////////////////////////////// + /// Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Packet(); + + //////////////////////////////////////////////////////////// + /// Append data to the end of the packet + /// + /// \param Data : Pointer to the bytes to append + /// \param SizeInBytes : Number of bytes to append + /// + //////////////////////////////////////////////////////////// + void Append(const void* Data, std::size_t SizeInBytes); + + //////////////////////////////////////////////////////////// + /// Clear the packet data + /// + //////////////////////////////////////////////////////////// + void Clear(); + + //////////////////////////////////////////////////////////// + /// Get a pointer to the data contained in the packet + /// Warning : the returned pointer may be invalid after you + /// append data to the packet + /// + /// \return Pointer to the data + /// + //////////////////////////////////////////////////////////// + const char* GetData() const; + + //////////////////////////////////////////////////////////// + /// Get the size of the data contained in the packet + /// + /// \return Data size, in bytes + /// + //////////////////////////////////////////////////////////// + std::size_t GetDataSize() const; + + //////////////////////////////////////////////////////////// + /// Tell if the reading position has reached the end of the packet + /// + /// \return True if all data have been read into the packet + /// + //////////////////////////////////////////////////////////// + bool EndOfPacket() const; + + //////////////////////////////////////////////////////////// + /// Return the validity of packet + /// + /// \return True if last data extraction from packet was successful + /// + //////////////////////////////////////////////////////////// + operator bool() const; + + //////////////////////////////////////////////////////////// + /// Operator >> overloads to extract data from the packet + /// + //////////////////////////////////////////////////////////// + Packet& operator >>(bool& Data); + Packet& operator >>(Int8& Data); + Packet& operator >>(Uint8& Data); + Packet& operator >>(Int16& Data); + Packet& operator >>(Uint16& Data); + Packet& operator >>(Int32& Data); + Packet& operator >>(Uint32& Data); + Packet& operator >>(float& Data); + Packet& operator >>(double& Data); + Packet& operator >>(char* Data); + Packet& operator >>(std::string& Data); + Packet& operator >>(wchar_t* Data); + Packet& operator >>(std::wstring& Data); + + //////////////////////////////////////////////////////////// + /// Operator << overloads to put data into the packet + /// + //////////////////////////////////////////////////////////// + Packet& operator <<(bool Data); + Packet& operator <<(Int8 Data); + Packet& operator <<(Uint8 Data); + Packet& operator <<(Int16 Data); + Packet& operator <<(Uint16 Data); + Packet& operator <<(Int32 Data); + Packet& operator <<(Uint32 Data); + Packet& operator <<(float Data); + Packet& operator <<(double Data); + Packet& operator <<(const char* Data); + Packet& operator <<(const std::string& Data); + Packet& operator <<(const wchar_t* Data); + Packet& operator <<(const std::wstring& Data); + +private : + + friend class SocketTCP; + friend class SocketUDP; + + //////////////////////////////////////////////////////////// + /// Check if the packet can extract a given size of bytes + /// + /// \param Size : Size to check + /// + /// \return True if Size bytes can be read from the packet's data + /// + //////////////////////////////////////////////////////////// + bool CheckSize(std::size_t Size); + + //////////////////////////////////////////////////////////// + /// Called before the packet is sent to the network + /// + /// \param DataSize : Variable to fill with the size of data to send + /// + /// \return Pointer to the array of bytes to send + /// + //////////////////////////////////////////////////////////// + virtual const char* OnSend(std::size_t& DataSize); + + //////////////////////////////////////////////////////////// + /// Called after the packet has been received from the network + /// + /// \param Data : Pointer to the array of received bytes + /// \param DataSize : Size of the array of bytes + /// + //////////////////////////////////////////////////////////// + virtual void OnReceive(const char* Data, std::size_t DataSize); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector myData; ///< Data stored in the packet + std::size_t myReadPos; ///< Current reading position in the packet + bool myIsValid; ///< Reading state of the packet +}; + +} // namespace sf + + +#endif // SFML_PACKET_HPP diff --git a/Externals/SFML/include/SFML/Network/Selector.hpp b/Externals/SFML/include/SFML/Network/Selector.hpp new file mode 100644 index 0000000000..3ab7dfaa70 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Selector.hpp @@ -0,0 +1,116 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SELECTOR_HPP +#define SFML_SELECTOR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Selector allow reading from multiple sockets +/// without blocking. It's a kind of multiplexer +//////////////////////////////////////////////////////////// +template +class Selector : private SelectorBase +{ +public : + + //////////////////////////////////////////////////////////// + /// Add a socket to watch + /// + /// \param Socket : Socket to add + /// + //////////////////////////////////////////////////////////// + void Add(Type Socket); + + //////////////////////////////////////////////////////////// + /// Remove a socket + /// + /// \param Socket : Socket to remove + /// + //////////////////////////////////////////////////////////// + void Remove(Type Socket); + + //////////////////////////////////////////////////////////// + /// Remove all sockets + /// + //////////////////////////////////////////////////////////// + void Clear(); + + //////////////////////////////////////////////////////////// + /// Wait and collect sockets which are ready for reading. + /// This functions will return either when at least one socket + /// is ready, or when the given time is out + /// + /// \param Timeout : Timeout, in seconds (0 by default : no timeout) + /// + /// \return Number of sockets ready to be read + /// + //////////////////////////////////////////////////////////// + unsigned int Wait(float Timeout = 0.f); + + //////////////////////////////////////////////////////////// + /// After a call to Wait(), get the Index-th socket which is + /// ready for reading. The total number of sockets ready + /// is the integer returned by the previous call to Wait() + /// + /// \param Index : Index of the socket to get + /// + /// \return The Index-th socket + /// + //////////////////////////////////////////////////////////// + Type GetSocketReady(unsigned int Index); + +private : + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map SocketTable; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketTable mySockets; ///< Table matching the SFML socket instances with their low-level handles +}; + +#include + +// Let's define the two only valid types of Selector +typedef Selector SelectorUDP; +typedef Selector SelectorTCP; + +} // namespace sf + + +#endif // SFML_SELECTOR_HPP diff --git a/Externals/SFML/include/SFML/Network/Selector.inl b/Externals/SFML/include/SFML/Network/Selector.inl new file mode 100644 index 0000000000..326c994602 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Selector.inl @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +/// Add a socket to watch +//////////////////////////////////////////////////////////// +template +void Selector::Add(Type Socket) +{ + if (Socket.IsValid()) + { + SelectorBase::Add(Socket.mySocket); + mySockets[Socket.mySocket] = Socket; + } +} + + +//////////////////////////////////////////////////////////// +/// Remove a socket +//////////////////////////////////////////////////////////// +template +void Selector::Remove(Type Socket) +{ + typename SocketTable::iterator It = mySockets.find(Socket.mySocket); + if (It != mySockets.end()) + { + SelectorBase::Remove(Socket.mySocket); + mySockets.erase(It); + } +} + + +//////////////////////////////////////////////////////////// +/// Remove all sockets +//////////////////////////////////////////////////////////// +template +void Selector::Clear() +{ + SelectorBase::Clear(); + mySockets.clear(); +} + + +//////////////////////////////////////////////////////////// +/// Wait and collect sockets which are ready for reading. +/// This functions will return either when at least one socket +/// is ready, or when the given time is out +//////////////////////////////////////////////////////////// +template +unsigned int Selector::Wait(float Timeout) +{ + // No socket in the selector : return 0 + if (mySockets.empty()) + return 0; + + return SelectorBase::Wait(Timeout); +} + + +//////////////////////////////////////////////////////////// +/// After a call to Wait(), get the Index-th socket which is +/// ready for reading. The total number of sockets ready +/// is the integer returned by the previous call to Wait() +//////////////////////////////////////////////////////////// +template +Type Selector::GetSocketReady(unsigned int Index) +{ + SocketHelper::SocketType Socket = SelectorBase::GetSocketReady(Index); + + typename SocketTable::const_iterator It = mySockets.find(Socket); + if (It != mySockets.end()) + return It->second; + else + return Type(Socket); +} diff --git a/Externals/SFML/include/SFML/Network/SelectorBase.hpp b/Externals/SFML/include/SFML/Network/SelectorBase.hpp new file mode 100644 index 0000000000..433e7893c4 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/SelectorBase.hpp @@ -0,0 +1,112 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SELECTORBASE_HPP +#define SFML_SELECTORBASE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Private base class for selectors. +/// As Selector is a template class, this base is needed so that +/// every system call get compiled in SFML (not inlined) +//////////////////////////////////////////////////////////// +class SFML_API SelectorBase +{ +public : + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + //////////////////////////////////////////////////////////// + SelectorBase(); + + //////////////////////////////////////////////////////////// + /// Add a socket to watch + /// + /// \param Socket : Socket to add + /// + //////////////////////////////////////////////////////////// + void Add(SocketHelper::SocketType Socket); + + //////////////////////////////////////////////////////////// + /// Remove a socket + /// + /// \param Socket : Socket to remove + /// + //////////////////////////////////////////////////////////// + void Remove(SocketHelper::SocketType Socket); + + //////////////////////////////////////////////////////////// + /// Remove all sockets + /// + //////////////////////////////////////////////////////////// + void Clear(); + + //////////////////////////////////////////////////////////// + /// Wait and collect sockets which are ready for reading. + /// This functions will return either when at least one socket + /// is ready, or when the given time is out + /// + /// \param Timeout : Timeout, in seconds (0 by default : no timeout) + /// + /// \return Number of sockets ready to be read + /// + //////////////////////////////////////////////////////////// + unsigned int Wait(float Timeout = 0.f); + + //////////////////////////////////////////////////////////// + /// After a call to Wait(), get the Index-th socket which is + /// ready for reading. The total number of sockets ready + /// is the integer returned by the previous call to Wait() + /// + /// \param Index : Index of the socket to get + /// + /// \return The Index-th socket + /// + //////////////////////////////////////////////////////////// + SocketHelper::SocketType GetSocketReady(unsigned int Index); + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + fd_set mySet; ///< Set of socket to watch + fd_set mySetReady; ///< Set of socket which are ready for reading + int myMaxSocket; ///< Maximum socket index +}; + +} // namespace sf + + +#endif // SFML_SELECTORBASE_HPP diff --git a/Externals/SFML/include/SFML/Network/SocketHelper.hpp b/Externals/SFML/include/SFML/Network/SocketHelper.hpp new file mode 100644 index 0000000000..36126dbb8a --- /dev/null +++ b/Externals/SFML/include/SFML/Network/SocketHelper.hpp @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETHELPER_HPP +#define SFML_SOCKETHELPER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +namespace Socket +{ + //////////////////////////////////////////////////////////// + /// Enumeration of status 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 + Disconnected, ///< The TCP socket has been disconnected + Error ///< An unexpected error happened + }; +} + +} // namespace sf + + +#ifdef SFML_SYSTEM_WINDOWS + + #include + +#else + + #include + +#endif + + +#endif // SFML_SOCKETHELPER_HPP diff --git a/Externals/SFML/include/SFML/Network/SocketTCP.hpp b/Externals/SFML/include/SFML/Network/SocketTCP.hpp new file mode 100644 index 0000000000..452b3045cd --- /dev/null +++ b/Externals/SFML/include/SFML/Network/SocketTCP.hpp @@ -0,0 +1,225 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETTCP_HPP +#define SFML_SOCKETTCP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Packet; +class IPAddress; +template class Selector; + +//////////////////////////////////////////////////////////// +/// SocketTCP wraps a socket using TCP protocol to +/// send data safely (but a bit slower) +//////////////////////////////////////////////////////////// +class SFML_API SocketTCP +{ +public : + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + //////////////////////////////////////////////////////////// + SocketTCP(); + + //////////////////////////////////////////////////////////// + /// Change the blocking state of the socket. + /// The default behaviour of a socket is blocking + /// + /// \param Blocking : Pass true to set the socket as blocking, or false for non-blocking + /// + //////////////////////////////////////////////////////////// + void SetBlocking(bool Blocking); + + //////////////////////////////////////////////////////////// + /// Connect to another computer on a specified port + /// + /// \param Port : Port to use for transfers (warning : ports < 1024 are reserved) + /// \param HostAddress : IP Address of the host to connect to + /// \param Timeout : Maximum time to wait, in seconds (0 by default : no timeout) (this parameter is ignored for non-blocking sockets) + /// + /// \return True if operation has been successful + /// + //////////////////////////////////////////////////////////// + Socket::Status Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout = 0.f); + + //////////////////////////////////////////////////////////// + /// Listen to a specified port for incoming data or connections + /// + /// \param Port : Port to listen to + /// + /// \return True if operation has been successful + /// + //////////////////////////////////////////////////////////// + bool Listen(unsigned short Port); + + //////////////////////////////////////////////////////////// + /// Wait for a connection (must be listening to a port). + /// This function will block if the socket is blocking + /// + /// \param Connected : Socket containing the connection with the connected client + /// \param Address : Pointer to an address to fill with client infos (NULL by default) + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Accept(SocketTCP& Connected, IPAddress* Address = NULL); + + //////////////////////////////////////////////////////////// + /// Send an array of bytes to the host (must be connected first) + /// + /// \param Data : Pointer to the bytes to send + /// \param Size : Number of bytes to send + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Send(const char* Data, std::size_t Size); + + //////////////////////////////////////////////////////////// + /// Receive an array of bytes from the host (must be connected first). + /// This function will block if the socket is blocking + /// + /// \param Data : Pointer to a byte array to fill (make sure it is big enough) + /// \param MaxSize : Maximum number of bytes to read + /// \param SizeReceived : Number of bytes received + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived); + + //////////////////////////////////////////////////////////// + /// Send a packet of data to the host (must be connected first) + /// + /// \param PacketToSend : Packet to send + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Send(Packet& PacketToSend); + + //////////////////////////////////////////////////////////// + /// Receive a packet from the host (must be connected first). + /// This function will block if the socket is blocking + /// + /// \param PacketToReceive : Packet to fill with received data + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Receive(Packet& PacketToReceive); + + //////////////////////////////////////////////////////////// + /// Close the socket + /// + /// \return True if operation has been successful + /// + //////////////////////////////////////////////////////////// + bool Close(); + + //////////////////////////////////////////////////////////// + /// Check if the socket is in a valid state ; this function + /// can be called any time to check if the socket is OK + /// + /// \return True if the socket is valid + /// + //////////////////////////////////////////////////////////// + bool IsValid() const; + + //////////////////////////////////////////////////////////// + /// Comparison operator == + /// + /// \param Other : Socket to compare + /// + /// \return True if *this == Other + /// + //////////////////////////////////////////////////////////// + bool operator ==(const SocketTCP& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator != + /// + /// \param Other : Socket to compare + /// + /// \return True if *this != Other + /// + //////////////////////////////////////////////////////////// + bool operator !=(const SocketTCP& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator <. + /// Provided for compatibility with standard containers, as + /// comparing two sockets doesn't make much sense... + /// + /// \param Other : Socket to compare + /// + /// \return True if *this < Other + /// + //////////////////////////////////////////////////////////// + bool operator <(const SocketTCP& Other) const; + +private : + + friend class Selector; + + //////////////////////////////////////////////////////////// + /// Construct the socket from a socket descriptor + /// (for internal use only) + /// + /// \param Descriptor : Socket descriptor + /// + //////////////////////////////////////////////////////////// + SocketTCP(SocketHelper::SocketType Descriptor); + + //////////////////////////////////////////////////////////// + /// Create the socket + /// + /// \param Descriptor : System socket descriptor to use (0 by default -- create a new socket) + /// + //////////////////////////////////////////////////////////// + void Create(SocketHelper::SocketType Descriptor = 0); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketHelper::SocketType mySocket; ///< Socket descriptor + std::vector myPendingPacket; ///< Data of the current pending packet, if any (in non-blocking mode) + Int32 myPendingPacketSize; ///< Size of the current pending packet, if any (in non-blocking mode) + bool myIsBlocking; ///< Is the socket blocking or non-blocking ? +}; + +} // namespace sf + + +#endif // SFML_SOCKETTCP_HPP diff --git a/Externals/SFML/include/SFML/Network/SocketUDP.hpp b/Externals/SFML/include/SFML/Network/SocketUDP.hpp new file mode 100644 index 0000000000..ba43762de5 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/SocketUDP.hpp @@ -0,0 +1,224 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETUDP_HPP +#define SFML_SOCKETUDP_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Packet; +class IPAddress; +template class Selector; + +//////////////////////////////////////////////////////////// +/// SocketUDP wraps a socket using UDP protocol to +/// send data fastly (but with less safety) +//////////////////////////////////////////////////////////// +class SFML_API SocketUDP +{ +public : + + //////////////////////////////////////////////////////////// + /// Default constructor + /// + //////////////////////////////////////////////////////////// + SocketUDP(); + + //////////////////////////////////////////////////////////// + /// Change the blocking state of the socket. + /// The default behaviour of a socket is blocking + /// + /// \param Blocking : Pass true to set the socket as blocking, or false for non-blocking + /// + //////////////////////////////////////////////////////////// + void SetBlocking(bool Blocking); + + //////////////////////////////////////////////////////////// + /// Bind the socket to a specific port + /// + /// \param Port : Port to bind the socket to + /// + /// \return True if operation has been successful + /// + //////////////////////////////////////////////////////////// + bool Bind(unsigned short Port); + + //////////////////////////////////////////////////////////// + /// Unbind the socket from its previous port, if any + /// + /// \return True if operation has been successful + /// + //////////////////////////////////////////////////////////// + bool Unbind(); + + //////////////////////////////////////////////////////////// + /// Send an array of bytes + /// + /// \param Data : Pointer to the bytes to send + /// \param Size : Number of bytes to send + /// \param Address : Address of the computer to send the packet to + /// \param Port : Port to send the data to + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port); + + //////////////////////////////////////////////////////////// + /// Receive an array of bytes. + /// This function will block if the socket is blocking + /// + /// \param Data : Pointer to a byte array to fill (make sure it is big enough) + /// \param MaxSize : Maximum number of bytes to read + /// \param SizeReceived : Number of bytes received + /// \param Address : Address of the computer which sent the data + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address); + + //////////////////////////////////////////////////////////// + /// Send a packet of data + /// + /// \param PacketToSend : Packet to send + /// \param Address : Address of the computer to send the packet to + /// \param Port : Port to send the data to + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port); + + //////////////////////////////////////////////////////////// + /// Receive a packet. + /// This function will block if the socket is blocking + /// + /// \param PacketToReceive : Packet to fill with received data + /// \param Address : Address of the computer which sent the packet + /// + /// \return Status code + /// + //////////////////////////////////////////////////////////// + Socket::Status Receive(Packet& PacketToReceive, IPAddress& Address); + + //////////////////////////////////////////////////////////// + /// Close the socket + /// + /// \return True if operation has been successful + /// + //////////////////////////////////////////////////////////// + bool Close(); + + //////////////////////////////////////////////////////////// + /// Check if the socket is in a valid state ; this function + /// can be called any time to check if the socket is OK + /// + /// \return True if the socket is valid + /// + //////////////////////////////////////////////////////////// + bool IsValid() const; + + //////////////////////////////////////////////////////////// + /// Get the port the socket is currently bound to + /// + /// \return Current port (0 means the socket is not bound) + /// + //////////////////////////////////////////////////////////// + unsigned short GetPort() const; + + //////////////////////////////////////////////////////////// + /// Comparison operator == + /// + /// \param Other : Socket to compare + /// + /// \return True if *this == Other + /// + //////////////////////////////////////////////////////////// + bool operator ==(const SocketUDP& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator != + /// + /// \param Other : Socket to compare + /// + /// \return True if *this != Other + /// + //////////////////////////////////////////////////////////// + bool operator !=(const SocketUDP& Other) const; + + //////////////////////////////////////////////////////////// + /// Comparison operator <. + /// Provided for compatibility with standard containers, as + /// comparing two sockets doesn't make much sense... + /// + /// \param Other : Socket to compare + /// + /// \return True if *this < Other + /// + //////////////////////////////////////////////////////////// + bool operator <(const SocketUDP& Other) const; + +private : + + friend class Selector; + + //////////////////////////////////////////////////////////// + /// Construct the socket from a socket descriptor + /// (for internal use only) + /// + /// \param Descriptor : Socket descriptor + /// + //////////////////////////////////////////////////////////// + SocketUDP(SocketHelper::SocketType Descriptor); + + //////////////////////////////////////////////////////////// + /// Create the socket + /// + /// \param Descriptor : System socket descriptor to use (0 by default -- create a new socket) + /// + //////////////////////////////////////////////////////////// + void Create(SocketHelper::SocketType Descriptor = 0); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketHelper::SocketType mySocket; ///< Socket identifier + unsigned short myPort; ///< Port to which the socket is bound + std::vector myPendingPacket; ///< Data of the current pending packet, if any (in non-blocking mode) + Int32 myPendingPacketSize; ///< Size of the current pending packet, if any (in non-blocking mode) + bool myIsBlocking; ///< Is the socket blocking or non-blocking ? +}; + +} // namespace sf + + +#endif // SFML_SOCKETUDP_HPP diff --git a/Externals/SFML/include/SFML/Network/Sockets.hpp b/Externals/SFML/include/SFML/Network/Sockets.hpp new file mode 100644 index 0000000000..b611e852b8 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Sockets.hpp @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETS_HPP +#define SFML_SOCKETS_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +#ifdef SFML_SYSTEM_WINDOWS + + #include + +#else + + #include + +#endif + + +#endif // SFML_SOCKETS_HPP diff --git a/Externals/SFML/include/SFML/Network/Unix/SocketHelper.hpp b/Externals/SFML/include/SFML/Network/Unix/SocketHelper.hpp new file mode 100644 index 0000000000..1068cd8536 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Unix/SocketHelper.hpp @@ -0,0 +1,96 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETHELPERUNIX_HPP +#define SFML_SOCKETHELPERUNIX_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// This class defines helper functions to do all the +/// non-portable socket stuff. This class is meant for internal +/// use only +//////////////////////////////////////////////////////////// +class SFML_API SocketHelper +{ +public : + + //////////////////////////////////////////////////////////// + // Define some socket types + //////////////////////////////////////////////////////////// + typedef int SocketType; + typedef socklen_t LengthType; + + //////////////////////////////////////////////////////////// + /// Return the value of the invalid socket + /// + /// \return Unique value of the invalid socket + /// + //////////////////////////////////////////////////////////// + static SocketType InvalidSocket(); + + //////////////////////////////////////////////////////////// + /// Close / destroy a socket + /// + /// \param Socket : Socket to close + /// + /// \return True on success + /// + //////////////////////////////////////////////////////////// + static bool Close(SocketType Socket); + + //////////////////////////////////////////////////////////// + /// Set a socket as blocking or non-blocking + /// + /// \param Socket : Socket to modify + /// \param Block : New blocking state of the socket + /// + //////////////////////////////////////////////////////////// + static void SetBlocking(SocketType Socket, bool Block); + + //////////////////////////////////////////////////////////// + /// Get the last socket error status + /// + /// \return Status corresponding to the last socket error + /// + //////////////////////////////////////////////////////////// + static Socket::Status GetErrorStatus(); +}; + +} // namespace sf + + +#endif // SFML_SOCKETHELPERUNIX_HPP diff --git a/Externals/SFML/include/SFML/Network/Win32/SocketHelper.hpp b/Externals/SFML/include/SFML/Network/Win32/SocketHelper.hpp new file mode 100644 index 0000000000..d7851b4645 --- /dev/null +++ b/Externals/SFML/include/SFML/Network/Win32/SocketHelper.hpp @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SOCKETHELPERWIN32_HPP +#define SFML_SOCKETHELPERWIN32_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// This class defines helper functions to do all the +/// non-portable socket stuff. This class is meant for internal +/// use only +//////////////////////////////////////////////////////////// +class SFML_API SocketHelper +{ +public : + + //////////////////////////////////////////////////////////// + // Define some socket types + //////////////////////////////////////////////////////////// + typedef SOCKET SocketType; + typedef int LengthType; + + //////////////////////////////////////////////////////////// + /// Return the value of the invalid socket + /// + /// \return Unique value of the invalid socket + /// + //////////////////////////////////////////////////////////// + static SocketType InvalidSocket(); + + //////////////////////////////////////////////////////////// + /// Close / destroy a socket + /// + /// \param Socket : Socket to close + /// + /// \return True on success + /// + //////////////////////////////////////////////////////////// + static bool Close(SocketType Socket); + + //////////////////////////////////////////////////////////// + /// Set a socket as blocking or non-blocking + /// + /// \param Socket : Socket to modify + /// \param Block : New blocking state of the socket + /// + //////////////////////////////////////////////////////////// + static void SetBlocking(SocketType Socket, bool Block); + + //////////////////////////////////////////////////////////// + /// Get the last socket error status + /// + /// \return Status corresponding to the last socket error + /// + //////////////////////////////////////////////////////////// + static Socket::Status GetErrorStatus(); +}; + +} // namespace sf + + +#endif // SFML_SOCKETHELPERWIN32_HPP diff --git a/Externals/SFML/include/SFML/System.hpp b/Externals/SFML/include/SFML/System.hpp new file mode 100644 index 0000000000..0fd60564be --- /dev/null +++ b/Externals/SFML/include/SFML/System.hpp @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_SYSTEM_HPP +#define SFML_SYSTEM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// + +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +#endif // SFML_SYSTEM_HPP diff --git a/Externals/SFML/include/SFML/System/NonCopyable.hpp b/Externals/SFML/include/SFML/System/NonCopyable.hpp new file mode 100644 index 0000000000..338653db6d --- /dev/null +++ b/Externals/SFML/include/SFML/System/NonCopyable.hpp @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_NONCOPYABLE_HPP +#define SFML_NONCOPYABLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Utility base class to easily declare non-copyable classes. +/// Just inherit from NonCopyable to get a non-copyable class +//////////////////////////////////////////////////////////// +struct SFML_API NonCopyable +{ +protected : + + //////////////////////////////////////////////////////////// + /// The default constructor won't be generated, so provide it + /// + //////////////////////////////////////////////////////////// + NonCopyable() {} + +private : + + //////////////////////////////////////////////////////////// + /// Copy constructor : declare it private and don't implement + /// it to prevent from calling it + /// + //////////////////////////////////////////////////////////// + NonCopyable(const NonCopyable&); + + //////////////////////////////////////////////////////////// + /// Assignment operator : declare it private and don't implement + /// it to prevent from calling it + /// + //////////////////////////////////////////////////////////// + NonCopyable& operator =(const NonCopyable&); +}; + +} // namespace sf + + +#endif // SFML_NONCOPYABLE_HPP diff --git a/Externals/SFML/src/SFML/Network/Ftp.cpp b/Externals/SFML/src/SFML/Network/Ftp.cpp new file mode 100644 index 0000000000..090e6af803 --- /dev/null +++ b/Externals/SFML/src/SFML/Network/Ftp.cpp @@ -0,0 +1,709 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +// Utility class for exchanging stuff with the server +// on the data channel +//////////////////////////////////////////////////////////// +class Ftp::DataChannel : NonCopyable +{ +public : + + //////////////////////////////////////////////////////////// + // Constructor + //////////////////////////////////////////////////////////// + DataChannel(Ftp& Owner); + + //////////////////////////////////////////////////////////// + // Destructor + //////////////////////////////////////////////////////////// + ~DataChannel(); + + //////////////////////////////////////////////////////////// + // Open the data channel using the specified mode and port + //////////////////////////////////////////////////////////// + Ftp::Response Open(Ftp::TransferMode Mode); + + //////////////////////////////////////////////////////////// + // Send data on the data channel + //////////////////////////////////////////////////////////// + void Send(const std::vector& Data); + + //////////////////////////////////////////////////////////// + // Receive data on the data channel until it is closed + //////////////////////////////////////////////////////////// + void Receive(std::vector& Data); + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Ftp& myFtp; ///< Reference to the owner Ftp instance + SocketTCP myDataSocket; ///< Socket used for data transfers +}; + + +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Ftp::Response::Response(Status Code, const std::string& Message) : +myStatus (Code), +myMessage(Message) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Convenience function to check if the response status code +/// means a success +//////////////////////////////////////////////////////////// +bool Ftp::Response::IsOk() const +{ + return myStatus < 400; +} + + +//////////////////////////////////////////////////////////// +/// Get the response status code +//////////////////////////////////////////////////////////// +Ftp::Response::Status Ftp::Response::GetStatus() const +{ + return myStatus; +} + + +//////////////////////////////////////////////////////////// +/// Get the full message contained in the response +//////////////////////////////////////////////////////////// +const std::string& Ftp::Response::GetMessage() const +{ + return myMessage; +} + + +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response Resp) : +Ftp::Response(Resp) +{ + if (IsOk()) + { + // Extract the directory from the server response + std::string::size_type Begin = Resp.GetMessage().find('"', 0); + std::string::size_type End = Resp.GetMessage().find('"', Begin + 1); + myDirectory = Resp.GetMessage().substr(Begin + 1, End - Begin - 1); + } +} + + +//////////////////////////////////////////////////////////// +/// Get the directory returned in the response +//////////////////////////////////////////////////////////// +const std::string& Ftp::DirectoryResponse::GetDirectory() const +{ + return myDirectory; +} + + +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Ftp::ListingResponse::ListingResponse(Ftp::Response Resp, const std::vector& Data) : +Ftp::Response(Resp) +{ + if (IsOk()) + { + // Fill the array of strings + std::string Paths(Data.begin(), Data.end()); + std::string::size_type LastPos = 0; + for (std::string::size_type Pos = Paths.find("\r\n"); Pos != std::string::npos; Pos = Paths.find("\r\n", LastPos)) + { + myFilenames.push_back(Paths.substr(LastPos, Pos - LastPos)); + LastPos = Pos + 2; + } + } +} + + +//////////////////////////////////////////////////////////// +/// Get the number of filenames in the listing +//////////////////////////////////////////////////////////// +std::size_t Ftp::ListingResponse::GetCount() const +{ + return myFilenames.size(); +} + + +//////////////////////////////////////////////////////////// +/// Get the Index-th filename in the directory +//////////////////////////////////////////////////////////// +const std::string& Ftp::ListingResponse::GetFilename(std::size_t Index) const +{ + return myFilenames[Index]; +} + + +//////////////////////////////////////////////////////////// +/// Destructor -- close the connection with the server +//////////////////////////////////////////////////////////// +Ftp::~Ftp() +{ + Disconnect(); +} + + +//////////////////////////////////////////////////////////// +/// Connect to the specified FTP server +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::Connect(const IPAddress& Server, unsigned short Port, float Timeout) +{ + // Connect to the server + if (myCommandSocket.Connect(Port, Server, Timeout) != Socket::Done) + return Response(Response::ConnectionFailed); + + // Get the response to the connection + return GetResponse(); +} + + +//////////////////////////////////////////////////////////// +/// Log in using anonymous account +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::Login() +{ + return Login("anonymous", "user@sfml-dev.org"); +} + + +//////////////////////////////////////////////////////////// +/// Log in using a username and a password +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::Login(const std::string& UserName, const std::string& Password) +{ + Response Resp = SendCommand("USER", UserName); + if (Resp.IsOk()) + Resp = SendCommand("PASS", Password); + + return Resp; +} + + +//////////////////////////////////////////////////////////// +/// Close the connection with FTP server +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::Disconnect() +{ + // Send the exit command + Response Resp = SendCommand("QUIT"); + if (Resp.IsOk()) + myCommandSocket.Close(); + + return Resp; +} + + +//////////////////////////////////////////////////////////// +/// Send a null command just to prevent from being disconnected +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::KeepAlive() +{ + return SendCommand("NOOP"); +} + + +//////////////////////////////////////////////////////////// +/// Get the current working directory +//////////////////////////////////////////////////////////// +Ftp::DirectoryResponse Ftp::GetWorkingDirectory() +{ + return DirectoryResponse(SendCommand("PWD")); +} + + +//////////////////////////////////////////////////////////// +/// Get the contents of the given directory +/// (subdirectories and files) +//////////////////////////////////////////////////////////// +Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& Directory) +{ + // Open a data channel on default port (20) using ASCII transfer mode + std::vector DirData; + DataChannel Data(*this); + Response Resp = Data.Open(Ascii); + if (Resp.IsOk()) + { + // Tell the server to send us the listing + Resp = SendCommand("NLST", Directory); + if (Resp.IsOk()) + { + // Receive the listing + Data.Receive(DirData); + + // Get the response from the server + Resp = GetResponse(); + } + } + + return ListingResponse(Resp, DirData); +} + + +//////////////////////////////////////////////////////////// +/// Change the current working directory +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::ChangeDirectory(const std::string& Directory) +{ + return SendCommand("CWD", Directory); +} + + +//////////////////////////////////////////////////////////// +/// Go to the parent directory of the current one +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::ParentDirectory() +{ + return SendCommand("CDUP"); +} + + +//////////////////////////////////////////////////////////// +/// Create a new directory +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::MakeDirectory(const std::string& Name) +{ + return SendCommand("MKD", Name); +} + + +//////////////////////////////////////////////////////////// +/// Remove an existing directory +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::DeleteDirectory(const std::string& Name) +{ + return SendCommand("RMD", Name); +} + + +//////////////////////////////////////////////////////////// +/// Rename a file +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::RenameFile(const std::string& File, const std::string& NewName) +{ + Response Resp = SendCommand("RNFR", File); + if (Resp.IsOk()) + Resp = SendCommand("RNTO", NewName); + + return Resp; +} + + +//////////////////////////////////////////////////////////// +/// Remove an existing file +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::DeleteFile(const std::string& Name) +{ + return SendCommand("DELE", Name); +} + + +//////////////////////////////////////////////////////////// +/// Download a file from the server +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode) +{ + // Open a data channel using the given transfer mode + DataChannel Data(*this); + Response Resp = Data.Open(Mode); + if (Resp.IsOk()) + { + // Tell the server to start the transfer + Resp = SendCommand("RETR", DistantFile); + if (Resp.IsOk()) + { + // Receive the file data + std::vector FileData; + Data.Receive(FileData); + + // Get the response from the server + Resp = GetResponse(); + if (Resp.IsOk()) + { + // Extract the filename from the file path + std::string Filename = DistantFile; + std::string::size_type Pos = Filename.find_last_of("/\\"); + if (Pos != std::string::npos) + Filename = Filename.substr(Pos + 1); + + // Make sure the destination path ends with a slash + std::string Path = DestPath; + if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/')) + Path += "/"; + + // Create the file and copy the received data into it + std::ofstream File((Path + Filename).c_str(), std::ios_base::binary); + if (!File) + return Response(Response::InvalidFile); + File.write(&FileData[0], static_cast(FileData.size())); + } + } + } + + return Resp; +} + + +//////////////////////////////////////////////////////////// +/// Upload a file to the server +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode) +{ + // Get the contents of the file to send + std::ifstream File(LocalFile.c_str(), std::ios_base::binary); + if (!File) + return Response(Response::InvalidFile); + File.seekg(0, std::ios::end); + std::size_t Length = File.tellg(); + File.seekg(0, std::ios::beg); + std::vector FileData(Length); + File.read(&FileData[0], static_cast(Length)); + + // Extract the filename from the file path + std::string Filename = LocalFile; + std::string::size_type Pos = Filename.find_last_of("/\\"); + if (Pos != std::string::npos) + Filename = Filename.substr(Pos + 1); + + // Make sure the destination path ends with a slash + std::string Path = DestPath; + if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/')) + Path += "/"; + + // Open a data channel using the given transfer mode + DataChannel Data(*this); + Response Resp = Data.Open(Mode); + if (Resp.IsOk()) + { + // Tell the server to start the transfer + Resp = SendCommand("STOR", Path + Filename); + if (Resp.IsOk()) + { + // Send the file data + Data.Send(FileData); + + // Get the response from the server + Resp = GetResponse(); + } + } + + return Resp; +} + + +//////////////////////////////////////////////////////////// +/// Send a command to the FTP server +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::SendCommand(const std::string& Command, const std::string& Parameter) +{ + // Build the command string + std::string CommandStr; + if (Parameter != "") + CommandStr = Command + " " + Parameter + "\r\n"; + else + CommandStr = Command + "\r\n"; + + // Send it to the server + if (myCommandSocket.Send(CommandStr.c_str(), CommandStr.length()) != sf::Socket::Done) + return Response(Response::ConnectionClosed); + + // Get the response + return GetResponse(); +} + + +//////////////////////////////////////////////////////////// +/// Receive a response from the server +/// (usually after a command has been sent) +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::GetResponse() +{ + // We'll use a variable to keep track of the last valid code. + // It is useful in case of multi-lines responses, because the end of such a response + // will start by the same code + unsigned int LastCode = 0; + bool IsInsideMultiline = false; + std::string Message; + + for (;;) + { + // Receive the response from the server + char Buffer[1024]; + std::size_t Length; + if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done) + return Response(Response::ConnectionClosed); + + // There can be several lines inside the received buffer, extract them all + std::istringstream In(std::string(Buffer, Length), std::ios_base::binary); + while (In) + { + // Try to extract the code + unsigned int Code; + if (In >> Code) + { + // Extract the separator + char Sep; + In.get(Sep); + + // The '-' character means a multiline response + if ((Sep == '-') && !IsInsideMultiline) + { + // Set the multiline flag + IsInsideMultiline = true; + + // Keep track of the code + if (LastCode == 0) + LastCode = Code; + + // Extract the line + std::getline(In, Message); + + // Remove the ending '\r' (all lines are terminated by "\r\n") + Message.erase(Message.length() - 1); + Message = Sep + Message + "\n"; + } + else + { + // We must make sure that the code is the same, otherwise it means + // we haven't reached the end of the multiline response + if ((Sep != '-') && ((Code == LastCode) || (LastCode == 0))) + { + // Clear the multiline flag + IsInsideMultiline = false; + + // Extract the line + std::string Line; + std::getline(In, Line); + + // Remove the ending '\r' (all lines are terminated by "\r\n") + Line.erase(Line.length() - 1); + + // Append it to the message + if (Code == LastCode) + { + std::ostringstream Out; + Out << Code << Sep << Line; + Message += Out.str(); + } + else + { + Message = Sep + Line; + } + + // Return the response code and message + return Response(static_cast(Code), Message); + } + else + { + // The line we just read was actually not a response, + // only a new part of the current multiline response + + // Extract the line + std::string Line; + std::getline(In, Line); + + if (!Line.empty()) + { + // Remove the ending '\r' (all lines are terminated by "\r\n") + Line.erase(Line.length() - 1); + + // Append it to the current message + std::ostringstream Out; + Out << Code << Sep << Line << "\n"; + Message += Out.str(); + } + } + } + } + else if (LastCode != 0) + { + // It seems we are in the middle of a multiline response + + // Clear the error bits of the stream + In.clear(); + + // Extract the line + std::string Line; + std::getline(In, Line); + + if (!Line.empty()) + { + // Remove the ending '\r' (all lines are terminated by "\r\n") + Line.erase(Line.length() - 1); + + // Append it to the current message + Message += Line + "\n"; + } + } + else + { + // Error : cannot extract the code, and we are not in a multiline response + return Response(Response::InvalidResponse); + } + } + } + + // We never reach there +} + + +//////////////////////////////////////////////////////////// +/// Constructor +//////////////////////////////////////////////////////////// +Ftp::DataChannel::DataChannel(Ftp& Owner) : +myFtp(Owner) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Destructor +//////////////////////////////////////////////////////////// +Ftp::DataChannel::~DataChannel() +{ + // Close the data socket + myDataSocket.Close(); +} + + +//////////////////////////////////////////////////////////// +/// Open the data channel using the specified mode and port +//////////////////////////////////////////////////////////// +Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode Mode) +{ + // Open a data connection in active mode (we connect to the server) + Ftp::Response Resp = myFtp.SendCommand("PASV"); + if (Resp.IsOk()) + { + // Extract the connection address and port from the response + std::string::size_type begin = Resp.GetMessage().find_first_of("0123456789"); + if (begin != std::string::npos) + { + sf::Uint8 Data[6] = {0, 0, 0, 0, 0, 0}; + std::string Str = Resp.GetMessage().substr(begin); + std::size_t Index = 0; + for (int i = 0; i < 6; ++i) + { + // Extract the current number + while (isdigit(Str[Index])) + { + Data[i] = Data[i] * 10 + (Str[Index] - '0'); + Index++; + } + + // Skip separator + Index++; + } + + // Reconstruct connection port and address + unsigned short Port = Data[4] * 256 + Data[5]; + sf::IPAddress Address(static_cast(Data[0]), + static_cast(Data[1]), + static_cast(Data[2]), + static_cast(Data[3])); + + // Connect the data channel to the server + if (myDataSocket.Connect(Port, Address) == Socket::Done) + { + // Translate the transfer mode to the corresponding FTP parameter + std::string ModeStr; + switch (Mode) + { + case Ftp::Binary : ModeStr = "I"; break; + case Ftp::Ascii : ModeStr = "A"; break; + case Ftp::Ebcdic : ModeStr = "E"; break; + } + + // Set the transfer mode + Resp = myFtp.SendCommand("TYPE", ModeStr); + } + else + { + // Failed to connect to the server + Resp = Ftp::Response(Ftp::Response::ConnectionFailed); + } + } + } + + return Resp; +} + + +//////////////////////////////////////////////////////////// +/// Receive data on the data channel until it is closed +//////////////////////////////////////////////////////////// +void Ftp::DataChannel::Receive(std::vector& Data) +{ + // Receive data + Data.clear(); + char Buffer[1024]; + std::size_t Received; + while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done) + { + std::copy(Buffer, Buffer + Received, std::back_inserter(Data)); + } + + // Close the data socket + myDataSocket.Close(); +} + + +//////////////////////////////////////////////////////////// +/// Send data on the data channel +//////////////////////////////////////////////////////////// +void Ftp::DataChannel::Send(const std::vector& Data) +{ + // Send data + myDataSocket.Send(&Data[0], Data.size()); + + // Close the data socket + myDataSocket.Close(); +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/Http.cpp b/Externals/SFML/src/SFML/Network/Http.cpp new file mode 100644 index 0000000000..4794aff131 --- /dev/null +++ b/Externals/SFML/src/SFML/Network/Http.cpp @@ -0,0 +1,425 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace +{ + //////////////////////////////////////////////////////////// + // Convenience function to convert a string to lower case + //////////////////////////////////////////////////////////// + std::string ToLower(const std::string& Str) + { + std::string Ret = Str; + for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i) + *i = static_cast(tolower(*i)); + + return Ret; + } +} + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body) : +myMethod (RequestMethod), +myURI (URI), +myMajorVersion(1), +myMinorVersion(0), +myBody (Body) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Set the value of a field; the field is added if it doesn't exist +//////////////////////////////////////////////////////////// +void Http::Request::SetField(const std::string& Field, const std::string& Value) +{ + myFields[ToLower(Field)] = Value; +} + + +//////////////////////////////////////////////////////////// +/// Set the request method. +/// This parameter is Get by default +//////////////////////////////////////////////////////////// +void Http::Request::SetMethod(Http::Request::Method RequestMethod) +{ + myMethod = RequestMethod; +} + + +//////////////////////////////////////////////////////////// +/// Set the target URI of the request. +/// This parameter is "/" by default +//////////////////////////////////////////////////////////// +void Http::Request::SetURI(const std::string& URI) +{ + myURI = URI; + + // Make sure it starts with a '/' + if (myURI.empty() || (myURI[0] != '/')) + myURI.insert(0, "/"); +} + + +//////////////////////////////////////////////////////////// +/// Set the HTTP version of the request. +/// This parameter is 1.0 by default +//////////////////////////////////////////////////////////// +void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor) +{ + myMajorVersion = Major; + myMinorVersion = Minor; +} + + +//////////////////////////////////////////////////////////// +/// Set the body of the request. This parameter is optional and +/// makes sense only for POST requests. +/// This parameter is empty by default +//////////////////////////////////////////////////////////// +void Http::Request::SetBody(const std::string& Body) +{ + myBody = Body; +} + + +//////////////////////////////////////////////////////////// +/// Get the string representation of a request header +//////////////////////////////////////////////////////////// +std::string Http::Request::ToString() const +{ + std::ostringstream Out; + + // Convert the method to its string representation + std::string RequestMethod; + switch (myMethod) + { + default : + case Get : RequestMethod = "GET"; break; + case Post : RequestMethod = "POST"; break; + case Head : RequestMethod = "HEAD"; break; + } + + // Write the first line containing the request type + Out << RequestMethod << " " << myURI << " "; + Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n"; + + // Write fields + for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i) + { + Out << i->first << ": " << i->second << "\r\n"; + } + + // Use an extra \r\n to separate the header from the body + Out << "\r\n"; + + // Add the body + Out << myBody; + + return Out.str(); +} + + +//////////////////////////////////////////////////////////// +/// Check if the given field has been defined +//////////////////////////////////////////////////////////// +bool Http::Request::HasField(const std::string& Field) const +{ + return myFields.find(Field) != myFields.end(); +} + + +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Http::Response::Response() : +myStatus (ConnectionFailed), +myMajorVersion(0), +myMinorVersion(0) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Get the value of a field +//////////////////////////////////////////////////////////// +const std::string& Http::Response::GetField(const std::string& Field) const +{ + FieldTable::const_iterator It = myFields.find(Field); + if (It != myFields.end()) + { + return It->second; + } + else + { + static const std::string Empty = ""; + return Empty; + } +} + + +//////////////////////////////////////////////////////////// +/// Get the header's status code +//////////////////////////////////////////////////////////// +Http::Response::Status Http::Response::GetStatus() const +{ + return myStatus; +} + + +//////////////////////////////////////////////////////////// +/// Get the major HTTP version number of the response +//////////////////////////////////////////////////////////// +unsigned int Http::Response::GetMajorHttpVersion() const +{ + return myMajorVersion; +} + + +//////////////////////////////////////////////////////////// +/// Get the major HTTP version number of the response +//////////////////////////////////////////////////////////// +unsigned int Http::Response::GetMinorHttpVersion() const +{ + return myMinorVersion; +} + + +//////////////////////////////////////////////////////////// +/// Get the body of the response. The body can contain : +/// - the requested page (for GET requests) +/// - a response from the server (for POST requests) +/// - nothing (for HEAD requests) +/// - an error message (in case of an error) +//////////////////////////////////////////////////////////// +const std::string& Http::Response::GetBody() const +{ + return myBody; +} + + +//////////////////////////////////////////////////////////// +/// Construct the header from a response string +//////////////////////////////////////////////////////////// +void Http::Response::FromString(const std::string& Data) +{ + std::istringstream In(Data); + + // Extract the HTTP version from the first line + std::string Version; + if (In >> Version) + { + if ((Version.size() >= 8) && (Version[6] == '.') && + (ToLower(Version.substr(0, 5)) == "http/") && + isdigit(Version[5]) && isdigit(Version[7])) + { + myMajorVersion = Version[5] - '0'; + myMinorVersion = Version[7] - '0'; + } + else + { + // Invalid HTTP version + myStatus = InvalidResponse; + return; + } + } + + // Extract the status code from the first line + int StatusCode; + if (In >> StatusCode) + { + myStatus = static_cast(StatusCode); + } + else + { + // Invalid status code + myStatus = InvalidResponse; + return; + } + + // Ignore the end of the first line + In.ignore(10000, '\n'); + + // Parse the other lines, which contain fields, one by one + std::string Line; + while (std::getline(In, Line) && (Line.size() > 2)) + { + std::string::size_type Pos = Line.find(": "); + if (Pos != std::string::npos) + { + // Extract the field name and its value + std::string Field = Line.substr(0, Pos); + std::string Value = Line.substr(Pos + 2); + + // Remove any trailing \r + if (!Value.empty() && (*Value.rbegin() == '\r')) + Value.erase(Value.size() - 1); + + // Add the field + myFields[ToLower(Field)] = Value; + } + } + + // Finally extract the body + myBody.clear(); + while (std::getline(In, Line)) + myBody += Line + "\n"; +} + + +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Http::Http() : +myHost(), +myPort(0) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Construct the Http instance with the target host +//////////////////////////////////////////////////////////// +Http::Http(const std::string& Host, unsigned short Port) +{ + SetHost(Host, Port); +} + + +//////////////////////////////////////////////////////////// +/// Set the target host +//////////////////////////////////////////////////////////// +void Http::SetHost(const std::string& Host, unsigned short Port) +{ + // Detect the protocol used + std::string Protocol = ToLower(Host.substr(0, 8)); + if (Protocol.substr(0, 7) == "http://") + { + // HTTP protocol + myHostName = Host.substr(7); + myPort = (Port != 0 ? Port : 80); + } + else if (Protocol == "https://") + { + // HTTPS protocol + myHostName = Host.substr(8); + myPort = (Port != 0 ? Port : 443); + } + else + { + // Undefined protocol - use HTTP + myHostName = Host; + myPort = (Port != 0 ? Port : 80); + } + + // Remove any trailing '/' from the host name + if (!myHostName.empty() && (*myHostName.rbegin() == '/')) + myHostName.erase(myHostName.size() - 1); + + myHost = sf::IPAddress(myHostName); +} + + +//////////////////////////////////////////////////////////// +/// Send a HTTP request and return the server's response. +/// You must be connected to a host before sending requests. +/// Any missing mandatory header field will be added with an appropriate value. +/// Warning : this function waits for the server's response and may +/// not return instantly; use a thread if you don't want to block your +/// application. +//////////////////////////////////////////////////////////// +Http::Response Http::SendRequest(const Http::Request& Req) +{ + // First make sure the request is valid -- add missing mandatory fields + Request ToSend(Req); + if (!ToSend.HasField("From")) + { + ToSend.SetField("From", "user@sfml-dev.org"); + } + if (!ToSend.HasField("User-Agent")) + { + ToSend.SetField("User-Agent", "libsfml-network/1.x"); + } + if (!ToSend.HasField("Host")) + { + ToSend.SetField("Host", myHostName); + } + if (!ToSend.HasField("Content-Length")) + { + std::ostringstream Out; + Out << ToSend.myBody.size(); + ToSend.SetField("Content-Length", Out.str()); + } + + // Prepare the response + Response Received; + + // Connect the socket to the host + if (myConnection.Connect(myPort, myHost) == Socket::Done) + { + // Convert the request to string and send it through the connected socket + std::string RequestStr = ToSend.ToString(); + + if (!RequestStr.empty()) + { + // Send it through the socket + if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done) + { + // Wait for the server's response + std::string ReceivedStr; + std::size_t Size = 0; + char Buffer[1024]; + while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done) + { + ReceivedStr.append(Buffer, Buffer + Size); + } + + // Build the Response object from the received data + Received.FromString(ReceivedStr); + } + } + + // Close the connection + myConnection.Close(); + } + + return Received; +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/IPAddress.cpp b/Externals/SFML/src/SFML/Network/IPAddress.cpp new file mode 100644 index 0000000000..985ef41c75 --- /dev/null +++ b/Externals/SFML/src/SFML/Network/IPAddress.cpp @@ -0,0 +1,303 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Static member data +//////////////////////////////////////////////////////////// +const IPAddress IPAddress::LocalHost("127.0.0.1"); + + +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +IPAddress::IPAddress() : +myAddress(INADDR_NONE) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Construct the address from a string +//////////////////////////////////////////////////////////// +IPAddress::IPAddress(const std::string& Address) +{ + // First try to convert it as a byte representation ("xxx.xxx.xxx.xxx") + myAddress = inet_addr(Address.c_str()); + + // If not successful, try to convert it as a host name + if (!IsValid()) + { + hostent* Host = gethostbyname(Address.c_str()); + if (Host) + { + // Host found, extract its IP address + myAddress = reinterpret_cast(Host->h_addr)->s_addr; + } + else + { + // Host name not found on the network + myAddress = INADDR_NONE; + } + } +} + + +//////////////////////////////////////////////////////////// +/// Construct the address from a C-style string ; +/// Needed for implicit conversions from literal strings to IPAddress to work +//////////////////////////////////////////////////////////// +IPAddress::IPAddress(const char* Address) +{ + // First try to convert it as a byte representation ("xxx.xxx.xxx.xxx") + myAddress = inet_addr(Address); + + // If not successful, try to convert it as a host name + if (!IsValid()) + { + hostent* Host = gethostbyname(Address); + if (Host) + { + // Host found, extract its IP address + myAddress = reinterpret_cast(Host->h_addr)->s_addr; + } + else + { + // Host name not found on the network + myAddress = INADDR_NONE; + } + } +} + + +//////////////////////////////////////////////////////////// +/// Construct the address from 4 bytes +//////////////////////////////////////////////////////////// +IPAddress::IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3) +{ + myAddress = htonl((Byte0 << 24) | (Byte1 << 16) | (Byte2 << 8) | Byte3); +} + + +//////////////////////////////////////////////////////////// +/// Construct the address from a 32-bits integer +//////////////////////////////////////////////////////////// +IPAddress::IPAddress(Uint32 Address) +{ + myAddress = htonl(Address); +} + + +//////////////////////////////////////////////////////////// +/// Tell if the address is a valid one +//////////////////////////////////////////////////////////// +bool IPAddress::IsValid() const +{ + return myAddress != INADDR_NONE; +} + + +//////////////////////////////////////////////////////////// +/// Get a string representation of the address +//////////////////////////////////////////////////////////// +std::string IPAddress::ToString() const +{ + in_addr InAddr; + InAddr.s_addr = myAddress; + + return inet_ntoa(InAddr); +} + + +//////////////////////////////////////////////////////////// +/// Get an integer representation of the address +//////////////////////////////////////////////////////////// +Uint32 IPAddress::ToInteger() const +{ + return ntohl(myAddress); +} + + +//////////////////////////////////////////////////////////// +/// Get the computer's local IP address (from the LAN point of view) +//////////////////////////////////////////////////////////// +IPAddress IPAddress::GetLocalAddress() +{ + // The method here is to connect a UDP socket to anyone (here to localhost), + // and get the local socket address with the getsockname function. + // UDP connection will not send anything to the network, so this function won't cause any overhead + + IPAddress LocalAddress; + + // Create the socket + SocketHelper::SocketType Socket = socket(PF_INET, SOCK_DGRAM, 0); + if (Socket == SocketHelper::InvalidSocket()) + return LocalAddress; + + // Build the host address (use a random port) + sockaddr_in SockAddr; + memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero)); + SockAddr.sin_addr.s_addr = INADDR_LOOPBACK; + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(4567); + + // Connect the socket + if (connect(Socket, reinterpret_cast(&SockAddr), sizeof(SockAddr)) == -1) + { + SocketHelper::Close(Socket); + return LocalAddress; + } + + // Get the local address of the socket connection + SocketHelper::LengthType Size = sizeof(SockAddr); + if (getsockname(Socket, reinterpret_cast(&SockAddr), &Size) == -1) + { + SocketHelper::Close(Socket); + return LocalAddress; + } + + // Close the socket + SocketHelper::Close(Socket); + + // Finally build the IP address + LocalAddress.myAddress = SockAddr.sin_addr.s_addr; + + return LocalAddress; +} + + +//////////////////////////////////////////////////////////// +/// Get the computer's public IP address (from the web point of view) +//////////////////////////////////////////////////////////// +IPAddress IPAddress::GetPublicAddress() +{ + // The trick here is more complicated, because the only way + // to get our public IP address is to get it from a distant computer. + // Here we get the web page from http://www.whatismyip.org + // and parse the result to extract our IP address + // (not very hard : the web page contains only our IP address) + + IPAddress PublicAddress; + + // Connect to the web server and get its index page + Http Server("www.whatismyip.org"); + Http::Request Request(Http::Request::Get, "/"); + Http::Response Page = Server.SendRequest(Request); + + // If the request was successful, we can extract + // the address from the body of the web page + if (Page.GetStatus() == Http::Response::Ok) + PublicAddress = Page.GetBody(); + + return PublicAddress; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator == +//////////////////////////////////////////////////////////// +bool IPAddress::operator ==(const IPAddress& Other) const +{ + return myAddress == Other.myAddress; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator != +//////////////////////////////////////////////////////////// +bool IPAddress::operator !=(const IPAddress& Other) const +{ + return myAddress != Other.myAddress; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator < +//////////////////////////////////////////////////////////// +bool IPAddress::operator <(const IPAddress& Other) const +{ + return myAddress < Other.myAddress; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator > +//////////////////////////////////////////////////////////// +bool IPAddress::operator >(const IPAddress& Other) const +{ + return myAddress > Other.myAddress; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator <= +//////////////////////////////////////////////////////////// +bool IPAddress::operator <=(const IPAddress& Other) const +{ + return myAddress <= Other.myAddress; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator >= +//////////////////////////////////////////////////////////// +bool IPAddress::operator >=(const IPAddress& Other) const +{ + return myAddress >= Other.myAddress; +} + + +//////////////////////////////////////////////////////////// +/// Operator >> overload to extract an address from an input stream +//////////////////////////////////////////////////////////// +std::istream& operator >>(std::istream& Stream, IPAddress& Address) +{ + std::string Str; + Stream >> Str; + Address = IPAddress(Str); + + return Stream; +} + + +//////////////////////////////////////////////////////////// +/// Operator << overload to print an address to an output stream +//////////////////////////////////////////////////////////// +std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address) +{ + return Stream << Address.ToString(); +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/Packet.cpp b/Externals/SFML/src/SFML/Network/Packet.cpp new file mode 100644 index 0000000000..9bc37ddaff --- /dev/null +++ b/Externals/SFML/src/SFML/Network/Packet.cpp @@ -0,0 +1,426 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +Packet::Packet() : +myReadPos(0), +myIsValid(true) +{ + +} + + +//////////////////////////////////////////////////////////// +/// Virtual destructor +//////////////////////////////////////////////////////////// +Packet::~Packet() +{ + +} + + +//////////////////////////////////////////////////////////// +/// Append data to the end of the packet +//////////////////////////////////////////////////////////// +void Packet::Append(const void* Data, std::size_t SizeInBytes) +{ + if (Data && (SizeInBytes > 0)) + { + std::size_t Start = myData.size(); + myData.resize(Start + SizeInBytes); + memcpy(&myData[Start], Data, SizeInBytes); + } +} + + +//////////////////////////////////////////////////////////// +/// Clear the packet data +//////////////////////////////////////////////////////////// +void Packet::Clear() +{ + myData.clear(); + myReadPos = 0; + myIsValid = true; +} + + +//////////////////////////////////////////////////////////// +/// Get a pointer to the data contained in the packet +/// Warning : the returned pointer may be invalid after you +/// append data to the packet +//////////////////////////////////////////////////////////// +const char* Packet::GetData() const +{ + return !myData.empty() ? &myData[0] : NULL; +} + + +//////////////////////////////////////////////////////////// +/// Get the size of the data contained in the packet +//////////////////////////////////////////////////////////// +std::size_t Packet::GetDataSize() const +{ + return myData.size(); +} + + +//////////////////////////////////////////////////////////// +/// Tell if the reading position has reached the end of the packet +//////////////////////////////////////////////////////////// +bool Packet::EndOfPacket() const +{ + return myReadPos >= myData.size(); +} + + +//////////////////////////////////////////////////////////// +/// Tell if the packet is valid for reading +//////////////////////////////////////////////////////////// +Packet::operator bool() const +{ + return myIsValid; +} + + +//////////////////////////////////////////////////////////// +/// Operator >> overloads to extract data from the packet +//////////////////////////////////////////////////////////// +Packet& Packet::operator >>(bool& Data) +{ + Uint8 Value; + if (*this >> Value) + Data = (Value != 0); + + return *this; +} +Packet& Packet::operator >>(Int8& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = *reinterpret_cast(GetData() + myReadPos); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(Uint8& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = *reinterpret_cast(GetData() + myReadPos); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(Int16& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = ntohs(*reinterpret_cast(GetData() + myReadPos)); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(Uint16& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = ntohs(*reinterpret_cast(GetData() + myReadPos)); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(Int32& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = ntohl(*reinterpret_cast(GetData() + myReadPos)); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(Uint32& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = ntohl(*reinterpret_cast(GetData() + myReadPos)); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(float& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = *reinterpret_cast(GetData() + myReadPos); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(double& Data) +{ + if (CheckSize(sizeof(Data))) + { + Data = *reinterpret_cast(GetData() + myReadPos); + myReadPos += sizeof(Data); + } + + return *this; +} +Packet& Packet::operator >>(char* Data) +{ + // First extract string length + Uint32 Length; + *this >> Length; + + if ((Length > 0) && CheckSize(Length)) + { + // Then extract characters + memcpy(Data, GetData() + myReadPos, Length); + Data[Length] = '\0'; + + // Update reading position + myReadPos += Length; + } + + return *this; +} +Packet& Packet::operator >>(std::string& Data) +{ + // First extract string length + Uint32 Length; + *this >> Length; + + Data.clear(); + if ((Length > 0) && CheckSize(Length)) + { + // Then extract characters + Data.assign(GetData() + myReadPos, Length); + + // Update reading position + myReadPos += Length; + } + + return *this; +} +Packet& Packet::operator >>(wchar_t* Data) +{ + // First extract string length + Uint32 Length; + *this >> Length; + + if ((Length > 0) && CheckSize(Length * sizeof(Int32))) + { + // Then extract characters + for (Uint32 i = 0; i < Length; ++i) + { + Uint32 c; + *this >> c; + Data[i] = static_cast(c); + } + Data[Length] = L'\0'; + } + + return *this; +} +Packet& Packet::operator >>(std::wstring& Data) +{ + // First extract string length + Uint32 Length; + *this >> Length; + + Data.clear(); + if ((Length > 0) && CheckSize(Length * sizeof(Int32))) + { + // Then extract characters + for (Uint32 i = 0; i < Length; ++i) + { + Uint32 c; + *this >> c; + Data += static_cast(c); + } + } + + return *this; +} + + +//////////////////////////////////////////////////////////// +/// Operator << overloads to put data into the packet +//////////////////////////////////////////////////////////// +Packet& Packet::operator <<(bool Data) +{ + *this << static_cast(Data); + return *this; +} +Packet& Packet::operator <<(Int8 Data) +{ + Append(&Data, sizeof(Data)); + return *this; +} +Packet& Packet::operator <<(Uint8 Data) +{ + Append(&Data, sizeof(Data)); + return *this; +} +Packet& Packet::operator <<(Int16 Data) +{ + Int16 ToWrite = htons(Data); + Append(&ToWrite, sizeof(ToWrite)); + return *this; +} +Packet& Packet::operator <<(Uint16 Data) +{ + Uint16 ToWrite = htons(Data); + Append(&ToWrite, sizeof(ToWrite)); + return *this; +} +Packet& Packet::operator <<(Int32 Data) +{ + Int32 ToWrite = htonl(Data); + Append(&ToWrite, sizeof(ToWrite)); + return *this; +} +Packet& Packet::operator <<(Uint32 Data) +{ + Uint32 ToWrite = htonl(Data); + Append(&ToWrite, sizeof(ToWrite)); + return *this; +} +Packet& Packet::operator <<(float Data) +{ + Append(&Data, sizeof(Data)); + return *this; +} +Packet& Packet::operator <<(double Data) +{ + Append(&Data, sizeof(Data)); + return *this; +} +Packet& Packet::operator <<(const char* Data) +{ + // First insert string length + Uint32 Length = 0; + for (const char* c = Data; *c != '\0'; ++c) + ++Length; + *this << Length; + + // Then insert characters + Append(Data, Length * sizeof(char)); + + return *this; +} +Packet& Packet::operator <<(const std::string& Data) +{ + // First insert string length + Uint32 Length = static_cast(Data.size()); + *this << Length; + + // Then insert characters + if (Length > 0) + { + Append(Data.c_str(), Length * sizeof(std::string::value_type)); + } + + return *this; +} +Packet& Packet::operator <<(const wchar_t* Data) +{ + // First insert string length + Uint32 Length = 0; + for (const wchar_t* c = Data; *c != L'\0'; ++c) + ++Length; + *this << Length; + + // Then insert characters + for (const wchar_t* c = Data; *c != L'\0'; ++c) + *this << static_cast(*c); + + return *this; +} +Packet& Packet::operator <<(const std::wstring& Data) +{ + // First insert string length + Uint32 Length = static_cast(Data.size()); + *this << Length; + + // Then insert characters + if (Length > 0) + { + for (std::wstring::const_iterator c = Data.begin(); c != Data.end(); ++c) + *this << static_cast(*c); + } + + return *this; +} + + +//////////////////////////////////////////////////////////// +/// Check if the packet can extract a given size of bytes +//////////////////////////////////////////////////////////// +bool Packet::CheckSize(std::size_t Size) +{ + myIsValid = myIsValid && (myReadPos + Size <= myData.size()); + + return myIsValid; +} + + +//////////////////////////////////////////////////////////// +/// Called before the packet is sent to the network +//////////////////////////////////////////////////////////// +const char* Packet::OnSend(std::size_t& DataSize) +{ + DataSize = GetDataSize(); + return GetData(); +} + + +//////////////////////////////////////////////////////////// +/// Called after the packet has been received from the network +//////////////////////////////////////////////////////////// +void Packet::OnReceive(const char* Data, std::size_t DataSize) +{ + Append(Data, DataSize); +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/SelectorBase.cpp b/Externals/SFML/src/SFML/Network/SelectorBase.cpp new file mode 100644 index 0000000000..ebe31a7be7 --- /dev/null +++ b/Externals/SFML/src/SFML/Network/SelectorBase.cpp @@ -0,0 +1,132 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifdef _MSC_VER + #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro +#endif + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +SelectorBase::SelectorBase() : +myMaxSocket(0) +{ + Clear(); +} + + +//////////////////////////////////////////////////////////// +/// Add a socket to watch +//////////////////////////////////////////////////////////// +void SelectorBase::Add(SocketHelper::SocketType Socket) +{ + FD_SET(Socket, &mySet); + + int Size = static_cast(Socket); + if (Size > myMaxSocket) + myMaxSocket = Size; +} + + +//////////////////////////////////////////////////////////// +/// Remove a socket +//////////////////////////////////////////////////////////// +void SelectorBase::Remove(SocketHelper::SocketType Socket) +{ + FD_CLR(Socket, &mySet); +} + + +//////////////////////////////////////////////////////////// +/// Remove all sockets +//////////////////////////////////////////////////////////// +void SelectorBase::Clear() +{ + FD_ZERO(&mySet); + FD_ZERO(&mySetReady); + + myMaxSocket = 0; +} + + +//////////////////////////////////////////////////////////// +/// Wait and collect sockets which are ready for reading. +/// This functions will return either when at least one socket +/// is ready, or when the given time is out +//////////////////////////////////////////////////////////// +unsigned int SelectorBase::Wait(float Timeout) +{ + // Setup the timeout structure + timeval Time; + Time.tv_sec = static_cast(Timeout); + Time.tv_usec = (static_cast(Timeout * 1000) % 1000) * 1000; + + // Prepare the set of sockets to return + mySetReady = mySet; + + // Wait until one of the sockets is ready for reading, or timeout is reached + int NbSockets = select(myMaxSocket + 1, &mySetReady, NULL, NULL, Timeout > 0 ? &Time : NULL); + + return NbSockets >= 0 ? static_cast(NbSockets) : 0; +} + + +//////////////////////////////////////////////////////////// +/// After a call to Wait(), get the Index-th socket which is +/// ready for reading. The total number of sockets ready +/// is the integer returned by the previous call to Wait() +//////////////////////////////////////////////////////////// +SocketHelper::SocketType SelectorBase::GetSocketReady(unsigned int Index) +{ + // The standard FD_xxx interface doesn't define a direct access, + // so we must go through the whole set to find the socket we're looking for + for (int i = 0; i < myMaxSocket + 1; ++i) + { + if (FD_ISSET(i, &mySetReady)) + { + // Current socket is ready, but is it the Index-th one ? + if (Index > 0) + { + Index--; + } + else + { + return static_cast(i); + } + } + } + + // Invalid index : return an invalid socket + return SocketHelper::InvalidSocket(); +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/SocketTCP.cpp b/Externals/SFML/src/SFML/Network/SocketTCP.cpp new file mode 100644 index 0000000000..f7f9ec1498 --- /dev/null +++ b/Externals/SFML/src/SFML/Network/SocketTCP.cpp @@ -0,0 +1,490 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _MSC_VER + #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro +#endif + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +SocketTCP::SocketTCP() +{ + Create(SocketHelper::InvalidSocket()); +} + + +//////////////////////////////////////////////////////////// +/// Change the blocking state of the socket +//////////////////////////////////////////////////////////// +void SocketTCP::SetBlocking(bool Blocking) +{ + // Make sure our socket is valid + if (!IsValid()) + Create(); + + SocketHelper::SetBlocking(mySocket, Blocking); + myIsBlocking = Blocking; +} + + +//////////////////////////////////////////////////////////// +/// Connect to another computer on a specified port +//////////////////////////////////////////////////////////// +Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout) +{ + // Make sure our socket is valid + if (!IsValid()) + Create(); + + // Build the host address + sockaddr_in SockAddr; + memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero)); + SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str()); + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(Port); + + if (Timeout <= 0) + { + // ----- We're not using a timeout : just try to connect ----- + + if (connect(mySocket, reinterpret_cast(&SockAddr), sizeof(SockAddr)) == -1) + { + // Failed to connect + return SocketHelper::GetErrorStatus(); + } + + // Connection succeeded + return Socket::Done; + } + else + { + // ----- We're using a timeout : we'll need a few tricks to make it work ----- + + // Save the previous blocking state + bool IsBlocking = myIsBlocking; + + // Switch to non-blocking to enable our connection timeout + if (IsBlocking) + SetBlocking(false); + + // Try to connect to host + if (connect(mySocket, reinterpret_cast(&SockAddr), sizeof(SockAddr)) >= 0) + { + // We got instantly connected! (it may no happen a lot...) + return Socket::Done; + } + + // Get the error status + Socket::Status Status = SocketHelper::GetErrorStatus(); + + // If we were in non-blocking mode, return immediatly + if (!IsBlocking) + return Status; + + // Otherwise, wait until something happens to our socket (success, timeout or error) + if (Status == Socket::NotReady) + { + // Setup the selector + fd_set Selector; + FD_ZERO(&Selector); + FD_SET(mySocket, &Selector); + + // Setup the timeout + timeval Time; + Time.tv_sec = static_cast(Timeout); + Time.tv_usec = (static_cast(Timeout * 1000) % 1000) * 1000; + + // Wait for something to write on our socket (would mean the connection has been accepted) + if (select(static_cast(mySocket + 1), NULL, &Selector, NULL, &Time) > 0) + { + // Connection succeeded + Status = Socket::Done; + } + else + { + // Failed to connect before timeout is over + Status = SocketHelper::GetErrorStatus(); + } + } + + // Switch back to blocking mode + SetBlocking(true); + + return Status; + } +} + + +//////////////////////////////////////////////////////////// +/// Listen to a specified port for incoming data or connections +//////////////////////////////////////////////////////////// +bool SocketTCP::Listen(unsigned short Port) +{ + // Make sure our socket is valid + if (!IsValid()) + Create(); + + // Build the address + sockaddr_in SockAddr; + memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero)); + SockAddr.sin_addr.s_addr = htonl(INADDR_ANY); + SockAddr.sin_family = AF_INET; + SockAddr.sin_port = htons(Port); + + // Bind the socket to the specified port + if (bind(mySocket, reinterpret_cast(&SockAddr), sizeof(SockAddr)) == -1) + { + // Not likely to happen, but... + std::cerr << "Failed to bind socket to port " << Port << std::endl; + return false; + } + + // Listen to the bound port + if (listen(mySocket, 0) == -1) + { + // Oops, socket is deaf + std::cerr << "Failed to listen to port " << Port << std::endl; + return false; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +/// Wait for a connection (must be listening to a port). +/// This function will block if the socket is blocking +//////////////////////////////////////////////////////////// +Socket::Status SocketTCP::Accept(SocketTCP& Connected, IPAddress* Address) +{ + // Address that will be filled with client informations + sockaddr_in ClientAddress; + SocketHelper::LengthType Length = sizeof(ClientAddress); + + // Accept a new connection + Connected = accept(mySocket, reinterpret_cast(&ClientAddress), &Length); + + // Check errors + if (!Connected.IsValid()) + { + if (Address) + *Address = IPAddress(); + + return SocketHelper::GetErrorStatus(); + } + + // Fill address if requested + if (Address) + *Address = IPAddress(inet_ntoa(ClientAddress.sin_addr)); + + return Socket::Done; +} + + +//////////////////////////////////////////////////////////// +/// Send an array of bytes to the host (must be connected first) +//////////////////////////////////////////////////////////// +Socket::Status SocketTCP::Send(const char* Data, std::size_t Size) +{ + // First check that socket is valid + if (!IsValid()) + return Socket::Error; + + // Check parameters + if (Data && Size) + { + // Loop until every byte has been sent + int Sent = 0; + int SizeToSend = static_cast(Size); + for (int Length = 0; Length < SizeToSend; Length += Sent) + { + // Send a chunk of data + Sent = send(mySocket, Data + Length, SizeToSend - Length, 0); + + // Check if an error occured + if (Sent <= 0) + return SocketHelper::GetErrorStatus(); + } + + return Socket::Done; + } + else + { + // Error... + std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl; + return Socket::Error; + } +} + + +//////////////////////////////////////////////////////////// +/// Receive an array of bytes from the host (must be connected first). +/// This function will block if the socket is blocking +//////////////////////////////////////////////////////////// +Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived) +{ + // First clear the size received + SizeReceived = 0; + + // Check that socket is valid + if (!IsValid()) + return Socket::Error; + + // Check parameters + if (Data && MaxSize) + { + // Receive a chunk of bytes + int Received = recv(mySocket, Data, static_cast(MaxSize), 0); + + // Check the number of bytes received + if (Received > 0) + { + SizeReceived = static_cast(Received); + return Socket::Done; + } + else if (Received == 0) + { + return Socket::Disconnected; + } + else + { + return SocketHelper::GetErrorStatus(); + } + } + else + { + // Error... + std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl; + return Socket::Error; + } +} + + +//////////////////////////////////////////////////////////// +/// Send a packet of data to the host (must be connected first) +//////////////////////////////////////////////////////////// +Socket::Status SocketTCP::Send(Packet& PacketToSend) +{ + // Get the data to send from the packet + std::size_t DataSize = 0; + const char* Data = PacketToSend.OnSend(DataSize); + + // Send the packet size + Uint32 PacketSize = htonl(static_cast(DataSize)); + Send(reinterpret_cast(&PacketSize), sizeof(PacketSize)); + + // Send the packet data + if (PacketSize > 0) + { + return Send(Data, DataSize); + } + else + { + return Socket::Done; + } +} + + +//////////////////////////////////////////////////////////// +/// Receive a packet from the host (must be connected first). +/// This function will block if the socket is blocking +//////////////////////////////////////////////////////////// +Socket::Status SocketTCP::Receive(Packet& PacketToReceive) +{ + // We start by getting the size of the incoming packet + Uint32 PacketSize = 0; + std::size_t Received = 0; + if (myPendingPacketSize < 0) + { + Socket::Status Status = Receive(reinterpret_cast(&PacketSize), sizeof(PacketSize), Received); + if (Status != Socket::Done) + return Status; + + PacketSize = ntohl(PacketSize); + } + else + { + // There is a pending packet : we already know its size + PacketSize = myPendingPacketSize; + } + + // Then loop until we receive all the packet data + char Buffer[1024]; + while (myPendingPacket.size() < PacketSize) + { + // Receive a chunk of data + std::size_t SizeToGet = std::min(static_cast(PacketSize - myPendingPacket.size()), sizeof(Buffer)); + Socket::Status Status = Receive(Buffer, SizeToGet, Received); + if (Status != Socket::Done) + { + // We must save the size of the pending packet until we can receive its content + if (Status == Socket::NotReady) + myPendingPacketSize = PacketSize; + return Status; + } + + // Append it into the packet + if (Received > 0) + { + myPendingPacket.resize(myPendingPacket.size() + Received); + char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received; + memcpy(Begin, Buffer, Received); + } + } + + // We have received all the datas : we can copy it to the user packet, and clear our internal packet + PacketToReceive.Clear(); + if (!myPendingPacket.empty()) + PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size()); + myPendingPacket.clear(); + myPendingPacketSize = -1; + + return Socket::Done; +} + + +//////////////////////////////////////////////////////////// +/// Close the socket +//////////////////////////////////////////////////////////// +bool SocketTCP::Close() +{ + if (IsValid()) + { + if (!SocketHelper::Close(mySocket)) + { + std::cerr << "Failed to close socket" << std::endl; + return false; + } + + mySocket = SocketHelper::InvalidSocket(); + } + + myIsBlocking = true; + + return true; +} + + +//////////////////////////////////////////////////////////// +/// Check if the socket is in a valid state ; this function +/// can be called any time to check if the socket is OK +//////////////////////////////////////////////////////////// +bool SocketTCP::IsValid() const +{ + return mySocket != SocketHelper::InvalidSocket(); +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator == +//////////////////////////////////////////////////////////// +bool SocketTCP::operator ==(const SocketTCP& Other) const +{ + return mySocket == Other.mySocket; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator != +//////////////////////////////////////////////////////////// +bool SocketTCP::operator !=(const SocketTCP& Other) const +{ + return mySocket != Other.mySocket; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator <. +/// Provided for compatibility with standard containers, as +/// comparing two sockets doesn't make much sense... +//////////////////////////////////////////////////////////// +bool SocketTCP::operator <(const SocketTCP& Other) const +{ + return mySocket < Other.mySocket; +} + + +//////////////////////////////////////////////////////////// +/// Construct the socket from a socket descriptor +/// (for internal use only) +//////////////////////////////////////////////////////////// +SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor) +{ + Create(Descriptor); +} + + +//////////////////////////////////////////////////////////// +/// Create the socket +//////////////////////////////////////////////////////////// +void SocketTCP::Create(SocketHelper::SocketType Descriptor) +{ + // Use the given socket descriptor, or get a new one + mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0); + myIsBlocking = true; + + // Reset the pending packet + myPendingPacket.clear(); + myPendingPacketSize = -1; + + // Setup default options + if (IsValid()) + { + // To avoid the "Address already in use" error message when trying to bind to the same port + int Yes = 1; + if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&Yes), sizeof(Yes)) == -1) + { + std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; " + << "binding to a same port may fail if too fast" << std::endl; + } + + // Disable the Nagle algorithm (ie. removes buffering of TCP packets) + if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&Yes), sizeof(Yes)) == -1) + { + std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; " + << "all your TCP packets will be buffered" << std::endl; + } + + // Set blocking by default (should always be the case anyway) + SetBlocking(true); + } +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/SocketUDP.cpp b/Externals/SFML/src/SFML/Network/SocketUDP.cpp new file mode 100644 index 0000000000..2cd42274ab --- /dev/null +++ b/Externals/SFML/src/SFML/Network/SocketUDP.cpp @@ -0,0 +1,431 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Default constructor +//////////////////////////////////////////////////////////// +SocketUDP::SocketUDP() +{ + Create(); +} + + +//////////////////////////////////////////////////////////// +/// Change the blocking state of the socket +//////////////////////////////////////////////////////////// +void SocketUDP::SetBlocking(bool Blocking) +{ + // Make sure our socket is valid + if (!IsValid()) + Create(); + + SocketHelper::SetBlocking(mySocket, Blocking); + myIsBlocking = Blocking; +} + + +//////////////////////////////////////////////////////////// +/// Bind the socket to a specific port +//////////////////////////////////////////////////////////// +bool SocketUDP::Bind(unsigned short Port) +{ + // Check if the socket is already bound to the specified port + if (myPort != Port) + { + // If the socket was previously bound to another port, we need to recreate it + if (myPort != 0) + { + Close(); + Create(); + } + + if (Port != 0) + { + // Build an address with the specified port + sockaddr_in Addr; + Addr.sin_family = AF_INET; + Addr.sin_port = htons(Port); + Addr.sin_addr.s_addr = INADDR_ANY; + memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero)); + + // Bind the socket to the port + if (bind(mySocket, reinterpret_cast(&Addr), sizeof(Addr)) == -1) + { + std::cerr << "Failed to bind the socket to port " << Port << std::endl; + myPort = 0; + return false; + } + } + + // Save the new port + myPort = Port; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +/// Unbind the socket to its previous port +//////////////////////////////////////////////////////////// +bool SocketUDP::Unbind() +{ + // To unbind the socket, we just recreate it + if (myPort != 0) + { + Close(); + Create(); + myPort = 0; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +/// Send an array of bytes +//////////////////////////////////////////////////////////// +Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port) +{ + // Make sure the socket is valid + if (!IsValid()) + Create(); + + // Check parameters + if (Data && Size) + { + // Build the target address + sockaddr_in Target; + Target.sin_family = AF_INET; + Target.sin_port = htons(Port); + Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str()); + memset(Target.sin_zero, 0, sizeof(Target.sin_zero)); + + // Loop until every byte has been sent + int Sent = 0; + int SizeToSend = static_cast(Size); + for (int Length = 0; Length < SizeToSend; Length += Sent) + { + // Send a chunk of data + Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast(&Target), sizeof(Target)); + + // Check errors + if (Sent <= 0) + return SocketHelper::GetErrorStatus(); + } + + return Socket::Done; + } + else + { + // Error... + std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl; + return Socket::Error; + } +} + + +//////////////////////////////////////////////////////////// +/// Receive an array of bytes. +/// This function will block if the socket is blocking +//////////////////////////////////////////////////////////// +Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address) +{ + // First clear the size received + SizeReceived = 0; + + // Make sure the socket is bound to a port + if (myPort == 0) + { + std::cerr << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl; + return Socket::Error; + } + + // Make sure the socket is valid + if (!IsValid()) + Create(); + + // Check parameters + if (Data && MaxSize) + { + // Data that will be filled with the other computer's address + sockaddr_in Sender; + Sender.sin_family = AF_INET; + Sender.sin_port = htons(myPort); + Sender.sin_addr.s_addr = INADDR_ANY; + memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero)); + SocketHelper::LengthType SenderSize = sizeof(Sender); + + // Receive a chunk of bytes + int Received = recvfrom(mySocket, Data, static_cast(MaxSize), 0, reinterpret_cast(&Sender), &SenderSize); + + // Check the number of bytes received + if (Received > 0) + { + Address = IPAddress(inet_ntoa(Sender.sin_addr)); + SizeReceived = static_cast(Received); + return Socket::Done; + } + else + { + Address = IPAddress(); + return Received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus(); + } + } + else + { + // Error... + std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl; + return Socket::Error; + } +} + + +//////////////////////////////////////////////////////////// +/// Send a packet of data +//////////////////////////////////////////////////////////// +Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port) +{ + // Get the data to send from the packet + std::size_t DataSize = 0; + const char* Data = PacketToSend.OnSend(DataSize); + + // Send the packet size + Uint32 PacketSize = htonl(static_cast(DataSize)); + Send(reinterpret_cast(&PacketSize), sizeof(PacketSize), Address, Port); + + // Send the packet data + if (PacketSize > 0) + { + return Send(Data, DataSize, Address, Port); + } + else + { + return Socket::Done; + } +} + + +//////////////////////////////////////////////////////////// +/// Receive a packet. +/// This function will block if the socket is blocking +//////////////////////////////////////////////////////////// +Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address) +{ + // This is not safe at all, as data can be lost, duplicated, or arrive in a different order. + // So if a packet is split into more than one chunk, nobody knows what could happen... + // Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it. + + // We start by getting the size of the incoming packet + Uint32 PacketSize = 0; + std::size_t Received = 0; + if (myPendingPacketSize < 0) + { + Socket::Status Status = Receive(reinterpret_cast(&PacketSize), sizeof(PacketSize), Received, Address); + if (Status != Socket::Done) + return Status; + + PacketSize = ntohl(PacketSize); + } + else + { + // There is a pending packet : we already know its size + PacketSize = myPendingPacketSize; + } + + // Clear the user packet + PacketToReceive.Clear(); + + // Use another address instance for receiving the packet data ; + // chunks of data coming from a different sender will be discarded (and lost...) + IPAddress Sender; + + // Then loop until we receive all the packet data + char Buffer[1024]; + while (myPendingPacket.size() < PacketSize) + { + // Receive a chunk of data + std::size_t SizeToGet = std::min(static_cast(PacketSize - myPendingPacket.size()), sizeof(Buffer)); + Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender); + if (Status != Socket::Done) + { + // We must save the size of the pending packet until we can receive its content + if (Status == Socket::NotReady) + myPendingPacketSize = PacketSize; + return Status; + } + + // Append it into the packet + if ((Sender == Address) && (Received > 0)) + { + myPendingPacket.resize(myPendingPacket.size() + Received); + char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received; + memcpy(Begin, Buffer, Received); + } + } + + // We have received all the datas : we can copy it to the user packet, and clear our internal packet + PacketToReceive.Clear(); + if (!myPendingPacket.empty()) + PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size()); + myPendingPacket.clear(); + myPendingPacketSize = -1; + + return Socket::Done; +} + + +//////////////////////////////////////////////////////////// +/// Close the socket +//////////////////////////////////////////////////////////// +bool SocketUDP::Close() +{ + if (IsValid()) + { + if (!SocketHelper::Close(mySocket)) + { + std::cerr << "Failed to close socket" << std::endl; + return false; + } + + mySocket = SocketHelper::InvalidSocket(); + } + + myPort = 0; + myIsBlocking = true; + + return true; +} + + +//////////////////////////////////////////////////////////// +/// Check if the socket is in a valid state ; this function +/// can be called any time to check if the socket is OK +//////////////////////////////////////////////////////////// +bool SocketUDP::IsValid() const +{ + return mySocket != SocketHelper::InvalidSocket(); +} + + +//////////////////////////////////////////////////////////// +/// Get the port the socket is currently bound to +//////////////////////////////////////////////////////////// +unsigned short SocketUDP::GetPort() const +{ + return myPort; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator == +//////////////////////////////////////////////////////////// +bool SocketUDP::operator ==(const SocketUDP& Other) const +{ + return mySocket == Other.mySocket; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator != +//////////////////////////////////////////////////////////// +bool SocketUDP::operator !=(const SocketUDP& Other) const +{ + return mySocket != Other.mySocket; +} + + +//////////////////////////////////////////////////////////// +/// Comparison operator <. +/// Provided for compatibility with standard containers, as +/// comparing two sockets doesn't make much sense... +//////////////////////////////////////////////////////////// +bool SocketUDP::operator <(const SocketUDP& Other) const +{ + return mySocket < Other.mySocket; +} + + +//////////////////////////////////////////////////////////// +/// Construct the socket from a socket descriptor +/// (for internal use only) +//////////////////////////////////////////////////////////// +SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor) +{ + Create(Descriptor); +} + + +//////////////////////////////////////////////////////////// +/// Create the socket +//////////////////////////////////////////////////////////// +void SocketUDP::Create(SocketHelper::SocketType Descriptor) +{ + // Use the given socket descriptor, or get a new one + mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0); + myIsBlocking = true; + + // Clear the last port used + myPort = 0; + + // Reset the pending packet + myPendingPacket.clear(); + myPendingPacketSize = -1; + + // Setup default options + if (IsValid()) + { + // To avoid the "Address already in use" error message when trying to bind to the same port + int Yes = 1; + if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&Yes), sizeof(Yes)) == -1) + { + std::cerr << "Failed to set socket option \"reuse address\" ; " + << "binding to a same port may fail if too fast" << std::endl; + } + + // Enable broadcast by default + if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&Yes), sizeof(Yes)) == -1) + { + std::cerr << "Failed to enable broadcast on UDP socket" << std::endl; + } + + // Set blocking by default (should always be the case anyway) + SetBlocking(true); + } +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/Unix/SocketHelper.cpp b/Externals/SFML/src/SFML/Network/Unix/SocketHelper.cpp new file mode 100644 index 0000000000..2a2e6b2cfc --- /dev/null +++ b/Externals/SFML/src/SFML/Network/Unix/SocketHelper.cpp @@ -0,0 +1,83 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Return the value of the invalid socket +//////////////////////////////////////////////////////////// +SocketHelper::SocketType SocketHelper::InvalidSocket() +{ + return -1; +} + + +//////////////////////////////////////////////////////////// +/// Close / destroy a socket +//////////////////////////////////////////////////////////// +bool SocketHelper::Close(SocketHelper::SocketType Socket) +{ + return close(Socket) != -1; +} + + +//////////////////////////////////////////////////////////// +/// Set a socket as blocking or non-blocking +//////////////////////////////////////////////////////////// +void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block) +{ + int Status = fcntl(Socket, F_GETFL); + if (Block) + fcntl(Socket, F_SETFL, Status & ~O_NONBLOCK); + else + fcntl(Socket, F_SETFL, Status | O_NONBLOCK); +} + + +//////////////////////////////////////////////////////////// +/// Get the last socket error status +//////////////////////////////////////////////////////////// +Socket::Status SocketHelper::GetErrorStatus() +{ + switch (errno) + { + case EWOULDBLOCK : return Socket::NotReady; + case ECONNABORTED : return Socket::Disconnected; + case ECONNRESET : return Socket::Disconnected; + case ETIMEDOUT : return Socket::Disconnected; + case ENETRESET : return Socket::Disconnected; + case ENOTCONN : return Socket::Disconnected; + default : return Socket::Error; + } +} + +} // namespace sf diff --git a/Externals/SFML/src/SFML/Network/Win32/SocketHelper.cpp b/Externals/SFML/src/SFML/Network/Win32/SocketHelper.cpp new file mode 100644 index 0000000000..f3ddb0855e --- /dev/null +++ b/Externals/SFML/src/SFML/Network/Win32/SocketHelper.cpp @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// Return the value of the invalid socket +//////////////////////////////////////////////////////////// +SocketHelper::SocketType SocketHelper::InvalidSocket() +{ + return INVALID_SOCKET; +} + + +//////////////////////////////////////////////////////////// +/// Close / destroy a socket +//////////////////////////////////////////////////////////// +bool SocketHelper::Close(SocketHelper::SocketType Socket) +{ + return closesocket(Socket) != -1; +} + + +//////////////////////////////////////////////////////////// +/// Set a socket as blocking or non-blocking +//////////////////////////////////////////////////////////// +void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block) +{ + unsigned long Blocking = Block ? 0 : 1; + ioctlsocket(Socket, FIONBIO, &Blocking); +} + + +//////////////////////////////////////////////////////////// +/// Get the last socket error status +//////////////////////////////////////////////////////////// +Socket::Status SocketHelper::GetErrorStatus() +{ + switch (WSAGetLastError()) + { + case WSAEWOULDBLOCK : return Socket::NotReady; + case WSAECONNABORTED : return Socket::Disconnected; + case WSAECONNRESET : return Socket::Disconnected; + case WSAETIMEDOUT : return Socket::Disconnected; + case WSAENETRESET : return Socket::Disconnected; + case WSAENOTCONN : return Socket::Disconnected; + default : return Socket::Error; + } +} + + +//////////////////////////////////////////////////////////// +// Windows needs some initialization and cleanup to get +// sockets working properly... so let's create a class that will +// do it automatically +//////////////////////////////////////////////////////////// +struct SocketInitializer +{ + SocketInitializer() + { + WSADATA InitData; + WSAStartup(MAKEWORD(2,2), &InitData); + } + + ~SocketInitializer() + { + WSACleanup(); + } +}; + +SocketInitializer GlobalInitializer; + +} // namespace sf diff --git a/Source/Dolphin.sln b/Source/Dolphin.sln index d8b3cc9072..2a4606a6b0 100644 --- a/Source/Dolphin.sln +++ b/Source/Dolphin.sln @@ -182,6 +182,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DSPSpy", "DSPSpy\DSPSpy.vcp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "..\Externals\SOIL\SOIL.vcproj", "{C0B84DA9-FF15-4FAB-9590-17132F3C6DE4}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SFML_Network", "..\Externals\SFML\build\vc2008\sfml-network.vcproj", "{823DDC98-42D5-4A38-88CF-9DC06C788AE4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -604,6 +606,20 @@ Global {C0B84DA9-FF15-4FAB-9590-17132F3C6DE4}.Release|Win32.Build.0 = Release|Win32 {C0B84DA9-FF15-4FAB-9590-17132F3C6DE4}.Release|x64.ActiveCfg = Release|x64 {C0B84DA9-FF15-4FAB-9590-17132F3C6DE4}.Release|x64.Build.0 = Release|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Debug|Win32.ActiveCfg = Debug|Win32 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Debug|Win32.Build.0 = Debug|Win32 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Debug|x64.ActiveCfg = Debug|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Debug|x64.Build.0 = Debug|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.DebugFast|Win32.ActiveCfg = Debug|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.DebugFast|x64.ActiveCfg = Debug|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.DebugFast|x64.Build.0 = Debug|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release_JITIL|Win32.ActiveCfg = Release|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release_JITIL|x64.ActiveCfg = Release|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release_JITIL|x64.Build.0 = Release|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release|Win32.ActiveCfg = Release|Win32 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release|Win32.Build.0 = Release|Win32 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release|x64.ActiveCfg = Release|x64 + {823DDC98-42D5-4A38-88CF-9DC06C788AE4}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE