summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPetr Mrázek2012-03-11 13:37:40 +0100
committerPetr Mrázek2012-03-11 13:37:40 +0100
commit7ef04f1dfc0e66621dafd52201b48ab77cfff770 (patch)
tree80fd056a1ab56a30b05b7fadc039d5a8d3b4deaa /src
downloadclsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.gz
clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.bz2
clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.xz
import original clsocket files
Diffstat (limited to 'src')
-rw-r--r--src/ActiveSocket.cpp314
-rw-r--r--src/ActiveSocket.h89
-rw-r--r--src/HTTPActiveSocket.cpp0
-rw-r--r--src/HTTPActiveSocket.h74
-rwxr-xr-xsrc/Host.h251
-rw-r--r--src/PassiveSocket.cpp332
-rw-r--r--src/PassiveSocket.h117
-rwxr-xr-xsrc/SimpleSocket.cpp1135
-rwxr-xr-xsrc/SimpleSocket.h514
-rw-r--r--src/StatTimer.h114
10 files changed, 2940 insertions, 0 deletions
diff --git a/src/ActiveSocket.cpp b/src/ActiveSocket.cpp
new file mode 100644
index 0000000..6da25e8
--- /dev/null
+++ b/src/ActiveSocket.cpp
@@ -0,0 +1,314 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* 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 uint8 *pAddr, int16 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 uint8 *pAddr, int16 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 uint8 *pAddr, int16 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 uint8 *pAddr, int16 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;
+}
diff --git a/src/ActiveSocket.h b/src/ActiveSocket.h
new file mode 100644
index 0000000..c38fa5b
--- /dev/null
+++ b/src/ActiveSocket.h
@@ -0,0 +1,89 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* 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 uint8 *pAddr, int16 nPort);
+
+private:
+ /// Utility function used to create a TCP connection, called from Open().
+ /// @return true if successful connection made, otherwise false.
+ bool ConnectTCP(const uint8 *pAddr, int16 nPort);
+
+ /// Utility function used to create a UDP connection, called from Open().
+ /// @return true if successful connection made, otherwise false.
+ bool ConnectUDP(const uint8 *pAddr, int16 nPort);
+
+ /// Utility function used to create a RAW connection, called from Open().
+ /// @return true if successful connection made, otherwise false.
+ bool ConnectRAW(const uint8 *pAddr, int16 nPort);
+
+ private:
+ struct hostent *m_pHE;
+};
+
+#endif /* __ACTIVESOCKET_H__ */
+
diff --git a/src/HTTPActiveSocket.cpp b/src/HTTPActiveSocket.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/HTTPActiveSocket.cpp
diff --git a/src/HTTPActiveSocket.h b/src/HTTPActiveSocket.h
new file mode 100644
index 0000000..0091b15
--- /dev/null
+++ b/src/HTTPActiveSocket.h
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* HTTPActiveSocket.h - Active Socket Decleration */
+/* */
+/* Author : Mark Carrier (mark@carrierlabs.com) */
+/* */
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2010. 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 __HTTPACTIVESOCKET_H__
+#define __HTTPACTIVESOCKET_H__
+
+#include <string>
+#include "ActiveSocket.h"
+
+using namespace std;
+
+/// 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 CHttpActiveSocket : public CActiveSocket {
+
+public:
+ virtual Send(const uint8 *pBuf, size_t bytesToSend);
+ virtual Receive();
+
+private:
+// date
+ string m_szServer;
+// lastmodified
+ int32 m_nContentLength;
+ string m_szHost;
+ string m_szContentType;
+ string m_bConnection;
+ string m_szSetCookie;
+ string m_szLocation;
+ string m_szCacheControl;
+};
+
+#endif // __HTTPACTIVESOCKET_H__ \ No newline at end of file
diff --git a/src/Host.h b/src/Host.h
new file mode 100755
index 0000000..b24d225
--- /dev/null
+++ b/src/Host.h
@@ -0,0 +1,251 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* 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
+ #define UINT8_MAX (UCHAR_MAX)
+ #define UINT16_MAX (USHRT_MAX)
+ #define UINT32_MAX (ULONG_MAX)
+
+ #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((const char *)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((const char *)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__ */
+
diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp
new file mode 100644
index 0000000..1f94390
--- /dev/null
+++ b/src/PassiveSocket.cpp
@@ -0,0 +1,332 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* 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 uint8 *pInterface, const uint8 *pGroup, int16 nPort)
+{
+ bool bRetVal = false;
+#ifdef WIN32
+ ULONG inAddr;
+#else
+ int32 nReuse;
+ in_addr_t inAddr;
+
+ nReuse = IPTOS_LOWDELAY;
+#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((const char *)pInterface)))
+ {
+ m_stMulticastGroup.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else
+ {
+ if ((inAddr = inet_addr((const char *)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((const char *)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 uint8 *pAddr, int16 nPort, int32 nConnectionBacklog)
+{
+ bool bRetVal = false;
+#ifdef WIN32
+ ULONG inAddr;
+#else
+ int32 nReuse;
+ in_addr_t inAddr;
+
+ nReuse = IPTOS_LOWDELAY;
+#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.
+ //--------------------------------------------------------------------------
+#ifdef _LINUX
+ 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((const char *)pAddr)))
+ {
+ m_stServerSockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ else
+ {
+ if ((inAddr = inet_addr((const char *)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)
+ {
+ Close();
+ }
+
+ 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;
+}
diff --git a/src/PassiveSocket.h b/src/PassiveSocket.h
new file mode 100644
index 0000000..b26f284
--- /dev/null
+++ b/src/PassiveSocket.h
@@ -0,0 +1,117 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* 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 uint8 *pInterface, const uint8 *pGroup, int16 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
+ /// condiitions 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 uint8 *pAddr, int16 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__
diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp
new file mode 100755
index 0000000..55d982e
--- /dev/null
+++ b/src/SimpleSocket.cpp
@@ -0,0 +1,1135 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* CSimpleSocket.cpp - CSimpleSocket 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 "SimpleSocket.h"
+
+CSimpleSocket::CSimpleSocket(CSocketType nType) :
+ m_socket(INVALID_SOCKET),
+ m_socketErrno(CSimpleSocket::SocketInvalidSocket),
+ m_pBuffer(NULL), m_nBufferSize(0), m_nSocketDomain(AF_INET),
+ m_nSocketType(SocketTypeInvalid), m_nBytesReceived(-1),
+ m_nBytesSent(-1), m_nFlags(0),
+ m_bIsBlocking(true)
+{
+ SetConnectTimeout(1, 0);
+ memset(&m_stRecvTimeout, 0, sizeof(struct timeval));
+ memset(&m_stSendTimeout, 0, sizeof(struct timeval));
+ memset(&m_stLinger, 0, sizeof(struct linger));
+
+ switch(nType)
+ {
+ //----------------------------------------------------------------------
+ // Declare socket type stream - TCP
+ //----------------------------------------------------------------------
+ case CSimpleSocket::SocketTypeTcp:
+ {
+ m_nSocketDomain = AF_INET;
+ m_nSocketType = CSimpleSocket::SocketTypeTcp;
+ break;
+ }
+ case CSimpleSocket::SocketTypeTcp6:
+ {
+ m_nSocketDomain = AF_INET6;
+ m_nSocketType = CSimpleSocket::SocketTypeTcp6;
+ break;
+ }
+ //----------------------------------------------------------------------
+ // Declare socket type datagram - UDP
+ //----------------------------------------------------------------------
+ case CSimpleSocket::SocketTypeUdp:
+ {
+ m_nSocketDomain = AF_INET;
+ m_nSocketType = CSimpleSocket::SocketTypeUdp;
+ break;
+ }
+ case CSimpleSocket::SocketTypeUdp6:
+ {
+ m_nSocketDomain = AF_INET6;
+ m_nSocketType = CSimpleSocket::SocketTypeUdp6;
+ break;
+ }
+ //----------------------------------------------------------------------
+ // Declare socket type raw Ethernet - Ethernet
+ //----------------------------------------------------------------------
+ case CSimpleSocket::SocketTypeRaw:
+ {
+#ifdef _LINUX
+ m_nSocketDomain = AF_PACKET;
+ m_nSocketType = CSimpleSocket::SocketTypeRaw;
+#endif
+#ifdef WIN32
+ m_nSocketType = CSimpleSocket::SocketTypeInvalid;
+#endif
+ break;
+ }
+ default:
+ m_nSocketType = CSimpleSocket::SocketTypeInvalid;
+ break;
+ }
+}
+
+CSimpleSocket::CSimpleSocket(CSimpleSocket &socket)
+{
+ m_pBuffer = new uint8[socket.m_nBufferSize];
+ m_nBufferSize = socket.m_nBufferSize;
+ memcpy(m_pBuffer, socket.m_pBuffer, socket.m_nBufferSize);
+}
+
+CSimpleSocket *CSimpleSocket::operator=(CSimpleSocket &socket)
+{
+ if (m_nBufferSize != socket.m_nBufferSize)
+ {
+ delete m_pBuffer;
+ m_pBuffer = new uint8[socket.m_nBufferSize];
+ m_nBufferSize = socket.m_nBufferSize;
+ memcpy(m_pBuffer, socket.m_pBuffer, socket.m_nBufferSize);
+ }
+
+ return this;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// Initialize() - Initialize socket class
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::Initialize()
+{
+ errno = CSimpleSocket::SocketSuccess;
+
+#ifdef WIN32
+ //-------------------------------------------------------------------------
+ // Data structure containing general Windows Sockets Info
+ //-------------------------------------------------------------------------
+ memset(&m_hWSAData, 0, sizeof(m_hWSAData));
+ WSAStartup(MAKEWORD(2, 0), &m_hWSAData);
+#endif
+
+ //-------------------------------------------------------------------------
+ // Create the basic Socket Handle
+ //-------------------------------------------------------------------------
+ m_timer.Initialize();
+ m_timer.SetStartTime();
+ m_socket = socket(m_nSocketDomain, m_nSocketType, 0);
+ m_timer.SetEndTime();
+
+ TranslateSocketError();
+
+ return (IsSocketValid());
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// BindInterface()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::BindInterface(uint8 *pInterface)
+{
+ bool bRetVal = false;
+ struct in_addr stInterfaceAddr;
+
+ if (GetMulticast() == true)
+ {
+ if (pInterface)
+ {
+ stInterfaceAddr.s_addr= inet_addr((const char *)pInterface);
+ if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_MULTICAST_IF, &stInterfaceAddr, sizeof(stInterfaceAddr)) == SocketSuccess)
+ {
+ bRetVal = true;
+ }
+ }
+ }
+ else
+ {
+ SetSocketError(CSimpleSocket::SocketProtocolError);
+ }
+
+ return bRetVal;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// SetMulticast()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetMulticast(bool bEnable, uint8 multicastTTL)
+{
+ bool bRetVal = false;
+
+ if (GetSocketType() == CSimpleSocket::SocketTypeUdp)
+ {
+ m_bIsMulticast = bEnable;
+ if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&multicastTTL, sizeof(multicastTTL)) == SocketError)
+ {
+ TranslateSocketError();
+ bRetVal = false;
+ }
+ else
+ {
+ bRetVal = true;
+ }
+ }
+ else
+ {
+ m_socketErrno = CSimpleSocket::SocketProtocolError;
+ }
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetSocketDscp()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetSocketDscp(int32 nDscp)
+{
+ bool bRetVal = true;
+ int32 nTempVal = nDscp;
+
+ nTempVal <<= 4;
+ nTempVal /= 4;
+
+ if (IsSocketValid())
+ {
+ if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_TOS, &nTempVal, sizeof(nTempVal)) == SocketError)
+ {
+ TranslateSocketError();
+ bRetVal = false;
+ }
+ }
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// GetSocketDscp()
+//
+//------------------------------------------------------------------------------
+int32 CSimpleSocket::GetSocketDscp(void)
+{
+ int32 nTempVal = 0;
+ socklen_t nLen = 0;
+
+ if (IsSocketValid())
+ {
+ if (GETSOCKOPT(m_socket, IPPROTO_IP, IP_TOS, &nTempVal, &nLen) == SocketError)
+ {
+ TranslateSocketError();
+ }
+
+ nTempVal *= 4;
+ nTempVal >>= 4;
+ }
+
+ return nTempVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// GetWindowSize()
+//
+//------------------------------------------------------------------------------
+uint16 CSimpleSocket::GetWindowSize(uint32 nOptionName)
+{
+ uint32 nTcpWinSize = 0;
+
+ //-------------------------------------------------------------------------
+ // no socket given, return system default allocate our own new socket
+ //-------------------------------------------------------------------------
+ if (m_socket != CSimpleSocket::SocketError)
+ {
+ socklen_t nLen = sizeof(nTcpWinSize);
+
+ //---------------------------------------------------------------------
+ // query for buffer size
+ //---------------------------------------------------------------------
+ GETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nTcpWinSize, &nLen);
+ TranslateSocketError();
+ }
+ else
+ {
+ SetSocketError(CSimpleSocket::SocketInvalidSocket);
+ }
+
+ return nTcpWinSize;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetWindowSize()
+//
+//------------------------------------------------------------------------------
+uint16 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize)
+{
+ uint32 nRetVal = 0;
+
+ //-------------------------------------------------------------------------
+ // no socket given, return system default allocate our own new socket
+ //-------------------------------------------------------------------------
+ if (m_socket != CSimpleSocket::SocketError)
+ {
+ nRetVal = SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize));
+ TranslateSocketError();
+ }
+ else
+ {
+ SetSocketError(CSimpleSocket::SocketInvalidSocket);
+ }
+
+ return (uint16)nWindowSize;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// DisableNagleAlgorithm()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::DisableNagleAlgoritm()
+{
+ bool bRetVal = false;
+ int32 nTcpNoDelay = 1;
+
+ //----------------------------------------------------------------------
+ // Set TCP NoDelay flag to true
+ //----------------------------------------------------------------------
+ if (SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nTcpNoDelay, sizeof(int32)) == 0)
+ {
+ bRetVal = true;
+ }
+
+ TranslateSocketError();
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// EnableNagleAlgorithm()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::EnableNagleAlgoritm()
+{
+ bool bRetVal = false;
+ int32 nTcpNoDelay = 0;
+
+ //----------------------------------------------------------------------
+ // Set TCP NoDelay flag to false
+ //----------------------------------------------------------------------
+ if (SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nTcpNoDelay, sizeof(int32)) == 0)
+ {
+ bRetVal = true;
+ }
+
+ TranslateSocketError();
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Send() - Send data on a valid socket
+//
+//------------------------------------------------------------------------------
+int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend)
+{
+ SetSocketError(SocketSuccess);
+ m_nBytesSent = 0;
+
+ switch(m_nSocketType)
+ {
+ case CSimpleSocket::SocketTypeTcp:
+ {
+ if (IsSocketValid())
+ {
+ if ((bytesToSend > 0) && (pBuf != NULL))
+ {
+ m_timer.Initialize();
+ m_timer.SetStartTime();
+
+ //---------------------------------------------------------
+ // Check error condition and attempt to resend if call
+ // was interrupted by a signal.
+ //---------------------------------------------------------
+ do
+ {
+ m_nBytesSent = SEND(m_socket, pBuf, bytesToSend, 0);
+ TranslateSocketError();
+ } while (GetSocketError() == CSimpleSocket::SocketInterrupted);
+
+ m_timer.SetEndTime();
+ }
+ }
+ break;
+ }
+ case CSimpleSocket::SocketTypeUdp:
+ {
+ if (IsSocketValid())
+ {
+ if ((bytesToSend > 0) && (pBuf != NULL))
+ {
+ m_timer.Initialize();
+ m_timer.SetStartTime();
+
+ //---------------------------------------------------------
+ // Check error condition and attempt to resend if call
+ // was interrupted by a signal.
+ //---------------------------------------------------------
+ // if (GetMulticast())
+ // {
+ // do
+ // {
+ // m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, (const sockaddr *)&m_stMulticastGroup,
+ // sizeof(m_stMulticastGroup));
+ // TranslateSocketError();
+ // } while (GetSocketError() == CSimpleSocket::SocketInterrupted);
+ // }
+ // else
+ {
+ do
+ {
+ m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, (const sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr));
+ TranslateSocketError();
+ } while (GetSocketError() == CSimpleSocket::SocketInterrupted);
+ }
+
+ m_timer.SetEndTime();
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return m_nBytesSent;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Close() - Close socket and free up any memory allocated for the socket
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::Close(void)
+{
+ bool bRetVal = false;
+
+ //--------------------------------------------------------------------------
+ // delete internal buffer
+ //--------------------------------------------------------------------------
+ if (m_pBuffer != NULL)
+ {
+ delete [] m_pBuffer;
+ m_pBuffer = NULL;
+ }
+
+ //--------------------------------------------------------------------------
+ // if socket handle is currently valid, close and then invalidate
+ //--------------------------------------------------------------------------
+ if (IsSocketValid())
+ {
+ if (CLOSE(m_socket) != CSimpleSocket::SocketError)
+ {
+ m_socket = INVALID_SOCKET;
+ bRetVal = true;
+ }
+ }
+
+ TranslateSocketError();
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Shtudown()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::Shutdown(CShutdownMode nShutdown)
+{
+ CSocketError nRetVal = SocketEunknown;
+
+ nRetVal = (CSocketError)shutdown(m_socket, CSimpleSocket::Sends);
+ TranslateSocketError();
+
+ return (nRetVal == CSimpleSocket::SocketSuccess) ? true: false;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Flush()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::Flush()
+{
+ int32 nTcpNoDelay = 1;
+ int32 nCurFlags = 0;
+ uint8 tmpbuf = 0;
+ bool bRetVal = false;
+
+ //--------------------------------------------------------------------------
+ // Get the current setting of the TCP_NODELAY flag.
+ //--------------------------------------------------------------------------
+ if (GETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nCurFlags, sizeof(int32)) == 0)
+ {
+ //----------------------------------------------------------------------
+ // Set TCP NoDelay flag
+ //----------------------------------------------------------------------
+ if (SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nTcpNoDelay, sizeof(int32)) == 0)
+ {
+ //------------------------------------------------------------------
+ // Send empty byte stream to flush the TCP send buffer
+ //------------------------------------------------------------------
+ if (Send(&tmpbuf, 0) != CSimpleSocket::SocketError)
+ {
+ bRetVal = true;
+ }
+
+ TranslateSocketError();
+ }
+
+ //----------------------------------------------------------------------
+ // Reset the TCP_NODELAY flag to original state.
+ //----------------------------------------------------------------------
+ SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nCurFlags, sizeof(int32));
+ }
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Writev -
+//
+//------------------------------------------------------------------------------
+int32 CSimpleSocket::Writev(const struct iovec *pVector, size_t nCount)
+{
+ int32 nBytes = 0;
+ int32 nBytesSent = 0;
+ int32 i = 0;
+
+ //--------------------------------------------------------------------------
+ // Send each buffer as a separate send, windows does not support this
+ // function call.
+ //--------------------------------------------------------------------------
+ for (i = 0; i < (int32)nCount; i++)
+ {
+ if ((nBytes = Send((uint8 *)pVector[i].iov_base, pVector[i].iov_len)) == CSimpleSocket::SocketError)
+ {
+ break;
+ }
+
+ nBytesSent += nBytes;
+ }
+
+ if (i > 0)
+ {
+ Flush();
+ }
+
+ return nBytesSent;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Send() - Send data on a valid socket via a vector of buffers.
+//
+//------------------------------------------------------------------------------
+int32 CSimpleSocket::Send(const struct iovec *sendVector, int32 nNumItems)
+{
+ SetSocketError(SocketSuccess);
+ m_nBytesSent = 0;
+
+ if ((m_nBytesSent = WRITEV(m_socket, sendVector, nNumItems)) == CSimpleSocket::SocketError)
+ {
+ TranslateSocketError();
+ }
+
+ return m_nBytesSent;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetReceiveTimeout()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetReceiveTimeout(int32 nRecvTimeoutSec, int32 nRecvTimeoutUsec)
+{
+ bool bRetVal = true;
+
+ memset(&m_stRecvTimeout, 0, sizeof(struct timeval));
+
+ m_stRecvTimeout.tv_sec = nRecvTimeoutSec;
+ m_stRecvTimeout.tv_usec = nRecvTimeoutUsec;
+
+ //--------------------------------------------------------------------------
+ // Sanity check to make sure the options are supported!
+ //--------------------------------------------------------------------------
+ if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_RCVTIMEO, &m_stRecvTimeout,
+ sizeof(struct timeval)) == CSimpleSocket::SocketError)
+ {
+ bRetVal = false;
+ TranslateSocketError();
+ }
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetSendTimeout()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec)
+{
+ bool bRetVal = true;
+
+ memset(&m_stSendTimeout, 0, sizeof(struct timeval));
+ m_stSendTimeout.tv_sec = nSendTimeoutSec;
+ m_stSendTimeout.tv_usec = nSendTimeoutUsec;
+
+ //--------------------------------------------------------------------------
+ // Sanity check to make sure the options are supported!
+ //--------------------------------------------------------------------------
+ if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_SNDTIMEO, &m_stSendTimeout,
+ sizeof(struct timeval)) == CSimpleSocket::SocketError)
+ {
+ bRetVal = false;
+ TranslateSocketError();
+ }
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetOptionReuseAddr()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetOptionReuseAddr()
+{
+ bool bRetVal = false;
+ int32 nReuse = IPTOS_LOWDELAY;
+
+ if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nReuse, sizeof(int32)) == 0)
+ {
+ bRetVal = true;
+ }
+
+ TranslateSocketError();
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetOptionLinger()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetOptionLinger(bool bEnable, uint16 nTime)
+{
+ bool bRetVal = false;
+
+ m_stLinger.l_onoff = (bEnable == true) ? 1: 0;
+ m_stLinger.l_linger = nTime;
+
+ if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_LINGER, &m_stLinger, sizeof(m_stLinger)) == 0)
+ {
+ bRetVal = true;
+ }
+
+ TranslateSocketError();
+
+ return bRetVal;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Receive() - Attempts to receive a block of data on an established
+// connection. Data is received in an internal buffer managed
+// by the class. This buffer is only valid until the next call
+// to Receive(), a call to Close(), or until the object goes out
+// of scope.
+//
+//------------------------------------------------------------------------------
+int32 CSimpleSocket::Receive(int32 nMaxBytes)
+{
+ m_nBytesReceived = 0;
+
+ //--------------------------------------------------------------------------
+ // If the socket is invalid then return false.
+ //--------------------------------------------------------------------------
+ if (IsSocketValid() == false)
+ {
+ return m_nBytesReceived;
+ }
+
+ //--------------------------------------------------------------------------
+ // Free existing buffer and allocate a new buffer the size of
+ // nMaxBytes.
+ //--------------------------------------------------------------------------
+ if ((m_pBuffer != NULL) && (nMaxBytes != m_nBufferSize))
+ {
+ delete [] m_pBuffer;
+ m_pBuffer = NULL;
+ }
+
+ //--------------------------------------------------------------------------
+ // Allocate a new internal buffer to receive data.
+ //--------------------------------------------------------------------------
+ if (m_pBuffer == NULL)
+ {
+ m_nBufferSize = nMaxBytes;
+ m_pBuffer = new uint8[nMaxBytes];
+ }
+
+ SetSocketError(SocketSuccess);
+
+ m_timer.Initialize();
+ m_timer.SetStartTime();
+
+ switch (m_nSocketType)
+ {
+ //----------------------------------------------------------------------
+ // If zero bytes are received, then return. If SocketERROR is
+ // received, free buffer and return CSocket::SocketError (-1) to caller.
+ //----------------------------------------------------------------------
+ case CSimpleSocket::SocketTypeTcp:
+ {
+ do
+ {
+ m_nBytesReceived = RECV(m_socket, (m_pBuffer + m_nBytesReceived),
+ nMaxBytes, m_nFlags);
+ TranslateSocketError();
+ } while ((GetSocketError() == CSimpleSocket::SocketInterrupted));
+
+ break;
+ }
+ case CSimpleSocket::SocketTypeUdp:
+ {
+ uint32 srcSize;
+
+ srcSize = sizeof(struct sockaddr_in);
+
+ if (GetMulticast() == true)
+ {
+ do
+ {
+ m_nBytesReceived = RECVFROM(m_socket, m_pBuffer, nMaxBytes, 0,
+ &m_stMulticastGroup, &srcSize);
+ TranslateSocketError();
+ } while (GetSocketError() == CSimpleSocket::SocketInterrupted);
+ }
+ else
+ {
+ do
+ {
+ m_nBytesReceived = RECVFROM(m_socket, m_pBuffer, nMaxBytes, 0,
+ &m_stClientSockaddr, &srcSize);
+ TranslateSocketError();
+ } while (GetSocketError() == CSimpleSocket::SocketInterrupted);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ m_timer.SetEndTime();
+ TranslateSocketError();
+
+ //--------------------------------------------------------------------------
+ // If we encounter an error translate the error code and return. One
+ // possible error code could be EAGAIN (EWOULDBLOCK) if the socket is
+ // non-blocking. This does not mean there is an error, but no data is
+ // yet available on the socket.
+ //--------------------------------------------------------------------------
+ if (m_nBytesReceived == CSimpleSocket::SocketError)
+ {
+ if (m_pBuffer != NULL)
+ {
+ delete [] m_pBuffer;
+ m_pBuffer = NULL;
+ }
+ }
+
+ return m_nBytesReceived;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetNonblocking()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetNonblocking(void)
+{
+ int32 nCurFlags;
+
+#if WIN32
+ nCurFlags = 1;
+
+ if (ioctlsocket(m_socket, FIONBIO, (ULONG *)&nCurFlags) != 0)
+ {
+ TranslateSocketError();
+ return false;
+ }
+#else
+ if ((nCurFlags = fcntl(m_socket, F_GETFL)) < 0)
+ {
+ TranslateSocketError();
+ return false;
+ }
+
+ nCurFlags |= O_NONBLOCK;
+
+ if (fcntl(m_socket, F_SETFL, nCurFlags) != 0)
+ {
+ TranslateSocketError();
+ return false;
+ }
+#endif
+
+ m_bIsBlocking = false;
+
+ return true;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SetBlocking()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::SetBlocking(void)
+{
+ int32 nCurFlags;
+
+#if WIN32
+ nCurFlags = 0;
+
+ if (ioctlsocket(m_socket, FIONBIO, (ULONG *)&nCurFlags) != 0)
+ {
+ return false;
+ }
+#else
+ if ((nCurFlags = fcntl(m_socket, F_GETFL)) < 0)
+ {
+ TranslateSocketError();
+ return false;
+ }
+
+ nCurFlags &= (~O_NONBLOCK);
+
+ if (fcntl(m_socket, F_SETFL, nCurFlags) != 0)
+ {
+ TranslateSocketError();
+ return false;
+ }
+#endif
+ m_bIsBlocking = true;
+
+ return true;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// SendFile() - stands-in for system provided sendfile
+//
+//------------------------------------------------------------------------------
+int32 CSimpleSocket::SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 nCount)
+{
+ int32 nOutCount = CSimpleSocket::SocketError;
+
+ static char szData[SOCKET_SENDFILE_BLOCKSIZE];
+ int32 nInCount = 0;
+
+ if (lseek(nInFd, *pOffset, SEEK_SET) == -1)
+ {
+ return -1;
+ }
+
+ while (nOutCount < nCount)
+ {
+ nInCount = (nCount - nOutCount) < SOCKET_SENDFILE_BLOCKSIZE ? (nCount - nOutCount) : SOCKET_SENDFILE_BLOCKSIZE;
+
+ if ((read(nInFd, szData, nInCount)) != (int32)nInCount)
+ {
+ return -1;
+ }
+
+ if ((SEND(nOutFd, szData, nInCount, 0)) != (int32)nInCount)
+ {
+ return -1;
+ }
+
+ nOutCount += nInCount;
+ }
+
+ *pOffset += nOutCount;
+
+ TranslateSocketError();
+
+ return nOutCount;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// TranslateSocketError() -
+//
+//------------------------------------------------------------------------------
+void CSimpleSocket::TranslateSocketError(void)
+{
+#ifdef _LINUX
+ switch (errno)
+ {
+ case EXIT_SUCCESS:
+ SetSocketError(CSimpleSocket::SocketSuccess);
+ break;
+ case ENOTCONN:
+ SetSocketError(CSimpleSocket::SocketNotconnected);
+ break;
+ case ENOTSOCK:
+ case EBADF:
+ case EACCES:
+ case EAFNOSUPPORT:
+ case EMFILE:
+ case ENFILE:
+ case ENOBUFS:
+ case ENOMEM:
+ case EPROTONOSUPPORT:
+ SetSocketError(CSimpleSocket::SocketInvalidSocket);
+ break;
+ case ECONNREFUSED :
+ SetSocketError(CSimpleSocket::SocketConnectionRefused);
+ break;
+ case ETIMEDOUT:
+ SetSocketError(CSimpleSocket::SocketTimedout);
+ break;
+ case EINPROGRESS:
+ SetSocketError(CSimpleSocket::SocketEinprogress);
+ break;
+ case EWOULDBLOCK:
+ // case EAGAIN:
+ SetSocketError(CSimpleSocket::SocketEwouldblock);
+ break;
+ case EINTR:
+ SetSocketError(CSimpleSocket::SocketInterrupted);
+ break;
+ case ECONNABORTED:
+ SetSocketError(CSimpleSocket::SocketConnectionAborted);
+ break;
+ case EINVAL:
+ case EPROTO:
+ SetSocketError(CSimpleSocket::SocketProtocolError);
+ break;
+ case EPERM:
+ SetSocketError(CSimpleSocket::SocketFirewallError);
+ break;
+ case EFAULT:
+ SetSocketError(CSimpleSocket::SocketInvalidSocketBuffer);
+ break;
+ case ECONNRESET:
+ SetSocketError(CSimpleSocket::SocketConnectionReset);
+ break;
+ case ENOPROTOOPT:
+ SetSocketError(CSimpleSocket::SocketConnectionReset);
+ break;
+ default:
+ SetSocketError(CSimpleSocket::SocketEunknown);
+ break;
+ }
+#endif
+#ifdef WIN32
+ int32 nError = WSAGetLastError();
+ switch (nError)
+ {
+ case EXIT_SUCCESS:
+ SetSocketError(CSimpleSocket::SocketSuccess);
+ break;
+ case WSAEBADF:
+ case WSAENOTCONN:
+ SetSocketError(CSimpleSocket::SocketNotconnected);
+ break;
+ case WSAEINTR:
+ SetSocketError(CSimpleSocket::SocketInterrupted);
+ break;
+ case WSAEACCES:
+ case WSAEAFNOSUPPORT:
+ case WSAEINVAL:
+ case WSAEMFILE:
+ case WSAENOBUFS:
+ case WSAEPROTONOSUPPORT:
+ SetSocketError(CSimpleSocket::SocketInvalidSocket);
+ break;
+ case WSAECONNREFUSED :
+ SetSocketError(CSimpleSocket::SocketConnectionRefused);
+ break;
+ case WSAETIMEDOUT:
+ SetSocketError(CSimpleSocket::SocketTimedout);
+ break;
+ case WSAEINPROGRESS:
+ SetSocketError(CSimpleSocket::SocketEinprogress);
+ break;
+ case WSAECONNABORTED:
+ SetSocketError(CSimpleSocket::SocketConnectionAborted);
+ break;
+ case WSAEWOULDBLOCK:
+ SetSocketError(CSimpleSocket::SocketEwouldblock);
+ break;
+ case WSAENOTSOCK:
+ SetSocketError(CSimpleSocket::SocketInvalidSocket);
+ break;
+ case WSAECONNRESET:
+ SetSocketError(CSimpleSocket::SocketConnectionReset);
+ break;
+ case WSANO_DATA:
+ SetSocketError(CSimpleSocket::SocketInvalidAddress);
+ break;
+ case WSAEADDRINUSE:
+ SetSocketError(CSimpleSocket::SocketAddressInUse);
+ break;
+ case WSAEFAULT:
+ SetSocketError(CSimpleSocket::SocketInvalidPointer);
+ break;
+ default:
+ SetSocketError(CSimpleSocket::SocketEunknown);
+ break;
+ }
+#endif
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Select()
+//
+//------------------------------------------------------------------------------
+bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec)
+{
+ bool bRetVal = false;
+ struct timeval *pTimeout = NULL;
+ struct timeval timeout;
+ int32 nNumDescriptors = -1;
+ int32 nError = 0;
+
+ FD_ZERO(&m_errorFds);
+ FD_ZERO(&m_readFds);
+ FD_ZERO(&m_writeFds);
+ FD_SET(m_socket, &m_errorFds);
+ FD_SET(m_socket, &m_readFds);
+ FD_SET(m_socket, &m_writeFds);
+
+ //---------------------------------------------------------------------
+ // If timeout has been specified then set value, otherwise set timeout
+ // to NULL which will block until a descriptor is ready for read/write
+ // or an error has occurred.
+ //---------------------------------------------------------------------
+ if ((nTimeoutSec > 0) || (nTimeoutUSec > 0))
+ {
+ timeout.tv_sec = nTimeoutSec;
+ timeout.tv_usec = nTimeoutUSec;
+ pTimeout = &timeout;
+ }
+
+ nNumDescriptors = SELECT(m_socket+1, &m_readFds, &m_writeFds, &m_errorFds, pTimeout);
+// nNumDescriptors = SELECT(m_socket+1, &m_readFds, NULL, NULL, pTimeout);
+
+ //----------------------------------------------------------------------
+ // Handle timeout
+ //----------------------------------------------------------------------
+ if (nNumDescriptors == 0)
+ {
+ SetSocketError(CSimpleSocket::SocketTimedout);
+ }
+ //----------------------------------------------------------------------
+ // If a file descriptor (read/write) is set then check the
+ // socket error (SO_ERROR) to see if there is a pending error.
+ //----------------------------------------------------------------------
+ else if ((FD_ISSET(m_socket, &m_readFds)) || (FD_ISSET(m_socket, &m_writeFds)))
+ {
+ int32 nLen = sizeof(nError);
+
+ if (GETSOCKOPT(m_socket, SOL_SOCKET, SO_ERROR, &nError, &nLen) == 0)
+ {
+ errno = nError;
+
+ if (nError == 0)
+ {
+ bRetVal = true;
+ }
+ }
+
+ TranslateSocketError();
+ }
+
+ return bRetVal;
+}
+
diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h
new file mode 100755
index 0000000..bda3ee1
--- /dev/null
+++ b/src/SimpleSocket.h
@@ -0,0 +1,514 @@
+/*---------------------------------------------------------------------------*/
+/* */
+/* 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_packet.h>
+ #include <linux/if_ether.h>
+ #include <linux/if.h>
+ #include <sys/sendfile.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);
+
+ /// Attempts to receive a block of data on an established connection.
+ /// @param nMaxBytes maximum number of bytes to receive.
+ /// @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);
+
+ /// 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(uint8 *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
+ uint8 *GetClientAddr() { return (uint8 *)inet_ntoa(m_stClientSockaddr.sin_addr); };
+
+ /// Returns the port number on which the client is connected.
+ /// @return client port number.
+ int16 GetClientPort() { return m_stClientSockaddr.sin_port; };
+
+ /// Returns server Internet host address as a string in standard numbers-and-dots notation.
+ /// @return NULL if invalid
+ uint8 *GetServerAddr() { return (uint8 *)inet_ntoa(m_stServerSockaddr.sin_addr); };
+
+ /// Returns the port number on which the server is connected.
+ /// @return server port number.
+ int16 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.
+ uint16 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.
+ uint16 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.
+ uint16 SetReceiveWindowSize(uint16 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.
+ uint16 SetSendWindowSize(uint16 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.
+ uint16 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.
+ uint16 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__ */
+
diff --git a/src/StatTimer.h b/src/StatTimer.h
new file mode 100644
index 0000000..b58d59c
--- /dev/null
+++ b/src/StatTimer.h
@@ -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__