summaryrefslogtreecommitdiff
path: root/src/SFML/Network
diff options
context:
space:
mode:
Diffstat (limited to 'src/SFML/Network')
-rw-r--r--src/SFML/Network/.svn/all-wcprops53
-rw-r--r--src/SFML/Network/.svn/entries306
-rw-r--r--src/SFML/Network/.svn/format1
-rw-r--r--src/SFML/Network/.svn/text-base/Ftp.cpp.svn-base709
-rw-r--r--src/SFML/Network/.svn/text-base/Http.cpp.svn-base425
-rw-r--r--src/SFML/Network/.svn/text-base/IPAddress.cpp.svn-base303
-rw-r--r--src/SFML/Network/.svn/text-base/Makefile.svn-base34
-rw-r--r--src/SFML/Network/.svn/text-base/Packet.cpp.svn-base426
-rw-r--r--src/SFML/Network/.svn/text-base/SelectorBase.cpp.svn-base132
-rw-r--r--src/SFML/Network/.svn/text-base/SocketTCP.cpp.svn-base486
-rw-r--r--src/SFML/Network/.svn/text-base/SocketUDP.cpp.svn-base427
-rw-r--r--src/SFML/Network/Ftp.cpp709
-rw-r--r--src/SFML/Network/Http.cpp425
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/IPAddress.cpp91
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/Makefile6
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/Packet.cpp82
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/SelectorBase.cpp2
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/SocketTCP.cpp160
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/SocketUDP.cpp93
-rw-r--r--src/SFML/Network/Unix/.svn/all-wcprops11
-rw-r--r--src/SFML/Network/Unix/.svn/entries62
-rw-r--r--src/SFML/Network/Unix/.svn/format1
-rw-r--r--src/SFML/Network/Unix/.svn/text-base/SocketHelper.cpp.svn-base83
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/Unix/SocketHelper.cpp0
-rw-r--r--src/SFML/Network/Win32/.svn/all-wcprops11
-rw-r--r--src/SFML/Network/Win32/.svn/entries62
-rw-r--r--src/SFML/Network/Win32/.svn/format1
-rw-r--r--src/SFML/Network/Win32/.svn/text-base/SocketHelper.cpp.svn-base100
-rw-r--r--[-rwxr-xr-x]src/SFML/Network/Win32/SocketHelper.cpp0
29 files changed, 5022 insertions, 179 deletions
diff --git a/src/SFML/Network/.svn/all-wcprops b/src/SFML/Network/.svn/all-wcprops
new file mode 100644
index 0000000..4f2253b
--- /dev/null
+++ b/src/SFML/Network/.svn/all-wcprops
@@ -0,0 +1,53 @@
+K 25
+svn:wc:ra_dav:version-url
+V 43
+/svnroot/sfml/!svn/ver/912/src/SFML/Network
+END
+IPAddress.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/sfml/!svn/ver/905/src/SFML/Network/IPAddress.cpp
+END
+Http.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/sfml/!svn/ver/912/src/SFML/Network/Http.cpp
+END
+SocketTCP.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/sfml/!svn/ver/912/src/SFML/Network/SocketTCP.cpp
+END
+SocketUDP.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/sfml/!svn/ver/912/src/SFML/Network/SocketUDP.cpp
+END
+Packet.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svnroot/sfml/!svn/ver/841/src/SFML/Network/Packet.cpp
+END
+Ftp.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svnroot/sfml/!svn/ver/912/src/SFML/Network/Ftp.cpp
+END
+SelectorBase.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 60
+/svnroot/sfml/!svn/ver/784/src/SFML/Network/SelectorBase.cpp
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/sfml/!svn/ver/763/src/SFML/Network/Makefile
+END
diff --git a/src/SFML/Network/.svn/entries b/src/SFML/Network/.svn/entries
new file mode 100644
index 0000000..cd52cb7
--- /dev/null
+++ b/src/SFML/Network/.svn/entries
@@ -0,0 +1,306 @@
+9
+
+dir
+915
+https://sfml.svn.sourceforge.net/svnroot/sfml/src/SFML/Network
+https://sfml.svn.sourceforge.net/svnroot/sfml
+
+
+
+2008-10-21T18:42:24.730017Z
+912
+laurentgom
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+4e206d99-4929-0410-ac5d-dfc041789085
+
+IPAddress.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+74244104112de7e9677ffd45849aeabb
+2008-10-11T19:31:03.152262Z
+905
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9840
+
+Http.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+30ea45e51443da70e9654658e3411001
+2008-10-21T18:42:24.730017Z
+912
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12998
+
+SocketTCP.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+2e05f9d427a5ca5c353991d0ab7bb4d7
+2008-10-21T18:42:24.730017Z
+912
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15742
+
+Win32
+dir
+
+SocketUDP.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+9802c4afa7021973c97e229a0590164f
+2008-10-21T18:42:24.730017Z
+912
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+14012
+
+Unix
+dir
+
+Packet.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+30370e9c2cd63158a83785dcd906c087
+2008-08-30T15:01:48.265908Z
+841
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10993
+
+Ftp.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+d2d8f4a5af7cb349589e1ef5caebeb9d
+2008-10-21T18:42:24.730017Z
+912
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+23884
+
+SelectorBase.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+942027844524ec35b02f0e5308d96776
+2008-07-30T11:21:15.772571Z
+784
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4430
+
+Makefile
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+2008057c53799b5fc08db46f8e0d7111
+2008-07-13T05:32:14.531189Z
+763
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+737
+
diff --git a/src/SFML/Network/.svn/format b/src/SFML/Network/.svn/format
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/src/SFML/Network/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/src/SFML/Network/.svn/text-base/Ftp.cpp.svn-base b/src/SFML/Network/.svn/text-base/Ftp.cpp.svn-base
new file mode 100644
index 0000000..df0976e
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/Ftp.cpp.svn-base
@@ -0,0 +1,709 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Ftp.hpp>
+#include <SFML/Network/IPAddress.hpp>
+#include <algorithm>
+#include <fstream>
+#include <iterator>
+#include <sstream>
+
+
+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<char>& Data);
+
+ ////////////////////////////////////////////////////////////
+ // Receive data on the data channel until it is closed
+ ////////////////////////////////////////////////////////////
+ void Receive(std::vector<char>& Data);
+
+private :
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Ftp& myFtp; ///< Reference to the owner Ftp instance
+ SocketTCP myDataSocket; ///< Socket used for data transfers
+};
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Ftp::Response::Response(Status Code, const std::string& Message) :
+myStatus (Code),
+myMessage(Message)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Convenience function to check if the response status code
+/// means a success
+////////////////////////////////////////////////////////////
+bool Ftp::Response::IsOk() const
+{
+ return myStatus < 400;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the response status code
+////////////////////////////////////////////////////////////
+Ftp::Response::Status Ftp::Response::GetStatus() const
+{
+ return myStatus;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the full message contained in the response
+////////////////////////////////////////////////////////////
+const std::string& Ftp::Response::GetMessage() const
+{
+ return myMessage;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response Resp) :
+Ftp::Response(Resp)
+{
+ if (IsOk())
+ {
+ // Extract the directory from the server response
+ std::string::size_type Begin = Resp.GetMessage().find('"', 0);
+ std::string::size_type End = Resp.GetMessage().find('"', Begin + 1);
+ myDirectory = Resp.GetMessage().substr(Begin + 1, End - Begin - 1);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the directory returned in the response
+////////////////////////////////////////////////////////////
+const std::string& Ftp::DirectoryResponse::GetDirectory() const
+{
+ return myDirectory;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Ftp::ListingResponse::ListingResponse(Ftp::Response Resp, const std::vector<char>& Data) :
+Ftp::Response(Resp)
+{
+ if (IsOk())
+ {
+ // Fill the array of strings
+ std::string Paths(Data.begin(), Data.end());
+ std::string::size_type LastPos = 0;
+ for (std::string::size_type Pos = Paths.find("\r\n"); Pos != std::string::npos; Pos = Paths.find("\r\n", LastPos))
+ {
+ myFilenames.push_back(Paths.substr(LastPos, Pos - LastPos));
+ LastPos = Pos + 2;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the number of filenames in the listing
+////////////////////////////////////////////////////////////
+std::size_t Ftp::ListingResponse::GetCount() const
+{
+ return myFilenames.size();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the Index-th filename in the directory
+////////////////////////////////////////////////////////////
+const std::string& Ftp::ListingResponse::GetFilename(std::size_t Index) const
+{
+ return myFilenames[Index];
+}
+
+
+////////////////////////////////////////////////////////////
+/// Destructor -- close the connection with the server
+////////////////////////////////////////////////////////////
+Ftp::~Ftp()
+{
+ Disconnect();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Connect to the specified FTP server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Connect(const IPAddress& Server, unsigned short Port, float Timeout)
+{
+ // Connect to the server
+ if (myCommandSocket.Connect(Port, Server, Timeout) != Socket::Done)
+ return Response(Response::ConnectionFailed);
+
+ // Get the response to the connection
+ return GetResponse();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Log in using anonymous account
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Login()
+{
+ return Login("anonymous", "user@sfml-dev.org");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Log in using a username and a password
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Login(const std::string& UserName, const std::string& Password)
+{
+ Response Resp = SendCommand("USER", UserName);
+ if (Resp.IsOk())
+ Resp = SendCommand("PASS", Password);
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Close the connection with FTP server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Disconnect()
+{
+ // Send the exit command
+ Response Resp = SendCommand("QUIT");
+ if (Resp.IsOk())
+ myCommandSocket.Close();
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a null command just to prevent from being disconnected
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::KeepAlive()
+{
+ return SendCommand("NOOP");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the current working directory
+////////////////////////////////////////////////////////////
+Ftp::DirectoryResponse Ftp::GetWorkingDirectory()
+{
+ return DirectoryResponse(SendCommand("PWD"));
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the contents of the given directory
+/// (subdirectories and files)
+////////////////////////////////////////////////////////////
+Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& Directory)
+{
+ // Open a data channel on default port (20) using ASCII transfer mode
+ std::vector<char> DirData;
+ DataChannel Data(*this);
+ Response Resp = Data.Open(Ascii);
+ if (Resp.IsOk())
+ {
+ // Tell the server to send us the listing
+ Resp = SendCommand("NLST", Directory);
+ if (Resp.IsOk())
+ {
+ // Receive the listing
+ Data.Receive(DirData);
+
+ // Get the response from the server
+ Resp = GetResponse();
+ }
+ }
+
+ return ListingResponse(Resp, DirData);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Change the current working directory
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::ChangeDirectory(const std::string& Directory)
+{
+ return SendCommand("CWD", Directory);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Go to the parent directory of the current one
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::ParentDirectory()
+{
+ return SendCommand("CDUP");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Create a new directory
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::MakeDirectory(const std::string& Name)
+{
+ return SendCommand("MKD", Name);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Remove an existing directory
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DeleteDirectory(const std::string& Name)
+{
+ return SendCommand("RMD", Name);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Rename a file
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::RenameFile(const std::string& File, const std::string& NewName)
+{
+ Response Resp = SendCommand("RNFR", File);
+ if (Resp.IsOk())
+ Resp = SendCommand("RNTO", NewName);
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Remove an existing file
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DeleteFile(const std::string& Name)
+{
+ return SendCommand("DELE", Name);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Download a file from the server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode)
+{
+ // Open a data channel using the given transfer mode
+ DataChannel Data(*this);
+ Response Resp = Data.Open(Mode);
+ if (Resp.IsOk())
+ {
+ // Tell the server to start the transfer
+ Resp = SendCommand("RETR", DistantFile);
+ if (Resp.IsOk())
+ {
+ // Receive the file data
+ std::vector<char> FileData;
+ Data.Receive(FileData);
+
+ // Get the response from the server
+ Resp = GetResponse();
+ if (Resp.IsOk())
+ {
+ // Extract the filename from the file path
+ std::string Filename = DistantFile;
+ std::string::size_type Pos = Filename.find_last_of("/\\");
+ if (Pos != std::string::npos)
+ Filename = Filename.substr(Pos + 1);
+
+ // Make sure the destination path ends with a slash
+ std::string Path = DestPath;
+ if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
+ Path += "/";
+
+ // Create the file and copy the received data into it
+ std::ofstream File((Path + Filename).c_str(), std::ios_base::binary);
+ if (!File)
+ return Response(Response::InvalidFile);
+ File.write(&FileData[0], static_cast<std::streamsize>(FileData.size()));
+ }
+ }
+ }
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Upload a file to the server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode)
+{
+ // Get the contents of the file to send
+ std::ifstream File(LocalFile.c_str(), std::ios_base::binary);
+ if (!File)
+ return Response(Response::InvalidFile);
+ File.seekg(0, std::ios::end);
+ std::size_t Length = File.tellg();
+ File.seekg(0, std::ios::beg);
+ std::vector<char> FileData(Length);
+ File.read(&FileData[0], static_cast<std::streamsize>(Length));
+
+ // Extract the filename from the file path
+ std::string Filename = LocalFile;
+ std::string::size_type Pos = Filename.find_last_of("/\\");
+ if (Pos != std::string::npos)
+ Filename = Filename.substr(Pos + 1);
+
+ // Make sure the destination path ends with a slash
+ std::string Path = DestPath;
+ if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
+ Path += "/";
+
+ // Open a data channel using the given transfer mode
+ DataChannel Data(*this);
+ Response Resp = Data.Open(Mode);
+ if (Resp.IsOk())
+ {
+ // Tell the server to start the transfer
+ Resp = SendCommand("STOR", Path + Filename);
+ if (Resp.IsOk())
+ {
+ // Send the file data
+ Data.Send(FileData);
+
+ // Get the response from the server
+ Resp = GetResponse();
+ }
+ }
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a command to the FTP server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::SendCommand(const std::string& Command, const std::string& Parameter)
+{
+ // Build the command string
+ std::string CommandStr;
+ if (Parameter != "")
+ CommandStr = Command + " " + Parameter + "\r\n";
+ else
+ CommandStr = Command + "\r\n";
+
+ // Send it to the server
+ if (myCommandSocket.Send(CommandStr.c_str(), CommandStr.length()) != sf::Socket::Done)
+ return Response(Response::ConnectionClosed);
+
+ // Get the response
+ return GetResponse();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive a response from the server
+/// (usually after a command has been sent)
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::GetResponse()
+{
+ // We'll use a variable to keep track of the last valid code.
+ // It is useful in case of multi-lines responses, because the end of such a response
+ // will start by the same code
+ unsigned int LastCode = 0;
+ bool IsInsideMultiline = false;
+ std::string Message;
+
+ for (;;)
+ {
+ // Receive the response from the server
+ char Buffer[1024];
+ std::size_t Length;
+ if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done)
+ return Response(Response::ConnectionClosed);
+
+ // There can be several lines inside the received buffer, extract them all
+ std::istringstream In(std::string(Buffer, Length), std::ios_base::binary);
+ while (In)
+ {
+ // Try to extract the code
+ unsigned int Code;
+ if (In >> Code)
+ {
+ // Extract the separator
+ char Sep;
+ In.get(Sep);
+
+ // The '-' character means a multiline response
+ if ((Sep == '-') && !IsInsideMultiline)
+ {
+ // Set the multiline flag
+ IsInsideMultiline = true;
+
+ // Keep track of the code
+ if (LastCode == 0)
+ LastCode = Code;
+
+ // Extract the line
+ std::getline(In, Message);
+
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Message.erase(Message.length() - 1);
+ Message = Sep + Message + "\n";
+ }
+ else
+ {
+ // We must make sure that the code is the same, otherwise it means
+ // we haven't reached the end of the multiline response
+ if ((Sep != '-') && ((Code == LastCode) || (LastCode == 0)))
+ {
+ // Clear the multiline flag
+ IsInsideMultiline = false;
+
+ // Extract the line
+ std::string Line;
+ std::getline(In, Line);
+
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Line.erase(Line.length() - 1);
+
+ // Append it to the message
+ if (Code == LastCode)
+ {
+ std::ostringstream Out;
+ Out << Code << Sep << Line;
+ Message += Out.str();
+ }
+ else
+ {
+ Message = Sep + Line;
+ }
+
+ // Return the response code and message
+ return Response(static_cast<Response::Status>(Code), Message);
+ }
+ else
+ {
+ // The line we just read was actually not a response,
+ // only a new part of the current multiline response
+
+ // Extract the line
+ std::string Line;
+ std::getline(In, Line);
+
+ if (!Line.empty())
+ {
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Line.erase(Line.length() - 1);
+
+ // Append it to the current message
+ std::ostringstream Out;
+ Out << Code << Sep << Line << "\n";
+ Message += Out.str();
+ }
+ }
+ }
+ }
+ else if (LastCode != 0)
+ {
+ // It seems we are in the middle of a multiline response
+
+ // Clear the error bits of the stream
+ In.clear();
+
+ // Extract the line
+ std::string Line;
+ std::getline(In, Line);
+
+ if (!Line.empty())
+ {
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Line.erase(Line.length() - 1);
+
+ // Append it to the current message
+ Message += Line + "\n";
+ }
+ }
+ else
+ {
+ // Error : cannot extract the code, and we are not in a multiline response
+ return Response(Response::InvalidResponse);
+ }
+ }
+ }
+
+ // We never reach there
+}
+
+
+////////////////////////////////////////////////////////////
+/// Constructor
+////////////////////////////////////////////////////////////
+Ftp::DataChannel::DataChannel(Ftp& Owner) :
+myFtp(Owner)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Destructor
+////////////////////////////////////////////////////////////
+Ftp::DataChannel::~DataChannel()
+{
+ // Close the data socket
+ myDataSocket.Close();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Open the data channel using the specified mode and port
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode Mode)
+{
+ // Open a data connection in active mode (we connect to the server)
+ Ftp::Response Resp = myFtp.SendCommand("PASV");
+ if (Resp.IsOk())
+ {
+ // Extract the connection address and port from the response
+ std::string::size_type begin = Resp.GetMessage().find_first_of("0123456789");
+ if (begin != std::string::npos)
+ {
+ sf::Uint8 Data[6] = {0, 0, 0, 0, 0, 0};
+ std::string Str = Resp.GetMessage().substr(begin);
+ std::size_t Index = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ // Extract the current number
+ while (isdigit(Str[Index]))
+ {
+ Data[i] = Data[i] * 10 + (Str[Index] - '0');
+ Index++;
+ }
+
+ // Skip separator
+ Index++;
+ }
+
+ // Reconstruct connection port and address
+ unsigned short Port = Data[4] * 256 + Data[5];
+ sf::IPAddress Address(static_cast<sf::Uint8>(Data[0]),
+ static_cast<sf::Uint8>(Data[1]),
+ static_cast<sf::Uint8>(Data[2]),
+ static_cast<sf::Uint8>(Data[3]));
+
+ // Connect the data channel to the server
+ if (myDataSocket.Connect(Port, Address) == Socket::Done)
+ {
+ // Translate the transfer mode to the corresponding FTP parameter
+ std::string ModeStr;
+ switch (Mode)
+ {
+ case Ftp::Binary : ModeStr = "I"; break;
+ case Ftp::Ascii : ModeStr = "A"; break;
+ case Ftp::Ebcdic : ModeStr = "E"; break;
+ }
+
+ // Set the transfer mode
+ Resp = myFtp.SendCommand("TYPE", ModeStr);
+ }
+ else
+ {
+ // Failed to connect to the server
+ Resp = Ftp::Response(Ftp::Response::ConnectionFailed);
+ }
+ }
+ }
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive data on the data channel until it is closed
+////////////////////////////////////////////////////////////
+void Ftp::DataChannel::Receive(std::vector<char>& Data)
+{
+ // Receive data
+ Data.clear();
+ char Buffer[1024];
+ std::size_t Received;
+ while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done)
+ {
+ std::copy(Buffer, Buffer + Received, std::back_inserter(Data));
+ }
+
+ // Close the data socket
+ myDataSocket.Close();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send data on the data channel
+////////////////////////////////////////////////////////////
+void Ftp::DataChannel::Send(const std::vector<char>& Data)
+{
+ // Send data
+ myDataSocket.Send(&Data[0], Data.size());
+
+ // Close the data socket
+ myDataSocket.Close();
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/.svn/text-base/Http.cpp.svn-base b/src/SFML/Network/.svn/text-base/Http.cpp.svn-base
new file mode 100644
index 0000000..1becb80
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/Http.cpp.svn-base
@@ -0,0 +1,425 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Http.hpp>
+#include <ctype.h>
+#include <sstream>
+
+
+namespace
+{
+ ////////////////////////////////////////////////////////////
+ // Convenience function to convert a string to lower case
+ ////////////////////////////////////////////////////////////
+ std::string ToLower(const std::string& Str)
+ {
+ std::string Ret = Str;
+ for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
+ *i = static_cast<char>(tolower(*i));
+
+ return Ret;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body) :
+myMethod (RequestMethod),
+myURI (URI),
+myMajorVersion(1),
+myMinorVersion(0),
+myBody (Body)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the value of a field; the field is added if it doesn't exist
+////////////////////////////////////////////////////////////
+void Http::Request::SetField(const std::string& Field, const std::string& Value)
+{
+ myFields[ToLower(Field)] = Value;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the request method.
+/// This parameter is Get by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetMethod(Http::Request::Method RequestMethod)
+{
+ myMethod = RequestMethod;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the target URI of the request.
+/// This parameter is "/" by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetURI(const std::string& URI)
+{
+ myURI = URI;
+
+ // Make sure it starts with a '/'
+ if (myURI.empty() || (myURI[0] != '/'))
+ myURI.insert(0, "/");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the HTTP version of the request.
+/// This parameter is 1.0 by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor)
+{
+ myMajorVersion = Major;
+ myMinorVersion = Minor;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the body of the request. This parameter is optional and
+/// makes sense only for POST requests.
+/// This parameter is empty by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetBody(const std::string& Body)
+{
+ myBody = Body;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the string representation of a request header
+////////////////////////////////////////////////////////////
+std::string Http::Request::ToString() const
+{
+ std::ostringstream Out;
+
+ // Convert the method to its string representation
+ std::string RequestMethod;
+ switch (myMethod)
+ {
+ default :
+ case Get : RequestMethod = "GET"; break;
+ case Post : RequestMethod = "POST"; break;
+ case Head : RequestMethod = "HEAD"; break;
+ }
+
+ // Write the first line containing the request type
+ Out << RequestMethod << " " << myURI << " ";
+ Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n";
+
+ // Write fields
+ for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i)
+ {
+ Out << i->first << ": " << i->second << "\r\n";
+ }
+
+ // Use an extra \r\n to separate the header from the body
+ Out << "\r\n";
+
+ // Add the body
+ Out << myBody;
+
+ return Out.str();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Check if the given field has been defined
+////////////////////////////////////////////////////////////
+bool Http::Request::HasField(const std::string& Field) const
+{
+ return myFields.find(Field) != myFields.end();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Http::Response::Response() :
+myStatus (ConnectionFailed),
+myMajorVersion(0),
+myMinorVersion(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the value of a field
+////////////////////////////////////////////////////////////
+const std::string& Http::Response::GetField(const std::string& Field) const
+{
+ FieldTable::const_iterator It = myFields.find(Field);
+ if (It != myFields.end())
+ {
+ return It->second;
+ }
+ else
+ {
+ static const std::string Empty = "";
+ return Empty;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the header's status code
+////////////////////////////////////////////////////////////
+Http::Response::Status Http::Response::GetStatus() const
+{
+ return myStatus;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the major HTTP version number of the response
+////////////////////////////////////////////////////////////
+unsigned int Http::Response::GetMajorHttpVersion() const
+{
+ return myMajorVersion;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the major HTTP version number of the response
+////////////////////////////////////////////////////////////
+unsigned int Http::Response::GetMinorHttpVersion() const
+{
+ return myMinorVersion;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the body of the response. The body can contain :
+/// - the requested page (for GET requests)
+/// - a response from the server (for POST requests)
+/// - nothing (for HEAD requests)
+/// - an error message (in case of an error)
+////////////////////////////////////////////////////////////
+const std::string& Http::Response::GetBody() const
+{
+ return myBody;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the header from a response string
+////////////////////////////////////////////////////////////
+void Http::Response::FromString(const std::string& Data)
+{
+ std::istringstream In(Data);
+
+ // Extract the HTTP version from the first line
+ std::string Version;
+ if (In >> Version)
+ {
+ if ((Version.size() >= 8) && (Version[6] == '.') &&
+ (ToLower(Version.substr(0, 5)) == "http/") &&
+ isdigit(Version[5]) && isdigit(Version[7]))
+ {
+ myMajorVersion = Version[5] - '0';
+ myMinorVersion = Version[7] - '0';
+ }
+ else
+ {
+ // Invalid HTTP version
+ myStatus = InvalidResponse;
+ return;
+ }
+ }
+
+ // Extract the status code from the first line
+ int StatusCode;
+ if (In >> StatusCode)
+ {
+ myStatus = static_cast<Status>(StatusCode);
+ }
+ else
+ {
+ // Invalid status code
+ myStatus = InvalidResponse;
+ return;
+ }
+
+ // Ignore the end of the first line
+ In.ignore(10000, '\n');
+
+ // Parse the other lines, which contain fields, one by one
+ std::string Line;
+ while (std::getline(In, Line) && (Line.size() > 2))
+ {
+ std::string::size_type Pos = Line.find(": ");
+ if (Pos != std::string::npos)
+ {
+ // Extract the field name and its value
+ std::string Field = Line.substr(0, Pos);
+ std::string Value = Line.substr(Pos + 2);
+
+ // Remove any trailing \r
+ if (!Value.empty() && (*Value.rbegin() == '\r'))
+ Value.erase(Value.size() - 1);
+
+ // Add the field
+ myFields[ToLower(Field)] = Value;
+ }
+ }
+
+ // Finally extract the body
+ myBody.clear();
+ while (std::getline(In, Line))
+ myBody += Line + "\n";
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Http::Http() :
+myHost(),
+myPort(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the Http instance with the target host
+////////////////////////////////////////////////////////////
+Http::Http(const std::string& Host, unsigned short Port)
+{
+ SetHost(Host, Port);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the target host
+////////////////////////////////////////////////////////////
+void Http::SetHost(const std::string& Host, unsigned short Port)
+{
+ // Detect the protocol used
+ std::string Protocol = ToLower(Host.substr(0, 8));
+ if (Protocol.substr(0, 7) == "http://")
+ {
+ // HTTP protocol
+ myHostName = Host.substr(7);
+ myPort = (Port != 0 ? Port : 80);
+ }
+ else if (Protocol == "https://")
+ {
+ // HTTPS protocol
+ myHostName = Host.substr(8);
+ myPort = (Port != 0 ? Port : 443);
+ }
+ else
+ {
+ // Undefined protocol - use HTTP
+ myHostName = Host;
+ myPort = (Port != 0 ? Port : 80);
+ }
+
+ // Remove any trailing '/' from the host name
+ if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
+ myHostName.erase(myHostName.size() - 1);
+
+ myHost = sf::IPAddress(myHostName);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a HTTP request and return the server's response.
+/// You must be connected to a host before sending requests.
+/// Any missing mandatory header field will be added with an appropriate value.
+/// Warning : this function waits for the server's response and may
+/// not return instantly; use a thread if you don't want to block your
+/// application.
+////////////////////////////////////////////////////////////
+Http::Response Http::SendRequest(const Http::Request& Req)
+{
+ // First make sure the request is valid -- add missing mandatory fields
+ Request ToSend(Req);
+ if (!ToSend.HasField("From"))
+ {
+ ToSend.SetField("From", "user@sfml-dev.org");
+ }
+ if (!ToSend.HasField("User-Agent"))
+ {
+ ToSend.SetField("User-Agent", "libsfml-network/1.x");
+ }
+ if (!ToSend.HasField("Host"))
+ {
+ ToSend.SetField("Host", myHostName);
+ }
+ if (!ToSend.HasField("Content-Length"))
+ {
+ std::ostringstream Out;
+ Out << ToSend.myBody.size();
+ ToSend.SetField("Content-Length", Out.str());
+ }
+
+ // Prepare the response
+ Response Received;
+
+ // Connect the socket to the host
+ if (myConnection.Connect(myPort, myHost) == Socket::Done)
+ {
+ // Convert the request to string and send it through the connected socket
+ std::string RequestStr = ToSend.ToString();
+
+ if (!RequestStr.empty())
+ {
+ // Send it through the socket
+ if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
+ {
+ // Wait for the server's response
+ std::string ReceivedStr;
+ std::size_t Size = 0;
+ char Buffer[1024];
+ while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
+ {
+ ReceivedStr.append(Buffer, Buffer + Size);
+ }
+
+ // Build the Response object from the received data
+ Received.FromString(ReceivedStr);
+ }
+ }
+
+ // Close the connection
+ myConnection.Close();
+ }
+
+ return Received;
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/.svn/text-base/IPAddress.cpp.svn-base b/src/SFML/Network/.svn/text-base/IPAddress.cpp.svn-base
new file mode 100644
index 0000000..cd34613
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/IPAddress.cpp.svn-base
@@ -0,0 +1,303 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/IPAddress.hpp>
+#include <SFML/Network/Http.hpp>
+#include <SFML/Network/SocketHelper.hpp>
+#include <string.h>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Static member data
+////////////////////////////////////////////////////////////
+const IPAddress IPAddress::LocalHost("127.0.0.1");
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+IPAddress::IPAddress() :
+myAddress(INADDR_NONE)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the address from a string
+////////////////////////////////////////////////////////////
+IPAddress::IPAddress(const std::string& Address)
+{
+ // First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
+ myAddress = inet_addr(Address.c_str());
+
+ // If not successful, try to convert it as a host name
+ if (!IsValid())
+ {
+ hostent* Host = gethostbyname(Address.c_str());
+ if (Host)
+ {
+ // Host found, extract its IP address
+ myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
+ }
+ else
+ {
+ // Host name not found on the network
+ myAddress = INADDR_NONE;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the address from a C-style string ;
+/// Needed for implicit conversions from literal strings to IPAddress to work
+////////////////////////////////////////////////////////////
+IPAddress::IPAddress(const char* Address)
+{
+ // First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
+ myAddress = inet_addr(Address);
+
+ // If not successful, try to convert it as a host name
+ if (!IsValid())
+ {
+ hostent* Host = gethostbyname(Address);
+ if (Host)
+ {
+ // Host found, extract its IP address
+ myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
+ }
+ else
+ {
+ // Host name not found on the network
+ myAddress = INADDR_NONE;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the address from 4 bytes
+////////////////////////////////////////////////////////////
+IPAddress::IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3)
+{
+ myAddress = htonl((Byte0 << 24) | (Byte1 << 16) | (Byte2 << 8) | Byte3);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the address from a 32-bits integer
+////////////////////////////////////////////////////////////
+IPAddress::IPAddress(Uint32 Address)
+{
+ myAddress = htonl(Address);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Tell if the address is a valid one
+////////////////////////////////////////////////////////////
+bool IPAddress::IsValid() const
+{
+ return myAddress != INADDR_NONE;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get a string representation of the address
+////////////////////////////////////////////////////////////
+std::string IPAddress::ToString() const
+{
+ in_addr InAddr;
+ InAddr.s_addr = myAddress;
+
+ return inet_ntoa(InAddr);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get an integer representation of the address
+////////////////////////////////////////////////////////////
+Uint32 IPAddress::ToInteger() const
+{
+ return ntohl(myAddress);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the computer's local IP address (from the LAN point of view)
+////////////////////////////////////////////////////////////
+IPAddress IPAddress::GetLocalAddress()
+{
+ // The method here is to connect a UDP socket to anyone (here to localhost),
+ // and get the local socket address with the getsockname function.
+ // UDP connection will not send anything to the network, so this function won't cause any overhead
+
+ IPAddress LocalAddress;
+
+ // Create the socket
+ SocketHelper::SocketType Socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (Socket == SocketHelper::InvalidSocket())
+ return LocalAddress;
+
+ // Build the host address (use a random port)
+ sockaddr_in SockAddr;
+ memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
+ SockAddr.sin_addr.s_addr = INADDR_LOOPBACK;
+ SockAddr.sin_family = AF_INET;
+ SockAddr.sin_port = htons(4567);
+
+ // Connect the socket
+ if (connect(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
+ {
+ SocketHelper::Close(Socket);
+ return LocalAddress;
+ }
+
+ // Get the local address of the socket connection
+ SocketHelper::LengthType Size = sizeof(SockAddr);
+ if (getsockname(Socket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) == -1)
+ {
+ SocketHelper::Close(Socket);
+ return LocalAddress;
+ }
+
+ // Close the socket
+ SocketHelper::Close(Socket);
+
+ // Finally build the IP address
+ LocalAddress.myAddress = SockAddr.sin_addr.s_addr;
+
+ return LocalAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the computer's public IP address (from the web point of view)
+////////////////////////////////////////////////////////////
+IPAddress IPAddress::GetPublicAddress()
+{
+ // The trick here is more complicated, because the only way
+ // to get our public IP address is to get it from a distant computer.
+ // Here we get the web page from http://www.whatismyip.org
+ // and parse the result to extract our IP address
+ // (not very hard : the web page contains only our IP address)
+
+ IPAddress PublicAddress;
+
+ // Connect to the web server and get its index page
+ Http Server("www.whatismyip.org");
+ Http::Request Request(Http::Request::Get, "/");
+ Http::Response Page = Server.SendRequest(Request);
+
+ // If the request was successful, we can extract
+ // the address from the body of the web page
+ if (Page.GetStatus() == Http::Response::Ok)
+ PublicAddress = Page.GetBody();
+
+ return PublicAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator ==
+////////////////////////////////////////////////////////////
+bool IPAddress::operator ==(const IPAddress& Other) const
+{
+ return myAddress == Other.myAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator !=
+////////////////////////////////////////////////////////////
+bool IPAddress::operator !=(const IPAddress& Other) const
+{
+ return myAddress != Other.myAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator <
+////////////////////////////////////////////////////////////
+bool IPAddress::operator <(const IPAddress& Other) const
+{
+ return myAddress < Other.myAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator >
+////////////////////////////////////////////////////////////
+bool IPAddress::operator >(const IPAddress& Other) const
+{
+ return myAddress > Other.myAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator <=
+////////////////////////////////////////////////////////////
+bool IPAddress::operator <=(const IPAddress& Other) const
+{
+ return myAddress <= Other.myAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator >=
+////////////////////////////////////////////////////////////
+bool IPAddress::operator >=(const IPAddress& Other) const
+{
+ return myAddress >= Other.myAddress;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Operator >> overload to extract an address from an input stream
+////////////////////////////////////////////////////////////
+std::istream& operator >>(std::istream& Stream, IPAddress& Address)
+{
+ std::string Str;
+ Stream >> Str;
+ Address = IPAddress(Str);
+
+ return Stream;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Operator << overload to print an address to an output stream
+////////////////////////////////////////////////////////////
+std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address)
+{
+ return Stream << Address.ToString();
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/.svn/text-base/Makefile.svn-base b/src/SFML/Network/.svn/text-base/Makefile.svn-base
new file mode 100644
index 0000000..d30da62
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,34 @@
+SRC = $(wildcard *.cpp ./Unix/*.cpp)
+OBJ = $(SRC:.cpp=.o)
+
+ifeq ($(STATIC), yes)
+ LIB = libsfml-network-s.a
+ LIBNAME = $(LIBPATH)/$(LIB)
+ INSTALL =
+else
+ LIB = libsfml-network.so
+ LIBNAME = $(LIBPATH)/$(LIB).$(VERSION)
+ INSTALL = && $(LN) $(LNFLAGS) $(DESTLIBDIR)/$(LIB).$(VERSION) $(DESTLIBDIR)/$(LIB)
+endif
+
+all: $(LIB)
+
+libsfml-network-s.a: $(OBJ)
+ $(AR) $(ARFLAGS) $(LIBNAME) $(OBJ)
+
+libsfml-network.so: $(OBJ)
+ $(CPP) $(LDFLAGS) -Wl,-soname,$(LIB).$(VERSION) -o $(LIBNAME) $(OBJ)
+
+$(OBJ): %.o: %.cpp
+ $(CPP) -o $@ -c $< $(CFLAGS)
+
+.PHONY: clean mrproper
+
+clean:
+ @rm -rf $(OBJ)
+
+mrproper: clean
+ @rm -rf $(LIBNAME)
+
+install:
+ @($(CP) $(LIBNAME) $(DESTLIBDIR) $(INSTALL))
diff --git a/src/SFML/Network/.svn/text-base/Packet.cpp.svn-base b/src/SFML/Network/.svn/text-base/Packet.cpp.svn-base
new file mode 100644
index 0000000..df693d5
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/Packet.cpp.svn-base
@@ -0,0 +1,426 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/SocketHelper.hpp>
+#include <string.h>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Packet::Packet() :
+myReadPos(0),
+myIsValid(true)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Virtual destructor
+////////////////////////////////////////////////////////////
+Packet::~Packet()
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Append data to the end of the packet
+////////////////////////////////////////////////////////////
+void Packet::Append(const void* Data, std::size_t SizeInBytes)
+{
+ if (Data && (SizeInBytes > 0))
+ {
+ std::size_t Start = myData.size();
+ myData.resize(Start + SizeInBytes);
+ memcpy(&myData[Start], Data, SizeInBytes);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Clear the packet data
+////////////////////////////////////////////////////////////
+void Packet::Clear()
+{
+ myData.clear();
+ myReadPos = 0;
+ myIsValid = true;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get a pointer to the data contained in the packet
+/// Warning : the returned pointer may be invalid after you
+/// append data to the packet
+////////////////////////////////////////////////////////////
+const char* Packet::GetData() const
+{
+ return !myData.empty() ? &myData[0] : NULL;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the size of the data contained in the packet
+////////////////////////////////////////////////////////////
+std::size_t Packet::GetDataSize() const
+{
+ return myData.size();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Tell if the reading position has reached the end of the packet
+////////////////////////////////////////////////////////////
+bool Packet::EndOfPacket() const
+{
+ return myReadPos >= myData.size();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Tell if the packet is valid for reading
+////////////////////////////////////////////////////////////
+Packet::operator bool() const
+{
+ return myIsValid;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Operator >> overloads to extract data from the packet
+////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(bool& Data)
+{
+ Uint8 Value;
+ if (*this >> Value)
+ Data = (Value != 0);
+
+ return *this;
+}
+Packet& Packet::operator >>(Int8& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = *reinterpret_cast<const Int8*>(GetData() + myReadPos);
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(Uint8& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = *reinterpret_cast<const Uint8*>(GetData() + myReadPos);
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(Int16& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = ntohs(*reinterpret_cast<const Int16*>(GetData() + myReadPos));
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(Uint16& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = ntohs(*reinterpret_cast<const Uint16*>(GetData() + myReadPos));
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(Int32& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = ntohl(*reinterpret_cast<const Int32*>(GetData() + myReadPos));
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(Uint32& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = ntohl(*reinterpret_cast<const Uint32*>(GetData() + myReadPos));
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(float& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = *reinterpret_cast<const float*>(GetData() + myReadPos);
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(double& Data)
+{
+ if (CheckSize(sizeof(Data)))
+ {
+ Data = *reinterpret_cast<const double*>(GetData() + myReadPos);
+ myReadPos += sizeof(Data);
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(char* Data)
+{
+ // First extract string length
+ Uint32 Length;
+ *this >> Length;
+
+ if ((Length > 0) && CheckSize(Length))
+ {
+ // Then extract characters
+ memcpy(Data, GetData() + myReadPos, Length);
+ Data[Length] = '\0';
+
+ // Update reading position
+ myReadPos += Length;
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(std::string& Data)
+{
+ // First extract string length
+ Uint32 Length;
+ *this >> Length;
+
+ Data.clear();
+ if ((Length > 0) && CheckSize(Length))
+ {
+ // Then extract characters
+ Data.assign(GetData() + myReadPos, Length);
+
+ // Update reading position
+ myReadPos += Length;
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(wchar_t* Data)
+{
+ // First extract string length
+ Uint32 Length;
+ *this >> Length;
+
+ if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
+ {
+ // Then extract characters
+ for (Uint32 i = 0; i < Length; ++i)
+ {
+ Uint32 c;
+ *this >> c;
+ Data[i] = static_cast<wchar_t>(c);
+ }
+ Data[Length] = L'\0';
+ }
+
+ return *this;
+}
+Packet& Packet::operator >>(std::wstring& Data)
+{
+ // First extract string length
+ Uint32 Length;
+ *this >> Length;
+
+ Data.clear();
+ if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
+ {
+ // Then extract characters
+ for (Uint32 i = 0; i < Length; ++i)
+ {
+ Uint32 c;
+ *this >> c;
+ Data += static_cast<wchar_t>(c);
+ }
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Operator << overloads to put data into the packet
+////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(bool Data)
+{
+ *this << static_cast<Uint8>(Data);
+ return *this;
+}
+Packet& Packet::operator <<(Int8 Data)
+{
+ Append(&Data, sizeof(Data));
+ return *this;
+}
+Packet& Packet::operator <<(Uint8 Data)
+{
+ Append(&Data, sizeof(Data));
+ return *this;
+}
+Packet& Packet::operator <<(Int16 Data)
+{
+ Int16 ToWrite = htons(Data);
+ Append(&ToWrite, sizeof(ToWrite));
+ return *this;
+}
+Packet& Packet::operator <<(Uint16 Data)
+{
+ Uint16 ToWrite = htons(Data);
+ Append(&ToWrite, sizeof(ToWrite));
+ return *this;
+}
+Packet& Packet::operator <<(Int32 Data)
+{
+ Int32 ToWrite = htonl(Data);
+ Append(&ToWrite, sizeof(ToWrite));
+ return *this;
+}
+Packet& Packet::operator <<(Uint32 Data)
+{
+ Uint32 ToWrite = htonl(Data);
+ Append(&ToWrite, sizeof(ToWrite));
+ return *this;
+}
+Packet& Packet::operator <<(float Data)
+{
+ Append(&Data, sizeof(Data));
+ return *this;
+}
+Packet& Packet::operator <<(double Data)
+{
+ Append(&Data, sizeof(Data));
+ return *this;
+}
+Packet& Packet::operator <<(const char* Data)
+{
+ // First insert string length
+ Uint32 Length = 0;
+ for (const char* c = Data; *c != '\0'; ++c)
+ ++Length;
+ *this << Length;
+
+ // Then insert characters
+ Append(Data, Length * sizeof(char));
+
+ return *this;
+}
+Packet& Packet::operator <<(const std::string& Data)
+{
+ // First insert string length
+ Uint32 Length = static_cast<Uint32>(Data.size());
+ *this << Length;
+
+ // Then insert characters
+ if (Length > 0)
+ {
+ Append(Data.c_str(), Length * sizeof(std::string::value_type));
+ }
+
+ return *this;
+}
+Packet& Packet::operator <<(const wchar_t* Data)
+{
+ // First insert string length
+ Uint32 Length = 0;
+ for (const wchar_t* c = Data; *c != L'\0'; ++c)
+ ++Length;
+ *this << Length;
+
+ // Then insert characters
+ for (const wchar_t* c = Data; *c != L'\0'; ++c)
+ *this << static_cast<Int32>(*c);
+
+ return *this;
+}
+Packet& Packet::operator <<(const std::wstring& Data)
+{
+ // First insert string length
+ Uint32 Length = static_cast<Uint32>(Data.size());
+ *this << Length;
+
+ // Then insert characters
+ if (Length > 0)
+ {
+ for (std::wstring::const_iterator c = Data.begin(); c != Data.end(); ++c)
+ *this << static_cast<Int32>(*c);
+ }
+
+ return *this;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Check if the packet can extract a given size of bytes
+////////////////////////////////////////////////////////////
+bool Packet::CheckSize(std::size_t Size)
+{
+ myIsValid = myIsValid && (myReadPos + Size <= myData.size());
+
+ return myIsValid;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Called before the packet is sent to the network
+////////////////////////////////////////////////////////////
+const char* Packet::OnSend(std::size_t& DataSize)
+{
+ DataSize = GetDataSize();
+ return GetData();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Called after the packet has been received from the network
+////////////////////////////////////////////////////////////
+void Packet::OnReceive(const char* Data, std::size_t DataSize)
+{
+ Append(Data, DataSize);
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/.svn/text-base/SelectorBase.cpp.svn-base b/src/SFML/Network/.svn/text-base/SelectorBase.cpp.svn-base
new file mode 100644
index 0000000..6631753
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/SelectorBase.cpp.svn-base
@@ -0,0 +1,132 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+ #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
+#endif
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/SelectorBase.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+SelectorBase::SelectorBase() :
+myMaxSocket(0)
+{
+ Clear();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Add a socket to watch
+////////////////////////////////////////////////////////////
+void SelectorBase::Add(SocketHelper::SocketType Socket)
+{
+ FD_SET(Socket, &mySet);
+
+ int Size = static_cast<int>(Socket);
+ if (Size > myMaxSocket)
+ myMaxSocket = Size;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Remove a socket
+////////////////////////////////////////////////////////////
+void SelectorBase::Remove(SocketHelper::SocketType Socket)
+{
+ FD_CLR(Socket, &mySet);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Remove all sockets
+////////////////////////////////////////////////////////////
+void SelectorBase::Clear()
+{
+ FD_ZERO(&mySet);
+ FD_ZERO(&mySetReady);
+
+ myMaxSocket = 0;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Wait and collect sockets which are ready for reading.
+/// This functions will return either when at least one socket
+/// is ready, or when the given time is out
+////////////////////////////////////////////////////////////
+unsigned int SelectorBase::Wait(float Timeout)
+{
+ // Setup the timeout structure
+ timeval Time;
+ Time.tv_sec = static_cast<long>(Timeout);
+ Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
+
+ // Prepare the set of sockets to return
+ mySetReady = mySet;
+
+ // Wait until one of the sockets is ready for reading, or timeout is reached
+ int NbSockets = select(myMaxSocket + 1, &mySetReady, NULL, NULL, Timeout > 0 ? &Time : NULL);
+
+ return NbSockets >= 0 ? static_cast<unsigned int>(NbSockets) : 0;
+}
+
+
+////////////////////////////////////////////////////////////
+/// After a call to Wait(), get the Index-th socket which is
+/// ready for reading. The total number of sockets ready
+/// is the integer returned by the previous call to Wait()
+////////////////////////////////////////////////////////////
+SocketHelper::SocketType SelectorBase::GetSocketReady(unsigned int Index)
+{
+ // The standard FD_xxx interface doesn't define a direct access,
+ // so we must go through the whole set to find the socket we're looking for
+ for (int i = 0; i < myMaxSocket + 1; ++i)
+ {
+ if (FD_ISSET(i, &mySetReady))
+ {
+ // Current socket is ready, but is it the Index-th one ?
+ if (Index > 0)
+ {
+ Index--;
+ }
+ else
+ {
+ return static_cast<SocketHelper::SocketType>(i);
+ }
+ }
+ }
+
+ // Invalid index : return an invalid socket
+ return SocketHelper::InvalidSocket();
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/.svn/text-base/SocketTCP.cpp.svn-base b/src/SFML/Network/.svn/text-base/SocketTCP.cpp.svn-base
new file mode 100644
index 0000000..1f5e553
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/SocketTCP.cpp.svn-base
@@ -0,0 +1,486 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/SocketTCP.hpp>
+#include <SFML/Network/IPAddress.hpp>
+#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/SocketHelper.hpp>
+#include <algorithm>
+#include <iostream>
+#include <string.h>
+
+
+#ifdef _MSC_VER
+ #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
+#endif
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+SocketTCP::SocketTCP()
+{
+ Create(SocketHelper::InvalidSocket());
+}
+
+
+////////////////////////////////////////////////////////////
+/// Change the blocking state of the socket
+////////////////////////////////////////////////////////////
+void SocketTCP::SetBlocking(bool Blocking)
+{
+ // Make sure our socket is valid
+ if (!IsValid())
+ Create();
+
+ SocketHelper::SetBlocking(mySocket, Blocking);
+ myIsBlocking = Blocking;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Connect to another computer on a specified port
+////////////////////////////////////////////////////////////
+Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout)
+{
+ // Make sure our socket is valid
+ if (!IsValid())
+ Create();
+
+ // Build the host address
+ sockaddr_in SockAddr;
+ memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
+ SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str());
+ SockAddr.sin_family = AF_INET;
+ SockAddr.sin_port = htons(Port);
+
+ if (Timeout <= 0)
+ {
+ // ----- We're not using a timeout : just try to connect -----
+
+ if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
+ {
+ // Failed to connect
+ return SocketHelper::GetErrorStatus();
+ }
+
+ // Connection succeeded
+ return Socket::Done;
+ }
+ else
+ {
+ // ----- We're using a timeout : we'll need a few tricks to make it work -----
+
+ // Save the previous blocking state
+ bool IsBlocking = myIsBlocking;
+
+ // Switch to non-blocking to enable our connection timeout
+ if (IsBlocking)
+ SetBlocking(false);
+
+ // Try to connect to host
+ if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0)
+ {
+ // We got instantly connected! (it may no happen a lot...)
+ return Socket::Done;
+ }
+
+ // Get the error status
+ Socket::Status Status = SocketHelper::GetErrorStatus();
+
+ // If we were in non-blocking mode, return immediatly
+ if (!IsBlocking)
+ return Status;
+
+ // Otherwise, wait until something happens to our socket (success, timeout or error)
+ if (Status == Socket::NotReady)
+ {
+ // Setup the selector
+ fd_set Selector;
+ FD_ZERO(&Selector);
+ FD_SET(mySocket, &Selector);
+
+ // Setup the timeout
+ timeval Time;
+ Time.tv_sec = static_cast<long>(Timeout);
+ Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
+
+ // Wait for something to write on our socket (would mean the connection has been accepted)
+ if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0)
+ {
+ // Connection succeeded
+ Status = Socket::Done;
+ }
+ else
+ {
+ // Failed to connect before timeout is over
+ Status = SocketHelper::GetErrorStatus();
+ }
+ }
+
+ // Switch back to blocking mode
+ SetBlocking(true);
+
+ return Status;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Listen to a specified port for incoming data or connections
+////////////////////////////////////////////////////////////
+bool SocketTCP::Listen(unsigned short Port)
+{
+ // Make sure our socket is valid
+ if (!IsValid())
+ Create();
+
+ // Build the address
+ sockaddr_in SockAddr;
+ memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
+ SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ SockAddr.sin_family = AF_INET;
+ SockAddr.sin_port = htons(Port);
+
+ // Bind the socket to the specified port
+ if (bind(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
+ {
+ // Not likely to happen, but...
+ std::cerr << "Failed to bind socket to port " << Port << std::endl;
+ return false;
+ }
+
+ // Listen to the bound port
+ if (listen(mySocket, 0) == -1)
+ {
+ // Oops, socket is deaf
+ std::cerr << "Failed to listen to port " << Port << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Wait for a connection (must be listening to a port).
+/// This function will block if the socket is blocking
+////////////////////////////////////////////////////////////
+Socket::Status SocketTCP::Accept(SocketTCP& Connected, IPAddress* Address)
+{
+ // Address that will be filled with client informations
+ sockaddr_in ClientAddress;
+ SocketHelper::LengthType Length = sizeof(ClientAddress);
+
+ // Accept a new connection
+ Connected = accept(mySocket, reinterpret_cast<sockaddr*>(&ClientAddress), &Length);
+
+ // Check errors
+ if (!Connected.IsValid())
+ {
+ if (Address)
+ *Address = IPAddress();
+
+ return SocketHelper::GetErrorStatus();
+ }
+
+ // Fill address if requested
+ if (Address)
+ *Address = IPAddress(inet_ntoa(ClientAddress.sin_addr));
+
+ return Socket::Done;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send an array of bytes to the host (must be connected first)
+////////////////////////////////////////////////////////////
+Socket::Status SocketTCP::Send(const char* Data, std::size_t Size)
+{
+ // First check that socket is valid
+ if (!IsValid())
+ return Socket::Error;
+
+ // Check parameters
+ if (Data && Size)
+ {
+ // Loop until every byte has been sent
+ int Sent = 0;
+ int SizeToSend = static_cast<int>(Size);
+ for (int Length = 0; Length < SizeToSend; Length += Sent)
+ {
+ // Send a chunk of data
+ Sent = send(mySocket, Data + Length, SizeToSend - Length, 0);
+
+ // Check if an error occured
+ if (Sent <= 0)
+ return SocketHelper::GetErrorStatus();
+ }
+
+ return Socket::Done;
+ }
+ else
+ {
+ // Error...
+ std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
+ return Socket::Error;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive an array of bytes from the host (must be connected first).
+/// This function will block if the socket is blocking
+////////////////////////////////////////////////////////////
+Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived)
+{
+ // First clear the size received
+ SizeReceived = 0;
+
+ // Check that socket is valid
+ if (!IsValid())
+ return Socket::Error;
+
+ // Check parameters
+ if (Data && MaxSize)
+ {
+ // Receive a chunk of bytes
+ int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
+
+ // Check the number of bytes received
+ if (Received > 0)
+ {
+ SizeReceived = static_cast<std::size_t>(Received);
+ return Socket::Done;
+ }
+ else if (Received == 0)
+ {
+ return Socket::Disconnected;
+ }
+ else
+ {
+ return SocketHelper::GetErrorStatus();
+ }
+ }
+ else
+ {
+ // Error...
+ std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
+ return Socket::Error;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a packet of data to the host (must be connected first)
+////////////////////////////////////////////////////////////
+Socket::Status SocketTCP::Send(Packet& PacketToSend)
+{
+ // Get the data to send from the packet
+ std::size_t DataSize = 0;
+ const char* Data = PacketToSend.OnSend(DataSize);
+
+ // Send the packet size
+ Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
+ Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize));
+
+ // Send the packet data
+ if (PacketSize > 0)
+ {
+ return Send(Data, DataSize);
+ }
+ else
+ {
+ return Socket::Done;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive a packet from the host (must be connected first).
+/// This function will block if the socket is blocking
+////////////////////////////////////////////////////////////
+Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
+{
+ // We start by getting the size of the incoming packet
+ Uint32 PacketSize = 0;
+ std::size_t Received = 0;
+ if (myPendingPacketSize < 0)
+ {
+ Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received);
+ if (Status != Socket::Done)
+ return Status;
+
+ PacketSize = ntohl(PacketSize);
+ }
+ else
+ {
+ // There is a pending packet : we already know its size
+ PacketSize = myPendingPacketSize;
+ }
+
+ // Then loop until we receive all the packet data
+ char Buffer[1024];
+ while (myPendingPacket.size() < PacketSize)
+ {
+ // Receive a chunk of data
+ std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
+ Socket::Status Status = Receive(Buffer, SizeToGet, Received);
+ if (Status != Socket::Done)
+ {
+ // We must save the size of the pending packet until we can receive its content
+ if (Status == Socket::NotReady)
+ myPendingPacketSize = PacketSize;
+ return Status;
+ }
+
+ // Append it into the packet
+ if (Received > 0)
+ {
+ myPendingPacket.resize(myPendingPacket.size() + Received);
+ char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
+ memcpy(Begin, Buffer, Received);
+ }
+ }
+
+ // We have received all the datas : we can copy it to the user packet, and clear our internal packet
+ PacketToReceive.Clear();
+ if (!myPendingPacket.empty())
+ PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
+ myPendingPacket.clear();
+ myPendingPacketSize = -1;
+
+ return Socket::Done;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Close the socket
+////////////////////////////////////////////////////////////
+bool SocketTCP::Close()
+{
+ if (!SocketHelper::Close(mySocket))
+ {
+ std::cerr << "Failed to close socket" << std::endl;
+ return false;
+ }
+
+ mySocket = SocketHelper::InvalidSocket();
+ myIsBlocking = true;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Check if the socket is in a valid state ; this function
+/// can be called any time to check if the socket is OK
+////////////////////////////////////////////////////////////
+bool SocketTCP::IsValid() const
+{
+ return mySocket != SocketHelper::InvalidSocket();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator ==
+////////////////////////////////////////////////////////////
+bool SocketTCP::operator ==(const SocketTCP& Other) const
+{
+ return mySocket == Other.mySocket;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator !=
+////////////////////////////////////////////////////////////
+bool SocketTCP::operator !=(const SocketTCP& Other) const
+{
+ return mySocket != Other.mySocket;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator <.
+/// Provided for compatibility with standard containers, as
+/// comparing two sockets doesn't make much sense...
+////////////////////////////////////////////////////////////
+bool SocketTCP::operator <(const SocketTCP& Other) const
+{
+ return mySocket < Other.mySocket;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the socket from a socket descriptor
+/// (for internal use only)
+////////////////////////////////////////////////////////////
+SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor)
+{
+ Create(Descriptor);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Create the socket
+////////////////////////////////////////////////////////////
+void SocketTCP::Create(SocketHelper::SocketType Descriptor)
+{
+ // Use the given socket descriptor, or get a new one
+ mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0);
+ myIsBlocking = true;
+
+ // Reset the pending packet
+ myPendingPacket.clear();
+ myPendingPacketSize = -1;
+
+ // Setup default options
+ if (IsValid())
+ {
+ // To avoid the "Address already in use" error message when trying to bind to the same port
+ int Yes = 1;
+ if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; "
+ << "binding to a same port may fail if too fast" << std::endl;
+ }
+
+ // Disable the Nagle algorithm (ie. removes buffering of TCP packets)
+ if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; "
+ << "all your TCP packets will be buffered" << std::endl;
+ }
+
+ // Set blocking by default (should always be the case anyway)
+ SetBlocking(true);
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/.svn/text-base/SocketUDP.cpp.svn-base b/src/SFML/Network/.svn/text-base/SocketUDP.cpp.svn-base
new file mode 100644
index 0000000..9f045c0
--- /dev/null
+++ b/src/SFML/Network/.svn/text-base/SocketUDP.cpp.svn-base
@@ -0,0 +1,427 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/SocketUDP.hpp>
+#include <SFML/Network/IPAddress.hpp>
+#include <SFML/Network/Packet.hpp>
+#include <algorithm>
+#include <iostream>
+#include <string.h>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+SocketUDP::SocketUDP()
+{
+ Create();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Change the blocking state of the socket
+////////////////////////////////////////////////////////////
+void SocketUDP::SetBlocking(bool Blocking)
+{
+ // Make sure our socket is valid
+ if (!IsValid())
+ Create();
+
+ SocketHelper::SetBlocking(mySocket, Blocking);
+ myIsBlocking = Blocking;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Bind the socket to a specific port
+////////////////////////////////////////////////////////////
+bool SocketUDP::Bind(unsigned short Port)
+{
+ // Check if the socket is already bound to the specified port
+ if (myPort != Port)
+ {
+ // If the socket was previously bound to another port, we need to recreate it
+ if (myPort != 0)
+ {
+ Close();
+ Create();
+ }
+
+ if (Port != 0)
+ {
+ // Build an address with the specified port
+ sockaddr_in Addr;
+ Addr.sin_family = AF_INET;
+ Addr.sin_port = htons(Port);
+ Addr.sin_addr.s_addr = INADDR_ANY;
+ memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero));
+
+ // Bind the socket to the port
+ if (bind(mySocket, reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr)) == -1)
+ {
+ std::cerr << "Failed to bind the socket to port " << Port << std::endl;
+ myPort = 0;
+ return false;
+ }
+ }
+
+ // Save the new port
+ myPort = Port;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Unbind the socket to its previous port
+////////////////////////////////////////////////////////////
+bool SocketUDP::Unbind()
+{
+ // To unbind the socket, we just recreate it
+ if (myPort != 0)
+ {
+ Close();
+ Create();
+ myPort = 0;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send an array of bytes
+////////////////////////////////////////////////////////////
+Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port)
+{
+ // Make sure the socket is valid
+ if (!IsValid())
+ Create();
+
+ // Check parameters
+ if (Data && Size)
+ {
+ // Build the target address
+ sockaddr_in Target;
+ Target.sin_family = AF_INET;
+ Target.sin_port = htons(Port);
+ Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str());
+ memset(Target.sin_zero, 0, sizeof(Target.sin_zero));
+
+ // Loop until every byte has been sent
+ int Sent = 0;
+ int SizeToSend = static_cast<int>(Size);
+ for (int Length = 0; Length < SizeToSend; Length += Sent)
+ {
+ // Send a chunk of data
+ Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target));
+
+ // Check errors
+ if (Sent <= 0)
+ return SocketHelper::GetErrorStatus();
+ }
+
+ return Socket::Done;
+ }
+ else
+ {
+ // Error...
+ std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
+ return Socket::Error;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive an array of bytes.
+/// This function will block if the socket is blocking
+////////////////////////////////////////////////////////////
+Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address)
+{
+ // First clear the size received
+ SizeReceived = 0;
+
+ // Make sure the socket is bound to a port
+ if (myPort == 0)
+ {
+ std::cerr << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl;
+ return Socket::Error;
+ }
+
+ // Make sure the socket is valid
+ if (!IsValid())
+ Create();
+
+ // Check parameters
+ if (Data && MaxSize)
+ {
+ // Data that will be filled with the other computer's address
+ sockaddr_in Sender;
+ Sender.sin_family = AF_INET;
+ Sender.sin_port = htons(myPort);
+ Sender.sin_addr.s_addr = INADDR_ANY;
+ memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero));
+ SocketHelper::LengthType SenderSize = sizeof(Sender);
+
+ // Receive a chunk of bytes
+ int Received = recvfrom(mySocket, Data, static_cast<int>(MaxSize), 0, reinterpret_cast<sockaddr*>(&Sender), &SenderSize);
+
+ // Check the number of bytes received
+ if (Received > 0)
+ {
+ Address = IPAddress(inet_ntoa(Sender.sin_addr));
+ SizeReceived = static_cast<std::size_t>(Received);
+ return Socket::Done;
+ }
+ else
+ {
+ Address = IPAddress();
+ return Received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus();
+ }
+ }
+ else
+ {
+ // Error...
+ std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
+ return Socket::Error;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a packet of data
+////////////////////////////////////////////////////////////
+Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port)
+{
+ // Get the data to send from the packet
+ std::size_t DataSize = 0;
+ const char* Data = PacketToSend.OnSend(DataSize);
+
+ // Send the packet size
+ Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
+ Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port);
+
+ // Send the packet data
+ if (PacketSize > 0)
+ {
+ return Send(Data, DataSize, Address, Port);
+ }
+ else
+ {
+ return Socket::Done;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive a packet.
+/// This function will block if the socket is blocking
+////////////////////////////////////////////////////////////
+Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address)
+{
+ // This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
+ // So if a packet is split into more than one chunk, nobody knows what could happen...
+ // Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it.
+
+ // We start by getting the size of the incoming packet
+ Uint32 PacketSize = 0;
+ std::size_t Received = 0;
+ if (myPendingPacketSize < 0)
+ {
+ Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received, Address);
+ if (Status != Socket::Done)
+ return Status;
+
+ PacketSize = ntohl(PacketSize);
+ }
+ else
+ {
+ // There is a pending packet : we already know its size
+ PacketSize = myPendingPacketSize;
+ }
+
+ // Clear the user packet
+ PacketToReceive.Clear();
+
+ // Use another address instance for receiving the packet data ;
+ // chunks of data coming from a different sender will be discarded (and lost...)
+ IPAddress Sender;
+
+ // Then loop until we receive all the packet data
+ char Buffer[1024];
+ while (myPendingPacket.size() < PacketSize)
+ {
+ // Receive a chunk of data
+ std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
+ Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender);
+ if (Status != Socket::Done)
+ {
+ // We must save the size of the pending packet until we can receive its content
+ if (Status == Socket::NotReady)
+ myPendingPacketSize = PacketSize;
+ return Status;
+ }
+
+ // Append it into the packet
+ if ((Sender == Address) && (Received > 0))
+ {
+ myPendingPacket.resize(myPendingPacket.size() + Received);
+ char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
+ memcpy(Begin, Buffer, Received);
+ }
+ }
+
+ // We have received all the datas : we can copy it to the user packet, and clear our internal packet
+ PacketToReceive.Clear();
+ if (!myPendingPacket.empty())
+ PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
+ myPendingPacket.clear();
+ myPendingPacketSize = -1;
+
+ return Socket::Done;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Close the socket
+////////////////////////////////////////////////////////////
+bool SocketUDP::Close()
+{
+ if (!SocketHelper::Close(mySocket))
+ {
+ std::cerr << "Failed to close socket" << std::endl;
+ return false;
+ }
+
+ mySocket = SocketHelper::InvalidSocket();
+ myPort = 0;
+ myIsBlocking = true;
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Check if the socket is in a valid state ; this function
+/// can be called any time to check if the socket is OK
+////////////////////////////////////////////////////////////
+bool SocketUDP::IsValid() const
+{
+ return mySocket != SocketHelper::InvalidSocket();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the port the socket is currently bound to
+////////////////////////////////////////////////////////////
+unsigned short SocketUDP::GetPort() const
+{
+ return myPort;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator ==
+////////////////////////////////////////////////////////////
+bool SocketUDP::operator ==(const SocketUDP& Other) const
+{
+ return mySocket == Other.mySocket;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator !=
+////////////////////////////////////////////////////////////
+bool SocketUDP::operator !=(const SocketUDP& Other) const
+{
+ return mySocket != Other.mySocket;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Comparison operator <.
+/// Provided for compatibility with standard containers, as
+/// comparing two sockets doesn't make much sense...
+////////////////////////////////////////////////////////////
+bool SocketUDP::operator <(const SocketUDP& Other) const
+{
+ return mySocket < Other.mySocket;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the socket from a socket descriptor
+/// (for internal use only)
+////////////////////////////////////////////////////////////
+SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor)
+{
+ Create(Descriptor);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Create the socket
+////////////////////////////////////////////////////////////
+void SocketUDP::Create(SocketHelper::SocketType Descriptor)
+{
+ // Use the given socket descriptor, or get a new one
+ mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0);
+ myIsBlocking = true;
+
+ // Clear the last port used
+ myPort = 0;
+
+ // Reset the pending packet
+ myPendingPacket.clear();
+ myPendingPacketSize = -1;
+
+ // Setup default options
+ if (IsValid())
+ {
+ // To avoid the "Address already in use" error message when trying to bind to the same port
+ int Yes = 1;
+ if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to set socket option \"reuse address\" ; "
+ << "binding to a same port may fail if too fast" << std::endl;
+ }
+
+ // Enable broadcast by default
+ if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
+ }
+
+ // Set blocking by default (should always be the case anyway)
+ SetBlocking(true);
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/Ftp.cpp b/src/SFML/Network/Ftp.cpp
new file mode 100644
index 0000000..df0976e
--- /dev/null
+++ b/src/SFML/Network/Ftp.cpp
@@ -0,0 +1,709 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Ftp.hpp>
+#include <SFML/Network/IPAddress.hpp>
+#include <algorithm>
+#include <fstream>
+#include <iterator>
+#include <sstream>
+
+
+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<char>& Data);
+
+ ////////////////////////////////////////////////////////////
+ // Receive data on the data channel until it is closed
+ ////////////////////////////////////////////////////////////
+ void Receive(std::vector<char>& Data);
+
+private :
+
+ ////////////////////////////////////////////////////////////
+ // Member data
+ ////////////////////////////////////////////////////////////
+ Ftp& myFtp; ///< Reference to the owner Ftp instance
+ SocketTCP myDataSocket; ///< Socket used for data transfers
+};
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Ftp::Response::Response(Status Code, const std::string& Message) :
+myStatus (Code),
+myMessage(Message)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Convenience function to check if the response status code
+/// means a success
+////////////////////////////////////////////////////////////
+bool Ftp::Response::IsOk() const
+{
+ return myStatus < 400;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the response status code
+////////////////////////////////////////////////////////////
+Ftp::Response::Status Ftp::Response::GetStatus() const
+{
+ return myStatus;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the full message contained in the response
+////////////////////////////////////////////////////////////
+const std::string& Ftp::Response::GetMessage() const
+{
+ return myMessage;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response Resp) :
+Ftp::Response(Resp)
+{
+ if (IsOk())
+ {
+ // Extract the directory from the server response
+ std::string::size_type Begin = Resp.GetMessage().find('"', 0);
+ std::string::size_type End = Resp.GetMessage().find('"', Begin + 1);
+ myDirectory = Resp.GetMessage().substr(Begin + 1, End - Begin - 1);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the directory returned in the response
+////////////////////////////////////////////////////////////
+const std::string& Ftp::DirectoryResponse::GetDirectory() const
+{
+ return myDirectory;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Ftp::ListingResponse::ListingResponse(Ftp::Response Resp, const std::vector<char>& Data) :
+Ftp::Response(Resp)
+{
+ if (IsOk())
+ {
+ // Fill the array of strings
+ std::string Paths(Data.begin(), Data.end());
+ std::string::size_type LastPos = 0;
+ for (std::string::size_type Pos = Paths.find("\r\n"); Pos != std::string::npos; Pos = Paths.find("\r\n", LastPos))
+ {
+ myFilenames.push_back(Paths.substr(LastPos, Pos - LastPos));
+ LastPos = Pos + 2;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the number of filenames in the listing
+////////////////////////////////////////////////////////////
+std::size_t Ftp::ListingResponse::GetCount() const
+{
+ return myFilenames.size();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the Index-th filename in the directory
+////////////////////////////////////////////////////////////
+const std::string& Ftp::ListingResponse::GetFilename(std::size_t Index) const
+{
+ return myFilenames[Index];
+}
+
+
+////////////////////////////////////////////////////////////
+/// Destructor -- close the connection with the server
+////////////////////////////////////////////////////////////
+Ftp::~Ftp()
+{
+ Disconnect();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Connect to the specified FTP server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Connect(const IPAddress& Server, unsigned short Port, float Timeout)
+{
+ // Connect to the server
+ if (myCommandSocket.Connect(Port, Server, Timeout) != Socket::Done)
+ return Response(Response::ConnectionFailed);
+
+ // Get the response to the connection
+ return GetResponse();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Log in using anonymous account
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Login()
+{
+ return Login("anonymous", "user@sfml-dev.org");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Log in using a username and a password
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Login(const std::string& UserName, const std::string& Password)
+{
+ Response Resp = SendCommand("USER", UserName);
+ if (Resp.IsOk())
+ Resp = SendCommand("PASS", Password);
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Close the connection with FTP server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Disconnect()
+{
+ // Send the exit command
+ Response Resp = SendCommand("QUIT");
+ if (Resp.IsOk())
+ myCommandSocket.Close();
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a null command just to prevent from being disconnected
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::KeepAlive()
+{
+ return SendCommand("NOOP");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the current working directory
+////////////////////////////////////////////////////////////
+Ftp::DirectoryResponse Ftp::GetWorkingDirectory()
+{
+ return DirectoryResponse(SendCommand("PWD"));
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the contents of the given directory
+/// (subdirectories and files)
+////////////////////////////////////////////////////////////
+Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& Directory)
+{
+ // Open a data channel on default port (20) using ASCII transfer mode
+ std::vector<char> DirData;
+ DataChannel Data(*this);
+ Response Resp = Data.Open(Ascii);
+ if (Resp.IsOk())
+ {
+ // Tell the server to send us the listing
+ Resp = SendCommand("NLST", Directory);
+ if (Resp.IsOk())
+ {
+ // Receive the listing
+ Data.Receive(DirData);
+
+ // Get the response from the server
+ Resp = GetResponse();
+ }
+ }
+
+ return ListingResponse(Resp, DirData);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Change the current working directory
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::ChangeDirectory(const std::string& Directory)
+{
+ return SendCommand("CWD", Directory);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Go to the parent directory of the current one
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::ParentDirectory()
+{
+ return SendCommand("CDUP");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Create a new directory
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::MakeDirectory(const std::string& Name)
+{
+ return SendCommand("MKD", Name);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Remove an existing directory
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DeleteDirectory(const std::string& Name)
+{
+ return SendCommand("RMD", Name);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Rename a file
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::RenameFile(const std::string& File, const std::string& NewName)
+{
+ Response Resp = SendCommand("RNFR", File);
+ if (Resp.IsOk())
+ Resp = SendCommand("RNTO", NewName);
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Remove an existing file
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DeleteFile(const std::string& Name)
+{
+ return SendCommand("DELE", Name);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Download a file from the server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode)
+{
+ // Open a data channel using the given transfer mode
+ DataChannel Data(*this);
+ Response Resp = Data.Open(Mode);
+ if (Resp.IsOk())
+ {
+ // Tell the server to start the transfer
+ Resp = SendCommand("RETR", DistantFile);
+ if (Resp.IsOk())
+ {
+ // Receive the file data
+ std::vector<char> FileData;
+ Data.Receive(FileData);
+
+ // Get the response from the server
+ Resp = GetResponse();
+ if (Resp.IsOk())
+ {
+ // Extract the filename from the file path
+ std::string Filename = DistantFile;
+ std::string::size_type Pos = Filename.find_last_of("/\\");
+ if (Pos != std::string::npos)
+ Filename = Filename.substr(Pos + 1);
+
+ // Make sure the destination path ends with a slash
+ std::string Path = DestPath;
+ if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
+ Path += "/";
+
+ // Create the file and copy the received data into it
+ std::ofstream File((Path + Filename).c_str(), std::ios_base::binary);
+ if (!File)
+ return Response(Response::InvalidFile);
+ File.write(&FileData[0], static_cast<std::streamsize>(FileData.size()));
+ }
+ }
+ }
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Upload a file to the server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode)
+{
+ // Get the contents of the file to send
+ std::ifstream File(LocalFile.c_str(), std::ios_base::binary);
+ if (!File)
+ return Response(Response::InvalidFile);
+ File.seekg(0, std::ios::end);
+ std::size_t Length = File.tellg();
+ File.seekg(0, std::ios::beg);
+ std::vector<char> FileData(Length);
+ File.read(&FileData[0], static_cast<std::streamsize>(Length));
+
+ // Extract the filename from the file path
+ std::string Filename = LocalFile;
+ std::string::size_type Pos = Filename.find_last_of("/\\");
+ if (Pos != std::string::npos)
+ Filename = Filename.substr(Pos + 1);
+
+ // Make sure the destination path ends with a slash
+ std::string Path = DestPath;
+ if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
+ Path += "/";
+
+ // Open a data channel using the given transfer mode
+ DataChannel Data(*this);
+ Response Resp = Data.Open(Mode);
+ if (Resp.IsOk())
+ {
+ // Tell the server to start the transfer
+ Resp = SendCommand("STOR", Path + Filename);
+ if (Resp.IsOk())
+ {
+ // Send the file data
+ Data.Send(FileData);
+
+ // Get the response from the server
+ Resp = GetResponse();
+ }
+ }
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a command to the FTP server
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::SendCommand(const std::string& Command, const std::string& Parameter)
+{
+ // Build the command string
+ std::string CommandStr;
+ if (Parameter != "")
+ CommandStr = Command + " " + Parameter + "\r\n";
+ else
+ CommandStr = Command + "\r\n";
+
+ // Send it to the server
+ if (myCommandSocket.Send(CommandStr.c_str(), CommandStr.length()) != sf::Socket::Done)
+ return Response(Response::ConnectionClosed);
+
+ // Get the response
+ return GetResponse();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive a response from the server
+/// (usually after a command has been sent)
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::GetResponse()
+{
+ // We'll use a variable to keep track of the last valid code.
+ // It is useful in case of multi-lines responses, because the end of such a response
+ // will start by the same code
+ unsigned int LastCode = 0;
+ bool IsInsideMultiline = false;
+ std::string Message;
+
+ for (;;)
+ {
+ // Receive the response from the server
+ char Buffer[1024];
+ std::size_t Length;
+ if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done)
+ return Response(Response::ConnectionClosed);
+
+ // There can be several lines inside the received buffer, extract them all
+ std::istringstream In(std::string(Buffer, Length), std::ios_base::binary);
+ while (In)
+ {
+ // Try to extract the code
+ unsigned int Code;
+ if (In >> Code)
+ {
+ // Extract the separator
+ char Sep;
+ In.get(Sep);
+
+ // The '-' character means a multiline response
+ if ((Sep == '-') && !IsInsideMultiline)
+ {
+ // Set the multiline flag
+ IsInsideMultiline = true;
+
+ // Keep track of the code
+ if (LastCode == 0)
+ LastCode = Code;
+
+ // Extract the line
+ std::getline(In, Message);
+
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Message.erase(Message.length() - 1);
+ Message = Sep + Message + "\n";
+ }
+ else
+ {
+ // We must make sure that the code is the same, otherwise it means
+ // we haven't reached the end of the multiline response
+ if ((Sep != '-') && ((Code == LastCode) || (LastCode == 0)))
+ {
+ // Clear the multiline flag
+ IsInsideMultiline = false;
+
+ // Extract the line
+ std::string Line;
+ std::getline(In, Line);
+
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Line.erase(Line.length() - 1);
+
+ // Append it to the message
+ if (Code == LastCode)
+ {
+ std::ostringstream Out;
+ Out << Code << Sep << Line;
+ Message += Out.str();
+ }
+ else
+ {
+ Message = Sep + Line;
+ }
+
+ // Return the response code and message
+ return Response(static_cast<Response::Status>(Code), Message);
+ }
+ else
+ {
+ // The line we just read was actually not a response,
+ // only a new part of the current multiline response
+
+ // Extract the line
+ std::string Line;
+ std::getline(In, Line);
+
+ if (!Line.empty())
+ {
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Line.erase(Line.length() - 1);
+
+ // Append it to the current message
+ std::ostringstream Out;
+ Out << Code << Sep << Line << "\n";
+ Message += Out.str();
+ }
+ }
+ }
+ }
+ else if (LastCode != 0)
+ {
+ // It seems we are in the middle of a multiline response
+
+ // Clear the error bits of the stream
+ In.clear();
+
+ // Extract the line
+ std::string Line;
+ std::getline(In, Line);
+
+ if (!Line.empty())
+ {
+ // Remove the ending '\r' (all lines are terminated by "\r\n")
+ Line.erase(Line.length() - 1);
+
+ // Append it to the current message
+ Message += Line + "\n";
+ }
+ }
+ else
+ {
+ // Error : cannot extract the code, and we are not in a multiline response
+ return Response(Response::InvalidResponse);
+ }
+ }
+ }
+
+ // We never reach there
+}
+
+
+////////////////////////////////////////////////////////////
+/// Constructor
+////////////////////////////////////////////////////////////
+Ftp::DataChannel::DataChannel(Ftp& Owner) :
+myFtp(Owner)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Destructor
+////////////////////////////////////////////////////////////
+Ftp::DataChannel::~DataChannel()
+{
+ // Close the data socket
+ myDataSocket.Close();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Open the data channel using the specified mode and port
+////////////////////////////////////////////////////////////
+Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode Mode)
+{
+ // Open a data connection in active mode (we connect to the server)
+ Ftp::Response Resp = myFtp.SendCommand("PASV");
+ if (Resp.IsOk())
+ {
+ // Extract the connection address and port from the response
+ std::string::size_type begin = Resp.GetMessage().find_first_of("0123456789");
+ if (begin != std::string::npos)
+ {
+ sf::Uint8 Data[6] = {0, 0, 0, 0, 0, 0};
+ std::string Str = Resp.GetMessage().substr(begin);
+ std::size_t Index = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ // Extract the current number
+ while (isdigit(Str[Index]))
+ {
+ Data[i] = Data[i] * 10 + (Str[Index] - '0');
+ Index++;
+ }
+
+ // Skip separator
+ Index++;
+ }
+
+ // Reconstruct connection port and address
+ unsigned short Port = Data[4] * 256 + Data[5];
+ sf::IPAddress Address(static_cast<sf::Uint8>(Data[0]),
+ static_cast<sf::Uint8>(Data[1]),
+ static_cast<sf::Uint8>(Data[2]),
+ static_cast<sf::Uint8>(Data[3]));
+
+ // Connect the data channel to the server
+ if (myDataSocket.Connect(Port, Address) == Socket::Done)
+ {
+ // Translate the transfer mode to the corresponding FTP parameter
+ std::string ModeStr;
+ switch (Mode)
+ {
+ case Ftp::Binary : ModeStr = "I"; break;
+ case Ftp::Ascii : ModeStr = "A"; break;
+ case Ftp::Ebcdic : ModeStr = "E"; break;
+ }
+
+ // Set the transfer mode
+ Resp = myFtp.SendCommand("TYPE", ModeStr);
+ }
+ else
+ {
+ // Failed to connect to the server
+ Resp = Ftp::Response(Ftp::Response::ConnectionFailed);
+ }
+ }
+ }
+
+ return Resp;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Receive data on the data channel until it is closed
+////////////////////////////////////////////////////////////
+void Ftp::DataChannel::Receive(std::vector<char>& Data)
+{
+ // Receive data
+ Data.clear();
+ char Buffer[1024];
+ std::size_t Received;
+ while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done)
+ {
+ std::copy(Buffer, Buffer + Received, std::back_inserter(Data));
+ }
+
+ // Close the data socket
+ myDataSocket.Close();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send data on the data channel
+////////////////////////////////////////////////////////////
+void Ftp::DataChannel::Send(const std::vector<char>& Data)
+{
+ // Send data
+ myDataSocket.Send(&Data[0], Data.size());
+
+ // Close the data socket
+ myDataSocket.Close();
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/Http.cpp b/src/SFML/Network/Http.cpp
new file mode 100644
index 0000000..1becb80
--- /dev/null
+++ b/src/SFML/Network/Http.cpp
@@ -0,0 +1,425 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/Http.hpp>
+#include <ctype.h>
+#include <sstream>
+
+
+namespace
+{
+ ////////////////////////////////////////////////////////////
+ // Convenience function to convert a string to lower case
+ ////////////////////////////////////////////////////////////
+ std::string ToLower(const std::string& Str)
+ {
+ std::string Ret = Str;
+ for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
+ *i = static_cast<char>(tolower(*i));
+
+ return Ret;
+ }
+}
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body) :
+myMethod (RequestMethod),
+myURI (URI),
+myMajorVersion(1),
+myMinorVersion(0),
+myBody (Body)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the value of a field; the field is added if it doesn't exist
+////////////////////////////////////////////////////////////
+void Http::Request::SetField(const std::string& Field, const std::string& Value)
+{
+ myFields[ToLower(Field)] = Value;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the request method.
+/// This parameter is Get by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetMethod(Http::Request::Method RequestMethod)
+{
+ myMethod = RequestMethod;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the target URI of the request.
+/// This parameter is "/" by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetURI(const std::string& URI)
+{
+ myURI = URI;
+
+ // Make sure it starts with a '/'
+ if (myURI.empty() || (myURI[0] != '/'))
+ myURI.insert(0, "/");
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the HTTP version of the request.
+/// This parameter is 1.0 by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor)
+{
+ myMajorVersion = Major;
+ myMinorVersion = Minor;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the body of the request. This parameter is optional and
+/// makes sense only for POST requests.
+/// This parameter is empty by default
+////////////////////////////////////////////////////////////
+void Http::Request::SetBody(const std::string& Body)
+{
+ myBody = Body;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the string representation of a request header
+////////////////////////////////////////////////////////////
+std::string Http::Request::ToString() const
+{
+ std::ostringstream Out;
+
+ // Convert the method to its string representation
+ std::string RequestMethod;
+ switch (myMethod)
+ {
+ default :
+ case Get : RequestMethod = "GET"; break;
+ case Post : RequestMethod = "POST"; break;
+ case Head : RequestMethod = "HEAD"; break;
+ }
+
+ // Write the first line containing the request type
+ Out << RequestMethod << " " << myURI << " ";
+ Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n";
+
+ // Write fields
+ for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i)
+ {
+ Out << i->first << ": " << i->second << "\r\n";
+ }
+
+ // Use an extra \r\n to separate the header from the body
+ Out << "\r\n";
+
+ // Add the body
+ Out << myBody;
+
+ return Out.str();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Check if the given field has been defined
+////////////////////////////////////////////////////////////
+bool Http::Request::HasField(const std::string& Field) const
+{
+ return myFields.find(Field) != myFields.end();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Http::Response::Response() :
+myStatus (ConnectionFailed),
+myMajorVersion(0),
+myMinorVersion(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the value of a field
+////////////////////////////////////////////////////////////
+const std::string& Http::Response::GetField(const std::string& Field) const
+{
+ FieldTable::const_iterator It = myFields.find(Field);
+ if (It != myFields.end())
+ {
+ return It->second;
+ }
+ else
+ {
+ static const std::string Empty = "";
+ return Empty;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the header's status code
+////////////////////////////////////////////////////////////
+Http::Response::Status Http::Response::GetStatus() const
+{
+ return myStatus;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the major HTTP version number of the response
+////////////////////////////////////////////////////////////
+unsigned int Http::Response::GetMajorHttpVersion() const
+{
+ return myMajorVersion;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the major HTTP version number of the response
+////////////////////////////////////////////////////////////
+unsigned int Http::Response::GetMinorHttpVersion() const
+{
+ return myMinorVersion;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the body of the response. The body can contain :
+/// - the requested page (for GET requests)
+/// - a response from the server (for POST requests)
+/// - nothing (for HEAD requests)
+/// - an error message (in case of an error)
+////////////////////////////////////////////////////////////
+const std::string& Http::Response::GetBody() const
+{
+ return myBody;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the header from a response string
+////////////////////////////////////////////////////////////
+void Http::Response::FromString(const std::string& Data)
+{
+ std::istringstream In(Data);
+
+ // Extract the HTTP version from the first line
+ std::string Version;
+ if (In >> Version)
+ {
+ if ((Version.size() >= 8) && (Version[6] == '.') &&
+ (ToLower(Version.substr(0, 5)) == "http/") &&
+ isdigit(Version[5]) && isdigit(Version[7]))
+ {
+ myMajorVersion = Version[5] - '0';
+ myMinorVersion = Version[7] - '0';
+ }
+ else
+ {
+ // Invalid HTTP version
+ myStatus = InvalidResponse;
+ return;
+ }
+ }
+
+ // Extract the status code from the first line
+ int StatusCode;
+ if (In >> StatusCode)
+ {
+ myStatus = static_cast<Status>(StatusCode);
+ }
+ else
+ {
+ // Invalid status code
+ myStatus = InvalidResponse;
+ return;
+ }
+
+ // Ignore the end of the first line
+ In.ignore(10000, '\n');
+
+ // Parse the other lines, which contain fields, one by one
+ std::string Line;
+ while (std::getline(In, Line) && (Line.size() > 2))
+ {
+ std::string::size_type Pos = Line.find(": ");
+ if (Pos != std::string::npos)
+ {
+ // Extract the field name and its value
+ std::string Field = Line.substr(0, Pos);
+ std::string Value = Line.substr(Pos + 2);
+
+ // Remove any trailing \r
+ if (!Value.empty() && (*Value.rbegin() == '\r'))
+ Value.erase(Value.size() - 1);
+
+ // Add the field
+ myFields[ToLower(Field)] = Value;
+ }
+ }
+
+ // Finally extract the body
+ myBody.clear();
+ while (std::getline(In, Line))
+ myBody += Line + "\n";
+}
+
+
+////////////////////////////////////////////////////////////
+/// Default constructor
+////////////////////////////////////////////////////////////
+Http::Http() :
+myHost(),
+myPort(0)
+{
+
+}
+
+
+////////////////////////////////////////////////////////////
+/// Construct the Http instance with the target host
+////////////////////////////////////////////////////////////
+Http::Http(const std::string& Host, unsigned short Port)
+{
+ SetHost(Host, Port);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set the target host
+////////////////////////////////////////////////////////////
+void Http::SetHost(const std::string& Host, unsigned short Port)
+{
+ // Detect the protocol used
+ std::string Protocol = ToLower(Host.substr(0, 8));
+ if (Protocol.substr(0, 7) == "http://")
+ {
+ // HTTP protocol
+ myHostName = Host.substr(7);
+ myPort = (Port != 0 ? Port : 80);
+ }
+ else if (Protocol == "https://")
+ {
+ // HTTPS protocol
+ myHostName = Host.substr(8);
+ myPort = (Port != 0 ? Port : 443);
+ }
+ else
+ {
+ // Undefined protocol - use HTTP
+ myHostName = Host;
+ myPort = (Port != 0 ? Port : 80);
+ }
+
+ // Remove any trailing '/' from the host name
+ if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
+ myHostName.erase(myHostName.size() - 1);
+
+ myHost = sf::IPAddress(myHostName);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Send a HTTP request and return the server's response.
+/// You must be connected to a host before sending requests.
+/// Any missing mandatory header field will be added with an appropriate value.
+/// Warning : this function waits for the server's response and may
+/// not return instantly; use a thread if you don't want to block your
+/// application.
+////////////////////////////////////////////////////////////
+Http::Response Http::SendRequest(const Http::Request& Req)
+{
+ // First make sure the request is valid -- add missing mandatory fields
+ Request ToSend(Req);
+ if (!ToSend.HasField("From"))
+ {
+ ToSend.SetField("From", "user@sfml-dev.org");
+ }
+ if (!ToSend.HasField("User-Agent"))
+ {
+ ToSend.SetField("User-Agent", "libsfml-network/1.x");
+ }
+ if (!ToSend.HasField("Host"))
+ {
+ ToSend.SetField("Host", myHostName);
+ }
+ if (!ToSend.HasField("Content-Length"))
+ {
+ std::ostringstream Out;
+ Out << ToSend.myBody.size();
+ ToSend.SetField("Content-Length", Out.str());
+ }
+
+ // Prepare the response
+ Response Received;
+
+ // Connect the socket to the host
+ if (myConnection.Connect(myPort, myHost) == Socket::Done)
+ {
+ // Convert the request to string and send it through the connected socket
+ std::string RequestStr = ToSend.ToString();
+
+ if (!RequestStr.empty())
+ {
+ // Send it through the socket
+ if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
+ {
+ // Wait for the server's response
+ std::string ReceivedStr;
+ std::size_t Size = 0;
+ char Buffer[1024];
+ while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
+ {
+ ReceivedStr.append(Buffer, Buffer + Size);
+ }
+
+ // Build the Response object from the received data
+ Received.FromString(ReceivedStr);
+ }
+ }
+
+ // Close the connection
+ myConnection.Close();
+ }
+
+ return Received;
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/IPAddress.cpp b/src/SFML/Network/IPAddress.cpp
index 132d20b..cd34613 100755..100644
--- a/src/SFML/Network/IPAddress.cpp
+++ b/src/SFML/Network/IPAddress.cpp
@@ -26,7 +26,9 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/IPAddress.hpp>
+#include <SFML/Network/Http.hpp>
#include <SFML/Network/SocketHelper.hpp>
+#include <string.h>
namespace sf
@@ -110,6 +112,15 @@ IPAddress::IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3)
////////////////////////////////////////////////////////////
+/// Construct the address from a 32-bits integer
+////////////////////////////////////////////////////////////
+IPAddress::IPAddress(Uint32 Address)
+{
+ myAddress = htonl(Address);
+}
+
+
+////////////////////////////////////////////////////////////
/// Tell if the address is a valid one
////////////////////////////////////////////////////////////
bool IPAddress::IsValid() const
@@ -131,6 +142,15 @@ std::string IPAddress::ToString() const
////////////////////////////////////////////////////////////
+/// Get an integer representation of the address
+////////////////////////////////////////////////////////////
+Uint32 IPAddress::ToInteger() const
+{
+ return ntohl(myAddress);
+}
+
+
+////////////////////////////////////////////////////////////
/// Get the computer's local IP address (from the LAN point of view)
////////////////////////////////////////////////////////////
IPAddress IPAddress::GetLocalAddress()
@@ -191,70 +211,15 @@ IPAddress IPAddress::GetPublicAddress()
IPAddress PublicAddress;
- // Create the socket
- SocketHelper::SocketType Socket = socket(PF_INET, SOCK_STREAM, 0);
- if (Socket == SocketHelper::InvalidSocket())
- return PublicAddress;
-
- // Build the server address (use port 80 for HTTP)
- IPAddress Server("www.whatismyip.org");
- sockaddr_in SockAddr;
- memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
- SockAddr.sin_addr.s_addr = inet_addr(Server.ToString().c_str());
- SockAddr.sin_family = AF_INET;
- SockAddr.sin_port = htons(80);
-
- // Connect the socket
- if (connect(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
- {
- SocketHelper::Close(Socket);
- return PublicAddress;
- }
-
- // Send a request for getting the index page
- const char Request[] = "GET / HTTP/1.0\r\n"
- "From: camembert@fromage.com\r\n"
- "User-Agent: SFML/1.0\r\n"
- "\r\n";
- if (send(Socket, Request, sizeof(Request), 0) <= 0)
- {
- SocketHelper::Close(Socket);
- return PublicAddress;
- }
-
- // Get the response (the source code of the web page)
- char Response[1024] = {0};
- int Received = 0;
- do
- {
- // Get the next chunk of response from the server
- char Buffer[1024];
- Received = recv(Socket, Buffer, sizeof(Buffer), 0);
-
- if (Received > 0)
- {
- // We received something : concatenate it to the response
- Buffer[Received] = '\0';
- strcat(Response, Buffer);
- }
- else if (Received < 0)
- {
- // We received an error : return an invalid address
- return PublicAddress;
- }
- } while (Received > 0);
-
- // Close the socket
- SocketHelper::Close(Socket);
+ // Connect to the web server and get its index page
+ Http Server("www.whatismyip.org");
+ Http::Request Request(Http::Request::Get, "/");
+ Http::Response Page = Server.SendRequest(Request);
- // Extract the address from the source code of the web page
- // (extract from first \r\n\r\n to the end)
- std::string Page = Response;
- std::string::size_type Start = Page.find("\r\n\r\n");
- if (Start != std::string::npos)
- {
- PublicAddress = Page.substr(Start + 4);
- }
+ // If the request was successful, we can extract
+ // the address from the body of the web page
+ if (Page.GetStatus() == Http::Response::Ok)
+ PublicAddress = Page.GetBody();
return PublicAddress;
}
diff --git a/src/SFML/Network/Makefile b/src/SFML/Network/Makefile
index 3e2b3cf..d30da62 100755..100644
--- a/src/SFML/Network/Makefile
+++ b/src/SFML/Network/Makefile
@@ -1,14 +1,14 @@
SRC = $(wildcard *.cpp ./Unix/*.cpp)
OBJ = $(SRC:.cpp=.o)
-ifeq ($(static), yes)
+ifeq ($(STATIC), yes)
LIB = libsfml-network-s.a
LIBNAME = $(LIBPATH)/$(LIB)
INSTALL =
else
LIB = libsfml-network.so
LIBNAME = $(LIBPATH)/$(LIB).$(VERSION)
- INSTALL = && $(LN) $(LNFLAGS) /usr/lib/$(LIB).$(VERSION) /usr/lib/$(LIB)
+ INSTALL = && $(LN) $(LNFLAGS) $(DESTLIBDIR)/$(LIB).$(VERSION) $(DESTLIBDIR)/$(LIB)
endif
all: $(LIB)
@@ -31,4 +31,4 @@ mrproper: clean
@rm -rf $(LIBNAME)
install:
- @($(CP) $(LIBNAME) /usr/lib $(INSTALL))
+ @($(CP) $(LIBNAME) $(DESTLIBDIR) $(INSTALL))
diff --git a/src/SFML/Network/Packet.cpp b/src/SFML/Network/Packet.cpp
index 935b69f..df693d5 100755..100644
--- a/src/SFML/Network/Packet.cpp
+++ b/src/SFML/Network/Packet.cpp
@@ -27,6 +27,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Network/Packet.hpp>
#include <SFML/Network/SocketHelper.hpp>
+#include <string.h>
namespace sf
@@ -56,9 +57,12 @@ Packet::~Packet()
////////////////////////////////////////////////////////////
void Packet::Append(const void* Data, std::size_t SizeInBytes)
{
- std::size_t Start = myData.size();
- myData.resize(Start + SizeInBytes);
- memcpy(&myData[Start], Data, SizeInBytes);
+ if (Data && (SizeInBytes > 0))
+ {
+ std::size_t Start = myData.size();
+ myData.resize(Start + SizeInBytes);
+ memcpy(&myData[Start], Data, SizeInBytes);
+ }
}
@@ -87,9 +91,18 @@ const char* Packet::GetData() const
////////////////////////////////////////////////////////////
/// Get the size of the data contained in the packet
////////////////////////////////////////////////////////////
-Uint32 Packet::GetDataSize() const
+std::size_t Packet::GetDataSize() const
{
- return static_cast<Uint32>(myData.size());
+ return myData.size();
+}
+
+
+////////////////////////////////////////////////////////////
+/// Tell if the reading position has reached the end of the packet
+////////////////////////////////////////////////////////////
+bool Packet::EndOfPacket() const
+{
+ return myReadPos >= myData.size();
}
@@ -105,6 +118,14 @@ Packet::operator bool() const
////////////////////////////////////////////////////////////
/// Operator >> overloads to extract data from the packet
////////////////////////////////////////////////////////////
+Packet& Packet::operator >>(bool& Data)
+{
+ Uint8 Value;
+ if (*this >> Value)
+ Data = (Value != 0);
+
+ return *this;
+}
Packet& Packet::operator >>(Int8& Data)
{
if (CheckSize(sizeof(Data)))
@@ -191,7 +212,7 @@ Packet& Packet::operator >>(char* Data)
Uint32 Length;
*this >> Length;
- if (CheckSize(Length))
+ if ((Length > 0) && CheckSize(Length))
{
// Then extract characters
memcpy(Data, GetData() + myReadPos, Length);
@@ -209,7 +230,8 @@ Packet& Packet::operator >>(std::string& Data)
Uint32 Length;
*this >> Length;
- if (CheckSize(Length))
+ Data.clear();
+ if ((Length > 0) && CheckSize(Length))
{
// Then extract characters
Data.assign(GetData() + myReadPos, Length);
@@ -226,7 +248,7 @@ Packet& Packet::operator >>(wchar_t* Data)
Uint32 Length;
*this >> Length;
- if (CheckSize(Length * sizeof(Int32)))
+ if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
{
// Then extract characters
for (Uint32 i = 0; i < Length; ++i)
@@ -246,10 +268,10 @@ Packet& Packet::operator >>(std::wstring& Data)
Uint32 Length;
*this >> Length;
- if (CheckSize(Length * sizeof(Int32)))
+ Data.clear();
+ if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
{
// Then extract characters
- Data.clear();
for (Uint32 i = 0; i < Length; ++i)
{
Uint32 c;
@@ -265,6 +287,11 @@ Packet& Packet::operator >>(std::wstring& Data)
////////////////////////////////////////////////////////////
/// Operator << overloads to put data into the packet
////////////////////////////////////////////////////////////
+Packet& Packet::operator <<(bool Data)
+{
+ *this << static_cast<Uint8>(Data);
+ return *this;
+}
Packet& Packet::operator <<(Int8 Data)
{
Append(&Data, sizeof(Data));
@@ -329,7 +356,10 @@ Packet& Packet::operator <<(const std::string& Data)
*this << Length;
// Then insert characters
- Append(Data.c_str(), Length * sizeof(std::string::value_type));
+ if (Length > 0)
+ {
+ Append(Data.c_str(), Length * sizeof(std::string::value_type));
+ }
return *this;
}
@@ -354,8 +384,11 @@ Packet& Packet::operator <<(const std::wstring& Data)
*this << Length;
// Then insert characters
- for (std::wstring::const_iterator c = Data.begin(); c != Data.end(); ++c)
- *this << static_cast<Int32>(*c);
+ if (Length > 0)
+ {
+ for (std::wstring::const_iterator c = Data.begin(); c != Data.end(); ++c)
+ *this << static_cast<Int32>(*c);
+ }
return *this;
}
@@ -366,33 +399,28 @@ Packet& Packet::operator <<(const std::wstring& Data)
////////////////////////////////////////////////////////////
bool Packet::CheckSize(std::size_t Size)
{
- if (myIsValid && (myReadPos + Size <= myData.size()))
- {
- return true;
- }
- else
- {
- myIsValid = false;
- return false;
- }
+ myIsValid = myIsValid && (myReadPos + Size <= myData.size());
+
+ return myIsValid;
}
////////////////////////////////////////////////////////////
-/// Called before the packet is send to the network
+/// Called before the packet is sent to the network
////////////////////////////////////////////////////////////
-void Packet::OnSend()
+const char* Packet::OnSend(std::size_t& DataSize)
{
- // Nothing by default
+ DataSize = GetDataSize();
+ return GetData();
}
////////////////////////////////////////////////////////////
/// Called after the packet has been received from the network
////////////////////////////////////////////////////////////
-void Packet::OnReceive()
+void Packet::OnReceive(const char* Data, std::size_t DataSize)
{
- // Nothing by default
+ Append(Data, DataSize);
}
} // namespace sf
diff --git a/src/SFML/Network/SelectorBase.cpp b/src/SFML/Network/SelectorBase.cpp
index 7d4a2fe..6631753 100755..100644
--- a/src/SFML/Network/SelectorBase.cpp
+++ b/src/SFML/Network/SelectorBase.cpp
@@ -105,7 +105,7 @@ unsigned int SelectorBase::Wait(float Timeout)
/// 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
+SocketHelper::SocketType SelectorBase::GetSocketReady(unsigned int Index)
{
// The standard FD_xxx interface doesn't define a direct access,
// so we must go through the whole set to find the socket we're looking for
diff --git a/src/SFML/Network/SocketTCP.cpp b/src/SFML/Network/SocketTCP.cpp
index e209530..1f5e553 100755..100644
--- a/src/SFML/Network/SocketTCP.cpp
+++ b/src/SFML/Network/SocketTCP.cpp
@@ -28,8 +28,15 @@
#include <SFML/Network/SocketTCP.hpp>
#include <SFML/Network/IPAddress.hpp>
#include <SFML/Network/Packet.hpp>
+#include <SFML/Network/SocketHelper.hpp>
#include <algorithm>
#include <iostream>
+#include <string.h>
+
+
+#ifdef _MSC_VER
+ #pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
+#endif
namespace sf
@@ -37,10 +44,9 @@ namespace sf
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
-SocketTCP::SocketTCP() :
-mySocket(SocketHelper::InvalidSocket())
+SocketTCP::SocketTCP()
{
-
+ Create(SocketHelper::InvalidSocket());
}
@@ -54,13 +60,14 @@ void SocketTCP::SetBlocking(bool Blocking)
Create();
SocketHelper::SetBlocking(mySocket, Blocking);
+ myIsBlocking = Blocking;
}
////////////////////////////////////////////////////////////
/// Connect to another computer on a specified port
////////////////////////////////////////////////////////////
-bool SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress)
+Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout)
{
// Make sure our socket is valid
if (!IsValid())
@@ -73,15 +80,75 @@ bool SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress)
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(Port);
- // Connect
- if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
+ if (Timeout <= 0)
{
- // Error...
- std::cerr << "Failed to connect socket to host " << HostAddress << std::endl;
- return false;
+ // ----- We're not using a timeout : just try to connect -----
+
+ if (connect(mySocket, reinterpret_cast<sockaddr*>(&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 -----
- return true;
+ // Save the previous blocking state
+ bool IsBlocking = myIsBlocking;
+
+ // Switch to non-blocking to enable our connection timeout
+ if (IsBlocking)
+ SetBlocking(false);
+
+ // Try to connect to host
+ if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0)
+ {
+ // We got instantly connected! (it may no happen a lot...)
+ return Socket::Done;
+ }
+
+ // Get the error status
+ Socket::Status Status = SocketHelper::GetErrorStatus();
+
+ // If we were in non-blocking mode, return immediatly
+ if (!IsBlocking)
+ return Status;
+
+ // Otherwise, wait until something happens to our socket (success, timeout or error)
+ if (Status == Socket::NotReady)
+ {
+ // Setup the selector
+ fd_set Selector;
+ FD_ZERO(&Selector);
+ FD_SET(mySocket, &Selector);
+
+ // Setup the timeout
+ timeval Time;
+ Time.tv_sec = static_cast<long>(Timeout);
+ Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
+
+ // Wait for something to write on our socket (would mean the connection has been accepted)
+ if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0)
+ {
+ // Connection succeeded
+ Status = Socket::Done;
+ }
+ else
+ {
+ // Failed to connect before timeout is over
+ Status = SocketHelper::GetErrorStatus();
+ }
+ }
+
+ // Switch back to blocking mode
+ SetBlocking(true);
+
+ return Status;
+ }
}
@@ -235,17 +302,18 @@ Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t&
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Send(Packet& PacketToSend)
{
- // Let the packet do custom stuff before sending it
- PacketToSend.OnSend();
+ // Get the data to send from the packet
+ std::size_t DataSize = 0;
+ const char* Data = PacketToSend.OnSend(DataSize);
- // First send the packet size
- Uint32 PacketSize = htonl(PacketToSend.GetDataSize());
+ // Send the packet size
+ Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize));
// Send the packet data
if (PacketSize > 0)
{
- return Send(PacketToSend.GetData(), PacketToSend.GetDataSize());
+ return Send(Data, DataSize);
}
else
{
@@ -277,15 +345,12 @@ Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
PacketSize = myPendingPacketSize;
}
- // Clear the user packet
- PacketToReceive.Clear();
-
// Then loop until we receive all the packet data
char Buffer[1024];
- while (myPendingPacket.GetDataSize() < PacketSize)
+ while (myPendingPacket.size() < PacketSize)
{
// Receive a chunk of data
- Uint32 SizeToGet = std::min(PacketSize - myPendingPacket.GetDataSize(), static_cast<Uint32>(sizeof(Buffer)));
+ std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
Socket::Status Status = Receive(Buffer, SizeToGet, Received);
if (Status != Socket::Done)
{
@@ -296,17 +361,21 @@ Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
}
// Append it into the packet
- myPendingPacket.Append(Buffer, Received);
+ if (Received > 0)
+ {
+ myPendingPacket.resize(myPendingPacket.size() + Received);
+ char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
+ memcpy(Begin, Buffer, Received);
+ }
}
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
- PacketToReceive = myPendingPacket;
- myPendingPacket.Clear();
+ PacketToReceive.Clear();
+ if (!myPendingPacket.empty())
+ PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
+ myPendingPacket.clear();
myPendingPacketSize = -1;
- // Let the packet do custom stuff after data reception
- PacketToReceive.OnReceive();
-
return Socket::Done;
}
@@ -323,6 +392,8 @@ bool SocketTCP::Close()
}
mySocket = SocketHelper::InvalidSocket();
+ myIsBlocking = true;
+
return true;
}
@@ -370,41 +441,46 @@ bool SocketTCP::operator <(const SocketTCP& Other) const
/// Construct the socket from a socket descriptor
/// (for internal use only)
////////////////////////////////////////////////////////////
-SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor) :
-mySocket (Descriptor),
-myPendingPacketSize(-1)
+SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor)
{
- // Set blocking by default (should always be the case anyway)
- if (IsValid())
- SetBlocking(true);
+ Create(Descriptor);
}
////////////////////////////////////////////////////////////
/// Create the socket
////////////////////////////////////////////////////////////
-void SocketTCP::Create()
+void SocketTCP::Create(SocketHelper::SocketType Descriptor)
{
- // Get a new socket descriptor
- mySocket = socket(PF_INET, SOCK_STREAM, 0);
+ // Use the given socket descriptor, or get a new one
+ mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0);
+ myIsBlocking = true;
+
+ // Reset the pending packet
+ myPendingPacket.clear();
+ myPendingPacketSize = -1;
+ // Setup default options
if (IsValid())
{
// To avoid the "Address already in use" error message when trying to bind to the same port
- char Yes = 1;
- if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1)
+ int Yes = 1;
+ if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
{
- std::cerr << "Failed to set socket option \"reuse address\" ; "
+ std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; "
<< "binding to a same port may fail if too fast" << std::endl;
}
+ // Disable the Nagle algorithm (ie. removes buffering of TCP packets)
+ if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; "
+ << "all your TCP packets will be buffered" << std::endl;
+ }
+
// Set blocking by default (should always be the case anyway)
SetBlocking(true);
}
-
- // Reset the pending packet
- myPendingPacket.Clear();
- myPendingPacketSize = -1;
}
} // namespace sf
diff --git a/src/SFML/Network/SocketUDP.cpp b/src/SFML/Network/SocketUDP.cpp
index 38fbe0c..9f045c0 100755..100644
--- a/src/SFML/Network/SocketUDP.cpp
+++ b/src/SFML/Network/SocketUDP.cpp
@@ -30,6 +30,7 @@
#include <SFML/Network/Packet.hpp>
#include <algorithm>
#include <iostream>
+#include <string.h>
namespace sf
@@ -37,9 +38,7 @@ namespace sf
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
-SocketUDP::SocketUDP() :
-mySocket(SocketHelper::InvalidSocket()),
-myPort (0)
+SocketUDP::SocketUDP()
{
Create();
}
@@ -55,6 +54,7 @@ void SocketUDP::SetBlocking(bool Blocking)
Create();
SocketHelper::SetBlocking(mySocket, Blocking);
+ myIsBlocking = Blocking;
}
@@ -220,17 +220,18 @@ Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t&
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port)
{
- // Let the packet do custom stuff before sending it
- PacketToSend.OnSend();
+ // Get the data to send from the packet
+ std::size_t DataSize = 0;
+ const char* Data = PacketToSend.OnSend(DataSize);
- // First send the packet size
- Uint32 PacketSize = htonl(PacketToSend.GetDataSize());
+ // Send the packet size
+ Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port);
// Send the packet data
if (PacketSize > 0)
{
- return Send(PacketToSend.GetData(), PacketToSend.GetDataSize(), Address, Port);
+ return Send(Data, DataSize, Address, Port);
}
else
{
@@ -275,10 +276,10 @@ Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address)
// Then loop until we receive all the packet data
char Buffer[1024];
- while (myPendingPacket.GetDataSize() < PacketSize)
+ while (myPendingPacket.size() < PacketSize)
{
// Receive a chunk of data
- Uint32 SizeToGet = std::min(PacketSize - myPendingPacket.GetDataSize(), static_cast<Uint32>(sizeof(Buffer)));
+ std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender);
if (Status != Socket::Done)
{
@@ -289,18 +290,21 @@ Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address)
}
// Append it into the packet
- if (Sender == Address)
- myPendingPacket.Append(Buffer, Received);
+ if ((Sender == Address) && (Received > 0))
+ {
+ myPendingPacket.resize(myPendingPacket.size() + Received);
+ char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
+ memcpy(Begin, Buffer, Received);
+ }
}
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
- PacketToReceive = myPendingPacket;
- myPendingPacket.Clear();
+ PacketToReceive.Clear();
+ if (!myPendingPacket.empty())
+ PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
+ myPendingPacket.clear();
myPendingPacketSize = -1;
- // Let the packet do custom stuff after data reception
- PacketToReceive.OnReceive();
-
return Socket::Done;
}
@@ -316,8 +320,9 @@ bool SocketUDP::Close()
return false;
}
- mySocket = SocketHelper::InvalidSocket();
- myPort = 0;
+ mySocket = SocketHelper::InvalidSocket();
+ myPort = 0;
+ myIsBlocking = true;
return true;
}
@@ -375,46 +380,48 @@ bool SocketUDP::operator <(const SocketUDP& Other) const
/// Construct the socket from a socket descriptor
/// (for internal use only)
////////////////////////////////////////////////////////////
-SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor) :
-mySocket(Descriptor),
-myPort (0)
+SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor)
{
- // Set blocking by default (should always be the case anyway)
- SetBlocking(true);
+ Create(Descriptor);
}
////////////////////////////////////////////////////////////
/// Create the socket
////////////////////////////////////////////////////////////
-void SocketUDP::Create()
+void SocketUDP::Create(SocketHelper::SocketType Descriptor)
{
- // Get a new socket descriptor
- mySocket = socket(PF_INET, SOCK_DGRAM, 0);
+ // 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;
- // To avoid the "Address already in use" error message when trying to bind to the same port
- char Yes = 1;
- if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(int)) == -1)
- {
- std::cerr << "Failed to set socket option \"reuse address\" ; "
- << "binding to a same port may fail if too fast" << std::endl;
- }
+ // Reset the pending packet
+ myPendingPacket.clear();
+ myPendingPacketSize = -1;
- // Enable broadcast by default
- if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, &Yes, sizeof(int)) == -1)
+ // Setup default options
+ if (IsValid())
{
- std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
- }
+ // 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<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to set socket option \"reuse address\" ; "
+ << "binding to a same port may fail if too fast" << std::endl;
+ }
- // Set blocking by default (should always be the case anyway)
- SetBlocking(true);
+ // Enable broadcast by default
+ if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
+ {
+ std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
+ }
- // Reset the pending packet
- myPendingPacket.Clear();
- myPendingPacketSize = -1;
+ // Set blocking by default (should always be the case anyway)
+ SetBlocking(true);
+ }
}
} // namespace sf
diff --git a/src/SFML/Network/Unix/.svn/all-wcprops b/src/SFML/Network/Unix/.svn/all-wcprops
new file mode 100644
index 0000000..e08b12e
--- /dev/null
+++ b/src/SFML/Network/Unix/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svnroot/sfml/!svn/ver/383/src/SFML/Network/Unix
+END
+SocketHelper.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 65
+/svnroot/sfml/!svn/ver/354/src/SFML/Network/Unix/SocketHelper.cpp
+END
diff --git a/src/SFML/Network/Unix/.svn/entries b/src/SFML/Network/Unix/.svn/entries
new file mode 100644
index 0000000..6bf301d
--- /dev/null
+++ b/src/SFML/Network/Unix/.svn/entries
@@ -0,0 +1,62 @@
+9
+
+dir
+915
+https://sfml.svn.sourceforge.net/svnroot/sfml/src/SFML/Network/Unix
+https://sfml.svn.sourceforge.net/svnroot/sfml
+
+
+
+2007-12-26T07:14:50.320767Z
+383
+laurentgom
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+4e206d99-4929-0410-ac5d-dfc041789085
+
+SocketHelper.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+88ba8b6ea7861c7e1c31c1c06e0bdb8b
+2007-12-08T08:38:55.079027Z
+354
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2970
+
diff --git a/src/SFML/Network/Unix/.svn/format b/src/SFML/Network/Unix/.svn/format
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/src/SFML/Network/Unix/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/src/SFML/Network/Unix/.svn/text-base/SocketHelper.cpp.svn-base b/src/SFML/Network/Unix/.svn/text-base/SocketHelper.cpp.svn-base
new file mode 100644
index 0000000..5fdf9d3
--- /dev/null
+++ b/src/SFML/Network/Unix/.svn/text-base/SocketHelper.cpp.svn-base
@@ -0,0 +1,83 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/SocketHelper.hpp>
+#include <errno.h>
+#include <fcntl.h>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Return the value of the invalid socket
+////////////////////////////////////////////////////////////
+SocketHelper::SocketType SocketHelper::InvalidSocket()
+{
+ return -1;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Close / destroy a socket
+////////////////////////////////////////////////////////////
+bool SocketHelper::Close(SocketHelper::SocketType Socket)
+{
+ return close(Socket) != -1;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set a socket as blocking or non-blocking
+////////////////////////////////////////////////////////////
+void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block)
+{
+ int Status = fcntl(Socket, F_GETFL);
+ if (Block)
+ fcntl(Socket, F_SETFL, Status & ~O_NONBLOCK);
+ else
+ fcntl(Socket, F_SETFL, Status | O_NONBLOCK);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the last socket error status
+////////////////////////////////////////////////////////////
+Socket::Status SocketHelper::GetErrorStatus()
+{
+ switch (errno)
+ {
+ case EWOULDBLOCK : return Socket::NotReady;
+ case ECONNABORTED : return Socket::Disconnected;
+ case ECONNRESET : return Socket::Disconnected;
+ case ETIMEDOUT : return Socket::Disconnected;
+ case ENETRESET : return Socket::Disconnected;
+ case ENOTCONN : return Socket::Disconnected;
+ default : return Socket::Error;
+ }
+}
+
+} // namespace sf
diff --git a/src/SFML/Network/Unix/SocketHelper.cpp b/src/SFML/Network/Unix/SocketHelper.cpp
index 5fdf9d3..5fdf9d3 100755..100644
--- a/src/SFML/Network/Unix/SocketHelper.cpp
+++ b/src/SFML/Network/Unix/SocketHelper.cpp
diff --git a/src/SFML/Network/Win32/.svn/all-wcprops b/src/SFML/Network/Win32/.svn/all-wcprops
new file mode 100644
index 0000000..19a126b
--- /dev/null
+++ b/src/SFML/Network/Win32/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svnroot/sfml/!svn/ver/434/src/SFML/Network/Win32
+END
+SocketHelper.cpp
+K 25
+svn:wc:ra_dav:version-url
+V 66
+/svnroot/sfml/!svn/ver/434/src/SFML/Network/Win32/SocketHelper.cpp
+END
diff --git a/src/SFML/Network/Win32/.svn/entries b/src/SFML/Network/Win32/.svn/entries
new file mode 100644
index 0000000..4b85837
--- /dev/null
+++ b/src/SFML/Network/Win32/.svn/entries
@@ -0,0 +1,62 @@
+9
+
+dir
+915
+https://sfml.svn.sourceforge.net/svnroot/sfml/src/SFML/Network/Win32
+https://sfml.svn.sourceforge.net/svnroot/sfml
+
+
+
+2008-01-23T16:10:18.126022Z
+434
+laurentgom
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+4e206d99-4929-0410-ac5d-dfc041789085
+
+SocketHelper.cpp
+file
+
+
+
+
+2008-11-01T16:23:45.000000Z
+896c6a926959787ef4d8949f31503bed
+2008-01-23T16:10:18.126022Z
+434
+laurentgom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3426
+
diff --git a/src/SFML/Network/Win32/.svn/format b/src/SFML/Network/Win32/.svn/format
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/src/SFML/Network/Win32/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/src/SFML/Network/Win32/.svn/text-base/SocketHelper.cpp.svn-base b/src/SFML/Network/Win32/.svn/text-base/SocketHelper.cpp.svn-base
new file mode 100644
index 0000000..972aeb7
--- /dev/null
+++ b/src/SFML/Network/Win32/.svn/text-base/SocketHelper.cpp.svn-base
@@ -0,0 +1,100 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Network/SocketHelper.hpp>
+
+
+namespace sf
+{
+////////////////////////////////////////////////////////////
+/// Return the value of the invalid socket
+////////////////////////////////////////////////////////////
+SocketHelper::SocketType SocketHelper::InvalidSocket()
+{
+ return INVALID_SOCKET;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Close / destroy a socket
+////////////////////////////////////////////////////////////
+bool SocketHelper::Close(SocketHelper::SocketType Socket)
+{
+ return closesocket(Socket) != -1;
+}
+
+
+////////////////////////////////////////////////////////////
+/// Set a socket as blocking or non-blocking
+////////////////////////////////////////////////////////////
+void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block)
+{
+ unsigned long Blocking = Block ? 0 : 1;
+ ioctlsocket(Socket, FIONBIO, &Blocking);
+}
+
+
+////////////////////////////////////////////////////////////
+/// Get the last socket error status
+////////////////////////////////////////////////////////////
+Socket::Status SocketHelper::GetErrorStatus()
+{
+ switch (WSAGetLastError())
+ {
+ case WSAEWOULDBLOCK : return Socket::NotReady;
+ case WSAECONNABORTED : return Socket::Disconnected;
+ case WSAECONNRESET : return Socket::Disconnected;
+ case WSAETIMEDOUT : return Socket::Disconnected;
+ case WSAENETRESET : return Socket::Disconnected;
+ case WSAENOTCONN : return Socket::Disconnected;
+ default : return Socket::Error;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// Windows needs some initialization and cleanup to get
+// sockets working properly... so let's create a class that will
+// do it automatically
+////////////////////////////////////////////////////////////
+struct SocketInitializer
+{
+ SocketInitializer()
+ {
+ WSADATA InitData;
+ WSAStartup(MAKEWORD(2,2), &InitData);
+ }
+
+ ~SocketInitializer()
+ {
+ WSACleanup();
+ }
+};
+
+SocketInitializer GlobalInitializer;
+
+} // namespace sf
diff --git a/src/SFML/Network/Win32/SocketHelper.cpp b/src/SFML/Network/Win32/SocketHelper.cpp
index 972aeb7..972aeb7 100755..100644
--- a/src/SFML/Network/Win32/SocketHelper.cpp
+++ b/src/SFML/Network/Win32/SocketHelper.cpp