1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Initial implementation of basic TCP/UDP sockets.

This commit is contained in:
Sandu Liviu Catalin 2020-04-20 04:46:05 +03:00
parent 8a927419c2
commit 5393b62892
20 changed files with 4533 additions and 6 deletions

View File

@ -16,7 +16,7 @@ if(CMAKE_VERSION VERSION_LESS "3.1")
endif() endif()
else() else()
# Apparently the above does not work with cmake from on debian 8 # Apparently the above does not work with cmake from on debian 8
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
# Try the standard method as well # Try the standard method as well
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)

View File

@ -284,7 +284,7 @@ public:
, m_Mem(MemRef::Get()) , m_Mem(MemRef::Get())
{ {
Request(size < 8 ? 8 : size); Request(size < 8 ? 8 : size);
m_Cur += Write(m_Cur, data, size); Write(m_Cur, data, size);
Move(pos); Move(pos);
} }

View File

@ -46,6 +46,7 @@ add_library(SqModule MODULE
Library/Numeric/LongInt.cpp Library/Numeric/LongInt.hpp Library/Numeric/LongInt.cpp Library/Numeric/LongInt.hpp
Library/Numeric/Math.cpp Library/Numeric/Math.hpp Library/Numeric/Math.cpp Library/Numeric/Math.hpp
Library/Numeric/Random.cpp Library/Numeric/Random.hpp Library/Numeric/Random.cpp Library/Numeric/Random.hpp
Library/Socket.cpp Library/Socket.hpp
Library/SQLite.cpp Library/SQLite.hpp Library/SQLite.cpp Library/SQLite.hpp
Library/String.cpp Library/String.hpp Library/String.cpp Library/String.hpp
Library/System.cpp Library/System.hpp Library/System.cpp Library/System.hpp
@ -74,7 +75,7 @@ add_library(SqModule MODULE
# Link to base libraries # Link to base libraries
target_link_libraries(SqModule VCMP Squirrel Sqrat SqSDK) target_link_libraries(SqModule VCMP Squirrel Sqrat SqSDK)
# Link to third-party libraries # Link to third-party libraries
target_link_libraries(SqModule SimpleINI HashLib B64Lib AES256Lib WhirlpoolLib TinyDir PUGIXML SQLite MaxmindDB) target_link_libraries(SqModule SimpleINI HashLib B64Lib AES256Lib WhirlpoolLib TinyDir PUGIXML SQLite MaxmindDB SimpleSocket)
# Link to mysql client library # Link to mysql client library
if(ENABLE_MYSQL) if(ENABLE_MYSQL)
# Include the implementation # Include the implementation

View File

@ -367,7 +367,6 @@ bool Core::Initialize()
InitializeRoutines(); InitializeRoutines();
InitializeTasks(); InitializeTasks();
// Initialize third-party // Initialize third-party
// Initialization successful // Initialization successful
return true; return true;
@ -476,7 +475,7 @@ void Core::Terminate(bool shutdown)
const ContainerCleaner cc_keybinds(m_Keybinds, ENT_KEYBIND, !shutdown); const ContainerCleaner cc_keybinds(m_Keybinds, ENT_KEYBIND, !shutdown);
cLogDbg(m_Verbosity >= 1, "Terminating routines an commands"); cLogDbg(m_Verbosity >= 1, "Terminating routines an commands");
// Release third-party // Release third-party
// Release all resources from routines and tasks // Release all resources from routines and tasks
TerminateRoutines(); TerminateRoutines();
TerminateTasks(); TerminateTasks();

180
module/Library/Socket.cpp Normal file
View File

@ -0,0 +1,180 @@
// ------------------------------------------------------------------------------------------------
#include "Library/Socket.hpp"
#include "Misc/Signal.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMODE_DECL_TYPENAME(SimpleSocketTypename, _SC("SimpleSocket"))
SQMODE_DECL_TYPENAME(PassiveSocketTypename, _SC("PassiveSocket"))
SQMODE_DECL_TYPENAME(ActiveSocketTypename, _SC("ActiveSocket"))
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SimpleSocket::Validate(CCStr file, Int32 line) const
{
if (!m_Socket)
{
SqThrowF("Invalid socket reference =>[%s:%d]", file, line);
}
}
#else
void SimpleSocket::Validate() const
{
if (!m_Socket)
{
SqThrowF("Invalid socket reference");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
LightObj PassiveSocket::Accept()
{
SQMOD_VALIDATE(*this);
// Forward the request and store the returned instance
CActiveSocket * socket = Get()->Accept();
// Was there a socket returned?
if (socket)
{
// Return an object with the new socket instance
return LightObj(SqTypeIdentity< ActiveSocket >{}, SqVM(), socket);
}
// Return a null object
return LightObj{};
}
// ================================================================================================
void Register_Socket(HSQUIRRELVM vm)
{
Table skns(vm);
skns.Bind(_SC("Simple"),
Class< SimpleSocket, NoConstructor< SimpleSocket > >(vm, SimpleSocketTypename::Str)
// Properties
.Prop(_SC("IsValid"), &SimpleSocket::IsSocketValid)
.Prop(_SC("ErrorDescription"), &SimpleSocket::DescribeError)
.Prop(_SC("NonBlocking"), &SimpleSocket::IsNonBlocking)
.Prop(_SC("Data"), &SimpleSocket::GetData)
.Prop(_SC("BytesReceived"), &SimpleSocket::GetBytesReceived)
.Prop(_SC("BytesSent"), &SimpleSocket::GetBytesSent)
.Prop(_SC("ConnectTimeoutSec"), &SimpleSocket::GetConnectTimeoutSec)
.Prop(_SC("ConnectTimeoutUSec"), &SimpleSocket::GetConnectTimeoutUSec)
.Prop(_SC("ReceiveTimeoutSec"), &SimpleSocket::GetReceiveTimeoutSec)
.Prop(_SC("ReceiveTimeoutUSec"), &SimpleSocket::GetReceiveTimeoutUSec)
.Prop(_SC("Multicast"), &SimpleSocket::GetMulticast, &SimpleSocket::SetMulticast)
.Prop(_SC("SendTimeoutSec"), &SimpleSocket::GetSendTimeoutSec)
.Prop(_SC("SendTimeoutUSec"), &SimpleSocket::GetSendTimeoutUSec)
.Prop(_SC("SocketError"), &SimpleSocket::GetSocketError)
.Prop(_SC("TotalTimeMs"), &SimpleSocket::GetTotalTimeMs)
.Prop(_SC("TotalTimeUsec"), &SimpleSocket::GetTotalTimeUsec)
.Prop(_SC("SocketDSCP"), &SimpleSocket::GetSocketDSCP, &SimpleSocket::SetSocketDSCP)
.Prop(_SC("SocketType"), &SimpleSocket::GetSocketType)
.Prop(_SC("ClientAddr"), &SimpleSocket::GetClientAddr)
.Prop(_SC("ClientPort"), &SimpleSocket::GetClientPort)
.Prop(_SC("ServerAddr"), &SimpleSocket::GetServerAddr)
.Prop(_SC("ServerPort"), &SimpleSocket::GetServerPort)
.Prop(_SC("ReceiveWindowSize"), &SimpleSocket::GetReceiveWindowSize, &SimpleSocket::SetReceiveWindowSize)
.Prop(_SC("SendWindowSize"), &SimpleSocket::GetSendWindowSize, &SimpleSocket::SetSendWindowSize)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &SimpleSocketTypename::Fn)
// Member Methods
.Func(_SC("Initialize"), &SimpleSocket::Initialize)
.Func(_SC("Close"), &SimpleSocket::Close)
.Func(_SC("Shutdown"), &SimpleSocket::Shutdown)
.Func(_SC("Select"), &SimpleSocket::Select)
.Func(_SC("SelectEx"), &SimpleSocket::SelectEx)
.Func(_SC("TranslateSocketError"), &SimpleSocket::TranslateSocketError)
.Func(_SC("DescribeError"), &SimpleSocket::DescribeError)
.Func(_SC("Receive"), &SimpleSocket::Receive)
.Func(_SC("ReceiveInto"), &SimpleSocket::ReceiveInto)
.Func(_SC("Send"), &SimpleSocket::Send)
.Func(_SC("SendFile"), &SimpleSocket::SendFile)
.Func(_SC("SetBlocking"), &SimpleSocket::SetBlocking)
.Func(_SC("SetNonBlocking"), &SimpleSocket::SetNonBlocking)
.Func(_SC("SetOptionLinger"), &SimpleSocket::SetOptionLinger)
.Func(_SC("SetOptionReuseAddr"), &SimpleSocket::SetOptionReuseAddr)
.Func(_SC("SetConnectTimeout"), &SimpleSocket::SetConnectTimeout)
.Func(_SC("SetReceiveTimeout"), &SimpleSocket::SetReceiveTimeout)
.Func(_SC("SetMulticast"), &SimpleSocket::SetMulticastEx)
.FmtFunc(_SC("BindInterface"), &SimpleSocket::BindInterface)
.Func(_SC("SetSendTimeout"), &SimpleSocket::SetSendTimeout)
.Func(_SC("SetSocketDSCP"), &SimpleSocket::SetSocketDSCPEx)
.Func(_SC("SetReceiveWindowSize"), &SimpleSocket::SetReceiveWindowSize)
.Func(_SC("SetSendWindowSize"), &SimpleSocket::SetSendWindowSize)
.Func(_SC("DisableNagleAlgoritm"), &SimpleSocket::DisableNagleAlgoritm)
.Func(_SC("EnableNagleAlgoritm"), &SimpleSocket::EnableNagleAlgoritm)
// Static Member Methods
.StaticFunc(_SC("DescribeErrorCode"), &SimpleSocket::DescribeErrorCode)
);
skns.Bind(_SC("Passive"),
DerivedClass< PassiveSocket, SimpleSocket, NoCopy< PassiveSocket > >(vm, PassiveSocketTypename::Str)
// Constructors
.Ctor()
.Ctor< int >()
// Meta-methods
.SquirrelFunc(_SC("_typename"), &PassiveSocketTypename::Fn)
.Func(_SC("_tostring"), &PassiveSocket::ToString)
// Member Methods
.Func(_SC("Accept"), &PassiveSocket::Accept)
.Func(_SC("BindMulticast"), &PassiveSocket::BindMulticast)
.FmtFunc(_SC("Listen"), &PassiveSocket::Listen)
.FmtFunc(_SC("ListenEx"), &PassiveSocket::ListenEx)
.FmtFunc(_SC("SendStr"), &PassiveSocket::SendStr)
);
skns.Bind(_SC("Active"),
DerivedClass< ActiveSocket, SimpleSocket, NoCopy< ActiveSocket > >(vm, ActiveSocketTypename::Str)
// Constructors
.Ctor()
.Ctor< int >()
// Meta-methods
.SquirrelFunc(_SC("_typename"), &ActiveSocketTypename::Fn)
.Func(_SC("_tostring"), &ActiveSocket::ToString)
// Member Methods
.Func(_SC("Open"), &ActiveSocket::Open)
.FmtFunc(_SC("SendStr"), &ActiveSocket::SendStr)
);
RootTable(vm).Bind(_SC("SqSocket"), skns);
ConstTable(vm).Enum(_SC("SqSocketType"), Enumeration(vm)
.Const(_SC("Invalid"), static_cast< SQInteger >(CSimpleSocket::SocketTypeInvalid))
.Const(_SC("TCP"), static_cast< SQInteger >(CSimpleSocket::SocketTypeTcp))
.Const(_SC("UDP"), static_cast< SQInteger >(CSimpleSocket::SocketTypeUdp))
.Const(_SC("TCP6"), static_cast< SQInteger >(CSimpleSocket::SocketTypeTcp6))
.Const(_SC("UDP6"), static_cast< SQInteger >(CSimpleSocket::SocketTypeUdp6))
.Const(_SC("Raw"), static_cast< SQInteger >(CSimpleSocket::SocketTypeRaw))
);
ConstTable(vm).Enum(_SC("SqSocketError"), Enumeration(vm)
.Const(_SC("Error"), static_cast< SQInteger >(CSimpleSocket::SocketError))
.Const(_SC("Success"), static_cast< SQInteger >(CSimpleSocket::SocketSuccess))
.Const(_SC("InvalidSocket"), static_cast< SQInteger >(CSimpleSocket::SocketInvalidSocket))
.Const(_SC("InvalidAddress"), static_cast< SQInteger >(CSimpleSocket::SocketInvalidAddress))
.Const(_SC("InvalidPort"), static_cast< SQInteger >(CSimpleSocket::SocketInvalidPort))
.Const(_SC("ConnectionRefused"), static_cast< SQInteger >(CSimpleSocket::SocketConnectionRefused))
.Const(_SC("Timedout"), static_cast< SQInteger >(CSimpleSocket::SocketTimedout))
.Const(_SC("Ewouldblock"), static_cast< SQInteger >(CSimpleSocket::SocketEwouldblock))
.Const(_SC("Notconnected"), static_cast< SQInteger >(CSimpleSocket::SocketNotconnected))
.Const(_SC("Einprogress"), static_cast< SQInteger >(CSimpleSocket::SocketEinprogress))
.Const(_SC("Interrupted"), static_cast< SQInteger >(CSimpleSocket::SocketInterrupted))
.Const(_SC("ConnectionAborted"), static_cast< SQInteger >(CSimpleSocket::SocketConnectionAborted))
.Const(_SC("ProtocolError"), static_cast< SQInteger >(CSimpleSocket::SocketProtocolError))
.Const(_SC("FirewallError"), static_cast< SQInteger >(CSimpleSocket::SocketFirewallError))
.Const(_SC("InvalidSocketBuffer"), static_cast< SQInteger >(CSimpleSocket::SocketInvalidSocketBuffer))
.Const(_SC("ConnectionReset"), static_cast< SQInteger >(CSimpleSocket::SocketConnectionReset))
.Const(_SC("AddressInUse"), static_cast< SQInteger >(CSimpleSocket::SocketAddressInUse))
.Const(_SC("InvalidPointer"), static_cast< SQInteger >(CSimpleSocket::SocketInvalidPointer))
.Const(_SC("Eunknown"), static_cast< SQInteger >(CSimpleSocket::SocketEunknown))
);
ConstTable(vm).Enum(_SC("SqSocketShutdownMode"), Enumeration(vm)
.Const(_SC("Receives"), static_cast< SQInteger >(CSimpleSocket::Receives))
.Const(_SC("Sends"), static_cast< SQInteger >(CSimpleSocket::Sends))
.Const(_SC("Both"), static_cast< SQInteger >(CSimpleSocket::Both))
);
}
} // Namespace:: SqMod

700
module/Library/Socket.hpp Normal file
View File

@ -0,0 +1,700 @@
#pragma once
// ------------------------------------------------------------------------------------------------
#include "Base/Shared.hpp"
#include "Library/Utils/Buffer.hpp"
#include "Library/Numeric/LongInt.hpp"
// ------------------------------------------------------------------------------------------------
#include <PassiveSocket.h>
#include <ActiveSocket.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Handle validation.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
#define SQMOD_VALIDATE(x) (x).Validate(__FILE__, __LINE__)
#else
#define SQMOD_VALIDATE(x) (x).Validate()
#endif // _DEBUG
/* ------------------------------------------------------------------------------------------------
* Provides a platform independent class to for socket development. This class is designed
* to abstract socket communication development in a platform independent manner.
*/
class SimpleSocket
{
protected:
/* --------------------------------------------------------------------------------------------
* The managed socket instance.
*/
CSimpleSocket * m_Socket;
/* --------------------------------------------------------------------------------------------
* Default constructor. Initializes everything to null.
*/
SimpleSocket() : m_Socket(nullptr) { }
/* --------------------------------------------------------------------------------------------
* Explicit constructor. Initializes with the given socket instance.
*/
explicit SimpleSocket(CSimpleSocket * socket)
: m_Socket(socket)
{
if (!socket)
{
STHROWF("Invalid socket instance.");
}
}
/* --------------------------------------------------------------------------------------------
* Destructor constructor.
*/
virtual ~SimpleSocket()
{
// Close the socket
if (m_Socket && m_Socket->IsSocketValid())
{
m_Socket->Close();
}
// Delete the managed socket (`delete` checks for NULL)
delete m_Socket;
}
/* --------------------------------------------------------------------------------------------
* Validate the managed connection handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Validate(CCStr file, Int32 line) const;
#else
void Validate() const;
#endif // _DEBUG
public:
/* --------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
SimpleSocket(const SimpleSocket &) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
SimpleSocket(SimpleSocket &&) = delete;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
SimpleSocket & operator = (const SimpleSocket &) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
SimpleSocket & operator = (SimpleSocket &&) = delete;
/* --------------------------------------------------------------------------------------------
* Initialize instance of CSocket. This method MUST be called before an object can be used.
*/
bool Initialize()
{
SQMOD_VALIDATE(*this);
return m_Socket->Initialize();
}
/* --------------------------------------------------------------------------------------------
* Close the managed socket.
*/
bool Close()
{
SQMOD_VALIDATE(*this);
return m_Socket->Close();
}
/* --------------------------------------------------------------------------------------------
* Shutdown the managed socket with various send and receive operations.
*/
bool Shutdown(SQInteger mode)
{
SQMOD_VALIDATE(*this);
return m_Socket->Shutdown(static_cast< CSimpleSocket::CShutdownMode >(mode));
}
/* --------------------------------------------------------------------------------------------
* Examine the socket descriptor sets currently owned by the instance of the socket class
* (the readfds, writefds, and errorfds parameters) to see whether some of their descriptors
* are ready for reading, are ready for writing, or have an exceptional condition pending, respectively.
* Block until an event happens on the specified file descriptors.
*/
bool Select()
{
SQMOD_VALIDATE(*this);
return m_Socket->Select();
}
/* --------------------------------------------------------------------------------------------
* Examine the socket descriptor sets currently owned by the instance of the socket class
* (the readfds, writefds, and errorfds parameters) to see whether some of their descriptors
* are ready for reading, are ready for writing, or have an exceptional condition pending, respectively.
*/
bool SelectEx(SQInteger timeout_sec, SQInteger timeout_usec)
{
SQMOD_VALIDATE(*this);
return m_Socket->Select(static_cast< Int32 >(timeout_sec), static_cast< Int32 >(timeout_usec));
}
/* --------------------------------------------------------------------------------------------
* Does the current instance of the socket object contain a valid socket descriptor.
*/
bool IsSocketValid()
{
SQMOD_VALIDATE(*this);
return m_Socket->IsSocketValid();
}
/* --------------------------------------------------------------------------------------------
* Provides a standard error code for cross platform development by mapping the
* operating system error to an error defined by the CSocket class.
*/
void TranslateSocketError()
{
SQMOD_VALIDATE(*this);
m_Socket->TranslateSocketError();
}
/* --------------------------------------------------------------------------------------------
* Returns a human-readable description of the given error code or the last error code of a socket.
*/
LightObj DescribeError()
{
SQMOD_VALIDATE(*this);
return LightObj(m_Socket->DescribeError(), -1);
}
/* --------------------------------------------------------------------------------------------
* Returns a human-readable description of the given error code or the last error code of a socket.
*/
static LightObj DescribeErrorCode(SQInteger err)
{
return LightObj(CSimpleSocket::DescribeError(static_cast< CSimpleSocket::CSocketError >(err)), -1);
}
/* --------------------------------------------------------------------------------------------
* Attempts to receive a block of data on an established connection. Buffer cursor is not affected!
*/
SQInteger Receive(Buffer::SzType max_bytes)
{
SQMOD_VALIDATE(*this);
// Now the call can be forwarded
return m_Socket->Receive(max_bytes, nullptr);
}
/* --------------------------------------------------------------------------------------------
* Attempts to receive a block of data on an established connection. Buffer cursor is not affected!
*/
SQInteger ReceiveInto(Buffer::SzType max_bytes, SqBuffer & out)
{
SQMOD_VALIDATE(*this);
// Make sure there is enough space in the buffer
if (max_bytes > out.GetRef()->Capacity())
{
out.GetRef()->Adjust(max_bytes); // We don't keep old data!
}
// Now the call can be forwarded
return m_Socket->Receive(max_bytes, out.GetRef()->Get< Uint8 >());
}
/* --------------------------------------------------------------------------------------------
* Attempts to send a block of data on an established connection.. Buffer cursor is not affected!
*/
SQInteger Send(SqBuffer & in, Buffer::SzType bytes_to_send)
{
SQMOD_VALIDATE(*this);
// Make sure there is enough data in the buffer
if (bytes_to_send > in.GetRef()->Capacity())
{
STHROWF("Not enough data in the buffer");
}
// Now the call can be forwarded
return m_Socket->Send(in.GetRef()->Get< Uint8 >(), bytes_to_send);
}
/* --------------------------------------------------------------------------------------------
* Copies data between one file descriptor and another.
*/
SQInteger SendFile(Int32 out_fd, Int32 in_fd, SLongInt & offset, Int32 count)
{
SQMOD_VALIDATE(*this);
// Create a native offset
off_t native_offset = ConvTo< off_t >::From(offset.GetNum());
// Forward the call and save the result
auto r = m_Socket->SendFile(out_fd, in_fd, &native_offset, count);
// Translate the native offset back to the wrapper
offset.SetNum(native_offset);
// Return back the result
return r;
}
/* --------------------------------------------------------------------------------------------
* Returns blocking/non-blocking state of socket.
*/
bool IsNonBlocking()
{
SQMOD_VALIDATE(*this);
return m_Socket->IsNonblocking();
}
/* --------------------------------------------------------------------------------------------
* Set the socket to blocking.
*/
bool SetBlocking()
{
SQMOD_VALIDATE(*this);
return m_Socket->SetBlocking();
}
/* --------------------------------------------------------------------------------------------
* Set the socket as non-blocking.
*/
bool SetNonBlocking()
{
SQMOD_VALIDATE(*this);
return m_Socket->SetNonblocking();
}
/* --------------------------------------------------------------------------------------------
* Returns a copy of the internal buffer used to receive data. Very ineffective. Use carefully.
*/
SqBuffer GetData()
{
SQMOD_VALIDATE(*this);
return SqBuffer(reinterpret_cast< Buffer::ConstPtr >(m_Socket->GetData()),
static_cast< Buffer::SzType >(m_Socket->GetBytesReceived()), 0);
}
/* --------------------------------------------------------------------------------------------
* Returns the number of bytes received on the last call to SimpleSocket::Receive().
*/
SQInteger GetBytesReceived()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetBytesReceived();
}
/* --------------------------------------------------------------------------------------------
* Returns the number of bytes sent on the last call to SimpleSocket::Send().
*/
SQInteger GetBytesSent()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetBytesSent();
}
/* --------------------------------------------------------------------------------------------
* Controls the actions taken when CSimpleSocket::Close is executed on a socket object that has unsent data.
*/
bool SetOptionLinger(bool toggle, SQInteger time)
{
SQMOD_VALIDATE(*this);
return m_Socket->SetOptionLinger(toggle, ConvTo< Uint16 >::From(time));
}
/* --------------------------------------------------------------------------------------------
* Tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway.
*/
bool SetOptionReuseAddr()
{
SQMOD_VALIDATE(*this);
return m_Socket->SetOptionReuseAddr();
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum number of seconds a call to
* SimpleSocket::Open waits until it completes.
*/
SQInteger GetConnectTimeoutSec()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetConnectTimeoutSec();
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum number of microseconds a call to
* SimpleSocket::Open waits until it completes.
*/
SQInteger GetConnectTimeoutUSec()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetConnectTimeoutUSec();
}
/* --------------------------------------------------------------------------------------------
* Sets the timeout value that specifies the maximum amount of time a call to
* SimpleSocket::Receive waits until it completes.
*/
void SetConnectTimeout(Int32 timeout_sec, Int32 timeout_usec)
{
SQMOD_VALIDATE(*this);
m_Socket->SetConnectTimeout(timeout_sec, timeout_usec);
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum number of seconds a a call to
* SimpleSocket::Receive waits until it completes.
*/
SQInteger GetReceiveTimeoutSec()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetReceiveTimeoutSec();
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum number of microseconds a call to
* SimpleSocket::Receive waits until it completes.
*/
SQInteger GetReceiveTimeoutUSec()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetReceiveTimeoutUSec();
}
/* --------------------------------------------------------------------------------------------
* Sets the timeout value that specifies the maximum amount of time a call to
* SimpleSocket::Receive waits until it completes.
*/
bool SetReceiveTimeout(Int32 timeout_sec, Int32 timeout_usec)
{
SQMOD_VALIDATE(*this);
return m_Socket->SetReceiveTimeout(timeout_sec, timeout_usec);
}
/* --------------------------------------------------------------------------------------------
* Enable/disable multi-cast for a socket. This options is only valid for socket descriptors
* of type SimpleSocket::SocketTypeUdp.
*/
void SetMulticast(bool toggle)
{
SQMOD_VALIDATE(*this);
if (!m_Socket->SetMulticast(toggle, 1)) STHROWF("Unable to set multi-cast on socket.");
}
/* --------------------------------------------------------------------------------------------
* Enable/disable multi-cast for a socket. This options is only valid for socket descriptors
* of type SimpleSocket::SocketTypeUdp.
*/
bool SetMulticastEx(bool toggle, Uint8 multicast_ttl)
{
SQMOD_VALIDATE(*this);
return m_Socket->SetMulticast(toggle, multicast_ttl);
}
/* --------------------------------------------------------------------------------------------
* Return true if socket is multi-cast or false is socket is uni-cast.
*/
bool GetMulticast()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetMulticast();
}
/* --------------------------------------------------------------------------------------------
* Bind socket to a specific interface when using multi-cast.
*/
bool BindInterface(StackStrF & intrf)
{
SQMOD_VALIDATE(*this);
return m_Socket->BindInterface(intrf.mPtr);
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum number of seconds a a call to
* SimpleSocket::Send waits until it completes.
*/
SQInteger GetSendTimeoutSec()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetSendTimeoutSec();
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum number of microseconds a call to
* SimpleSocket::Send waits until it completes.
*/
SQInteger GetSendTimeoutUSec()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetSendTimeoutUSec();
}
/* --------------------------------------------------------------------------------------------
* Gets the timeout value that specifies the maximum amount of time a call to
* SimpleSocket::Send waits until it completes.
*/
bool SetSendTimeout(Int32 timeout_sec, Int32 timeout_usec)
{
SQMOD_VALIDATE(*this);
return m_Socket->SetSendTimeout(timeout_sec, timeout_usec);
}
/* --------------------------------------------------------------------------------------------
*
*/
SQInteger GetSocketError()
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->GetSocketError());
}
/* --------------------------------------------------------------------------------------------
* Get the total time the of the last operation in milliseconds.
*/
SQInteger GetTotalTimeMs()
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->GetTotalTimeMs());
}
/* --------------------------------------------------------------------------------------------
* Get the total time the of the last operation in microseconds.
*/
SQInteger GetTotalTimeUsec()
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->GetTotalTimeUsec());
}
/* --------------------------------------------------------------------------------------------
* Return Differentiated Services Code Point (DSCP) value currently set on the socket object.
*/
Int32 GetSocketDSCP()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetSocketDscp();
}
/* --------------------------------------------------------------------------------------------
* Set Differentiated Services Code Point (DSCP) for socket object.
*/
void SetSocketDSCP(Int32 dscp)
{
SQMOD_VALIDATE(*this);
if (!m_Socket->SetSocketDscp(dscp)) STHROWF("Unable to set DSCP on socket.");
}
/* --------------------------------------------------------------------------------------------
* Set Differentiated Services Code Point (DSCP) for socket object.
*/
bool SetSocketDSCPEx(Int32 dscp)
{
SQMOD_VALIDATE(*this);
return m_Socket->SetSocketDscp(dscp);
}
/* --------------------------------------------------------------------------------------------
* Return socket type.
*/
SQInteger GetSocketType()
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->GetSocketType());
}
/* --------------------------------------------------------------------------------------------
* Returns clients Internet host address as a string in standard numbers-and-dots notation.
*/
LightObj GetClientAddr()
{
SQMOD_VALIDATE(*this);
return LightObj(m_Socket->GetClientAddr(), -1);
}
/* --------------------------------------------------------------------------------------------
* Returns the port number on which the client is connected.
*/
SQInteger GetClientPort()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetClientPort();
}
/* --------------------------------------------------------------------------------------------
* Returns server Internet host address as a string in standard numbers-and-dots notation.
*/
LightObj GetServerAddr()
{
SQMOD_VALIDATE(*this);
return LightObj(m_Socket->GetServerAddr(), -1);
}
/* --------------------------------------------------------------------------------------------
* Returns the port number on which the server is connected.
*/
SQInteger GetServerPort()
{
SQMOD_VALIDATE(*this);
return m_Socket->GetServerPort();
}
/* --------------------------------------------------------------------------------------------
* Get the TCP receive buffer window size for the current socket object.
*/
SQInteger GetReceiveWindowSize()
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->GetReceiveWindowSize());
}
/* --------------------------------------------------------------------------------------------
* Get the TCP send buffer window size for the current socket object.
*/
SQInteger GetSendWindowSize()
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->GetSendWindowSize());
}
/* --------------------------------------------------------------------------------------------
* Set the TCP receive buffer window size for the current socket object.
*/
SQInteger SetReceiveWindowSize(SQInteger window_size)
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->SetReceiveWindowSize(ConvTo< Uint32 >::From(window_size)));
}
/* --------------------------------------------------------------------------------------------
* Set the TCP send buffer window size for the current socket object.
*/
SQInteger SetSendWindowSize(SQInteger window_size)
{
SQMOD_VALIDATE(*this);
return static_cast< SQInteger >(m_Socket->SetSendWindowSize(ConvTo< Uint32 >::From(window_size)));
}
/* --------------------------------------------------------------------------------------------
* Disable the Nagle algorithm (Set TCP_NODELAY to true)
*/
bool DisableNagleAlgoritm()
{
SQMOD_VALIDATE(*this);
return m_Socket->DisableNagleAlgoritm();
}
/* --------------------------------------------------------------------------------------------
* Enable the Nagle algorithm (Set TCP_NODELAY to false)
*/
bool EnableNagleAlgoritm()
{
SQMOD_VALIDATE(*this);
return m_Socket->EnableNagleAlgoritm();
}
};
/* ------------------------------------------------------------------------------------------------
* Provides a platform independent class to create a passive socket. A passive socket is used to
* create a "listening" socket. This type of object would be used when an application needs to
* wait for inbound connections.
*/
class PassiveSocket : public SimpleSocket
{
public:
/* --------------------------------------------------------------------------------------------
* Default constructor. Defaults to creating a TCP socket.
*/
PassiveSocket()
: PassiveSocket(CSimpleSocket::SocketTypeTcp)
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor. Creates a socket of the specified type.
*/
explicit PassiveSocket(SQInteger type)
: SimpleSocket(new CPassiveSocket(static_cast< CSimpleSocket::CSocketType >(type)))
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor. Creates a socket with the specified instance.
*/
explicit PassiveSocket(CPassiveSocket * socket)
: SimpleSocket(socket)
{
}
/* --------------------------------------------------------------------------------------------
* Retrieve the managed socket to the type that we expect.
*/
CPassiveSocket * Get()
{
return dynamic_cast< CPassiveSocket * >(m_Socket);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the managed socket to the type that we expect.
*/
const CPassiveSocket * Get() const
{
return dynamic_cast< CPassiveSocket * >(m_Socket);
}
/* --------------------------------------------------------------------------------------------
* Return a string representation of this instance.
*/
LightObj ToString()
{
return m_Socket ? LightObj{} : GetServerAddr();
}
/* --------------------------------------------------------------------------------------------
* Extracts the first connection request on the queue of pending connections and creates a newly connected socket.
*/
LightObj Accept();
/* --------------------------------------------------------------------------------------------
* Bind to a multi-cast group on a specified interface, multi-cast group, and port.
*/
bool BindMulticast(StackStrF & intrf, StackStrF & group, Uint16 port)
{
SQMOD_VALIDATE(*this);
return Get()->BindMulticast(intrf.mPtr, group.mPtr, port);
}
/* --------------------------------------------------------------------------------------------
* Create a listening socket at local IP address 'x.x.x.x' or 'localhost' if addr is NULL on port port.
*/
bool Listen(Uint16 port, StackStrF & addr)
{
SQMOD_VALIDATE(*this);
return Get()->Listen(addr.mPtr, port);
}
/* --------------------------------------------------------------------------------------------
* Create a listening socket at local IP address 'x.x.x.x' or 'localhost' if addr is NULL on port port.
*/
bool ListenEx(Uint16 port, Int32 connection_backlog, StackStrF & addr)
{
SQMOD_VALIDATE(*this);
return Get()->Listen(addr.mPtr, port, connection_backlog);
}
/* --------------------------------------------------------------------------------------------
* Attempts to send a string on an established connection.
*/
Int32 SendStr(StackStrF & str)
{
SQMOD_VALIDATE(*this);
return Get()->Send(reinterpret_cast< const uint8_t * >(str.mPtr),
static_cast< size_t >(str.mLen) * (sizeof(SQChar) / sizeof(uint8_t)));
}
};
/* ------------------------------------------------------------------------------------------------
* Provides a platform independent class to create an active socket. An active socket is used to
* create a socket which connects to a server. This type of object would be used when
* an application needs to send/receive data from a server.
*/
class ActiveSocket : public SimpleSocket
{
friend class PassiveSocket;
public:
/* --------------------------------------------------------------------------------------------
* Default constructor. Defaults to creating a TCP socket.
*/
ActiveSocket()
: ActiveSocket(CSimpleSocket::SocketTypeTcp)
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor. Creates a socket of the specified type.
*/
explicit ActiveSocket(SQInteger type)
: SimpleSocket(new CActiveSocket(static_cast< CSimpleSocket::CSocketType >(type)))
{
}
/* --------------------------------------------------------------------------------------------
* Explicit constructor. Creates a socket with the specified instance.
*/
explicit ActiveSocket(CActiveSocket * socket)
: SimpleSocket(socket)
{
}
/* --------------------------------------------------------------------------------------------
* Retrieve the managed socket to the type that we expect.
*/
CActiveSocket * Get()
{
return dynamic_cast< CActiveSocket * >(m_Socket);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the managed socket to the type that we expect.
*/
const CActiveSocket * Get() const
{
return dynamic_cast< CActiveSocket * >(m_Socket);
}
/* --------------------------------------------------------------------------------------------
* Return a string representation of this instance.
*/
LightObj ToString()
{
return m_Socket ? LightObj{} : GetClientAddr();
}
/* --------------------------------------------------------------------------------------------
* Establish a connection to the address specified by addr.
*/
bool Open(Uint16 port, StackStrF & addr)
{
SQMOD_VALIDATE(*this);
return Get()->Open(addr.mPtr, port);
}
/* --------------------------------------------------------------------------------------------
* Attempts to send a string on an established connection.
*/
Int32 SendStr(StackStrF & str)
{
SQMOD_VALIDATE(*this);
return Get()->Send(reinterpret_cast< const uint8_t * >(str.mPtr),
static_cast< size_t >(str.mLen) * (sizeof(SQChar) / sizeof(uint8_t)));
}
};
// ------------------------------------------------------------------------------------------------
} // Namespace:: SqMod

View File

@ -112,7 +112,7 @@ protected:
/* ---------------------------------------------------------------------------------------- /* ----------------------------------------------------------------------------------------
* Forwarding constructor. * Forwarding constructor.
*/ */
Slot(Object & env, Function & func) Slot(Object & env, ::Sqrat::Function & func)
: Slot(env.GetObj(), func.GetFunc()) : Slot(env.GetObj(), func.GetFunc())
{ {
/* ... */ /* ... */

View File

@ -40,6 +40,7 @@ extern void Register_Crypt(HSQUIRRELVM vm);
extern void Register_IO(HSQUIRRELVM vm); extern void Register_IO(HSQUIRRELVM vm);
extern void Register_MMDB(HSQUIRRELVM vm); extern void Register_MMDB(HSQUIRRELVM vm);
extern void Register_Numeric(HSQUIRRELVM vm); extern void Register_Numeric(HSQUIRRELVM vm);
extern void Register_Socket(HSQUIRRELVM vm);
extern void Register_SQLite(HSQUIRRELVM vm); extern void Register_SQLite(HSQUIRRELVM vm);
extern void Register_String(HSQUIRRELVM vm); extern void Register_String(HSQUIRRELVM vm);
extern void Register_System(HSQUIRRELVM vm); extern void Register_System(HSQUIRRELVM vm);
@ -88,6 +89,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
Register_IO(vm); Register_IO(vm);
Register_MMDB(vm); Register_MMDB(vm);
Register_Numeric(vm); Register_Numeric(vm);
Register_Socket(vm);
Register_SQLite(vm); Register_SQLite(vm);
Register_String(vm); Register_String(vm);
Register_System(vm); Register_System(vm);

View File

@ -7,7 +7,9 @@ add_subdirectory(PUGIXML)
add_subdirectory(SQLite) add_subdirectory(SQLite)
add_subdirectory(TinyDir) add_subdirectory(TinyDir)
add_subdirectory(Whirlpool) add_subdirectory(Whirlpool)
add_subdirectory(SimpleSocket)
# Build our own mysql client on windows # Build our own mysql client on windows
if(WIN32 AND ENABLE_MYSQL) if(WIN32 AND ENABLE_MYSQL)
add_subdirectory(MDBC) add_subdirectory(MDBC)
endif() endif()
# Disregard warnings from this library

View File

@ -0,0 +1,310 @@
/*---------------------------------------------------------------------------*/
/* */
/* CActiveSocket.cpp - Active Socket Implementation */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#include "ActiveSocket.h"
CActiveSocket::CActiveSocket(CSocketType nType) : CSimpleSocket(nType)
{
}
//------------------------------------------------------------------------------
//
// ConnectTCP() -
//
//------------------------------------------------------------------------------
bool CActiveSocket::ConnectTCP(const char *pAddr, uint16 nPort)
{
bool bRetVal = false;
struct in_addr stIpAddress;
//------------------------------------------------------------------
// Preconnection setup that must be preformed
//------------------------------------------------------------------
memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
m_stServerSockaddr.sin_family = AF_INET;
if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
{
#ifdef WIN32
TranslateSocketError();
#else
if (h_errno == HOST_NOT_FOUND)
{
SetSocketError(SocketInvalidAddress);
}
#endif
return bRetVal;
}
memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;
if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
{
TranslateSocketError();
return bRetVal;
}
m_stServerSockaddr.sin_port = htons(nPort);
//------------------------------------------------------------------
// Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only.
//
//------------------------------------------------------------------
m_timer.Initialize();
m_timer.SetStartTime();
if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) ==
CSimpleSocket::SocketError)
{
//--------------------------------------------------------------
// Get error value this might be a non-blocking socket so we
// must first check.
//--------------------------------------------------------------
TranslateSocketError();
//--------------------------------------------------------------
// If the socket is non-blocking and the current socket error
// is SocketEinprogress or SocketEwouldblock then poll connection
// with select for designated timeout period.
// Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK.
//--------------------------------------------------------------
if ((IsNonblocking()) &&
((GetSocketError() == CSimpleSocket::SocketEwouldblock) ||
(GetSocketError() == CSimpleSocket::SocketEinprogress)))
{
bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec());
}
}
else
{
TranslateSocketError();
bRetVal = true;
}
m_timer.SetEndTime();
return bRetVal;
}
//------------------------------------------------------------------------------
//
// ConnectUDP() -
//
//------------------------------------------------------------------------------
bool CActiveSocket::ConnectUDP(const char *pAddr, uint16 nPort)
{
bool bRetVal = false;
struct in_addr stIpAddress;
//------------------------------------------------------------------
// Pre-connection setup that must be preformed
//------------------------------------------------------------------
memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
m_stServerSockaddr.sin_family = AF_INET;
if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
{
#ifdef WIN32
TranslateSocketError();
#else
if (h_errno == HOST_NOT_FOUND)
{
SetSocketError(SocketInvalidAddress);
}
#endif
return bRetVal;
}
memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;
if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
{
TranslateSocketError();
return bRetVal;
}
m_stServerSockaddr.sin_port = htons(nPort);
//------------------------------------------------------------------
// Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only.
//
//------------------------------------------------------------------
m_timer.Initialize();
m_timer.SetStartTime();
if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
{
bRetVal = true;
}
TranslateSocketError();
m_timer.SetEndTime();
return bRetVal;
}
//------------------------------------------------------------------------------
//
// ConnectRAW() -
//
//------------------------------------------------------------------------------
bool CActiveSocket::ConnectRAW(const char *pAddr, uint16 nPort)
{
bool bRetVal = false;
struct in_addr stIpAddress;
//------------------------------------------------------------------
// Pre-connection setup that must be preformed
//------------------------------------------------------------------
memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr));
m_stServerSockaddr.sin_family = AF_INET;
if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL)
{
#ifdef WIN32
TranslateSocketError();
#else
if (h_errno == HOST_NOT_FOUND)
{
SetSocketError(SocketInvalidAddress);
}
#endif
return bRetVal;
}
memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length);
m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr;
if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError)
{
TranslateSocketError();
return bRetVal;
}
m_stServerSockaddr.sin_port = htons(nPort);
//------------------------------------------------------------------
// Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only.
//
//------------------------------------------------------------------
m_timer.Initialize();
m_timer.SetStartTime();
if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
{
bRetVal = true;
}
TranslateSocketError();
m_timer.SetEndTime();
return bRetVal;
}
//------------------------------------------------------------------------------
//
// Open() - Create a connection to a specified address on a specified port
//
//------------------------------------------------------------------------------
bool CActiveSocket::Open(const char *pAddr, uint16 nPort)
{
bool bRetVal = false;
if (IsSocketValid() == false)
{
SetSocketError(CSimpleSocket::SocketInvalidSocket);
return bRetVal;
}
if (pAddr == NULL)
{
SetSocketError(CSimpleSocket::SocketInvalidAddress);
return bRetVal;
}
if (nPort == 0)
{
SetSocketError(CSimpleSocket::SocketInvalidPort);
return bRetVal;
}
switch (m_nSocketType)
{
case CSimpleSocket::SocketTypeTcp :
{
bRetVal = ConnectTCP(pAddr, nPort);
break;
}
case CSimpleSocket::SocketTypeUdp :
{
bRetVal = ConnectUDP(pAddr, nPort);
break;
}
case CSimpleSocket::SocketTypeRaw :
break;
default:
break;
}
//--------------------------------------------------------------------------
// If successful then create a local copy of the address and port
//--------------------------------------------------------------------------
if (bRetVal)
{
socklen_t nSockLen = sizeof(struct sockaddr);
memset(&m_stServerSockaddr, 0, nSockLen);
getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen);
nSockLen = sizeof(struct sockaddr);
memset(&m_stClientSockaddr, 0, nSockLen);
getsockname(m_socket, (struct sockaddr *)&m_stClientSockaddr, &nSockLen);
SetSocketError(SocketSuccess);
}
return bRetVal;
}

View File

@ -0,0 +1,20 @@
# Create library
add_library(SimpleSocket STATIC
include/Host.h
include/StatTimer.h
include/ActiveSocket.h ActiveSocket.cpp
include/PassiveSocket.h PassiveSocket.cpp
include/SimpleSocket.h SimpleSocket.cpp
)
# Configure include folders
target_include_directories(SimpleSocket PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(SimpleSocket PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
# Configure macro options
target_compile_definitions(SimpleSocket PRIVATE _WIN32_WINNT=0x0601)
# OS and compiler checks.
if(UNIX)
target_compile_definitions(SimpleSocket PRIVATE _LINUX=1)
elseif(WIN32)
target_compile_definitions(SimpleSocket PRIVATE WIN32=1 _WIN32=1)
target_link_libraries(SimpleSocket PUBLIC Ws2_32)
endif()

View File

@ -0,0 +1,328 @@
/*---------------------------------------------------------------------------*/
/* */
/* PassiveSocket.cpp - Passive Socket Implementation */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#include "PassiveSocket.h"
CPassiveSocket::CPassiveSocket(CSocketType nType) : CSimpleSocket(nType)
{
}
bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, uint16 nPort)
{
bool bRetVal = false;
#ifdef WIN32
ULONG inAddr;
#else
in_addr_t inAddr;
#endif
//--------------------------------------------------------------------------
// Set the following socket option SO_REUSEADDR. This will allow the file
// descriptor to be reused immediately after the socket is closed instead
// of setting in a TIMED_WAIT state.
//--------------------------------------------------------------------------
memset(&m_stMulticastGroup,0,sizeof(m_stMulticastGroup));
m_stMulticastGroup.sin_family = AF_INET;
m_stMulticastGroup.sin_port = htons(nPort);
//--------------------------------------------------------------------------
// If no IP Address (interface ethn) is supplied, or the loop back is
// specified then bind to any interface, else bind to specified interface.
//--------------------------------------------------------------------------
if ((pInterface == NULL) || (!strlen(pInterface)))
{
m_stMulticastGroup.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
if ((inAddr = inet_addr(pInterface)) != INADDR_NONE)
{
m_stMulticastGroup.sin_addr.s_addr = inAddr;
}
}
//--------------------------------------------------------------------------
// Bind to the specified port
//--------------------------------------------------------------------------
if (bind(m_socket, (struct sockaddr *)&m_stMulticastGroup, sizeof(m_stMulticastGroup)) == 0)
{
//----------------------------------------------------------------------
// Join the multicast group
//----------------------------------------------------------------------
m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup);
m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr;
if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void *)&m_stMulticastRequest,
sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess)
{
bRetVal = true;
}
m_timer.SetEndTime();
}
m_timer.Initialize();
m_timer.SetStartTime();
//--------------------------------------------------------------------------
// If there was a socket error then close the socket to clean out the
// connection in the backlog.
//--------------------------------------------------------------------------
TranslateSocketError();
if (bRetVal == false)
{
Close();
}
return bRetVal;
}
//------------------------------------------------------------------------------
//
// Listen() -
//
//------------------------------------------------------------------------------
bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBacklog)
{
bool bRetVal = false;
#ifdef WIN32
ULONG inAddr;
#else
in_addr_t inAddr;
int32 nReuse;
nReuse = IPTOS_LOWDELAY;
//--------------------------------------------------------------------------
// Set the following socket option SO_REUSEADDR. This will allow the file
// descriptor to be reused immediately after the socket is closed instead
// of setting in a TIMED_WAIT state.
//--------------------------------------------------------------------------
SETSOCKOPT(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nReuse, sizeof(int32));
SETSOCKOPT(m_socket, IPPROTO_TCP, IP_TOS, &nReuse, sizeof(int32));
#endif
memset(&m_stServerSockaddr,0,sizeof(m_stServerSockaddr));
m_stServerSockaddr.sin_family = AF_INET;
m_stServerSockaddr.sin_port = htons(nPort);
//--------------------------------------------------------------------------
// If no IP Address (interface ethn) is supplied, or the loop back is
// specified then bind to any interface, else bind to specified interface.
//--------------------------------------------------------------------------
if ((pAddr == NULL) || (!strlen(pAddr)))
{
m_stServerSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
if ((inAddr = inet_addr(pAddr)) != INADDR_NONE)
{
m_stServerSockaddr.sin_addr.s_addr = inAddr;
}
}
m_timer.Initialize();
m_timer.SetStartTime();
//--------------------------------------------------------------------------
// Bind to the specified port
//--------------------------------------------------------------------------
if (bind(m_socket, (struct sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError)
{
if (m_nSocketType == CSimpleSocket::SocketTypeTcp)
{
if (listen(m_socket, nConnectionBacklog) != CSimpleSocket::SocketError)
{
bRetVal = true;
}
}
else
{
bRetVal = true;
}
}
m_timer.SetEndTime();
//--------------------------------------------------------------------------
// If there was a socket error then close the socket to clean out the
// connection in the backlog.
//--------------------------------------------------------------------------
TranslateSocketError();
if (bRetVal == false)
{
CSocketError err = GetSocketError();
Close();
SetSocketError(err);
}
return bRetVal;
}
//------------------------------------------------------------------------------
//
// Accept() -
//
//------------------------------------------------------------------------------
CActiveSocket *CPassiveSocket::Accept()
{
uint32 nSockLen;
CActiveSocket *pClientSocket = NULL;
SOCKET socket = CSimpleSocket::SocketError;
if (m_nSocketType != CSimpleSocket::SocketTypeTcp)
{
SetSocketError(CSimpleSocket::SocketProtocolError);
return pClientSocket;
}
pClientSocket = new CActiveSocket();
//--------------------------------------------------------------------------
// Wait for incoming connection.
//--------------------------------------------------------------------------
if (pClientSocket != NULL)
{
CSocketError socketErrno = SocketSuccess;
m_timer.Initialize();
m_timer.SetStartTime();
nSockLen = sizeof(m_stClientSockaddr);
do
{
errno = 0;
socket = accept(m_socket, (struct sockaddr *)&m_stClientSockaddr, (socklen_t *)&nSockLen);
if (socket != -1)
{
pClientSocket->SetSocketHandle(socket);
pClientSocket->TranslateSocketError();
socketErrno = pClientSocket->GetSocketError();
socklen_t nSockLen = sizeof(struct sockaddr);
//-------------------------------------------------------------
// Store client and server IP and port information for this
// connection.
//-------------------------------------------------------------
getpeername(m_socket, (struct sockaddr *)&pClientSocket->m_stClientSockaddr, &nSockLen);
memcpy((void *)&pClientSocket->m_stClientSockaddr, (void *)&m_stClientSockaddr, nSockLen);
memset(&pClientSocket->m_stServerSockaddr, 0, nSockLen);
getsockname(m_socket, (struct sockaddr *)&pClientSocket->m_stServerSockaddr, &nSockLen);
}
else
{
TranslateSocketError();
socketErrno = GetSocketError();
}
} while (socketErrno == CSimpleSocket::SocketInterrupted);
m_timer.SetEndTime();
if (socketErrno != CSimpleSocket::SocketSuccess)
{
delete pClientSocket;
pClientSocket = NULL;
}
}
return pClientSocket;
}
//------------------------------------------------------------------------------
//
// Send() - Send data on a valid socket
//
//------------------------------------------------------------------------------
int32 CPassiveSocket::Send(const uint8 *pBuf, size_t bytesToSend)
{
SetSocketError(SocketSuccess);
m_nBytesSent = 0;
switch(m_nSocketType)
{
case CSimpleSocket::SocketTypeUdp:
{
if (IsSocketValid())
{
if ((bytesToSend > 0) && (pBuf != NULL))
{
m_timer.Initialize();
m_timer.SetStartTime();
m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0,
(const sockaddr *)&m_stClientSockaddr,
sizeof(m_stClientSockaddr));
m_timer.SetEndTime();
if (m_nBytesSent == CSimpleSocket::SocketError)
{
TranslateSocketError();
}
}
}
break;
}
case CSimpleSocket::SocketTypeTcp:
CSimpleSocket::Send(pBuf, bytesToSend);
break;
default:
SetSocketError(SocketProtocolError);
break;
}
return m_nBytesSent;
}

153
module/Vendor/SimpleSocket/README vendored Normal file
View File

@ -0,0 +1,153 @@
------------------------------------------------------------------------------------------
* History
------------------------------------------------------------------------------------------
Written by Mark Carrier to provide a mechanism for writing cross platform socket code. This library was originally written to only support blocking TCP sockets. Over the years it has been extended to support UDP and RAW sockets as well. This is the first official release of the library and the following functionality is supported:
* Cross platform socket support.
o Windows 95, Windows 98, Windows XP
o Linux, Unix
o Macintosh OSX
* Support for sychronious, and asychronious sockets
* Supports TCP Streams
* Supports UDP Datagrams
* Supports Raw Sockets
* Thread Safe
* Signal Safe
------------------------------------------------------------------------------------------
* Building and Installing
------------------------------------------------------------------------------------------
This is a very small library and is very easy to build and configure. To build and install
make sure you are logged in as a user who has access to the recommend GNU installation
directories. Then type
make -BUILD=Release && make install
That is it now you are off and running.
NOTE: When using the library with WINDOWS you must define _WIN32 and when using with LINUX
you must define _LINUX.
------------------------------------------------------------------------------------------
* SimpleSocket Class Overview
------------------------------------------------------------------------------------------
Network communications via sockets can be abstracted into two categories of functionality; the active socket and the passive socket. The active socket object initiates a connection with a known host, whereas the passive socket object waits (or listens) for inbound requests for communication. The functionality of both objects is identical as far as sending and receiving data. This library makes distinction between the two objects because the operations for constructing and destructing the two are different.
This library is different from other socket libraries which define TCP sockets, UDP sockets, HTTP sockets, etc. The reason is the operations required for TCP, UDP, and RAW network communication is identical from a logical stand point. Thus a program could initially be written employing TCP streams, and then at some future point it could be discovered that UDP datagrams would satisify the solution. Changing between the two transport protocols would only require changing how the object is instantiated. The remaining code would in theory require minimal to no changes.
This library avoids abstractions like HTTP socket, or SMTP socket, soley because this type of object mixes the application and the transport layer. These types of abstractions can be created using this library as a base class.
The simple socket library is comprised of two class which can be used to represent all socket communications.
* Active Socket Class
* Passive Socket Class
------------------------------------------------------------------------------------------
* SimpleSocket Class Examples
------------------------------------------------------------------------------------------
When operating on a socket object most methods will return true or false
Simple Active Socket
As mentioned previously the active socket (CActiveSocket) is used to initiate a connections with a server on some known port. So you want to connect to an existing server...
How do you do it?
There are many ways using the existing Berkley Socket API, but the goal of this class is to remove the many calls and man page lookups and replace them with clear, concise set of methods which allow a developer to focus on the logic of network programming.
The following code will connect to a DAYTIME server on port 13, query for the current time, and close the socket.
#include <string.h>
#include "ActiveSocket.h" // Include header for active socket object definition
int main(int argc, char **argv)
{
CActiveSocket socket; // Instantiate active socket object (defaults to TCP).
char time[50];
memset(&time, 0, 50);
//--------------------------------------------------------------------------
// Initialize our socket object
//--------------------------------------------------------------------------
socket.Initialize();
//--------------------------------------------------------------------------
// Create a connection to the time server so that data can be sent
// and received.
//--------------------------------------------------------------------------
if (socket.Open("time-C.timefreq.bldrdoc.gov", 13))
{
//----------------------------------------------------------------------
// Send a requtest the server requesting the current time.
//----------------------------------------------------------------------
if (socket.Send((const uint8 *)"\n", 1))
{
//----------------------------------------------------------------------
// Receive response from the server.
//----------------------------------------------------------------------
socket.Receive(49);
memcpy(&time, socket.GetData(), 49);
printf("%s\n", time);
//----------------------------------------------------------------------
// Close the connection.
//----------------------------------------------------------------------
socket.Close();
}
}
return 1;
}
You can see that the amount of code required to an object for network communciation is very small and simple.
Simple Passive Socket
Now you want to build a server.
How do you do it?
For a practical test lets build an echo server. The server will listen on port 6789 an repsond back with what ever has been sent to the server.
#include "PassiveSocket.h" // Include header for active socket object definition
#define MAX_PACKET 4096
int main(int argc, char **argv)
{
CPassiveSocket socket;
CActiveSocket *pClient = NULL;
//--------------------------------------------------------------------------
// Initialize our socket object
//--------------------------------------------------------------------------
socket.Initialize();
socket.Listen("127.0.0.1", 6789);
while (true)
{
if ((pClient = socket.Accept()) != NULL)
{
//----------------------------------------------------------------------
// Receive request from the client.
//----------------------------------------------------------------------
if (pClient->Receive(MAX_PACKET))
{
//------------------------------------------------------------------
// Send response to client and close connection to the client.
//------------------------------------------------------------------
pClient->Send( pClient->GetData(), pClient->GetBytesReceived() );
pClient->Close();
}
delete pClient;
}
}
//-----------------------------------------------------------------------------
// Receive request from the client.
//-----------------------------------------------------------------------------
socket.Close();
return 1;
}

479
module/Vendor/SimpleSocket/ReleaseNotes vendored Normal file
View File

@ -0,0 +1,479 @@
===============================================================================
Release v1.4.1
===============================================================================
I. New Features
---------------
* New methods:
CSimpleSocket::EnableNagleAlgorithm()
CSimpleSocket::DisableNagleAlgorithm()
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#95 - Add support to enable/disable Nable algorithm
#131 - Multicast receiver not working
Unreported Bugs
---------------
IV. Known Issues
----------------
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags.
#48 - Finish support for RAW sockets.
#50 - Add IPV6 support
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.4.0
===============================================================================
I. New Features
---------------
* Support for multicast
* New methods:
CPassiveSocket::BindMulticast()
CSimpleSocket::SetMulticast()
CSimpleSocket::GetMulticast()
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#92 - Add multicast to library
Unreported Bugs
---------------
IV. Known Issues
----------------
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags.
#48 - Finish support for RAW sockets.
#50 - Add IPV6 support
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.3.3
===============================================================================
I. New Features
---------------
* Now compiles for Macintosh - DMG file not yet supported
* New method CSimpleSocket::Shutdown() - used to control
shutdown on socket.
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#49 - Support for Macintosh
#86 - Create new method to control shutdown of socket
#87 - Memory leak detected
Unreported Bugs
---------------
IV. Known Issues
----------------
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags.
#48 - Finish support for RAW sockets.
#50 - Add IPV6 support
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.3.2
===============================================================================
I. New Features
---------------
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#84 - CActiveSocket::Close() shutsdown both sides of the socket
Unreported Bugs
---------------
IV. Known Issues
----------------
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags.
#48 - Finish support for RAW sockets.
#49 - Support for Macintosh.
#50 - Add IPV6 support
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.3.1
===============================================================================
I. New Features
---------------
* New methods:
SetOptionLinger() - Enable/disable linger option.
SetOptionReuseAddr() - Set option reuse port.
* SimpleSocket::Receive() will only allocate a buffer if the internal buffer
is NULL or the buffer size is not equal to the previously allocated
buffer.
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#64 - Method GetClientPort() returns value in byte swapped order
#83 - WIN32 SetBlocking() is broke.
Unreported Bugs
---------------
IV. Known Issues
----------------
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags.
#48 - Finish support for RAW sockets.
#49 - Support for Macintosh.
#50 - Add IPV6 support
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.3.0
===============================================================================
I. New Features
---------------
* New methods:
SendVector() - implements the iovec functionality on both linux and
Windows.
SetSendWindowSize() - Sent the TCP window size for send.
SetReceiveWindowSize() - Set the TCP windows size for receive.
GetSendWindowSize() - Get the TCP window size for send.
GetReceiveWindowSize() - Get the TCP window size fo receive.
Select(int sec, int usec) - Overloaded function to specify timeout
value of select.
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#33 - Add SendVector mehtod to class
#41 - Sockets library MUST be signal safe
#51 - Add support to set TCP windows size
#52 - Select closes socket if timeout occurs
#53 - UDP receive always fails even when successful
Unreported Bugs
---------------
IV. Known Issues
----------------
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags.
#48 - Finish support for RAW sockets.
#49 - Support for Macintosh.
#50 - Add IPV6 support
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.2.0
===============================================================================
I. New Features
---------------
* New method SetSocketDscp() and GetSocketDscp() for setting and getting DSCP values.
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#17 - Finish documentation of library
#34 - Add SendFile() method to class
#37 - Make new methods GetServerAddress() and GetClientAddress()
Unreported Bugs
---------------
IV. Known Issues
----------------
#41 - Sockets library MUST be signal safe
#44 - Add MTU size test to unit test so fragmentation can be tested.
#45 - Test Select() with Recv() and Send() set as non-blocking.
#47 - Mechanism to setting/setting socket options/flags
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.1.0
===============================================================================
I. New Features
---------------
* UDP Now supported
II. Deprecated Functionality
----------------------------
* SetSocketExpedited() method.
III. Bug Fixes
--------------
Reported Bugs
-------------
#18 - Compile under windows
#24 - Add more type and error checking to CSocket
#29 - Add UDP support
#35 - unit testing of socket library causes crash on windows
Unreported Bugs
---------------
IV. Known Issues
----------------
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.0.3
===============================================================================
I. New Features
---------------
* New method SetSocketExpedited() for setting expedited traffice (DSCP settings).
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
Reported Bugs
-------------
#27 - Finish adding stats code to CSocket class.
#30 - ConnectTCP() does not return correct error for inavlid IP Address.
Unreported Bugs
---------------
IV. Known Issues
----------------
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------
===============================================================================
Release v1.0.2
===============================================================================
I. New Features
---------------
* Implemented a new socket mode "CSocketMode::Passive" which allows the creation
of a listening socket. Two new methods are available to control behavior for
the listening socket: Listen() and Accept().
II. Deprecated Functionality
----------------------------
III. Bug Fixes
--------------
#23 - Create Listen() method
Reported Bugs
-------------
Unreported Bugs
---------------
IV. Known Issues
----------------
V. Configuration Changes
------------------------
VI. Release Tag Dependencies
----------------------------
VII. Errata
-----------
Bug Fixes
-------------
VIII. Documentation Changes
----------------------------

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
/*---------------------------------------------------------------------------*/
/* */
/* ActiveSocket.h - Active Socket Decleration */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#ifndef __ACTIVESOCKET_H__
#define __ACTIVESOCKET_H__
#include "SimpleSocket.h"
class CPassiveSocket;
/// Provides a platform independent class to create an active socket.
/// An active socket is used to create a socket which connects to a server.
/// This type of object would be used when an application needs to send/receive
/// data from a server.
class CActiveSocket : public CSimpleSocket {
public:
friend class CPassiveSocket;
CActiveSocket(CSocketType type = SocketTypeTcp);
virtual ~CActiveSocket() {
Close();
};
/// Established a connection to the address specified by pAddr.
/// Connection-based protocol sockets (CSocket::SocketTypeTcp) may
/// successfully call Open() only once, however; connectionless protocol
/// sockets (CSocket::SocketTypeUdp) may use Open() multiple times to
/// change their association.
/// @param pAddr specifies the destination address to connect.
/// @param nPort specifies the destination port.
/// @return true if successful connection made, otherwise false.
virtual bool Open(const char *pAddr, uint16 nPort);
private:
/// Utility function used to create a TCP connection, called from Open().
/// @return true if successful connection made, otherwise false.
bool ConnectTCP(const char *pAddr, uint16 nPort);
/// Utility function used to create a UDP connection, called from Open().
/// @return true if successful connection made, otherwise false.
bool ConnectUDP(const char *pAddr, uint16 nPort);
/// Utility function used to create a RAW connection, called from Open().
/// @return true if successful connection made, otherwise false.
bool ConnectRAW(const char *pAddr, uint16 nPort);
private:
struct hostent *m_pHE;
};
#endif /* __ACTIVESOCKET_H__ */

View File

@ -0,0 +1,257 @@
/*---------------------------------------------------------------------------*/
/* */
/* Host.h - Basic header file to provide cross-platform solutions via */
/* macros, conditional compilation, etc. */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#ifndef __HOST_H__
#define __HOST_H__
#include <limits.h>
#ifdef __cplusplus
extern "C"
{
#endif
/*---------------------------------------------------------------------------*/
/* */
/* Type Definition Macros */
/* */
/*---------------------------------------------------------------------------*/
#ifndef __WORDSIZE
/* Assume 32 */
#define __WORDSIZE 32
#endif
#if defined(_LINUX) || defined(_DARWIN)
typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
typedef int SOCKET;
#endif
#ifdef WIN32
struct iovec {
void *iov_base;
size_t iov_len;
};
typedef unsigned char uint8;
typedef char int8;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned int uint32;
typedef int int32;
#endif
#ifdef WIN32
typedef int socklen_t;
#endif
#if defined(WIN32)
typedef unsigned long long int uint64;
typedef long long int int64;
#elif (__WORDSIZE == 32)
__extension__
typedef long long int int64;
__extension__
typedef unsigned long long int uint64;
#elif (__WORDSIZE == 64)
typedef unsigned long int uint64;
typedef long int int64;
#endif
#ifdef WIN32
#ifndef UINT8_MAX
#define UINT8_MAX (UCHAR_MAX)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (USHRT_MAX)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (ULONG_MAX)
#endif
#if __WORDSIZE == 64
#define SIZE_MAX (18446744073709551615UL)
#else
#ifndef SIZE_MAX
#define SIZE_MAX (4294967295U)
#endif
#endif
#endif
#if defined(WIN32)
#define ssize_t size_t
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef htonll
#ifdef _BIG_ENDIAN
#define htonll(x) (x)
#define ntohll(x) (x)
#else
#define htonll(x) ((((uint64)htonl(x)) << 32) + htonl(x >> 32))
#define ntohll(x) ((((uint64)ntohl(x)) << 32) + ntohl(x >> 32))
#endif
#endif
/*---------------------------------------------------------------------------*/
/* */
/* Socket Macros */
/* */
/*---------------------------------------------------------------------------*/
#ifdef WIN32
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#define ACCEPT(a,b,c) accept(a,b,c)
#define CONNECT(a,b,c) connect(a,b,c)
#define CLOSE(a) closesocket(a)
#define READ(a,b,c) read(a,b,c)
#define RECV(a,b,c,d) recv(a, (char *)b, c, d)
#define RECVFROM(a,b,c,d,e,f) recvfrom(a, (char *)b, c, d, (sockaddr *)e, (int *)f)
#define RECV_FLAGS MSG_WAITALL
#define SELECT(a,b,c,d,e) select((int32)a,b,c,d,e)
#define SEND(a,b,c,d) send(a, (const char *)b, (int)c, d)
#define SENDTO(a,b,c,d,e,f) sendto(a, (const char *)b, (int)c, d, e, f)
#define SEND_FLAGS 0
#define SENDFILE(a,b,c,d) sendfile(a, b, c, d)
#define SET_SOCKET_ERROR(x,y) errno=y
#define SOCKET_ERROR_INTERUPT EINTR
#define SOCKET_ERROR_TIMEDOUT EAGAIN
#define WRITE(a,b,c) write(a,b,c)
#define WRITEV(a,b,c) Writev(b, c)
#define GETSOCKOPT(a,b,c,d,e) getsockopt(a,b,c,(char *)d, (int *)e)
#define SETSOCKOPT(a,b,c,d,e) setsockopt(a,b,c,(char *)d, (int)e)
#define GETHOSTBYNAME(a) gethostbyname(a)
#endif
#if defined(_LINUX) || defined(_DARWIN)
#define ACCEPT(a,b,c) accept(a,b,c)
#define CONNECT(a,b,c) connect(a,b,c)
#define CLOSE(a) close(a)
#define READ(a,b,c) read(a,b,c)
#define RECV(a,b,c,d) recv(a, (void *)b, c, d)
#define RECVFROM(a,b,c,d,e,f) recvfrom(a, (char *)b, c, d, (sockaddr *)e, f)
#define RECV_FLAGS MSG_WAITALL
#define SELECT(a,b,c,d,e) select(a,b,c,d,e)
#define SEND(a,b,c,d) send(a, (const int8 *)b, c, d)
#define SENDTO(a,b,c,d,e,f) sendto(a, (const int8 *)b, c, d, e, f)
#define SEND_FLAGS 0
#define SENDFILE(a,b,c,d) sendfile(a, b, c, d)
#define SET_SOCKET_ERROR(x,y) errno=y
#define SOCKET_ERROR_INTERUPT EINTR
#define SOCKET_ERROR_TIMEDOUT EAGAIN
#define WRITE(a,b,c) write(a,b,c)
#define WRITEV(a,b,c) writev(a, b, c)
#define GETSOCKOPT(a,b,c,d,e) getsockopt((int)a,(int)b,(int)c,(void *)d,(socklen_t *)e)
#define SETSOCKOPT(a,b,c,d,e) setsockopt((int)a,(int)b,(int)c,(const void *)d,(int)e)
#define GETHOSTBYNAME(a) gethostbyname(a)
#endif
/*---------------------------------------------------------------------------*/
/* */
/* File Macros */
/* */
/*---------------------------------------------------------------------------*/
#define STRUCT_STAT struct stat
#define LSTAT(x,y) lstat(x,y)
#define FILE_HANDLE FILE *
#define CLEARERR(x) clearerr(x)
#define FCLOSE(x) fclose(x)
#define FEOF(x) feof(x)
#define FERROR(x) ferror(x)
#define FFLUSH(x) fflush(x)
#define FILENO(s) fileno(s)
#define FOPEN(x,y) fopen(x, y)
//#define FREAD(a,b,c,d) fread(a, b, c, d)
#define FSTAT(s, st) fstat(FILENO(s), st)
//#define FWRITE(a,b,c,d) fwrite(a, b, c, d)
#define STAT_BLK_SIZE(x) ((x).st_blksize)
/*---------------------------------------------------------------------------*/
/* */
/* Misc Macros */
/* */
/*---------------------------------------------------------------------------*/
#if defined(WIN32)
#define GET_CLOCK_COUNT(x) QueryPerformanceCounter((LARGE_INTEGER *)x)
#else
#define GET_CLOCK_COUNT(x) gettimeofday(x, NULL)
#endif
#if defined(WIN32)
#define STRTOULL(x) _atoi64(x)
#else
#define STRTOULL(x) strtoull(x, NULL, 10)
#endif
#if defined(WIN32)
#define SNPRINTF _snprintf
#define PRINTF printf
#define VPRINTF vprintf
#define FPRINTF fprintf
#else
#define SNPRINTF snprintf
#define PRINTF printf
#define VPRINTF vprintf
#define FPRINTF fprintf
#endif
#ifdef __cplusplus
}
#endif
#endif /* __HOST_H__ */

View File

@ -0,0 +1,119 @@
/*---------------------------------------------------------------------------*/
/* */
/* Socket.h - Passive Socket Decleration. */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#ifndef __PASSIVESOCKET_H__
#define __PASSIVESOCKET_H__
#include "ActiveSocket.h"
/// Provides a platform independent class to create a passive socket.
/// A passive socket is used to create a "listening" socket. This type
/// of object would be used when an application needs to wait for
/// inbound connections. Support for CSimpleSocket::SocketTypeTcp,
/// CSimpleSocket::SocketTypeUdp, and CSimpleSocket::SocketTypeRaw is handled
/// in a similar fashion. The big difference is that the method
/// CPassiveSocket::Accept should not be called on the latter two socket
/// types.
class CPassiveSocket : public CSimpleSocket {
public:
CPassiveSocket(CSocketType type = SocketTypeTcp);
virtual ~CPassiveSocket() {
Close();
};
/// Extracts the first connection request on the queue of pending
/// connections and creates a newly connected socket. Used with
/// CSocketType CSimpleSocket::SocketTypeTcp. It is the responsibility of
/// the caller to delete the returned object when finished.
/// @return if successful a pointer to a newly created CActiveSocket object
/// will be returned and the internal error condition of the CPassiveSocket
/// object will be CPassiveSocket::SocketSuccess. If an error condition was encountered
/// the NULL will be returned and one of the following error conditions will be set:
/// CPassiveSocket::SocketEwouldblock, CPassiveSocket::SocketInvalidSocket,
/// CPassiveSocket::SocketConnectionAborted, CPassiveSocket::SocketInterrupted
/// CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketFirewallError
virtual CActiveSocket *Accept(void);
/// Bind to a multicast group on a specified interface, multicast group, and port
///
/// @param pInterface - interface on which to bind.
/// @param pGroup - multicast group address to bind.
/// @param nPort - port on which multicast
/// @return true if able to bind to interface and multicast group.
/// If not successful, the false is returned and one of the following error
/// condiitions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError,
/// CPassiveSocket::SocketInvalidSocket. The following socket errors are for Linux/Unix
/// derived systems only: CPassiveSocket::SocketInvalidSocketBuffer
bool BindMulticast(const char *pInterface, const char *pGroup, uint16 nPort);
/// Create a listening socket at local ip address 'x.x.x.x' or 'localhost'
/// if pAddr is NULL on port nPort.
///
/// @param pAddr specifies the IP address on which to listen.
/// @param nPort specifies the port on which to listen.
/// @param nConnectionBacklog specifies connection queue backlog (default 30,000)
/// @return true if a listening socket was created.
/// If not successful, the false is returned and one of the following error
/// conditions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError,
/// CPassiveSocket::SocketInvalidSocket. The following socket errors are for Linux/Unix
/// derived systems only: CPassiveSocket::SocketInvalidSocketBuffer
virtual bool Listen(const char *pAddr, uint16 nPort, int32 nConnectionBacklog = 30000);
/// Attempts to send a block of data on an established connection.
/// @param pBuf block of data to be sent.
/// @param bytesToSend size of data block to be sent.
/// @return number of bytes actually sent, return of zero means the
/// connection has been shutdown on the other side, and a return of -1
/// means that an error has occurred. If an error was signaled then one
/// of the following error codes will be set: CPassiveSocket::SocketInvalidSocket,
/// CPassiveSocket::SocketEwouldblock, SimpleSocket::SocketConnectionReset,
/// CPassiveSocket::SocketInvalidSocketBuffer, CPassiveSocket::SocketInterrupted,
/// CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketNotconnected
/// <br>\b Note: This function is used only for a socket of type
/// CSimpleSocket::SocketTypeUdp
virtual int32 Send(const uint8 *pBuf, size_t bytesToSend);
private:
struct ip_mreq m_stMulticastRequest; /// group address for multicast
};
#endif // __PASSIVESOCKET_H__

View File

@ -0,0 +1,583 @@
/*---------------------------------------------------------------------------*/
/* */
/* SimpleSocket.h - Simple Socket base class decleration. */
/* */
/* Author : Mark Carrier (mark@carrierlabs.com) */
/* */
/*---------------------------------------------------------------------------*/
/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#if defined(_LINUX) || defined (_DARWIN)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netdb.h>
#endif
#ifdef _LINUX
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if.h>
#include <sys/sendfile.h>
#endif
#ifdef _DARWIN
#include <net/if.h>
#endif
#if defined(_LINUX) || defined (_DARWIN)
#include <sys/time.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#ifdef _WIN32
#include <io.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#define IPTOS_LOWDELAY 0x10
#endif
#include "Host.h"
#include "StatTimer.h"
//-----------------------------------------------------------------------------
// General class macro definitions and typedefs
//-----------------------------------------------------------------------------
#ifndef INVALID_SOCKET
#define INVALID_SOCKET ~(0)
#endif
#define SOCKET_SENDFILE_BLOCKSIZE 8192
/// Provides a platform independent class to for socket development.
/// This class is designed to abstract socket communication development in a
/// platform independent manner.
/// - Socket types
/// -# CActiveSocket Class
/// -# CPassiveSocket Class
class CSimpleSocket {
public:
/// Defines the three possible states for shuting down a socket.
typedef enum
{
Receives = SHUT_RD, ///< Shutdown passive socket.
Sends = SHUT_WR, ///< Shutdown active socket.
Both = SHUT_RDWR ///< Shutdown both active and passive sockets.
} CShutdownMode;
/// Defines the socket types defined by CSimpleSocket class.
typedef enum
{
SocketTypeInvalid, ///< Invalid socket type.
SocketTypeTcp, ///< Defines socket as TCP socket.
SocketTypeUdp, ///< Defines socket as UDP socket.
SocketTypeTcp6, ///< Defines socket as IPv6 TCP socket.
SocketTypeUdp6, ///< Defines socket as IPv6 UDP socket.
SocketTypeRaw ///< Provides raw network protocol access.
} CSocketType;
/// Defines all error codes handled by the CSimpleSocket class.
typedef enum
{
SocketError = -1, ///< Generic socket error translates to error below.
SocketSuccess = 0, ///< No socket error.
SocketInvalidSocket, ///< Invalid socket handle.
SocketInvalidAddress, ///< Invalid destination address specified.
SocketInvalidPort, ///< Invalid destination port specified.
SocketConnectionRefused, ///< No server is listening at remote address.
SocketTimedout, ///< Timed out while attempting operation.
SocketEwouldblock, ///< Operation would block if socket were blocking.
SocketNotconnected, ///< Currently not connected.
SocketEinprogress, ///< Socket is non-blocking and the connection cannot be completed immediately
SocketInterrupted, ///< Call was interrupted by a signal that was caught before a valid connection arrived.
SocketConnectionAborted, ///< The connection has been aborted.
SocketProtocolError, ///< Invalid protocol for operation.
SocketFirewallError, ///< Firewall rules forbid connection.
SocketInvalidSocketBuffer, ///< The receive buffer point outside the process's address space.
SocketConnectionReset, ///< Connection was forcibly closed by the remote host.
SocketAddressInUse, ///< Address already in use.
SocketInvalidPointer, ///< Pointer type supplied as argument is invalid.
SocketEunknown ///< Unknown error please report to mark@carrierlabs.com
} CSocketError;
public:
CSimpleSocket(CSocketType type = SocketTypeTcp);
CSimpleSocket(CSimpleSocket &socket);
virtual ~CSimpleSocket()
{
if (m_pBuffer != NULL)
{
delete [] m_pBuffer;
m_pBuffer = NULL;
}
};
/// Initialize instance of CSocket. This method MUST be called before an
/// object can be used. Errors : CSocket::SocketProtocolError,
/// CSocket::SocketInvalidSocket,
/// @return true if properly initialized.
virtual bool Initialize(void);
/// Close socket
/// @return true if successfully closed otherwise returns false.
virtual bool Close(void);
/// Shutdown shut down socket send and receive operations
/// CShutdownMode::Receives - Disables further receive operations.
/// CShutdownMode::Sends - Disables further send operations.
/// CShutdownBoth:: - Disables further send and receive operations.
/// @param nShutdown specifies the type of shutdown.
/// @return true if successfully shutdown otherwise returns false.
virtual bool Shutdown(CShutdownMode nShutdown);
/// Examine the socket descriptor sets currently owned by the instance of
/// the socket class (the readfds, writefds, and errorfds parameters) to
/// see whether some of their descriptors are ready for reading, are ready
/// for writing, or have an exceptional condition pending, respectively.
/// Block until an event happens on the specified file descriptors.
/// @return true if socket has data ready, or false if not ready or timed out.
virtual bool Select(void) {
return Select(0,0);
};
/// Examine the socket descriptor sets currently owned by the instance of
/// the socket class (the readfds, writefds, and errorfds parameters) to
/// see whether some of their descriptors are ready for reading, are ready
/// for writing, or have an exceptional condition pending, respectively.
/// @param nTimeoutSec timeout in seconds for select.
/// @param nTimeoutUSec timeout in micro seconds for select.
/// @return true if socket has data ready, or false if not ready or timed out.
virtual bool Select(int32 nTimeoutSec, int32 nTimeoutUSec);
/// Does the current instance of the socket object contain a valid socket
/// descriptor.
/// @return true if the socket object contains a valid socket descriptor.
virtual bool IsSocketValid(void) {
return (m_socket != SocketError);
};
/// Provides a standard error code for cross platform development by
/// mapping the operating system error to an error defined by the CSocket
/// class.
void TranslateSocketError(void);
/// Returns a human-readable description of the given error code
/// or the last error code of a socket
static const char *DescribeError(CSocketError err);
inline const char *DescribeError() {
return DescribeError(m_socketErrno);
};
/// Attempts to receive a block of data on an established connection.
/// @param nMaxBytes maximum number of bytes to receive.
/// @param pBuffer, memory where to receive the data,
/// NULL receives to internal buffer returned with GetData()
/// Non-NULL receives directly there, but GetData() will return WRONG ptr!
/// @return number of bytes actually received.
/// @return of zero means the connection has been shutdown on the other side.
/// @return of -1 means that an error has occurred.
virtual int32 Receive(int32 nMaxBytes = 1, uint8 * pBuffer = 0);
/// Attempts to send a block of data on an established connection.
/// @param pBuf block of data to be sent.
/// @param bytesToSend size of data block to be sent.
/// @return number of bytes actually sent.
/// @return of zero means the connection has been shutdown on the other side.
/// @return of -1 means that an error has occurred.
virtual int32 Send(const uint8 *pBuf, size_t bytesToSend);
/// Attempts to send at most nNumItem blocks described by sendVector
/// to the socket descriptor associated with the socket object.
/// @param sendVector pointer to an array of iovec structures
/// @param nNumItems number of items in the vector to process
/// <br>\b NOTE: Buffers are processed in the order specified.
/// @return number of bytes actually sent, return of zero means the
/// connection has been shutdown on the other side, and a return of -1
/// means that an error has occurred.
virtual int32 Send(const struct iovec *sendVector, int32 nNumItems);
/// Copies data between one file descriptor and another.
/// On some systems this copying is done within the kernel, and thus is
/// more efficient than the combination of CSimpleSocket::Send and
/// CSimpleSocket::Receive, which would require transferring data to and
/// from user space.
/// <br>\b Note: This is available on all implementations, but the kernel
/// implementation is only available on Unix type systems.
/// @param nOutFd descriptor opened for writing.
/// @param nInFd descriptor opened for reading.
/// @param pOffset from which to start reading data from input file.
/// @param nCount number of bytes to copy between file descriptors.
/// @return number of bytes written to the out socket descriptor.
virtual int32 SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 nCount);
/// Returns blocking/non-blocking state of socket.
/// @return true if the socket is non-blocking, else return false.
bool IsNonblocking(void) {
return (m_bIsBlocking == false);
};
/// Set the socket to blocking.
/// @return true if successful set to blocking, else return false;
bool SetBlocking(void);
/// Set the socket as non-blocking.
/// @return true if successful set to non-blocking, else return false;
bool SetNonblocking(void);
/// Get a pointer to internal receive buffer. The user MUST not free this
/// pointer when finished. This memory is managed internally by the CSocket
/// class.
/// @return pointer to data if valid, else returns NULL.
uint8 *GetData(void) {
return m_pBuffer;
};
/// Returns the number of bytes received on the last call to
/// CSocket::Receive().
/// @return number of bytes received.
int32 GetBytesReceived(void) {
return m_nBytesReceived;
};
/// Returns the number of bytes sent on the last call to
/// CSocket::Send().
/// @return number of bytes sent.
int32 GetBytesSent(void) {
return m_nBytesSent;
};
/// Controls the actions taken when CSimpleSocket::Close is executed on a
/// socket object that has unsent data. The default value for this option
/// is \b off.
/// - Following are the three possible scenarios.
/// -# \b bEnable is false, CSimpleSocket::Close returns immediately, but
/// any unset data is transmitted (after CSimpleSocket::Close returns)
/// -# \b bEnable is true and \b nTime is zero, CSimpleSocket::Close return
/// immediately and any unsent data is discarded.
/// -# \b bEnable is true and \b nTime is nonzero, CSimpleSocket::Close does
/// not return until all unsent data is transmitted (or the connection is
/// Closed by the remote system).
/// <br><p>
/// @param bEnable true to enable option false to disable option.
/// @param nTime time in seconds to linger.
/// @return true if option successfully set
bool SetOptionLinger(bool bEnable, uint16 nTime);
/// Tells the kernel that even if this port is busy (in the TIME_WAIT state),
/// go ahead and reuse it anyway. If it is busy, but with another state,
/// you will still get an address already in use error.
/// @return true if option successfully set
bool SetOptionReuseAddr();
/// Gets the timeout value that specifies the maximum number of seconds a
/// call to CSimpleSocket::Open waits until it completes.
/// @return the length of time in seconds
int32 GetConnectTimeoutSec(void) {
return m_stConnectTimeout.tv_sec;
};
/// Gets the timeout value that specifies the maximum number of microseconds
/// a call to CSimpleSocket::Open waits until it completes.
/// @return the length of time in microseconds
int32 GetConnectTimeoutUSec(void) {
return m_stConnectTimeout.tv_usec;
};
/// Sets the timeout value that specifies the maximum amount of time a call
/// to CSimpleSocket::Receive waits until it completes. Use the method
/// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
/// If a call to CSimpleSocket::Receive has blocked for the specified length of
/// time without receiving additional data, it returns with a partial count
/// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data
/// were received.
/// @param nConnectTimeoutSec of timeout in seconds.
/// @param nConnectTimeoutUsec of timeout in microseconds.
/// @return true if socket connection timeout was successfully set.
void SetConnectTimeout(int32 nConnectTimeoutSec, int32 nConnectTimeoutUsec = 0)
{
m_stConnectTimeout.tv_sec = nConnectTimeoutSec;
m_stConnectTimeout.tv_usec = nConnectTimeoutUsec;
};
/// Gets the timeout value that specifies the maximum number of seconds a
/// a call to CSimpleSocket::Receive waits until it completes.
/// @return the length of time in seconds
int32 GetReceiveTimeoutSec(void) {
return m_stRecvTimeout.tv_sec;
};
/// Gets the timeout value that specifies the maximum number of microseconds
/// a call to CSimpleSocket::Receive waits until it completes.
/// @return the length of time in microseconds
int32 GetReceiveTimeoutUSec(void) {
return m_stRecvTimeout.tv_usec;
};
/// Sets the timeout value that specifies the maximum amount of time a call
/// to CSimpleSocket::Receive waits until it completes. Use the method
/// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
/// If a call to CSimpleSocket::Receive has blocked for the specified length of
/// time without receiving additional data, it returns with a partial count
/// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data
/// were received.
/// @param nRecvTimeoutSec of timeout in seconds.
/// @param nRecvTimeoutUsec of timeout in microseconds.
/// @return true if socket timeout was successfully set.
bool SetReceiveTimeout(int32 nRecvTimeoutSec, int32 nRecvTimeoutUsec = 0);
/// Enable/disable multicast for a socket. This options is only valid for
/// socket descriptors of type CSimpleSocket::SocketTypeUdp.
/// @return true if multicast was enabled or false if socket type is not
/// CSimpleSocket::SocketTypeUdp and the error will be set to
/// CSimpleSocket::SocketProtocolError
bool SetMulticast(bool bEnable, uint8 multicastTTL = 1);
/// Return true if socket is multicast or false is socket is unicast
/// @return true if multicast is enabled
bool GetMulticast() {
return m_bIsMulticast;
};
/// Bind socket to a specific interface when using multicast.
/// @return true if successfully bound to interface
bool BindInterface(const char *pInterface);
/// Gets the timeout value that specifies the maximum number of seconds a
/// a call to CSimpleSocket::Send waits until it completes.
/// @return the length of time in seconds
int32 GetSendTimeoutSec(void) {
return m_stSendTimeout.tv_sec;
};
/// Gets the timeout value that specifies the maximum number of microseconds
/// a call to CSimpleSocket::Send waits until it completes.
/// @return the length of time in microseconds
int32 GetSendTimeoutUSec(void) {
return m_stSendTimeout.tv_usec;
};
/// Gets the timeout value that specifies the maximum amount of time a call
/// to CSimpleSocket::Send waits until it completes.
/// @return the length of time in seconds
bool SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec = 0);
/// Returns the last error that occured for the instace of the CSimpleSocket
/// instance. This method should be called immediately to retrieve the
/// error code for the failing mehtod call.
/// @return last error that occured.
CSocketError GetSocketError(void) {
return m_socketErrno;
};
/// Get the total time the of the last operation in milliseconds.
/// @return number of milliseconds of last operation.
uint32 GetTotalTimeMs() {
return m_timer.GetMilliSeconds();
};
/// Get the total time the of the last operation in microseconds.
/// @return number of microseconds or last operation.
uint32 GetTotalTimeUsec() {
return m_timer.GetMicroSeconds();
};
/// Return Differentiated Services Code Point (DSCP) value currently set on the socket object.
/// @return DSCP for current socket object.
/// <br><br> \b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
int GetSocketDscp(void);
/// Set Differentiated Services Code Point (DSCP) for socket object.
/// @param nDscp value of TOS setting which will be converted to DSCP
/// @return true if DSCP value was properly set
/// <br><br> \b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
bool SetSocketDscp(int nDscp);
/// Return socket descriptor
/// @return socket descriptor which is a signed 32 bit integer.
SOCKET GetSocketDescriptor() {
return m_socket;
};
/// Return socket descriptor
/// @return socket descriptor which is a signed 32 bit integer.
CSocketType GetSocketType() {
return m_nSocketType;
};
/// Returns clients Internet host address as a string in standard numbers-and-dots notation.
/// @return NULL if invalid
const char *GetClientAddr() {
return inet_ntoa(m_stClientSockaddr.sin_addr);
};
/// Returns the port number on which the client is connected.
/// @return client port number.
uint16 GetClientPort() {
return m_stClientSockaddr.sin_port;
};
/// Returns server Internet host address as a string in standard numbers-and-dots notation.
/// @return NULL if invalid
const char *GetServerAddr() {
return inet_ntoa(m_stServerSockaddr.sin_addr);
};
/// Returns the port number on which the server is connected.
/// @return server port number.
uint16 GetServerPort() {
return ntohs(m_stServerSockaddr.sin_port);
};
/// Get the TCP receive buffer window size for the current socket object.
/// <br><br>\b NOTE: Linux will set the receive buffer to twice the value passed.
/// @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
uint32 GetReceiveWindowSize() {
return GetWindowSize(SO_RCVBUF);
};
/// Get the TCP send buffer window size for the current socket object.
/// <br><br>\b NOTE: Linux will set the send buffer to twice the value passed.
/// @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
uint32 GetSendWindowSize() {
return GetWindowSize(SO_SNDBUF);
};
/// Set the TCP receive buffer window size for the current socket object.
/// <br><br>\b NOTE: Linux will set the receive buffer to twice the value passed.
/// @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
uint32 SetReceiveWindowSize(uint32 nWindowSize) {
return SetWindowSize(SO_RCVBUF, nWindowSize);
};
/// Set the TCP send buffer window size for the current socket object.
/// <br><br>\b NOTE: Linux will set the send buffer to twice the value passed.
/// @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
uint32 SetSendWindowSize(uint32 nWindowSize) {
return SetWindowSize(SO_SNDBUF, nWindowSize);
};
/// Disable the Nagle algorithm (Set TCP_NODELAY to true)
/// @return false if failed to set socket option otherwise return true;
bool DisableNagleAlgoritm();
/// Enable the Nagle algorithm (Set TCP_NODELAY to false)
/// @return false if failed to set socket option otherwise return true;
bool EnableNagleAlgoritm();
protected:
/// Set internal socket error to that specified error
/// @param error type of error
void SetSocketError(CSimpleSocket::CSocketError error) {
m_socketErrno = error;
};
/// Set object socket handle to that specified as parameter
/// @param socket value of socket descriptor
void SetSocketHandle(SOCKET socket) {
m_socket = socket;
};
private:
/// Generic function used to get the send/receive window size
/// @return zero on failure else the number of bytes of the TCP window size if successful.
uint32 GetWindowSize(uint32 nOptionName);
/// Generic function used to set the send/receive window size
/// @return zero on failure else the number of bytes of the TCP window size if successful.
uint32 SetWindowSize(uint32 nOptionName, uint32 nWindowSize);
/// Attempts to send at most nNumItem blocks described by sendVector
/// to the socket descriptor associated with the socket object.
/// @param sendVector pointer to an array of iovec structures
/// @param nNumItems number of items in the vector to process
/// <br>\b Note: This implementation is for systems that don't natively
/// support this functionality.
/// @return number of bytes actually sent, return of zero means the
/// connection has been shutdown on the other side, and a return of -1
/// means that an error has occurred.
int32 Writev(const struct iovec *pVector, size_t nCount);
/// Flush the socket descriptor owned by the object.
/// @return true data was successfully sent, else return false;
bool Flush();
CSimpleSocket *operator=(CSimpleSocket &socket);
protected:
SOCKET m_socket; /// socket handle
CSocketError m_socketErrno; /// number of last error
uint8 *m_pBuffer; /// internal send/receive buffer
int32 m_nBufferSize; /// size of internal send/receive buffer
int32 m_nSocketDomain; /// socket type PF_INET, PF_INET6
CSocketType m_nSocketType; /// socket type - UDP, TCP or RAW
int32 m_nBytesReceived; /// number of bytes received
int32 m_nBytesSent; /// number of bytes sent
uint32 m_nFlags; /// socket flags
bool m_bIsBlocking; /// is socket blocking
bool m_bIsMulticast; /// is the UDP socket multicast;
struct timeval m_stConnectTimeout; /// connection timeout
struct timeval m_stRecvTimeout; /// receive timeout
struct timeval m_stSendTimeout; /// send timeout
struct sockaddr_in m_stServerSockaddr; /// server address
struct sockaddr_in m_stClientSockaddr; /// client address
struct sockaddr_in m_stMulticastGroup; /// multicast group to bind to
struct linger m_stLinger; /// linger flag
CStatTimer m_timer; /// internal statistics.
#ifdef WIN32
WSADATA m_hWSAData; /// Windows
#endif
fd_set m_writeFds; /// write file descriptor set
fd_set m_readFds; /// read file descriptor set
fd_set m_errorFds; /// error file descriptor set
};
#endif /* __SOCKET_H__ */

View File

@ -0,0 +1,114 @@
/*----------------------------------------------------------------------------*/
/* */
/* StatTimer.h: interface for the CStatTimer class. */
/* */
/* Author: Mark Carrier (mark@carrierlabs.com) */
/* */
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2006 CarrierLabs, LLC. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 4. The name "CarrierLabs" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* mark@carrierlabs.com.
*
* THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*----------------------------------------------------------------------------*/
#ifndef __CSTATTIMER_H__
#define __CSTATTIMER_H__
#include <string.h>
#if WIN32
#include <Winsock2.h>
#include <time.h>
#endif
#ifdef _LINUX
#include <stdio.h>
#include <sys/time.h>
#endif
#include "Host.h"
#if defined(WIN32)
#define GET_CLOCK_COUNT(x) QueryPerformanceCounter((LARGE_INTEGER *)x)
#else
#define GET_CLOCK_COUNT(x) gettimeofday(x, NULL)
#endif
#define MILLISECONDS_CONVERSION 1000
#define MICROSECONDS_CONVERSION 1000000
/// Class to abstract socket communications in a cross platform manner.
/// This class is designed
class CStatTimer {
public:
CStatTimer()
{
};
~CStatTimer()
{
};
void Initialize()
{
memset(&m_startTime, 0, sizeof(struct timeval));
memset(&m_endTime, 0, sizeof(struct timeval));
};
struct timeval GetStartTime() { return m_startTime; };
void SetStartTime() { GET_CLOCK_COUNT(&m_startTime); };
struct timeval GetEndTime() { return m_endTime; };
void SetEndTime() { GET_CLOCK_COUNT(&m_endTime); };
uint32 GetMilliSeconds() { return (CalcTotalUSec() / MILLISECONDS_CONVERSION); };
uint32 GetMicroSeconds() { return (CalcTotalUSec()); };
uint32 GetSeconds() { return (CalcTotalUSec() / MICROSECONDS_CONVERSION); };
uint32 GetCurrentTime()
{
struct timeval tmpTime;
GET_CLOCK_COUNT(&tmpTime);
return ((tmpTime.tv_sec * MICROSECONDS_CONVERSION) + tmpTime.tv_usec);
};
private:
uint32 CalcTotalUSec() { return (((m_endTime.tv_sec - m_startTime.tv_sec) * MICROSECONDS_CONVERSION) +
(m_endTime.tv_usec - m_startTime.tv_usec)); };
private:
struct timeval m_startTime;
struct timeval m_endTime;
};
#endif // __CSTATTIMER_H__