summaryrefslogtreecommitdiff
path: root/src/SimpleSocket.cpp
diff options
context:
space:
mode:
authorPetr Mrázek2012-03-11 13:37:40 +0100
committerPetr Mrázek2012-03-11 13:37:40 +0100
commit7ef04f1dfc0e66621dafd52201b48ab77cfff770 (patch)
tree80fd056a1ab56a30b05b7fadc039d5a8d3b4deaa /src/SimpleSocket.cpp
downloadclsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.gz
clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.bz2
clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.xz
import original clsocket files
Diffstat (limited to 'src/SimpleSocket.cpp')
-rwxr-xr-xsrc/SimpleSocket.cpp1135
1 files changed, 1135 insertions, 0 deletions
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;
+}
+