Add sfml network library. Hopefully this will make net-related coding a breeze :)

Note that as it is not used by anything yet, it has not yet been added as a dependency for any projects

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3184 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Shawn Hoffman 2009-05-08 17:04:11 +00:00
commit 56398758b0
28 changed files with 6097 additions and 0 deletions

709
Externals/SFML/src/SFML/Network/Ftp.cpp vendored Normal file
View file

@ -0,0 +1,709 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/Ftp.hpp>
#include <SFML/Network/IPAddress.hpp>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <sstream>
namespace sf
{
////////////////////////////////////////////////////////////
// Utility class for exchanging stuff with the server
// on the data channel
////////////////////////////////////////////////////////////
class Ftp::DataChannel : NonCopyable
{
public :
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
DataChannel(Ftp& Owner);
////////////////////////////////////////////////////////////
// Destructor
////////////////////////////////////////////////////////////
~DataChannel();
////////////////////////////////////////////////////////////
// Open the data channel using the specified mode and port
////////////////////////////////////////////////////////////
Ftp::Response Open(Ftp::TransferMode Mode);
////////////////////////////////////////////////////////////
// Send data on the data channel
////////////////////////////////////////////////////////////
void Send(const std::vector<char>& Data);
////////////////////////////////////////////////////////////
// Receive data on the data channel until it is closed
////////////////////////////////////////////////////////////
void Receive(std::vector<char>& Data);
private :
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
Ftp& myFtp; ///< Reference to the owner Ftp instance
SocketTCP myDataSocket; ///< Socket used for data transfers
};
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Ftp::Response::Response(Status Code, const std::string& Message) :
myStatus (Code),
myMessage(Message)
{
}
////////////////////////////////////////////////////////////
/// Convenience function to check if the response status code
/// means a success
////////////////////////////////////////////////////////////
bool Ftp::Response::IsOk() const
{
return myStatus < 400;
}
////////////////////////////////////////////////////////////
/// Get the response status code
////////////////////////////////////////////////////////////
Ftp::Response::Status Ftp::Response::GetStatus() const
{
return myStatus;
}
////////////////////////////////////////////////////////////
/// Get the full message contained in the response
////////////////////////////////////////////////////////////
const std::string& Ftp::Response::GetMessage() const
{
return myMessage;
}
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Ftp::DirectoryResponse::DirectoryResponse(Ftp::Response Resp) :
Ftp::Response(Resp)
{
if (IsOk())
{
// Extract the directory from the server response
std::string::size_type Begin = Resp.GetMessage().find('"', 0);
std::string::size_type End = Resp.GetMessage().find('"', Begin + 1);
myDirectory = Resp.GetMessage().substr(Begin + 1, End - Begin - 1);
}
}
////////////////////////////////////////////////////////////
/// Get the directory returned in the response
////////////////////////////////////////////////////////////
const std::string& Ftp::DirectoryResponse::GetDirectory() const
{
return myDirectory;
}
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Ftp::ListingResponse::ListingResponse(Ftp::Response Resp, const std::vector<char>& Data) :
Ftp::Response(Resp)
{
if (IsOk())
{
// Fill the array of strings
std::string Paths(Data.begin(), Data.end());
std::string::size_type LastPos = 0;
for (std::string::size_type Pos = Paths.find("\r\n"); Pos != std::string::npos; Pos = Paths.find("\r\n", LastPos))
{
myFilenames.push_back(Paths.substr(LastPos, Pos - LastPos));
LastPos = Pos + 2;
}
}
}
////////////////////////////////////////////////////////////
/// Get the number of filenames in the listing
////////////////////////////////////////////////////////////
std::size_t Ftp::ListingResponse::GetCount() const
{
return myFilenames.size();
}
////////////////////////////////////////////////////////////
/// Get the Index-th filename in the directory
////////////////////////////////////////////////////////////
const std::string& Ftp::ListingResponse::GetFilename(std::size_t Index) const
{
return myFilenames[Index];
}
////////////////////////////////////////////////////////////
/// Destructor -- close the connection with the server
////////////////////////////////////////////////////////////
Ftp::~Ftp()
{
Disconnect();
}
////////////////////////////////////////////////////////////
/// Connect to the specified FTP server
////////////////////////////////////////////////////////////
Ftp::Response Ftp::Connect(const IPAddress& Server, unsigned short Port, float Timeout)
{
// Connect to the server
if (myCommandSocket.Connect(Port, Server, Timeout) != Socket::Done)
return Response(Response::ConnectionFailed);
// Get the response to the connection
return GetResponse();
}
////////////////////////////////////////////////////////////
/// Log in using anonymous account
////////////////////////////////////////////////////////////
Ftp::Response Ftp::Login()
{
return Login("anonymous", "user@sfml-dev.org");
}
////////////////////////////////////////////////////////////
/// Log in using a username and a password
////////////////////////////////////////////////////////////
Ftp::Response Ftp::Login(const std::string& UserName, const std::string& Password)
{
Response Resp = SendCommand("USER", UserName);
if (Resp.IsOk())
Resp = SendCommand("PASS", Password);
return Resp;
}
////////////////////////////////////////////////////////////
/// Close the connection with FTP server
////////////////////////////////////////////////////////////
Ftp::Response Ftp::Disconnect()
{
// Send the exit command
Response Resp = SendCommand("QUIT");
if (Resp.IsOk())
myCommandSocket.Close();
return Resp;
}
////////////////////////////////////////////////////////////
/// Send a null command just to prevent from being disconnected
////////////////////////////////////////////////////////////
Ftp::Response Ftp::KeepAlive()
{
return SendCommand("NOOP");
}
////////////////////////////////////////////////////////////
/// Get the current working directory
////////////////////////////////////////////////////////////
Ftp::DirectoryResponse Ftp::GetWorkingDirectory()
{
return DirectoryResponse(SendCommand("PWD"));
}
////////////////////////////////////////////////////////////
/// Get the contents of the given directory
/// (subdirectories and files)
////////////////////////////////////////////////////////////
Ftp::ListingResponse Ftp::GetDirectoryListing(const std::string& Directory)
{
// Open a data channel on default port (20) using ASCII transfer mode
std::vector<char> DirData;
DataChannel Data(*this);
Response Resp = Data.Open(Ascii);
if (Resp.IsOk())
{
// Tell the server to send us the listing
Resp = SendCommand("NLST", Directory);
if (Resp.IsOk())
{
// Receive the listing
Data.Receive(DirData);
// Get the response from the server
Resp = GetResponse();
}
}
return ListingResponse(Resp, DirData);
}
////////////////////////////////////////////////////////////
/// Change the current working directory
////////////////////////////////////////////////////////////
Ftp::Response Ftp::ChangeDirectory(const std::string& Directory)
{
return SendCommand("CWD", Directory);
}
////////////////////////////////////////////////////////////
/// Go to the parent directory of the current one
////////////////////////////////////////////////////////////
Ftp::Response Ftp::ParentDirectory()
{
return SendCommand("CDUP");
}
////////////////////////////////////////////////////////////
/// Create a new directory
////////////////////////////////////////////////////////////
Ftp::Response Ftp::MakeDirectory(const std::string& Name)
{
return SendCommand("MKD", Name);
}
////////////////////////////////////////////////////////////
/// Remove an existing directory
////////////////////////////////////////////////////////////
Ftp::Response Ftp::DeleteDirectory(const std::string& Name)
{
return SendCommand("RMD", Name);
}
////////////////////////////////////////////////////////////
/// Rename a file
////////////////////////////////////////////////////////////
Ftp::Response Ftp::RenameFile(const std::string& File, const std::string& NewName)
{
Response Resp = SendCommand("RNFR", File);
if (Resp.IsOk())
Resp = SendCommand("RNTO", NewName);
return Resp;
}
////////////////////////////////////////////////////////////
/// Remove an existing file
////////////////////////////////////////////////////////////
Ftp::Response Ftp::DeleteFile(const std::string& Name)
{
return SendCommand("DELE", Name);
}
////////////////////////////////////////////////////////////
/// Download a file from the server
////////////////////////////////////////////////////////////
Ftp::Response Ftp::Download(const std::string& DistantFile, const std::string& DestPath, TransferMode Mode)
{
// Open a data channel using the given transfer mode
DataChannel Data(*this);
Response Resp = Data.Open(Mode);
if (Resp.IsOk())
{
// Tell the server to start the transfer
Resp = SendCommand("RETR", DistantFile);
if (Resp.IsOk())
{
// Receive the file data
std::vector<char> FileData;
Data.Receive(FileData);
// Get the response from the server
Resp = GetResponse();
if (Resp.IsOk())
{
// Extract the filename from the file path
std::string Filename = DistantFile;
std::string::size_type Pos = Filename.find_last_of("/\\");
if (Pos != std::string::npos)
Filename = Filename.substr(Pos + 1);
// Make sure the destination path ends with a slash
std::string Path = DestPath;
if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
Path += "/";
// Create the file and copy the received data into it
std::ofstream File((Path + Filename).c_str(), std::ios_base::binary);
if (!File)
return Response(Response::InvalidFile);
File.write(&FileData[0], static_cast<std::streamsize>(FileData.size()));
}
}
}
return Resp;
}
////////////////////////////////////////////////////////////
/// Upload a file to the server
////////////////////////////////////////////////////////////
Ftp::Response Ftp::Upload(const std::string& LocalFile, const std::string& DestPath, TransferMode Mode)
{
// Get the contents of the file to send
std::ifstream File(LocalFile.c_str(), std::ios_base::binary);
if (!File)
return Response(Response::InvalidFile);
File.seekg(0, std::ios::end);
std::size_t Length = File.tellg();
File.seekg(0, std::ios::beg);
std::vector<char> FileData(Length);
File.read(&FileData[0], static_cast<std::streamsize>(Length));
// Extract the filename from the file path
std::string Filename = LocalFile;
std::string::size_type Pos = Filename.find_last_of("/\\");
if (Pos != std::string::npos)
Filename = Filename.substr(Pos + 1);
// Make sure the destination path ends with a slash
std::string Path = DestPath;
if (!Path.empty() && (Path[Path.size() - 1] != '\\') && (Path[Path.size() - 1] != '/'))
Path += "/";
// Open a data channel using the given transfer mode
DataChannel Data(*this);
Response Resp = Data.Open(Mode);
if (Resp.IsOk())
{
// Tell the server to start the transfer
Resp = SendCommand("STOR", Path + Filename);
if (Resp.IsOk())
{
// Send the file data
Data.Send(FileData);
// Get the response from the server
Resp = GetResponse();
}
}
return Resp;
}
////////////////////////////////////////////////////////////
/// Send a command to the FTP server
////////////////////////////////////////////////////////////
Ftp::Response Ftp::SendCommand(const std::string& Command, const std::string& Parameter)
{
// Build the command string
std::string CommandStr;
if (Parameter != "")
CommandStr = Command + " " + Parameter + "\r\n";
else
CommandStr = Command + "\r\n";
// Send it to the server
if (myCommandSocket.Send(CommandStr.c_str(), CommandStr.length()) != sf::Socket::Done)
return Response(Response::ConnectionClosed);
// Get the response
return GetResponse();
}
////////////////////////////////////////////////////////////
/// Receive a response from the server
/// (usually after a command has been sent)
////////////////////////////////////////////////////////////
Ftp::Response Ftp::GetResponse()
{
// We'll use a variable to keep track of the last valid code.
// It is useful in case of multi-lines responses, because the end of such a response
// will start by the same code
unsigned int LastCode = 0;
bool IsInsideMultiline = false;
std::string Message;
for (;;)
{
// Receive the response from the server
char Buffer[1024];
std::size_t Length;
if (myCommandSocket.Receive(Buffer, sizeof(Buffer), Length) != sf::Socket::Done)
return Response(Response::ConnectionClosed);
// There can be several lines inside the received buffer, extract them all
std::istringstream In(std::string(Buffer, Length), std::ios_base::binary);
while (In)
{
// Try to extract the code
unsigned int Code;
if (In >> Code)
{
// Extract the separator
char Sep;
In.get(Sep);
// The '-' character means a multiline response
if ((Sep == '-') && !IsInsideMultiline)
{
// Set the multiline flag
IsInsideMultiline = true;
// Keep track of the code
if (LastCode == 0)
LastCode = Code;
// Extract the line
std::getline(In, Message);
// Remove the ending '\r' (all lines are terminated by "\r\n")
Message.erase(Message.length() - 1);
Message = Sep + Message + "\n";
}
else
{
// We must make sure that the code is the same, otherwise it means
// we haven't reached the end of the multiline response
if ((Sep != '-') && ((Code == LastCode) || (LastCode == 0)))
{
// Clear the multiline flag
IsInsideMultiline = false;
// Extract the line
std::string Line;
std::getline(In, Line);
// Remove the ending '\r' (all lines are terminated by "\r\n")
Line.erase(Line.length() - 1);
// Append it to the message
if (Code == LastCode)
{
std::ostringstream Out;
Out << Code << Sep << Line;
Message += Out.str();
}
else
{
Message = Sep + Line;
}
// Return the response code and message
return Response(static_cast<Response::Status>(Code), Message);
}
else
{
// The line we just read was actually not a response,
// only a new part of the current multiline response
// Extract the line
std::string Line;
std::getline(In, Line);
if (!Line.empty())
{
// Remove the ending '\r' (all lines are terminated by "\r\n")
Line.erase(Line.length() - 1);
// Append it to the current message
std::ostringstream Out;
Out << Code << Sep << Line << "\n";
Message += Out.str();
}
}
}
}
else if (LastCode != 0)
{
// It seems we are in the middle of a multiline response
// Clear the error bits of the stream
In.clear();
// Extract the line
std::string Line;
std::getline(In, Line);
if (!Line.empty())
{
// Remove the ending '\r' (all lines are terminated by "\r\n")
Line.erase(Line.length() - 1);
// Append it to the current message
Message += Line + "\n";
}
}
else
{
// Error : cannot extract the code, and we are not in a multiline response
return Response(Response::InvalidResponse);
}
}
}
// We never reach there
}
////////////////////////////////////////////////////////////
/// Constructor
////////////////////////////////////////////////////////////
Ftp::DataChannel::DataChannel(Ftp& Owner) :
myFtp(Owner)
{
}
////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
Ftp::DataChannel::~DataChannel()
{
// Close the data socket
myDataSocket.Close();
}
////////////////////////////////////////////////////////////
/// Open the data channel using the specified mode and port
////////////////////////////////////////////////////////////
Ftp::Response Ftp::DataChannel::Open(Ftp::TransferMode Mode)
{
// Open a data connection in active mode (we connect to the server)
Ftp::Response Resp = myFtp.SendCommand("PASV");
if (Resp.IsOk())
{
// Extract the connection address and port from the response
std::string::size_type begin = Resp.GetMessage().find_first_of("0123456789");
if (begin != std::string::npos)
{
sf::Uint8 Data[6] = {0, 0, 0, 0, 0, 0};
std::string Str = Resp.GetMessage().substr(begin);
std::size_t Index = 0;
for (int i = 0; i < 6; ++i)
{
// Extract the current number
while (isdigit(Str[Index]))
{
Data[i] = Data[i] * 10 + (Str[Index] - '0');
Index++;
}
// Skip separator
Index++;
}
// Reconstruct connection port and address
unsigned short Port = Data[4] * 256 + Data[5];
sf::IPAddress Address(static_cast<sf::Uint8>(Data[0]),
static_cast<sf::Uint8>(Data[1]),
static_cast<sf::Uint8>(Data[2]),
static_cast<sf::Uint8>(Data[3]));
// Connect the data channel to the server
if (myDataSocket.Connect(Port, Address) == Socket::Done)
{
// Translate the transfer mode to the corresponding FTP parameter
std::string ModeStr;
switch (Mode)
{
case Ftp::Binary : ModeStr = "I"; break;
case Ftp::Ascii : ModeStr = "A"; break;
case Ftp::Ebcdic : ModeStr = "E"; break;
}
// Set the transfer mode
Resp = myFtp.SendCommand("TYPE", ModeStr);
}
else
{
// Failed to connect to the server
Resp = Ftp::Response(Ftp::Response::ConnectionFailed);
}
}
}
return Resp;
}
////////////////////////////////////////////////////////////
/// Receive data on the data channel until it is closed
////////////////////////////////////////////////////////////
void Ftp::DataChannel::Receive(std::vector<char>& Data)
{
// Receive data
Data.clear();
char Buffer[1024];
std::size_t Received;
while (myDataSocket.Receive(Buffer, sizeof(Buffer), Received) == sf::Socket::Done)
{
std::copy(Buffer, Buffer + Received, std::back_inserter(Data));
}
// Close the data socket
myDataSocket.Close();
}
////////////////////////////////////////////////////////////
/// Send data on the data channel
////////////////////////////////////////////////////////////
void Ftp::DataChannel::Send(const std::vector<char>& Data)
{
// Send data
myDataSocket.Send(&Data[0], Data.size());
// Close the data socket
myDataSocket.Close();
}
} // namespace sf

425
Externals/SFML/src/SFML/Network/Http.cpp vendored Normal file
View file

@ -0,0 +1,425 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/Http.hpp>
#include <ctype.h>
#include <sstream>
namespace
{
////////////////////////////////////////////////////////////
// Convenience function to convert a string to lower case
////////////////////////////////////////////////////////////
std::string ToLower(const std::string& Str)
{
std::string Ret = Str;
for (std::string::iterator i = Ret.begin(); i != Ret.end(); ++i)
*i = static_cast<char>(tolower(*i));
return Ret;
}
}
namespace sf
{
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Http::Request::Request(Method RequestMethod, const std::string& URI, const std::string& Body) :
myMethod (RequestMethod),
myURI (URI),
myMajorVersion(1),
myMinorVersion(0),
myBody (Body)
{
}
////////////////////////////////////////////////////////////
/// Set the value of a field; the field is added if it doesn't exist
////////////////////////////////////////////////////////////
void Http::Request::SetField(const std::string& Field, const std::string& Value)
{
myFields[ToLower(Field)] = Value;
}
////////////////////////////////////////////////////////////
/// Set the request method.
/// This parameter is Get by default
////////////////////////////////////////////////////////////
void Http::Request::SetMethod(Http::Request::Method RequestMethod)
{
myMethod = RequestMethod;
}
////////////////////////////////////////////////////////////
/// Set the target URI of the request.
/// This parameter is "/" by default
////////////////////////////////////////////////////////////
void Http::Request::SetURI(const std::string& URI)
{
myURI = URI;
// Make sure it starts with a '/'
if (myURI.empty() || (myURI[0] != '/'))
myURI.insert(0, "/");
}
////////////////////////////////////////////////////////////
/// Set the HTTP version of the request.
/// This parameter is 1.0 by default
////////////////////////////////////////////////////////////
void Http::Request::SetHttpVersion(unsigned int Major, unsigned int Minor)
{
myMajorVersion = Major;
myMinorVersion = Minor;
}
////////////////////////////////////////////////////////////
/// Set the body of the request. This parameter is optional and
/// makes sense only for POST requests.
/// This parameter is empty by default
////////////////////////////////////////////////////////////
void Http::Request::SetBody(const std::string& Body)
{
myBody = Body;
}
////////////////////////////////////////////////////////////
/// Get the string representation of a request header
////////////////////////////////////////////////////////////
std::string Http::Request::ToString() const
{
std::ostringstream Out;
// Convert the method to its string representation
std::string RequestMethod;
switch (myMethod)
{
default :
case Get : RequestMethod = "GET"; break;
case Post : RequestMethod = "POST"; break;
case Head : RequestMethod = "HEAD"; break;
}
// Write the first line containing the request type
Out << RequestMethod << " " << myURI << " ";
Out << "HTTP/" << myMajorVersion << "." << myMinorVersion << "\r\n";
// Write fields
for (FieldTable::const_iterator i = myFields.begin(); i != myFields.end(); ++i)
{
Out << i->first << ": " << i->second << "\r\n";
}
// Use an extra \r\n to separate the header from the body
Out << "\r\n";
// Add the body
Out << myBody;
return Out.str();
}
////////////////////////////////////////////////////////////
/// Check if the given field has been defined
////////////////////////////////////////////////////////////
bool Http::Request::HasField(const std::string& Field) const
{
return myFields.find(Field) != myFields.end();
}
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Http::Response::Response() :
myStatus (ConnectionFailed),
myMajorVersion(0),
myMinorVersion(0)
{
}
////////////////////////////////////////////////////////////
/// Get the value of a field
////////////////////////////////////////////////////////////
const std::string& Http::Response::GetField(const std::string& Field) const
{
FieldTable::const_iterator It = myFields.find(Field);
if (It != myFields.end())
{
return It->second;
}
else
{
static const std::string Empty = "";
return Empty;
}
}
////////////////////////////////////////////////////////////
/// Get the header's status code
////////////////////////////////////////////////////////////
Http::Response::Status Http::Response::GetStatus() const
{
return myStatus;
}
////////////////////////////////////////////////////////////
/// Get the major HTTP version number of the response
////////////////////////////////////////////////////////////
unsigned int Http::Response::GetMajorHttpVersion() const
{
return myMajorVersion;
}
////////////////////////////////////////////////////////////
/// Get the major HTTP version number of the response
////////////////////////////////////////////////////////////
unsigned int Http::Response::GetMinorHttpVersion() const
{
return myMinorVersion;
}
////////////////////////////////////////////////////////////
/// Get the body of the response. The body can contain :
/// - the requested page (for GET requests)
/// - a response from the server (for POST requests)
/// - nothing (for HEAD requests)
/// - an error message (in case of an error)
////////////////////////////////////////////////////////////
const std::string& Http::Response::GetBody() const
{
return myBody;
}
////////////////////////////////////////////////////////////
/// Construct the header from a response string
////////////////////////////////////////////////////////////
void Http::Response::FromString(const std::string& Data)
{
std::istringstream In(Data);
// Extract the HTTP version from the first line
std::string Version;
if (In >> Version)
{
if ((Version.size() >= 8) && (Version[6] == '.') &&
(ToLower(Version.substr(0, 5)) == "http/") &&
isdigit(Version[5]) && isdigit(Version[7]))
{
myMajorVersion = Version[5] - '0';
myMinorVersion = Version[7] - '0';
}
else
{
// Invalid HTTP version
myStatus = InvalidResponse;
return;
}
}
// Extract the status code from the first line
int StatusCode;
if (In >> StatusCode)
{
myStatus = static_cast<Status>(StatusCode);
}
else
{
// Invalid status code
myStatus = InvalidResponse;
return;
}
// Ignore the end of the first line
In.ignore(10000, '\n');
// Parse the other lines, which contain fields, one by one
std::string Line;
while (std::getline(In, Line) && (Line.size() > 2))
{
std::string::size_type Pos = Line.find(": ");
if (Pos != std::string::npos)
{
// Extract the field name and its value
std::string Field = Line.substr(0, Pos);
std::string Value = Line.substr(Pos + 2);
// Remove any trailing \r
if (!Value.empty() && (*Value.rbegin() == '\r'))
Value.erase(Value.size() - 1);
// Add the field
myFields[ToLower(Field)] = Value;
}
}
// Finally extract the body
myBody.clear();
while (std::getline(In, Line))
myBody += Line + "\n";
}
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Http::Http() :
myHost(),
myPort(0)
{
}
////////////////////////////////////////////////////////////
/// Construct the Http instance with the target host
////////////////////////////////////////////////////////////
Http::Http(const std::string& Host, unsigned short Port)
{
SetHost(Host, Port);
}
////////////////////////////////////////////////////////////
/// Set the target host
////////////////////////////////////////////////////////////
void Http::SetHost(const std::string& Host, unsigned short Port)
{
// Detect the protocol used
std::string Protocol = ToLower(Host.substr(0, 8));
if (Protocol.substr(0, 7) == "http://")
{
// HTTP protocol
myHostName = Host.substr(7);
myPort = (Port != 0 ? Port : 80);
}
else if (Protocol == "https://")
{
// HTTPS protocol
myHostName = Host.substr(8);
myPort = (Port != 0 ? Port : 443);
}
else
{
// Undefined protocol - use HTTP
myHostName = Host;
myPort = (Port != 0 ? Port : 80);
}
// Remove any trailing '/' from the host name
if (!myHostName.empty() && (*myHostName.rbegin() == '/'))
myHostName.erase(myHostName.size() - 1);
myHost = sf::IPAddress(myHostName);
}
////////////////////////////////////////////////////////////
/// Send a HTTP request and return the server's response.
/// You must be connected to a host before sending requests.
/// Any missing mandatory header field will be added with an appropriate value.
/// Warning : this function waits for the server's response and may
/// not return instantly; use a thread if you don't want to block your
/// application.
////////////////////////////////////////////////////////////
Http::Response Http::SendRequest(const Http::Request& Req)
{
// First make sure the request is valid -- add missing mandatory fields
Request ToSend(Req);
if (!ToSend.HasField("From"))
{
ToSend.SetField("From", "user@sfml-dev.org");
}
if (!ToSend.HasField("User-Agent"))
{
ToSend.SetField("User-Agent", "libsfml-network/1.x");
}
if (!ToSend.HasField("Host"))
{
ToSend.SetField("Host", myHostName);
}
if (!ToSend.HasField("Content-Length"))
{
std::ostringstream Out;
Out << ToSend.myBody.size();
ToSend.SetField("Content-Length", Out.str());
}
// Prepare the response
Response Received;
// Connect the socket to the host
if (myConnection.Connect(myPort, myHost) == Socket::Done)
{
// Convert the request to string and send it through the connected socket
std::string RequestStr = ToSend.ToString();
if (!RequestStr.empty())
{
// Send it through the socket
if (myConnection.Send(RequestStr.c_str(), RequestStr.size()) == sf::Socket::Done)
{
// Wait for the server's response
std::string ReceivedStr;
std::size_t Size = 0;
char Buffer[1024];
while (myConnection.Receive(Buffer, sizeof(Buffer), Size) == sf::Socket::Done)
{
ReceivedStr.append(Buffer, Buffer + Size);
}
// Build the Response object from the received data
Received.FromString(ReceivedStr);
}
}
// Close the connection
myConnection.Close();
}
return Received;
}
} // namespace sf

View file

@ -0,0 +1,303 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/IPAddress.hpp>
#include <SFML/Network/Http.hpp>
#include <SFML/Network/SocketHelper.hpp>
#include <string.h>
namespace sf
{
////////////////////////////////////////////////////////////
/// Static member data
////////////////////////////////////////////////////////////
const IPAddress IPAddress::LocalHost("127.0.0.1");
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
IPAddress::IPAddress() :
myAddress(INADDR_NONE)
{
}
////////////////////////////////////////////////////////////
/// Construct the address from a string
////////////////////////////////////////////////////////////
IPAddress::IPAddress(const std::string& Address)
{
// First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
myAddress = inet_addr(Address.c_str());
// If not successful, try to convert it as a host name
if (!IsValid())
{
hostent* Host = gethostbyname(Address.c_str());
if (Host)
{
// Host found, extract its IP address
myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
}
else
{
// Host name not found on the network
myAddress = INADDR_NONE;
}
}
}
////////////////////////////////////////////////////////////
/// Construct the address from a C-style string ;
/// Needed for implicit conversions from literal strings to IPAddress to work
////////////////////////////////////////////////////////////
IPAddress::IPAddress(const char* Address)
{
// First try to convert it as a byte representation ("xxx.xxx.xxx.xxx")
myAddress = inet_addr(Address);
// If not successful, try to convert it as a host name
if (!IsValid())
{
hostent* Host = gethostbyname(Address);
if (Host)
{
// Host found, extract its IP address
myAddress = reinterpret_cast<in_addr*>(Host->h_addr)->s_addr;
}
else
{
// Host name not found on the network
myAddress = INADDR_NONE;
}
}
}
////////////////////////////////////////////////////////////
/// Construct the address from 4 bytes
////////////////////////////////////////////////////////////
IPAddress::IPAddress(Uint8 Byte0, Uint8 Byte1, Uint8 Byte2, Uint8 Byte3)
{
myAddress = htonl((Byte0 << 24) | (Byte1 << 16) | (Byte2 << 8) | Byte3);
}
////////////////////////////////////////////////////////////
/// Construct the address from a 32-bits integer
////////////////////////////////////////////////////////////
IPAddress::IPAddress(Uint32 Address)
{
myAddress = htonl(Address);
}
////////////////////////////////////////////////////////////
/// Tell if the address is a valid one
////////////////////////////////////////////////////////////
bool IPAddress::IsValid() const
{
return myAddress != INADDR_NONE;
}
////////////////////////////////////////////////////////////
/// Get a string representation of the address
////////////////////////////////////////////////////////////
std::string IPAddress::ToString() const
{
in_addr InAddr;
InAddr.s_addr = myAddress;
return inet_ntoa(InAddr);
}
////////////////////////////////////////////////////////////
/// Get an integer representation of the address
////////////////////////////////////////////////////////////
Uint32 IPAddress::ToInteger() const
{
return ntohl(myAddress);
}
////////////////////////////////////////////////////////////
/// Get the computer's local IP address (from the LAN point of view)
////////////////////////////////////////////////////////////
IPAddress IPAddress::GetLocalAddress()
{
// The method here is to connect a UDP socket to anyone (here to localhost),
// and get the local socket address with the getsockname function.
// UDP connection will not send anything to the network, so this function won't cause any overhead
IPAddress LocalAddress;
// Create the socket
SocketHelper::SocketType Socket = socket(PF_INET, SOCK_DGRAM, 0);
if (Socket == SocketHelper::InvalidSocket())
return LocalAddress;
// Build the host address (use a random port)
sockaddr_in SockAddr;
memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
SockAddr.sin_addr.s_addr = INADDR_LOOPBACK;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(4567);
// Connect the socket
if (connect(Socket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
{
SocketHelper::Close(Socket);
return LocalAddress;
}
// Get the local address of the socket connection
SocketHelper::LengthType Size = sizeof(SockAddr);
if (getsockname(Socket, reinterpret_cast<sockaddr*>(&SockAddr), &Size) == -1)
{
SocketHelper::Close(Socket);
return LocalAddress;
}
// Close the socket
SocketHelper::Close(Socket);
// Finally build the IP address
LocalAddress.myAddress = SockAddr.sin_addr.s_addr;
return LocalAddress;
}
////////////////////////////////////////////////////////////
/// Get the computer's public IP address (from the web point of view)
////////////////////////////////////////////////////////////
IPAddress IPAddress::GetPublicAddress()
{
// The trick here is more complicated, because the only way
// to get our public IP address is to get it from a distant computer.
// Here we get the web page from http://www.whatismyip.org
// and parse the result to extract our IP address
// (not very hard : the web page contains only our IP address)
IPAddress PublicAddress;
// Connect to the web server and get its index page
Http Server("www.whatismyip.org");
Http::Request Request(Http::Request::Get, "/");
Http::Response Page = Server.SendRequest(Request);
// If the request was successful, we can extract
// the address from the body of the web page
if (Page.GetStatus() == Http::Response::Ok)
PublicAddress = Page.GetBody();
return PublicAddress;
}
////////////////////////////////////////////////////////////
/// Comparison operator ==
////////////////////////////////////////////////////////////
bool IPAddress::operator ==(const IPAddress& Other) const
{
return myAddress == Other.myAddress;
}
////////////////////////////////////////////////////////////
/// Comparison operator !=
////////////////////////////////////////////////////////////
bool IPAddress::operator !=(const IPAddress& Other) const
{
return myAddress != Other.myAddress;
}
////////////////////////////////////////////////////////////
/// Comparison operator <
////////////////////////////////////////////////////////////
bool IPAddress::operator <(const IPAddress& Other) const
{
return myAddress < Other.myAddress;
}
////////////////////////////////////////////////////////////
/// Comparison operator >
////////////////////////////////////////////////////////////
bool IPAddress::operator >(const IPAddress& Other) const
{
return myAddress > Other.myAddress;
}
////////////////////////////////////////////////////////////
/// Comparison operator <=
////////////////////////////////////////////////////////////
bool IPAddress::operator <=(const IPAddress& Other) const
{
return myAddress <= Other.myAddress;
}
////////////////////////////////////////////////////////////
/// Comparison operator >=
////////////////////////////////////////////////////////////
bool IPAddress::operator >=(const IPAddress& Other) const
{
return myAddress >= Other.myAddress;
}
////////////////////////////////////////////////////////////
/// Operator >> overload to extract an address from an input stream
////////////////////////////////////////////////////////////
std::istream& operator >>(std::istream& Stream, IPAddress& Address)
{
std::string Str;
Stream >> Str;
Address = IPAddress(Str);
return Stream;
}
////////////////////////////////////////////////////////////
/// Operator << overload to print an address to an output stream
////////////////////////////////////////////////////////////
std::ostream& operator <<(std::ostream& Stream, const IPAddress& Address)
{
return Stream << Address.ToString();
}
} // namespace sf

View file

@ -0,0 +1,426 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/Packet.hpp>
#include <SFML/Network/SocketHelper.hpp>
#include <string.h>
namespace sf
{
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Packet::Packet() :
myReadPos(0),
myIsValid(true)
{
}
////////////////////////////////////////////////////////////
/// Virtual destructor
////////////////////////////////////////////////////////////
Packet::~Packet()
{
}
////////////////////////////////////////////////////////////
/// Append data to the end of the packet
////////////////////////////////////////////////////////////
void Packet::Append(const void* Data, std::size_t SizeInBytes)
{
if (Data && (SizeInBytes > 0))
{
std::size_t Start = myData.size();
myData.resize(Start + SizeInBytes);
memcpy(&myData[Start], Data, SizeInBytes);
}
}
////////////////////////////////////////////////////////////
/// Clear the packet data
////////////////////////////////////////////////////////////
void Packet::Clear()
{
myData.clear();
myReadPos = 0;
myIsValid = true;
}
////////////////////////////////////////////////////////////
/// Get a pointer to the data contained in the packet
/// Warning : the returned pointer may be invalid after you
/// append data to the packet
////////////////////////////////////////////////////////////
const char* Packet::GetData() const
{
return !myData.empty() ? &myData[0] : NULL;
}
////////////////////////////////////////////////////////////
/// Get the size of the data contained in the packet
////////////////////////////////////////////////////////////
std::size_t Packet::GetDataSize() const
{
return myData.size();
}
////////////////////////////////////////////////////////////
/// Tell if the reading position has reached the end of the packet
////////////////////////////////////////////////////////////
bool Packet::EndOfPacket() const
{
return myReadPos >= myData.size();
}
////////////////////////////////////////////////////////////
/// Tell if the packet is valid for reading
////////////////////////////////////////////////////////////
Packet::operator bool() const
{
return myIsValid;
}
////////////////////////////////////////////////////////////
/// Operator >> overloads to extract data from the packet
////////////////////////////////////////////////////////////
Packet& Packet::operator >>(bool& Data)
{
Uint8 Value;
if (*this >> Value)
Data = (Value != 0);
return *this;
}
Packet& Packet::operator >>(Int8& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = *reinterpret_cast<const Int8*>(GetData() + myReadPos);
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(Uint8& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = *reinterpret_cast<const Uint8*>(GetData() + myReadPos);
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(Int16& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = ntohs(*reinterpret_cast<const Int16*>(GetData() + myReadPos));
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(Uint16& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = ntohs(*reinterpret_cast<const Uint16*>(GetData() + myReadPos));
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(Int32& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = ntohl(*reinterpret_cast<const Int32*>(GetData() + myReadPos));
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(Uint32& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = ntohl(*reinterpret_cast<const Uint32*>(GetData() + myReadPos));
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(float& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = *reinterpret_cast<const float*>(GetData() + myReadPos);
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(double& Data)
{
if (CheckSize(sizeof(Data)))
{
Data = *reinterpret_cast<const double*>(GetData() + myReadPos);
myReadPos += sizeof(Data);
}
return *this;
}
Packet& Packet::operator >>(char* Data)
{
// First extract string length
Uint32 Length;
*this >> Length;
if ((Length > 0) && CheckSize(Length))
{
// Then extract characters
memcpy(Data, GetData() + myReadPos, Length);
Data[Length] = '\0';
// Update reading position
myReadPos += Length;
}
return *this;
}
Packet& Packet::operator >>(std::string& Data)
{
// First extract string length
Uint32 Length;
*this >> Length;
Data.clear();
if ((Length > 0) && CheckSize(Length))
{
// Then extract characters
Data.assign(GetData() + myReadPos, Length);
// Update reading position
myReadPos += Length;
}
return *this;
}
Packet& Packet::operator >>(wchar_t* Data)
{
// First extract string length
Uint32 Length;
*this >> Length;
if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
{
// Then extract characters
for (Uint32 i = 0; i < Length; ++i)
{
Uint32 c;
*this >> c;
Data[i] = static_cast<wchar_t>(c);
}
Data[Length] = L'\0';
}
return *this;
}
Packet& Packet::operator >>(std::wstring& Data)
{
// First extract string length
Uint32 Length;
*this >> Length;
Data.clear();
if ((Length > 0) && CheckSize(Length * sizeof(Int32)))
{
// Then extract characters
for (Uint32 i = 0; i < Length; ++i)
{
Uint32 c;
*this >> c;
Data += static_cast<wchar_t>(c);
}
}
return *this;
}
////////////////////////////////////////////////////////////
/// Operator << overloads to put data into the packet
////////////////////////////////////////////////////////////
Packet& Packet::operator <<(bool Data)
{
*this << static_cast<Uint8>(Data);
return *this;
}
Packet& Packet::operator <<(Int8 Data)
{
Append(&Data, sizeof(Data));
return *this;
}
Packet& Packet::operator <<(Uint8 Data)
{
Append(&Data, sizeof(Data));
return *this;
}
Packet& Packet::operator <<(Int16 Data)
{
Int16 ToWrite = htons(Data);
Append(&ToWrite, sizeof(ToWrite));
return *this;
}
Packet& Packet::operator <<(Uint16 Data)
{
Uint16 ToWrite = htons(Data);
Append(&ToWrite, sizeof(ToWrite));
return *this;
}
Packet& Packet::operator <<(Int32 Data)
{
Int32 ToWrite = htonl(Data);
Append(&ToWrite, sizeof(ToWrite));
return *this;
}
Packet& Packet::operator <<(Uint32 Data)
{
Uint32 ToWrite = htonl(Data);
Append(&ToWrite, sizeof(ToWrite));
return *this;
}
Packet& Packet::operator <<(float Data)
{
Append(&Data, sizeof(Data));
return *this;
}
Packet& Packet::operator <<(double Data)
{
Append(&Data, sizeof(Data));
return *this;
}
Packet& Packet::operator <<(const char* Data)
{
// First insert string length
Uint32 Length = 0;
for (const char* c = Data; *c != '\0'; ++c)
++Length;
*this << Length;
// Then insert characters
Append(Data, Length * sizeof(char));
return *this;
}
Packet& Packet::operator <<(const std::string& Data)
{
// First insert string length
Uint32 Length = static_cast<Uint32>(Data.size());
*this << Length;
// Then insert characters
if (Length > 0)
{
Append(Data.c_str(), Length * sizeof(std::string::value_type));
}
return *this;
}
Packet& Packet::operator <<(const wchar_t* Data)
{
// First insert string length
Uint32 Length = 0;
for (const wchar_t* c = Data; *c != L'\0'; ++c)
++Length;
*this << Length;
// Then insert characters
for (const wchar_t* c = Data; *c != L'\0'; ++c)
*this << static_cast<Int32>(*c);
return *this;
}
Packet& Packet::operator <<(const std::wstring& Data)
{
// First insert string length
Uint32 Length = static_cast<Uint32>(Data.size());
*this << Length;
// Then insert characters
if (Length > 0)
{
for (std::wstring::const_iterator c = Data.begin(); c != Data.end(); ++c)
*this << static_cast<Int32>(*c);
}
return *this;
}
////////////////////////////////////////////////////////////
/// Check if the packet can extract a given size of bytes
////////////////////////////////////////////////////////////
bool Packet::CheckSize(std::size_t Size)
{
myIsValid = myIsValid && (myReadPos + Size <= myData.size());
return myIsValid;
}
////////////////////////////////////////////////////////////
/// Called before the packet is sent to the network
////////////////////////////////////////////////////////////
const char* Packet::OnSend(std::size_t& DataSize)
{
DataSize = GetDataSize();
return GetData();
}
////////////////////////////////////////////////////////////
/// Called after the packet has been received from the network
////////////////////////////////////////////////////////////
void Packet::OnReceive(const char* Data, std::size_t DataSize)
{
Append(Data, DataSize);
}
} // namespace sf

View file

@ -0,0 +1,132 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifdef _MSC_VER
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
#endif
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/SelectorBase.hpp>
namespace sf
{
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
SelectorBase::SelectorBase() :
myMaxSocket(0)
{
Clear();
}
////////////////////////////////////////////////////////////
/// Add a socket to watch
////////////////////////////////////////////////////////////
void SelectorBase::Add(SocketHelper::SocketType Socket)
{
FD_SET(Socket, &mySet);
int Size = static_cast<int>(Socket);
if (Size > myMaxSocket)
myMaxSocket = Size;
}
////////////////////////////////////////////////////////////
/// Remove a socket
////////////////////////////////////////////////////////////
void SelectorBase::Remove(SocketHelper::SocketType Socket)
{
FD_CLR(Socket, &mySet);
}
////////////////////////////////////////////////////////////
/// Remove all sockets
////////////////////////////////////////////////////////////
void SelectorBase::Clear()
{
FD_ZERO(&mySet);
FD_ZERO(&mySetReady);
myMaxSocket = 0;
}
////////////////////////////////////////////////////////////
/// Wait and collect sockets which are ready for reading.
/// This functions will return either when at least one socket
/// is ready, or when the given time is out
////////////////////////////////////////////////////////////
unsigned int SelectorBase::Wait(float Timeout)
{
// Setup the timeout structure
timeval Time;
Time.tv_sec = static_cast<long>(Timeout);
Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
// Prepare the set of sockets to return
mySetReady = mySet;
// Wait until one of the sockets is ready for reading, or timeout is reached
int NbSockets = select(myMaxSocket + 1, &mySetReady, NULL, NULL, Timeout > 0 ? &Time : NULL);
return NbSockets >= 0 ? static_cast<unsigned int>(NbSockets) : 0;
}
////////////////////////////////////////////////////////////
/// After a call to Wait(), get the Index-th socket which is
/// ready for reading. The total number of sockets ready
/// is the integer returned by the previous call to Wait()
////////////////////////////////////////////////////////////
SocketHelper::SocketType SelectorBase::GetSocketReady(unsigned int Index)
{
// The standard FD_xxx interface doesn't define a direct access,
// so we must go through the whole set to find the socket we're looking for
for (int i = 0; i < myMaxSocket + 1; ++i)
{
if (FD_ISSET(i, &mySetReady))
{
// Current socket is ready, but is it the Index-th one ?
if (Index > 0)
{
Index--;
}
else
{
return static_cast<SocketHelper::SocketType>(i);
}
}
}
// Invalid index : return an invalid socket
return SocketHelper::InvalidSocket();
}
} // namespace sf

View file

@ -0,0 +1,490 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/SocketTCP.hpp>
#include <SFML/Network/IPAddress.hpp>
#include <SFML/Network/Packet.hpp>
#include <SFML/Network/SocketHelper.hpp>
#include <algorithm>
#include <iostream>
#include <string.h>
#ifdef _MSC_VER
#pragma warning(disable : 4127) // "conditional expression is constant" generated by the FD_SET macro
#endif
namespace sf
{
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
SocketTCP::SocketTCP()
{
Create(SocketHelper::InvalidSocket());
}
////////////////////////////////////////////////////////////
/// Change the blocking state of the socket
////////////////////////////////////////////////////////////
void SocketTCP::SetBlocking(bool Blocking)
{
// Make sure our socket is valid
if (!IsValid())
Create();
SocketHelper::SetBlocking(mySocket, Blocking);
myIsBlocking = Blocking;
}
////////////////////////////////////////////////////////////
/// Connect to another computer on a specified port
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Connect(unsigned short Port, const IPAddress& HostAddress, float Timeout)
{
// Make sure our socket is valid
if (!IsValid())
Create();
// Build the host address
sockaddr_in SockAddr;
memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
SockAddr.sin_addr.s_addr = inet_addr(HostAddress.ToString().c_str());
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(Port);
if (Timeout <= 0)
{
// ----- We're not using a timeout : just try to connect -----
if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
{
// Failed to connect
return SocketHelper::GetErrorStatus();
}
// Connection succeeded
return Socket::Done;
}
else
{
// ----- We're using a timeout : we'll need a few tricks to make it work -----
// Save the previous blocking state
bool IsBlocking = myIsBlocking;
// Switch to non-blocking to enable our connection timeout
if (IsBlocking)
SetBlocking(false);
// Try to connect to host
if (connect(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) >= 0)
{
// We got instantly connected! (it may no happen a lot...)
return Socket::Done;
}
// Get the error status
Socket::Status Status = SocketHelper::GetErrorStatus();
// If we were in non-blocking mode, return immediatly
if (!IsBlocking)
return Status;
// Otherwise, wait until something happens to our socket (success, timeout or error)
if (Status == Socket::NotReady)
{
// Setup the selector
fd_set Selector;
FD_ZERO(&Selector);
FD_SET(mySocket, &Selector);
// Setup the timeout
timeval Time;
Time.tv_sec = static_cast<long>(Timeout);
Time.tv_usec = (static_cast<long>(Timeout * 1000) % 1000) * 1000;
// Wait for something to write on our socket (would mean the connection has been accepted)
if (select(static_cast<int>(mySocket + 1), NULL, &Selector, NULL, &Time) > 0)
{
// Connection succeeded
Status = Socket::Done;
}
else
{
// Failed to connect before timeout is over
Status = SocketHelper::GetErrorStatus();
}
}
// Switch back to blocking mode
SetBlocking(true);
return Status;
}
}
////////////////////////////////////////////////////////////
/// Listen to a specified port for incoming data or connections
////////////////////////////////////////////////////////////
bool SocketTCP::Listen(unsigned short Port)
{
// Make sure our socket is valid
if (!IsValid())
Create();
// Build the address
sockaddr_in SockAddr;
memset(SockAddr.sin_zero, 0, sizeof(SockAddr.sin_zero));
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(Port);
// Bind the socket to the specified port
if (bind(mySocket, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr)) == -1)
{
// Not likely to happen, but...
std::cerr << "Failed to bind socket to port " << Port << std::endl;
return false;
}
// Listen to the bound port
if (listen(mySocket, 0) == -1)
{
// Oops, socket is deaf
std::cerr << "Failed to listen to port " << Port << std::endl;
return false;
}
return true;
}
////////////////////////////////////////////////////////////
/// Wait for a connection (must be listening to a port).
/// This function will block if the socket is blocking
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Accept(SocketTCP& Connected, IPAddress* Address)
{
// Address that will be filled with client informations
sockaddr_in ClientAddress;
SocketHelper::LengthType Length = sizeof(ClientAddress);
// Accept a new connection
Connected = accept(mySocket, reinterpret_cast<sockaddr*>(&ClientAddress), &Length);
// Check errors
if (!Connected.IsValid())
{
if (Address)
*Address = IPAddress();
return SocketHelper::GetErrorStatus();
}
// Fill address if requested
if (Address)
*Address = IPAddress(inet_ntoa(ClientAddress.sin_addr));
return Socket::Done;
}
////////////////////////////////////////////////////////////
/// Send an array of bytes to the host (must be connected first)
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Send(const char* Data, std::size_t Size)
{
// First check that socket is valid
if (!IsValid())
return Socket::Error;
// Check parameters
if (Data && Size)
{
// Loop until every byte has been sent
int Sent = 0;
int SizeToSend = static_cast<int>(Size);
for (int Length = 0; Length < SizeToSend; Length += Sent)
{
// Send a chunk of data
Sent = send(mySocket, Data + Length, SizeToSend - Length, 0);
// Check if an error occured
if (Sent <= 0)
return SocketHelper::GetErrorStatus();
}
return Socket::Done;
}
else
{
// Error...
std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
return Socket::Error;
}
}
////////////////////////////////////////////////////////////
/// Receive an array of bytes from the host (must be connected first).
/// This function will block if the socket is blocking
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived)
{
// First clear the size received
SizeReceived = 0;
// Check that socket is valid
if (!IsValid())
return Socket::Error;
// Check parameters
if (Data && MaxSize)
{
// Receive a chunk of bytes
int Received = recv(mySocket, Data, static_cast<int>(MaxSize), 0);
// Check the number of bytes received
if (Received > 0)
{
SizeReceived = static_cast<std::size_t>(Received);
return Socket::Done;
}
else if (Received == 0)
{
return Socket::Disconnected;
}
else
{
return SocketHelper::GetErrorStatus();
}
}
else
{
// Error...
std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
return Socket::Error;
}
}
////////////////////////////////////////////////////////////
/// Send a packet of data to the host (must be connected first)
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Send(Packet& PacketToSend)
{
// Get the data to send from the packet
std::size_t DataSize = 0;
const char* Data = PacketToSend.OnSend(DataSize);
// Send the packet size
Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize));
// Send the packet data
if (PacketSize > 0)
{
return Send(Data, DataSize);
}
else
{
return Socket::Done;
}
}
////////////////////////////////////////////////////////////
/// Receive a packet from the host (must be connected first).
/// This function will block if the socket is blocking
////////////////////////////////////////////////////////////
Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
{
// We start by getting the size of the incoming packet
Uint32 PacketSize = 0;
std::size_t Received = 0;
if (myPendingPacketSize < 0)
{
Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received);
if (Status != Socket::Done)
return Status;
PacketSize = ntohl(PacketSize);
}
else
{
// There is a pending packet : we already know its size
PacketSize = myPendingPacketSize;
}
// Then loop until we receive all the packet data
char Buffer[1024];
while (myPendingPacket.size() < PacketSize)
{
// Receive a chunk of data
std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
Socket::Status Status = Receive(Buffer, SizeToGet, Received);
if (Status != Socket::Done)
{
// We must save the size of the pending packet until we can receive its content
if (Status == Socket::NotReady)
myPendingPacketSize = PacketSize;
return Status;
}
// Append it into the packet
if (Received > 0)
{
myPendingPacket.resize(myPendingPacket.size() + Received);
char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
memcpy(Begin, Buffer, Received);
}
}
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
PacketToReceive.Clear();
if (!myPendingPacket.empty())
PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
myPendingPacket.clear();
myPendingPacketSize = -1;
return Socket::Done;
}
////////////////////////////////////////////////////////////
/// Close the socket
////////////////////////////////////////////////////////////
bool SocketTCP::Close()
{
if (IsValid())
{
if (!SocketHelper::Close(mySocket))
{
std::cerr << "Failed to close socket" << std::endl;
return false;
}
mySocket = SocketHelper::InvalidSocket();
}
myIsBlocking = true;
return true;
}
////////////////////////////////////////////////////////////
/// Check if the socket is in a valid state ; this function
/// can be called any time to check if the socket is OK
////////////////////////////////////////////////////////////
bool SocketTCP::IsValid() const
{
return mySocket != SocketHelper::InvalidSocket();
}
////////////////////////////////////////////////////////////
/// Comparison operator ==
////////////////////////////////////////////////////////////
bool SocketTCP::operator ==(const SocketTCP& Other) const
{
return mySocket == Other.mySocket;
}
////////////////////////////////////////////////////////////
/// Comparison operator !=
////////////////////////////////////////////////////////////
bool SocketTCP::operator !=(const SocketTCP& Other) const
{
return mySocket != Other.mySocket;
}
////////////////////////////////////////////////////////////
/// Comparison operator <.
/// Provided for compatibility with standard containers, as
/// comparing two sockets doesn't make much sense...
////////////////////////////////////////////////////////////
bool SocketTCP::operator <(const SocketTCP& Other) const
{
return mySocket < Other.mySocket;
}
////////////////////////////////////////////////////////////
/// Construct the socket from a socket descriptor
/// (for internal use only)
////////////////////////////////////////////////////////////
SocketTCP::SocketTCP(SocketHelper::SocketType Descriptor)
{
Create(Descriptor);
}
////////////////////////////////////////////////////////////
/// Create the socket
////////////////////////////////////////////////////////////
void SocketTCP::Create(SocketHelper::SocketType Descriptor)
{
// Use the given socket descriptor, or get a new one
mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_STREAM, 0);
myIsBlocking = true;
// Reset the pending packet
myPendingPacket.clear();
myPendingPacketSize = -1;
// Setup default options
if (IsValid())
{
// To avoid the "Address already in use" error message when trying to bind to the same port
int Yes = 1;
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
{
std::cerr << "Failed to set socket option \"SO_REUSEADDR\" ; "
<< "binding to a same port may fail if too fast" << std::endl;
}
// Disable the Nagle algorithm (ie. removes buffering of TCP packets)
if (setsockopt(mySocket, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
{
std::cerr << "Failed to set socket option \"TCP_NODELAY\" ; "
<< "all your TCP packets will be buffered" << std::endl;
}
// Set blocking by default (should always be the case anyway)
SetBlocking(true);
}
}
} // namespace sf

View file

@ -0,0 +1,431 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/SocketUDP.hpp>
#include <SFML/Network/IPAddress.hpp>
#include <SFML/Network/Packet.hpp>
#include <algorithm>
#include <iostream>
#include <string.h>
namespace sf
{
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
SocketUDP::SocketUDP()
{
Create();
}
////////////////////////////////////////////////////////////
/// Change the blocking state of the socket
////////////////////////////////////////////////////////////
void SocketUDP::SetBlocking(bool Blocking)
{
// Make sure our socket is valid
if (!IsValid())
Create();
SocketHelper::SetBlocking(mySocket, Blocking);
myIsBlocking = Blocking;
}
////////////////////////////////////////////////////////////
/// Bind the socket to a specific port
////////////////////////////////////////////////////////////
bool SocketUDP::Bind(unsigned short Port)
{
// Check if the socket is already bound to the specified port
if (myPort != Port)
{
// If the socket was previously bound to another port, we need to recreate it
if (myPort != 0)
{
Close();
Create();
}
if (Port != 0)
{
// Build an address with the specified port
sockaddr_in Addr;
Addr.sin_family = AF_INET;
Addr.sin_port = htons(Port);
Addr.sin_addr.s_addr = INADDR_ANY;
memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero));
// Bind the socket to the port
if (bind(mySocket, reinterpret_cast<sockaddr*>(&Addr), sizeof(Addr)) == -1)
{
std::cerr << "Failed to bind the socket to port " << Port << std::endl;
myPort = 0;
return false;
}
}
// Save the new port
myPort = Port;
}
return true;
}
////////////////////////////////////////////////////////////
/// Unbind the socket to its previous port
////////////////////////////////////////////////////////////
bool SocketUDP::Unbind()
{
// To unbind the socket, we just recreate it
if (myPort != 0)
{
Close();
Create();
myPort = 0;
}
return true;
}
////////////////////////////////////////////////////////////
/// Send an array of bytes
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Send(const char* Data, std::size_t Size, const IPAddress& Address, unsigned short Port)
{
// Make sure the socket is valid
if (!IsValid())
Create();
// Check parameters
if (Data && Size)
{
// Build the target address
sockaddr_in Target;
Target.sin_family = AF_INET;
Target.sin_port = htons(Port);
Target.sin_addr.s_addr = inet_addr(Address.ToString().c_str());
memset(Target.sin_zero, 0, sizeof(Target.sin_zero));
// Loop until every byte has been sent
int Sent = 0;
int SizeToSend = static_cast<int>(Size);
for (int Length = 0; Length < SizeToSend; Length += Sent)
{
// Send a chunk of data
Sent = sendto(mySocket, Data + Length, SizeToSend - Length, 0, reinterpret_cast<sockaddr*>(&Target), sizeof(Target));
// Check errors
if (Sent <= 0)
return SocketHelper::GetErrorStatus();
}
return Socket::Done;
}
else
{
// Error...
std::cerr << "Cannot send data over the network (invalid parameters)" << std::endl;
return Socket::Error;
}
}
////////////////////////////////////////////////////////////
/// Receive an array of bytes.
/// This function will block if the socket is blocking
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Receive(char* Data, std::size_t MaxSize, std::size_t& SizeReceived, IPAddress& Address)
{
// First clear the size received
SizeReceived = 0;
// Make sure the socket is bound to a port
if (myPort == 0)
{
std::cerr << "Failed to receive data ; the UDP socket first needs to be bound to a port" << std::endl;
return Socket::Error;
}
// Make sure the socket is valid
if (!IsValid())
Create();
// Check parameters
if (Data && MaxSize)
{
// Data that will be filled with the other computer's address
sockaddr_in Sender;
Sender.sin_family = AF_INET;
Sender.sin_port = htons(myPort);
Sender.sin_addr.s_addr = INADDR_ANY;
memset(Sender.sin_zero, 0, sizeof(Sender.sin_zero));
SocketHelper::LengthType SenderSize = sizeof(Sender);
// Receive a chunk of bytes
int Received = recvfrom(mySocket, Data, static_cast<int>(MaxSize), 0, reinterpret_cast<sockaddr*>(&Sender), &SenderSize);
// Check the number of bytes received
if (Received > 0)
{
Address = IPAddress(inet_ntoa(Sender.sin_addr));
SizeReceived = static_cast<std::size_t>(Received);
return Socket::Done;
}
else
{
Address = IPAddress();
return Received == 0 ? Socket::Disconnected : SocketHelper::GetErrorStatus();
}
}
else
{
// Error...
std::cerr << "Cannot receive data from the network (invalid parameters)" << std::endl;
return Socket::Error;
}
}
////////////////////////////////////////////////////////////
/// Send a packet of data
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, unsigned short Port)
{
// Get the data to send from the packet
std::size_t DataSize = 0;
const char* Data = PacketToSend.OnSend(DataSize);
// Send the packet size
Uint32 PacketSize = htonl(static_cast<unsigned long>(DataSize));
Send(reinterpret_cast<const char*>(&PacketSize), sizeof(PacketSize), Address, Port);
// Send the packet data
if (PacketSize > 0)
{
return Send(Data, DataSize, Address, Port);
}
else
{
return Socket::Done;
}
}
////////////////////////////////////////////////////////////
/// Receive a packet.
/// This function will block if the socket is blocking
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address)
{
// This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
// So if a packet is split into more than one chunk, nobody knows what could happen...
// Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it.
// We start by getting the size of the incoming packet
Uint32 PacketSize = 0;
std::size_t Received = 0;
if (myPendingPacketSize < 0)
{
Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received, Address);
if (Status != Socket::Done)
return Status;
PacketSize = ntohl(PacketSize);
}
else
{
// There is a pending packet : we already know its size
PacketSize = myPendingPacketSize;
}
// Clear the user packet
PacketToReceive.Clear();
// Use another address instance for receiving the packet data ;
// chunks of data coming from a different sender will be discarded (and lost...)
IPAddress Sender;
// Then loop until we receive all the packet data
char Buffer[1024];
while (myPendingPacket.size() < PacketSize)
{
// Receive a chunk of data
std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer));
Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender);
if (Status != Socket::Done)
{
// We must save the size of the pending packet until we can receive its content
if (Status == Socket::NotReady)
myPendingPacketSize = PacketSize;
return Status;
}
// Append it into the packet
if ((Sender == Address) && (Received > 0))
{
myPendingPacket.resize(myPendingPacket.size() + Received);
char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received;
memcpy(Begin, Buffer, Received);
}
}
// We have received all the datas : we can copy it to the user packet, and clear our internal packet
PacketToReceive.Clear();
if (!myPendingPacket.empty())
PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size());
myPendingPacket.clear();
myPendingPacketSize = -1;
return Socket::Done;
}
////////////////////////////////////////////////////////////
/// Close the socket
////////////////////////////////////////////////////////////
bool SocketUDP::Close()
{
if (IsValid())
{
if (!SocketHelper::Close(mySocket))
{
std::cerr << "Failed to close socket" << std::endl;
return false;
}
mySocket = SocketHelper::InvalidSocket();
}
myPort = 0;
myIsBlocking = true;
return true;
}
////////////////////////////////////////////////////////////
/// Check if the socket is in a valid state ; this function
/// can be called any time to check if the socket is OK
////////////////////////////////////////////////////////////
bool SocketUDP::IsValid() const
{
return mySocket != SocketHelper::InvalidSocket();
}
////////////////////////////////////////////////////////////
/// Get the port the socket is currently bound to
////////////////////////////////////////////////////////////
unsigned short SocketUDP::GetPort() const
{
return myPort;
}
////////////////////////////////////////////////////////////
/// Comparison operator ==
////////////////////////////////////////////////////////////
bool SocketUDP::operator ==(const SocketUDP& Other) const
{
return mySocket == Other.mySocket;
}
////////////////////////////////////////////////////////////
/// Comparison operator !=
////////////////////////////////////////////////////////////
bool SocketUDP::operator !=(const SocketUDP& Other) const
{
return mySocket != Other.mySocket;
}
////////////////////////////////////////////////////////////
/// Comparison operator <.
/// Provided for compatibility with standard containers, as
/// comparing two sockets doesn't make much sense...
////////////////////////////////////////////////////////////
bool SocketUDP::operator <(const SocketUDP& Other) const
{
return mySocket < Other.mySocket;
}
////////////////////////////////////////////////////////////
/// Construct the socket from a socket descriptor
/// (for internal use only)
////////////////////////////////////////////////////////////
SocketUDP::SocketUDP(SocketHelper::SocketType Descriptor)
{
Create(Descriptor);
}
////////////////////////////////////////////////////////////
/// Create the socket
////////////////////////////////////////////////////////////
void SocketUDP::Create(SocketHelper::SocketType Descriptor)
{
// Use the given socket descriptor, or get a new one
mySocket = Descriptor ? Descriptor : socket(PF_INET, SOCK_DGRAM, 0);
myIsBlocking = true;
// Clear the last port used
myPort = 0;
// Reset the pending packet
myPendingPacket.clear();
myPendingPacketSize = -1;
// Setup default options
if (IsValid())
{
// To avoid the "Address already in use" error message when trying to bind to the same port
int Yes = 1;
if (setsockopt(mySocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
{
std::cerr << "Failed to set socket option \"reuse address\" ; "
<< "binding to a same port may fail if too fast" << std::endl;
}
// Enable broadcast by default
if (setsockopt(mySocket, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&Yes), sizeof(Yes)) == -1)
{
std::cerr << "Failed to enable broadcast on UDP socket" << std::endl;
}
// Set blocking by default (should always be the case anyway)
SetBlocking(true);
}
}
} // namespace sf

View file

@ -0,0 +1,83 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/SocketHelper.hpp>
#include <errno.h>
#include <fcntl.h>
namespace sf
{
////////////////////////////////////////////////////////////
/// Return the value of the invalid socket
////////////////////////////////////////////////////////////
SocketHelper::SocketType SocketHelper::InvalidSocket()
{
return -1;
}
////////////////////////////////////////////////////////////
/// Close / destroy a socket
////////////////////////////////////////////////////////////
bool SocketHelper::Close(SocketHelper::SocketType Socket)
{
return close(Socket) != -1;
}
////////////////////////////////////////////////////////////
/// Set a socket as blocking or non-blocking
////////////////////////////////////////////////////////////
void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block)
{
int Status = fcntl(Socket, F_GETFL);
if (Block)
fcntl(Socket, F_SETFL, Status & ~O_NONBLOCK);
else
fcntl(Socket, F_SETFL, Status | O_NONBLOCK);
}
////////////////////////////////////////////////////////////
/// Get the last socket error status
////////////////////////////////////////////////////////////
Socket::Status SocketHelper::GetErrorStatus()
{
switch (errno)
{
case EWOULDBLOCK : return Socket::NotReady;
case ECONNABORTED : return Socket::Disconnected;
case ECONNRESET : return Socket::Disconnected;
case ETIMEDOUT : return Socket::Disconnected;
case ENETRESET : return Socket::Disconnected;
case ENOTCONN : return Socket::Disconnected;
default : return Socket::Error;
}
}
} // namespace sf

View file

@ -0,0 +1,100 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2008 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Network/SocketHelper.hpp>
namespace sf
{
////////////////////////////////////////////////////////////
/// Return the value of the invalid socket
////////////////////////////////////////////////////////////
SocketHelper::SocketType SocketHelper::InvalidSocket()
{
return INVALID_SOCKET;
}
////////////////////////////////////////////////////////////
/// Close / destroy a socket
////////////////////////////////////////////////////////////
bool SocketHelper::Close(SocketHelper::SocketType Socket)
{
return closesocket(Socket) != -1;
}
////////////////////////////////////////////////////////////
/// Set a socket as blocking or non-blocking
////////////////////////////////////////////////////////////
void SocketHelper::SetBlocking(SocketHelper::SocketType Socket, bool Block)
{
unsigned long Blocking = Block ? 0 : 1;
ioctlsocket(Socket, FIONBIO, &Blocking);
}
////////////////////////////////////////////////////////////
/// Get the last socket error status
////////////////////////////////////////////////////////////
Socket::Status SocketHelper::GetErrorStatus()
{
switch (WSAGetLastError())
{
case WSAEWOULDBLOCK : return Socket::NotReady;
case WSAECONNABORTED : return Socket::Disconnected;
case WSAECONNRESET : return Socket::Disconnected;
case WSAETIMEDOUT : return Socket::Disconnected;
case WSAENETRESET : return Socket::Disconnected;
case WSAENOTCONN : return Socket::Disconnected;
default : return Socket::Error;
}
}
////////////////////////////////////////////////////////////
// Windows needs some initialization and cleanup to get
// sockets working properly... so let's create a class that will
// do it automatically
////////////////////////////////////////////////////////////
struct SocketInitializer
{
SocketInitializer()
{
WSADATA InitData;
WSAStartup(MAKEWORD(2,2), &InitData);
}
~SocketInitializer()
{
WSACleanup();
}
};
SocketInitializer GlobalInitializer;
} // namespace sf