diff options
| author | Petr Mrázek | 2012-03-11 13:37:40 +0100 |
|---|---|---|
| committer | Petr Mrázek | 2012-03-11 13:37:40 +0100 |
| commit | 7ef04f1dfc0e66621dafd52201b48ab77cfff770 (patch) | |
| tree | 80fd056a1ab56a30b05b7fadc039d5a8d3b4deaa /src | |
| download | clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.gz clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.bz2 clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.xz | |
import original clsocket files
Diffstat (limited to 'src')
| -rw-r--r-- | src/ActiveSocket.cpp | 314 | ||||
| -rw-r--r-- | src/ActiveSocket.h | 89 | ||||
| -rw-r--r-- | src/HTTPActiveSocket.cpp | 0 | ||||
| -rw-r--r-- | src/HTTPActiveSocket.h | 74 | ||||
| -rwxr-xr-x | src/Host.h | 251 | ||||
| -rw-r--r-- | src/PassiveSocket.cpp | 332 | ||||
| -rw-r--r-- | src/PassiveSocket.h | 117 | ||||
| -rwxr-xr-x | src/SimpleSocket.cpp | 1135 | ||||
| -rwxr-xr-x | src/SimpleSocket.h | 514 | ||||
| -rw-r--r-- | src/StatTimer.h | 114 |
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__ |
