FS#86 - Rewrite the sockets API
Updated the API documentation of the whole network module The system headers are no longer included by the sfml-network public headers git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1475 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
parent
a09ee0f9e3
commit
9280771665
66 changed files with 3976 additions and 2992 deletions
|
@ -36,35 +36,19 @@
|
|||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
// Utility class for exchanging stuff with the server
|
||||
// on the data channel
|
||||
////////////////////////////////////////////////////////////
|
||||
class Ftp::DataChannel : NonCopyable
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
DataChannel(Ftp& owner);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Destructor
|
||||
////////////////////////////////////////////////////////////
|
||||
~DataChannel();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Open the data channel using the specified mode and port
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Open(Ftp::TransferMode mode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Send data on the data channel
|
||||
////////////////////////////////////////////////////////////
|
||||
void Send(const std::vector<char>& data);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Receive data on the data channel until it is closed
|
||||
////////////////////////////////////////////////////////////
|
||||
void Receive(std::vector<char>& data);
|
||||
|
||||
|
@ -74,12 +58,10 @@ private :
|
|||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp& myFtp; ///< Reference to the owner Ftp instance
|
||||
SocketTCP myDataSocket; ///< Socket used for data transfers
|
||||
TcpSocket myDataSocket; ///< Socket used for data transfers
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response::Response(Status code, const std::string& message) :
|
||||
myStatus (code),
|
||||
|
@ -89,9 +71,6 @@ myMessage(message)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Convenience function to check if the response status code
|
||||
/// means a success
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Ftp::Response::IsOk() const
|
||||
{
|
||||
|
@ -99,8 +78,6 @@ bool Ftp::Response::IsOk() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the response status code
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response::Status Ftp::Response::GetStatus() const
|
||||
{
|
||||
|
@ -108,8 +85,6 @@ Ftp::Response::Status Ftp::Response::GetStatus() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the full message contained in the response
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& Ftp::Response::GetMessage() const
|
||||
{
|
||||
|
@ -118,23 +93,19 @@ const std::string& Ftp::Response::GetMessage() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response response) :
|
||||
Ftp::DirectoryResponse::DirectoryResponse(const Ftp::Response& response) :
|
||||
Ftp::Response(response)
|
||||
{
|
||||
if (IsOk())
|
||||
{
|
||||
// Extract the directory from the server response
|
||||
std::string::size_type begin = response.GetMessage().find('"', 0);
|
||||
std::string::size_type end = response.GetMessage().find('"', begin + 1);
|
||||
myDirectory = response.GetMessage().substr(begin + 1, end - begin - 1);
|
||||
std::string::size_type begin = GetMessage().find('"', 0);
|
||||
std::string::size_type end = GetMessage().find('"', begin + 1);
|
||||
myDirectory = GetMessage().substr(begin + 1, end - begin - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the directory returned in the response
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& Ftp::DirectoryResponse::GetDirectory() const
|
||||
{
|
||||
|
@ -143,9 +114,7 @@ const std::string& Ftp::DirectoryResponse::GetDirectory() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::ListingResponse::ListingResponse(Ftp::Response response, const std::vector<char>& data) :
|
||||
Ftp::ListingResponse::ListingResponse(const Ftp::Response& response, const std::vector<char>& data) :
|
||||
Ftp::Response(response)
|
||||
{
|
||||
if (IsOk())
|
||||
|
@ -163,25 +132,12 @@ Ftp::Response(response)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the number of filenames in the listing
|
||||
////////////////////////////////////////////////////////////
|
||||
std::size_t Ftp::ListingResponse::GetCount() const
|
||||
const std::vector<std::string>& Ftp::ListingResponse::GetFilenames() const
|
||||
{
|
||||
return myFilenames.size();
|
||||
return myFilenames;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the Index-th filename in the directory
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& Ftp::ListingResponse::GetFilename(std::size_t index) const
|
||||
{
|
||||
return myFilenames[index];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Destructor -- close the connection with the server
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::~Ftp()
|
||||
{
|
||||
|
@ -189,13 +145,11 @@ Ftp::~Ftp()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Connect to the specified FTP server
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::Connect(const IpAddress& server, unsigned short port, float timeout)
|
||||
{
|
||||
// Connect to the server
|
||||
if (myCommandSocket.Connect(port, server, timeout) != Socket::Done)
|
||||
if (myCommandSocket.Connect(server, port, timeout) != Socket::Done)
|
||||
return Response(Response::ConnectionFailed);
|
||||
|
||||
// Get the response to the connection
|
||||
|
@ -203,8 +157,6 @@ Ftp::Response Ftp::Connect(const IpAddress& server, unsigned short port, float t
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Log in using anonymous account
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::Login()
|
||||
{
|
||||
|
@ -212,8 +164,6 @@ Ftp::Response Ftp::Login()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Log in using a username and a password
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::Login(const std::string& name, const std::string& password)
|
||||
{
|
||||
|
@ -225,22 +175,18 @@ Ftp::Response Ftp::Login(const std::string& name, const std::string& password)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Close the connection with FTP server
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::Disconnect()
|
||||
{
|
||||
// Send the exit command
|
||||
Response response = SendCommand("QUIT");
|
||||
if (response.IsOk())
|
||||
myCommandSocket.Close();
|
||||
myCommandSocket.Disconnect();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send a null command just to prevent from being disconnected
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::KeepAlive()
|
||||
{
|
||||
|
@ -248,8 +194,6 @@ Ftp::Response Ftp::KeepAlive()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the current working directory
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::DirectoryResponse Ftp::GetWorkingDirectory()
|
||||
{
|
||||
|
@ -257,9 +201,6 @@ Ftp::DirectoryResponse Ftp::GetWorkingDirectory()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the contents of the given directory
|
||||
/// (subdirectories and files)
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& directory)
|
||||
{
|
||||
|
@ -285,8 +226,6 @@ Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& directory)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Change the current working directory
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::ChangeDirectory(const std::string& directory)
|
||||
{
|
||||
|
@ -294,8 +233,6 @@ Ftp::Response Ftp::ChangeDirectory(const std::string& directory)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Go to the parent directory of the current one
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::ParentDirectory()
|
||||
{
|
||||
|
@ -304,16 +241,12 @@ Ftp::Response Ftp::ParentDirectory()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Create a new directory
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::MakeDirectory(const std::string& name)
|
||||
Ftp::Response Ftp::CreateDirectory(const std::string& name)
|
||||
{
|
||||
return SendCommand("MKD", name);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Remove an existing directory
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::DeleteDirectory(const std::string& name)
|
||||
{
|
||||
|
@ -321,8 +254,6 @@ Ftp::Response Ftp::DeleteDirectory(const std::string& name)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Rename a file
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::RenameFile(const std::string& file, const std::string& newName)
|
||||
{
|
||||
|
@ -334,8 +265,6 @@ Ftp::Response Ftp::RenameFile(const std::string& file, const std::string& newNam
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Remove an existing file
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::DeleteFile(const std::string& name)
|
||||
{
|
||||
|
@ -344,9 +273,7 @@ Ftp::Response Ftp::DeleteFile(const std::string& name)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Download a file from the server
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& destPath, TransferMode mode)
|
||||
Ftp::Response Ftp::Download(const std::string& remoteFile, const std::string& localPath, TransferMode mode)
|
||||
{
|
||||
// Open a data channel using the given transfer mode
|
||||
DataChannel data(*this);
|
||||
|
@ -354,7 +281,7 @@ Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& d
|
|||
if (response.IsOk())
|
||||
{
|
||||
// Tell the server to start the transfer
|
||||
response = SendCommand("RETR", distantFile);
|
||||
response = SendCommand("RETR", remoteFile);
|
||||
if (response.IsOk())
|
||||
{
|
||||
// Receive the file data
|
||||
|
@ -366,13 +293,13 @@ Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& d
|
|||
if (response.IsOk())
|
||||
{
|
||||
// Extract the filename from the file path
|
||||
std::string filename = distantFile;
|
||||
std::string filename = remoteFile;
|
||||
std::string::size_type pos = filename.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
filename = filename.substr(pos + 1);
|
||||
|
||||
// Make sure the destination path ends with a slash
|
||||
std::string path = destPath;
|
||||
std::string path = localPath;
|
||||
if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/'))
|
||||
path += "/";
|
||||
|
||||
|
@ -392,9 +319,7 @@ Ftp::Response Ftp::Download(const std::string& distantFile, const std::string& d
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Upload a file to the server
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& destPath, TransferMode mode)
|
||||
Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& remotePath, TransferMode mode)
|
||||
{
|
||||
// Get the contents of the file to send
|
||||
std::ifstream file(localFile.c_str(), std::ios_base::binary);
|
||||
|
@ -415,7 +340,7 @@ Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& destP
|
|||
filename = filename.substr(pos + 1);
|
||||
|
||||
// Make sure the destination path ends with a slash
|
||||
std::string path = destPath;
|
||||
std::string path = remotePath;
|
||||
if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/'))
|
||||
path += "/";
|
||||
|
||||
|
@ -440,8 +365,6 @@ Ftp::Response Ftp::Upload(const std::string& localFile, const std::string& destP
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send a command to the FTP server
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::SendCommand(const std::string& command, const std::string& parameter)
|
||||
{
|
||||
|
@ -461,9 +384,6 @@ Ftp::Response Ftp::SendCommand(const std::string& command, const std::string& pa
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Receive a response from the server
|
||||
/// (usually after a command has been sent)
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::GetResponse()
|
||||
{
|
||||
|
@ -596,8 +516,6 @@ Ftp::Response Ftp::GetResponse()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::DataChannel::DataChannel(Ftp& owner) :
|
||||
myFtp(owner)
|
||||
|
@ -606,18 +524,6 @@ myFtp(owner)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Destructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::DataChannel::~DataChannel()
|
||||
{
|
||||
// Close the data socket
|
||||
myDataSocket.Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Open the data channel using the specified mode and port
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode mode)
|
||||
{
|
||||
|
@ -653,7 +559,7 @@ Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode mode)
|
|||
static_cast<Uint8>(data[3]));
|
||||
|
||||
// Connect the data channel to the server
|
||||
if (myDataSocket.Connect(port, address) == Socket::Done)
|
||||
if (myDataSocket.Connect(address, port) == Socket::Done)
|
||||
{
|
||||
// Translate the transfer mode to the corresponding FTP parameter
|
||||
std::string modeStr;
|
||||
|
@ -679,8 +585,6 @@ Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode mode)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Receive data on the data channel until it is closed
|
||||
////////////////////////////////////////////////////////////
|
||||
void Ftp::DataChannel::Receive(std::vector<char>& data)
|
||||
{
|
||||
|
@ -694,12 +598,10 @@ void Ftp::DataChannel::Receive(std::vector<char>& data)
|
|||
}
|
||||
|
||||
// Close the data socket
|
||||
myDataSocket.Close();
|
||||
myDataSocket.Disconnect();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send data on the data channel
|
||||
////////////////////////////////////////////////////////////
|
||||
void Ftp::DataChannel::Send(const std::vector<char>& data)
|
||||
{
|
||||
|
@ -708,7 +610,7 @@ void Ftp::DataChannel::Send(const std::vector<char>& data)
|
|||
myDataSocket.Send(&data[0], data.size());
|
||||
|
||||
// Close the data socket
|
||||
myDataSocket.Close();
|
||||
myDataSocket.Disconnect();
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -32,16 +32,16 @@
|
|||
#include <sstream>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Private data
|
||||
////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
// Convenience function to convert a string to lower case
|
||||
////////////////////////////////////////////////////////////
|
||||
// Convert a string to lower case
|
||||
std::string ToLower(std::string str)
|
||||
{
|
||||
for (std::string::iterator i = str.begin(); i != str.end(); ++i)
|
||||
*i = static_cast<char>(tolower(*i));
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
@ -50,19 +50,15 @@ namespace
|
|||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Http::Request::Request(Method method, const std::string& URI, const std::string& body)
|
||||
Http::Request::Request(const std::string& uri, Method method, const std::string& body)
|
||||
{
|
||||
SetMethod(method);
|
||||
SetURI(URI);
|
||||
SetUri(uri);
|
||||
SetHttpVersion(1, 0);
|
||||
SetBody(body);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set the value of a field; the field is added if it doesn't exist
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::Request::SetField(const std::string& field, const std::string& value)
|
||||
{
|
||||
|
@ -70,9 +66,6 @@ void Http::Request::SetField(const std::string& field, const std::string& value)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set the request method.
|
||||
/// This parameter is Get by default
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::Request::SetMethod(Http::Request::Method method)
|
||||
{
|
||||
|
@ -81,12 +74,9 @@ void Http::Request::SetMethod(Http::Request::Method method)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set the target URI of the request.
|
||||
/// This parameter is "/" by default
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::Request::SetURI(const std::string& URI)
|
||||
void Http::Request::SetUri(const std::string& uri)
|
||||
{
|
||||
myURI = URI;
|
||||
myURI = uri;
|
||||
|
||||
// Make sure it starts with a '/'
|
||||
if (myURI.empty() || (myURI[0] != '/'))
|
||||
|
@ -94,9 +84,6 @@ void Http::Request::SetURI(const std::string& URI)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set the HTTP version of the request.
|
||||
/// This parameter is 1.0 by default
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::Request::SetHttpVersion(unsigned int major, unsigned int minor)
|
||||
{
|
||||
|
@ -105,10 +92,6 @@ void Http::Request::SetHttpVersion(unsigned int major, unsigned int minor)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set the body of the request. This parameter is optional and
|
||||
/// makes sense only for POST requests.
|
||||
/// This parameter is empty by default
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::Request::SetBody(const std::string& body)
|
||||
{
|
||||
|
@ -117,9 +100,7 @@ void Http::Request::SetBody(const std::string& body)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the string representation of a request header
|
||||
////////////////////////////////////////////////////////////
|
||||
std::string Http::Request::ToString() const
|
||||
std::string Http::Request::Prepare() const
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
|
@ -153,8 +134,6 @@ std::string Http::Request::ToString() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Check if the given field has been defined
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Http::Request::HasField(const std::string& field) const
|
||||
{
|
||||
|
@ -162,8 +141,6 @@ bool Http::Request::HasField(const std::string& field) const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Http::Response::Response() :
|
||||
myStatus (ConnectionFailed),
|
||||
|
@ -174,8 +151,6 @@ myMinorVersion(0)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the value of a field
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& Http::Response::GetField(const std::string& field) const
|
||||
{
|
||||
|
@ -192,8 +167,6 @@ const std::string& Http::Response::GetField(const std::string& field) const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the header's status code
|
||||
////////////////////////////////////////////////////////////
|
||||
Http::Response::Status Http::Response::GetStatus() const
|
||||
{
|
||||
|
@ -201,8 +174,6 @@ Http::Response::Status Http::Response::GetStatus() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the major HTTP version number of the response
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Http::Response::GetMajorHttpVersion() const
|
||||
{
|
||||
|
@ -210,8 +181,6 @@ unsigned int Http::Response::GetMajorHttpVersion() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the major HTTP version number of the response
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Http::Response::GetMinorHttpVersion() const
|
||||
{
|
||||
|
@ -219,12 +188,6 @@ unsigned int Http::Response::GetMinorHttpVersion() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the body of the response. The body can contain :
|
||||
/// - the requested page (for GET requests)
|
||||
/// - a response from the server (for POST requests)
|
||||
/// - nothing (for HEAD requests)
|
||||
/// - an error message (in case of an error)
|
||||
////////////////////////////////////////////////////////////
|
||||
const std::string& Http::Response::GetBody() const
|
||||
{
|
||||
|
@ -233,9 +196,7 @@ const std::string& Http::Response::GetBody() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Construct the header from a response string
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::Response::FromString(const std::string& data)
|
||||
void Http::Response::Parse(const std::string& data)
|
||||
{
|
||||
std::istringstream in(data);
|
||||
|
||||
|
@ -300,8 +261,6 @@ void Http::Response::FromString(const std::string& data)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Http::Http() :
|
||||
myHost(),
|
||||
|
@ -311,8 +270,6 @@ myPort(0)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Construct the Http instance with the target host
|
||||
////////////////////////////////////////////////////////////
|
||||
Http::Http(const std::string& host, unsigned short port)
|
||||
{
|
||||
|
@ -320,8 +277,6 @@ Http::Http(const std::string& host, unsigned short port)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set the target host
|
||||
////////////////////////////////////////////////////////////
|
||||
void Http::SetHost(const std::string& host, unsigned short port)
|
||||
{
|
||||
|
@ -354,17 +309,10 @@ void Http::SetHost(const std::string& host, unsigned short port)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send a HTTP request and return the server's response.
|
||||
/// You must be connected to a host before sending requests.
|
||||
/// Any missing mandatory header field will be added with an appropriate value.
|
||||
/// Warning : this function waits for the server's response and may
|
||||
/// not return instantly; use a thread if you don't want to block your
|
||||
/// application.
|
||||
////////////////////////////////////////////////////////////
|
||||
Http::Response Http::SendRequest(const Http::Request& request, float timeout)
|
||||
{
|
||||
// First make sure the request is valid -- add missing mandatory fields
|
||||
// First make sure that the request is valid -- add missing mandatory fields
|
||||
Request toSend(request);
|
||||
if (!toSend.HasField("From"))
|
||||
{
|
||||
|
@ -397,10 +345,10 @@ Http::Response Http::SendRequest(const Http::Request& request, float timeout)
|
|||
Response received;
|
||||
|
||||
// Connect the socket to the host
|
||||
if (myConnection.Connect(myPort, myHost, timeout) == Socket::Done)
|
||||
if (myConnection.Connect(myHost, myPort, timeout) == Socket::Done)
|
||||
{
|
||||
// Convert the request to string and send it through the connected socket
|
||||
std::string requestStr = toSend.ToString();
|
||||
std::string requestStr = toSend.Prepare();
|
||||
|
||||
if (!requestStr.empty())
|
||||
{
|
||||
|
@ -417,12 +365,12 @@ Http::Response Http::SendRequest(const Http::Request& request, float timeout)
|
|||
}
|
||||
|
||||
// Build the Response object from the received data
|
||||
received.FromString(receivedStr);
|
||||
received.Parse(receivedStr);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the connection
|
||||
myConnection.Close();
|
||||
myConnection.Disconnect();
|
||||
}
|
||||
|
||||
return received;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/IpAddress.hpp>
|
||||
#include <SFML/Network/Http.hpp>
|
||||
#include <SFML/Network/SocketHelper.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
@ -135,37 +135,31 @@ IpAddress IpAddress::GetLocalAddress()
|
|||
IpAddress localAddress;
|
||||
|
||||
// Create the socket
|
||||
SocketHelper::SocketType sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == SocketHelper::InvalidSocket())
|
||||
SocketHandle sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (sock == priv::SocketImpl::InvalidSocket())
|
||||
return localAddress;
|
||||
|
||||
// Build the host address (use a random port)
|
||||
sockaddr_in sockAddr;
|
||||
memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
|
||||
sockAddr.sin_addr.s_addr = INADDR_LOOPBACK;
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_port = htons(4567);
|
||||
|
||||
// Connect the socket
|
||||
if (connect(sock, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) == -1)
|
||||
// Connect the socket to localhost on any port
|
||||
sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_LOOPBACK, 0);
|
||||
if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||
{
|
||||
SocketHelper::Close(sock);
|
||||
priv::SocketImpl::Close(sock);
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
// Get the local address of the socket connection
|
||||
SocketHelper::LengthType size = sizeof(sockAddr);
|
||||
if (getsockname(sock, reinterpret_cast<sockaddr*>(&sockAddr), &size) == -1)
|
||||
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||
if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1)
|
||||
{
|
||||
SocketHelper::Close(sock);
|
||||
priv::SocketImpl::Close(sock);
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
// Close the socket
|
||||
SocketHelper::Close(sock);
|
||||
priv::SocketImpl::Close(sock);
|
||||
|
||||
// Finally build the IP address
|
||||
localAddress.myAddress = sockAddr.sin_addr.s_addr;
|
||||
localAddress.myAddress = address.sin_addr.s_addr;
|
||||
|
||||
return localAddress;
|
||||
}
|
||||
|
@ -181,7 +175,7 @@ IpAddress IpAddress::GetPublicAddress(float timeout)
|
|||
// (not very hard: the web page contains only our IP address).
|
||||
|
||||
Http server("www.sfml-dev.org");
|
||||
Http::Request request(Http::Request::Get, "/ip-provider.php");
|
||||
Http::Request request("/ip-provider.php", Http::Request::Get);
|
||||
Http::Response page = server.SendRequest(request, timeout);
|
||||
if (page.GetStatus() == Http::Response::Ok)
|
||||
return IpAddress(page.GetBody());
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
#include <SFML/Network/SocketHelper.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <SFML/System/String.hpp>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -34,8 +34,6 @@
|
|||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet::Packet() :
|
||||
myReadPos(0),
|
||||
myIsValid(true)
|
||||
|
@ -44,8 +42,6 @@ myIsValid(true)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Virtual destructor
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet::~Packet()
|
||||
{
|
||||
|
@ -53,8 +49,6 @@ Packet::~Packet()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Append data to the end of the packet
|
||||
////////////////////////////////////////////////////////////
|
||||
void Packet::Append(const void* data, std::size_t sizeInBytes)
|
||||
{
|
||||
|
@ -67,8 +61,6 @@ void Packet::Append(const void* data, std::size_t sizeInBytes)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Clear the packet data
|
||||
////////////////////////////////////////////////////////////
|
||||
void Packet::Clear()
|
||||
{
|
||||
|
@ -78,10 +70,6 @@ void Packet::Clear()
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get a pointer to the data contained in the packet
|
||||
/// Warning : the returned pointer may be invalid after you
|
||||
/// append data to the packet
|
||||
////////////////////////////////////////////////////////////
|
||||
const char* Packet::GetData() const
|
||||
{
|
||||
|
@ -89,8 +77,6 @@ const char* Packet::GetData() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the size of the data contained in the packet
|
||||
////////////////////////////////////////////////////////////
|
||||
std::size_t Packet::GetDataSize() const
|
||||
{
|
||||
|
@ -98,8 +84,6 @@ std::size_t Packet::GetDataSize() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Tell if the reading position has reached the end of the packet
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Packet::EndOfPacket() const
|
||||
{
|
||||
|
@ -107,8 +91,6 @@ bool Packet::EndOfPacket() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Tell if the packet is valid for reading
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet::operator bool() const
|
||||
{
|
||||
|
@ -116,8 +98,6 @@ Packet::operator bool() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Operator >> overloads to extract data from the packet
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(bool& data)
|
||||
{
|
||||
|
@ -127,6 +107,9 @@ Packet& Packet::operator >>(bool& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(Int8& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -137,6 +120,9 @@ Packet& Packet::operator >>(Int8& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(Uint8& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -147,6 +133,9 @@ Packet& Packet::operator >>(Uint8& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(Int16& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -157,6 +146,9 @@ Packet& Packet::operator >>(Int16& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(Uint16& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -167,6 +159,9 @@ Packet& Packet::operator >>(Uint16& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(Int32& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -177,6 +172,9 @@ Packet& Packet::operator >>(Int32& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(Uint32& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -187,6 +185,9 @@ Packet& Packet::operator >>(Uint32& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(float& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -197,6 +198,9 @@ Packet& Packet::operator >>(float& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(double& data)
|
||||
{
|
||||
if (CheckSize(sizeof(data)))
|
||||
|
@ -207,6 +211,9 @@ Packet& Packet::operator >>(double& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(char* data)
|
||||
{
|
||||
// First extract string length
|
||||
|
@ -225,6 +232,9 @@ Packet& Packet::operator >>(char* data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(std::string& data)
|
||||
{
|
||||
// First extract string length
|
||||
|
@ -243,6 +253,9 @@ Packet& Packet::operator >>(std::string& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(wchar_t* data)
|
||||
{
|
||||
// First extract string length
|
||||
|
@ -263,6 +276,9 @@ Packet& Packet::operator >>(wchar_t* data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(std::wstring& data)
|
||||
{
|
||||
// First extract string length
|
||||
|
@ -283,6 +299,9 @@ Packet& Packet::operator >>(std::wstring& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator >>(String& data)
|
||||
{
|
||||
// First extract the string length
|
||||
|
@ -305,58 +324,83 @@ Packet& Packet::operator >>(String& data)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Operator << overloads to put data into the packet
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator <<(bool data)
|
||||
{
|
||||
*this << static_cast<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
|
||||
|
@ -370,6 +414,9 @@ Packet& Packet::operator <<(const char* data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator <<(const std::string& data)
|
||||
{
|
||||
// First insert string length
|
||||
|
@ -384,6 +431,9 @@ Packet& Packet::operator <<(const std::string& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator <<(const wchar_t* data)
|
||||
{
|
||||
// First insert string length
|
||||
|
@ -398,6 +448,9 @@ Packet& Packet::operator <<(const wchar_t* data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator <<(const std::wstring& data)
|
||||
{
|
||||
// First insert string length
|
||||
|
@ -413,6 +466,9 @@ Packet& Packet::operator <<(const std::wstring& data)
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Packet& Packet::operator <<(const String& data)
|
||||
{
|
||||
// First insert the string length
|
||||
|
@ -430,8 +486,6 @@ Packet& Packet::operator <<(const String& data)
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Check if the packet can extract a given size of bytes
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Packet::CheckSize(std::size_t size)
|
||||
{
|
||||
|
@ -442,21 +496,17 @@ bool Packet::CheckSize(std::size_t size)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Called before the packet is sent to the network
|
||||
////////////////////////////////////////////////////////////
|
||||
const char* Packet::OnSend(std::size_t& dataSize)
|
||||
const char* Packet::OnSend(std::size_t& size)
|
||||
{
|
||||
dataSize = GetDataSize();
|
||||
size = GetDataSize();
|
||||
return GetData();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Called after the packet has been received from the network
|
||||
////////////////////////////////////////////////////////////
|
||||
void Packet::OnReceive(const char* data, std::size_t dataSize)
|
||||
void Packet::OnReceive(const char* data, std::size_t size)
|
||||
{
|
||||
Append(data, dataSize);
|
||||
Append(data, size);
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
155
src/SFML/Network/Socket.cpp
Normal file
155
src/SFML/Network/Socket.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/Socket.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Socket(Type type) :
|
||||
myType (type),
|
||||
mySocket (priv::SocketImpl::InvalidSocket()),
|
||||
myIsBlocking(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::~Socket()
|
||||
{
|
||||
// Close the socket before it gets destructed
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Socket::SetBlocking(bool blocking)
|
||||
{
|
||||
// Apply if the socket is already created
|
||||
if (mySocket != priv::SocketImpl::InvalidSocket())
|
||||
priv::SocketImpl::SetBlocking(mySocket, blocking);
|
||||
|
||||
myIsBlocking = blocking;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Socket::IsBlocking() const
|
||||
{
|
||||
return myIsBlocking;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketHandle Socket::GetHandle() const
|
||||
{
|
||||
return mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Socket::Create()
|
||||
{
|
||||
// Don't create the socket if it already exists
|
||||
if (mySocket == priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
SocketHandle handle = socket(PF_INET, myType == Tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||
Create(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Socket::Create(SocketHandle handle)
|
||||
{
|
||||
// Don't create the socket if it already exists
|
||||
if (mySocket == priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
// Assign the new handle
|
||||
mySocket = handle;
|
||||
|
||||
// Set the current blocking state
|
||||
SetBlocking(myIsBlocking);
|
||||
|
||||
// To avoid the "Address already in use" error message when trying to bind to the same port
|
||||
int yes = 1;
|
||||
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to set socket option \"SO_REUSEADDR\" ; "
|
||||
<< "binding to a same port may fail if too fast" << std::endl;
|
||||
}
|
||||
|
||||
if (myType == Tcp)
|
||||
{
|
||||
// Disable the Nagle algorithm (ie. removes buffering of TCP packets)
|
||||
if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to set socket option \"TCP_NODELAY\" ; "
|
||||
<< "all your TCP packets will be buffered" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable broadcast by default for UDP sockets
|
||||
if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to enable broadcast on UDP socket" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Socket::Close()
|
||||
{
|
||||
// Close the socket
|
||||
if (mySocket != priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
priv::SocketImpl::Close(mySocket);
|
||||
mySocket = priv::SocketImpl::InvalidSocket();
|
||||
}
|
||||
|
||||
// Reset the pending packet data
|
||||
myPendingPacket = PendingPacket();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::PendingPacket::PendingPacket() :
|
||||
Size (0),
|
||||
SizeReceived(0),
|
||||
Data ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace sf
|
39
src/SFML/Network/SocketImpl.hpp
Normal file
39
src/SFML/Network/SocketImpl.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Config.hpp>
|
||||
|
||||
|
||||
#if defined(SFML_SYSTEM_WINDOWS)
|
||||
|
||||
#include <SFML/Network/Win32/SocketImpl.hpp>
|
||||
|
||||
#else
|
||||
|
||||
#include <SFML/Network/Unix/SocketImpl.hpp>
|
||||
|
||||
#endif
|
|
@ -22,114 +22,116 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/SelectorBase.hpp>
|
||||
#include <SFML/Network/SocketSelector.hpp>
|
||||
#include <SFML/Network/Socket.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
||||
#endif
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Default constructor
|
||||
struct SocketSelector::SocketSelectorImpl
|
||||
{
|
||||
fd_set AllSockets; ///< Set containing all the sockets handles
|
||||
fd_set SocketsReady; ///< Set containing handles of the sockets that are ready
|
||||
int MaxSocket; ///< Maximum socket handle
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SelectorBase::SelectorBase() :
|
||||
myMaxSocket(0)
|
||||
SocketSelector::SocketSelector() :
|
||||
myImpl(new SocketSelectorImpl)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Add a socket to watch
|
||||
////////////////////////////////////////////////////////////
|
||||
void SelectorBase::Add(SocketHelper::SocketType socket)
|
||||
SocketSelector::SocketSelector(const SocketSelector& copy) :
|
||||
myImpl(new SocketSelectorImpl(*copy.myImpl))
|
||||
{
|
||||
FD_SET(socket, &mySet);
|
||||
|
||||
int size = static_cast<int>(socket);
|
||||
if (size > myMaxSocket)
|
||||
myMaxSocket = size;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Remove a socket
|
||||
////////////////////////////////////////////////////////////
|
||||
void SelectorBase::Remove(SocketHelper::SocketType socket)
|
||||
SocketSelector::~SocketSelector()
|
||||
{
|
||||
FD_CLR(socket, &mySet);
|
||||
delete myImpl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Remove all sockets
|
||||
////////////////////////////////////////////////////////////
|
||||
void SelectorBase::Clear()
|
||||
void SocketSelector::Add(Socket& socket)
|
||||
{
|
||||
FD_ZERO(&mySet);
|
||||
FD_ZERO(&mySetReady);
|
||||
FD_SET(socket.GetHandle(), &myImpl->AllSockets);
|
||||
|
||||
myMaxSocket = 0;
|
||||
int size = static_cast<int>(socket.GetHandle());
|
||||
if (size > myImpl->MaxSocket)
|
||||
myImpl->MaxSocket = size;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Wait and collect sockets which are ready for reading.
|
||||
/// This functions will return either when at least one socket
|
||||
/// is ready, or when the given time is out
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int SelectorBase::Wait(float timeout)
|
||||
void SocketSelector::Remove(Socket& socket)
|
||||
{
|
||||
// Setup the timeout structure
|
||||
FD_CLR(socket.GetHandle(), &myImpl->AllSockets);
|
||||
FD_CLR(socket.GetHandle(), &myImpl->SocketsReady);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void SocketSelector::Clear()
|
||||
{
|
||||
FD_ZERO(&myImpl->AllSockets);
|
||||
FD_ZERO(&myImpl->SocketsReady);
|
||||
|
||||
myImpl->MaxSocket = 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketSelector::Wait(float timeout)
|
||||
{
|
||||
// Setup the timeout
|
||||
timeval time;
|
||||
time.tv_sec = static_cast<long>(timeout);
|
||||
time.tv_usec = (static_cast<long>(timeout * 1000) % 1000) * 1000;
|
||||
|
||||
// Prepare the set of sockets to return
|
||||
mySetReady = mySet;
|
||||
// Initialize the set that will contain the sockets that are ready
|
||||
myImpl->SocketsReady = myImpl->AllSockets;
|
||||
|
||||
// Wait until one of the sockets is ready for reading, or timeout is reached
|
||||
int nbSockets = select(myMaxSocket + 1, &mySetReady, NULL, NULL, timeout > 0 ? &time : NULL);
|
||||
int count = select(myImpl->MaxSocket + 1, &myImpl->SocketsReady, NULL, NULL, timeout > 0 ? &time : NULL);
|
||||
|
||||
return nbSockets >= 0 ? static_cast<unsigned int>(nbSockets) : 0;
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// After a call to Wait(), get the Index-th socket which is
|
||||
/// ready for reading. The total number of sockets ready
|
||||
/// is the integer returned by the previous call to Wait()
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketHelper::SocketType SelectorBase::GetSocketReady(unsigned int index) const
|
||||
bool SocketSelector::IsReady(Socket& socket) const
|
||||
{
|
||||
// We have to drop the const for FD_ISSET
|
||||
fd_set* set = const_cast<fd_set*>(&mySetReady);
|
||||
return FD_ISSET(socket.GetHandle(), &myImpl->SocketsReady) != 0;
|
||||
}
|
||||
|
||||
// The standard FD_xxx interface doesn't define a direct access,
|
||||
// so we must iterate through the whole set to find the socket that we're looking for
|
||||
for (int i = 0; i < myMaxSocket + 1; ++i)
|
||||
{
|
||||
if (FD_ISSET(i, set))
|
||||
{
|
||||
// Current socket is ready, but is it the index-th one ?
|
||||
if (index > 0)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<SocketHelper::SocketType>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid index : return an invalid socket
|
||||
return SocketHelper::InvalidSocket();
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketSelector& SocketSelector::operator =(const SocketSelector& right)
|
||||
{
|
||||
SocketSelector temp(right);
|
||||
|
||||
std::swap(myImpl, temp.myImpl);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -1,511 +0,0 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/SocketTCP.hpp>
|
||||
#include <SFML/Network/IpAddress.hpp>
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
#include <SFML/Network/SocketHelper.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
#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& host, float timeout)
|
||||
{
|
||||
// Make sure our socket is valid
|
||||
if (!IsValid())
|
||||
Create();
|
||||
|
||||
// Build the host address
|
||||
sockaddr_in sockAddr;
|
||||
memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
|
||||
sockAddr.sin_addr.s_addr = inet_addr(host.ToString().c_str());
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_port = htons(port);
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
// ----- We're not using a timeout : just try to connect -----
|
||||
|
||||
if (connect(mySocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) == -1)
|
||||
{
|
||||
// Failed to connect
|
||||
return SocketHelper::GetErrorStatus();
|
||||
}
|
||||
|
||||
// Connection succeeded
|
||||
return Socket::Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ----- We're using a timeout : we'll need a few tricks to make it work -----
|
||||
|
||||
// Save the previous blocking state
|
||||
bool blocking = myIsBlocking;
|
||||
|
||||
// Switch to non-blocking to enable our connection timeout
|
||||
if (blocking)
|
||||
SetBlocking(false);
|
||||
|
||||
// Try to connect to host
|
||||
if (connect(mySocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) >= 0)
|
||||
{
|
||||
// We got instantly connected! (it may no happen a lot...)
|
||||
return Socket::Done;
|
||||
}
|
||||
|
||||
// Get the error status
|
||||
Socket::Status status = SocketHelper::GetErrorStatus();
|
||||
|
||||
// If we were in non-blocking mode, return immediatly
|
||||
if (!blocking)
|
||||
return status;
|
||||
|
||||
// Otherwise, wait until something happens to our socket (success, timeout or error)
|
||||
if (status == Socket::NotReady)
|
||||
{
|
||||
// Setup the selector
|
||||
fd_set selector;
|
||||
FD_ZERO(&selector);
|
||||
FD_SET(mySocket, &selector);
|
||||
|
||||
// Setup the timeout
|
||||
timeval time;
|
||||
time.tv_sec = static_cast<long>(timeout);
|
||||
time.tv_usec = (static_cast<long>(timeout * 1000) % 1000) * 1000;
|
||||
|
||||
// Wait for something to write on our socket (which means that the connection request has returned)
|
||||
if (select(static_cast<int>(mySocket + 1), NULL, &selector, NULL, &time) > 0)
|
||||
{
|
||||
// At this point the connection may have been either accepted or refused.
|
||||
// To know whether it's a success or a failure, we try to retrieve the name of the connected peer
|
||||
SocketHelper::LengthType size = sizeof(sockAddr);
|
||||
if (getpeername(mySocket, reinterpret_cast<sockaddr*>(&sockAddr), &size) != -1)
|
||||
{
|
||||
// Connection accepted
|
||||
status = Socket::Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connection failed
|
||||
status = SocketHelper::GetErrorStatus();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to connect before timeout is over
|
||||
status = SocketHelper::GetErrorStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// Switch back to blocking mode
|
||||
SetBlocking(true);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Listen to a specified port for incoming data or connections
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketTCP::Listen(unsigned short port)
|
||||
{
|
||||
// Make sure our socket is valid
|
||||
if (!IsValid())
|
||||
Create();
|
||||
|
||||
// Build the address
|
||||
sockaddr_in sockAddr;
|
||||
memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
|
||||
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_port = htons(port);
|
||||
|
||||
// Bind the socket to the specified port
|
||||
if (bind(mySocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) == -1)
|
||||
{
|
||||
// Not likely to happen, but...
|
||||
Err() << "Failed to bind socket to port " << port << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Listen to the bound port
|
||||
if (listen(mySocket, 0) == -1)
|
||||
{
|
||||
// Oops, socket is deaf
|
||||
Err() << "Failed to listen to port " << port << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Wait for a connection (must be listening to a port).
|
||||
/// This function will block if the socket is blocking
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketTCP::Accept(SocketTCP& connected, IpAddress* address)
|
||||
{
|
||||
// Address that will be filled with client informations
|
||||
sockaddr_in clientAddress;
|
||||
SocketHelper::LengthType length = sizeof(clientAddress);
|
||||
|
||||
// Accept a new connection
|
||||
connected = accept(mySocket, reinterpret_cast<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 sizeInBytes)
|
||||
{
|
||||
// First check that socket is valid
|
||||
if (!IsValid())
|
||||
return Socket::Error;
|
||||
|
||||
// Check parameters
|
||||
if (data && sizeInBytes)
|
||||
{
|
||||
// Loop until every byte has been sent
|
||||
int sent = 0;
|
||||
int sizeToSend = static_cast<int>(sizeInBytes);
|
||||
for (int length = 0; length < sizeToSend; length += sent)
|
||||
{
|
||||
// Send a chunk of data
|
||||
sent = send(mySocket, data + length, sizeToSend - length, 0);
|
||||
|
||||
// Check if an error occured
|
||||
if (sent <= 0)
|
||||
return SocketHelper::GetErrorStatus();
|
||||
}
|
||||
|
||||
return Socket::Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error...
|
||||
Err() << "Cannot send data over the network (invalid parameters)" << std::endl;
|
||||
return Socket::Error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Receive an array of bytes from the host (must be connected first).
|
||||
/// This function will block if the socket is blocking
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketTCP::Receive(char* data, std::size_t maxSize, std::size_t& sizeReceived)
|
||||
{
|
||||
// First clear the size received
|
||||
sizeReceived = 0;
|
||||
|
||||
// Check that socket is valid
|
||||
if (!IsValid())
|
||||
return Socket::Error;
|
||||
|
||||
// Check parameters
|
||||
if (data && maxSize)
|
||||
{
|
||||
// Receive a chunk of bytes
|
||||
int received = recv(mySocket, data, static_cast<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...
|
||||
Err() << "Cannot receive data from the network (invalid parameters)" << std::endl;
|
||||
return Socket::Error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send a packet of data to the host (must be connected first)
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketTCP::Send(Packet& packet)
|
||||
{
|
||||
// Get the data to send from the packet
|
||||
std::size_t dataSize = 0;
|
||||
const char* data = packet.OnSend(dataSize);
|
||||
|
||||
// Send the packet size
|
||||
Uint32 packetSize = htonl(static_cast<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& packet)
|
||||
{
|
||||
// We start by getting the size of the incoming packet
|
||||
Uint32 packetSize = 0;
|
||||
std::size_t received = 0;
|
||||
if (myPendingPacketSize < 0)
|
||||
{
|
||||
// Loop until we've received the entire size of the packet
|
||||
// (even a 4 bytes variable may be received in more than one call)
|
||||
while (myPendingHeaderSize < sizeof(myPendingHeader))
|
||||
{
|
||||
char* data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
|
||||
Socket::Status status = Receive(data, sizeof(myPendingHeader) - myPendingHeaderSize, received);
|
||||
myPendingHeaderSize += received;
|
||||
|
||||
if (status != Socket::Done)
|
||||
return status;
|
||||
}
|
||||
|
||||
packetSize = ntohl(myPendingHeader);
|
||||
myPendingHeaderSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is a pending packet : we already know its size
|
||||
packetSize = myPendingPacketSize;
|
||||
}
|
||||
|
||||
// Then loop until we receive all the packet data
|
||||
char buffer[1024];
|
||||
while (myPendingPacket.size() < packetSize)
|
||||
{
|
||||
// Receive a chunk of data
|
||||
std::size_t sizeToGet = std::min(static_cast<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
|
||||
packet.Clear();
|
||||
if (!myPendingPacket.empty())
|
||||
packet.OnReceive(&myPendingPacket[0], myPendingPacket.size());
|
||||
myPendingPacket.clear();
|
||||
myPendingPacketSize = -1;
|
||||
|
||||
return Socket::Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Close the socket
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketTCP::Close()
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
if (!SocketHelper::Close(mySocket))
|
||||
{
|
||||
Err() << "Failed to close socket" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
mySocket = SocketHelper::InvalidSocket();
|
||||
}
|
||||
|
||||
myIsBlocking = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Check if the socket is in a valid state ; this function
|
||||
/// can be called any time to check if the socket is OK
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketTCP::IsValid() const
|
||||
{
|
||||
return mySocket != SocketHelper::InvalidSocket();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Comparison operator ==
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketTCP::operator ==(const SocketTCP& other) const
|
||||
{
|
||||
return mySocket == other.mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Comparison operator !=
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketTCP::operator !=(const SocketTCP& other) const
|
||||
{
|
||||
return mySocket != other.mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Comparison operator <.
|
||||
/// Provided for compatibility with standard containers, as
|
||||
/// comparing two sockets doesn't make much sense...
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketTCP::operator <(const SocketTCP& other) const
|
||||
{
|
||||
return mySocket < other.mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Construct the socket from a socket descriptor
|
||||
/// (for internal use only)
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketTCP::SocketTCP(SocketHelper::SocketType descriptor)
|
||||
{
|
||||
Create(descriptor);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Create the socket
|
||||
////////////////////////////////////////////////////////////
|
||||
void SocketTCP::Create(SocketHelper::SocketType descriptor)
|
||||
{
|
||||
// Use the given socket descriptor, or get a new one
|
||||
mySocket = descriptor ? descriptor : socket(PF_INET, SOCK_STREAM, 0);
|
||||
myIsBlocking = true;
|
||||
|
||||
// Reset the pending packet
|
||||
myPendingHeaderSize = 0;
|
||||
myPendingPacket.clear();
|
||||
myPendingPacketSize = -1;
|
||||
|
||||
// Setup default options
|
||||
if (IsValid())
|
||||
{
|
||||
// To avoid the "Address already in use" error message when trying to bind to the same port
|
||||
int yes = 1;
|
||||
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to set socket option \"SO_REUSEADDR\" ; "
|
||||
<< "binding to a same port may fail if too fast" << std::endl;
|
||||
}
|
||||
|
||||
// Disable the Nagle algorithm (ie. removes buffering of TCP packets)
|
||||
if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to set socket option \"TCP_NODELAY\" ; "
|
||||
<< "all your TCP packets will be buffered" << std::endl;
|
||||
}
|
||||
|
||||
// Set blocking by default (should always be the case anyway)
|
||||
SetBlocking(true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -1,433 +0,0 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/SocketUDP.hpp>
|
||||
#include <SFML/Network/IpAddress.hpp>
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
#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 unbind it first
|
||||
Unbind();
|
||||
|
||||
if (port != 0)
|
||||
{
|
||||
// Build an address with the specified port
|
||||
sockaddr_in sockAddr;
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_port = htons(port);
|
||||
sockAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
|
||||
|
||||
// Bind the socket to the port
|
||||
if (bind(mySocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) == -1)
|
||||
{
|
||||
Err() << "Failed to bind the socket to port " << port << std::endl;
|
||||
myPort = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the new port
|
||||
myPort = port;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Unbind the socket to its previous port
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketUDP::Unbind()
|
||||
{
|
||||
// To unbind the socket, we just recreate it
|
||||
if (myPort != 0)
|
||||
{
|
||||
Close();
|
||||
Create();
|
||||
myPort = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send an array of bytes
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketUDP::Send(const char* data, std::size_t sizeInBytes, const IpAddress& address, unsigned short port)
|
||||
{
|
||||
// Make sure the socket is valid
|
||||
if (!IsValid())
|
||||
Create();
|
||||
|
||||
// Check parameters
|
||||
if (data && sizeInBytes)
|
||||
{
|
||||
// Build the target address
|
||||
sockaddr_in sockAddr;
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_port = htons(port);
|
||||
sockAddr.sin_addr.s_addr = inet_addr(address.ToString().c_str());
|
||||
memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
|
||||
|
||||
// Loop until every byte has been sent
|
||||
int sent = 0;
|
||||
int sizeToSend = static_cast<int>(sizeInBytes);
|
||||
for (int length = 0; length < sizeToSend; length += sent)
|
||||
{
|
||||
// Send a chunk of data
|
||||
sent = sendto(mySocket, data + length, sizeToSend - length, 0, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr));
|
||||
|
||||
// Check errors
|
||||
if (sent <= 0)
|
||||
return SocketHelper::GetErrorStatus();
|
||||
}
|
||||
|
||||
return Socket::Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error...
|
||||
Err() << "Cannot send data over the network (invalid parameters)" << std::endl;
|
||||
return Socket::Error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Receive an array of bytes.
|
||||
/// This function will block if the socket is blocking
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketUDP::Receive(char* data, std::size_t maxSize, std::size_t& sizeReceived, IpAddress& address, unsigned short& port)
|
||||
{
|
||||
// First clear the size received
|
||||
sizeReceived = 0;
|
||||
|
||||
// Make sure the socket is bound to a port
|
||||
if (myPort == 0)
|
||||
{
|
||||
Err() << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl;
|
||||
return Socket::Error;
|
||||
}
|
||||
|
||||
// Make sure the socket is valid
|
||||
if (!IsValid())
|
||||
Create();
|
||||
|
||||
// Check parameters
|
||||
if (data && maxSize)
|
||||
{
|
||||
// Data that will be filled with the other computer's address
|
||||
sockaddr_in sockAddr;
|
||||
sockAddr.sin_family = AF_INET;
|
||||
sockAddr.sin_port = 0;
|
||||
sockAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
memset(sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
|
||||
SocketHelper::LengthType sockAddrSize = sizeof(sockAddr);
|
||||
|
||||
// Receive a chunk of bytes
|
||||
int received = recvfrom(mySocket, data, static_cast<int>(maxSize), 0, reinterpret_cast<sockaddr*>(&sockAddr), &sockAddrSize);
|
||||
|
||||
// Check the number of bytes received
|
||||
if (received > 0)
|
||||
{
|
||||
address = IpAddress(inet_ntoa(sockAddr.sin_addr));
|
||||
port = ntohs(sockAddr.sin_port);
|
||||
sizeReceived = static_cast<std::size_t>(received);
|
||||
return Socket::Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
address = IpAddress();
|
||||
port = 0;
|
||||
return received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error...
|
||||
Err() << "Cannot receive data from the network (invalid parameters)" << std::endl;
|
||||
return Socket::Error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Send a packet of data
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketUDP::Send(Packet& packet, const IpAddress& address, unsigned short port)
|
||||
{
|
||||
// Get the data to send from the packet
|
||||
std::size_t dataSize = 0;
|
||||
const char* data = packet.OnSend(dataSize);
|
||||
|
||||
// Send the packet size
|
||||
Uint32 packetSize = htonl(static_cast<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& packet, IpAddress& address, unsigned short& port)
|
||||
{
|
||||
// We start by getting the size of the incoming packet
|
||||
Uint32 packetSize = 0;
|
||||
std::size_t received = 0;
|
||||
if (myPendingPacketSize < 0)
|
||||
{
|
||||
// Loop until we've received the entire size of the packet
|
||||
// (even a 4 bytes variable may be received in more than one call)
|
||||
while (myPendingHeaderSize < sizeof(myPendingHeader))
|
||||
{
|
||||
char* data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
|
||||
Socket::Status status = Receive(data, sizeof(myPendingHeader) - myPendingHeaderSize, received, address, port);
|
||||
myPendingHeaderSize += received;
|
||||
|
||||
if (status != Socket::Done)
|
||||
return status;
|
||||
}
|
||||
|
||||
packetSize = ntohl(myPendingHeader);
|
||||
myPendingHeaderSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There is a pending packet : we already know its size
|
||||
packetSize = myPendingPacketSize;
|
||||
}
|
||||
|
||||
// Use another address instance for receiving the packet data ;
|
||||
// chunks of data coming from a different sender will be discarded (and lost...)
|
||||
IpAddress sender;
|
||||
unsigned short senderPort;
|
||||
|
||||
// Then loop until we receive all the packet data
|
||||
char buffer[1024];
|
||||
while (myPendingPacket.size() < packetSize)
|
||||
{
|
||||
// Receive a chunk of data
|
||||
std::size_t sizeToGet = std::min(static_cast<std::size_t>(packetSize - myPendingPacket.size()), sizeof(buffer));
|
||||
Socket::Status status = Receive(buffer, sizeToGet, received, sender, senderPort);
|
||||
if (status != Socket::Done)
|
||||
{
|
||||
// We must save the size of the pending packet until we can receive its content
|
||||
if (status == Socket::NotReady)
|
||||
myPendingPacketSize = packetSize;
|
||||
return status;
|
||||
}
|
||||
|
||||
// Append it into the packet
|
||||
if ((sender == address) && (senderPort == port) && (received > 0))
|
||||
{
|
||||
myPendingPacket.resize(myPendingPacket.size() + received);
|
||||
char* begin = &myPendingPacket[0] + myPendingPacket.size() - received;
|
||||
memcpy(begin, buffer, received);
|
||||
}
|
||||
}
|
||||
|
||||
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
|
||||
packet.Clear();
|
||||
if (!myPendingPacket.empty())
|
||||
packet.OnReceive(&myPendingPacket[0], myPendingPacket.size());
|
||||
myPendingPacket.clear();
|
||||
myPendingPacketSize = -1;
|
||||
|
||||
return Socket::Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Close the socket
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketUDP::Close()
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
if (!SocketHelper::Close(mySocket))
|
||||
{
|
||||
Err() << "Failed to close socket" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
mySocket = SocketHelper::InvalidSocket();
|
||||
}
|
||||
|
||||
myPort = 0;
|
||||
myIsBlocking = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Check if the socket is in a valid state ; this function
|
||||
/// can be called any time to check if the socket is OK
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketUDP::IsValid() const
|
||||
{
|
||||
return mySocket != SocketHelper::InvalidSocket();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the port the socket is currently bound to
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned short SocketUDP::GetPort() const
|
||||
{
|
||||
return myPort;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Comparison operator ==
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketUDP::operator ==(const SocketUDP& other) const
|
||||
{
|
||||
return mySocket == other.mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Comparison operator !=
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketUDP::operator !=(const SocketUDP& other) const
|
||||
{
|
||||
return mySocket != other.mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Comparison operator <.
|
||||
/// Provided for compatibility with standard containers, as
|
||||
/// comparing two sockets doesn't make much sense...
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketUDP::operator <(const SocketUDP& other) const
|
||||
{
|
||||
return mySocket < other.mySocket;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Construct the socket from a socket descriptor
|
||||
/// (for internal use only)
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketUDP::SocketUDP(SocketHelper::SocketType descriptor)
|
||||
{
|
||||
Create(descriptor);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Create the socket
|
||||
////////////////////////////////////////////////////////////
|
||||
void SocketUDP::Create(SocketHelper::SocketType descriptor)
|
||||
{
|
||||
// Use the given socket descriptor, or get a new one
|
||||
mySocket = descriptor ? descriptor : socket(PF_INET, SOCK_DGRAM, 0);
|
||||
myIsBlocking = true;
|
||||
|
||||
// Clear the last port used
|
||||
myPort = 0;
|
||||
|
||||
// Reset the pending packet
|
||||
myPendingHeaderSize = 0;
|
||||
myPendingPacket.clear();
|
||||
myPendingPacketSize = -1;
|
||||
|
||||
// Setup default options
|
||||
if (IsValid())
|
||||
{
|
||||
// To avoid the "Address already in use" error message when trying to bind to the same port
|
||||
int yes = 1;
|
||||
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to set socket option \"reuse address\" ; "
|
||||
<< "binding to a same port may fail if too fast" << std::endl;
|
||||
}
|
||||
|
||||
// Enable broadcast by default
|
||||
if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&yes), sizeof(yes)) == -1)
|
||||
{
|
||||
Err() << "Failed to enable broadcast on UDP socket" << std::endl;
|
||||
}
|
||||
|
||||
// Set blocking by default (should always be the case anyway)
|
||||
SetBlocking(true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sf
|
97
src/SFML/Network/TcpListener.cpp
Normal file
97
src/SFML/Network/TcpListener.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/TcpListener.hpp>
|
||||
#include <SFML/Network/TcpSocket.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
TcpListener::TcpListener() :
|
||||
Socket(Tcp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpListener::Listen(unsigned short port)
|
||||
{
|
||||
// Create the internal socket if it doesn't exist
|
||||
Create();
|
||||
|
||||
// Bind the socket to the specified port
|
||||
sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_ANY, port);
|
||||
if (bind(GetHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||
{
|
||||
// Not likely to happen, but...
|
||||
Err() << "Failed to bind listener socket to port " << port << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Listen to the bound port
|
||||
if (listen(GetHandle(), 0) == -1)
|
||||
{
|
||||
// Oops, socket is deaf
|
||||
Err() << "Failed to listen to port " << port << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpListener::Accept(TcpSocket& socket)
|
||||
{
|
||||
// Make sure that we're listening
|
||||
if (GetHandle() == priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
Err() << "Failed to accept a new connection, the socket is not listening" << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Accept a new connection
|
||||
sockaddr_in address;
|
||||
priv::SocketImpl::AddrLength length = sizeof(address);
|
||||
SocketHandle remote = accept(GetHandle(), reinterpret_cast<sockaddr*>(&address), &length);
|
||||
|
||||
// Check for errors
|
||||
if (remote == priv::SocketImpl::InvalidSocket())
|
||||
return priv::SocketImpl::GetErrorStatus();
|
||||
|
||||
// Initialize the new connected socket
|
||||
socket.Close();
|
||||
socket.Create(remote);
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
} // namespace sf
|
352
src/SFML/Network/TcpSocket.cpp
Normal file
352
src/SFML/Network/TcpSocket.cpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/TcpSocket.hpp>
|
||||
#include <SFML/Network/IpAddress.hpp>
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
|
||||
#endif
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
TcpSocket::TcpSocket() :
|
||||
Socket(Tcp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned short TcpSocket::GetLocalPort() const
|
||||
{
|
||||
if (GetHandle() != priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
// Retrieve informations about the local end of the socket
|
||||
sockaddr_in address;
|
||||
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||
if (getsockname(GetHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||
{
|
||||
return ntohs(address.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
// We failed to retrieve the port
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
IpAddress TcpSocket::GetRemoteAddress() const
|
||||
{
|
||||
if (GetHandle() != priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
// Retrieve informations about the remote end of the socket
|
||||
sockaddr_in address;
|
||||
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||
if (getpeername(GetHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||
{
|
||||
return IpAddress(ntohl(address.sin_addr.s_addr));
|
||||
}
|
||||
}
|
||||
|
||||
// We failed to retrieve the address
|
||||
return IpAddress::None;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned short TcpSocket::GetRemotePort() const
|
||||
{
|
||||
if (GetHandle() != priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
// Retrieve informations about the remote end of the socket
|
||||
sockaddr_in address;
|
||||
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||
if (getpeername(GetHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||
{
|
||||
return ntohs(address.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
// We failed to retrieve the port
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpSocket::Connect(const IpAddress& remoteAddress, unsigned short remotePort, float timeout)
|
||||
{
|
||||
// Create the internal socket if it doesn't exist
|
||||
Create();
|
||||
|
||||
// Create the remote address
|
||||
sockaddr_in address = priv::SocketImpl::CreateAddress(remoteAddress.ToInteger(), remotePort);
|
||||
|
||||
if (timeout <= 0)
|
||||
{
|
||||
// ----- We're not using a timeout: just try to connect -----
|
||||
|
||||
// Connect the socket
|
||||
if (connect(GetHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||
return priv::SocketImpl::GetErrorStatus();
|
||||
|
||||
// Connection succeeded
|
||||
return Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ----- We're using a timeout: we'll need a few tricks to make it work -----
|
||||
|
||||
// Save the previous blocking state
|
||||
bool blocking = IsBlocking();
|
||||
|
||||
// Switch to non-blocking to enable our connection timeout
|
||||
if (blocking)
|
||||
SetBlocking(false);
|
||||
|
||||
// Try to connect to the remote address
|
||||
if (connect(GetHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) >= 0)
|
||||
{
|
||||
// We got instantly connected! (it may no happen a lot...)
|
||||
return Done;
|
||||
}
|
||||
|
||||
// Get the error status
|
||||
Status status = priv::SocketImpl::GetErrorStatus();
|
||||
|
||||
// If we were in non-blocking mode, return immediatly
|
||||
if (!blocking)
|
||||
return status;
|
||||
|
||||
// Otherwise, wait until something happens to our socket (success, timeout or error)
|
||||
if (status == Socket::NotReady)
|
||||
{
|
||||
// Setup the selector
|
||||
fd_set selector;
|
||||
FD_ZERO(&selector);
|
||||
FD_SET(GetHandle(), &selector);
|
||||
|
||||
// Setup the timeout
|
||||
timeval time;
|
||||
time.tv_sec = static_cast<long>(timeout);
|
||||
time.tv_usec = (static_cast<long>(timeout * 1000) % 1000) * 1000;
|
||||
|
||||
// Wait for something to write on our socket (which means that the connection request has returned)
|
||||
if (select(static_cast<int>(GetHandle() + 1), NULL, &selector, NULL, &time) > 0)
|
||||
{
|
||||
// At this point the connection may have been either accepted or refused.
|
||||
// To know whether it's a success or a failure, we must check the address of the connected peer
|
||||
if (GetRemoteAddress() != sf::IpAddress::None)
|
||||
{
|
||||
// Connection accepted
|
||||
status = Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connection refused
|
||||
status = priv::SocketImpl::GetErrorStatus();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed to connect before timeout is over
|
||||
status = priv::SocketImpl::GetErrorStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// Switch back to blocking mode
|
||||
SetBlocking(true);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TcpSocket::Disconnect()
|
||||
{
|
||||
// Simply close the socket
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpSocket::Send(const char* data, std::size_t size)
|
||||
{
|
||||
// Check the parameters
|
||||
if (!data || (size == 0))
|
||||
{
|
||||
Err() << "Cannot send data over the network (invalid parameters)" << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Loop until every byte has been sent
|
||||
int sent = 0;
|
||||
int sizeToSend = static_cast<int>(size);
|
||||
for (int length = 0; length < sizeToSend; length += sent)
|
||||
{
|
||||
// Send a chunk of data
|
||||
sent = send(GetHandle(), data + length, sizeToSend - length, 0);
|
||||
|
||||
// Check for errors
|
||||
if (sent <= 0)
|
||||
return priv::SocketImpl::GetErrorStatus();
|
||||
}
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpSocket::Receive(char* data, std::size_t size, std::size_t& received)
|
||||
{
|
||||
// First clear the variables to fill
|
||||
received = 0;
|
||||
|
||||
// Check the parameters
|
||||
if (!data || (size == 0))
|
||||
{
|
||||
Err() << "Cannot receive data from the network (invalid parameters)" << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Receive a chunk of bytes
|
||||
int sizeReceived = recv(GetHandle(), data, static_cast<int>(size), 0);
|
||||
|
||||
// Check the number of bytes received
|
||||
if (sizeReceived > 0)
|
||||
{
|
||||
received = static_cast<std::size_t>(sizeReceived);
|
||||
return Done;
|
||||
}
|
||||
else if (sizeReceived == 0)
|
||||
{
|
||||
return Socket::Disconnected;
|
||||
}
|
||||
else
|
||||
{
|
||||
return priv::SocketImpl::GetErrorStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpSocket::Send(Packet& packet)
|
||||
{
|
||||
// Get the data to send from the packet
|
||||
std::size_t size = 0;
|
||||
const char* data = packet.OnSend(size);
|
||||
|
||||
// First send the packet size
|
||||
Uint32 packetSize = htonl(static_cast<unsigned long>(size));
|
||||
Status status = Send(reinterpret_cast<const char*>(&packetSize), sizeof(packetSize));
|
||||
|
||||
// Make sure that the size was properly sent
|
||||
if (status != Done)
|
||||
return status;
|
||||
|
||||
// Send the packet data
|
||||
if (packetSize > 0)
|
||||
{
|
||||
return Send(data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status TcpSocket::Receive(Packet& packet)
|
||||
{
|
||||
// First clear the variables to fill
|
||||
packet.Clear();
|
||||
|
||||
// We start by getting the size of the incoming packet
|
||||
Uint32 packetSize = 0;
|
||||
std::size_t received = 0;
|
||||
if (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size))
|
||||
{
|
||||
// Loop until we've received the entire size of the packet
|
||||
// (even a 4 bytes variable may be received in more than one call)
|
||||
while (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size))
|
||||
{
|
||||
char* data = reinterpret_cast<char*>(&myPendingPacket.Size) + myPendingPacket.SizeReceived;
|
||||
Status status = Receive(data, sizeof(myPendingPacket.Size) - myPendingPacket.SizeReceived, received);
|
||||
myPendingPacket.SizeReceived += received;
|
||||
|
||||
if (status != Done)
|
||||
return status;
|
||||
}
|
||||
|
||||
// The packet size has been fully received
|
||||
packetSize = ntohl(myPendingPacket.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The packet size has already been received in a previous call
|
||||
packetSize = ntohl(myPendingPacket.Size);
|
||||
}
|
||||
|
||||
// Loop until we receive all the packet data
|
||||
char buffer[1024];
|
||||
while (myPendingPacket.Data.size() < packetSize)
|
||||
{
|
||||
// Receive a chunk of data
|
||||
std::size_t sizeToGet = std::min(static_cast<std::size_t>(packetSize - myPendingPacket.Data.size()), sizeof(buffer));
|
||||
Status status = Receive(buffer, sizeToGet, received);
|
||||
if (status != Done)
|
||||
return status;
|
||||
|
||||
// Append it into the packet
|
||||
if (received > 0)
|
||||
{
|
||||
myPendingPacket.Data.resize(myPendingPacket.Data.size() + received);
|
||||
char* begin = &myPendingPacket.Data[0] + myPendingPacket.Data.size() - received;
|
||||
memcpy(begin, buffer, received);
|
||||
}
|
||||
}
|
||||
|
||||
// We have received all the packet data: we can copy it to the user packet
|
||||
if (!myPendingPacket.Data.empty())
|
||||
packet.OnReceive(&myPendingPacket.Data[0], myPendingPacket.Data.size());
|
||||
|
||||
// Clear the pending packet data
|
||||
myPendingPacket = PendingPacket();
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
} // namespace sf
|
256
src/SFML/Network/UdpSocket.cpp
Normal file
256
src/SFML/Network/UdpSocket.cpp
Normal file
|
@ -0,0 +1,256 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/UdpSocket.hpp>
|
||||
#include <SFML/Network/IpAddress.hpp>
|
||||
#include <SFML/Network/Packet.hpp>
|
||||
#include <SFML/Network/SocketImpl.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
UdpSocket::UdpSocket() :
|
||||
Socket(Udp)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned short UdpSocket::GetLocalPort() const
|
||||
{
|
||||
if (GetHandle() != priv::SocketImpl::InvalidSocket())
|
||||
{
|
||||
// Retrieve informations about the local end of the socket
|
||||
sockaddr_in address;
|
||||
priv::SocketImpl::AddrLength size = sizeof(address);
|
||||
if (getsockname(GetHandle(), reinterpret_cast<sockaddr*>(&address), &size) != -1)
|
||||
{
|
||||
return ntohs(address.sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
// We failed to retrieve the port
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status UdpSocket::Bind(unsigned short port)
|
||||
{
|
||||
// Create the internal socket if it doesn't exist
|
||||
Create();
|
||||
|
||||
// Bind the socket
|
||||
sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_ANY, port);
|
||||
if (bind(GetHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
|
||||
{
|
||||
Err() << "Failed to bind socket to port " << port << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void UdpSocket::Unbind()
|
||||
{
|
||||
// Simply close the socket
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status UdpSocket::Send(const char* data, std::size_t size, const IpAddress& remoteAddress, unsigned short remotePort)
|
||||
{
|
||||
// Create the internal socket if it doesn't exist
|
||||
Create();
|
||||
|
||||
// Check the parameters
|
||||
if (!data || (size == 0))
|
||||
{
|
||||
Err() << "Cannot send data over the network (invalid parameters)" << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Build the target address
|
||||
sockaddr_in address = priv::SocketImpl::CreateAddress(remoteAddress.ToInteger(), remotePort);
|
||||
|
||||
// Loop until every byte has been sent
|
||||
int sent = 0;
|
||||
int sizeToSend = static_cast<int>(size);
|
||||
for (int length = 0; length < sizeToSend; length += sent)
|
||||
{
|
||||
// Send a chunk of data
|
||||
sent = sendto(GetHandle(), data + length, sizeToSend - length, 0, reinterpret_cast<sockaddr*>(&address), sizeof(address));
|
||||
|
||||
// Check for errors
|
||||
if (sent <= 0)
|
||||
return priv::SocketImpl::GetErrorStatus();
|
||||
}
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status UdpSocket::Receive(char* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort)
|
||||
{
|
||||
// First clear the variables to fill
|
||||
received = 0;
|
||||
remoteAddress = IpAddress();
|
||||
remotePort = 0;
|
||||
|
||||
// Check the parameters
|
||||
if (!data || (size == 0))
|
||||
{
|
||||
Err() << "Cannot receive data from the network (invalid parameters)" << std::endl;
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Data that will be filled with the other computer's address
|
||||
sockaddr_in address = priv::SocketImpl::CreateAddress(INADDR_ANY, 0);
|
||||
|
||||
// Receive a chunk of bytes
|
||||
priv::SocketImpl::AddrLength addressSize = sizeof(address);
|
||||
int sizeReceived = recvfrom(GetHandle(), data, static_cast<int>(size), 0, reinterpret_cast<sockaddr*>(&address), &addressSize);
|
||||
|
||||
// Check for errors
|
||||
if (sizeReceived <= 0)
|
||||
return priv::SocketImpl::GetErrorStatus();
|
||||
|
||||
// Fill the sender informations
|
||||
received = static_cast<std::size_t>(sizeReceived);
|
||||
remoteAddress = IpAddress(ntohl(address.sin_addr.s_addr));
|
||||
remotePort = ntohs(address.sin_port);
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status UdpSocket::Send(Packet& packet, const IpAddress& remoteAddress, unsigned short remotePort)
|
||||
{
|
||||
// Get the data to send from the packet
|
||||
std::size_t size = 0;
|
||||
const char* data = packet.OnSend(size);
|
||||
|
||||
// First send the packet size
|
||||
Uint32 packetSize = htonl(static_cast<unsigned long>(size));
|
||||
Status status = Send(reinterpret_cast<const char*>(&packetSize), sizeof(packetSize), remoteAddress, remotePort);
|
||||
|
||||
// Make sure that the size was properly sent
|
||||
if (status != Done)
|
||||
return status;
|
||||
|
||||
// Finally send the packet data
|
||||
if (packetSize > 0)
|
||||
{
|
||||
return Send(data, size, remoteAddress, remotePort);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status UdpSocket::Receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort)
|
||||
{
|
||||
// First clear the variables to fill
|
||||
packet.Clear();
|
||||
remoteAddress = IpAddress();
|
||||
remotePort = 0;
|
||||
|
||||
// We start by getting the size of the incoming packet
|
||||
Uint32 packetSize = 0;
|
||||
std::size_t received = 0;
|
||||
if (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size))
|
||||
{
|
||||
// Loop until we've received the entire size of the packet
|
||||
// (even a 4 bytes variable may be received in more than one call)
|
||||
while (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size))
|
||||
{
|
||||
char* data = reinterpret_cast<char*>(&myPendingPacket.Size) + myPendingPacket.SizeReceived;
|
||||
std::size_t size = sizeof(myPendingPacket.Size) - myPendingPacket.SizeReceived;
|
||||
Status status = Receive(data, size, received, remoteAddress, remotePort);
|
||||
myPendingPacket.SizeReceived += received;
|
||||
|
||||
if (status != Done)
|
||||
return status;
|
||||
}
|
||||
|
||||
// The packet size has been fully received
|
||||
packetSize = ntohl(myPendingPacket.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The packet size has already been received in a previous call
|
||||
packetSize = ntohl(myPendingPacket.Size);
|
||||
}
|
||||
|
||||
// Use another address instance for receiving the packet data,
|
||||
// chunks of data coming from a different sender will be discarded (and lost...)
|
||||
IpAddress currentSender;
|
||||
unsigned short currentPort;
|
||||
|
||||
// Loop until we receive all the packet data
|
||||
char buffer[1024];
|
||||
while (myPendingPacket.Data.size() < packetSize)
|
||||
{
|
||||
// Receive a chunk of data
|
||||
std::size_t sizeToGet = std::min(static_cast<std::size_t>(packetSize - myPendingPacket.Data.size()), sizeof(buffer));
|
||||
Status status = Receive(buffer, sizeToGet, received, currentSender, currentPort);
|
||||
if (status != Done)
|
||||
return status;
|
||||
|
||||
// Append it into the packet
|
||||
if ((currentSender == remoteAddress) && (currentPort == remotePort) && (received > 0))
|
||||
{
|
||||
myPendingPacket.Data.resize(myPendingPacket.Data.size() + received);
|
||||
char* begin = &myPendingPacket.Data[0] + myPendingPacket.Data.size() - received;
|
||||
memcpy(begin, buffer, received);
|
||||
}
|
||||
}
|
||||
|
||||
// We have received all the packet data: we can copy it to the user packet
|
||||
if (!myPendingPacket.Data.empty())
|
||||
packet.OnReceive(&myPendingPacket.Data[0], myPendingPacket.Data.size());
|
||||
|
||||
// Clear the pending packet data
|
||||
myPendingPacket = PendingPacket();
|
||||
|
||||
return Done;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sf
|
|
@ -25,35 +25,45 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/SocketHelper.hpp>
|
||||
#include <SFML/Network/Unix/SocketImpl.hpp>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Return the value of the invalid socket
|
||||
sockaddr_in SocketImpl::CreateAddress(unsigned long address, unsigned short port)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
addr.sin_addr.s_addr = htonl(address);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketHelper::SocketType SocketHelper::InvalidSocket()
|
||||
SocketHandle SocketImpl::InvalidSocket()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Close / destroy a socket
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketHelper::Close(SocketHelper::SocketType socket)
|
||||
void SocketImpl::Close(SocketHandle sock)
|
||||
{
|
||||
return close(socket) != -1;
|
||||
close(sock);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set a socket as blocking or non-blocking
|
||||
////////////////////////////////////////////////////////////
|
||||
void SocketHelper::SetBlocking(SocketHelper::SocketType sock, bool block)
|
||||
void SocketImpl::SetBlocking(SocketHandle sock, bool block)
|
||||
{
|
||||
int status = fcntl(sock, F_GETFL);
|
||||
if (block)
|
||||
|
@ -64,9 +74,7 @@ void SocketHelper::SetBlocking(SocketHelper::SocketType sock, bool block)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the last socket error status
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketHelper::GetErrorStatus()
|
||||
Socket::Status SocketImpl::GetErrorStatus()
|
||||
{
|
||||
// The followings are sometimes equal to EWOULDBLOCK,
|
||||
// so we have to make a special case for them in order
|
||||
|
@ -86,4 +94,6 @@ Socket::Status SocketHelper::GetErrorStatus()
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
109
src/SFML/Network/Unix/SocketImpl.hpp
Normal file
109
src/SFML/Network/Unix/SocketImpl.hpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_SOCKETIMPL_HPP
|
||||
#define SFML_SOCKETIMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/Socket.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Helper class implementing all the non-portable
|
||||
/// socket stuff; this is the Unix version
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SocketImpl
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Types
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef socklen_t AddrLength;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create an internal sockaddr_in address
|
||||
///
|
||||
/// \param address Target address
|
||||
/// \param port Target port
|
||||
///
|
||||
/// \return sockaddr_in ready to be used by socket functions
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static sockaddr_in CreateAddress(unsigned long address, unsigned short port);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the value of the invalid socket
|
||||
///
|
||||
/// \return Special value of the invalid socket
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static SocketHandle InvalidSocket();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close and destroy a socket
|
||||
///
|
||||
/// \param sock Handle of the socket to close
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void Close(SocketHandle sock);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set a socket as blocking or non-blocking
|
||||
///
|
||||
/// \param sock Handle of the socket
|
||||
/// \param block New blocking state of the socket
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void SetBlocking(SocketHandle sock, bool block);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the last socket error status
|
||||
///
|
||||
/// \return Status corresponding to the last socket error
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Socket::Status GetErrorStatus();
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SOCKETIMPL_HPP
|
|
@ -25,43 +25,51 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/SocketHelper.hpp>
|
||||
#include <SFML/Network/Win32/SocketImpl.hpp>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Return the value of the invalid socket
|
||||
sockaddr_in SocketImpl::CreateAddress(unsigned long address, unsigned short port)
|
||||
{
|
||||
sockaddr_in addr;
|
||||
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
|
||||
addr.sin_addr.s_addr = htonl(address);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
SocketHelper::SocketType SocketHelper::InvalidSocket()
|
||||
SocketHandle SocketImpl::InvalidSocket()
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Close / destroy a socket
|
||||
////////////////////////////////////////////////////////////
|
||||
bool SocketHelper::Close(SocketHelper::SocketType socket)
|
||||
void SocketImpl::Close(SocketHandle sock)
|
||||
{
|
||||
return closesocket(socket) != -1;
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Set a socket as blocking or non-blocking
|
||||
////////////////////////////////////////////////////////////
|
||||
void SocketHelper::SetBlocking(SocketHelper::SocketType socket, bool block)
|
||||
void SocketImpl::SetBlocking(SocketHandle sock, bool block)
|
||||
{
|
||||
unsigned long blocking = block ? 0 : 1;
|
||||
ioctlsocket(socket, FIONBIO, &blocking);
|
||||
ioctlsocket(sock, FIONBIO, &blocking);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the last socket error status
|
||||
////////////////////////////////////////////////////////////
|
||||
Socket::Status SocketHelper::GetErrorStatus()
|
||||
Socket::Status SocketImpl::GetErrorStatus()
|
||||
{
|
||||
switch (WSAGetLastError())
|
||||
{
|
||||
|
@ -86,7 +94,7 @@ struct SocketInitializer
|
|||
SocketInitializer()
|
||||
{
|
||||
WSADATA init;
|
||||
WSAStartup(MAKEWORD(2,2), &init);
|
||||
WSAStartup(MAKEWORD(2, 2), &init);
|
||||
}
|
||||
|
||||
~SocketInitializer()
|
||||
|
@ -97,4 +105,6 @@ struct SocketInitializer
|
|||
|
||||
SocketInitializer globalInitializer;
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
103
src/SFML/Network/Win32/SocketImpl.hpp
Normal file
103
src/SFML/Network/Win32/SocketImpl.hpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_SOCKETIMPL_HPP
|
||||
#define SFML_SOCKETIMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/Socket.hpp>
|
||||
#include <winsock2.h>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Helper class implementing all the non-portable
|
||||
/// socket stuff; this is the Windows version
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SocketImpl
|
||||
{
|
||||
public :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Types
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef int AddrLength;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create an internal sockaddr_in address
|
||||
///
|
||||
/// \param address Target address
|
||||
/// \param port Target port
|
||||
///
|
||||
/// \return sockaddr_in ready to be used by socket functions
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static sockaddr_in CreateAddress(unsigned long address, unsigned short port);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the value of the invalid socket
|
||||
///
|
||||
/// \return Special value of the invalid socket
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static SocketHandle InvalidSocket();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Close and destroy a socket
|
||||
///
|
||||
/// \param sock Handle of the socket to close
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void Close(SocketHandle sock);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set a socket as blocking or non-blocking
|
||||
///
|
||||
/// \param sock Handle of the socket
|
||||
/// \param block New blocking state of the socket
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void SetBlocking(SocketHandle sock, bool block);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Get the last socket error status
|
||||
///
|
||||
/// \return Status corresponding to the last socket error
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static Socket::Status GetErrorStatus();
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SOCKETIMPL_HPP
|
Loading…
Add table
Add a link
Reference in a new issue