From 928077166580b6e841bdad8f244926c31b44f172 Mon Sep 17 00:00:00 2001 From: LaurentGom Date: Tue, 23 Mar 2010 09:39:43 +0000 Subject: [PATCH] FS#86 - Rewrite the sockets API Updated the API documentation of the whole network module The system headers are no longer included by the sfml-network public headers git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1475 4e206d99-4929-0410-ac5d-dfc041789085 --- CSFML/build/VC2005/csfml-network.vcproj | 34 +- CSFML/build/VC2008/csfml-network.vcproj | 30 +- CSFML/build/codeblocks/CSFML.workspace | 4 +- CSFML/build/codeblocks/csfml-network.cbp | 19 +- CSFML/include/SFML/Network.h | 7 +- CSFML/include/SFML/Network/Ftp.h | 2 +- CSFML/include/SFML/Network/Http.h | 2 +- .../Network/{Selector.h => SocketSelector.h} | 48 +- CSFML/include/SFML/Network/TcpListener.h | 97 ++++ .../SFML/Network/{SocketTCP.h => TcpSocket.h} | 120 ++-- CSFML/include/SFML/Network/Types.h | 8 +- .../SFML/Network/{SocketUDP.h => UdpSocket.h} | 79 ++- CSFML/src/SFML/Network/Ftp.cpp | 19 +- CSFML/src/SFML/Network/FtpStruct.h | 8 + CSFML/src/SFML/Network/Http.cpp | 4 +- .../{Selector.cpp => SocketSelector.cpp} | 97 +++- ...electorStruct.h => SocketSelectorStruct.h} | 28 +- CSFML/src/SFML/Network/TcpListener.cpp | 94 ++++ CSFML/src/SFML/Network/TcpListenerStruct.h | 43 ++ .../Network/{SocketTCP.cpp => TcpSocket.cpp} | 137 ++--- .../{SocketTCPStruct.h => TcpSocketStruct.h} | 14 +- .../Network/{SocketUDP.cpp => UdpSocket.cpp} | 83 ++- .../{SocketUDPStruct.h => UdpSocketStruct.h} | 14 +- CSFML/src/SFML/Network/csfml-network-d.def | 87 +-- CSFML/src/SFML/Network/csfml-network.def | 89 +-- build/codeblocks/sfml-network.cbp | 25 +- build/vc2005/sfml-network.vcproj | 34 +- build/vc2008/sfml-network.vcproj | 34 +- include/SFML/Network.hpp | 7 +- include/SFML/Network/Ftp.hpp | 332 ++++++++---- include/SFML/Network/Http.hpp | 271 +++++++--- include/SFML/Network/IpAddress.hpp | 2 +- include/SFML/Network/Packet.hpp | 251 ++++++++- include/SFML/Network/Selector.hpp | 116 ---- include/SFML/Network/Selector.inl | 97 ---- include/SFML/Network/SelectorBase.hpp | 112 ---- include/SFML/Network/Socket.hpp | 234 ++++++++ .../{SocketHelper.hpp => SocketHandle.hpp} | 47 +- include/SFML/Network/SocketSelector.hpp | 251 +++++++++ include/SFML/Network/SocketTCP.hpp | 227 -------- include/SFML/Network/SocketUDP.hpp | 228 -------- include/SFML/Network/TcpListener.hpp | 131 +++++ include/SFML/Network/TcpSocket.hpp | 271 ++++++++++ include/SFML/Network/UdpSocket.hpp | 242 +++++++++ samples/ftp/Ftp.cpp | 11 +- samples/sockets/Sockets.cpp | 40 +- samples/sockets/TCP.cpp | 124 ++--- samples/sockets/UDP.cpp | 91 ++-- samples/voip/Client.cpp | 71 ++- samples/voip/Server.cpp | 25 +- src/SFML/Network/Ftp.cpp | 138 +---- src/SFML/Network/Http.cpp | 82 +-- src/SFML/Network/IpAddress.cpp | 32 +- src/SFML/Network/Packet.cpp | 116 ++-- src/SFML/Network/Socket.cpp | 155 ++++++ src/SFML/Network/SocketImpl.hpp | 39 ++ .../{SelectorBase.cpp => SocketSelector.cpp} | 124 ++--- src/SFML/Network/SocketTCP.cpp | 511 ------------------ src/SFML/Network/SocketUDP.cpp | 433 --------------- src/SFML/Network/TcpListener.cpp | 97 ++++ src/SFML/Network/TcpSocket.cpp | 352 ++++++++++++ src/SFML/Network/UdpSocket.cpp | 256 +++++++++ .../Unix/{SocketHelper.cpp => SocketImpl.cpp} | 36 +- .../SFML/Network/Unix/SocketImpl.hpp | 59 +- .../{SocketHelper.cpp => SocketImpl.cpp} | 40 +- .../SFML/Network/Win32/SocketImpl.hpp | 57 +- 66 files changed, 3976 insertions(+), 2992 deletions(-) rename CSFML/include/SFML/Network/{Selector.h => SocketSelector.h} (65%) create mode 100644 CSFML/include/SFML/Network/TcpListener.h rename CSFML/include/SFML/Network/{SocketTCP.h => TcpSocket.h} (68%) rename CSFML/include/SFML/Network/{SocketUDP.h => UdpSocket.h} (76%) rename CSFML/src/SFML/Network/{Selector.cpp => SocketSelector.cpp} (50%) rename CSFML/src/SFML/Network/{SelectorStruct.h => SocketSelectorStruct.h} (65%) create mode 100644 CSFML/src/SFML/Network/TcpListener.cpp create mode 100644 CSFML/src/SFML/Network/TcpListenerStruct.h rename CSFML/src/SFML/Network/{SocketTCP.cpp => TcpSocket.cpp} (64%) rename CSFML/src/SFML/Network/{SocketTCPStruct.h => TcpSocketStruct.h} (84%) rename CSFML/src/SFML/Network/{SocketUDP.cpp => UdpSocket.cpp} (76%) rename CSFML/src/SFML/Network/{SocketUDPStruct.h => UdpSocketStruct.h} (84%) delete mode 100644 include/SFML/Network/Selector.hpp delete mode 100644 include/SFML/Network/Selector.inl delete mode 100644 include/SFML/Network/SelectorBase.hpp create mode 100644 include/SFML/Network/Socket.hpp rename include/SFML/Network/{SocketHelper.hpp => SocketHandle.hpp} (62%) create mode 100644 include/SFML/Network/SocketSelector.hpp delete mode 100644 include/SFML/Network/SocketTCP.hpp delete mode 100644 include/SFML/Network/SocketUDP.hpp create mode 100644 include/SFML/Network/TcpListener.hpp create mode 100644 include/SFML/Network/TcpSocket.hpp create mode 100644 include/SFML/Network/UdpSocket.hpp create mode 100644 src/SFML/Network/Socket.cpp create mode 100644 src/SFML/Network/SocketImpl.hpp rename src/SFML/Network/{SelectorBase.cpp => SocketSelector.cpp} (50%) delete mode 100644 src/SFML/Network/SocketTCP.cpp delete mode 100644 src/SFML/Network/SocketUDP.cpp create mode 100644 src/SFML/Network/TcpListener.cpp create mode 100644 src/SFML/Network/TcpSocket.cpp create mode 100644 src/SFML/Network/UdpSocket.cpp rename src/SFML/Network/Unix/{SocketHelper.cpp => SocketImpl.cpp} (77%) rename include/SFML/Network/Unix/SocketHelper.hpp => src/SFML/Network/Unix/SocketImpl.hpp (62%) rename src/SFML/Network/Win32/{SocketHelper.cpp => SocketImpl.cpp} (75%) rename include/SFML/Network/Win32/SocketHelper.hpp => src/SFML/Network/Win32/SocketImpl.hpp (63%) diff --git a/CSFML/build/VC2005/csfml-network.vcproj b/CSFML/build/VC2005/csfml-network.vcproj index 9560a393..7fcf5aa5 100644 --- a/CSFML/build/VC2005/csfml-network.vcproj +++ b/CSFML/build/VC2005/csfml-network.vcproj @@ -243,49 +243,57 @@ > - - + + + + + + diff --git a/CSFML/build/VC2008/csfml-network.vcproj b/CSFML/build/VC2008/csfml-network.vcproj index 082bf230..7e494944 100644 --- a/CSFML/build/VC2008/csfml-network.vcproj +++ b/CSFML/build/VC2008/csfml-network.vcproj @@ -242,15 +242,15 @@ > + + + + + + diff --git a/CSFML/build/codeblocks/CSFML.workspace b/CSFML/build/codeblocks/CSFML.workspace index c01077e8..7ad62338 100644 --- a/CSFML/build/codeblocks/CSFML.workspace +++ b/CSFML/build/codeblocks/CSFML.workspace @@ -1,11 +1,11 @@ - + - + diff --git a/CSFML/build/codeblocks/csfml-network.cbp b/CSFML/build/codeblocks/csfml-network.cbp index 48fd47c8..4ce9a1b2 100644 --- a/CSFML/build/codeblocks/csfml-network.cbp +++ b/CSFML/build/codeblocks/csfml-network.cbp @@ -58,11 +58,14 @@ - + + + + @@ -70,12 +73,14 @@ - - - - - - + + + + + + + + diff --git a/CSFML/include/SFML/Network.h b/CSFML/include/SFML/Network.h index 94fe3337..b2de323e 100644 --- a/CSFML/include/SFML/Network.h +++ b/CSFML/include/SFML/Network.h @@ -32,9 +32,10 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include #endif // SFML_NETWORK_H diff --git a/CSFML/include/SFML/Network/Ftp.h b/CSFML/include/SFML/Network/Ftp.h index 70bd4c80..a9596c57 100644 --- a/CSFML/include/SFML/Network/Ftp.h +++ b/CSFML/include/SFML/Network/Ftp.h @@ -383,7 +383,7 @@ CSFML_API sfFtpResponse* sfFtp_ParentDirectory(sfFtp* ftp); /// \return Server response to the request /// //////////////////////////////////////////////////////////// -CSFML_API sfFtpResponse* sfFtp_MakeDirectory(sfFtp* ftp, const char* name); +CSFML_API sfFtpResponse* sfFtp_CreateDirectory(sfFtp* ftp, const char* name); //////////////////////////////////////////////////////////// /// Remove an existing directory diff --git a/CSFML/include/SFML/Network/Http.h b/CSFML/include/SFML/Network/Http.h index 3f282843..358370ee 100644 --- a/CSFML/include/SFML/Network/Http.h +++ b/CSFML/include/SFML/Network/Http.h @@ -123,7 +123,7 @@ CSFML_API void sfHttpRequest_SetMethod(sfHttpRequest* httpRequest, sfHttpMethod /// \param URI : URI to request, local to the host /// //////////////////////////////////////////////////////////// -CSFML_API void sfHttpRequest_SetURI(sfHttpRequest* httpRequest, const char* URI); +CSFML_API void sfHttpRequest_SetUri(sfHttpRequest* httpRequest, const char* uri); //////////////////////////////////////////////////////////// /// Set the HTTP version of the request. diff --git a/CSFML/include/SFML/Network/Selector.h b/CSFML/include/SFML/Network/SocketSelector.h similarity index 65% rename from CSFML/include/SFML/Network/Selector.h rename to CSFML/include/SFML/Network/SocketSelector.h index 206f95ad..169da92a 100644 --- a/CSFML/include/SFML/Network/Selector.h +++ b/CSFML/include/SFML/Network/SocketSelector.h @@ -22,8 +22,8 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SELECTOR_H -#define SFML_SELECTOR_H +#ifndef SFML_SOCKETSELECTOR_H +#define SFML_SOCKETSELECTOR_H //////////////////////////////////////////////////////////// // Headers @@ -38,8 +38,7 @@ /// \return A new sfSelector object /// //////////////////////////////////////////////////////////// -CSFML_API sfSelectorTCP* sfSelectorTCP_Create(); -CSFML_API sfSelectorUDP* sfSelectorUDP_Create(); +CSFML_API sfSocketSelector* sfSocketSelector_Create(); //////////////////////////////////////////////////////////// /// Copy an existing selector @@ -49,8 +48,7 @@ CSFML_API sfSelectorUDP* sfSelectorUDP_Create(); /// \return Copied object /// //////////////////////////////////////////////////////////// -CSFML_API sfSelectorTCP* sfSelectorTCP_Copy(sfSelectorTCP* selector); -CSFML_API sfSelectorUDP* sfSelectorUDP_Copy(sfSelectorUDP* selector); +CSFML_API sfSocketSelector* sfSocketSelector_Copy(sfSocketSelector* selector); //////////////////////////////////////////////////////////// /// Destroy an existing selector @@ -58,8 +56,7 @@ CSFML_API sfSelectorUDP* sfSelectorUDP_Copy(sfSelectorUDP* selector); /// \param selector : Selector to delete /// //////////////////////////////////////////////////////////// -CSFML_API void sfSelectorTCP_Destroy(sfSelectorTCP* selector); -CSFML_API void sfSelectorUDP_Destroy(sfSelectorUDP* selector); +CSFML_API void sfSocketSelector_Destroy(sfSocketSelector* selector); //////////////////////////////////////////////////////////// /// Add a socket to watch to a selector @@ -68,8 +65,9 @@ CSFML_API void sfSelectorUDP_Destroy(sfSelectorUDP* selector); /// \param socket : Socket to add /// //////////////////////////////////////////////////////////// -CSFML_API void sfSelectorTCP_Add(sfSelectorTCP* selector, sfSocketTCP* socket); -CSFML_API void sfSelectorUDP_Add(sfSelectorUDP* selector, sfSocketUDP* socket); +CSFML_API void sfSocketSelector_AddTcpListener(sfSocketSelector* selector, sfTcpListener* socket); +CSFML_API void sfSocketSelector_AddTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket); +CSFML_API void sfSocketSelector_AddUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket); //////////////////////////////////////////////////////////// /// Remove a socket from a selector @@ -78,8 +76,9 @@ CSFML_API void sfSelectorUDP_Add(sfSelectorUDP* selector, sfSocketUDP* socket); /// \param socket : Socket to remove /// //////////////////////////////////////////////////////////// -CSFML_API void sfSelectorTCP_Remove(sfSelectorTCP* selector, sfSocketTCP* socket); -CSFML_API void sfSelectorUDP_Remove(sfSelectorUDP* selector, sfSocketUDP* socket); +CSFML_API void sfSocketSelector_RemoveTcpListener(sfSocketSelector* selector, sfTcpListener* socket); +CSFML_API void sfSocketSelector_RemoveTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket); +CSFML_API void sfSocketSelector_RemoveUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket); //////////////////////////////////////////////////////////// /// Remove all sockets from a selector @@ -87,36 +86,33 @@ CSFML_API void sfSelectorUDP_Remove(sfSelectorUDP* selector, sfSocketUDP* socket /// \param selector : Selector to remove the socket from /// //////////////////////////////////////////////////////////// -CSFML_API void sfSelectorTCP_Clear(sfSelectorTCP* selector); -CSFML_API void sfSelectorUDP_Clear(sfSelectorUDP* selector); +CSFML_API void sfSocketSelector_Clear(sfSocketSelector* selector); //////////////////////////////////////////////////////////// /// 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 +/// is ready, or when the given timeout is over /// /// \param selector : Selector to check /// \param timeout : Maximum time to wait, in seconds (0 to disable timeout) /// -/// \return Number of sockets ready +/// \return sfTrue if there are sockets ready, sfFalse otherwise /// //////////////////////////////////////////////////////////// -CSFML_API unsigned int sfSelectorTCP_Wait(sfSelectorTCP* selector, float timeout); -CSFML_API unsigned int sfSelectorUDP_Wait(sfSelectorUDP* selector, float timeout); +CSFML_API sfBool sfSocketSelector_Wait(sfSocketSelector* selector, float 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() +/// Test a socket to know if it is ready to receive data /// /// \param selector : Selector to check -/// \param index : Index of the socket to get +/// \param socket : Socket to test /// -/// \return The Index-th socket +/// \return sfTrue if the socket is ready to receive data /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketTCP* sfSelectorTCP_GetSocketReady(const sfSelectorTCP* selector, unsigned int index); -CSFML_API sfSocketUDP* sfSelectorUDP_GetSocketReady(const sfSelectorUDP* selector, unsigned int index); +CSFML_API sfBool sfSocketSelector_IsTcpListenerReady(const sfSocketSelector* selector, sfTcpListener* socket); +CSFML_API sfBool sfSocketSelector_IsTcpSocketReady(const sfSocketSelector* selector, sfTcpSocket* socket); +CSFML_API sfBool sfSocketSelector_IsUdpSocketReady(const sfSocketSelector* selector, sfUdpSocket* socket); -#endif // SFML_SELECTOR_H +#endif // SFML_SOCKETSELECTOR_H diff --git a/CSFML/include/SFML/Network/TcpListener.h b/CSFML/include/SFML/Network/TcpListener.h new file mode 100644 index 00000000..21ffd9c5 --- /dev/null +++ b/CSFML/include/SFML/Network/TcpListener.h @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_TCPLISTENER_H +#define SFML_TCPLISTENER_H + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +//////////////////////////////////////////////////////////// +/// Construct a new TCP socket +/// +/// \return Pointer to the new socket +/// +//////////////////////////////////////////////////////////// +CSFML_API sfTcpListener* sfTcpListener_Create(); + +//////////////////////////////////////////////////////////// +/// Destroy an existing TCP socket +/// +/// \param socket : Socket to destroy +/// +//////////////////////////////////////////////////////////// +CSFML_API void sfTcpListener_Destroy(sfTcpListener* socket); + +//////////////////////////////////////////////////////////// +/// Change the blocking state of a TCP socket. +/// The default behaviour of a socket is blocking +/// +/// \param socket : Socket to modify +/// \param blocking : Pass sfTrue to set the socket as blocking, or sfFalse for non-blocking +/// +//////////////////////////////////////////////////////////// +CSFML_API void sfTcpListener_SetBlocking(sfTcpListener* socket, sfBool blocking); + +//////////////////////////////////////////////////////////// +/// Get the blocking state of the socket +/// +/// \param socket : Socket to read +/// +/// \Return sfTrue if the socket is blocking, sfFalse otherwise +/// +//////////////////////////////////////////////////////////// +CSFML_API sfBool sfTcpListener_IsBlocking(const sfTcpListener* socket); + +//////////////////////////////////////////////////////////// +/// Listen to a specified port for incoming data or connections +/// +/// \param socket : Socket to use for listening +/// \param port : Port to listen to +/// +/// \return Socket status +/// +//////////////////////////////////////////////////////////// +CSFML_API sfSocketStatus sfTcpListener_Listen(sfTcpListener* socket, unsigned short port); + +//////////////////////////////////////////////////////////// +/// Wait for a connection (must be listening to a port). +/// This function is blocking, ie. it won't return before +/// a connection has been accepted +/// +/// \param socket : Socket to use for accepting +/// \param connected : Pointer to a socket pointer that will be filled with the connected client +/// +/// \return Socket status +/// +//////////////////////////////////////////////////////////// +CSFML_API sfSocketStatus sfTcpListener_Accept(sfTcpListener* socket, sfTcpSocket** connected); + + +#endif // SFML_TCPLISTENER_H diff --git a/CSFML/include/SFML/Network/SocketTCP.h b/CSFML/include/SFML/Network/TcpSocket.h similarity index 68% rename from CSFML/include/SFML/Network/SocketTCP.h rename to CSFML/include/SFML/Network/TcpSocket.h index 90ca03f5..75a214d8 100644 --- a/CSFML/include/SFML/Network/SocketTCP.h +++ b/CSFML/include/SFML/Network/TcpSocket.h @@ -22,8 +22,8 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETTCP_H -#define SFML_SOCKETTCP_H +#ifndef SFML_TCPSOCKET_H +#define SFML_TCPSOCKET_H //////////////////////////////////////////////////////////// // Headers @@ -40,17 +40,7 @@ /// \return Pointer to the new socket /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketTCP* sfSocketTCP_Create(); - -//////////////////////////////////////////////////////////// -/// Copy an existing TCP socket -/// -/// \param socket : Socket to copy -/// -/// \return Copied object -/// -//////////////////////////////////////////////////////////// -CSFML_API sfSocketTCP* sfSocketTCP_Copy(sfSocketTCP* socket); +CSFML_API sfTcpSocket* sfTcpSocket_Create(); //////////////////////////////////////////////////////////// /// Destroy an existing TCP socket @@ -58,7 +48,7 @@ CSFML_API sfSocketTCP* sfSocketTCP_Copy(sfSocketTCP* socket); /// \param socket : Socket to destroy /// //////////////////////////////////////////////////////////// -CSFML_API void sfSocketTCP_Destroy(sfSocketTCP* socket); +CSFML_API void sfTcpSocket_Destroy(sfTcpSocket* socket); //////////////////////////////////////////////////////////// /// Change the blocking state of a TCP socket. @@ -68,45 +58,68 @@ CSFML_API void sfSocketTCP_Destroy(sfSocketTCP* socket); /// \param blocking : Pass sfTrue to set the socket as blocking, or false for non-blocking /// //////////////////////////////////////////////////////////// -CSFML_API void sfSocketTCP_SetBlocking(sfSocketTCP* socket, sfBool blocking); +CSFML_API void sfTcpSocket_SetBlocking(sfTcpSocket* socket, sfBool blocking); + +//////////////////////////////////////////////////////////// +/// Get the blocking state of the socket +/// +/// \param socket : Socket to read +/// +/// \Return sfTrue if the socket is blocking, sfFalse otherwise +/// +//////////////////////////////////////////////////////////// +CSFML_API sfBool sfTcpSocket_IsBlocking(const sfTcpSocket* socket); + +//////////////////////////////////////////////////////////// +/// Get the port to which a socket is bound locally +/// +/// \param socket : Socket to read +/// +/// \return Port to which the socket is bound +/// +//////////////////////////////////////////////////////////// +CSFML_API unsigned short sfTcpSocket_GetLocalPort(const sfTcpSocket* socket); + +//////////////////////////////////////////////////////////// +/// Get the address of the connected peer of a socket +/// +/// \param socket : Socket to read +/// +/// \return Address of the remote peer +/// +//////////////////////////////////////////////////////////// +CSFML_API sfIpAddress sfTcpSocket_GetRemoteAddress(const sfTcpSocket* socket); + +//////////////////////////////////////////////////////////// +/// Get the port of the connected peer to which a socket is connected +/// +/// \param socket : Socket to read +/// +/// \return Remote port to which the socket is connected +/// +//////////////////////////////////////////////////////////// +CSFML_API unsigned short sfTcpSocket_GetRemotePort(const sfTcpSocket* socket); //////////////////////////////////////////////////////////// /// Connect a TCP socket to another computer on a specified port /// -/// \param socket : Socket to use for connecting -/// \param port : Port to use for transfers (warning : ports < 1024 are reserved) +/// \param socket : Socket to connect /// \param host : IP Address of the host to connect to +/// \param port : Port to use for transfers (warning : ports < 1024 are reserved) /// \param timeout : Maximum time to wait (0 to use no timeout) /// /// \return sfTrue if operation has been successful /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketTCP_Connect(sfSocketTCP* socket, unsigned short port, sfIpAddress host, float timeout); +CSFML_API sfSocketStatus sfTcpSocket_Connect(sfTcpSocket* socket, sfIpAddress host, unsigned short port, float timeout); //////////////////////////////////////////////////////////// -/// Listen to a specified port for incoming data or connections +/// Disconnect a connect from its remote peer /// -/// \param socket : Socket to use for listening -/// \param port : Port to listen to -/// -/// \return sfTrue if operation has been successful +/// \param socket : Socket to disconnect /// //////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketTCP_Listen(sfSocketTCP* socket, unsigned short port); - -//////////////////////////////////////////////////////////// -/// Wait for a connection (must be listening to a port). -/// This function is blocking, ie. it won't return before -/// a connection has been accepted -/// -/// \param socket : Socket to use for accepting -/// \param connected : Pointer to a socket pointer that will be filled with the connected client -/// \param address : Pointer to an address to fill with client infos -/// -/// \return Socket status -/// -//////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketTCP_Accept(sfSocketTCP* socket, sfSocketTCP** connected, sfIpAddress* address); +CSFML_API void sfTcpSocket_Disconnect(sfTcpSocket* socket); //////////////////////////////////////////////////////////// /// Send an array of bytes to the host (must be connected first) @@ -118,7 +131,7 @@ CSFML_API sfSocketStatus sfSocketTCP_Accept(sfSocketTCP* socket, sfSocketTCP** c /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketTCP_Send(sfSocketTCP* socket, const char* data, size_t size); +CSFML_API sfSocketStatus sfTcpSocket_Send(sfTcpSocket* socket, const char* data, size_t size); //////////////////////////////////////////////////////////// /// Receive an array of bytes from the host (must be connected first) @@ -131,7 +144,7 @@ CSFML_API sfSocketStatus sfSocketTCP_Send(sfSocketTCP* socket, const char* data, /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketTCP_Receive(sfSocketTCP* socket, char* data, size_t maxSize, size_t* sizeReceived); +CSFML_API sfSocketStatus sfTcpSocket_Receive(sfTcpSocket* socket, char* data, size_t maxSize, size_t* sizeReceived); //////////////////////////////////////////////////////////// /// Send a packet of data to the host (must be connected first) @@ -142,7 +155,7 @@ CSFML_API sfSocketStatus sfSocketTCP_Receive(sfSocketTCP* socket, char* data, si /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketTCP_SendPacket(sfSocketTCP* socket, sfPacket* packet); +CSFML_API sfSocketStatus sfTcpSocket_SendPacket(sfTcpSocket* socket, sfPacket* packet); //////////////////////////////////////////////////////////// /// Receive a packet from the host (must be connected first) @@ -153,28 +166,7 @@ CSFML_API sfSocketStatus sfSocketTCP_SendPacket(sfSocketTCP* socket, sfPacket* p /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketTCP_ReceivePacket(sfSocketTCP* socket, sfPacket* packet); - -//////////////////////////////////////////////////////////// -/// Close the socket -/// -/// \param socket : Socket to close -/// -/// \return True if the socket was successfully closed -/// -//////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketTCP_Close(sfSocketTCP* socket); - -//////////////////////////////////////////////////////////// -/// Check if a socket is in a valid state ; this function -/// can be called any time to check if the socket is OK -/// -/// \param socket : Socket to check -/// -/// \return True if the socket is valid -/// -//////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketTCP_IsValid(const sfSocketTCP* socket); +CSFML_API sfSocketStatus sfTcpSocket_ReceivePacket(sfTcpSocket* socket, sfPacket* packet); -#endif // SFML_SOCKETTCP_H +#endif // SFML_TCPSOCKET_H diff --git a/CSFML/include/SFML/Network/Types.h b/CSFML/include/SFML/Network/Types.h index 5878a626..75709310 100644 --- a/CSFML/include/SFML/Network/Types.h +++ b/CSFML/include/SFML/Network/Types.h @@ -34,10 +34,10 @@ typedef struct sfHttpRequest sfHttpRequest; typedef struct sfHttpResponse sfHttpResponse; typedef struct sfHttp sfHttp; typedef struct sfPacket sfPacket; -typedef struct sfSelectorTCP sfSelectorTCP; -typedef struct sfSelectorUDP sfSelectorUDP; -typedef struct sfSocketTCP sfSocketTCP; -typedef struct sfSocketUDP sfSocketUDP; +typedef struct sfSocketSelector sfSocketSelector; +typedef struct sfTcpListener sfTcpListener; +typedef struct sfTcpSocket sfTcpSocket; +typedef struct sfUdpSocket sfUdpSocket; #endif // SFML_NETWORK_TYPES_H diff --git a/CSFML/include/SFML/Network/SocketUDP.h b/CSFML/include/SFML/Network/UdpSocket.h similarity index 76% rename from CSFML/include/SFML/Network/SocketUDP.h rename to CSFML/include/SFML/Network/UdpSocket.h index 3c8a40d9..89a1cb2b 100644 --- a/CSFML/include/SFML/Network/SocketUDP.h +++ b/CSFML/include/SFML/Network/UdpSocket.h @@ -22,8 +22,8 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETUDP_H -#define SFML_SOCKETUDP_H +#ifndef SFML_UDPSOCKET_H +#define SFML_UDPSOCKET_H //////////////////////////////////////////////////////////// // Headers @@ -40,17 +40,7 @@ /// \return Pointer to the new socket /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketUDP* sfSocketUDP_Create(); - -//////////////////////////////////////////////////////////// -/// Copy an existing UDP socket -/// -/// \param socket : Socket to copy -/// -/// \return Copied object -/// -//////////////////////////////////////////////////////////// -CSFML_API sfSocketUDP* sfSocketUDP_Copy(sfSocketUDP* socket); +CSFML_API sfUdpSocket* sfUdpSocket_Create(); //////////////////////////////////////////////////////////// /// Destroy an existing UDP socket @@ -58,7 +48,7 @@ CSFML_API sfSocketUDP* sfSocketUDP_Copy(sfSocketUDP* socket); /// \param socket : Socket to destroy /// //////////////////////////////////////////////////////////// -CSFML_API void sfSocketUDP_Destroy(sfSocketUDP* socket); +CSFML_API void sfUdpSocket_Destroy(sfUdpSocket* socket); //////////////////////////////////////////////////////////// /// Change the blocking state of a UDP socket. @@ -68,7 +58,27 @@ CSFML_API void sfSocketUDP_Destroy(sfSocketUDP* socket); /// \param blocking : Pass sfTrue to set the socket as blocking, or false for non-blocking /// //////////////////////////////////////////////////////////// -CSFML_API void sfSocketUDP_SetBlocking(sfSocketUDP* socket, sfBool blocking); +CSFML_API void sfUdpSocket_SetBlocking(sfUdpSocket* socket, sfBool blocking); + +//////////////////////////////////////////////////////////// +/// Get the blocking state of the socket +/// +/// \param socket : Socket to read +/// +/// \Return sfTrue if the socket is blocking, sfFalse otherwise +/// +//////////////////////////////////////////////////////////// +CSFML_API sfBool sfUdpSocket_IsBlocking(const sfUdpSocket* socket); + +//////////////////////////////////////////////////////////// +/// Get the port to which a socket is bound locally +/// +/// \param socket : Socket to read +/// +/// \return Port to which the socket is bound +/// +//////////////////////////////////////////////////////////// +CSFML_API unsigned short sfUdpSocket_GetLocalPort(const sfUdpSocket* socket); //////////////////////////////////////////////////////////// /// Bind a socket to a specific port @@ -76,20 +86,18 @@ CSFML_API void sfSocketUDP_SetBlocking(sfSocketUDP* socket, sfBool blocking); /// \param socket : Socket to bind /// \param port : Port to bind the socket to /// -/// \return True if operation has been successful +/// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketUDP_Bind(sfSocketUDP* socket, unsigned short port); +CSFML_API sfSocketStatus sfUdpSocket_Bind(sfUdpSocket* socket, unsigned short port); //////////////////////////////////////////////////////////// /// Unbind a socket from its previous port, if any /// /// \param socket : Socket to unbind /// -/// \return sfTrue if operation has been successful -/// //////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketUDP_Unbind(sfSocketUDP* socket); +CSFML_API void sfUdpSocket_Unbind(sfUdpSocket* socket); //////////////////////////////////////////////////////////// /// Send an array of bytes @@ -103,7 +111,7 @@ CSFML_API sfBool sfSocketUDP_Unbind(sfSocketUDP* socket); /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketUDP_Send(sfSocketUDP* socket, const char* data, size_t size, sfIpAddress address, unsigned short port); +CSFML_API sfSocketStatus sfUdpSocket_Send(sfUdpSocket* socket, const char* data, size_t size, sfIpAddress address, unsigned short port); //////////////////////////////////////////////////////////// /// Receive an array of bytes. @@ -120,7 +128,7 @@ CSFML_API sfSocketStatus sfSocketUDP_Send(sfSocketUDP* socket, const char* data, /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketUDP_Receive(sfSocketUDP* socket, char* data, size_t maxSize, size_t* sizeReceived, sfIpAddress* address, unsigned short* port); +CSFML_API sfSocketStatus sfUdpSocket_Receive(sfUdpSocket* socket, char* data, size_t maxSize, size_t* sizeReceived, sfIpAddress* address, unsigned short* port); //////////////////////////////////////////////////////////// /// Send a packet of data @@ -133,7 +141,7 @@ CSFML_API sfSocketStatus sfSocketUDP_Receive(sfSocketUDP* socket, char* data, si /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketUDP_SendPacket(sfSocketUDP* socket, sfPacket* packet, sfIpAddress address, unsigned short port); +CSFML_API sfSocketStatus sfUdpSocket_SendPacket(sfUdpSocket* socket, sfPacket* packet, sfIpAddress address, unsigned short port); //////////////////////////////////////////////////////////// /// Receive a packet. @@ -148,28 +156,7 @@ CSFML_API sfSocketStatus sfSocketUDP_SendPacket(sfSocketUDP* socket, sfPacket* p /// \return Socket status /// //////////////////////////////////////////////////////////// -CSFML_API sfSocketStatus sfSocketUDP_ReceivePacket(sfSocketUDP* socket, sfPacket* packet, sfIpAddress* address, unsigned short* port); - -//////////////////////////////////////////////////////////// -/// Close the socket -/// -/// \param socket : Socket to close -/// -/// \return True if the socket was successfully closed -/// -//////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketUDP_Close(sfSocketUDP* socket); - -//////////////////////////////////////////////////////////// -/// Check if a socket is in a valid state ; this function -/// can be called any time to check if the socket is OK -/// -/// \param socket : Socket to check -/// -/// \return sfTrue if the socket is valid -/// -//////////////////////////////////////////////////////////// -CSFML_API sfBool sfSocketUDP_IsValid(sfSocketUDP* socket); +CSFML_API sfSocketStatus sfUdpSocket_ReceivePacket(sfUdpSocket* socket, sfPacket* packet, sfIpAddress* address, unsigned short* port); -#endif // SFML_SOCKETUDP_H +#endif // SFML_UDPSOCKET_H diff --git a/CSFML/src/SFML/Network/Ftp.cpp b/CSFML/src/SFML/Network/Ftp.cpp index 43efb128..871379fd 100644 --- a/CSFML/src/SFML/Network/Ftp.cpp +++ b/CSFML/src/SFML/Network/Ftp.cpp @@ -39,6 +39,7 @@ void sfFtpListingResponse_Destroy(sfFtpListingResponse* ftpListingResponse) delete ftpListingResponse; } + //////////////////////////////////////////////////////////// /// Convenience function to check if the response status code /// means a success @@ -48,6 +49,7 @@ sfBool sfFtpListingResponse_IsOk(const sfFtpListingResponse* ftpListingResponse) CSFML_CALL_RETURN(ftpListingResponse, IsOk(), sfFalse); } + //////////////////////////////////////////////////////////// /// Get the response status code //////////////////////////////////////////////////////////// @@ -58,6 +60,7 @@ sfFtpStatus sfFtpListingResponse_GetStatus(const sfFtpListingResponse* ftpListin return static_cast(ftpListingResponse->This.GetStatus()); } + //////////////////////////////////////////////////////////// /// Get the full message contained in the response //////////////////////////////////////////////////////////// @@ -68,14 +71,18 @@ const char* sfFtpListingResponse_GetMessage(const sfFtpListingResponse* ftpListi return ftpListingResponse->This.GetMessage().c_str(); } + //////////////////////////////////////////////////////////// /// Get the number of filenames in the listing //////////////////////////////////////////////////////////// size_t sfFtpListingResponse_GetCount(const sfFtpListingResponse* ftpListingResponse) { - CSFML_CALL_RETURN(ftpListingResponse, GetCount(), 0); + CSFML_CHECK_RETURN(ftpListingResponse, 0); + + return ftpListingResponse->This.GetFilenames().size(); } + //////////////////////////////////////////////////////////// /// Get the Index-th filename in the directory //////////////////////////////////////////////////////////// @@ -83,7 +90,7 @@ const char* sfFtpListingResponse_GetFilename(const sfFtpListingResponse* ftpList { CSFML_CHECK_RETURN(ftpListingResponse, NULL); - return ftpListingResponse->This.GetFilename(index).c_str(); + return ftpListingResponse->This.GetFilenames()[index].c_str(); } @@ -95,6 +102,7 @@ void sfFtpDirectoryResponse_Destroy(sfFtpDirectoryResponse* ftpDirectoryResponse delete ftpDirectoryResponse; } + //////////////////////////////////////////////////////////// /// Convenience function to check if the response status code /// means a success @@ -104,6 +112,7 @@ sfBool sfFtpDirectoryResponse_IsOk(const sfFtpDirectoryResponse* ftpDirectoryRes CSFML_CALL_RETURN(ftpDirectoryResponse, IsOk(), sfFalse); } + //////////////////////////////////////////////////////////// /// Get the response status code //////////////////////////////////////////////////////////// @@ -114,6 +123,7 @@ sfFtpStatus sfFtpDirectoryResponse_GetStatus(const sfFtpDirectoryResponse* ftpDi return static_cast(ftpDirectoryResponse->This.GetStatus()); } + //////////////////////////////////////////////////////////// /// Get the full message contained in the response //////////////////////////////////////////////////////////// @@ -124,6 +134,7 @@ const char* sfFtpDirectoryResponse_GetMessage(const sfFtpDirectoryResponse* ftpD return ftpDirectoryResponse->This.GetMessage().c_str(); } + //////////////////////////////////////////////////////////// /// Get the directory returned in the response //////////////////////////////////////////////////////////// @@ -299,11 +310,11 @@ sfFtpResponse* sfFtp_ParentDirectory(sfFtp* ftp) //////////////////////////////////////////////////////////// /// Create a new directory //////////////////////////////////////////////////////////// -sfFtpResponse* sfFtp_MakeDirectory(sfFtp* ftp, const char* name) +sfFtpResponse* sfFtp_CreateDirectory(sfFtp* ftp, const char* name) { CSFML_CHECK_RETURN(ftp, NULL); - return new sfFtpResponse(ftp->This.MakeDirectory(name ? name : "")); + return new sfFtpResponse(ftp->This.CreateDirectory(name ? name : "")); } diff --git a/CSFML/src/SFML/Network/FtpStruct.h b/CSFML/src/SFML/Network/FtpStruct.h index 567608ff..adcacab1 100644 --- a/CSFML/src/SFML/Network/FtpStruct.h +++ b/CSFML/src/SFML/Network/FtpStruct.h @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include //////////////////////////////////////////////////////////// @@ -78,7 +79,14 @@ struct sfFtpListingResponse { } + ~sfFtpListingResponse() + { + for (std::vector::iterator it = Filenames.begin(); it != Filenames.end(); ++it) + delete[] *it; + } + sf::Ftp::ListingResponse This; + std::vector Filenames; }; diff --git a/CSFML/src/SFML/Network/Http.cpp b/CSFML/src/SFML/Network/Http.cpp index 2d307f9b..4dd651ed 100644 --- a/CSFML/src/SFML/Network/Http.cpp +++ b/CSFML/src/SFML/Network/Http.cpp @@ -73,9 +73,9 @@ void sfHttpRequest_SetMethod(sfHttpRequest* httpRequest, sfHttpMethod method) /// Set the target URI of the request. /// This parameter is "/" by default //////////////////////////////////////////////////////////// -void sfHttpRequest_SetURI(sfHttpRequest* httpRequest, const char* URI) +void sfHttpRequest_SetUri(sfHttpRequest* httpRequest, const char* uri) { - CSFML_CALL(httpRequest, SetURI(URI ? URI : "")); + CSFML_CALL(httpRequest, SetUri(uri ? uri : "")); } diff --git a/CSFML/src/SFML/Network/Selector.cpp b/CSFML/src/SFML/Network/SocketSelector.cpp similarity index 50% rename from CSFML/src/SFML/Network/Selector.cpp rename to CSFML/src/SFML/Network/SocketSelector.cpp index a1deb6f0..6e59e61c 100644 --- a/CSFML/src/SFML/Network/Selector.cpp +++ b/CSFML/src/SFML/Network/SocketSelector.cpp @@ -25,73 +25,118 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include -#include +#include +#include +#include +#include +#include #include //////////////////////////////////////////////////////////// /// Create a new selector //////////////////////////////////////////////////////////// -sfSelectorTCP* sfSelectorTCP_Create() {return new sfSelectorTCP;} -sfSelectorUDP* sfSelectorUDP_Create() {return new sfSelectorUDP;} +sfSocketSelector* sfSocketSelector_Create() +{ + return new sfSocketSelector; +} //////////////////////////////////////////////////////////// /// Copy an existing selector //////////////////////////////////////////////////////////// -sfSelectorTCP* sfSelectorTCP_Copy(sfSelectorTCP* selector) {CSFML_CHECK_RETURN(selector, NULL); return new sfSelectorTCP(*selector);} -sfSelectorUDP* sfSelectorUDP_Copy(sfSelectorUDP* selector) {CSFML_CHECK_RETURN(selector, NULL); return new sfSelectorUDP(*selector);} +sfSocketSelector* sfSocketSelector_Copy(sfSocketSelector* selector) +{ + CSFML_CHECK_RETURN(selector, NULL); + + return new sfSocketSelector(*selector); +} //////////////////////////////////////////////////////////// /// Destroy an existing selector //////////////////////////////////////////////////////////// -void sfSelectorTCP_Destroy(sfSelectorTCP* selector) {delete selector;} -void sfSelectorUDP_Destroy(sfSelectorUDP* selector) {delete selector;} +void sfSocketSelector_Destroy(sfSocketSelector* selector) +{ + delete selector; +} //////////////////////////////////////////////////////////// /// Add a socket to watch to a selector //////////////////////////////////////////////////////////// -void sfSelectorTCP_Add(sfSelectorTCP* selector, sfSocketTCP* socket) {CSFML_CALL(selector, Add(socket->This)); selector->Sockets[socket->This] = socket;} -void sfSelectorUDP_Add(sfSelectorUDP* selector, sfSocketUDP* socket) {CSFML_CALL(selector, Add(socket->This)); selector->Sockets[socket->This] = socket;} +void sfSocketSelector_AddTcpListener(sfSocketSelector* selector, sfTcpListener* socket) +{ + CSFML_CHECK(socket); + CSFML_CALL(selector, Add(socket->This)); +} +void sfSocketSelector_AddTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket) +{ + CSFML_CHECK(socket); + CSFML_CALL(selector, Add(socket->This)); +} +void sfSocketSelector_AddUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket) +{ + CSFML_CHECK(socket); + CSFML_CALL(selector, Add(socket->This)); +} //////////////////////////////////////////////////////////// /// Remove a socket from a selector //////////////////////////////////////////////////////////// -void sfSelectorTCP_Remove(sfSelectorTCP* selector, sfSocketTCP* socket) {CSFML_CALL(selector, Remove(socket->This)); selector->Sockets.erase(socket->This);} -void sfSelectorUDP_Remove(sfSelectorUDP* selector, sfSocketUDP* socket) {CSFML_CALL(selector, Remove(socket->This)); selector->Sockets.erase(socket->This);} +void sfSocketSelector_RemoveTcpListener(sfSocketSelector* selector, sfTcpListener* socket) +{ + CSFML_CHECK(socket); + CSFML_CALL(selector, Remove(socket->This)); +} +void sfSocketSelector_RemoveTcpSocket(sfSocketSelector* selector, sfTcpSocket* socket) +{ + CSFML_CHECK(socket); + CSFML_CALL(selector, Remove(socket->This)); +} +void sfSocketSelector_RemoveUdpSocket(sfSocketSelector* selector, sfUdpSocket* socket) +{ + CSFML_CHECK(socket); + CSFML_CALL(selector, Remove(socket->This)); +} //////////////////////////////////////////////////////////// /// Remove all sockets from a selector //////////////////////////////////////////////////////////// -void sfSelectorTCP_Clear(sfSelectorTCP* selector) {CSFML_CALL(selector, Clear()); selector->Sockets.clear();} -void sfSelectorUDP_Clear(sfSelectorUDP* selector) {CSFML_CALL(selector, Clear()); selector->Sockets.clear();} +void sfSocketSelector_Clear(sfSocketSelector* selector) +{ + CSFML_CALL(selector, 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 +/// is ready, or when the given timeout is over //////////////////////////////////////////////////////////// -unsigned int sfSelectorTCP_Wait(sfSelectorTCP* selector, float timeout) {CSFML_CALL_RETURN(selector, Wait(timeout), 0);} -unsigned int sfSelectorUDP_Wait(sfSelectorUDP* selector, float timeout) {CSFML_CALL_RETURN(selector, Wait(timeout), 0);} +sfBool sfSocketSelector_Wait(sfSocketSelector* selector, float timeout) +{ + CSFML_CALL_RETURN(selector, Wait(timeout), sfFalse); +} //////////////////////////////////////////////////////////// -/// 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() +/// Test a socket to know if it is ready to receive data //////////////////////////////////////////////////////////// -sfSocketTCP* sfSelectorTCP_GetSocketReady(const sfSelectorTCP* selector, unsigned int index) +sfBool sfSocketSelector_IsTcpListenerReady(const sfSocketSelector* selector, sfTcpListener* socket) { - CSFML_CHECK_RETURN(selector, NULL); - return selector->Sockets.find(selector->This.GetSocketReady(index))->second; + CSFML_CHECK_RETURN(socket, sfFalse); + CSFML_CALL_RETURN(selector, IsReady(socket->This), sfFalse); } -sfSocketUDP* sfSelectorUDP_GetSocketReady(const sfSelectorUDP* selector, unsigned int index) +sfBool sfSocketSelector_IsTcpSocketReady(const sfSocketSelector* selector, sfTcpSocket* socket) { - CSFML_CHECK_RETURN(selector, NULL); - return selector->Sockets.find(selector->This.GetSocketReady(index))->second; + CSFML_CHECK_RETURN(socket, sfFalse); + CSFML_CALL_RETURN(selector, IsReady(socket->This), sfFalse); +} +sfBool sfSocketSelector_IsUdpSocketReady(const sfSocketSelector* selector, sfUdpSocket* socket) +{ + CSFML_CHECK_RETURN(socket, sfFalse); + CSFML_CALL_RETURN(selector, IsReady(socket->This), sfFalse); } diff --git a/CSFML/src/SFML/Network/SelectorStruct.h b/CSFML/src/SFML/Network/SocketSelectorStruct.h similarity index 65% rename from CSFML/src/SFML/Network/SelectorStruct.h rename to CSFML/src/SFML/Network/SocketSelectorStruct.h index 9ffc6e34..740aac20 100644 --- a/CSFML/src/SFML/Network/SelectorStruct.h +++ b/CSFML/src/SFML/Network/SocketSelectorStruct.h @@ -22,36 +22,22 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SELECTORSTRUCT_H -#define SFML_SELECTORSTRUCT_H +#ifndef SFML_SOCKETSELECTORSTRUCT_H +#define SFML_SOCKETSELECTORSTRUCT_H //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include -#include -#include -#include +#include //////////////////////////////////////////////////////////// -// Internal structure of SelectorTCP +// Internal structure of sfSocketSelector //////////////////////////////////////////////////////////// -struct sfSelectorTCP +struct sfSocketSelector { - sf::SelectorTCP This; - std::map Sockets; + sf::SocketSelector This; }; -//////////////////////////////////////////////////////////// -// Internal structure of sfSelectorUDP -//////////////////////////////////////////////////////////// -struct sfSelectorUDP -{ - sf::SelectorUDP This; - std::map Sockets; -}; - - -#endif // SFML_SELECTORSTRUCT_H +#endif // SFML_SOCKETSELECTORSTRUCT_H diff --git a/CSFML/src/SFML/Network/TcpListener.cpp b/CSFML/src/SFML/Network/TcpListener.cpp new file mode 100644 index 00000000..74b23507 --- /dev/null +++ b/CSFML/src/SFML/Network/TcpListener.cpp @@ -0,0 +1,94 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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 + + +//////////////////////////////////////////////////////////// +/// Construct a new TCP socket +//////////////////////////////////////////////////////////// +sfTcpListener* sfTcpListener_Create() +{ + return new sfTcpListener; +} + + +//////////////////////////////////////////////////////////// +/// Destroy an existing TCP socket +//////////////////////////////////////////////////////////// +void sfTcpListener_Destroy(sfTcpListener* socket) +{ + delete socket; +} + + +//////////////////////////////////////////////////////////// +/// Change the blocking state of a TCP socket. +/// The default behaviour of a socket is blocking +//////////////////////////////////////////////////////////// +void sfTcpListener_SetBlocking(sfTcpListener* socket, sfBool blocking) +{ + CSFML_CALL(socket, SetBlocking(blocking == sfTrue)); +} + + +//////////////////////////////////////////////////////////// +/// Get the blocking state of the socket +//////////////////////////////////////////////////////////// +sfBool sfTcpListener_IsBlocking(const sfTcpListener* socket) +{ + CSFML_CALL_RETURN(socket, IsBlocking(), sfFalse); +} + + +//////////////////////////////////////////////////////////// +/// Listen to a specified port for incoming data or connections +//////////////////////////////////////////////////////////// +sfSocketStatus sfTcpListener_Listen(sfTcpListener* socket, unsigned short port) +{ + CSFML_CHECK_RETURN(socket, sfSocketError); + + return static_cast(socket->This.Listen(port)); +} + + +//////////////////////////////////////////////////////////// +/// Wait for a connection (must be listening to a port). +/// This function is blocking, ie. it won't return before +/// a connection has been accepted +//////////////////////////////////////////////////////////// +sfSocketStatus sfTcpListener_Accept(sfTcpListener* socket, sfTcpSocket** connected) +{ + CSFML_CHECK_RETURN(socket, sfSocketError); + CSFML_CHECK_RETURN(connected, sfSocketError); + + *connected = new sfTcpSocket; + return static_cast(socket->This.Accept((*connected)->This)); +} diff --git a/CSFML/src/SFML/Network/TcpListenerStruct.h b/CSFML/src/SFML/Network/TcpListenerStruct.h new file mode 100644 index 00000000..292dadd6 --- /dev/null +++ b/CSFML/src/SFML/Network/TcpListenerStruct.h @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_TCPLISTENERSTRUCT_H +#define SFML_TCPLISTENERSTRUCT_H + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +//////////////////////////////////////////////////////////// +// Internal structure of sfTcpListener +//////////////////////////////////////////////////////////// +struct sfTcpListener +{ + sf::TcpListener This; +}; + + +#endif // SFML_TCPLISTENERSTRUCT_H diff --git a/CSFML/src/SFML/Network/SocketTCP.cpp b/CSFML/src/SFML/Network/TcpSocket.cpp similarity index 64% rename from CSFML/src/SFML/Network/SocketTCP.cpp rename to CSFML/src/SFML/Network/TcpSocket.cpp index edd8d44b..5154f230 100644 --- a/CSFML/src/SFML/Network/SocketTCP.cpp +++ b/CSFML/src/SFML/Network/TcpSocket.cpp @@ -25,8 +25,8 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include -#include +#include +#include #include #include #include @@ -36,33 +36,18 @@ //////////////////////////////////////////////////////////// /// Construct a new TCP socket //////////////////////////////////////////////////////////// -sfSocketTCP* sfSocketTCP_Create() +sfTcpSocket* sfTcpSocket_Create() { - return new sfSocketTCP; -} - - -//////////////////////////////////////////////////////////// -/// Copy an existing TCP socket -//////////////////////////////////////////////////////////// -sfSocketTCP* sfSocketTCP_Copy(sfSocketTCP* socket) -{ - CSFML_CHECK_RETURN(socket, NULL); - - return new sfSocketTCP(*socket); + return new sfTcpSocket; } //////////////////////////////////////////////////////////// /// Destroy an existing TCP socket //////////////////////////////////////////////////////////// -void sfSocketTCP_Destroy(sfSocketTCP* socket) +void sfTcpSocket_Destroy(sfTcpSocket* socket) { - if (socket) - { - socket->This.Close(); - delete socket; - } + delete socket; } @@ -70,67 +55,80 @@ void sfSocketTCP_Destroy(sfSocketTCP* socket) /// Change the blocking state of a TCP socket. /// The default behaviour of a socket is blocking //////////////////////////////////////////////////////////// -void sfSocketTCP_SetBlocking(sfSocketTCP* socket, sfBool blocking) +void sfTcpSocket_SetBlocking(sfTcpSocket* socket, sfBool blocking) { CSFML_CALL(socket, SetBlocking(blocking == sfTrue)); } +//////////////////////////////////////////////////////////// +/// Get the blocking state of the socket +//////////////////////////////////////////////////////////// +sfBool sfTcpSocket_IsBlocking(const sfTcpSocket* socket) +{ + CSFML_CALL_RETURN(socket, IsBlocking(), sfFalse); +} + + +//////////////////////////////////////////////////////////// +/// Get the port to which a socket is bound locally +//////////////////////////////////////////////////////////// +unsigned short sfTcpSocket_GetLocalPort(const sfTcpSocket* socket) +{ + CSFML_CALL_RETURN(socket, GetLocalPort(), 0); +} + + +//////////////////////////////////////////////////////////// +/// Get the address of the connected peer of a socket +//////////////////////////////////////////////////////////// +sfIpAddress sfTcpSocket_GetRemoteAddress(const sfTcpSocket* socket) +{ + sfIpAddress result; + CSFML_CHECK_RETURN(socket, result); + + sf::IpAddress address = socket->This.GetRemoteAddress(); + strncpy(result.Address, address.ToString().c_str(), 16); + + return result; +} + + +//////////////////////////////////////////////////////////// +/// Get the port of the connected peer to which a socket is connected +//////////////////////////////////////////////////////////// +unsigned short sfTcpSocket_GetRemotePort(const sfTcpSocket* socket) +{ + CSFML_CALL_RETURN(socket, GetRemotePort(), 0); +} + + //////////////////////////////////////////////////////////// /// Connect a TCP socket to another computer on a specified port //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketTCP_Connect(sfSocketTCP* socket, unsigned short port, sfIpAddress host, float timeout) +sfSocketStatus sfTcpSocket_Connect(sfTcpSocket* socket, sfIpAddress host, unsigned short port, float timeout) { sf::IpAddress address(host.Address); CSFML_CHECK_RETURN(socket, sfSocketError); - return static_cast(socket->This.Connect(port, address, timeout)); + return static_cast(socket->This.Connect(address, port, timeout)); } //////////////////////////////////////////////////////////// -/// Listen to a specified port for incoming data or connections +/// Disconnect a connect from its remote peer //////////////////////////////////////////////////////////// -sfBool sfSocketTCP_Listen(sfSocketTCP* socket, unsigned short port) +void sfTcpSocket_Disconnect(sfTcpSocket* socket) { - CSFML_CALL_RETURN(socket, Listen(port), sfFalse); -} - - -//////////////////////////////////////////////////////////// -/// Wait for a connection (must be listening to a port). -/// This function is blocking, ie. it won't return before -/// a connection has been accepted -//////////////////////////////////////////////////////////// -sfSocketStatus sfSocketTCP_Accept(sfSocketTCP* socket, sfSocketTCP** connected, sfIpAddress* address) -{ - CSFML_CHECK_RETURN(socket, sfSocketError); - CSFML_CHECK_RETURN(connected, sfSocketError); - - // Call SFML internal function - sf::IpAddress clientAddress; - sf::SocketTCP client; - sf::Socket::Status status = socket->This.Accept(client, &clientAddress); - if (status != sf::Socket::Done) - return static_cast(status); - - // Convert the client socket returned - *connected = sfSocketTCP_Create(); - (*connected)->This = client; - - // Convert the address if needed - if (address) - strncpy(address->Address, clientAddress.ToString().c_str(), 16); - - return sfSocketDone; + CSFML_CALL(socket, Disconnect()); } //////////////////////////////////////////////////////////// /// Send an array of bytes to the host (must be connected first) //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketTCP_Send(sfSocketTCP* socket, const char* data, size_t size) +sfSocketStatus sfTcpSocket_Send(sfTcpSocket* socket, const char* data, size_t size) { CSFML_CHECK_RETURN(socket, sfSocketError); @@ -141,7 +139,7 @@ sfSocketStatus sfSocketTCP_Send(sfSocketTCP* socket, const char* data, size_t si //////////////////////////////////////////////////////////// /// Receive an array of bytes from the host (must be connected first) //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketTCP_Receive(sfSocketTCP* socket, char* data, size_t maxSize, size_t* sizeReceived) +sfSocketStatus sfTcpSocket_Receive(sfTcpSocket* socket, char* data, size_t maxSize, size_t* sizeReceived) { CSFML_CHECK_RETURN(socket, sfSocketError); @@ -160,7 +158,7 @@ sfSocketStatus sfSocketTCP_Receive(sfSocketTCP* socket, char* data, size_t maxSi //////////////////////////////////////////////////////////// /// Send a packet of data to the host (must be connected first) //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketTCP_SendPacket(sfSocketTCP* socket, sfPacket* packet) +sfSocketStatus sfTcpSocket_SendPacket(sfTcpSocket* socket, sfPacket* packet) { CSFML_CHECK_RETURN(socket, sfSocketError); CSFML_CHECK_RETURN(packet, sfSocketError); @@ -172,29 +170,10 @@ sfSocketStatus sfSocketTCP_SendPacket(sfSocketTCP* socket, sfPacket* packet) //////////////////////////////////////////////////////////// /// Receive a packet from the host (must be connected first) //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketTCP_ReceivePacket(sfSocketTCP* socket, sfPacket* packet) +sfSocketStatus sfTcpSocket_ReceivePacket(sfTcpSocket* socket, sfPacket* packet) { CSFML_CHECK_RETURN(socket, sfSocketError); CSFML_CHECK_RETURN(packet, sfSocketError); return static_cast(socket->This.Receive(packet->This)); } - - -//////////////////////////////////////////////////////////// -/// Close the socket -//////////////////////////////////////////////////////////// -sfBool sfSocketTCP_Close(sfSocketTCP* socket) -{ - CSFML_CALL_RETURN(socket, Close(), sfFalse); -} - - -//////////////////////////////////////////////////////////// -/// Check if a socket is in a valid state ; this function -/// can be called any time to check if the socket is OK -//////////////////////////////////////////////////////////// -sfBool sfSocketTCP_IsValid(const sfSocketTCP* socket) -{ - CSFML_CALL_RETURN(socket, IsValid(), sfFalse); -} diff --git a/CSFML/src/SFML/Network/SocketTCPStruct.h b/CSFML/src/SFML/Network/TcpSocketStruct.h similarity index 84% rename from CSFML/src/SFML/Network/SocketTCPStruct.h rename to CSFML/src/SFML/Network/TcpSocketStruct.h index 9577f611..f3f434bf 100644 --- a/CSFML/src/SFML/Network/SocketTCPStruct.h +++ b/CSFML/src/SFML/Network/TcpSocketStruct.h @@ -22,22 +22,22 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETTCPSTRUCT_H -#define SFML_SOCKETTCPSTRUCT_H +#ifndef SFML_TCPSOCKETSTRUCT_H +#define SFML_TCPSOCKETSTRUCT_H //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include //////////////////////////////////////////////////////////// -// Internal structure of sfSocketTCP +// Internal structure of sfTcpSocket //////////////////////////////////////////////////////////// -struct sfSocketTCP +struct sfTcpSocket { - sf::SocketTCP This; + sf::TcpSocket This; }; -#endif // SFML_SOCKETTCPSTRUCT_H +#endif // SFML_TCPSOCKETSTRUCT_H diff --git a/CSFML/src/SFML/Network/SocketUDP.cpp b/CSFML/src/SFML/Network/UdpSocket.cpp similarity index 76% rename from CSFML/src/SFML/Network/SocketUDP.cpp rename to CSFML/src/SFML/Network/UdpSocket.cpp index 21665f3b..fe163a72 100644 --- a/CSFML/src/SFML/Network/SocketUDP.cpp +++ b/CSFML/src/SFML/Network/UdpSocket.cpp @@ -25,8 +25,8 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include -#include +#include +#include #include #include #include @@ -36,33 +36,18 @@ //////////////////////////////////////////////////////////// /// Construct a new UDP socket //////////////////////////////////////////////////////////// -sfSocketUDP* sfSocketUDP_Create() +sfUdpSocket* sfUdpSocket_Create() { - return new sfSocketUDP; -} - - -//////////////////////////////////////////////////////////// -/// Copy an existing UDP socket -//////////////////////////////////////////////////////////// -sfSocketUDP* sfSocketUDP_Copy(sfSocketUDP* socket) -{ - CSFML_CHECK_RETURN(socket, NULL); - - return new sfSocketUDP(*socket); + return new sfUdpSocket; } //////////////////////////////////////////////////////////// /// Destroy an existing UDP socket //////////////////////////////////////////////////////////// -void sfSocketUDP_Destroy(sfSocketUDP* socket) +void sfUdpSocket_Destroy(sfUdpSocket* socket) { - if (socket) - { - socket->This.Close(); - delete socket; - } + delete socket; } @@ -70,34 +55,53 @@ void sfSocketUDP_Destroy(sfSocketUDP* socket) /// Change the blocking state of a UDP socket. /// The default behaviour of a socket is blocking //////////////////////////////////////////////////////////// -void sfSocketUDP_SetBlocking(sfSocketUDP* socket, sfBool blocking) +void sfUdpSocket_SetBlocking(sfUdpSocket* socket, sfBool blocking) { CSFML_CALL(socket, SetBlocking(blocking == sfTrue)); } +//////////////////////////////////////////////////////////// +/// Get the blocking state of the socket +//////////////////////////////////////////////////////////// +sfBool sfUdpSocket_IsBlocking(const sfUdpSocket* socket) +{ + CSFML_CALL_RETURN(socket, IsBlocking(), sfFalse); +} + + +//////////////////////////////////////////////////////////// +/// Get the port to which the socket is bound locally +//////////////////////////////////////////////////////////// +unsigned short sfUdpSocket_GetLocalPort(const sfUdpSocket* socket) +{ + CSFML_CALL_RETURN(socket, GetLocalPort(), 0); +} + //////////////////////////////////////////////////////////// /// Bind a socket to a specific port //////////////////////////////////////////////////////////// -sfBool sfSocketUDP_Bind(sfSocketUDP* socket, unsigned short port) +sfSocketStatus sfUdpSocket_Bind(sfUdpSocket* socket, unsigned short port) { - CSFML_CALL_RETURN(socket, Bind(port), sfFalse); + CSFML_CHECK_RETURN(socket, sfSocketError); + + return static_cast(socket->This.Bind(port)); } //////////////////////////////////////////////////////////// /// Unbind a socket from its previous port, if any //////////////////////////////////////////////////////////// -sfBool sfSocketUDP_Unbind(sfSocketUDP* socket) +void sfUdpSocket_Unbind(sfUdpSocket* socket) { - CSFML_CALL_RETURN(socket, Unbind(), sfFalse); + CSFML_CALL(socket, Unbind()); } //////////////////////////////////////////////////////////// /// Send an array of bytes //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketUDP_Send(sfSocketUDP* socket, const char* data, size_t size, sfIpAddress address, unsigned short port) +sfSocketStatus sfUdpSocket_Send(sfUdpSocket* socket, const char* data, size_t size, sfIpAddress address, unsigned short port) { CSFML_CHECK_RETURN(socket, sfSocketError) @@ -113,7 +117,7 @@ sfSocketStatus sfSocketUDP_Send(sfSocketUDP* socket, const char* data, size_t si /// This function is blocking, ie. it won't return before some /// bytes have been received //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketUDP_Receive(sfSocketUDP* socket, char* data, size_t maxSize, size_t* sizeReceived, sfIpAddress* address, unsigned short* port) +sfSocketStatus sfUdpSocket_Receive(sfUdpSocket* socket, char* data, size_t maxSize, size_t* sizeReceived, sfIpAddress* address, unsigned short* port) { CSFML_CHECK_RETURN(socket, sfSocketError); @@ -142,7 +146,7 @@ sfSocketStatus sfSocketUDP_Receive(sfSocketUDP* socket, char* data, size_t maxSi //////////////////////////////////////////////////////////// /// Send a packet of data //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketUDP_SendPacket(sfSocketUDP* socket, sfPacket* packet, sfIpAddress address, unsigned short port) +sfSocketStatus sfUdpSocket_SendPacket(sfUdpSocket* socket, sfPacket* packet, sfIpAddress address, unsigned short port) { CSFML_CHECK_RETURN(socket, sfSocketError); CSFML_CHECK_RETURN(packet, sfSocketError); @@ -159,7 +163,7 @@ sfSocketStatus sfSocketUDP_SendPacket(sfSocketUDP* socket, sfPacket* packet, sfI /// This function is blocking, ie. it won't return before a /// packet is received //////////////////////////////////////////////////////////// -sfSocketStatus sfSocketUDP_ReceivePacket(sfSocketUDP* socket, sfPacket* packet, sfIpAddress* address, unsigned short* port) +sfSocketStatus sfUdpSocket_ReceivePacket(sfUdpSocket* socket, sfPacket* packet, sfIpAddress* address, unsigned short* port) { CSFML_CHECK_RETURN(socket, sfSocketError); CSFML_CHECK_RETURN(packet, sfSocketError); @@ -178,22 +182,3 @@ sfSocketStatus sfSocketUDP_ReceivePacket(sfSocketUDP* socket, sfPacket* packet, return sfSocketDone; } - - -//////////////////////////////////////////////////////////// -/// Close the socket -//////////////////////////////////////////////////////////// -sfBool sfSocketUDP_Close(sfSocketUDP* socket) -{ - CSFML_CALL_RETURN(socket, Close(), sfFalse); -} - - -//////////////////////////////////////////////////////////// -/// Check if a socket is in a valid state ; this function -/// can be called any time to check if the socket is OK -//////////////////////////////////////////////////////////// -sfBool sfSocketUDP_IsValid(const sfSocketUDP* socket) -{ - CSFML_CALL_RETURN(socket, IsValid(), sfFalse); -} diff --git a/CSFML/src/SFML/Network/SocketUDPStruct.h b/CSFML/src/SFML/Network/UdpSocketStruct.h similarity index 84% rename from CSFML/src/SFML/Network/SocketUDPStruct.h rename to CSFML/src/SFML/Network/UdpSocketStruct.h index c7a974f1..40833eff 100644 --- a/CSFML/src/SFML/Network/SocketUDPStruct.h +++ b/CSFML/src/SFML/Network/UdpSocketStruct.h @@ -22,22 +22,22 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETUDPSTRUCT_H -#define SFML_SOCKETUDPSTRUCT_H +#ifndef SFML_UDPSOCKETSTRUCT_H +#define SFML_UDPSOCKETSTRUCT_H //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include //////////////////////////////////////////////////////////// -// Internal structure of sfSocketUDP +// Internal structure of sfUdpSocket //////////////////////////////////////////////////////////// -struct sfSocketUDP +struct sfUdpSocket { - sf::SocketUDP This; + sf::UdpSocket This; }; -#endif // SFML_SOCKETUDPSTRUCT_H +#endif // SFML_UDPSOCKETSTRUCT_H diff --git a/CSFML/src/SFML/Network/csfml-network-d.def b/CSFML/src/SFML/Network/csfml-network-d.def index a0e5e2f5..817409b4 100644 --- a/CSFML/src/SFML/Network/csfml-network-d.def +++ b/CSFML/src/SFML/Network/csfml-network-d.def @@ -26,7 +26,7 @@ EXPORTS sfFtp_GetDirectoryListing sfFtp_ChangeDirectory sfFtp_ParentDirectory - sfFtp_MakeDirectory + sfFtp_CreateDirectory sfFtp_DeleteDirectory sfFtp_RenameFile sfFtp_DeleteFile @@ -36,7 +36,7 @@ EXPORTS sfHttpRequest_Destroy sfHttpRequest_SetField sfHttpRequest_SetMethod - sfHttpRequest_SetURI + sfHttpRequest_SetUri sfHttpRequest_SetHttpVersion sfHttpRequest_SetBody sfHttpResponse_Destroy @@ -58,29 +58,36 @@ EXPORTS sfIpAddress_GetPublicAddress sfIpAddress_LocalHost sfIpAddress_None - sfSocketTCP_Create - sfSocketTCP_Destroy - sfSocketTCP_SetBlocking - sfSocketTCP_Connect - sfSocketTCP_Listen - sfSocketTCP_Accept - sfSocketTCP_Send - sfSocketTCP_Receive - sfSocketTCP_SendPacket - sfSocketTCP_ReceivePacket - sfSocketTCP_Close - sfSocketTCP_IsValid - sfSocketUDP_Create - sfSocketUDP_Destroy - sfSocketUDP_SetBlocking - sfSocketUDP_Bind - sfSocketUDP_Unbind - sfSocketUDP_Send - sfSocketUDP_Receive - sfSocketUDP_SendPacket - sfSocketUDP_ReceivePacket - sfSocketUDP_Close - sfSocketUDP_IsValid + sfTcpListener_Create + sfTcpListener_Destroy + sfTcpListener_SetBlocking + sfTcpListener_IsBlocking + sfTcpListener_Listen + sfTcpListener_Accept + sfTcpSocket_Create + sfTcpSocket_Destroy + sfTcpSocket_SetBlocking + sfTcpSocket_IsBlocking + sfTcpSocket_GetLocalPort + sfTcpSocket_GetRemoteAddress + sfTcpSocket_GetRemotePort + sfTcpSocket_Connect + sfTcpSocket_Disconnect + sfTcpSocket_Send + sfTcpSocket_Receive + sfTcpSocket_SendPacket + sfTcpSocket_ReceivePacket + sfUdpSocket_Create + sfUdpSocket_Destroy + sfUdpSocket_SetBlocking + sfUdpSocket_IsBlocking + sfUdpSocket_GetLocalPort + sfUdpSocket_Bind + sfUdpSocket_Unbind + sfUdpSocket_Send + sfUdpSocket_Receive + sfUdpSocket_SendPacket + sfUdpSocket_ReceivePacket sfPacket_Create sfPacket_Copy sfPacket_Destroy @@ -112,19 +119,17 @@ EXPORTS sfPacket_WriteDouble sfPacket_WriteString sfPacket_WriteWideString - sfSelectorTCP_Create - sfSelectorTCP_Copy - sfSelectorTCP_Destroy - sfSelectorTCP_Add - sfSelectorTCP_Remove - sfSelectorTCP_Clear - sfSelectorTCP_Wait - sfSelectorTCP_GetSocketReady - sfSelectorUDP_Create - sfSelectorUDP_Copy - sfSelectorUDP_Destroy - sfSelectorUDP_Add - sfSelectorUDP_Remove - sfSelectorUDP_Clear - sfSelectorUDP_Wait - sfSelectorUDP_GetSocketReady + sfSocketSelector_Create + sfSocketSelector_Copy + sfSocketSelector_Destroy + sfSocketSelector_AddTcpListener + sfSocketSelector_AddTcpSocket + sfSocketSelector_AddUdpSocket + sfSocketSelector_RemoveTcpListener + sfSocketSelector_RemoveTcpSocket + sfSocketSelector_RemoveUdpSocket + sfSocketSelector_Clear + sfSocketSelector_Wait + sfSocketSelector_IsTcpListenerReady + sfSocketSelector_IsTcpSocketReady + sfSocketSelector_IsUdpSocketReady diff --git a/CSFML/src/SFML/Network/csfml-network.def b/CSFML/src/SFML/Network/csfml-network.def index b0bf894d..aa8c639a 100644 --- a/CSFML/src/SFML/Network/csfml-network.def +++ b/CSFML/src/SFML/Network/csfml-network.def @@ -26,7 +26,7 @@ EXPORTS sfFtp_GetDirectoryListing sfFtp_ChangeDirectory sfFtp_ParentDirectory - sfFtp_MakeDirectory + sfFtp_CreateDirectory sfFtp_DeleteDirectory sfFtp_RenameFile sfFtp_DeleteFile @@ -36,7 +36,7 @@ EXPORTS sfHttpRequest_Destroy sfHttpRequest_SetField sfHttpRequest_SetMethod - sfHttpRequest_SetURI + sfHttpRequest_SetUri sfHttpRequest_SetHttpVersion sfHttpRequest_SetBody sfHttpResponse_Destroy @@ -58,31 +58,36 @@ EXPORTS sfIpAddress_GetPublicAddress sfIpAddress_LocalHost sfIpAddress_None - sfSocketTCP_Create - sfSocketTCP_Copy - sfSocketTCP_Destroy - sfSocketTCP_SetBlocking - sfSocketTCP_Connect - sfSocketTCP_Listen - sfSocketTCP_Accept - sfSocketTCP_Send - sfSocketTCP_Receive - sfSocketTCP_SendPacket - sfSocketTCP_ReceivePacket - sfSocketTCP_Close - sfSocketTCP_IsValid - sfSocketUDP_Create - sfSocketUDP_Copy - sfSocketUDP_Destroy - sfSocketUDP_SetBlocking - sfSocketUDP_Bind - sfSocketUDP_Unbind - sfSocketUDP_Send - sfSocketUDP_Receive - sfSocketUDP_SendPacket - sfSocketUDP_ReceivePacket - sfSocketUDP_Close - sfSocketUDP_IsValid + sfTcpListener_Create + sfTcpListener_Destroy + sfTcpListener_SetBlocking + sfTcpListener_IsBlocking + sfTcpListener_Listen + sfTcpListener_Accept + sfTcpSocket_Create + sfTcpSocket_Destroy + sfTcpSocket_SetBlocking + sfTcpSocket_IsBlocking + sfTcpSocket_GetLocalPort + sfTcpSocket_GetRemoteAddress + sfTcpSocket_GetRemotePort + sfTcpSocket_Connect + sfTcpSocket_Disconnect + sfTcpSocket_Send + sfTcpSocket_Receive + sfTcpSocket_SendPacket + sfTcpSocket_ReceivePacket + sfUdpSocket_Create + sfUdpSocket_Destroy + sfUdpSocket_SetBlocking + sfUdpSocket_IsBlocking + sfUdpSocket_GetLocalPort + sfUdpSocket_Bind + sfUdpSocket_Unbind + sfUdpSocket_Send + sfUdpSocket_Receive + sfUdpSocket_SendPacket + sfUdpSocket_ReceivePacket sfPacket_Create sfPacket_Copy sfPacket_Destroy @@ -114,19 +119,17 @@ EXPORTS sfPacket_WriteDouble sfPacket_WriteString sfPacket_WriteWideString - sfSelectorTCP_Create - sfSelectorTCP_Copy - sfSelectorTCP_Destroy - sfSelectorTCP_Add - sfSelectorTCP_Remove - sfSelectorTCP_Clear - sfSelectorTCP_Wait - sfSelectorTCP_GetSocketReady - sfSelectorUDP_Create - sfSelectorUDP_Copy - sfSelectorUDP_Destroy - sfSelectorUDP_Add - sfSelectorUDP_Remove - sfSelectorUDP_Clear - sfSelectorUDP_Wait - sfSelectorUDP_GetSocketReady + sfSocketSelector_Create + sfSocketSelector_Copy + sfSocketSelector_Destroy + sfSocketSelector_AddTcpListener + sfSocketSelector_AddTcpSocket + sfSocketSelector_AddUdpSocket + sfSocketSelector_RemoveTcpListener + sfSocketSelector_RemoveTcpSocket + sfSocketSelector_RemoveUdpSocket + sfSocketSelector_Clear + sfSocketSelector_Wait + sfSocketSelector_IsTcpListenerReady + sfSocketSelector_IsTcpSocketReady + sfSocketSelector_IsUdpSocketReady diff --git a/build/codeblocks/sfml-network.cbp b/build/codeblocks/sfml-network.cbp index 31d8a831..d33bbf72 100644 --- a/build/codeblocks/sfml-network.cbp +++ b/build/codeblocks/sfml-network.cbp @@ -116,21 +116,24 @@ - - - - - - - + + + + + + - - - - + + + + + + + + diff --git a/build/vc2005/sfml-network.vcproj b/build/vc2005/sfml-network.vcproj index 55edf761..5fbe4313 100644 --- a/build/vc2005/sfml-network.vcproj +++ b/build/vc2005/sfml-network.vcproj @@ -344,11 +344,11 @@ Name="Win32" > @@ -385,39 +385,51 @@ > + + + + + + diff --git a/build/vc2008/sfml-network.vcproj b/build/vc2008/sfml-network.vcproj index 8073a42a..2aaa323b 100644 --- a/build/vc2008/sfml-network.vcproj +++ b/build/vc2008/sfml-network.vcproj @@ -343,11 +343,11 @@ Name="Win32" > @@ -384,39 +384,51 @@ > + + + + + + diff --git a/include/SFML/Network.hpp b/include/SFML/Network.hpp index 77115f68..19696ae7 100644 --- a/include/SFML/Network.hpp +++ b/include/SFML/Network.hpp @@ -34,9 +34,10 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include #endif // SFML_NETWORK_HPP diff --git a/include/SFML/Network/Ftp.hpp b/include/SFML/Network/Ftp.hpp index be059f3e..c30a16bb 100644 --- a/include/SFML/Network/Ftp.hpp +++ b/include/SFML/Network/Ftp.hpp @@ -29,7 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include #include #include @@ -39,17 +39,16 @@ 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 +/// \li A FTP client +/// //////////////////////////////////////////////////////////// class SFML_API Ftp : NonCopyable { public : //////////////////////////////////////////////////////////// - /// Enumeration of transfer modes + /// \brief Enumeration of transfer modes + /// //////////////////////////////////////////////////////////// enum TransferMode { @@ -59,17 +58,16 @@ public : }; //////////////////////////////////////////////////////////// - /// This class wraps a FTP response, which is basically : - /// - a status code - /// - a message + /// \brief Define a FTP response + /// //////////////////////////////////////////////////////////// class SFML_API Response { public : //////////////////////////////////////////////////////////// - /// Enumerate all the valid status codes returned in - /// a FTP response + /// \brief Status codes possibly returned by a FTP response + /// //////////////////////////////////////////////////////////// enum Status { @@ -134,25 +132,30 @@ public : }; //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor /// - /// \param code : Response status code - /// \param message : Response message + /// This constructor is used by the FTP client to build + /// the response. + /// + /// \param code Response status code + /// \param message Response message /// //////////////////////////////////////////////////////////// Response(Status code = InvalidResponse, const std::string& message = ""); //////////////////////////////////////////////////////////// - /// Convenience function to check if the response status code - /// means a success + /// \brief Check if the status code means a success /// - /// \return True if status is success (code < 400) + /// This function is defined for convenience, it is + /// equivalent to testing if the status code is < 400. + /// + /// \return True if the status is a success, false if it is a failure /// //////////////////////////////////////////////////////////// bool IsOk() const; //////////////////////////////////////////////////////////// - /// Get the response status code + /// \brief Get the status code of the response /// /// \return Status code /// @@ -160,7 +163,7 @@ public : Status GetStatus() const; //////////////////////////////////////////////////////////// - /// Get the full message contained in the response + /// \brief Get the full message contained in the response /// /// \return The response message /// @@ -177,22 +180,23 @@ public : }; //////////////////////////////////////////////////////////// - /// Specialization of FTP response returning a directory + /// \brief Specialization of FTP response returning a directory + /// //////////////////////////////////////////////////////////// class SFML_API DirectoryResponse : public Response { public : //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor /// - /// \param response : Source response + /// \param response Source response /// //////////////////////////////////////////////////////////// - DirectoryResponse(Response response); + DirectoryResponse(const Response& response); //////////////////////////////////////////////////////////// - /// Get the directory returned in the response + /// \brief Get the directory returned in the response /// /// \return Directory name /// @@ -209,38 +213,29 @@ public : //////////////////////////////////////////////////////////// - /// Specialization of FTP response returning a filename lisiting + /// \brief Specialization of FTP response returning a + /// filename lisiting //////////////////////////////////////////////////////////// class SFML_API ListingResponse : public Response { public : //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor /// - /// \param response : Source response - /// \param data : Data containing the raw listing + /// \param response Source response + /// \param data Data containing the raw listing /// //////////////////////////////////////////////////////////// - ListingResponse(Response response, const std::vector& data); + ListingResponse(const Response& response, const std::vector& data); //////////////////////////////////////////////////////////// - /// Get the number of filenames in the listing + /// \brief Return the array of filenames /// - /// \return Total number of filenames + /// \return Array containing the requested 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; + const std::vector& GetFilenames() const; private : @@ -252,25 +247,52 @@ public : //////////////////////////////////////////////////////////// - /// Destructor -- close the connection with the server + /// \brief Destructor + /// + /// Automatically closes the connection with the server if + /// it is still opened. /// //////////////////////////////////////////////////////////// ~Ftp(); //////////////////////////////////////////////////////////// - /// Connect to the specified FTP server + /// \brief 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) + /// The port has a default value of 21, which is the standard + /// port used by the FTP protocol. You shouldn't use a different + /// value, unless you really know what you do. + /// This function tries to connect to the server so it may take + /// a while to complete, especially if the server is not + /// reachable. To avoid blocking your application for too long, + /// you can use a timeout. The default value, 0, means that the + /// system timeout will be used (which is usually pretty long). + /// + /// \param server Name or address of the FTP server to connect to + /// \param port Port used for the connection + /// \param timeout Maximum time to wait, in seconds /// /// \return Server response to the request /// + /// \see Disconnect + /// //////////////////////////////////////////////////////////// Response Connect(const IpAddress& server, unsigned short port = 21, float timeout = 0.f); //////////////////////////////////////////////////////////// - /// Log in using anonymous account + /// \brief Close the connection with the server + /// + /// \return Server response to the request + /// + /// \see Connect + /// + //////////////////////////////////////////////////////////// + Response Disconnect(); + + //////////////////////////////////////////////////////////// + /// \brief Log in using an anonymous account + /// + /// Logging in is mandatory after connecting to the server. + /// Users that are not logged in cannot perform any operation. /// /// \return Server response to the request /// @@ -278,10 +300,13 @@ public : Response Login(); //////////////////////////////////////////////////////////// - /// Log in using a username and a password + /// \brief Log in using a username and a password /// - /// \param name : User name - /// \param password : Password + /// Logging in is mandatory after connecting to the server. + /// Users that are not logged in cannot perform any operation. + /// + /// \param name User name + /// \param password Password /// /// \return Server response to the request /// @@ -289,15 +314,10 @@ public : Response Login(const std::string& name, const std::string& password); //////////////////////////////////////////////////////////// - /// Close the connection with FTP server + /// \brief Send a null command to keep the connection alive /// - /// \return Server response to the request - /// - //////////////////////////////////////////////////////////// - Response Disconnect(); - - //////////////////////////////////////////////////////////// - /// Send a null command just to prevent from being disconnected + /// This command is useful because the server may close the + /// connection automatically if no command is sent. /// /// \return Server response to the request /// @@ -305,31 +325,46 @@ public : Response KeepAlive(); //////////////////////////////////////////////////////////// - /// Get the current working directory + /// \brief Get the current working directory + /// + /// The working directory is the root path for subsequent + /// operations involving directories and/or filenames. /// /// \return Server response to the request /// + /// \see GetDirectoryListing, ChangeDirectory, ParentDirectory + /// //////////////////////////////////////////////////////////// DirectoryResponse GetWorkingDirectory(); //////////////////////////////////////////////////////////// - /// Get the contents of the given directory - /// (subdirectories and files) + /// \brief Get the contents of the given directory /// - /// \param directory : Directory to list ("" by default, the current one) + /// This function retrieves the sub-directories and files + /// contained in the given directory. It is not recursive. + /// The \a directory parameter is relative to the current + /// working directory. + /// + /// \param directory Directory to list /// /// \return Server response to the request /// + /// \see GetWorkingDirectory, ChangeDirectory, ParentDirectory + /// //////////////////////////////////////////////////////////// ListingResponse GetDirectoryListing(const std::string& directory = ""); //////////////////////////////////////////////////////////// - /// Change the current working directory + /// \brief Change the current working directory /// - /// \param directory : New directory, relative to the current one + /// The new directory must be relative to the current one. + /// + /// \param directory New working directory /// /// \return Server response to the request /// + /// \see GetWorkingDirectory, GetDirectoryListing, ParentDirectory + /// //////////////////////////////////////////////////////////// Response ChangeDirectory(const std::string& directory); @@ -338,81 +373,127 @@ public : /// /// \return Server response to the request /// + /// \see GetWorkingDirectory, GetDirectoryListing, ChangeDirectory + /// //////////////////////////////////////////////////////////// Response ParentDirectory(); //////////////////////////////////////////////////////////// - /// Create a new directory + /// \brief Create a new directory /// - /// \param name : Name of the directory to create + /// The new directory is created as a child of the current + /// working directory. + /// + /// \param name Name of the directory to create /// /// \return Server response to the request /// + /// \see DeleteDirectory + /// //////////////////////////////////////////////////////////// - Response MakeDirectory(const std::string& name); + Response CreateDirectory(const std::string& name); //////////////////////////////////////////////////////////// - /// Remove an existing directory + /// \brief Remove an existing directory /// - /// \param Name : Name of the directory to remove + /// The directory to remove must be relative to the + /// current working directory. + /// Use this function with caution, the directory will + /// be removed permanently! + /// + /// \param Name Name of the directory to remove /// /// \return Server response to the request /// + /// \see CreateDirectory + /// //////////////////////////////////////////////////////////// Response DeleteDirectory(const std::string& name); //////////////////////////////////////////////////////////// - /// Rename a file + /// \brief Rename an existing file /// - /// \param file : File to rename - /// \param newName : New name + /// The filenames must be relative to the current working + /// directory. + /// + /// \param file File to rename + /// \param newName New name of the file /// /// \return Server response to the request /// + /// \see DeleteFile + /// //////////////////////////////////////////////////////////// Response RenameFile(const std::string& file, const std::string& newName); //////////////////////////////////////////////////////////// - /// Remove an existing file + /// \brief Remove an existing file /// - /// \param name : File to remove + /// The file name must be relative to the current working + /// directory. + /// Use this function with caution, the file will be + /// removed permanently! + /// + /// \param name File to remove /// /// \return Server response to the request /// + /// \see RenameFile + /// //////////////////////////////////////////////////////////// Response DeleteFile(const std::string& name); //////////////////////////////////////////////////////////// - /// Download a file from the server + /// \brief 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 + /// The filename of the distant file is relative to the + /// current working directory of the server, and the local + /// destination path is relative to the current directory + /// of your application. + /// If you want to watch the progress (to update a progress bar + /// for example) or have the ability to stop or pause the download, + /// you can use the fourth parameter to pass your progress handler. + /// + /// \param remoteFile Filename of the distant file to download + /// \param localPath Where to put to file on the local computer + /// \param mode Transfer mode + /// \param handler Object that will be notified of the download progress /// /// \return Server response to the request /// + /// \see Upload + /// //////////////////////////////////////////////////////////// - Response Download(const std::string& distantFile, const std::string& destPath, TransferMode mode = Binary); + Response Download(const std::string& remoteFile, const std::string& localPath, TransferMode mode = Binary); //////////////////////////////////////////////////////////// - /// Upload a file to the server + /// \brief 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 + /// The name of the local file is relative to the current + /// working directory of your application, and the + /// remote path is relative to the current directory of the + /// FTP server. + /// If you want to watch the progress (to update a progress bar + /// for example) or have the ability to stop or pause the upload, + /// you can use the fourth parameter to pass your progress handler. + /// + /// \param localFile Path of the local file to upload + /// \param remotePath Where to put to file on the server + /// \param mode Transfer mode + /// \param handler Object that will be notified of the upload progress /// /// \return Server response to the request /// //////////////////////////////////////////////////////////// - Response Upload(const std::string& localFile, const std::string& destPath, TransferMode mode = Binary); + Response Upload(const std::string& localFile, const std::string& remotePath, TransferMode mode = Binary); private : //////////////////////////////////////////////////////////// - /// Send a command to the FTP server + /// \brief Send a command to the FTP server /// - /// \param command : Command to send - /// \param parameter : Command parameter + /// \param command Command to send + /// \param parameter Command parameter /// /// \return Server response to the request /// @@ -420,8 +501,10 @@ private : Response SendCommand(const std::string& command, const std::string& parameter = ""); //////////////////////////////////////////////////////////// - /// Receive a response from the server - /// (usually after a command has been sent) + /// \brief Receive a response from the server + /// + /// This function must be called after each call to + /// SendCommand that expects a response. /// /// \return Server response to the request /// @@ -429,8 +512,9 @@ private : Response GetResponse(); //////////////////////////////////////////////////////////// - /// Utility class for exchanging datas with the server - /// on the data channel + /// \brief Utility class for exchanging datas with the server + /// on the data channel + /// //////////////////////////////////////////////////////////// class DataChannel; @@ -439,10 +523,72 @@ private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - SocketTCP myCommandSocket; ///< Socket holding the control connection with the server + TcpSocket myCommandSocket; ///< Socket holding the control connection with the server }; } // namespace sf #endif // SFML_FTP_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Ftp +/// +/// sf::Ftp is a very simple FTP client that allows you +/// to communicate with a FTP server. The FTP protocol allows +/// you to manipulate a remote file system (list files, +/// upload, download, create, remove, ...). +/// +/// Using the FTP client consists of 4 parts: +/// \li Connecting to the FTP server +/// \li Logging in (either as a registered user or anonymously) +/// \li Sending commands to the server +/// \li Disconnecting (this part can be done implicitely by the destructor) +/// +/// Every command returns a FTP response, which contains the +/// status code as well as a message from the server. Some +/// commands such as GetWorkingDirectory and GetDirectoryListing +/// return additional data, and use a class derived from +/// sf::Ftp::Response to provide this data. +/// +/// All commands, especially Upload and Download, may take some +/// time to complete. This is important to know if you don't want +/// to block your application while the server is completing +/// the task. +/// +/// Usage example: +/// \code +/// // Create a new FTP client +/// sf::Ftp ftp; +/// +/// // Connect to the server +/// sf::Ftp::Response response = ftp.Connect("ftp://ftp.myserver.com"); +/// if (response.IsOk()) +/// std::cout << "Connected" << std::endl; +/// +/// // Log in +/// response = ftp.Login("laurent", "dF6Zm89D"); +/// if (response.IsOk()) +/// std::cout << "Logged in" << std::endl; +/// +/// // Print the working directory +/// sf::Ftp::DirectoryResponse directory = ftp.GetWorkingDirectory(); +/// if (directory.IsOk()) +/// std::cout << "Working directory: " << directory.GetDirectory() << std::endl; +/// +/// // Create a new directory +/// response = ftp.CreateDirectory("files"); +/// if (response.IsOk()) +/// std::cout << "Created new directory" << std::endl; +/// +/// // Upload a file to this new directory +/// response = ftp.Upload("local-path/file.txt", "files", sf::Ftp::Ascii); +/// if (response.IsOk()) +/// std::cout << "File uploaded" << std::endl; +/// +/// // Disconnect from the server (optional) +/// ftp.Disconnect(); +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/Http.hpp b/include/SFML/Network/Http.hpp index 7cdcf9fd..f79bc81c 100644 --- a/include/SFML/Network/Http.hpp +++ b/include/SFML/Network/Http.hpp @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include #include #include @@ -38,25 +38,24 @@ 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. +/// \brief A HTTP client +/// //////////////////////////////////////////////////////////// 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) + /// \brief Define a HTTP request + /// //////////////////////////////////////////////////////////// class SFML_API Request { public : //////////////////////////////////////////////////////////// - /// Enumerate the available HTTP methods for a request + /// \brief Enumerate the available HTTP methods for a request + /// //////////////////////////////////////////////////////////// enum Method { @@ -66,58 +65,76 @@ public : }; //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor /// - /// \param method : Method to use for the request - /// \param URI : Target URI - /// \param body : Content of the request's body + /// This constructor creates a GET request, with the root + /// URI ("/") and an empty body. + /// + /// \param uri Target URI + /// \param method Method to use for the request + /// \param body Content of the request's body /// //////////////////////////////////////////////////////////// - Request(Method method = Get, const std::string& URI = "/", const std::string& body = ""); + Request(const std::string& uri = "/", Method method = Get, const std::string& body = ""); //////////////////////////////////////////////////////////// - /// Set the value of a field; the field is added if it doesn't exist + /// \brief Set the value of a field /// - /// \param field : Name of the field to set (case-insensitive) - /// \param value : Value of the field + /// The field is created if it doesn't exist. The name of + /// the field is case insensitive. + /// By default, a request doesn't contain any field (but the + /// mandatory fields are added later by the HTTP client when + /// sending the request). + /// + /// \param field Name of the field to set + /// \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 + /// \brief Set the request method /// - /// \param method : Method to use for the request + /// See the Method enumeration for a complete list of all + /// the availale methods. + /// The method is Http::Request::Get by default. + /// + /// \param method Method to use for the request /// //////////////////////////////////////////////////////////// void SetMethod(Method method); //////////////////////////////////////////////////////////// - /// Set the target URI of the request. - /// This parameter is "/" by default + /// \brief Set the requested URI /// - /// \param URI : URI to request, local to the host + /// The URI is the resource (usually a web page or a file) + /// that you want to get or post. + /// The URI is "/" (the root page) by default. + /// + /// \param uri URI to request, relative to the host /// //////////////////////////////////////////////////////////// - void SetURI(const std::string& URI); + void SetUri(const std::string& uri); //////////////////////////////////////////////////////////// - /// Set the HTTP version of the request. - /// This parameter is 1.0 by default + /// \brief Set the HTTP version fo the request /// - /// \param major : Major version number - /// \param minor : Minor version number + /// The HTTP version is 1.0 by default. + /// + /// \param major Major HTTP version number + /// \param minor Minor HTTP 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 + /// \brief Set the body of the request /// - /// \param body : Content of the request body + /// The body of a request is optional and only makes sense + /// for POST requests. It is ignored for all other methods. + /// The body is empty by default. + /// + /// \param body Content of the body /// //////////////////////////////////////////////////////////// void SetBody(const std::string& body); @@ -127,19 +144,24 @@ public : friend class Http; //////////////////////////////////////////////////////////// - /// Get the string representation of the request header + /// \brief Prepare the final request to send to the server /// - /// \return String containing the request + /// This is used internally by Http before sending the + /// request to the web server. + /// + /// \return String containing the request, ready to be sent /// //////////////////////////////////////////////////////////// - std::string ToString() const; + std::string Prepare() const; //////////////////////////////////////////////////////////// - /// Check if the given field has been defined + /// \brief Check if the request defines a field /// - /// \param field : Name of the field to check (case-insensitive) + /// This function uses case-insensitive comparisons. /// - /// \return True if the field exists + /// \param field Name of the field to test + /// + /// \return True if the field exists, false otherwise /// //////////////////////////////////////////////////////////// bool HasField(const std::string& field) const; @@ -152,7 +174,7 @@ public : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - FieldTable myFields; ///< Fields of the header + FieldTable myFields; ///< Fields of the header associated to their value Method myMethod; ///< Method to use for the request std::string myURI; ///< Target URI of the request unsigned int myMajorVersion; ///< Major HTTP version @@ -161,17 +183,16 @@ public : }; //////////////////////////////////////////////////////////// - /// 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) + /// \brief Define a HTTP response + /// //////////////////////////////////////////////////////////// class SFML_API Response { public : //////////////////////////////////////////////////////////// - /// Enumerate all the valid status codes returned in - /// a HTTP response + /// \brief Enumerate all the valid status codes for a response + /// //////////////////////////////////////////////////////////// enum Status { @@ -210,15 +231,21 @@ public : }; //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor + /// + /// Constructs an empty response. /// //////////////////////////////////////////////////////////// Response(); //////////////////////////////////////////////////////////// - /// Get the value of a field + /// \brief Get the value of a field /// - /// \param field : Name of the field to get (case-insensitive) + /// If the field \a field is not found in the response header, + /// the empty string is returned. This function uses + /// case-insensitive comparisons. + /// + /// \param field Name of the field to get /// /// \return Value of the field, or empty string if not found /// @@ -226,35 +253,46 @@ public : const std::string& GetField(const std::string& field) const; //////////////////////////////////////////////////////////// - /// Get the header's status code + /// \brief Get the response status code /// - /// \return Header's status code + /// The status code should be the first thing to be checked + /// after receiving a response, it defines whether it is a + /// success, a failure or anything else (see the Status + /// enumeration). + /// + /// \return Status code of the response /// //////////////////////////////////////////////////////////// Status GetStatus() const; //////////////////////////////////////////////////////////// - /// Get the major HTTP version number of the response + /// \brief Get the major HTTP version number of the response /// - /// \return Major version number + /// \return Major HTTP version number + /// + /// \see GetMinorHttpVersion /// //////////////////////////////////////////////////////////// unsigned int GetMajorHttpVersion() const; //////////////////////////////////////////////////////////// - /// Get the major HTTP version number of the response + /// \brief Get the minor HTTP version number of the response /// - /// \return Major version number + /// \return Minor HTTP version number + /// + /// \see GetMajorHttpVersion /// //////////////////////////////////////////////////////////// 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) + /// \brief Get the body of the response + /// + /// The body of a response may contain: + /// \li the requested page (for GET requests) + /// \li a response from the server (for POST requests) + /// \li nothing (for HEAD requests) + /// \li an error message (in case of an error) /// /// \return The response body /// @@ -266,12 +304,15 @@ public : friend class Http; //////////////////////////////////////////////////////////// - /// Construct the header from a response string + /// \brief Construct the header from a response string /// - /// \param data : Content of the response's header to parse + /// This function is used by Http to build the response + /// of a request. + /// + /// \param data Content of the response to parse /// //////////////////////////////////////////////////////////// - void FromString(const std::string& data); + void Parse(const std::string& data); //////////////////////////////////////////////////////////// // Types @@ -289,39 +330,58 @@ public : }; //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor /// //////////////////////////////////////////////////////////// Http(); //////////////////////////////////////////////////////////// - /// Construct the Http instance with the target host + /// \brief Construct the HTTP client 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) + /// This is equivalent to calling SetHost(host, port). + /// The port has a default value of 0, which means that the + /// HTTP client will use the right port according to the + /// protocol used (80 for HTTP, 443 for HTTPS). You should + /// leave it like this unless you really need a port other + /// than the standard one, or use an unknown protocol. + /// + /// \param host Web server to connect to + /// \param port Port to use for connection /// //////////////////////////////////////////////////////////// Http(const std::string& host, unsigned short port = 0); //////////////////////////////////////////////////////////// - /// Set the target host + /// \brief 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) + /// This function just stores the host address and port, it + /// doesn't actually connect to it until you send a request. + /// The port has a default value of 0, which means that the + /// HTTP client will use the right port according to the + /// protocol used (80 for HTTP, 443 for HTTPS). You should + /// leave it like this unless you really need a port other + /// than the standard one, or use an unknown protocol. + /// + /// \param host Web server to connect to + /// \param port Port to use for connection /// //////////////////////////////////////////////////////////// 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. + /// \brief Send a HTTP request and return the server's response. /// - /// \param request : Request to send - /// \param timeout : Maximum time to wait, in seconds (0 by default, means no timeout) + /// You must have a valid host before sending a request (see SetHost). + /// Any missing mandatory header field in the request 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, or use a timeout to limit the time to wait. A value + /// of 0 means that the client will use the system defaut timeout + /// (which is usually pretty long). + /// + /// \param request Request to send + /// \param timeout Maximum time to wait, in seconds /// /// \return Server's response /// @@ -333,7 +393,7 @@ private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - SocketTCP myConnection; ///< Connection to the host + TcpSocket 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 @@ -343,3 +403,62 @@ private : #endif // SFML_HTTP_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Http +/// +/// sf::Http is a very simple HTTP client that allows you +/// to communicate with a web server. You can retrieve +/// web pages, send data to an interactive resource, +/// download a remote file, etc. +/// +/// The HTTP client is split into 3 classes: +/// \li sf::Http::Request +/// \li sf::Http::Response +/// \li sf::Http +/// +/// sf::Http::Request builds the request that will be +/// sent to the server. A request is made of: +/// \li a method (what you want to do) +/// \li a target URI (usually the name of the web page or file) +/// \li one or more header fields (options that you can pass to the server) +/// \li an optional body (for POST requests) +/// +/// sf::Http::Response parse the response from the web server +/// and provides getters to read them. The response contains: +/// \li a status code +/// \li header fields (that may be answers to the ones that you requested) +/// \li a body, which contains the contents of the requested resource +/// +/// sf::Http provides a simple function, SendRequest, to send a +/// sf::Http::Request and return the corresponding sf::Http::Response +/// from the server. +/// +/// Usage example: +/// \code +/// // Create a new HTTP client +/// sf::Http http; +/// +/// // We'll work on http://www.sfml-dev.org +/// http.SetHost("http://www.sfml-dev.org"); +/// +/// // Prepare a request to get the 'features.php' page +/// sf::Http::Request request("features.php"); +/// +/// // Send the request +/// sf::Http::Response response = http.SendRequest(request); +/// +/// // Check the status code and display the result +/// sf::Http::Response::Status status = response.GetStatus(); +/// if (status == sf::Http::Response::Ok) +/// { +/// std::cout << response.GetBody() << std::endl; +/// } +/// else +/// { +/// std::cout << "Error " << status << std::endl; +/// } +/// \endcode +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/IpAddress.hpp b/include/SFML/Network/IpAddress.hpp index d71d0633..7e2c6e72 100644 --- a/include/SFML/Network/IpAddress.hpp +++ b/include/SFML/Network/IpAddress.hpp @@ -105,7 +105,7 @@ public : /// \see ToInteger /// //////////////////////////////////////////////////////////// - IpAddress(Uint32 address); + explicit IpAddress(Uint32 address); //////////////////////////////////////////////////////////// /// \brief Get a string representation of the address diff --git a/include/SFML/Network/Packet.hpp b/include/SFML/Network/Packet.hpp index 0fde1d1f..aed0faf5 100644 --- a/include/SFML/Network/Packet.hpp +++ b/include/SFML/Network/Packet.hpp @@ -36,77 +36,133 @@ namespace sf { class String; +class TcpSocket; +class UdpSocket; //////////////////////////////////////////////////////////// -/// Packet wraps data to send / to receive through the network +/// \brief Utility class to build blocks of data to transfer +/// over the network +/// //////////////////////////////////////////////////////////// class SFML_API Packet { public : //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor + /// + /// Creates an empty packet. /// //////////////////////////////////////////////////////////// Packet(); //////////////////////////////////////////////////////////// - /// Virtual destructor + /// \brief Virtual destructor /// //////////////////////////////////////////////////////////// virtual ~Packet(); //////////////////////////////////////////////////////////// - /// Append data to the end of the packet + /// \brief Append data to the end of the packet /// - /// \param data : Pointer to the bytes to append - /// \param sizeInBytes : Number of bytes to append + /// \param data Pointer to the sequence of bytes to append + /// \param sizeInBytes Number of bytes to append + /// + /// \see Clear /// //////////////////////////////////////////////////////////// void Append(const void* data, std::size_t sizeInBytes); //////////////////////////////////////////////////////////// - /// Clear the packet data + /// \brief Clear the packet + /// + /// After calling Clear, the packet is empty. + /// + /// \see Append /// //////////////////////////////////////////////////////////// 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 + /// \brief Get a pointer to the data contained in the packet + /// + /// Warning: the returned pointer may become invalid after + /// you append data to the packet, therefore it should never + /// be stored. + /// The return pointer is NULL if the packet is empty. /// /// \return Pointer to the data /// + /// \see GetDataSize + /// //////////////////////////////////////////////////////////// const char* GetData() const; //////////////////////////////////////////////////////////// - /// Get the size of the data contained in the packet + /// \brief Get the size of the data contained in the packet + /// + /// This function returns the number of bytes pointed to by + /// what GetData returns. /// /// \return Data size, in bytes /// + /// \see GetData + /// //////////////////////////////////////////////////////////// std::size_t GetDataSize() const; //////////////////////////////////////////////////////////// - /// Tell if the reading position has reached the end of the packet + /// \brief Tell if the reading position has reached the + /// end of the packet /// - /// \return True if all data have been read into the packet + /// This function is useful to know if there is some data + /// left to be read, without actually reading it. + /// + /// \return True if all data was read, false otherwise + /// + /// \see operator bool /// //////////////////////////////////////////////////////////// bool EndOfPacket() const; //////////////////////////////////////////////////////////// - /// Return the validity of packet + /// \brief Test the validity of the packet, for reading + /// + /// This operator allows to test the packet as a boolean + /// variable, to check if a reading operation was successful. + /// + /// A packet will be in an invalid state if it has no more + /// data to read. + /// + /// This behaviour is the same as standard C++ streams. + /// + /// Usage example: + /// \begincode + /// float x; + /// packet >> x; + /// if (packet) + /// { + /// // ok, x was extracted successfully + /// } + /// + /// // -- or -- + /// + /// float x; + /// if (packet >> x) + /// { + /// // ok, x was extracted successfully + /// } + /// \endcode /// /// \return True if last data extraction from packet was successful /// + /// \see EndOfPacket + /// //////////////////////////////////////////////////////////// operator bool() const; //////////////////////////////////////////////////////////// - /// Operator >> overloads to extract data from the packet + /// Overloads of operator >> to read data from the packet /// //////////////////////////////////////////////////////////// Packet& operator >>(bool& data); @@ -125,7 +181,7 @@ public : Packet& operator >>(String& data); //////////////////////////////////////////////////////////// - /// Operator << overloads to put data into the packet + /// Overloads of operator << to write data into the packet /// //////////////////////////////////////////////////////////// Packet& operator <<(bool data); @@ -145,37 +201,57 @@ public : private : - friend class SocketTCP; - friend class SocketUDP; + friend class TcpSocket; + friend class UdpSocket; //////////////////////////////////////////////////////////// - /// Check if the packet can extract a given size of bytes + /// \brief Check if the packet can extract a given number of bytes /// - /// \param size : Size to check + /// This function updates accordingly the state of the packet. /// - /// \return True if Size bytes can be read from the packet's data + /// \param size Size to check + /// + /// \return True if \a size bytes can be read from the packet /// //////////////////////////////////////////////////////////// bool CheckSize(std::size_t size); //////////////////////////////////////////////////////////// - /// Called before the packet is sent to the network + /// \brief Called before the packet is sent over the network /// - /// \param dataSize : Variable to fill with the size of data to send + /// This function can be defined by derived classes to + /// transform the data before it is sent; this can be + /// used for compression, encryption, etc. + /// The function must return a pointer to the modified data, + /// as well as the number of bytes pointed. + /// The default implementation provides the packet's data + /// without transforming it. + /// + /// \param size Variable to fill with the size of data to send /// /// \return Pointer to the array of bytes to send /// + /// \see OnReceive + /// //////////////////////////////////////////////////////////// - virtual const char* OnSend(std::size_t& dataSize); + virtual const char* OnSend(std::size_t& size); //////////////////////////////////////////////////////////// - /// Called after the packet has been received from the network + /// \brief Called after the packet is received over the network /// - /// \param data : Pointer to the array of received bytes - /// \param dataSize : Size of the array of bytes + /// This function can be defined by derived classes to + /// transform the data after it is received; this can be + /// used for uncompression, decryption, etc. + /// The function receives a pointer to the received data, + /// and must fill the packet with the transformed bytes. + /// The default implementation fills the packet directly + /// without transforming the data. + /// + /// \param data Pointer to the received bytes + /// \param size Number of bytes /// //////////////////////////////////////////////////////////// - virtual void OnReceive(const char* data, std::size_t dataSize); + virtual void OnReceive(const char* data, std::size_t size); //////////////////////////////////////////////////////////// // Member data @@ -189,3 +265,122 @@ private : #endif // SFML_PACKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Packet +/// +/// Packets provide a safe and easy way to serialize data, +/// in order to send it over the network using sockets +/// (sf::TcpSocket, sf::UdpSocket). +/// +/// Packets solve 2 fundamental problems that arise when +/// transfering data over the network: +/// \li data is interpreted correctly according to the endianness +/// \li the bounds of the packet are preserved (one send == one receive) +/// +/// The sf::Packet class provides both input and output modes. +/// It is designed to follow the behaviour of standard C++ streams, +/// using operators >> and << to extract and insert data. +/// +/// It is recommended to use only fixed-size types (like sf::Int32, etc.), +/// to avoid possible differences between the sender and the receiver. +/// Indeed, the native C++ types may have different sizes on two platforms +/// and your data may be corrupted if that happens. +/// +/// Usage example: +/// \begincode +/// sf::Uint32 x = 24; +/// std::string s = "hello"; +/// double d = 5.89; +/// +/// // Group the variables to send into a packet +/// sf::Packet packet; +/// packet << x << s << d; +/// +/// // Send it over the network (socket is a valid sf::TcpSocket) +/// socket.Send(packet); +/// +/// ----------------------------------------------------------------- +/// +/// // Receive the packet at the other end +/// sf::Packet packet; +/// socket.Receive(packet); +/// +/// // Extract the variables contained in the packet +/// sf::Uint32 x; +/// std::string s; +/// double d; +/// if (packet >> x >> s >> d) +/// { +/// // Data extracted successfully... +/// } +/// \endcode +/// +/// Packets have built-in operator >> and << overloads for +/// standard types: +/// \li bool +/// \li fixed-size integer types (sf::Int8/16/32, sf::Uint8/16/32) +/// \li floating point numbers (float, double) +/// \li string types (char*, wchar_t*, std::string, std::wstring, sf::String) +/// +/// Like standard streams, it is also possible to define your own +/// overloads of operators >> and << in order to handle your +/// custom types. +/// +/// \begincode +/// struct MyStruct +/// { +/// float number; +/// sf::Int8 integer; +/// std::string str; +/// }; +/// +/// sf::Packet& operator <<(sf::Packet& packet, const MyStruct& m) +/// { +/// return packet << m.number << m.integer << m.str; +/// } +/// +/// sf::Packet& operator >>(sf::Packet& packet, MyStruct& m) +/// { +/// return packet >> m.number >> m.integer >> m.str; +/// } +/// \endcode +/// +/// Packets also provide an extra feature that allows to apply +/// custom transformations to the data before it is sent, +/// and after it is received. This is typically used to +/// handle automatic compression or encryption of the data. +/// This is achieved by inheriting from sf::Packet, and overriding +/// the OnSend and OnReceive functions. +/// +/// Here is an example: +/// \begincode +/// class ZipPacket : public sf::Packet +/// { +/// virtual const char* OnSend(std::size_t& size) +/// { +/// const char* srcData = GetData(); +/// std::size_t srcSize = GetDataSize(); +/// +/// return MySuperZipFunction(srcData, srcSize, &size); +/// } +/// +/// virtual void OnReceive(const char* data, std::size_t size) +/// { +/// std::size_t dstSize; +/// const char* dstData = MySuperUnzipFunction(data, size, &dstSize); +/// +/// Append(dstData, dstSize); +/// } +/// }; +/// +/// // Use like regular packets: +/// ZipPacket packet; +/// packet << x << s << d; +/// ... +/// \endcode +/// +/// \see sf::TcpSocket, sf::UdpSocket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/Selector.hpp b/include/SFML/Network/Selector.hpp deleted file mode 100644 index 7eb97da9..00000000 --- a/include/SFML/Network/Selector.hpp +++ /dev/null @@ -1,116 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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) const; - -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/include/SFML/Network/Selector.inl b/include/SFML/Network/Selector.inl deleted file mode 100644 index 0a58f63f..00000000 --- a/include/SFML/Network/Selector.inl +++ /dev/null @@ -1,97 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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) const -{ - 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/include/SFML/Network/SelectorBase.hpp b/include/SFML/Network/SelectorBase.hpp deleted file mode 100644 index d31234e7..00000000 --- a/include/SFML/Network/SelectorBase.hpp +++ /dev/null @@ -1,112 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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) const; - -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/include/SFML/Network/Socket.hpp b/include/SFML/Network/Socket.hpp new file mode 100644 index 00000000..4a9e4d5c --- /dev/null +++ b/include/SFML/Network/Socket.hpp @@ -0,0 +1,234 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_SOCKET_HPP +#define SFML_SOCKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +class SocketSelector; + +//////////////////////////////////////////////////////////// +/// \brief Base class for all the socket types +/// +//////////////////////////////////////////////////////////// +class SFML_API Socket : NonCopyable +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Status codes that may be returned by socket functions + /// + //////////////////////////////////////////////////////////// + enum Status + { + Done, ///< The socket has sent / received the data + NotReady, ///< The socket is not ready to send / receive data yet + Disconnected, ///< The TCP socket has been disconnected + Error ///< An unexpected error happened + }; + + //////////////////////////////////////////////////////////// + /// \brief Some special values used by sockets + /// + //////////////////////////////////////////////////////////// + enum + { + AnyPort = 0 ///< Special value that tells the system to pick any available port + }; + +public : + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Socket(); + + //////////////////////////////////////////////////////////// + /// \brief Set the blocking state of the socket + /// + /// In blocking mode, calls will not return until they have + /// completed their task. For example, a call to Receive in + /// blocking mode won't return until some data was actually + /// received. + /// In non-blocking mode, calls will always return immediately, + /// using the return code to signal whether there was data + /// available or not. + /// By default, all sockets are blocking. + /// + /// \param blocking True to set the socket as blocking, false for non-blocking + /// + /// \see IsBlocking + /// + //////////////////////////////////////////////////////////// + void SetBlocking(bool blocking); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the socket is blocking or non-blocking mode + /// + /// \return True if the socket is blocking, false otherwise + /// + /// \see SetBlocking + /// + //////////////////////////////////////////////////////////// + bool IsBlocking() const; + +protected : + + //////////////////////////////////////////////////////////// + /// \brief Types of protocols that the socket can use + /// + //////////////////////////////////////////////////////////// + enum Type + { + Tcp, ///< TCP protocol + Udp ///< UDP protocol + }; + + //////////////////////////////////////////////////////////// + /// \brief Structure holding the data of a pending packet + /// + //////////////////////////////////////////////////////////// + struct PendingPacket + { + PendingPacket(); + + Uint32 Size; ///< Data of packet size + std::size_t SizeReceived; ///< Number of size bytes received so far + std::vector Data; ///< Data of the packet + }; + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// This constructor can only be accessed by derived classes. + /// + /// \param type Type of the socket (TCP or UDP) + /// + //////////////////////////////////////////////////////////// + Socket(Type type); + + //////////////////////////////////////////////////////////// + /// \brief Return the internal handle of the socket + /// + /// The returned handle may be invalid if the socket + /// was not created yet (or already destroyed). + /// This function can only be accessed by derived classes. + /// + /// \return The internal (OS-specific) handle of the socket + /// + //////////////////////////////////////////////////////////// + SocketHandle GetHandle() const; + + //////////////////////////////////////////////////////////// + /// \brief Create the internal representation of the socket + /// + /// This function can only be accessed by derived classes. + /// + //////////////////////////////////////////////////////////// + void Create(); + + //////////////////////////////////////////////////////////// + /// \brief Create the internal representation of the socket + /// from a socket handle + /// + /// This function can only be accessed by derived classes. + /// + /// \param handle OS-specific handle of the socket to wrap + /// + //////////////////////////////////////////////////////////// + void Create(SocketHandle handle); + + //////////////////////////////////////////////////////////// + /// \brief Close the socket gracefully + /// + /// This function can only be accessed by derived classes. + /// + //////////////////////////////////////////////////////////// + void Close(); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + PendingPacket myPendingPacket; ///< Temporary data of the packet currently being received + +private : + + friend class SocketSelector; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Type myType; ///< Type of the socket (TCP or UDP) + SocketHandle mySocket; ///< Socket descriptor + bool myIsBlocking; ///< Current blocking mode of the socket +}; + +} // namespace sf + + +#endif // SFML_SOCKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Socket +/// +/// This class mainly defines internal stuff to be used by +/// derived classes. +/// +/// The only public features that it defines, and which +/// is therefore common to all the socket classes, is the +/// blocking state. All sockets can be set as blocking or +/// non-blocking. +/// +/// In blocking mode, socket functions will hang until +/// the operation completes, which means that the entire +/// program (well, in fact the current thread if you use +/// multiple ones) will be stuck waiting for your socket +/// operation to complete. +/// +/// In non-blocking mode, all the socket functions will +/// return immediately. If the socket is not ready to complete +/// the requested operation, the function simply returns +/// the proper status code (Socket::NotReady). +/// +/// The default mode, which is blocking, is the one that is +/// generally used, in combination with threads or selectors. +/// The non-blocking mode is rather used in real-time +/// applications that run an endless loop that can poll +/// the socket often enough, and cannot afford blocking +/// this loop. +/// +/// \see sf::TcpListener, sf::TcpSocket, sf::UdpSocket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/SocketHelper.hpp b/include/SFML/Network/SocketHandle.hpp similarity index 62% rename from include/SFML/Network/SocketHelper.hpp rename to include/SFML/Network/SocketHandle.hpp index 166ce607..aadd5223 100644 --- a/include/SFML/Network/SocketHelper.hpp +++ b/include/SFML/Network/SocketHandle.hpp @@ -22,43 +22,36 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETHELPER_HPP -#define SFML_SOCKETHELPER_HPP +#ifndef SFML_SOCKETHANDLE_HPP +#define SFML_SOCKETHANDLE_HPP //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// #include +#if defined(SFML_SYSTEM_WINDOWS) + #include +#endif + 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 - }; -} +//////////////////////////////////////////////////////////// +// Define the low-level socket handle type, specific to +// each platform +//////////////////////////////////////////////////////////// +#if defined(SFML_SYSTEM_WINDOWS) + + typedef UINT_PTR SocketHandle; + +#else + + typedef int SocketHandle; + +#endif } // namespace sf -#ifdef SFML_SYSTEM_WINDOWS - - #include - -#else - - #include - -#endif - - -#endif // SFML_SOCKETHELPER_HPP +#endif // SFML_SOCKETHANDLE_HPP diff --git a/include/SFML/Network/SocketSelector.hpp b/include/SFML/Network/SocketSelector.hpp new file mode 100644 index 00000000..aaddd339 --- /dev/null +++ b/include/SFML/Network/SocketSelector.hpp @@ -0,0 +1,251 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_SOCKETSELECTOR_HPP +#define SFML_SOCKETSELECTOR_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +class Socket; + +//////////////////////////////////////////////////////////// +/// \brief Multiplexer that allows to read from multiple sockets +/// +//////////////////////////////////////////////////////////// +class SFML_API SocketSelector +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + SocketSelector(); + + //////////////////////////////////////////////////////////// + /// \brief Copy constructor + /// + /// \param copy Instance to copy + /// + //////////////////////////////////////////////////////////// + SocketSelector(const SocketSelector& copy); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~SocketSelector(); + + //////////////////////////////////////////////////////////// + /// \brief Add a new socket to the selector + /// + /// This function keeps a weak reference to the socket, + /// so you have to make sure that the socket is not destroyed + /// while it is stored in the selector. + /// + /// \param socket Reference to the socket to add + /// + /// \see Remove, Clear + /// + //////////////////////////////////////////////////////////// + void Add(Socket& socket); + + //////////////////////////////////////////////////////////// + /// \brief Remove a socket from the selector + /// + /// This function doesn't destroy the socket, it simply + /// removes the reference that the selector has to it. + /// + /// \param socket Reference to the socket to remove + /// + /// \see Add, Clear + /// + //////////////////////////////////////////////////////////// + void Remove(Socket& socket); + + //////////////////////////////////////////////////////////// + /// \brief Remove all the sockets stored in the selector + /// + /// This function doesn't destroy any instance, it simply + /// removes all the references that the selector has to + /// external sockets. + /// + /// \see Add, Remove + /// + //////////////////////////////////////////////////////////// + void Clear(); + + //////////////////////////////////////////////////////////// + /// \brief Wait until one or more sockets are ready to receive + /// + /// This function returns as soon as at least one socket has + /// some data available to be received. To know which sockets are + /// ready, use the IsReady function. + /// If you use a timeout and no socket is ready before the timeout + /// is over, the function returns false. + /// + /// \return True if there are sockets ready, false otherwise + /// + /// \see IsReady + /// + //////////////////////////////////////////////////////////// + bool Wait(float timeout = 0.f); + + //////////////////////////////////////////////////////////// + /// \brief Test a socket to know if it is ready to receive data + /// + /// This function must be used after a call to Wait, to know + /// which sockets are ready to receive data. If a socket is + /// ready, a call to Receive will never block because we know + /// that there is data available to read. + /// Note that if this function returns true for a TcpListener, + /// this means that it is ready to accept a new connection. + /// + /// \return True if the socket is ready to read, false otherwise + /// + /// \see IsReady + /// + //////////////////////////////////////////////////////////// + bool IsReady(Socket& socket) const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + SocketSelector& operator =(const SocketSelector& right); + +private : + + struct SocketSelectorImpl; + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + SocketSelectorImpl* myImpl; ///< Opaque pointer to the implementation (which requires OS-specific types) +}; + +} // namespace sf + + +#endif // SFML_SOCKETSELECTOR_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::SocketSelector +/// +/// Socket selectors provide a way to wait until some data is +/// available on a set of sockets, instead of just one. This +/// is convenient when you have multiple sockets that may +/// possibly receive data, but you don't know which one will +/// be ready first. In particular, it avoids to use a thread +/// for each socket; with selectors, a single thread can handle +/// all the sockets. +/// +/// All types of sockets can be used in a selector: +/// \li sf::TcpListener +/// \li sf::TcpSocket +/// \li sf::UdpSocket +/// +/// A selector doesn't store its own copies of the sockets +/// (socket classes are not copyable anyway), it simply keeps +/// a reference to the original sockets that you pass to the +/// Add function. Therefore, you can't use the selector as a +/// socket container, you must store them oustide and make sure +/// that they are alive as long as they are used in the selector. +/// +/// Using a selector is simple: +/// \li populate the selector with all the sockets that you want to observe +/// \li make it wait until there is data available on any of the sockets +/// \li test each socket to find out which ones are ready +/// +/// Usage example: +/// \code +/// // Create a socket to listen to new connections +/// sf::TcpListener listener; +/// listener.Listen(55001); +/// +/// // Create a list to store the future clients +/// std::list clients; +/// +/// // Create a selector +/// sf::SocketSelector selector; +/// +/// // Add the listener to the selector +/// selector.Add(listener); +/// +/// // Endless loop that waits for new connections +/// while (running) +/// { +/// // Make the selector wait for data on any socket +/// if (selector.Wait()) +/// { +/// // Test the listener +/// if (selector.IsReady(listener)) +/// { +/// // The listener is ready: there is a pending connection +/// sf::TcpSocket* client = new sf::TcpSocket; +/// if (listener.accept(*client) == sf::Socket::Done) +/// { +/// // Add the new client to the clients list +/// clients.push_back(client); +/// +/// // Add the new client to the selector so that we will +/// // be notified when he sends something +/// selector.Add(*client); +/// } +/// } +/// else +/// { +/// // The listener socket is not ready, test all other sockets (the clients) +/// for (std::list::iterator it = clients.begin(); it != clients.end(); ++it) +/// { +/// sf::TcpSocket& client = **it; +/// if (selector.IsReady(client)) +/// { +/// // The client has sent some data, we can receive it +/// sf::Packet packet; +/// if (client.Receive(packet) == sf::Socket::Done) +/// { +/// ... +/// } +/// } +/// } +/// } +/// } +/// } +/// \endcode +/// +/// \see sf::Socket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/SocketTCP.hpp b/include/SFML/Network/SocketTCP.hpp deleted file mode 100644 index d6eb6a8a..00000000 --- a/include/SFML/Network/SocketTCP.hpp +++ /dev/null @@ -1,227 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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 host : 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& host, 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 - /// - /// \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 sizeInBytes : Number of bytes to send - /// - /// \return Status code - /// - //////////////////////////////////////////////////////////// - Socket::Status Send(const char* data, std::size_t sizeInBytes); - - //////////////////////////////////////////////////////////// - /// 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 packet : Packet to send - /// - /// \return Status code - /// - //////////////////////////////////////////////////////////// - Socket::Status Send(Packet& packet); - - //////////////////////////////////////////////////////////// - /// Receive a packet from the host (must be connected first). - /// This function will block if the socket is blocking - /// - /// \param packet : Packet to fill with received data - /// - /// \return Status code - /// - //////////////////////////////////////////////////////////// - Socket::Status Receive(Packet& packet); - - //////////////////////////////////////////////////////////// - /// 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 - Uint32 myPendingHeader; ///< Data of the current pending packet header, if any - Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any - std::vector myPendingPacket; ///< Data of the current pending packet, if any - Int32 myPendingPacketSize; ///< Size of the current pending packet, if any - bool myIsBlocking; ///< Is the socket blocking or non-blocking ? -}; - -} // namespace sf - - -#endif // SFML_SOCKETTCP_HPP diff --git a/include/SFML/Network/SocketUDP.hpp b/include/SFML/Network/SocketUDP.hpp deleted file mode 100644 index 1b35b903..00000000 --- a/include/SFML/Network/SocketUDP.hpp +++ /dev/null @@ -1,228 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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 sizeInBytes : 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 sizeInBytes, 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 - /// \param port : Port on which the remote computer sent the data - /// - /// \return Status code - /// - //////////////////////////////////////////////////////////// - Socket::Status Receive(char* data, std::size_t maxSize, std::size_t& sizeReceived, IpAddress& address, unsigned short& port); - - //////////////////////////////////////////////////////////// - /// Send a packet of data - /// - /// \param packet : 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& packet, const IpAddress& address, unsigned short port); - - //////////////////////////////////////////////////////////// - /// Receive a packet. - /// This function will block if the socket is blocking - /// - /// \param packet : Packet to fill with received data - /// \param Address : Address of the computer which sent the packet - /// \param Port : Port on which the remote computer sent the data - /// - /// \return Status code - /// - //////////////////////////////////////////////////////////// - Socket::Status Receive(Packet& packet, IpAddress& address, unsigned short& port); - - //////////////////////////////////////////////////////////// - /// 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 - Uint32 myPendingHeader; ///< Data of the current pending packet header, if any - Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any - std::vector myPendingPacket; ///< Data of the current pending packet, if any - Int32 myPendingPacketSize; ///< Size of the current pending packet, if any - bool myIsBlocking; ///< Is the socket blocking or non-blocking ? -}; - -} // namespace sf - - -#endif // SFML_SOCKETUDP_HPP diff --git a/include/SFML/Network/TcpListener.hpp b/include/SFML/Network/TcpListener.hpp new file mode 100644 index 00000000..6fa803f7 --- /dev/null +++ b/include/SFML/Network/TcpListener.hpp @@ -0,0 +1,131 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_TCPLISTENER_HPP +#define SFML_TCPLISTENER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +class TcpSocket; + +//////////////////////////////////////////////////////////// +/// \brief Socket that listens to new TCP connections +/// +//////////////////////////////////////////////////////////// +class SFML_API TcpListener : public Socket +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + TcpListener(); + + //////////////////////////////////////////////////////////// + /// \brief Start listening for connections + /// + /// This functions makes the socket listen to the specified + /// port, waiting for new connections. + /// If the socket was previously listening to another port, + /// it will be stopped first and bound to the new port. + /// + /// \param port Port to listen for new connections + /// + /// \return Status code + /// + /// \see Accept, Close + /// + //////////////////////////////////////////////////////////// + Status Listen(unsigned short port); + + //////////////////////////////////////////////////////////// + /// \brief Accept a new connection + /// + /// If the socket is in blocking mode, this function will + /// not return until a connection is actually received. + /// + /// \param socket Socket that will hold the new connection + /// + /// \return Status code + /// + /// \see Listen + /// + //////////////////////////////////////////////////////////// + Status Accept(TcpSocket& socket); +}; + + +} // namespace sf + + +#endif // SFML_TCPLISTENER_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::TcpListener +/// +/// A listener socket is a special type of socket that listens to +/// a given port and waits for connections on that port. +/// This is all it can do. +/// +/// When a new connection is received, the socket returns a +/// new instance of sf::TcpSocket that is properly +/// initialized and can be used to communicate with the +/// new client. +/// +/// Listener sockets are specific to the TCP protocol, +/// UDP sockets are connectionless and can therefore communicate +/// directly. As a consequence, a listener socket will always +/// return the new connections as sf::TcpSocket instances. +/// +/// Usage example: +/// \code +/// // Create a listener socket and make it wait for new +/// // connections on port 55001 +/// sf::TcpListener listener; +/// listener.Listen(55001); +/// +/// // Endless loop that waits for new connections +/// while (running) +/// { +/// sf::TcpSocket client; +/// if (listener.accept(client) == sf::Socket::Done) +/// { +/// // A new client just connected! +/// std::cout << "New connection received from " << client.GetRemoteAddress() << std::endl; +/// DoSomethingWith(client); +/// } +/// } +/// \endcode +/// +/// \see sf::TcpSocket, sf::Socket +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/TcpSocket.hpp b/include/SFML/Network/TcpSocket.hpp new file mode 100644 index 00000000..a938ca2a --- /dev/null +++ b/include/SFML/Network/TcpSocket.hpp @@ -0,0 +1,271 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_TCPSOCKET_HPP +#define SFML_TCPSOCKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +class TcpListener; +class IpAddress; +class Packet; + +//////////////////////////////////////////////////////////// +/// \brief Specialized socket using the TCP protocol +/// +//////////////////////////////////////////////////////////// +class SFML_API TcpSocket : public Socket +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + TcpSocket(); + + //////////////////////////////////////////////////////////// + /// \brief Get the port to which the socket is bound locally + /// + /// If the socket is not connected, this function returns 0. + /// + /// \return Port to which the socket is bound + /// + /// \see Connect, GetRemotePort + /// + //////////////////////////////////////////////////////////// + unsigned short GetLocalPort() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the address of the connected peer + /// + /// It the socket is not connected, this function returns + /// sf::IpAddress::None. + /// + /// \return Address of the remote peer + /// + /// \see GetRemotePort + /// + //////////////////////////////////////////////////////////// + IpAddress GetRemoteAddress() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the port of the connected peer to which + /// the socket is connected + /// + /// If the socket is not connected, this function returns 0. + /// + /// \return Remote port to which the socket is connected + /// + /// \see GetRemoteAddress + /// + //////////////////////////////////////////////////////////// + unsigned short GetRemotePort() const; + + //////////////////////////////////////////////////////////// + /// \brief Connect the socket to a remote peer + /// + /// In blocking mode, this function may take a while, especially + /// if the remote peer is not reachable. The last parameter allows + /// you to stop trying to connect after a given timeout. + /// If the socket was previously connected, it is first disconnected. + /// + /// \param remoteAddress Address of the remote peer + /// \param remotePort Port of the remote peer + /// \param timeout Optional maximum time to wait, in seconds + /// + /// \return Status code + /// + /// \see Disconnect + /// + //////////////////////////////////////////////////////////// + Status Connect(const IpAddress& remoteAddress, unsigned short remotePort, float timeout = 0.f); + + //////////////////////////////////////////////////////////// + /// \brief Disconnect the connect from its remote peer + /// + /// This function gracefully closes the connection. If the + /// socket is not connected, this function has no effect. + /// + /// \see Connect + /// + //////////////////////////////////////////////////////////// + void Disconnect(); + + //////////////////////////////////////////////////////////// + /// \brief Send raw data to the remote peer + /// + /// This function will fail if the socket is not connected. + /// + /// \param data Pointer to the sequence of bytes to send + /// \param size Number of bytes to send + /// + /// \return Status code + /// + /// \see Receive + /// + //////////////////////////////////////////////////////////// + Status Send(const char* data, std::size_t size); + + //////////////////////////////////////////////////////////// + /// \brief Receive raw data from the remote peer + /// + /// In blocking mode, this function will wait until some + /// bytes are actually received. + /// This function will fail if the socket is not connected. + /// + /// \param data Pointer to the array to fill with the received bytes + /// \param size Maximum number of bytes that can be received + /// \param received This variable is filled with the actual number of bytes received + /// + /// \return Status code + /// + /// \see Send + /// + //////////////////////////////////////////////////////////// + Status Receive(char* data, std::size_t size, std::size_t& received); + + //////////////////////////////////////////////////////////// + /// \brief Send a formatted packet of data to the remote peer + /// + /// This function will fail if the socket is not connected. + /// + /// \param packet Packet to send + /// + /// \return Status code + /// + /// \see Receive + /// + //////////////////////////////////////////////////////////// + Status Send(Packet& packet); + + //////////////////////////////////////////////////////////// + /// \brief Receive a formatted packet of data from the remote peer + /// + /// In blocking mode, this function will wait until the whole packet + /// has been received. + /// This function will fail if the socket is not connected. + /// + /// \param packet Packet to fill with the received data + /// + /// \return Status code + /// + /// \see Send + /// + //////////////////////////////////////////////////////////// + Status Receive(Packet& packet); + + friend class TcpListener; +}; + +} // namespace sf + + +#endif // SFML_TCPSOCKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::TcpSocket +/// +/// TCP is a connected protocol, which means that a TCP +/// socket can only communicate with the host it is connected +/// to. It can't send or receive anything if it is not connected. +/// +/// The TCP protocol is reliable but adds a slight overhead. +/// It ensures that your data will always be received in order +/// and without errors (no data corrupted, lost or duplicated). +/// +/// When a socket is connected to a remote host, you can +/// retrieve informations about this host with the +/// GetRemoteAddress and GetRemotePort functions. You can +/// also get the local port to which the socket is bound +/// (which is automatically chosen when the socket is connected), +/// with the GetLocalPort function. +/// +/// Sending and receiving data can use either the low-level +/// or the high-level functions. The low-level functions +/// process a raw sequence of bytes, and cannot ensure that +/// one call to Send will exactly match one call to Receive +/// at the other end of the socket. +/// +/// The high-level interface uses packets (see sf::Packet), +/// which are easier to use and provide more safety regarding +/// the data that is exchanged. You can look at the sf::Packet +/// class to get more details about how they work. +/// +/// The socket is automatically disconnected when it is destroyed, +/// but if you want to explicitely close the connection while +/// the socket instance is still alive, you can call Disconnect. +/// +/// Usage example: +/// \code +/// // ----- The client ----- +/// +/// // Create a socket and connect it to 192.168.1.50 on port 55001 +/// sf::TcpSocket socket; +/// socket.Connect("192.168.1.50", 55001); +/// +/// // Send a message to the connected host +/// std::string message = "Hi, I am a client"; +/// socket.Send(message.c_str(), message.size() + 1); +/// +/// // Receive an answer from the server +/// char buffer[1024]; +/// std::size_t received = 0; +/// socket.Receive(buffer, sizeof(buffer), received); +/// std::cout << "The server said: " << buffer << std::endl; +/// } +/// +/// // ----- The server ----- +/// +/// // Create a listener to wait for incoming connections on port 55001 +/// sf::TcpListener listener; +/// listener.Listen(55001); +/// +/// // Wait for a connection +/// sf::TcpSocket socket; +/// listener.Accept(socket); +/// std::cout << "New client connected: " << socket.GetRemoteAddress() << std::endl; +/// +/// // Receive a message from the client +/// char buffer[1024]; +/// std::size_t received = 0; +/// socket.Receive(buffer, sizeof(buffer), received); +/// std::cout << "The client said: " << buffer << std::endl; +/// +/// // Send an answer +/// std::string message = "Welcome, client"; +/// socket.Send(message.c_str(), message.size() + 1); +/// } +/// \endcode +/// +/// \see sf::Socket, sf::UdpSocket, sf::Packet +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/UdpSocket.hpp b/include/SFML/Network/UdpSocket.hpp new file mode 100644 index 00000000..00b0f885 --- /dev/null +++ b/include/SFML/Network/UdpSocket.hpp @@ -0,0 +1,242 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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_UDPSOCKET_HPP +#define SFML_UDPSOCKET_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +class IpAddress; +class Packet; + +//////////////////////////////////////////////////////////// +/// \brief Specialized socket using the UDP protocol +/// +//////////////////////////////////////////////////////////// +class SFML_API UdpSocket : public Socket +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + UdpSocket(); + + //////////////////////////////////////////////////////////// + /// \brief Get the port to which the socket is bound locally + /// + /// If the socket is not bound to a port, this function + /// returns 0. + /// + /// \return Port to which the socket is bound + /// + /// \see Bind + /// + //////////////////////////////////////////////////////////// + unsigned short GetLocalPort() const; + + //////////////////////////////////////////////////////////// + /// \brief Bind the socket to a specific port + /// + /// Binding the socket to a port is necessary for being + /// able to receive data on that port. + /// You can use the special value Socket::AnyPort to tell the + /// system to automatically pick an available port, and then + /// call GetLocalPort to retrieve the chosen port. + /// + /// \param port Port to bind the socket to + /// + /// \return Status code + /// + /// \see Unbind, GetLocalPort + /// + //////////////////////////////////////////////////////////// + Status Bind(unsigned short port); + + //////////////////////////////////////////////////////////// + /// \brief Unbind the socket from the local port to which it is bound + /// + /// The port that the socket was previously using is immediately + /// available after this function is called. If the + /// socket is not bound to a port, this function has no effect. + /// + /// \see Bind + /// + //////////////////////////////////////////////////////////// + void Unbind(); + + //////////////////////////////////////////////////////////// + /// \brief Send raw data to a remote peer + /// + /// \param data Pointer to the sequence of bytes to send + /// \param size Number of bytes to send + /// \param remoteAddress Address of the receiver + /// \param remotePort Port of the receiver to send the data to + /// + /// \return Status code + /// + /// \see Receive + /// + //////////////////////////////////////////////////////////// + Status Send(const char* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort); + + //////////////////////////////////////////////////////////// + /// \brief Receive raw data from a remote peer + /// + /// In blocking mode, this function will wait until some + /// bytes are actually received. + /// + /// \param data Pointer to the array to fill with the received bytes + /// \param size Maximum number of bytes that can be received + /// \param received This variable is filled with the actual number of bytes received + /// \param remoteAddress Address of the peer that sent the data + /// \param remotePort Port of the peer that sent the data + /// + /// \return Status code + /// + /// \see Send + /// + //////////////////////////////////////////////////////////// + Status Receive(char* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort); + + //////////////////////////////////////////////////////////// + /// \brief Send a formatted packet of data to a remote peer + /// + /// \param packet Packet to send + /// \param remoteAddress Address of the receiver + /// \param remotePort Port of the receiver to send the data to + /// + /// \return Status code + /// + /// \see Receive + /// + //////////////////////////////////////////////////////////// + Status Send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort); + + //////////////////////////////////////////////////////////// + /// \brief Receive a formatted packet of data from a remote peer + /// + /// In blocking mode, this function will wait until the whole packet + /// has been received. + /// + /// \param packet Packet to fill with the received data + /// \param remoteAddress Address of the peer that sent the data + /// \param remotePort Port of the peer that sent the data + /// + /// \return Status code + /// + /// \see Send + /// + //////////////////////////////////////////////////////////// + Status Receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort); +}; + +} // namespace sf + + +#endif // SFML_UDPSOCKET_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::UdpSocket +/// +/// A UDP socket is a connectionless socket. Instead of +/// connecting once to a remote host, like TCP sockets, +/// it can send to and receive from any host at any time. +/// +/// The UDP protocol is lightweight but unreliable. Unreliable +/// means that the data may be corrupted, duplicated, lost or +/// arrive out of order. UDP is generally used for real-time +/// communication (audio or video streaming, real-time games, +/// etc.) where speed is crucial and corrupted data +/// doesn't matter much. +/// +/// Sending and receiving data can use either the low-level +/// or the high-level functions. The low-level functions +/// process a raw sequence of bytes, and cannot ensure that +/// one call to Send will exactly match one call to Receive +/// at the other end of the socket. +/// +/// The high-level interface uses packets (see sf::Packet), +/// which are easier to use and provide more safety regarding +/// the data that is exchanged. You can look at the sf::Packet +/// class to get more details about how they work. +/// +/// If the socket is bound to a port, it is automatically +/// unbound from it when the socket is destroyed. However, +/// you can unbind the socket explicitely with the Unbind +/// function if necessary, to stop receiving messages or +/// make the port available for other sockets. +/// +/// Usage example: +/// \code +/// // ----- The client ----- +/// +/// // Create a socket and bind it to the port 55001 +/// sf::UdpSocket socket; +/// socket.Bind(55001); +/// +/// // Send a message to 192.168.1.50 on port 55002 +/// std::string message = "Hi, I am " + sf::IpAddress::GetLocalAddress().ToString(); +/// socket.Send(message.c_str(), message.size() + 1, "192.168.1.50", 55002); +/// +/// // Receive an answer (most likely from 192.168.1.50, but could be anyone else) +/// char buffer[1024]; +/// std::size_t received = 0; +/// sf::IpAddress sender; +/// unsigned short port; +/// socket.Receive(buffer, sizeof(buffer), received, sender, port); +/// std::cout << sender.ToString() << " said: " << buffer << std::endl; +/// } +/// +/// // ----- The server ----- +/// +/// // Create a socket and bind it to the port 55002 +/// sf::UdpSocket socket; +/// socket.Bind(55002); +/// +/// // Receive a message from anyone +/// char buffer[1024]; +/// std::size_t received = 0; +/// sf::IpAddress sender; +/// unsigned short port; +/// socket.Receive(buffer, sizeof(buffer), received, sender, port); +/// std::cout << sender.ToString() << " said: " << buffer << std::endl; +/// +/// // Send an answer +/// std::string message = "Welcome " + sender.ToString(); +/// socket.Send(message.c_str(), message.size() + 1, sender, port); +/// } +/// \endcode +/// +/// \see sf::Socket, sf::TcpSocket, sf::Packet +/// +//////////////////////////////////////////////////////////// diff --git a/samples/ftp/Ftp.cpp b/samples/ftp/Ftp.cpp index b7882aa5..330bf9be 100644 --- a/samples/ftp/Ftp.cpp +++ b/samples/ftp/Ftp.cpp @@ -90,7 +90,7 @@ int main() case 1 : { - // Print current server directory + // Print the current server directory sf::Ftp::DirectoryResponse response = server.GetWorkingDirectory(); std::cout << response << std::endl; std::cout << "Current directory is " << response.GetDirectory() << std::endl; @@ -99,11 +99,12 @@ int main() case 2 : { - // Print content of current server directory + // Print the contents of the current server directory sf::Ftp::ListingResponse response = server.GetDirectoryListing(); std::cout << response << std::endl; - for (std::size_t i = 0; i < response.GetCount(); ++i) - std::cout << response.GetFilename(i) << std::endl; + std::vector filenames = response.GetFilenames(); + for (std::vector::const_iterator it = filenames.begin(); it != filenames.end(); ++it) + std::cout << *it << std::endl; break; } @@ -123,7 +124,7 @@ int main() std::string directory; std::cout << "Name of the directory to create: "; std::cin >> directory; - std::cout << server.MakeDirectory(directory) << std::endl; + std::cout << server.CreateDirectory(directory) << std::endl; break; } diff --git a/samples/sockets/Sockets.cpp b/samples/sockets/Sockets.cpp index 21cb97f1..1fd40565 100644 --- a/samples/sockets/Sockets.cpp +++ b/samples/sockets/Sockets.cpp @@ -6,14 +6,10 @@ #include -//////////////////////////////////////////////////////////// -// Function prototypes -// (I'm too lazy to put them into separate headers...) -//////////////////////////////////////////////////////////// -void DoClientTCP(unsigned short Port); -void DoClientUDP(unsigned short Port); -void DoServerTCP(unsigned short Port); -void DoServerUDP(unsigned short Port); +void RunTcpServer(unsigned short Port); +void RunTcpClient(unsigned short Port); +void RunUdpServer(unsigned short Port); +void RunUdpClient(unsigned short Port); //////////////////////////////////////////////////////////// @@ -24,34 +20,34 @@ void DoServerUDP(unsigned short Port); //////////////////////////////////////////////////////////// int main() { - // Choose a random port for opening sockets (ports < 1024 are reserved) - const unsigned short port = 2435; + // Choose an arbitrary port for opening sockets + const unsigned short port = 50001; - // TCP or UDP ? + // TCP, UDP or connected UDP ? char protocol; - std::cout << "Do you want to use TCP ('t') or UDP ('u') ? "; + std::cout << "Do you want to use TCP (t) or UDP (u) ? "; std::cin >> protocol; // Client or server ? char who; - std::cout << "Do you want to be a server ('s') or a client ('c') ? "; + std::cout << "Do you want to be a server (s) or a client (c) ? "; std::cin >> who; - if (who == 's') + if (protocol == 't') { - // Run as a server - if (protocol == 't') - DoServerTCP(port); + // Test the TCP protocol + if (who == 's') + RunTcpServer(port); else - DoServerUDP(port); + RunTcpClient(port); } else { - // Run as a client - if (protocol == 't') - DoClientTCP(port); + // Test the unconnected UDP protocol + if (who == 's') + RunUdpServer(port); else - DoClientUDP(port); + RunUdpClient(port); } // Wait until the user presses 'enter' key diff --git a/samples/sockets/TCP.cpp b/samples/sockets/TCP.cpp index 124ffe06..473d06e4 100644 --- a/samples/sockets/TCP.cpp +++ b/samples/sockets/TCP.cpp @@ -7,87 +7,75 @@ //////////////////////////////////////////////////////////// -/// Create a client and connect it to a running server +/// Launch a server, wait for an incoming connection, +/// send a message and wait for the answer. /// //////////////////////////////////////////////////////////// -void DoClientTCP(unsigned short port) +void RunTcpServer(unsigned short port) { - // Ask for server address - sf::IpAddress serverAddress; - do - { - std::cout << "Type address or name of the server to connect to : "; - std::cin >> serverAddress; - } - while (serverAddress == sf::IpAddress::None); + // Create a server socket to accept new connections + sf::TcpListener listener; - // Create a TCP socket for communicating with server - sf::SocketTCP client; - - // Connect to the specified server - if (client.Connect(port, serverAddress) != sf::Socket::Done) - return; - std::cout << "Connected to server " << serverAddress << std::endl; - - // Receive a message from the client - char message[128]; - std::size_t received; - if (client.Receive(message, sizeof(message), received) != sf::Socket::Done) - return; - - // Show it - std::cout << "Message received from server : \"" << message << "\"" << std::endl; - - // Define a message to send back to the server - char toSend[] = "Hi, I'm a client !"; - - // Send the message - if (client.Send(toSend, sizeof(toSend)) != sf::Socket::Done) - return; - std::cout << "Message sent to server : \"" << toSend << "\"" << std::endl; - - // Close the socket when we're done - client.Close(); -} - - -//////////////////////////////////////////////////////////// -/// Launch a server and wait for incoming connections -/// -//////////////////////////////////////////////////////////// -void DoServerTCP(unsigned short port) -{ - // Create a TCP socket for communicating with clients - sf::SocketTCP server; - - // Listen to a port for incoming connections - if (!server.Listen(port)) + // Listen to the given port for incoming connections + if (listener.Listen(port) != sf::Socket::Done) return; std::cout << "Server is listening to port " << port << ", waiting for connections... " << std::endl; // Wait for a connection - sf::IpAddress clientAddress; - sf::SocketTCP client; - if (server.Accept(client, &clientAddress) != sf::Socket::Done) + sf::TcpSocket socket; + if (listener.Accept(socket) != sf::Socket::Done) return; - std::cout << "Client connected : " << clientAddress << std::endl; + std::cout << "Client connected: " << socket.GetRemoteAddress() << std::endl; - // Send a message to the client - char toSend[] = "Hi, I'm the server"; - if (client.Send(toSend, sizeof(toSend)) != sf::Socket::Done) + // Send a message to the connected client + const char out[] = "Hi, I'm the server"; + if (socket.Send(out, sizeof(out)) != sf::Socket::Done) return; - std::cout << "Message sent to the client : \"" << toSend << "\"" << std::endl; + std::cout << "Message sent to the client: \"" << out << "\"" << std::endl; // Receive a message back from the client - char message[128]; + char in[128]; std::size_t received; - if (client.Receive(message, sizeof(message), received) != sf::Socket::Done) + if (socket.Receive(in, sizeof(in), received) != sf::Socket::Done) return; - - // Show the message - std::cout << "Message received from the client : \"" << message << "\"" << std::endl; - - // Close the sockets when we're done - client.Close(); - server.Close(); + std::cout << "Answer received from the client: \"" << in << "\"" << std::endl; +} + + +//////////////////////////////////////////////////////////// +/// Create a client, connect it to a server, display the +/// welcome message and send an answer. +/// +//////////////////////////////////////////////////////////// +void RunTcpClient(unsigned short port) +{ + // Ask for the server address + sf::IpAddress server; + do + { + std::cout << "Type the address or name of the server to connect to: "; + std::cin >> server; + } + while (server == sf::IpAddress::None); + + // Create a socket for communicating with the server + sf::TcpSocket socket; + + // Connect to the server + if (socket.Connect(server, port) != sf::Socket::Done) + return; + std::cout << "Connected to server " << server << std::endl; + + // Receive a message from the server + char in[128]; + std::size_t received; + if (socket.Receive(in, sizeof(in), received) != sf::Socket::Done) + return; + std::cout << "Message received from the server: \"" << in << "\"" << std::endl; + + // Send an answer to the server + const char out[] = "Hi, I'm a client"; + if (socket.Send(out, sizeof(out)) != sf::Socket::Done) + return; + std::cout << "Message sent to the server: \"" << out << "\"" << std::endl; } diff --git a/samples/sockets/UDP.cpp b/samples/sockets/UDP.cpp index fa520cb0..0cfcb0df 100644 --- a/samples/sockets/UDP.cpp +++ b/samples/sockets/UDP.cpp @@ -7,59 +7,66 @@ //////////////////////////////////////////////////////////// -/// Create a client and send a message to a running server +/// Launch a server, wait for a message, send an answer. /// //////////////////////////////////////////////////////////// -void DoClientUDP(unsigned short port) +void RunUdpServer(unsigned short port) { - // Ask for server address - sf::IpAddress serverAddress; + // Create a socket to receive a message from anyone + sf::UdpSocket socket; + + // Listen to messages on the specified port + if (socket.Bind(port) != sf::Socket::Done) + return; + std::cout << "Server is listening to port " << port << ", waiting for a message... " << std::endl; + + // Wait for a message + char in[128]; + std::size_t received; + sf::IpAddress sender; + unsigned short senderPort; + if (socket.Receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done) + return; + std::cout << "Message received from client " << sender << ": \"" << in << "\"" << std::endl; + + // Send an answer to the client + const char out[] = "Hi, I'm the server"; + if (socket.Send(out, sizeof(out), sender, senderPort) != sf::Socket::Done) + return; + std::cout << "Message sent to the client: \"" << out << "\"" << std::endl; +} + + +//////////////////////////////////////////////////////////// +/// Send a message to the server, wait for the answer +/// +//////////////////////////////////////////////////////////// +void RunUdpClient(unsigned short port) +{ + // Ask for the server address + sf::IpAddress server; do { - std::cout << "Type address or name of the server to send the message to : "; - std::cin >> serverAddress; + std::cout << "Type the address or name of the server to connect to: "; + std::cin >> server; } - while (serverAddress == sf::IpAddress::None); + while (server == sf::IpAddress::None); - // Create a UDP socket for communicating with server - sf::SocketUDP client; + // Create a socket for communicating with the server + sf::UdpSocket socket; // Send a message to the server - char message[] = "Hi, I'm a client !"; - if (client.Send(message, sizeof(message), serverAddress, port) != sf::Socket::Done) + const char out[] = "Hi, I'm a client"; + if (socket.Send(out, sizeof(out), server, port) != sf::Socket::Done) return; - std::cout << "Message sent to server : \"" << message << "\"" << std::endl; + std::cout << "Message sent to the server: \"" << out << "\"" << std::endl; - // Close the socket when we're done - client.Close(); -} - - -//////////////////////////////////////////////////////////// -/// Launch a server and wait for incoming messages -/// -//////////////////////////////////////////////////////////// -void DoServerUDP(unsigned short port) -{ - // Create a UDP socket for communicating with clients - sf::SocketUDP server; - - // Bind it to the specified port - if (!server.Bind(port)) - return; - - // Receive a message from anyone - sf::IpAddress clientAddress; - unsigned short clientPort; - char message[128]; + // Receive an answer from anyone (but most likely from the server) + char in[128]; std::size_t received; - if (server.Receive(message, sizeof(message), received, clientAddress, clientPort) != sf::Socket::Done) + sf::IpAddress sender; + unsigned short senderPort; + if (socket.Receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done) return; - - // Display it - std::cout << "Message received from " << clientAddress << " on port " << clientPort - << ": \"" << message << "\"" << std::endl; - - // Close the socket when we're done - server.Close(); + std::cout << "Message received from " << sender << ": \"" << in << "\"" << std::endl; } diff --git a/samples/voip/Client.cpp b/samples/voip/Client.cpp index e397eece..f44bb918 100644 --- a/samples/voip/Client.cpp +++ b/samples/voip/Client.cpp @@ -22,17 +22,35 @@ public : //////////////////////////////////////////////////////////// /// Constructor /// - /// \param Socket : Socket that holds the connection with the server + /// \param host Remote host to which send the recording data + /// \param port Port of the remote host /// //////////////////////////////////////////////////////////// - NetworkRecorder(sf::SocketTCP socket) : - mySocket(socket) + NetworkRecorder(const sf::IpAddress& host, unsigned short port) : + myHost(host), + myPort(port) { - } private : + //////////////////////////////////////////////////////////// + /// /see SoundRecorder::OnStart + /// + //////////////////////////////////////////////////////////// + virtual bool OnStart() + { + if (mySocket.Connect(myHost, myPort) == sf::Socket::Done) + { + std::cout << "Connected to server " << myHost << std::endl; + return true; + } + else + { + return false; + } + } + //////////////////////////////////////////////////////////// /// /see SoundRecorder::ProcessSamples /// @@ -48,10 +66,27 @@ private : return mySocket.Send(packet) == sf::Socket::Done; } + //////////////////////////////////////////////////////////// + /// /see SoundRecorder::OnStop + /// + //////////////////////////////////////////////////////////// + virtual void OnStop() + { + // Send a "end-of-stream" packet + sf::Packet packet; + packet << endOfStream; + mySocket.Send(packet); + + // Close the socket + mySocket.Disconnect(); + } + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - sf::SocketTCP mySocket; ///< Socket used to communicate with the server + sf::IpAddress myHost; ///< Address of the remote host + unsigned short myPort; ///< Remote port + sf::TcpSocket mySocket; ///< Socket used to communicate with the server }; @@ -70,41 +105,25 @@ void DoClient(unsigned short port) } // Ask for server address - sf::IpAddress serverAddress; + sf::IpAddress server; do { std::cout << "Type address or name of the server to connect to : "; - std::cin >> serverAddress; + std::cin >> server; } - while (serverAddress == sf::IpAddress::None); + while (server == sf::IpAddress::None); - // Create a TCP socket for communicating with server - sf::SocketTCP socket; - - // Connect to the specified server - if (socket.Connect(port, serverAddress) != sf::Socket::Done) - return; - std::cout << "Connected to server " << serverAddress << std::endl; + // Create an instance of our custom recorder + NetworkRecorder recorder(server, port); // Wait for user input... std::cin.ignore(10000, '\n'); std::cout << "Press enter to start recording audio"; std::cin.ignore(10000, '\n'); - // Create a instance of our custom recorder - NetworkRecorder recorder(socket); - // Start capturing audio data recorder.Start(44100); std::cout << "Recording... press enter to stop"; std::cin.ignore(10000, '\n'); recorder.Stop(); - - // Send a "end-of-stream" packet - sf::Packet packet; - packet << endOfStream; - socket.Send(packet); - - // Close the socket when we're done - socket.Close(); } diff --git a/samples/voip/Server.cpp b/samples/voip/Server.cpp index 965e72ab..784ea02c 100644 --- a/samples/voip/Server.cpp +++ b/samples/voip/Server.cpp @@ -32,17 +32,6 @@ public : Initialize(1, 44100); } - //////////////////////////////////////////////////////////// - /// Destructor - /// - //////////////////////////////////////////////////////////// - ~NetworkAudioStream() - { - // Close the sockets - myClient.Close(); - myListener.Close(); - } - //////////////////////////////////////////////////////////// /// Run the server, stream audio data from the client /// @@ -52,14 +41,14 @@ public : if (!myHasFinished) { // Listen to the given port for incoming connections - if (!myListener.Listen(port)) + if (myListener.Listen(port) != sf::Socket::Done) return; std::cout << "Server is listening to port " << port << ", waiting for connections... " << std::endl; // Wait for a connection - sf::IpAddress clientAddress; - myListener.Accept(myClient, &clientAddress); - std::cout << "Client connected : " << clientAddress << std::endl; + if (myListener.Accept(myClient) != sf::Socket::Done) + return; + std::cout << "Client connected: " << myClient.GetRemoteAddress() << std::endl; // Start playback Play(); @@ -149,7 +138,7 @@ private : else if (id == endOfStream) { // End of stream reached : we stop receiving audio data - std::cout << "Audio data has been 100% received !" << std::endl; + std::cout << "Audio data has been 100% received!" << std::endl; myHasFinished = true; } else @@ -164,8 +153,8 @@ private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - sf::SocketTCP myListener; - sf::SocketTCP myClient; + sf::TcpListener myListener; + sf::TcpSocket myClient; sf::Mutex myMutex; std::vector mySamples; std::vector myTempBuffer; diff --git a/src/SFML/Network/Ftp.cpp b/src/SFML/Network/Ftp.cpp index f592fed7..e4855223 100644 --- a/src/SFML/Network/Ftp.cpp +++ b/src/SFML/Network/Ftp.cpp @@ -36,35 +36,19 @@ 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); @@ -74,12 +58,10 @@ private : // Member data //////////////////////////////////////////////////////////// Ftp& myFtp; ///< Reference to the owner Ftp instance - SocketTCP myDataSocket; ///< Socket used for data transfers + TcpSocket myDataSocket; ///< Socket used for data transfers }; -//////////////////////////////////////////////////////////// -/// Default constructor //////////////////////////////////////////////////////////// Ftp::Response::Response(Status code, const std::string& message) : myStatus (code), @@ -89,9 +71,6 @@ myMessage(message) } -//////////////////////////////////////////////////////////// -/// Convenience function to check if the response status code -/// means a success //////////////////////////////////////////////////////////// bool Ftp::Response::IsOk() const { @@ -99,8 +78,6 @@ bool Ftp::Response::IsOk() const } -//////////////////////////////////////////////////////////// -/// Get the response status code //////////////////////////////////////////////////////////// Ftp::Response::Status Ftp::Response::GetStatus() const { @@ -108,8 +85,6 @@ Ftp::Response::Status Ftp::Response::GetStatus() const } -//////////////////////////////////////////////////////////// -/// Get the full message contained in the response //////////////////////////////////////////////////////////// const std::string& Ftp::Response::GetMessage() const { @@ -118,23 +93,19 @@ const std::string& Ftp::Response::GetMessage() const //////////////////////////////////////////////////////////// -/// Default constructor -//////////////////////////////////////////////////////////// -Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response response) : +Ftp::DirectoryResponse::DirectoryResponse(const Ftp::Response& response) : Ftp::Response(response) { if (IsOk()) { // Extract the directory from the server response - std::string::size_type begin = response.GetMessage().find('"', 0); - std::string::size_type end = response.GetMessage().find('"', begin + 1); - myDirectory = response.GetMessage().substr(begin + 1, end - begin - 1); + std::string::size_type begin = GetMessage().find('"', 0); + std::string::size_type end = GetMessage().find('"', begin + 1); + myDirectory = GetMessage().substr(begin + 1, end - begin - 1); } } -//////////////////////////////////////////////////////////// -/// Get the directory returned in the response //////////////////////////////////////////////////////////// const std::string& Ftp::DirectoryResponse::GetDirectory() const { @@ -143,9 +114,7 @@ const std::string& Ftp::DirectoryResponse::GetDirectory() const //////////////////////////////////////////////////////////// -/// Default constructor -//////////////////////////////////////////////////////////// -Ftp::ListingResponse::ListingResponse(Ftp::Response response, const std::vector& data) : +Ftp::ListingResponse::ListingResponse(const Ftp::Response& response, const std::vector& data) : Ftp::Response(response) { if (IsOk()) @@ -163,25 +132,12 @@ Ftp::Response(response) //////////////////////////////////////////////////////////// -/// Get the number of filenames in the listing -//////////////////////////////////////////////////////////// -std::size_t Ftp::ListingResponse::GetCount() const +const std::vector& Ftp::ListingResponse::GetFilenames() const { - return myFilenames.size(); + return myFilenames; } -//////////////////////////////////////////////////////////// -/// 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() { @@ -189,13 +145,11 @@ Ftp::~Ftp() } -//////////////////////////////////////////////////////////// -/// 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) + if (myCommandSocket.Connect(server, port, timeout) != Socket::Done) return Response(Response::ConnectionFailed); // Get the response to the connection @@ -203,8 +157,6 @@ Ftp::Response Ftp::Connect(const IpAddress& server, unsigned short port, float t } -//////////////////////////////////////////////////////////// -/// Log in using anonymous account //////////////////////////////////////////////////////////// Ftp::Response Ftp::Login() { @@ -212,8 +164,6 @@ Ftp::Response Ftp::Login() } -//////////////////////////////////////////////////////////// -/// Log in using a username and a password //////////////////////////////////////////////////////////// Ftp::Response Ftp::Login(const std::string& name, const std::string& password) { @@ -225,22 +175,18 @@ Ftp::Response Ftp::Login(const std::string& name, const std::string& password) } -//////////////////////////////////////////////////////////// -/// Close the connection with FTP server //////////////////////////////////////////////////////////// Ftp::Response Ftp::Disconnect() { // Send the exit command Response response = SendCommand("QUIT"); if (response.IsOk()) - myCommandSocket.Close(); + myCommandSocket.Disconnect(); return response; } -//////////////////////////////////////////////////////////// -/// Send a null command just to prevent from being disconnected //////////////////////////////////////////////////////////// Ftp::Response Ftp::KeepAlive() { @@ -248,8 +194,6 @@ Ftp::Response Ftp::KeepAlive() } -//////////////////////////////////////////////////////////// -/// Get the current working directory //////////////////////////////////////////////////////////// Ftp::DirectoryResponse Ftp::GetWorkingDirectory() { @@ -257,9 +201,6 @@ Ftp::DirectoryResponse Ftp::GetWorkingDirectory() } -//////////////////////////////////////////////////////////// -/// Get the contents of the given directory -/// (subdirectories and files) //////////////////////////////////////////////////////////// Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& directory) { @@ -285,8 +226,6 @@ Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& directory) } -//////////////////////////////////////////////////////////// -/// Change the current working directory //////////////////////////////////////////////////////////// Ftp::Response Ftp::ChangeDirectory(const std::string& directory) { @@ -294,8 +233,6 @@ Ftp::Response Ftp::ChangeDirectory(const std::string& directory) } -//////////////////////////////////////////////////////////// -/// Go to the parent directory of the current one //////////////////////////////////////////////////////////// Ftp::Response Ftp::ParentDirectory() { @@ -304,16 +241,12 @@ Ftp::Response Ftp::ParentDirectory() //////////////////////////////////////////////////////////// -/// Create a new directory -//////////////////////////////////////////////////////////// -Ftp::Response Ftp::MakeDirectory(const std::string& name) +Ftp::Response Ftp::CreateDirectory(const std::string& name) { return SendCommand("MKD", name); } -//////////////////////////////////////////////////////////// -/// Remove an existing directory //////////////////////////////////////////////////////////// Ftp::Response Ftp::DeleteDirectory(const std::string& name) { @@ -321,8 +254,6 @@ Ftp::Response Ftp::DeleteDirectory(const std::string& name) } -//////////////////////////////////////////////////////////// -/// Rename a file //////////////////////////////////////////////////////////// Ftp::Response Ftp::RenameFile(const std::string& file, const std::string& newName) { @@ -334,8 +265,6 @@ Ftp::Response Ftp::RenameFile(const std::string& file, const std::string& newNam } -//////////////////////////////////////////////////////////// -/// Remove an existing file //////////////////////////////////////////////////////////// Ftp::Response Ftp::DeleteFile(const std::string& name) { @@ -344,9 +273,7 @@ Ftp::Response Ftp::DeleteFile(const std::string& name) //////////////////////////////////////////////////////////// -/// Download a file from the server -//////////////////////////////////////////////////////////// -Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& destPath, TransferMode mode) +Ftp::Response Ftp::Download(const std::string& remoteFile, const std::string& localPath, TransferMode mode) { // Open a data channel using the given transfer mode DataChannel data(*this); @@ -354,7 +281,7 @@ Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& d if (response.IsOk()) { // Tell the server to start the transfer - response = SendCommand("RETR", distantFile); + response = SendCommand("RETR", remoteFile); if (response.IsOk()) { // Receive the file data @@ -366,13 +293,13 @@ Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& d if (response.IsOk()) { // Extract the filename from the file path - std::string filename = distantFile; + std::string filename = remoteFile; 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; + std::string path = localPath; if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/')) path += "/"; @@ -392,9 +319,7 @@ Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& d //////////////////////////////////////////////////////////// -/// Upload a file to the server -//////////////////////////////////////////////////////////// -Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& destPath, TransferMode mode) +Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& remotePath, TransferMode mode) { // Get the contents of the file to send std::ifstream file(localFile.c_str(), std::ios_base::binary); @@ -415,7 +340,7 @@ Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& destP filename = filename.substr(pos + 1); // Make sure the destination path ends with a slash - std::string path = destPath; + std::string path = remotePath; if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/')) path += "/"; @@ -440,8 +365,6 @@ Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& destP } -//////////////////////////////////////////////////////////// -/// Send a command to the FTP server //////////////////////////////////////////////////////////// Ftp::Response Ftp::SendCommand(const std::string& command, const std::string& parameter) { @@ -461,9 +384,6 @@ Ftp::Response Ftp::SendCommand(const std::string& command, const std::string& pa } -//////////////////////////////////////////////////////////// -/// Receive a response from the server -/// (usually after a command has been sent) //////////////////////////////////////////////////////////// Ftp::Response Ftp::GetResponse() { @@ -596,8 +516,6 @@ Ftp::Response Ftp::GetResponse() } -//////////////////////////////////////////////////////////// -/// Constructor //////////////////////////////////////////////////////////// Ftp::DataChannel::DataChannel(Ftp& owner) : myFtp(owner) @@ -606,18 +524,6 @@ 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) { @@ -653,7 +559,7 @@ Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode mode) static_cast(data[3])); // Connect the data channel to the server - if (myDataSocket.Connect(port, address) == Socket::Done) + if (myDataSocket.Connect(address, port) == Socket::Done) { // Translate the transfer mode to the corresponding FTP parameter std::string modeStr; @@ -679,8 +585,6 @@ Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode mode) } -//////////////////////////////////////////////////////////// -/// Receive data on the data channel until it is closed //////////////////////////////////////////////////////////// void Ftp::DataChannel::Receive(std::vector& data) { @@ -694,12 +598,10 @@ void Ftp::DataChannel::Receive(std::vector& data) } // Close the data socket - myDataSocket.Close(); + myDataSocket.Disconnect(); } -//////////////////////////////////////////////////////////// -/// Send data on the data channel //////////////////////////////////////////////////////////// void Ftp::DataChannel::Send(const std::vector& data) { @@ -708,7 +610,7 @@ void Ftp::DataChannel::Send(const std::vector& data) myDataSocket.Send(&data[0], data.size()); // Close the data socket - myDataSocket.Close(); + myDataSocket.Disconnect(); } } // namespace sf diff --git a/src/SFML/Network/Http.cpp b/src/SFML/Network/Http.cpp index 65829b65..8b15dba8 100644 --- a/src/SFML/Network/Http.cpp +++ b/src/SFML/Network/Http.cpp @@ -32,16 +32,16 @@ #include +//////////////////////////////////////////////////////////// +// Private data +//////////////////////////////////////////////////////////// namespace { - //////////////////////////////////////////////////////////// - // Convenience function to convert a string to lower case - //////////////////////////////////////////////////////////// + // Convert a string to lower case std::string ToLower(std::string str) { for (std::string::iterator i = str.begin(); i != str.end(); ++i) *i = static_cast(tolower(*i)); - return str; } } @@ -50,19 +50,15 @@ namespace namespace sf { //////////////////////////////////////////////////////////// -/// Default constructor -//////////////////////////////////////////////////////////// -Http::Request::Request(Method method, const std::string& URI, const std::string& body) +Http::Request::Request(const std::string& uri, Method method, const std::string& body) { SetMethod(method); - SetURI(URI); + SetUri(uri); SetHttpVersion(1, 0); SetBody(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) { @@ -70,9 +66,6 @@ void Http::Request::SetField(const std::string& field, const std::string& value) } -//////////////////////////////////////////////////////////// -/// Set the request method. -/// This parameter is Get by default //////////////////////////////////////////////////////////// void Http::Request::SetMethod(Http::Request::Method method) { @@ -81,12 +74,9 @@ void Http::Request::SetMethod(Http::Request::Method method) //////////////////////////////////////////////////////////// -/// Set the target URI of the request. -/// This parameter is "/" by default -//////////////////////////////////////////////////////////// -void Http::Request::SetURI(const std::string& URI) +void Http::Request::SetUri(const std::string& uri) { - myURI = URI; + myURI = uri; // Make sure it starts with a '/' if (myURI.empty() || (myURI[0] != '/')) @@ -94,9 +84,6 @@ void Http::Request::SetURI(const std::string& URI) } -//////////////////////////////////////////////////////////// -/// Set the HTTP version of the request. -/// This parameter is 1.0 by default //////////////////////////////////////////////////////////// void Http::Request::SetHttpVersion(unsigned int major, unsigned int minor) { @@ -105,10 +92,6 @@ void Http::Request::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 //////////////////////////////////////////////////////////// void Http::Request::SetBody(const std::string& body) { @@ -117,9 +100,7 @@ void Http::Request::SetBody(const std::string& body) //////////////////////////////////////////////////////////// -/// Get the string representation of a request header -//////////////////////////////////////////////////////////// -std::string Http::Request::ToString() const +std::string Http::Request::Prepare() const { std::ostringstream out; @@ -153,8 +134,6 @@ std::string Http::Request::ToString() const } -//////////////////////////////////////////////////////////// -/// Check if the given field has been defined //////////////////////////////////////////////////////////// bool Http::Request::HasField(const std::string& field) const { @@ -162,8 +141,6 @@ bool Http::Request::HasField(const std::string& field) const } -//////////////////////////////////////////////////////////// -/// Default constructor //////////////////////////////////////////////////////////// Http::Response::Response() : myStatus (ConnectionFailed), @@ -174,8 +151,6 @@ myMinorVersion(0) } -//////////////////////////////////////////////////////////// -/// Get the value of a field //////////////////////////////////////////////////////////// const std::string& Http::Response::GetField(const std::string& field) const { @@ -192,8 +167,6 @@ const std::string& Http::Response::GetField(const std::string& field) const } -//////////////////////////////////////////////////////////// -/// Get the header's status code //////////////////////////////////////////////////////////// Http::Response::Status Http::Response::GetStatus() const { @@ -201,8 +174,6 @@ Http::Response::Status Http::Response::GetStatus() const } -//////////////////////////////////////////////////////////// -/// Get the major HTTP version number of the response //////////////////////////////////////////////////////////// unsigned int Http::Response::GetMajorHttpVersion() const { @@ -210,8 +181,6 @@ unsigned int Http::Response::GetMajorHttpVersion() const } -//////////////////////////////////////////////////////////// -/// Get the major HTTP version number of the response //////////////////////////////////////////////////////////// unsigned int Http::Response::GetMinorHttpVersion() const { @@ -219,12 +188,6 @@ unsigned int Http::Response::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) //////////////////////////////////////////////////////////// const std::string& Http::Response::GetBody() const { @@ -233,9 +196,7 @@ const std::string& Http::Response::GetBody() const //////////////////////////////////////////////////////////// -/// Construct the header from a response string -//////////////////////////////////////////////////////////// -void Http::Response::FromString(const std::string& data) +void Http::Response::Parse(const std::string& data) { std::istringstream in(data); @@ -300,8 +261,6 @@ void Http::Response::FromString(const std::string& data) } -//////////////////////////////////////////////////////////// -/// Default constructor //////////////////////////////////////////////////////////// Http::Http() : myHost(), @@ -311,8 +270,6 @@ myPort(0) } -//////////////////////////////////////////////////////////// -/// Construct the Http instance with the target host //////////////////////////////////////////////////////////// Http::Http(const std::string& host, unsigned short port) { @@ -320,8 +277,6 @@ Http::Http(const std::string& host, unsigned short port) } -//////////////////////////////////////////////////////////// -/// Set the target host //////////////////////////////////////////////////////////// void Http::SetHost(const std::string& host, unsigned short port) { @@ -354,17 +309,10 @@ void Http::SetHost(const std::string& host, unsigned short port) } -//////////////////////////////////////////////////////////// -/// 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& request, float timeout) { - // First make sure the request is valid -- add missing mandatory fields + // First make sure that the request is valid -- add missing mandatory fields Request toSend(request); if (!toSend.HasField("From")) { @@ -397,10 +345,10 @@ Http::Response Http::SendRequest(const Http::Request& request, float timeout) Response received; // Connect the socket to the host - if (myConnection.Connect(myPort, myHost, timeout) == Socket::Done) + if (myConnection.Connect(myHost, myPort, timeout) == Socket::Done) { // Convert the request to string and send it through the connected socket - std::string requestStr = toSend.ToString(); + std::string requestStr = toSend.Prepare(); if (!requestStr.empty()) { @@ -417,12 +365,12 @@ Http::Response Http::SendRequest(const Http::Request& request, float timeout) } // Build the Response object from the received data - received.FromString(receivedStr); + received.Parse(receivedStr); } } // Close the connection - myConnection.Close(); + myConnection.Disconnect(); } return received; diff --git a/src/SFML/Network/IpAddress.cpp b/src/SFML/Network/IpAddress.cpp index 846fc02a..1d59378b 100644 --- a/src/SFML/Network/IpAddress.cpp +++ b/src/SFML/Network/IpAddress.cpp @@ -27,7 +27,7 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include #include @@ -135,37 +135,31 @@ IpAddress IpAddress::GetLocalAddress() IpAddress localAddress; // Create the socket - SocketHelper::SocketType sock = socket(PF_INET, SOCK_DGRAM, 0); - if (sock == SocketHelper::InvalidSocket()) + SocketHandle sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock == priv::SocketImpl::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(sock, reinterpret_cast(&sockAddr), sizeof(sockAddr)) == -1) + // Connect the socket to localhost on any port + sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_LOOPBACK, 0); + if (connect(sock, reinterpret_cast(&address), sizeof(address)) == -1) { - SocketHelper::Close(sock); + priv::SocketImpl::Close(sock); return localAddress; } // Get the local address of the socket connection - SocketHelper::LengthType size = sizeof(sockAddr); - if (getsockname(sock, reinterpret_cast(&sockAddr), &size) == -1) + priv::SocketImpl::AddrLength size = sizeof(address); + if (getsockname(sock, reinterpret_cast(&address), &size) == -1) { - SocketHelper::Close(sock); + priv::SocketImpl::Close(sock); return localAddress; } // Close the socket - SocketHelper::Close(sock); + priv::SocketImpl::Close(sock); // Finally build the IP address - localAddress.myAddress = sockAddr.sin_addr.s_addr; + localAddress.myAddress = address.sin_addr.s_addr; return localAddress; } @@ -181,7 +175,7 @@ IpAddress IpAddress::GetPublicAddress(float timeout) // (not very hard: the web page contains only our IP address). Http server("www.sfml-dev.org"); - Http::Request request(Http::Request::Get, "/ip-provider.php"); + Http::Request request("/ip-provider.php", Http::Request::Get); Http::Response page = server.SendRequest(request, timeout); if (page.GetStatus() == Http::Response::Ok) return IpAddress(page.GetBody()); diff --git a/src/SFML/Network/Packet.cpp b/src/SFML/Network/Packet.cpp index e54b0fce..8808e0e1 100644 --- a/src/SFML/Network/Packet.cpp +++ b/src/SFML/Network/Packet.cpp @@ -26,7 +26,7 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include #include #include @@ -34,8 +34,6 @@ namespace sf { //////////////////////////////////////////////////////////// -/// Default constructor -//////////////////////////////////////////////////////////// Packet::Packet() : myReadPos(0), myIsValid(true) @@ -44,8 +42,6 @@ myIsValid(true) } -//////////////////////////////////////////////////////////// -/// Virtual destructor //////////////////////////////////////////////////////////// Packet::~Packet() { @@ -53,8 +49,6 @@ Packet::~Packet() } -//////////////////////////////////////////////////////////// -/// Append data to the end of the packet //////////////////////////////////////////////////////////// void Packet::Append(const void* data, std::size_t sizeInBytes) { @@ -67,8 +61,6 @@ void Packet::Append(const void* data, std::size_t sizeInBytes) } -//////////////////////////////////////////////////////////// -/// Clear the packet data //////////////////////////////////////////////////////////// void Packet::Clear() { @@ -78,10 +70,6 @@ void Packet::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 //////////////////////////////////////////////////////////// const char* Packet::GetData() const { @@ -89,8 +77,6 @@ const char* Packet::GetData() const } -//////////////////////////////////////////////////////////// -/// Get the size of the data contained in the packet //////////////////////////////////////////////////////////// std::size_t Packet::GetDataSize() const { @@ -98,8 +84,6 @@ std::size_t Packet::GetDataSize() const } -//////////////////////////////////////////////////////////// -/// Tell if the reading position has reached the end of the packet //////////////////////////////////////////////////////////// bool Packet::EndOfPacket() const { @@ -107,8 +91,6 @@ bool Packet::EndOfPacket() const } -//////////////////////////////////////////////////////////// -/// Tell if the packet is valid for reading //////////////////////////////////////////////////////////// Packet::operator bool() const { @@ -116,8 +98,6 @@ Packet::operator bool() const } -//////////////////////////////////////////////////////////// -/// Operator >> overloads to extract data from the packet //////////////////////////////////////////////////////////// Packet& Packet::operator >>(bool& data) { @@ -127,6 +107,9 @@ Packet& Packet::operator >>(bool& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(Int8& data) { if (CheckSize(sizeof(data))) @@ -137,6 +120,9 @@ Packet& Packet::operator >>(Int8& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(Uint8& data) { if (CheckSize(sizeof(data))) @@ -147,6 +133,9 @@ Packet& Packet::operator >>(Uint8& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(Int16& data) { if (CheckSize(sizeof(data))) @@ -157,6 +146,9 @@ Packet& Packet::operator >>(Int16& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(Uint16& data) { if (CheckSize(sizeof(data))) @@ -167,6 +159,9 @@ Packet& Packet::operator >>(Uint16& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(Int32& data) { if (CheckSize(sizeof(data))) @@ -177,6 +172,9 @@ Packet& Packet::operator >>(Int32& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(Uint32& data) { if (CheckSize(sizeof(data))) @@ -187,6 +185,9 @@ Packet& Packet::operator >>(Uint32& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(float& data) { if (CheckSize(sizeof(data))) @@ -197,6 +198,9 @@ Packet& Packet::operator >>(float& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(double& data) { if (CheckSize(sizeof(data))) @@ -207,6 +211,9 @@ Packet& Packet::operator >>(double& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(char* data) { // First extract string length @@ -225,6 +232,9 @@ Packet& Packet::operator >>(char* data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(std::string& data) { // First extract string length @@ -243,6 +253,9 @@ Packet& Packet::operator >>(std::string& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(wchar_t* data) { // First extract string length @@ -263,6 +276,9 @@ Packet& Packet::operator >>(wchar_t* data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(std::wstring& data) { // First extract string length @@ -283,6 +299,9 @@ Packet& Packet::operator >>(std::wstring& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator >>(String& data) { // First extract the string length @@ -305,58 +324,83 @@ Packet& Packet::operator >>(String& data) } -//////////////////////////////////////////////////////////// -/// 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 @@ -370,6 +414,9 @@ Packet& Packet::operator <<(const char* data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator <<(const std::string& data) { // First insert string length @@ -384,6 +431,9 @@ Packet& Packet::operator <<(const std::string& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator <<(const wchar_t* data) { // First insert string length @@ -398,6 +448,9 @@ Packet& Packet::operator <<(const wchar_t* data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator <<(const std::wstring& data) { // First insert string length @@ -413,6 +466,9 @@ Packet& Packet::operator <<(const std::wstring& data) return *this; } + + +//////////////////////////////////////////////////////////// Packet& Packet::operator <<(const String& data) { // First insert the string length @@ -430,8 +486,6 @@ Packet& Packet::operator <<(const String& data) } -//////////////////////////////////////////////////////////// -/// Check if the packet can extract a given size of bytes //////////////////////////////////////////////////////////// bool Packet::CheckSize(std::size_t size) { @@ -442,21 +496,17 @@ bool Packet::CheckSize(std::size_t size) //////////////////////////////////////////////////////////// -/// Called before the packet is sent to the network -//////////////////////////////////////////////////////////// -const char* Packet::OnSend(std::size_t& dataSize) +const char* Packet::OnSend(std::size_t& size) { - dataSize = GetDataSize(); + size = GetDataSize(); return GetData(); } //////////////////////////////////////////////////////////// -/// Called after the packet has been received from the network -//////////////////////////////////////////////////////////// -void Packet::OnReceive(const char* data, std::size_t dataSize) +void Packet::OnReceive(const char* data, std::size_t size) { - Append(data, dataSize); + Append(data, size); } } // namespace sf diff --git a/src/SFML/Network/Socket.cpp b/src/SFML/Network/Socket.cpp new file mode 100644 index 00000000..382b5454 --- /dev/null +++ b/src/SFML/Network/Socket.cpp @@ -0,0 +1,155 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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 +{ +//////////////////////////////////////////////////////////// +Socket::Socket(Type type) : +myType (type), +mySocket (priv::SocketImpl::InvalidSocket()), +myIsBlocking(true) +{ + +} + + +//////////////////////////////////////////////////////////// +Socket::~Socket() +{ + // Close the socket before it gets destructed + Close(); +} + + +//////////////////////////////////////////////////////////// +void Socket::SetBlocking(bool blocking) +{ + // Apply if the socket is already created + if (mySocket != priv::SocketImpl::InvalidSocket()) + priv::SocketImpl::SetBlocking(mySocket, blocking); + + myIsBlocking = blocking; +} + + +//////////////////////////////////////////////////////////// +bool Socket::IsBlocking() const +{ + return myIsBlocking; +} + + +//////////////////////////////////////////////////////////// +SocketHandle Socket::GetHandle() const +{ + return mySocket; +} + + +//////////////////////////////////////////////////////////// +void Socket::Create() +{ + // Don't create the socket if it already exists + if (mySocket == priv::SocketImpl::InvalidSocket()) + { + SocketHandle handle = socket(PF_INET, myType == Tcp ? SOCK_STREAM : SOCK_DGRAM, 0); + Create(handle); + } +} + + +//////////////////////////////////////////////////////////// +void Socket::Create(SocketHandle handle) +{ + // Don't create the socket if it already exists + if (mySocket == priv::SocketImpl::InvalidSocket()) + { + // Assign the new handle + mySocket = handle; + + // Set the current blocking state + SetBlocking(myIsBlocking); + + // 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) + { + Err() << "Failed to set socket option \"SO_REUSEADDR\" ; " + << "binding to a same port may fail if too fast" << std::endl; + } + + if (myType == Tcp) + { + // Disable the Nagle algorithm (ie. removes buffering of TCP packets) + if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&yes), sizeof(yes)) == -1) + { + Err() << "Failed to set socket option \"TCP_NODELAY\" ; " + << "all your TCP packets will be buffered" << std::endl; + } + } + else + { + // Enable broadcast by default for UDP sockets + if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&yes), sizeof(yes)) == -1) + { + Err() << "Failed to enable broadcast on UDP socket" << std::endl; + } + } + } +} + + +//////////////////////////////////////////////////////////// +void Socket::Close() +{ + // Close the socket + if (mySocket != priv::SocketImpl::InvalidSocket()) + { + priv::SocketImpl::Close(mySocket); + mySocket = priv::SocketImpl::InvalidSocket(); + } + + // Reset the pending packet data + myPendingPacket = PendingPacket(); +} + + +//////////////////////////////////////////////////////////// +Socket::PendingPacket::PendingPacket() : +Size (0), +SizeReceived(0), +Data () +{ + +} + +} // namespace sf diff --git a/src/SFML/Network/SocketImpl.hpp b/src/SFML/Network/SocketImpl.hpp new file mode 100644 index 00000000..11ea9d7d --- /dev/null +++ b/src/SFML/Network/SocketImpl.hpp @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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 + + +#if defined(SFML_SYSTEM_WINDOWS) + + #include + +#else + + #include + +#endif diff --git a/src/SFML/Network/SelectorBase.cpp b/src/SFML/Network/SocketSelector.cpp similarity index 50% rename from src/SFML/Network/SelectorBase.cpp rename to src/SFML/Network/SocketSelector.cpp index bf5cff02..bbb31175 100644 --- a/src/SFML/Network/SelectorBase.cpp +++ b/src/SFML/Network/SocketSelector.cpp @@ -22,114 +22,116 @@ // //////////////////////////////////////////////////////////// -#ifdef _MSC_VER - #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro -#endif - //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#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 +struct SocketSelector::SocketSelectorImpl +{ + fd_set AllSockets; ///< Set containing all the sockets handles + fd_set SocketsReady; ///< Set containing handles of the sockets that are ready + int MaxSocket; ///< Maximum socket handle +}; + + //////////////////////////////////////////////////////////// -SelectorBase::SelectorBase() : -myMaxSocket(0) +SocketSelector::SocketSelector() : +myImpl(new SocketSelectorImpl) { Clear(); } //////////////////////////////////////////////////////////// -/// Add a socket to watch -//////////////////////////////////////////////////////////// -void SelectorBase::Add(SocketHelper::SocketType socket) +SocketSelector::SocketSelector(const SocketSelector& copy) : +myImpl(new SocketSelectorImpl(*copy.myImpl)) { - FD_SET(socket, &mySet); - int size = static_cast(socket); - if (size > myMaxSocket) - myMaxSocket = size; } //////////////////////////////////////////////////////////// -/// Remove a socket -//////////////////////////////////////////////////////////// -void SelectorBase::Remove(SocketHelper::SocketType socket) +SocketSelector::~SocketSelector() { - FD_CLR(socket, &mySet); + delete myImpl; } //////////////////////////////////////////////////////////// -/// Remove all sockets -//////////////////////////////////////////////////////////// -void SelectorBase::Clear() +void SocketSelector::Add(Socket& socket) { - FD_ZERO(&mySet); - FD_ZERO(&mySetReady); + FD_SET(socket.GetHandle(), &myImpl->AllSockets); - myMaxSocket = 0; + int size = static_cast(socket.GetHandle()); + if (size > myImpl->MaxSocket) + myImpl->MaxSocket = size; } //////////////////////////////////////////////////////////// -/// 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) +void SocketSelector::Remove(Socket& socket) { - // Setup the timeout structure + FD_CLR(socket.GetHandle(), &myImpl->AllSockets); + FD_CLR(socket.GetHandle(), &myImpl->SocketsReady); +} + + +//////////////////////////////////////////////////////////// +void SocketSelector::Clear() +{ + FD_ZERO(&myImpl->AllSockets); + FD_ZERO(&myImpl->SocketsReady); + + myImpl->MaxSocket = 0; +} + + +//////////////////////////////////////////////////////////// +bool SocketSelector::Wait(float timeout) +{ + // Setup the timeout 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; + // Initialize the set that will contain the sockets that are ready + myImpl->SocketsReady = myImpl->AllSockets; // 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); + int count = select(myImpl->MaxSocket + 1, &myImpl->SocketsReady, NULL, NULL, timeout > 0 ? &time : NULL); - return nbSockets >= 0 ? static_cast(nbSockets) : 0; + return count > 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) const +bool SocketSelector::IsReady(Socket& socket) const { - // We have to drop the const for FD_ISSET - fd_set* set = const_cast(&mySetReady); + return FD_ISSET(socket.GetHandle(), &myImpl->SocketsReady) != 0; +} - // The standard FD_xxx interface doesn't define a direct access, - // so we must iterate through the whole set to find the socket that we're looking for - for (int i = 0; i < myMaxSocket + 1; ++i) - { - if (FD_ISSET(i, set)) - { - // 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(); +//////////////////////////////////////////////////////////// +SocketSelector& SocketSelector::operator =(const SocketSelector& right) +{ + SocketSelector temp(right); + + std::swap(myImpl, temp.myImpl); + + return *this; } } // namespace sf diff --git a/src/SFML/Network/SocketTCP.cpp b/src/SFML/Network/SocketTCP.cpp deleted file mode 100644 index 980b2956..00000000 --- a/src/SFML/Network/SocketTCP.cpp +++ /dev/null @@ -1,511 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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& host, 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(host.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 blocking = myIsBlocking; - - // Switch to non-blocking to enable our connection timeout - if (blocking) - 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 (!blocking) - 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 (which means that the connection request has returned) - if (select(static_cast(mySocket + 1), NULL, &selector, NULL, &time) > 0) - { - // At this point the connection may have been either accepted or refused. - // To know whether it's a success or a failure, we try to retrieve the name of the connected peer - SocketHelper::LengthType size = sizeof(sockAddr); - if (getpeername(mySocket, reinterpret_cast(&sockAddr), &size) != -1) - { - // Connection accepted - status = Socket::Done; - } - else - { - // Connection failed - status = SocketHelper::GetErrorStatus(); - } - } - 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... - Err() << "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 - Err() << "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 sizeInBytes) -{ - // First check that socket is valid - if (!IsValid()) - return Socket::Error; - - // Check parameters - if (data && sizeInBytes) - { - // Loop until every byte has been sent - int sent = 0; - int sizeToSend = static_cast(sizeInBytes); - 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... - Err() << "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... - Err() << "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& packet) -{ - // Get the data to send from the packet - std::size_t dataSize = 0; - const char* data = packet.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& packet) -{ - // We start by getting the size of the incoming packet - Uint32 packetSize = 0; - std::size_t received = 0; - if (myPendingPacketSize < 0) - { - // Loop until we've received the entire size of the packet - // (even a 4 bytes variable may be received in more than one call) - while (myPendingHeaderSize < sizeof(myPendingHeader)) - { - char* data = reinterpret_cast(&myPendingHeader) + myPendingHeaderSize; - Socket::Status status = Receive(data, sizeof(myPendingHeader) - myPendingHeaderSize, received); - myPendingHeaderSize += received; - - if (status != Socket::Done) - return status; - } - - packetSize = ntohl(myPendingHeader); - myPendingHeaderSize = 0; - } - 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 - packet.Clear(); - if (!myPendingPacket.empty()) - packet.OnReceive(&myPendingPacket[0], myPendingPacket.size()); - myPendingPacket.clear(); - myPendingPacketSize = -1; - - return Socket::Done; -} - - -//////////////////////////////////////////////////////////// -/// Close the socket -//////////////////////////////////////////////////////////// -bool SocketTCP::Close() -{ - if (IsValid()) - { - if (!SocketHelper::Close(mySocket)) - { - Err() << "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 - myPendingHeaderSize = 0; - 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) - { - Err() << "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) - { - Err() << "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/src/SFML/Network/SocketUDP.cpp b/src/SFML/Network/SocketUDP.cpp deleted file mode 100644 index 51127c80..00000000 --- a/src/SFML/Network/SocketUDP.cpp +++ /dev/null @@ -1,433 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 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 unbind it first - Unbind(); - - if (port != 0) - { - // Build an address with the specified port - sockaddr_in sockAddr; - sockAddr.sin_family = AF_INET; - sockAddr.sin_port = htons(port); - sockAddr.sin_addr.s_addr = INADDR_ANY; - memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); - - // Bind the socket to the port - if (bind(mySocket, reinterpret_cast(&sockAddr), sizeof(sockAddr)) == -1) - { - Err() << "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 sizeInBytes, const IpAddress& address, unsigned short port) -{ - // Make sure the socket is valid - if (!IsValid()) - Create(); - - // Check parameters - if (data && sizeInBytes) - { - // Build the target address - sockaddr_in sockAddr; - sockAddr.sin_family = AF_INET; - sockAddr.sin_port = htons(port); - sockAddr.sin_addr.s_addr = inet_addr(address.ToString().c_str()); - memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); - - // Loop until every byte has been sent - int sent = 0; - int sizeToSend = static_cast(sizeInBytes); - for (int length = 0; length < sizeToSend; length += sent) - { - // Send a chunk of data - sent = sendto(mySocket, data + length, sizeToSend - length, 0, reinterpret_cast(&sockAddr), sizeof(sockAddr)); - - // Check errors - if (sent <= 0) - return SocketHelper::GetErrorStatus(); - } - - return Socket::Done; - } - else - { - // Error... - Err() << "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, unsigned short& port) -{ - // First clear the size received - sizeReceived = 0; - - // Make sure the socket is bound to a port - if (myPort == 0) - { - Err() << "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 sockAddr; - sockAddr.sin_family = AF_INET; - sockAddr.sin_port = 0; - sockAddr.sin_addr.s_addr = INADDR_ANY; - memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero)); - SocketHelper::LengthType sockAddrSize = sizeof(sockAddr); - - // Receive a chunk of bytes - int received = recvfrom(mySocket, data, static_cast(maxSize), 0, reinterpret_cast(&sockAddr), &sockAddrSize); - - // Check the number of bytes received - if (received > 0) - { - address = IpAddress(inet_ntoa(sockAddr.sin_addr)); - port = ntohs(sockAddr.sin_port); - sizeReceived = static_cast(received); - return Socket::Done; - } - else - { - address = IpAddress(); - port = 0; - return received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus(); - } - } - else - { - // Error... - Err() << "Cannot receive data from the network (invalid parameters)" << std::endl; - return Socket::Error; - } -} - - -//////////////////////////////////////////////////////////// -/// Send a packet of data -//////////////////////////////////////////////////////////// -Socket::Status SocketUDP::Send(Packet& packet, const IpAddress& address, unsigned short port) -{ - // Get the data to send from the packet - std::size_t dataSize = 0; - const char* data = packet.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& packet, IpAddress& address, unsigned short& port) -{ - // We start by getting the size of the incoming packet - Uint32 packetSize = 0; - std::size_t received = 0; - if (myPendingPacketSize < 0) - { - // Loop until we've received the entire size of the packet - // (even a 4 bytes variable may be received in more than one call) - while (myPendingHeaderSize < sizeof(myPendingHeader)) - { - char* data = reinterpret_cast(&myPendingHeader) + myPendingHeaderSize; - Socket::Status status = Receive(data, sizeof(myPendingHeader) - myPendingHeaderSize, received, address, port); - myPendingHeaderSize += received; - - if (status != Socket::Done) - return status; - } - - packetSize = ntohl(myPendingHeader); - myPendingHeaderSize = 0; - } - else - { - // There is a pending packet : we already know its size - packetSize = myPendingPacketSize; - } - - // Use another address instance for receiving the packet data ; - // chunks of data coming from a different sender will be discarded (and lost...) - IpAddress sender; - unsigned short senderPort; - - // 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, senderPort); - 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) && (senderPort == port) && (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 - packet.Clear(); - if (!myPendingPacket.empty()) - packet.OnReceive(&myPendingPacket[0], myPendingPacket.size()); - myPendingPacket.clear(); - myPendingPacketSize = -1; - - return Socket::Done; -} - - -//////////////////////////////////////////////////////////// -/// Close the socket -//////////////////////////////////////////////////////////// -bool SocketUDP::Close() -{ - if (IsValid()) - { - if (!SocketHelper::Close(mySocket)) - { - Err() << "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 - myPendingHeaderSize = 0; - 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) - { - Err() << "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) - { - Err() << "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/src/SFML/Network/TcpListener.cpp b/src/SFML/Network/TcpListener.cpp new file mode 100644 index 00000000..615ecd0d --- /dev/null +++ b/src/SFML/Network/TcpListener.cpp @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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 +{ +//////////////////////////////////////////////////////////// +TcpListener::TcpListener() : +Socket(Tcp) +{ + +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpListener::Listen(unsigned short port) +{ + // Create the internal socket if it doesn't exist + Create(); + + // Bind the socket to the specified port + sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_ANY, port); + if (bind(GetHandle(), reinterpret_cast(&address), sizeof(address)) == -1) + { + // Not likely to happen, but... + Err() << "Failed to bind listener socket to port " << port << std::endl; + return Error; + } + + // Listen to the bound port + if (listen(GetHandle(), 0) == -1) + { + // Oops, socket is deaf + Err() << "Failed to listen to port " << port << std::endl; + return Error; + } + + return Done; +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpListener::Accept(TcpSocket& socket) +{ + // Make sure that we're listening + if (GetHandle() == priv::SocketImpl::InvalidSocket()) + { + Err() << "Failed to accept a new connection, the socket is not listening" << std::endl; + return Error; + } + + // Accept a new connection + sockaddr_in address; + priv::SocketImpl::AddrLength length = sizeof(address); + SocketHandle remote = accept(GetHandle(), reinterpret_cast(&address), &length); + + // Check for errors + if (remote == priv::SocketImpl::InvalidSocket()) + return priv::SocketImpl::GetErrorStatus(); + + // Initialize the new connected socket + socket.Close(); + socket.Create(remote); + + return Done; +} + +} // namespace sf diff --git a/src/SFML/Network/TcpSocket.cpp b/src/SFML/Network/TcpSocket.cpp new file mode 100644 index 00000000..20d7881a --- /dev/null +++ b/src/SFML/Network/TcpSocket.cpp @@ -0,0 +1,352 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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 + +#ifdef _MSC_VER + #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro +#endif + + +namespace sf +{ +//////////////////////////////////////////////////////////// +TcpSocket::TcpSocket() : +Socket(Tcp) +{ + +} + + +//////////////////////////////////////////////////////////// +unsigned short TcpSocket::GetLocalPort() const +{ + if (GetHandle() != priv::SocketImpl::InvalidSocket()) + { + // Retrieve informations about the local end of the socket + sockaddr_in address; + priv::SocketImpl::AddrLength size = sizeof(address); + if (getsockname(GetHandle(), reinterpret_cast(&address), &size) != -1) + { + return ntohs(address.sin_port); + } + } + + // We failed to retrieve the port + return 0; +} + + +//////////////////////////////////////////////////////////// +IpAddress TcpSocket::GetRemoteAddress() const +{ + if (GetHandle() != priv::SocketImpl::InvalidSocket()) + { + // Retrieve informations about the remote end of the socket + sockaddr_in address; + priv::SocketImpl::AddrLength size = sizeof(address); + if (getpeername(GetHandle(), reinterpret_cast(&address), &size) != -1) + { + return IpAddress(ntohl(address.sin_addr.s_addr)); + } + } + + // We failed to retrieve the address + return IpAddress::None; +} + + +//////////////////////////////////////////////////////////// +unsigned short TcpSocket::GetRemotePort() const +{ + if (GetHandle() != priv::SocketImpl::InvalidSocket()) + { + // Retrieve informations about the remote end of the socket + sockaddr_in address; + priv::SocketImpl::AddrLength size = sizeof(address); + if (getpeername(GetHandle(), reinterpret_cast(&address), &size) != -1) + { + return ntohs(address.sin_port); + } + } + + // We failed to retrieve the port + return 0; +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpSocket::Connect(const IpAddress& remoteAddress, unsigned short remotePort, float timeout) +{ + // Create the internal socket if it doesn't exist + Create(); + + // Create the remote address + sockaddr_in address = priv::SocketImpl::CreateAddress(remoteAddress.ToInteger(), remotePort); + + if (timeout <= 0) + { + // ----- We're not using a timeout: just try to connect ----- + + // Connect the socket + if (connect(GetHandle(), reinterpret_cast(&address), sizeof(address)) == -1) + return priv::SocketImpl::GetErrorStatus(); + + // Connection succeeded + return Done; + } + else + { + // ----- We're using a timeout: we'll need a few tricks to make it work ----- + + // Save the previous blocking state + bool blocking = IsBlocking(); + + // Switch to non-blocking to enable our connection timeout + if (blocking) + SetBlocking(false); + + // Try to connect to the remote address + if (connect(GetHandle(), reinterpret_cast(&address), sizeof(address)) >= 0) + { + // We got instantly connected! (it may no happen a lot...) + return Done; + } + + // Get the error status + Status status = priv::SocketImpl::GetErrorStatus(); + + // If we were in non-blocking mode, return immediatly + if (!blocking) + 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(GetHandle(), &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 (which means that the connection request has returned) + if (select(static_cast(GetHandle() + 1), NULL, &selector, NULL, &time) > 0) + { + // At this point the connection may have been either accepted or refused. + // To know whether it's a success or a failure, we must check the address of the connected peer + if (GetRemoteAddress() != sf::IpAddress::None) + { + // Connection accepted + status = Done; + } + else + { + // Connection refused + status = priv::SocketImpl::GetErrorStatus(); + } + } + else + { + // Failed to connect before timeout is over + status = priv::SocketImpl::GetErrorStatus(); + } + } + + // Switch back to blocking mode + SetBlocking(true); + + return status; + } +} + + +//////////////////////////////////////////////////////////// +void TcpSocket::Disconnect() +{ + // Simply close the socket + Close(); +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpSocket::Send(const char* data, std::size_t size) +{ + // Check the parameters + if (!data || (size == 0)) + { + Err() << "Cannot send data over the network (invalid parameters)" << std::endl; + return Error; + } + + // 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(GetHandle(), data + length, sizeToSend - length, 0); + + // Check for errors + if (sent <= 0) + return priv::SocketImpl::GetErrorStatus(); + } + + return Done; +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpSocket::Receive(char* data, std::size_t size, std::size_t& received) +{ + // First clear the variables to fill + received = 0; + + // Check the parameters + if (!data || (size == 0)) + { + Err() << "Cannot receive data from the network (invalid parameters)" << std::endl; + return Error; + } + + // Receive a chunk of bytes + int sizeReceived = recv(GetHandle(), data, static_cast(size), 0); + + // Check the number of bytes received + if (sizeReceived > 0) + { + received = static_cast(sizeReceived); + return Done; + } + else if (sizeReceived == 0) + { + return Socket::Disconnected; + } + else + { + return priv::SocketImpl::GetErrorStatus(); + } +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpSocket::Send(Packet& packet) +{ + // Get the data to send from the packet + std::size_t size = 0; + const char* data = packet.OnSend(size); + + // First send the packet size + Uint32 packetSize = htonl(static_cast(size)); + Status status = Send(reinterpret_cast(&packetSize), sizeof(packetSize)); + + // Make sure that the size was properly sent + if (status != Done) + return status; + + // Send the packet data + if (packetSize > 0) + { + return Send(data, size); + } + else + { + return Done; + } +} + + +//////////////////////////////////////////////////////////// +Socket::Status TcpSocket::Receive(Packet& packet) +{ + // First clear the variables to fill + packet.Clear(); + + // We start by getting the size of the incoming packet + Uint32 packetSize = 0; + std::size_t received = 0; + if (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size)) + { + // Loop until we've received the entire size of the packet + // (even a 4 bytes variable may be received in more than one call) + while (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size)) + { + char* data = reinterpret_cast(&myPendingPacket.Size) + myPendingPacket.SizeReceived; + Status status = Receive(data, sizeof(myPendingPacket.Size) - myPendingPacket.SizeReceived, received); + myPendingPacket.SizeReceived += received; + + if (status != Done) + return status; + } + + // The packet size has been fully received + packetSize = ntohl(myPendingPacket.Size); + } + else + { + // The packet size has already been received in a previous call + packetSize = ntohl(myPendingPacket.Size); + } + + // Loop until we receive all the packet data + char buffer[1024]; + while (myPendingPacket.Data.size() < packetSize) + { + // Receive a chunk of data + std::size_t sizeToGet = std::min(static_cast(packetSize - myPendingPacket.Data.size()), sizeof(buffer)); + Status status = Receive(buffer, sizeToGet, received); + if (status != Done) + return status; + + // Append it into the packet + if (received > 0) + { + myPendingPacket.Data.resize(myPendingPacket.Data.size() + received); + char* begin = &myPendingPacket.Data[0] + myPendingPacket.Data.size() - received; + memcpy(begin, buffer, received); + } + } + + // We have received all the packet data: we can copy it to the user packet + if (!myPendingPacket.Data.empty()) + packet.OnReceive(&myPendingPacket.Data[0], myPendingPacket.Data.size()); + + // Clear the pending packet data + myPendingPacket = PendingPacket(); + + return Done; +} + +} // namespace sf diff --git a/src/SFML/Network/UdpSocket.cpp b/src/SFML/Network/UdpSocket.cpp new file mode 100644 index 00000000..d4269c00 --- /dev/null +++ b/src/SFML/Network/UdpSocket.cpp @@ -0,0 +1,256 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 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 +{ +//////////////////////////////////////////////////////////// +UdpSocket::UdpSocket() : +Socket(Udp) +{ + +} + + +//////////////////////////////////////////////////////////// +unsigned short UdpSocket::GetLocalPort() const +{ + if (GetHandle() != priv::SocketImpl::InvalidSocket()) + { + // Retrieve informations about the local end of the socket + sockaddr_in address; + priv::SocketImpl::AddrLength size = sizeof(address); + if (getsockname(GetHandle(), reinterpret_cast(&address), &size) != -1) + { + return ntohs(address.sin_port); + } + } + + // We failed to retrieve the port + return 0; +} + + +//////////////////////////////////////////////////////////// +Socket::Status UdpSocket::Bind(unsigned short port) +{ + // Create the internal socket if it doesn't exist + Create(); + + // Bind the socket + sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_ANY, port); + if (bind(GetHandle(), reinterpret_cast(&address), sizeof(address)) == -1) + { + Err() << "Failed to bind socket to port " << port << std::endl; + return Error; + } + + return Done; +} + + +//////////////////////////////////////////////////////////// +void UdpSocket::Unbind() +{ + // Simply close the socket + Close(); +} + + +//////////////////////////////////////////////////////////// +Socket::Status UdpSocket::Send(const char* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort) +{ + // Create the internal socket if it doesn't exist + Create(); + + // Check the parameters + if (!data || (size == 0)) + { + Err() << "Cannot send data over the network (invalid parameters)" << std::endl; + return Error; + } + + // Build the target address + sockaddr_in address = priv::SocketImpl::CreateAddress(remoteAddress.ToInteger(), remotePort); + + // 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(GetHandle(), data + length, sizeToSend - length, 0, reinterpret_cast(&address), sizeof(address)); + + // Check for errors + if (sent <= 0) + return priv::SocketImpl::GetErrorStatus(); + } + + return Done; +} + + +//////////////////////////////////////////////////////////// +Socket::Status UdpSocket::Receive(char* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort) +{ + // First clear the variables to fill + received = 0; + remoteAddress = IpAddress(); + remotePort = 0; + + // Check the parameters + if (!data || (size == 0)) + { + Err() << "Cannot receive data from the network (invalid parameters)" << std::endl; + return Error; + } + + // Data that will be filled with the other computer's address + sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_ANY, 0); + + // Receive a chunk of bytes + priv::SocketImpl::AddrLength addressSize = sizeof(address); + int sizeReceived = recvfrom(GetHandle(), data, static_cast(size), 0, reinterpret_cast(&address), &addressSize); + + // Check for errors + if (sizeReceived <= 0) + return priv::SocketImpl::GetErrorStatus(); + + // Fill the sender informations + received = static_cast(sizeReceived); + remoteAddress = IpAddress(ntohl(address.sin_addr.s_addr)); + remotePort = ntohs(address.sin_port); + + return Done; +} + + +//////////////////////////////////////////////////////////// +Socket::Status UdpSocket::Send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort) +{ + // Get the data to send from the packet + std::size_t size = 0; + const char* data = packet.OnSend(size); + + // First send the packet size + Uint32 packetSize = htonl(static_cast(size)); + Status status = Send(reinterpret_cast(&packetSize), sizeof(packetSize), remoteAddress, remotePort); + + // Make sure that the size was properly sent + if (status != Done) + return status; + + // Finally send the packet data + if (packetSize > 0) + { + return Send(data, size, remoteAddress, remotePort); + } + else + { + return Done; + } +} + + +//////////////////////////////////////////////////////////// +Socket::Status UdpSocket::Receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort) +{ + // First clear the variables to fill + packet.Clear(); + remoteAddress = IpAddress(); + remotePort = 0; + + // We start by getting the size of the incoming packet + Uint32 packetSize = 0; + std::size_t received = 0; + if (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size)) + { + // Loop until we've received the entire size of the packet + // (even a 4 bytes variable may be received in more than one call) + while (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size)) + { + char* data = reinterpret_cast(&myPendingPacket.Size) + myPendingPacket.SizeReceived; + std::size_t size = sizeof(myPendingPacket.Size) - myPendingPacket.SizeReceived; + Status status = Receive(data, size, received, remoteAddress, remotePort); + myPendingPacket.SizeReceived += received; + + if (status != Done) + return status; + } + + // The packet size has been fully received + packetSize = ntohl(myPendingPacket.Size); + } + else + { + // The packet size has already been received in a previous call + packetSize = ntohl(myPendingPacket.Size); + } + + // Use another address instance for receiving the packet data, + // chunks of data coming from a different sender will be discarded (and lost...) + IpAddress currentSender; + unsigned short currentPort; + + // Loop until we receive all the packet data + char buffer[1024]; + while (myPendingPacket.Data.size() < packetSize) + { + // Receive a chunk of data + std::size_t sizeToGet = std::min(static_cast(packetSize - myPendingPacket.Data.size()), sizeof(buffer)); + Status status = Receive(buffer, sizeToGet, received, currentSender, currentPort); + if (status != Done) + return status; + + // Append it into the packet + if ((currentSender == remoteAddress) && (currentPort == remotePort) && (received > 0)) + { + myPendingPacket.Data.resize(myPendingPacket.Data.size() + received); + char* begin = &myPendingPacket.Data[0] + myPendingPacket.Data.size() - received; + memcpy(begin, buffer, received); + } + } + + // We have received all the packet data: we can copy it to the user packet + if (!myPendingPacket.Data.empty()) + packet.OnReceive(&myPendingPacket.Data[0], myPendingPacket.Data.size()); + + // Clear the pending packet data + myPendingPacket = PendingPacket(); + + return Done; +} + + +} // namespace sf diff --git a/src/SFML/Network/Unix/SocketHelper.cpp b/src/SFML/Network/Unix/SocketImpl.cpp similarity index 77% rename from src/SFML/Network/Unix/SocketHelper.cpp rename to src/SFML/Network/Unix/SocketImpl.cpp index 20ee77dc..bf6c86a3 100644 --- a/src/SFML/Network/Unix/SocketHelper.cpp +++ b/src/SFML/Network/Unix/SocketImpl.cpp @@ -25,35 +25,45 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include #include #include +#include namespace sf { +namespace priv +{ //////////////////////////////////////////////////////////// -/// Return the value of the invalid socket +sockaddr_in SocketImpl::CreateAddress(unsigned long address, unsigned short port) +{ + sockaddr_in addr; + memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); + addr.sin_addr.s_addr = htonl(address); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + return addr; +} + + //////////////////////////////////////////////////////////// -SocketHelper::SocketType SocketHelper::InvalidSocket() +SocketHandle SocketImpl::InvalidSocket() { return -1; } //////////////////////////////////////////////////////////// -/// Close / destroy a socket -//////////////////////////////////////////////////////////// -bool SocketHelper::Close(SocketHelper::SocketType socket) +void SocketImpl::Close(SocketHandle sock) { - return close(socket) != -1; + close(sock); } //////////////////////////////////////////////////////////// -/// Set a socket as blocking or non-blocking -//////////////////////////////////////////////////////////// -void SocketHelper::SetBlocking(SocketHelper::SocketType sock, bool block) +void SocketImpl::SetBlocking(SocketHandle sock, bool block) { int status = fcntl(sock, F_GETFL); if (block) @@ -64,9 +74,7 @@ void SocketHelper::SetBlocking(SocketHelper::SocketType sock, bool block) //////////////////////////////////////////////////////////// -/// Get the last socket error status -//////////////////////////////////////////////////////////// -Socket::Status SocketHelper::GetErrorStatus() +Socket::Status SocketImpl::GetErrorStatus() { // The followings are sometimes equal to EWOULDBLOCK, // so we have to make a special case for them in order @@ -86,4 +94,6 @@ Socket::Status SocketHelper::GetErrorStatus() } } +} // namespace priv + } // namespace sf diff --git a/include/SFML/Network/Unix/SocketHelper.hpp b/src/SFML/Network/Unix/SocketImpl.hpp similarity index 62% rename from include/SFML/Network/Unix/SocketHelper.hpp rename to src/SFML/Network/Unix/SocketImpl.hpp index 1068cd85..ae37e62c 100644 --- a/include/SFML/Network/Unix/SocketHelper.hpp +++ b/src/SFML/Network/Unix/SocketImpl.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com) +// Copyright (C) 2007-2009 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. @@ -22,12 +22,13 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETHELPERUNIX_HPP -#define SFML_SOCKETHELPERUNIX_HPP +#ifndef SFML_SOCKETIMPL_HPP +#define SFML_SOCKETIMPL_HPP //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include #include #include #include @@ -39,47 +40,57 @@ namespace sf { +namespace priv +{ //////////////////////////////////////////////////////////// -/// This class defines helper functions to do all the -/// non-portable socket stuff. This class is meant for internal -/// use only +/// \brief Helper class implementing all the non-portable +/// socket stuff; this is the Unix version +/// //////////////////////////////////////////////////////////// -class SFML_API SocketHelper +class SocketImpl { public : //////////////////////////////////////////////////////////// - // Define some socket types + // Types //////////////////////////////////////////////////////////// - typedef int SocketType; - typedef socklen_t LengthType; + typedef socklen_t AddrLength; //////////////////////////////////////////////////////////// - /// Return the value of the invalid socket + /// \brief Create an internal sockaddr_in address /// - /// \return Unique value of the invalid socket + /// \param address Target address + /// \param port Target port + /// + /// \return sockaddr_in ready to be used by socket functions /// //////////////////////////////////////////////////////////// - static SocketType InvalidSocket(); + static sockaddr_in CreateAddress(unsigned long address, unsigned short port); //////////////////////////////////////////////////////////// - /// Close / destroy a socket + /// \brief Return the value of the invalid socket /// - /// \param Socket : Socket to close - /// - /// \return True on success + /// \return Special value of the invalid socket /// //////////////////////////////////////////////////////////// - static bool Close(SocketType Socket); + static SocketHandle InvalidSocket(); //////////////////////////////////////////////////////////// - /// Set a socket as blocking or non-blocking + /// \brief Close and destroy a socket /// - /// \param Socket : Socket to modify - /// \param Block : New blocking state of the socket + /// \param sock Handle of the socket to close /// //////////////////////////////////////////////////////////// - static void SetBlocking(SocketType Socket, bool Block); + static void Close(SocketHandle sock); + + //////////////////////////////////////////////////////////// + /// \brief Set a socket as blocking or non-blocking + /// + /// \param sock Handle of the socket + /// \param block New blocking state of the socket + /// + //////////////////////////////////////////////////////////// + static void SetBlocking(SocketHandle sock, bool block); //////////////////////////////////////////////////////////// /// Get the last socket error status @@ -90,7 +101,9 @@ public : static Socket::Status GetErrorStatus(); }; +} // namespace priv + } // namespace sf -#endif // SFML_SOCKETHELPERUNIX_HPP +#endif // SFML_SOCKETIMPL_HPP diff --git a/src/SFML/Network/Win32/SocketHelper.cpp b/src/SFML/Network/Win32/SocketImpl.cpp similarity index 75% rename from src/SFML/Network/Win32/SocketHelper.cpp rename to src/SFML/Network/Win32/SocketImpl.cpp index f84bd498..a7592cfc 100644 --- a/src/SFML/Network/Win32/SocketHelper.cpp +++ b/src/SFML/Network/Win32/SocketImpl.cpp @@ -25,43 +25,51 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include +#include +#include namespace sf { +namespace priv +{ //////////////////////////////////////////////////////////// -/// Return the value of the invalid socket +sockaddr_in SocketImpl::CreateAddress(unsigned long address, unsigned short port) +{ + sockaddr_in addr; + memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); + addr.sin_addr.s_addr = htonl(address); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + return addr; +} + + //////////////////////////////////////////////////////////// -SocketHelper::SocketType SocketHelper::InvalidSocket() +SocketHandle SocketImpl::InvalidSocket() { return INVALID_SOCKET; } //////////////////////////////////////////////////////////// -/// Close / destroy a socket -//////////////////////////////////////////////////////////// -bool SocketHelper::Close(SocketHelper::SocketType socket) +void SocketImpl::Close(SocketHandle sock) { - return closesocket(socket) != -1; + closesocket(sock); } //////////////////////////////////////////////////////////// -/// Set a socket as blocking or non-blocking -//////////////////////////////////////////////////////////// -void SocketHelper::SetBlocking(SocketHelper::SocketType socket, bool block) +void SocketImpl::SetBlocking(SocketHandle sock, bool block) { unsigned long blocking = block ? 0 : 1; - ioctlsocket(socket, FIONBIO, &blocking); + ioctlsocket(sock, FIONBIO, &blocking); } //////////////////////////////////////////////////////////// -/// Get the last socket error status -//////////////////////////////////////////////////////////// -Socket::Status SocketHelper::GetErrorStatus() +Socket::Status SocketImpl::GetErrorStatus() { switch (WSAGetLastError()) { @@ -86,7 +94,7 @@ struct SocketInitializer SocketInitializer() { WSADATA init; - WSAStartup(MAKEWORD(2,2), &init); + WSAStartup(MAKEWORD(2, 2), &init); } ~SocketInitializer() @@ -97,4 +105,6 @@ struct SocketInitializer SocketInitializer globalInitializer; +} // namespace priv + } // namespace sf diff --git a/include/SFML/Network/Win32/SocketHelper.hpp b/src/SFML/Network/Win32/SocketImpl.hpp similarity index 63% rename from include/SFML/Network/Win32/SocketHelper.hpp rename to src/SFML/Network/Win32/SocketImpl.hpp index 2ebf8899..f6e5b001 100644 --- a/include/SFML/Network/Win32/SocketHelper.hpp +++ b/src/SFML/Network/Win32/SocketImpl.hpp @@ -22,58 +22,69 @@ // //////////////////////////////////////////////////////////// -#ifndef SFML_SOCKETHELPERWIN32_HPP -#define SFML_SOCKETHELPERWIN32_HPP +#ifndef SFML_SOCKETIMPL_HPP +#define SFML_SOCKETIMPL_HPP //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include #include namespace sf { +namespace priv +{ //////////////////////////////////////////////////////////// -/// This class defines helper functions to do all the -/// non-portable socket stuff. This class is meant for internal -/// use only +/// \brief Helper class implementing all the non-portable +/// socket stuff; this is the Windows version +/// //////////////////////////////////////////////////////////// -class SFML_API SocketHelper +class SocketImpl { public : //////////////////////////////////////////////////////////// - // Define some socket types + // Types //////////////////////////////////////////////////////////// - typedef SOCKET SocketType; - typedef int LengthType; + typedef int AddrLength; //////////////////////////////////////////////////////////// - /// Return the value of the invalid socket + /// \brief Create an internal sockaddr_in address /// - /// \return Unique value of the invalid socket + /// \param address Target address + /// \param port Target port + /// + /// \return sockaddr_in ready to be used by socket functions /// //////////////////////////////////////////////////////////// - static SocketType InvalidSocket(); + static sockaddr_in CreateAddress(unsigned long address, unsigned short port); //////////////////////////////////////////////////////////// - /// Close / destroy a socket + /// \brief Return the value of the invalid socket /// - /// \param socket : Socket to close - /// - /// \return True on success + /// \return Special value of the invalid socket /// //////////////////////////////////////////////////////////// - static bool Close(SocketType socket); + static SocketHandle InvalidSocket(); //////////////////////////////////////////////////////////// - /// Set a socket as blocking or non-blocking + /// \brief Close and destroy a socket /// - /// \param socket : Socket to modify - /// \param block : New blocking state of the socket + /// \param sock Handle of the socket to close /// //////////////////////////////////////////////////////////// - static void SetBlocking(SocketType socket, bool block); + static void Close(SocketHandle sock); + + //////////////////////////////////////////////////////////// + /// \brief Set a socket as blocking or non-blocking + /// + /// \param sock Handle of the socket + /// \param block New blocking state of the socket + /// + //////////////////////////////////////////////////////////// + static void SetBlocking(SocketHandle sock, bool block); //////////////////////////////////////////////////////////// /// Get the last socket error status @@ -84,7 +95,9 @@ public : static Socket::Status GetErrorStatus(); }; +} // namespace priv + } // namespace sf -#endif // SFML_SOCKETHELPERWIN32_HPP +#endif // SFML_SOCKETIMPL_HPP