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/SimpleSocket.h | |
| download | clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.gz clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.bz2 clsocket-7ef04f1dfc0e66621dafd52201b48ab77cfff770.tar.xz | |
import original clsocket files
Diffstat (limited to 'src/SimpleSocket.h')
| -rwxr-xr-x | src/SimpleSocket.h | 514 |
1 files changed, 514 insertions, 0 deletions
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__ */ + |
