├── .gitignore ├── .travis.yml ├── examples ├── EchoServer.cpp ├── QueryDayTime.cpp └── RecvAsync.cpp ├── CMakeLists.txt ├── src ├── ActiveSocket.h ├── StatTimer.h ├── PassiveSocket.h ├── Host.h ├── ActiveSocket.cpp ├── PassiveSocket.cpp ├── SimpleSocket.h └── SimpleSocket.cpp ├── README └── ReleaseNotes /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: cpp 3 | matrix: 4 | include: 5 | - env: GCC_VERSION=4.8 6 | addons: 7 | apt: 8 | packages: 9 | - gcc-4.8-multilib 10 | - g++-4.8-multilib 11 | script: 12 | - mkdir build-travis 13 | - cd build-travis 14 | - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DCLSOCKET_EXAMPLES:BOOL=ON 15 | - make -j3 16 | notifications: 17 | email: false 18 | irc: 19 | channels: 20 | - "chat.freenode.net#dfhack" 21 | on_success: change 22 | on_failure: always 23 | -------------------------------------------------------------------------------- /examples/EchoServer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "PassiveSocket.h" // Include header for active socket object definition 3 | 4 | #define MAX_PACKET 4096 5 | 6 | int main(int argc, char **argv) 7 | { 8 | CPassiveSocket socket; 9 | CActiveSocket *pClient = NULL; 10 | 11 | //-------------------------------------------------------------------------- 12 | // Initialize our socket object 13 | //-------------------------------------------------------------------------- 14 | socket.Initialize(); 15 | 16 | if (!socket.Listen("127.0.0.1", 6789)) 17 | { 18 | std::cerr << socket.DescribeError() << std::endl; 19 | return 1; 20 | } 21 | 22 | while (socket.IsSocketValid()) 23 | { 24 | if ((pClient = socket.Accept()) != NULL) 25 | { 26 | //---------------------------------------------------------------------- 27 | // Receive request from the client. 28 | //---------------------------------------------------------------------- 29 | if (pClient->Receive(MAX_PACKET)) 30 | { 31 | //------------------------------------------------------------------ 32 | // Send response to client and close connection to the client. 33 | //------------------------------------------------------------------ 34 | pClient->Send( pClient->GetData(), pClient->GetBytesReceived() ); 35 | pClient->Close(); 36 | } 37 | 38 | delete pClient; 39 | } 40 | } 41 | 42 | //----------------------------------------------------------------------------- 43 | // Receive request from the client. 44 | //----------------------------------------------------------------------------- 45 | socket.Close(); 46 | 47 | return 1; 48 | } 49 | -------------------------------------------------------------------------------- /examples/QueryDayTime.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "ActiveSocket.h" // Include header for active socket object definition 4 | 5 | int main(int argc, char **argv) 6 | { 7 | CActiveSocket socket; // Instantiate active socket object (defaults to TCP). 8 | char time[50]; 9 | 10 | memset(&time, 0, 50); 11 | 12 | //-------------------------------------------------------------------------- 13 | // Initialize our socket object 14 | //-------------------------------------------------------------------------- 15 | socket.Initialize(); 16 | 17 | //-------------------------------------------------------------------------- 18 | // Create a connection to the time server so that data can be sent 19 | // and received. 20 | //-------------------------------------------------------------------------- 21 | if (socket.Open("time-C.timefreq.bldrdoc.gov", 13)) 22 | { 23 | //---------------------------------------------------------------------- 24 | // Send a requtest the server requesting the current time. 25 | //---------------------------------------------------------------------- 26 | if (socket.Send((const uint8 *)"\n", 1)) 27 | { 28 | //---------------------------------------------------------------------- 29 | // Receive response from the server. 30 | //---------------------------------------------------------------------- 31 | socket.Receive(49); 32 | memcpy(&time, socket.GetData(), 49); 33 | printf("%s\n", time); 34 | 35 | //---------------------------------------------------------------------- 36 | // Close the connection. 37 | //---------------------------------------------------------------------- 38 | socket.Close(); 39 | } 40 | } 41 | 42 | 43 | return 1; 44 | } 45 | -------------------------------------------------------------------------------- /examples/RecvAsync.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "PassiveSocket.h" 3 | 4 | #ifdef WIN32 5 | #include 6 | 7 | // usually defined with #include 8 | static void sleep( unsigned int seconds ) 9 | { 10 | Sleep( seconds * 1000 ); 11 | } 12 | #endif 13 | 14 | #define MAX_PACKET 4096 15 | #define TEST_PACKET "Test Packet" 16 | 17 | struct thread_data 18 | { 19 | const char *pszServerAddr; 20 | short int nPort; 21 | int nNumBytesToReceive; 22 | int nTotalPayloadSize; 23 | }; 24 | 25 | 26 | void *CreateTCPEchoServer(void *param) 27 | { 28 | CPassiveSocket socket; 29 | CActiveSocket *pClient = NULL; 30 | struct thread_data *pData = (struct thread_data *)param; 31 | int nBytesReceived = 0; 32 | 33 | socket.Initialize(); 34 | socket.Listen(pData->pszServerAddr, pData->nPort); 35 | 36 | if ((pClient = socket.Accept()) != NULL) 37 | { 38 | while (nBytesReceived != pData->nTotalPayloadSize) 39 | { 40 | if (nBytesReceived += pClient->Receive(pData->nNumBytesToReceive)) 41 | { 42 | pClient->Send((const uint8 *)pClient->GetData(), pClient->GetBytesReceived()); 43 | } 44 | } 45 | 46 | sleep(100); 47 | 48 | delete pClient; 49 | } 50 | 51 | socket.Close(); 52 | 53 | return NULL; 54 | } 55 | 56 | int main(int argc, char **argv) 57 | { 58 | pthread_t threadId; 59 | struct thread_data thData; 60 | CActiveSocket client; 61 | char result[1024]; 62 | 63 | thData.pszServerAddr = "127.0.0.1"; 64 | thData.nPort = 6789; 65 | thData.nNumBytesToReceive = 1; 66 | thData.nTotalPayloadSize = (int)strlen(TEST_PACKET); 67 | 68 | pthread_create(&threadId, 0, CreateTCPEchoServer, &thData); 69 | sleep(1); // allow a second for the thread to create and listen 70 | 71 | client.Initialize(); 72 | client.SetNonblocking(); 73 | 74 | if (client.Open("127.0.0.1", 6789)) 75 | { 76 | if (client.Send((uint8 *)TEST_PACKET, strlen(TEST_PACKET))) 77 | { 78 | int numBytes = -1; 79 | int bytesReceived = 0; 80 | 81 | client.Select(); 82 | 83 | while (bytesReceived != strlen(TEST_PACKET)) 84 | { 85 | numBytes = client.Receive(MAX_PACKET); 86 | 87 | if (numBytes > 0) 88 | { 89 | bytesReceived += numBytes; 90 | memset(result, 0, 1024); 91 | memcpy(result, client.GetData(), numBytes); 92 | printf("received %d bytes: '%s'\n", numBytes, result); 93 | } 94 | else 95 | { 96 | printf("Received %d bytes\n", numBytes); 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | project(clsocket) 3 | 4 | # set up versioning. 5 | set(BUILD_MAJOR "1") 6 | set(BUILD_MINOR "4") 7 | set(BUILD_VERSION "3") 8 | set(BUILD_VERSION ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_VERSION}) 9 | 10 | include_directories(src) 11 | 12 | SET(CLSOCKET_HEADERS 13 | src/ActiveSocket.h 14 | src/Host.h 15 | src/PassiveSocket.h 16 | src/SimpleSocket.h 17 | src/StatTimer.h 18 | ) 19 | 20 | SET(CLSOCKET_SOURCES 21 | src/SimpleSocket.cpp 22 | src/ActiveSocket.cpp 23 | src/PassiveSocket.cpp 24 | ) 25 | 26 | # mark headers as headers... 27 | SET_SOURCE_FILES_PROPERTIES( ${CLSOCKET_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE ) 28 | # append to sources so that dependency checks work on headers 29 | LIST(APPEND CLSOCKET_SOURCES ${CLSOCKET_HEADERS}) 30 | 31 | # OS and compiler checks. 32 | if(UNIX) 33 | # linux / normal unix 34 | add_definitions(-D_LINUX) 35 | if(CYGWIN) 36 | # Special Cygwin stuff here 37 | elseif(APPLE) 38 | # Special Apple stuff here 39 | remove_definitions(-D_LINUX) 40 | add_definitions(-D_DARWIN) 41 | endif() 42 | elseif(WIN32) 43 | add_definitions(-DWIN32) 44 | SET(PROJECT_LIBS Ws2_32.lib) 45 | if(MINGW) 46 | # Special MINGW stuff here 47 | elseif(MSVC) 48 | # Special MSVC stuff here 49 | add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) 50 | else() 51 | # No idea what it is, but there's a good chance it's too weird. 52 | MESSAGE( FATAL_ERROR "Using unknown WIN32 compiler... NOT. Please add to build system." ) 53 | endif() 54 | endif() 55 | 56 | OPTION(CLSOCKET_SHARED "Build clsocket lib as shared." ON) 57 | OPTION(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependency." OFF) 58 | 59 | # make the lib 60 | if(CLSOCKET_SHARED) 61 | if(CLSOCKET_DEP_ONLY) 62 | ADD_LIBRARY(clsocket SHARED EXCLUDE_FROM_ALL ${CLSOCKET_SOURCES}) 63 | else() 64 | ADD_LIBRARY(clsocket SHARED ${CLSOCKET_SOURCES}) 65 | endif() 66 | else() 67 | if(CLSOCKET_DEP_ONLY) 68 | ADD_LIBRARY(clsocket STATIC EXCLUDE_FROM_ALL ${CLSOCKET_SOURCES}) 69 | else() 70 | ADD_LIBRARY(clsocket STATIC ${CLSOCKET_SOURCES}) 71 | endif() 72 | endif() 73 | TARGET_LINK_LIBRARIES(clsocket ${PROJECT_LIBS}) 74 | TARGET_INCLUDE_DIRECTORIES(clsocket PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) 75 | 76 | # install into configured prefix 77 | if(NOT CLSOCKET_DEP_ONLY) 78 | install(TARGETS clsocket ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) 79 | install(FILES ${CLSOCKET_HEADERS} DESTINATION include) 80 | else() 81 | 82 | endif() 83 | 84 | set_target_properties(clsocket PROPERTIES VERSION ${BUILD_VERSION} 85 | SOVERSION ${BUILD_MAJOR}) 86 | 87 | if(UNIX) 88 | OPTION(CLSOCKET_EXAMPLES "Build the examples" OFF) 89 | 90 | if(CLSOCKET_EXAMPLES) 91 | ADD_EXECUTABLE(clsocket-example examples/RecvAsync.cpp) 92 | TARGET_LINK_LIBRARIES(clsocket-example clsocket pthread) 93 | if(NOT CLSOCKET_DEP_ONLY) 94 | install(TARGETS clsocket-example DESTINATION bin) 95 | endif() 96 | 97 | ADD_EXECUTABLE(querydaytime-example examples/QueryDayTime.cpp) 98 | TARGET_LINK_LIBRARIES(querydaytime-example clsocket) 99 | 100 | ADD_EXECUTABLE(echoserver-example examples/EchoServer.cpp) 101 | TARGET_LINK_LIBRARIES(echoserver-example clsocket) 102 | endif() 103 | endif() 104 | 105 | -------------------------------------------------------------------------------- /src/ActiveSocket.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* ActiveSocket.h - Active Socket Decleration */ 4 | /* */ 5 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*---------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #ifndef __ACTIVESOCKET_H__ 44 | #define __ACTIVESOCKET_H__ 45 | 46 | #include "SimpleSocket.h" 47 | 48 | class CPassiveSocket; 49 | 50 | /// Provides a platform independent class to create an active socket. 51 | /// An active socket is used to create a socket which connects to a server. 52 | /// This type of object would be used when an application needs to send/receive 53 | /// data from a server. 54 | class EXPORT CActiveSocket : public CSimpleSocket { 55 | public: 56 | friend class CPassiveSocket; 57 | 58 | CActiveSocket(CSocketType type = SocketTypeTcp); 59 | virtual ~CActiveSocket() { 60 | Close(); 61 | }; 62 | 63 | /// Established a connection to the address specified by pAddr. 64 | /// Connection-based protocol sockets (CSocket::SocketTypeTcp) may 65 | /// successfully call Open() only once, however; connectionless protocol 66 | /// sockets (CSocket::SocketTypeUdp) may use Open() multiple times to 67 | /// change their association. 68 | /// @param pAddr specifies the destination address to connect. 69 | /// @param nPort specifies the destination port. 70 | /// @return true if successful connection made, otherwise false. 71 | virtual bool Open(const char *pAddr, uint16 nPort); 72 | 73 | private: 74 | /// Utility function used to create a TCP connection, called from Open(). 75 | /// @return true if successful connection made, otherwise false. 76 | bool ConnectTCP(const char *pAddr, uint16 nPort); 77 | 78 | /// Utility function used to create a UDP connection, called from Open(). 79 | /// @return true if successful connection made, otherwise false. 80 | bool ConnectUDP(const char *pAddr, uint16 nPort); 81 | 82 | /// Utility function used to create a RAW connection, called from Open(). 83 | /// @return true if successful connection made, otherwise false. 84 | bool ConnectRAW(const char *pAddr, uint16 nPort); 85 | 86 | private: 87 | struct hostent *m_pHE; 88 | }; 89 | 90 | #endif /* __ACTIVESOCKET_H__ */ 91 | 92 | -------------------------------------------------------------------------------- /src/StatTimer.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------*/ 2 | /* */ 3 | /* StatTimer.h: interface for the CStatTimer class. */ 4 | /* */ 5 | /* Author: Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*----------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2006 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #ifndef __CSTATTIMER_H__ 44 | #define __CSTATTIMER_H__ 45 | 46 | #include 47 | 48 | #if WIN32 49 | #include 50 | #include 51 | #endif 52 | 53 | #ifdef _LINUX 54 | #include 55 | #include 56 | #endif 57 | 58 | #include "Host.h" 59 | 60 | #if defined(WIN32) 61 | #define GET_CLOCK_COUNT(x) QueryPerformanceCounter((LARGE_INTEGER *)x) 62 | #else 63 | #define GET_CLOCK_COUNT(x) gettimeofday(x, NULL) 64 | #endif 65 | 66 | #define MILLISECONDS_CONVERSION 1000 67 | #define MICROSECONDS_CONVERSION 1000000 68 | 69 | /// Class to abstract socket communications in a cross platform manner. 70 | /// This class is designed 71 | class EXPORT CStatTimer { 72 | public: 73 | CStatTimer() 74 | { 75 | }; 76 | 77 | ~CStatTimer() 78 | { 79 | }; 80 | 81 | void Initialize() 82 | { 83 | memset(&m_startTime, 0, sizeof(struct timeval)); 84 | memset(&m_endTime, 0, sizeof(struct timeval)); 85 | }; 86 | 87 | struct timeval GetStartTime() { return m_startTime; }; 88 | void SetStartTime() { GET_CLOCK_COUNT(&m_startTime); }; 89 | 90 | struct timeval GetEndTime() { return m_endTime; }; 91 | void SetEndTime() { GET_CLOCK_COUNT(&m_endTime); }; 92 | 93 | uint32 GetMilliSeconds() { return (CalcTotalUSec() / MILLISECONDS_CONVERSION); }; 94 | uint32 GetMicroSeconds() { return (CalcTotalUSec()); }; 95 | uint32 GetSeconds() { return (CalcTotalUSec() / MICROSECONDS_CONVERSION); }; 96 | 97 | uint32 GetCurrentTime() 98 | { 99 | struct timeval tmpTime; 100 | GET_CLOCK_COUNT(&tmpTime); 101 | return ((tmpTime.tv_sec * MICROSECONDS_CONVERSION) + tmpTime.tv_usec); 102 | }; 103 | 104 | private: 105 | uint32 CalcTotalUSec() { return (((m_endTime.tv_sec - m_startTime.tv_sec) * MICROSECONDS_CONVERSION) + 106 | (m_endTime.tv_usec - m_startTime.tv_usec)); }; 107 | 108 | 109 | private: 110 | struct timeval m_startTime; 111 | struct timeval m_endTime; 112 | }; 113 | 114 | #endif // __CSTATTIMER_H__ 115 | -------------------------------------------------------------------------------- /src/PassiveSocket.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* Socket.h - Passive Socket Decleration. */ 4 | /* */ 5 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*---------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #ifndef __PASSIVESOCKET_H__ 44 | #define __PASSIVESOCKET_H__ 45 | #include "ActiveSocket.h" 46 | 47 | /// Provides a platform independent class to create a passive socket. 48 | /// A passive socket is used to create a "listening" socket. This type 49 | /// of object would be used when an application needs to wait for 50 | /// inbound connections. Support for CSimpleSocket::SocketTypeTcp, 51 | /// CSimpleSocket::SocketTypeUdp, and CSimpleSocket::SocketTypeRaw is handled 52 | /// in a similar fashion. The big difference is that the method 53 | /// CPassiveSocket::Accept should not be called on the latter two socket 54 | /// types. 55 | class EXPORT CPassiveSocket : public CSimpleSocket { 56 | public: 57 | CPassiveSocket(CSocketType type = SocketTypeTcp); 58 | virtual ~CPassiveSocket() { 59 | Close(); 60 | }; 61 | 62 | /// Extracts the first connection request on the queue of pending 63 | /// connections and creates a newly connected socket. Used with 64 | /// CSocketType CSimpleSocket::SocketTypeTcp. It is the responsibility of 65 | /// the caller to delete the returned object when finished. 66 | /// @return if successful a pointer to a newly created CActiveSocket object 67 | /// will be returned and the internal error condition of the CPassiveSocket 68 | /// object will be CPassiveSocket::SocketSuccess. If an error condition was encountered 69 | /// the NULL will be returned and one of the following error conditions will be set: 70 | /// CPassiveSocket::SocketEwouldblock, CPassiveSocket::SocketInvalidSocket, 71 | /// CPassiveSocket::SocketConnectionAborted, CPassiveSocket::SocketInterrupted 72 | /// CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketFirewallError 73 | virtual CActiveSocket *Accept(void); 74 | 75 | /// Bind to a multicast group on a specified interface, multicast group, and port 76 | /// 77 | /// @param pInterface - interface on which to bind. 78 | /// @param pGroup - multicast group address to bind. 79 | /// @param nPort - port on which multicast 80 | /// @return true if able to bind to interface and multicast group. 81 | /// If not successful, the false is returned and one of the following error 82 | /// condiitions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, 83 | /// CPassiveSocket::SocketInvalidSocket. The following socket errors are for Linux/Unix 84 | /// derived systems only: CPassiveSocket::SocketInvalidSocketBuffer 85 | bool BindMulticast(const char *pInterface, const char *pGroup, uint16 nPort); 86 | 87 | /// Create a listening socket at local ip address 'x.x.x.x' or 'localhost' 88 | /// if pAddr is NULL on port nPort. 89 | /// 90 | /// @param pAddr specifies the IP address on which to listen. 91 | /// @param nPort specifies the port on which to listen. 92 | /// @param nConnectionBacklog specifies connection queue backlog (default 30,000) 93 | /// @return true if a listening socket was created. 94 | /// If not successful, the false is returned and one of the following error 95 | /// conditions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, 96 | /// CPassiveSocket::SocketInvalidSocket. The following socket errors are for Linux/Unix 97 | /// derived systems only: CPassiveSocket::SocketInvalidSocketBuffer 98 | virtual bool Listen(const char *pAddr, uint16 nPort, int32 nConnectionBacklog = 30000); 99 | 100 | /// Attempts to send a block of data on an established connection. 101 | /// @param pBuf block of data to be sent. 102 | /// @param bytesToSend size of data block to be sent. 103 | /// @return number of bytes actually sent, return of zero means the 104 | /// connection has been shutdown on the other side, and a return of -1 105 | /// means that an error has occurred. If an error was signaled then one 106 | /// of the following error codes will be set: CPassiveSocket::SocketInvalidSocket, 107 | /// CPassiveSocket::SocketEwouldblock, SimpleSocket::SocketConnectionReset, 108 | /// CPassiveSocket::SocketInvalidSocketBuffer, CPassiveSocket::SocketInterrupted, 109 | /// CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketNotconnected 110 | ///
\b Note: This function is used only for a socket of type 111 | /// CSimpleSocket::SocketTypeUdp 112 | virtual int32 Send(const uint8 *pBuf, size_t bytesToSend); 113 | 114 | private: 115 | struct ip_mreq m_stMulticastRequest; /// group address for multicast 116 | 117 | }; 118 | 119 | #endif // __PASSIVESOCKET_H__ 120 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------------ 2 | * History 3 | ------------------------------------------------------------------------------------------ 4 | Written by Mark Carrier to provide a mechanism for writing cross platform socket code. This library was originally written to only support blocking TCP sockets. Over the years it has been extended to support UDP and RAW sockets as well. This is the first official release of the library and the following functionality is supported: 5 | 6 | * Cross platform socket support. 7 | o Windows 95, Windows 98, Windows XP 8 | o Linux, Unix 9 | o Macintosh OSX 10 | * Support for sychronious, and asychronious sockets 11 | * Supports TCP Streams 12 | * Supports UDP Datagrams 13 | * Supports Raw Sockets 14 | * Thread Safe 15 | * Signal Safe 16 | 17 | ------------------------------------------------------------------------------------------ 18 | * Building and Installing 19 | ------------------------------------------------------------------------------------------ 20 | This is a very small library and is very easy to build and configure. To build and install 21 | make sure you are logged in as a user who has access to the recommend GNU installation 22 | directories. Then type 23 | 24 | make -BUILD=Release && make install 25 | 26 | That is it now you are off and running. 27 | 28 | NOTE: When using the library with WINDOWS you must define _WIN32 and when using with LINUX 29 | you must define _LINUX. 30 | 31 | ------------------------------------------------------------------------------------------ 32 | * SimpleSocket Class Overview 33 | ------------------------------------------------------------------------------------------ 34 | Network communications via sockets can be abstracted into two categories of functionality; the active socket and the passive socket. The active socket object initiates a connection with a known host, whereas the passive socket object waits (or listens) for inbound requests for communication. The functionality of both objects is identical as far as sending and receiving data. This library makes distinction between the two objects because the operations for constructing and destructing the two are different. 35 | 36 | This library is different from other socket libraries which define TCP sockets, UDP sockets, HTTP sockets, etc. The reason is the operations required for TCP, UDP, and RAW network communication is identical from a logical stand point. Thus a program could initially be written employing TCP streams, and then at some future point it could be discovered that UDP datagrams would satisify the solution. Changing between the two transport protocols would only require changing how the object is instantiated. The remaining code would in theory require minimal to no changes. 37 | 38 | This library avoids abstractions like HTTP socket, or SMTP socket, soley because this type of object mixes the application and the transport layer. These types of abstractions can be created using this library as a base class. 39 | 40 | The simple socket library is comprised of two class which can be used to represent all socket communications. 41 | 42 | * Active Socket Class 43 | * Passive Socket Class 44 | 45 | 46 | ------------------------------------------------------------------------------------------ 47 | * SimpleSocket Class Examples 48 | ------------------------------------------------------------------------------------------ 49 | When operating on a socket object most methods will return true or false 50 | Simple Active Socket 51 | As mentioned previously the active socket (CActiveSocket) is used to initiate a connections with a server on some known port. So you want to connect to an existing server... 52 | 53 | How do you do it? 54 | 55 | There are many ways using the existing Berkley Socket API, but the goal of this class is to remove the many calls and man page lookups and replace them with clear, concise set of methods which allow a developer to focus on the logic of network programming. 56 | 57 | The following code will connect to a DAYTIME server on port 13, query for the current time, and close the socket. 58 | 59 | #include 60 | #include "ActiveSocket.h" // Include header for active socket object definition 61 | 62 | int main(int argc, char **argv) 63 | { 64 | CActiveSocket socket; // Instantiate active socket object (defaults to TCP). 65 | char time[50]; 66 | 67 | memset(&time, 0, 50); 68 | 69 | //-------------------------------------------------------------------------- 70 | // Initialize our socket object 71 | //-------------------------------------------------------------------------- 72 | socket.Initialize(); 73 | 74 | //-------------------------------------------------------------------------- 75 | // Create a connection to the time server so that data can be sent 76 | // and received. 77 | //-------------------------------------------------------------------------- 78 | if (socket.Open("time-C.timefreq.bldrdoc.gov", 13)) 79 | { 80 | //---------------------------------------------------------------------- 81 | // Send a requtest the server requesting the current time. 82 | //---------------------------------------------------------------------- 83 | if (socket.Send((const uint8 *)"\n", 1)) 84 | { 85 | //---------------------------------------------------------------------- 86 | // Receive response from the server. 87 | //---------------------------------------------------------------------- 88 | socket.Receive(49); 89 | memcpy(&time, socket.GetData(), 49); 90 | printf("%s\n", time); 91 | 92 | //---------------------------------------------------------------------- 93 | // Close the connection. 94 | //---------------------------------------------------------------------- 95 | socket.Close(); 96 | } 97 | } 98 | 99 | 100 | return 1; 101 | } 102 | 103 | You can see that the amount of code required to an object for network communciation is very small and simple. 104 | Simple Passive Socket 105 | Now you want to build a server. 106 | 107 | How do you do it? 108 | 109 | For a practical test lets build an echo server. The server will listen on port 6789 an repsond back with what ever has been sent to the server. 110 | 111 | #include 112 | #include "PassiveSocket.h" // Include header for active socket object definition 113 | 114 | #define MAX_PACKET 4096 115 | 116 | int main(int argc, char **argv) 117 | { 118 | CPassiveSocket socket; 119 | CActiveSocket *pClient = NULL; 120 | 121 | //-------------------------------------------------------------------------- 122 | // Initialize our socket object 123 | //-------------------------------------------------------------------------- 124 | socket.Initialize(); 125 | 126 | if (!socket.Listen("127.0.0.1", 6789)) 127 | { 128 | std::cerr << socket.DescribeError() << std::endl; 129 | return 1; 130 | } 131 | 132 | while (socket.IsSocketValid()) 133 | { 134 | if ((pClient = socket.Accept()) != NULL) 135 | { 136 | //---------------------------------------------------------------------- 137 | // Receive request from the client. 138 | //---------------------------------------------------------------------- 139 | if (pClient->Receive(MAX_PACKET)) 140 | { 141 | //------------------------------------------------------------------ 142 | // Send response to client and close connection to the client. 143 | //------------------------------------------------------------------ 144 | pClient->Send( pClient->GetData(), pClient->GetBytesReceived() ); 145 | pClient->Close(); 146 | } 147 | 148 | delete pClient; 149 | } 150 | } 151 | 152 | //----------------------------------------------------------------------------- 153 | // Receive request from the client. 154 | //----------------------------------------------------------------------------- 155 | socket.Close(); 156 | 157 | return 1; 158 | } 159 | -------------------------------------------------------------------------------- /src/Host.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* Host.h - Basic header file to provide cross-platform solutions via */ 4 | /* macros, conditional compilation, etc. */ 5 | /* */ 6 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 7 | /* */ 8 | /*---------------------------------------------------------------------------*/ 9 | /* Copyright (c) 2007 CarrierLabs, LLC. All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 18 | * 2. Redistributions in binary form must reproduce the above copyright 19 | * notice, this list of conditions and the following disclaimer in 20 | * the documentation and/or other materials provided with the 21 | * distribution. 22 | * 23 | * 3. The name of the author may not be used to endorse or promote products 24 | * derived from this software without specific prior written permission. 25 | * 26 | * 4. The name "CarrierLabs" must not be used to 27 | * endorse or promote products derived from this software without 28 | * prior written permission. For written permission, please contact 29 | * mark@carrierlabs.com. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 32 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 35 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 37 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 38 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 41 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 42 | * OF THE POSSIBILITY OF SUCH DAMAGE. 43 | *----------------------------------------------------------------------------*/ 44 | #ifndef __HOST_H__ 45 | #define __HOST_H__ 46 | 47 | #include 48 | 49 | #ifdef __cplusplus 50 | extern "C" 51 | { 52 | #endif 53 | 54 | /*---------------------------------------------------------------------------*/ 55 | /* */ 56 | /* Type Definition Macros */ 57 | /* */ 58 | /*---------------------------------------------------------------------------*/ 59 | #ifndef __WORDSIZE 60 | /* Assume 32 */ 61 | #define __WORDSIZE 32 62 | #endif 63 | 64 | #if defined(_LINUX) || defined(_DARWIN) 65 | typedef unsigned char uint8; 66 | typedef char int8; 67 | typedef unsigned short uint16; 68 | typedef short int16; 69 | typedef unsigned int uint32; 70 | typedef int int32; 71 | typedef int SOCKET; 72 | #endif 73 | 74 | #ifdef WIN32 75 | struct iovec { 76 | void *iov_base; 77 | size_t iov_len; 78 | }; 79 | 80 | typedef unsigned char uint8; 81 | typedef char int8; 82 | typedef unsigned short uint16; 83 | typedef short int16; 84 | typedef unsigned int uint32; 85 | typedef int int32; 86 | #endif 87 | 88 | #ifdef WIN32 89 | typedef int socklen_t; 90 | #endif 91 | 92 | #if defined(WIN32) 93 | typedef unsigned long long int uint64; 94 | typedef long long int int64; 95 | #elif (__WORDSIZE == 32) 96 | __extension__ 97 | typedef long long int int64; 98 | __extension__ 99 | typedef unsigned long long int uint64; 100 | #elif (__WORDSIZE == 64) 101 | typedef unsigned long int uint64; 102 | typedef long int int64; 103 | #endif 104 | 105 | #ifdef WIN32 106 | 107 | #ifndef UINT8_MAX 108 | #define UINT8_MAX (UCHAR_MAX) 109 | #endif 110 | #ifndef UINT16_MAX 111 | #define UINT16_MAX (USHRT_MAX) 112 | #endif 113 | #ifndef UINT32_MAX 114 | #define UINT32_MAX (ULONG_MAX) 115 | #endif 116 | 117 | #if __WORDSIZE == 64 118 | #define SIZE_MAX (18446744073709551615UL) 119 | #else 120 | #ifndef SIZE_MAX 121 | #define SIZE_MAX (4294967295U) 122 | #endif 123 | #endif 124 | #endif 125 | 126 | #if defined(WIN32) 127 | #define ssize_t size_t 128 | #endif 129 | 130 | #ifndef TRUE 131 | #define TRUE 1 132 | #endif 133 | 134 | #ifndef FALSE 135 | #define FALSE 0 136 | #endif 137 | 138 | #ifndef htonll 139 | #ifdef _BIG_ENDIAN 140 | #define htonll(x) (x) 141 | #define ntohll(x) (x) 142 | #else 143 | #define htonll(x) ((((uint64)htonl(x)) << 32) + htonl(x >> 32)) 144 | #define ntohll(x) ((((uint64)ntohl(x)) << 32) + ntohl(x >> 32)) 145 | #endif 146 | #endif 147 | 148 | /*---------------------------------------------------------------------------*/ 149 | /* */ 150 | /* Socket Macros */ 151 | /* */ 152 | /*---------------------------------------------------------------------------*/ 153 | #ifdef WIN32 154 | #define SHUT_RD 0 155 | #define SHUT_WR 1 156 | #define SHUT_RDWR 2 157 | #define ACCEPT(a,b,c) accept(a,b,c) 158 | #define CONNECT(a,b,c) connect(a,b,c) 159 | #define CLOSE(a) closesocket(a) 160 | #define READ(a,b,c) read(a,b,c) 161 | #define RECV(a,b,c,d) recv(a, (char *)b, c, d) 162 | #define RECVFROM(a,b,c,d,e,f) recvfrom(a, (char *)b, c, d, (sockaddr *)e, (int *)f) 163 | #define RECV_FLAGS MSG_WAITALL 164 | #define SELECT(a,b,c,d,e) select((int32)a,b,c,d,e) 165 | #define SEND(a,b,c,d) send(a, (const char *)b, (int)c, d) 166 | #define SENDTO(a,b,c,d,e,f) sendto(a, (const char *)b, (int)c, d, e, f) 167 | #define SEND_FLAGS 0 168 | #define SENDFILE(a,b,c,d) sendfile(a, b, c, d) 169 | #define SET_SOCKET_ERROR(x,y) errno=y 170 | #define SOCKET_ERROR_INTERUPT EINTR 171 | #define SOCKET_ERROR_TIMEDOUT EAGAIN 172 | #define WRITE(a,b,c) write(a,b,c) 173 | #define WRITEV(a,b,c) Writev(b, c) 174 | #define GETSOCKOPT(a,b,c,d,e) getsockopt(a,b,c,(char *)d, (int *)e) 175 | #define SETSOCKOPT(a,b,c,d,e) setsockopt(a,b,c,(char *)d, (int)e) 176 | #define GETHOSTBYNAME(a) gethostbyname(a) 177 | #endif 178 | 179 | #if defined(_LINUX) || defined(_DARWIN) 180 | #define ACCEPT(a,b,c) accept(a,b,c) 181 | #define CONNECT(a,b,c) connect(a,b,c) 182 | #define CLOSE(a) close(a) 183 | #define READ(a,b,c) read(a,b,c) 184 | #define RECV(a,b,c,d) recv(a, (void *)b, c, d) 185 | #define RECVFROM(a,b,c,d,e,f) recvfrom(a, (char *)b, c, d, (sockaddr *)e, f) 186 | #define RECV_FLAGS MSG_WAITALL 187 | #define SELECT(a,b,c,d,e) select(a,b,c,d,e) 188 | #define SEND(a,b,c,d) send(a, (const int8 *)b, c, d) 189 | #define SENDTO(a,b,c,d,e,f) sendto(a, (const int8 *)b, c, d, e, f) 190 | #define SEND_FLAGS 0 191 | #define SENDFILE(a,b,c,d) sendfile(a, b, c, d) 192 | #define SET_SOCKET_ERROR(x,y) errno=y 193 | #define SOCKET_ERROR_INTERUPT EINTR 194 | #define SOCKET_ERROR_TIMEDOUT EAGAIN 195 | #define WRITE(a,b,c) write(a,b,c) 196 | #define WRITEV(a,b,c) writev(a, b, c) 197 | #define GETSOCKOPT(a,b,c,d,e) getsockopt((int)a,(int)b,(int)c,(void *)d,(socklen_t *)e) 198 | #define SETSOCKOPT(a,b,c,d,e) setsockopt((int)a,(int)b,(int)c,(const void *)d,(int)e) 199 | #define GETHOSTBYNAME(a) gethostbyname(a) 200 | #endif 201 | 202 | 203 | /*---------------------------------------------------------------------------*/ 204 | /* */ 205 | /* File Macros */ 206 | /* */ 207 | /*---------------------------------------------------------------------------*/ 208 | #define STRUCT_STAT struct stat 209 | #define LSTAT(x,y) lstat(x,y) 210 | #define FILE_HANDLE FILE * 211 | #define CLEARERR(x) clearerr(x) 212 | #define FCLOSE(x) fclose(x) 213 | #define FEOF(x) feof(x) 214 | #define FERROR(x) ferror(x) 215 | #define FFLUSH(x) fflush(x) 216 | #define FILENO(s) fileno(s) 217 | #define FOPEN(x,y) fopen(x, y) 218 | //#define FREAD(a,b,c,d) fread(a, b, c, d) 219 | #define FSTAT(s, st) fstat(FILENO(s), st) 220 | //#define FWRITE(a,b,c,d) fwrite(a, b, c, d) 221 | #define STAT_BLK_SIZE(x) ((x).st_blksize) 222 | 223 | 224 | /*---------------------------------------------------------------------------*/ 225 | /* */ 226 | /* Misc Macros */ 227 | /* */ 228 | /*---------------------------------------------------------------------------*/ 229 | #if defined(WIN32) 230 | #define GET_CLOCK_COUNT(x) QueryPerformanceCounter((LARGE_INTEGER *)x) 231 | #else 232 | #define GET_CLOCK_COUNT(x) gettimeofday(x, NULL) 233 | #endif 234 | 235 | #if defined(WIN32) 236 | #define STRTOULL(x) _atoi64(x) 237 | #else 238 | #define STRTOULL(x) strtoull(x, NULL, 10) 239 | #endif 240 | 241 | #if defined(WIN32) 242 | #define SNPRINTF _snprintf 243 | #define PRINTF printf 244 | #define VPRINTF vprintf 245 | #define FPRINTF fprintf 246 | #else 247 | #define SNPRINTF snprintf 248 | #define PRINTF printf 249 | #define VPRINTF vprintf 250 | #define FPRINTF fprintf 251 | #endif 252 | 253 | #ifdef _MSC_VER 254 | #define EXPORT __declspec(dllexport) 255 | #else 256 | #define EXPORT 257 | #endif 258 | 259 | #ifdef __cplusplus 260 | } 261 | #endif 262 | 263 | #endif /* __HOST_H__ */ 264 | -------------------------------------------------------------------------------- /src/ActiveSocket.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* CActiveSocket.cpp - Active Socket Implementation */ 4 | /* */ 5 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*---------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #include "ActiveSocket.h" 44 | 45 | CActiveSocket::CActiveSocket(CSocketType nType) : CSimpleSocket(nType) 46 | { 47 | } 48 | 49 | //------------------------------------------------------------------------------ 50 | // 51 | // ConnectTCP() - 52 | // 53 | //------------------------------------------------------------------------------ 54 | bool CActiveSocket::ConnectTCP(const char *pAddr, uint16 nPort) 55 | { 56 | bool bRetVal = false; 57 | struct in_addr stIpAddress; 58 | 59 | //------------------------------------------------------------------ 60 | // Preconnection setup that must be preformed 61 | //------------------------------------------------------------------ 62 | memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); 63 | m_stServerSockaddr.sin_family = AF_INET; 64 | 65 | if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL) 66 | { 67 | #ifdef WIN32 68 | TranslateSocketError(); 69 | #else 70 | if (h_errno == HOST_NOT_FOUND) 71 | { 72 | SetSocketError(SocketInvalidAddress); 73 | } 74 | #endif 75 | return bRetVal; 76 | } 77 | 78 | memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length); 79 | m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; 80 | 81 | if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) 82 | { 83 | TranslateSocketError(); 84 | return bRetVal; 85 | } 86 | 87 | m_stServerSockaddr.sin_port = htons(nPort); 88 | 89 | //------------------------------------------------------------------ 90 | // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. 91 | // 92 | //------------------------------------------------------------------ 93 | m_timer.Initialize(); 94 | m_timer.SetStartTime(); 95 | 96 | if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) == 97 | CSimpleSocket::SocketError) 98 | { 99 | //-------------------------------------------------------------- 100 | // Get error value this might be a non-blocking socket so we 101 | // must first check. 102 | //-------------------------------------------------------------- 103 | TranslateSocketError(); 104 | 105 | //-------------------------------------------------------------- 106 | // If the socket is non-blocking and the current socket error 107 | // is SocketEinprogress or SocketEwouldblock then poll connection 108 | // with select for designated timeout period. 109 | // Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK. 110 | //-------------------------------------------------------------- 111 | if ((IsNonblocking()) && 112 | ((GetSocketError() == CSimpleSocket::SocketEwouldblock) || 113 | (GetSocketError() == CSimpleSocket::SocketEinprogress))) 114 | { 115 | bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec()); 116 | } 117 | } 118 | else 119 | { 120 | TranslateSocketError(); 121 | bRetVal = true; 122 | } 123 | 124 | m_timer.SetEndTime(); 125 | 126 | return bRetVal; 127 | } 128 | 129 | //------------------------------------------------------------------------------ 130 | // 131 | // ConnectUDP() - 132 | // 133 | //------------------------------------------------------------------------------ 134 | bool CActiveSocket::ConnectUDP(const char *pAddr, uint16 nPort) 135 | { 136 | bool bRetVal = false; 137 | struct in_addr stIpAddress; 138 | 139 | //------------------------------------------------------------------ 140 | // Pre-connection setup that must be preformed 141 | //------------------------------------------------------------------ 142 | memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); 143 | m_stServerSockaddr.sin_family = AF_INET; 144 | 145 | if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL) 146 | { 147 | #ifdef WIN32 148 | TranslateSocketError(); 149 | #else 150 | if (h_errno == HOST_NOT_FOUND) 151 | { 152 | SetSocketError(SocketInvalidAddress); 153 | } 154 | #endif 155 | return bRetVal; 156 | } 157 | 158 | memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length); 159 | m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; 160 | 161 | if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) 162 | { 163 | TranslateSocketError(); 164 | return bRetVal; 165 | } 166 | 167 | m_stServerSockaddr.sin_port = htons(nPort); 168 | 169 | //------------------------------------------------------------------ 170 | // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. 171 | // 172 | //------------------------------------------------------------------ 173 | m_timer.Initialize(); 174 | m_timer.SetStartTime(); 175 | 176 | if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) 177 | { 178 | bRetVal = true; 179 | } 180 | 181 | TranslateSocketError(); 182 | 183 | m_timer.SetEndTime(); 184 | 185 | return bRetVal; 186 | } 187 | 188 | //------------------------------------------------------------------------------ 189 | // 190 | // ConnectRAW() - 191 | // 192 | //------------------------------------------------------------------------------ 193 | bool CActiveSocket::ConnectRAW(const char *pAddr, uint16 nPort) 194 | { 195 | bool bRetVal = false; 196 | struct in_addr stIpAddress; 197 | //------------------------------------------------------------------ 198 | // Pre-connection setup that must be preformed 199 | //------------------------------------------------------------------ 200 | memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); 201 | m_stServerSockaddr.sin_family = AF_INET; 202 | 203 | if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL) 204 | { 205 | #ifdef WIN32 206 | TranslateSocketError(); 207 | #else 208 | if (h_errno == HOST_NOT_FOUND) 209 | { 210 | SetSocketError(SocketInvalidAddress); 211 | } 212 | #endif 213 | return bRetVal; 214 | } 215 | 216 | memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length); 217 | m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; 218 | 219 | if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) 220 | { 221 | TranslateSocketError(); 222 | return bRetVal; 223 | } 224 | 225 | m_stServerSockaddr.sin_port = htons(nPort); 226 | 227 | //------------------------------------------------------------------ 228 | // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. 229 | // 230 | //------------------------------------------------------------------ 231 | m_timer.Initialize(); 232 | m_timer.SetStartTime(); 233 | 234 | if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) 235 | { 236 | bRetVal = true; 237 | } 238 | 239 | TranslateSocketError(); 240 | 241 | m_timer.SetEndTime(); 242 | 243 | return bRetVal; 244 | } 245 | 246 | 247 | //------------------------------------------------------------------------------ 248 | // 249 | // Open() - Create a connection to a specified address on a specified port 250 | // 251 | //------------------------------------------------------------------------------ 252 | bool CActiveSocket::Open(const char *pAddr, uint16 nPort) 253 | { 254 | bool bRetVal = false; 255 | 256 | if (IsSocketValid() == false) 257 | { 258 | SetSocketError(CSimpleSocket::SocketInvalidSocket); 259 | return bRetVal; 260 | } 261 | 262 | if (pAddr == NULL) 263 | { 264 | SetSocketError(CSimpleSocket::SocketInvalidAddress); 265 | return bRetVal; 266 | } 267 | 268 | if (nPort == 0) 269 | { 270 | SetSocketError(CSimpleSocket::SocketInvalidPort); 271 | return bRetVal; 272 | } 273 | 274 | switch (m_nSocketType) 275 | { 276 | case CSimpleSocket::SocketTypeTcp : 277 | { 278 | bRetVal = ConnectTCP(pAddr, nPort); 279 | break; 280 | } 281 | case CSimpleSocket::SocketTypeUdp : 282 | { 283 | bRetVal = ConnectUDP(pAddr, nPort); 284 | break; 285 | } 286 | case CSimpleSocket::SocketTypeRaw : 287 | break; 288 | default: 289 | break; 290 | } 291 | 292 | //-------------------------------------------------------------------------- 293 | // If successful then create a local copy of the address and port 294 | //-------------------------------------------------------------------------- 295 | if (bRetVal) 296 | { 297 | socklen_t nSockLen = sizeof(struct sockaddr); 298 | 299 | memset(&m_stServerSockaddr, 0, nSockLen); 300 | getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen); 301 | 302 | nSockLen = sizeof(struct sockaddr); 303 | memset(&m_stClientSockaddr, 0, nSockLen); 304 | getsockname(m_socket, (struct sockaddr *)&m_stClientSockaddr, &nSockLen); 305 | 306 | SetSocketError(SocketSuccess); 307 | } 308 | 309 | return bRetVal; 310 | } 311 | -------------------------------------------------------------------------------- /ReleaseNotes: -------------------------------------------------------------------------------- 1 | =============================================================================== 2 | Release v1.4.1 3 | =============================================================================== 4 | 5 | I. New Features 6 | --------------- 7 | * New methods: 8 | CSimpleSocket::EnableNagleAlgorithm() 9 | CSimpleSocket::DisableNagleAlgorithm() 10 | 11 | II. Deprecated Functionality 12 | ---------------------------- 13 | 14 | III. Bug Fixes 15 | -------------- 16 | 17 | Reported Bugs 18 | ------------- 19 | #95 - Add support to enable/disable Nable algorithm 20 | #131 - Multicast receiver not working 21 | 22 | Unreported Bugs 23 | --------------- 24 | 25 | IV. Known Issues 26 | ---------------- 27 | #44 - Add MTU size test to unit test so fragmentation can be tested. 28 | #45 - Test Select() with Recv() and Send() set as non-blocking. 29 | #47 - Mechanism to setting/setting socket options/flags. 30 | #48 - Finish support for RAW sockets. 31 | #50 - Add IPV6 support 32 | 33 | V. Configuration Changes 34 | ------------------------ 35 | 36 | VI. Release Tag Dependencies 37 | ---------------------------- 38 | 39 | VII. Errata 40 | ----------- 41 | 42 | Bug Fixes 43 | ------------- 44 | 45 | VIII. Documentation Changes 46 | ---------------------------- 47 | 48 | 49 | =============================================================================== 50 | Release v1.4.0 51 | =============================================================================== 52 | 53 | I. New Features 54 | --------------- 55 | * Support for multicast 56 | * New methods: 57 | CPassiveSocket::BindMulticast() 58 | CSimpleSocket::SetMulticast() 59 | CSimpleSocket::GetMulticast() 60 | 61 | 62 | II. Deprecated Functionality 63 | ---------------------------- 64 | 65 | III. Bug Fixes 66 | -------------- 67 | 68 | Reported Bugs 69 | ------------- 70 | #92 - Add multicast to library 71 | 72 | Unreported Bugs 73 | --------------- 74 | 75 | IV. Known Issues 76 | ---------------- 77 | #44 - Add MTU size test to unit test so fragmentation can be tested. 78 | #45 - Test Select() with Recv() and Send() set as non-blocking. 79 | #47 - Mechanism to setting/setting socket options/flags. 80 | #48 - Finish support for RAW sockets. 81 | #50 - Add IPV6 support 82 | 83 | V. Configuration Changes 84 | ------------------------ 85 | 86 | VI. Release Tag Dependencies 87 | ---------------------------- 88 | 89 | VII. Errata 90 | ----------- 91 | 92 | Bug Fixes 93 | ------------- 94 | 95 | VIII. Documentation Changes 96 | ---------------------------- 97 | 98 | 99 | =============================================================================== 100 | Release v1.3.3 101 | =============================================================================== 102 | 103 | I. New Features 104 | --------------- 105 | * Now compiles for Macintosh - DMG file not yet supported 106 | * New method CSimpleSocket::Shutdown() - used to control 107 | shutdown on socket. 108 | 109 | II. Deprecated Functionality 110 | ---------------------------- 111 | 112 | III. Bug Fixes 113 | -------------- 114 | 115 | Reported Bugs 116 | ------------- 117 | #49 - Support for Macintosh 118 | #86 - Create new method to control shutdown of socket 119 | #87 - Memory leak detected 120 | 121 | Unreported Bugs 122 | --------------- 123 | 124 | IV. Known Issues 125 | ---------------- 126 | #44 - Add MTU size test to unit test so fragmentation can be tested. 127 | #45 - Test Select() with Recv() and Send() set as non-blocking. 128 | #47 - Mechanism to setting/setting socket options/flags. 129 | #48 - Finish support for RAW sockets. 130 | #50 - Add IPV6 support 131 | 132 | V. Configuration Changes 133 | ------------------------ 134 | 135 | VI. Release Tag Dependencies 136 | ---------------------------- 137 | 138 | VII. Errata 139 | ----------- 140 | 141 | Bug Fixes 142 | ------------- 143 | 144 | VIII. Documentation Changes 145 | ---------------------------- 146 | 147 | 148 | =============================================================================== 149 | Release v1.3.2 150 | =============================================================================== 151 | 152 | I. New Features 153 | --------------- 154 | 155 | II. Deprecated Functionality 156 | ---------------------------- 157 | 158 | III. Bug Fixes 159 | -------------- 160 | 161 | Reported Bugs 162 | ------------- 163 | #84 - CActiveSocket::Close() shutsdown both sides of the socket 164 | 165 | Unreported Bugs 166 | --------------- 167 | 168 | IV. Known Issues 169 | ---------------- 170 | #44 - Add MTU size test to unit test so fragmentation can be tested. 171 | #45 - Test Select() with Recv() and Send() set as non-blocking. 172 | #47 - Mechanism to setting/setting socket options/flags. 173 | #48 - Finish support for RAW sockets. 174 | #49 - Support for Macintosh. 175 | #50 - Add IPV6 support 176 | 177 | V. Configuration Changes 178 | ------------------------ 179 | 180 | VI. Release Tag Dependencies 181 | ---------------------------- 182 | 183 | VII. Errata 184 | ----------- 185 | 186 | Bug Fixes 187 | ------------- 188 | 189 | VIII. Documentation Changes 190 | ---------------------------- 191 | 192 | 193 | =============================================================================== 194 | Release v1.3.1 195 | =============================================================================== 196 | 197 | I. New Features 198 | --------------- 199 | * New methods: 200 | SetOptionLinger() - Enable/disable linger option. 201 | SetOptionReuseAddr() - Set option reuse port. 202 | * SimpleSocket::Receive() will only allocate a buffer if the internal buffer 203 | is NULL or the buffer size is not equal to the previously allocated 204 | buffer. 205 | 206 | II. Deprecated Functionality 207 | ---------------------------- 208 | 209 | III. Bug Fixes 210 | -------------- 211 | 212 | Reported Bugs 213 | ------------- 214 | #64 - Method GetClientPort() returns value in byte swapped order 215 | #83 - WIN32 SetBlocking() is broke. 216 | 217 | Unreported Bugs 218 | --------------- 219 | 220 | IV. Known Issues 221 | ---------------- 222 | #44 - Add MTU size test to unit test so fragmentation can be tested. 223 | #45 - Test Select() with Recv() and Send() set as non-blocking. 224 | #47 - Mechanism to setting/setting socket options/flags. 225 | #48 - Finish support for RAW sockets. 226 | #49 - Support for Macintosh. 227 | #50 - Add IPV6 support 228 | 229 | V. Configuration Changes 230 | ------------------------ 231 | 232 | VI. Release Tag Dependencies 233 | ---------------------------- 234 | 235 | VII. Errata 236 | ----------- 237 | 238 | Bug Fixes 239 | ------------- 240 | 241 | VIII. Documentation Changes 242 | ---------------------------- 243 | 244 | 245 | 246 | =============================================================================== 247 | Release v1.3.0 248 | =============================================================================== 249 | 250 | I. New Features 251 | --------------- 252 | * New methods: 253 | SendVector() - implements the iovec functionality on both linux and 254 | Windows. 255 | SetSendWindowSize() - Sent the TCP window size for send. 256 | SetReceiveWindowSize() - Set the TCP windows size for receive. 257 | GetSendWindowSize() - Get the TCP window size for send. 258 | GetReceiveWindowSize() - Get the TCP window size fo receive. 259 | Select(int sec, int usec) - Overloaded function to specify timeout 260 | value of select. 261 | 262 | II. Deprecated Functionality 263 | ---------------------------- 264 | 265 | III. Bug Fixes 266 | -------------- 267 | 268 | Reported Bugs 269 | ------------- 270 | #33 - Add SendVector mehtod to class 271 | #41 - Sockets library MUST be signal safe 272 | #51 - Add support to set TCP windows size 273 | #52 - Select closes socket if timeout occurs 274 | #53 - UDP receive always fails even when successful 275 | 276 | Unreported Bugs 277 | --------------- 278 | 279 | IV. Known Issues 280 | ---------------- 281 | #44 - Add MTU size test to unit test so fragmentation can be tested. 282 | #45 - Test Select() with Recv() and Send() set as non-blocking. 283 | #47 - Mechanism to setting/setting socket options/flags. 284 | #48 - Finish support for RAW sockets. 285 | #49 - Support for Macintosh. 286 | #50 - Add IPV6 support 287 | 288 | V. Configuration Changes 289 | ------------------------ 290 | 291 | VI. Release Tag Dependencies 292 | ---------------------------- 293 | 294 | VII. Errata 295 | ----------- 296 | 297 | Bug Fixes 298 | ------------- 299 | 300 | VIII. Documentation Changes 301 | ---------------------------- 302 | 303 | 304 | 305 | 306 | =============================================================================== 307 | Release v1.2.0 308 | =============================================================================== 309 | 310 | I. New Features 311 | --------------- 312 | * New method SetSocketDscp() and GetSocketDscp() for setting and getting DSCP values. 313 | 314 | II. Deprecated Functionality 315 | ---------------------------- 316 | 317 | III. Bug Fixes 318 | -------------- 319 | 320 | Reported Bugs 321 | ------------- 322 | #17 - Finish documentation of library 323 | #34 - Add SendFile() method to class 324 | #37 - Make new methods GetServerAddress() and GetClientAddress() 325 | 326 | Unreported Bugs 327 | --------------- 328 | 329 | IV. Known Issues 330 | ---------------- 331 | #41 - Sockets library MUST be signal safe 332 | #44 - Add MTU size test to unit test so fragmentation can be tested. 333 | #45 - Test Select() with Recv() and Send() set as non-blocking. 334 | #47 - Mechanism to setting/setting socket options/flags 335 | 336 | V. Configuration Changes 337 | ------------------------ 338 | 339 | VI. Release Tag Dependencies 340 | ---------------------------- 341 | 342 | VII. Errata 343 | ----------- 344 | 345 | Bug Fixes 346 | ------------- 347 | 348 | VIII. Documentation Changes 349 | ---------------------------- 350 | 351 | 352 | 353 | =============================================================================== 354 | Release v1.1.0 355 | =============================================================================== 356 | 357 | I. New Features 358 | --------------- 359 | * UDP Now supported 360 | 361 | II. Deprecated Functionality 362 | ---------------------------- 363 | * SetSocketExpedited() method. 364 | 365 | III. Bug Fixes 366 | -------------- 367 | 368 | Reported Bugs 369 | ------------- 370 | #18 - Compile under windows 371 | #24 - Add more type and error checking to CSocket 372 | #29 - Add UDP support 373 | #35 - unit testing of socket library causes crash on windows 374 | 375 | Unreported Bugs 376 | --------------- 377 | 378 | IV. Known Issues 379 | ---------------- 380 | 381 | V. Configuration Changes 382 | ------------------------ 383 | 384 | VI. Release Tag Dependencies 385 | ---------------------------- 386 | 387 | VII. Errata 388 | ----------- 389 | 390 | Bug Fixes 391 | ------------- 392 | 393 | VIII. Documentation Changes 394 | ---------------------------- 395 | 396 | 397 | 398 | =============================================================================== 399 | Release v1.0.3 400 | =============================================================================== 401 | 402 | I. New Features 403 | --------------- 404 | * New method SetSocketExpedited() for setting expedited traffice (DSCP settings). 405 | 406 | II. Deprecated Functionality 407 | ---------------------------- 408 | 409 | III. Bug Fixes 410 | -------------- 411 | 412 | Reported Bugs 413 | ------------- 414 | #27 - Finish adding stats code to CSocket class. 415 | #30 - ConnectTCP() does not return correct error for inavlid IP Address. 416 | 417 | Unreported Bugs 418 | --------------- 419 | 420 | IV. Known Issues 421 | ---------------- 422 | 423 | V. Configuration Changes 424 | ------------------------ 425 | 426 | VI. Release Tag Dependencies 427 | ---------------------------- 428 | 429 | VII. Errata 430 | ----------- 431 | 432 | Bug Fixes 433 | ------------- 434 | 435 | VIII. Documentation Changes 436 | ---------------------------- 437 | 438 | 439 | 440 | =============================================================================== 441 | Release v1.0.2 442 | =============================================================================== 443 | 444 | I. New Features 445 | --------------- 446 | * Implemented a new socket mode "CSocketMode::Passive" which allows the creation 447 | of a listening socket. Two new methods are available to control behavior for 448 | the listening socket: Listen() and Accept(). 449 | 450 | II. Deprecated Functionality 451 | ---------------------------- 452 | 453 | III. Bug Fixes 454 | -------------- 455 | #23 - Create Listen() method 456 | 457 | Reported Bugs 458 | ------------- 459 | 460 | Unreported Bugs 461 | --------------- 462 | 463 | IV. Known Issues 464 | ---------------- 465 | 466 | V. Configuration Changes 467 | ------------------------ 468 | 469 | VI. Release Tag Dependencies 470 | ---------------------------- 471 | 472 | VII. Errata 473 | ----------- 474 | 475 | Bug Fixes 476 | ------------- 477 | 478 | VIII. Documentation Changes 479 | ---------------------------- 480 | -------------------------------------------------------------------------------- /src/PassiveSocket.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* PassiveSocket.cpp - Passive Socket Implementation */ 4 | /* */ 5 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*---------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #include "PassiveSocket.h" 44 | 45 | 46 | 47 | CPassiveSocket::CPassiveSocket(CSocketType nType) : CSimpleSocket(nType) 48 | { 49 | } 50 | 51 | bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, uint16 nPort) 52 | { 53 | bool bRetVal = false; 54 | #ifdef WIN32 55 | ULONG inAddr; 56 | #else 57 | in_addr_t inAddr; 58 | #endif 59 | 60 | //-------------------------------------------------------------------------- 61 | // Set the following socket option SO_REUSEADDR. This will allow the file 62 | // descriptor to be reused immediately after the socket is closed instead 63 | // of setting in a TIMED_WAIT state. 64 | //-------------------------------------------------------------------------- 65 | memset(&m_stMulticastGroup,0,sizeof(m_stMulticastGroup)); 66 | m_stMulticastGroup.sin_family = AF_INET; 67 | m_stMulticastGroup.sin_port = htons(nPort); 68 | 69 | //-------------------------------------------------------------------------- 70 | // If no IP Address (interface ethn) is supplied, or the loop back is 71 | // specified then bind to any interface, else bind to specified interface. 72 | //-------------------------------------------------------------------------- 73 | if ((pInterface == NULL) || (!strlen(pInterface))) 74 | { 75 | m_stMulticastGroup.sin_addr.s_addr = htonl(INADDR_ANY); 76 | } 77 | else 78 | { 79 | if ((inAddr = inet_addr(pInterface)) != INADDR_NONE) 80 | { 81 | m_stMulticastGroup.sin_addr.s_addr = inAddr; 82 | } 83 | } 84 | 85 | //-------------------------------------------------------------------------- 86 | // Bind to the specified port 87 | //-------------------------------------------------------------------------- 88 | if (bind(m_socket, (struct sockaddr *)&m_stMulticastGroup, sizeof(m_stMulticastGroup)) == 0) 89 | { 90 | //---------------------------------------------------------------------- 91 | // Join the multicast group 92 | //---------------------------------------------------------------------- 93 | m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup); 94 | m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr; 95 | 96 | if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, 97 | (void *)&m_stMulticastRequest, 98 | sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess) 99 | { 100 | bRetVal = true; 101 | } 102 | 103 | m_timer.SetEndTime(); 104 | } 105 | 106 | m_timer.Initialize(); 107 | m_timer.SetStartTime(); 108 | 109 | 110 | //-------------------------------------------------------------------------- 111 | // If there was a socket error then close the socket to clean out the 112 | // connection in the backlog. 113 | //-------------------------------------------------------------------------- 114 | TranslateSocketError(); 115 | 116 | if (bRetVal == false) 117 | { 118 | Close(); 119 | } 120 | 121 | return bRetVal; 122 | } 123 | 124 | 125 | //------------------------------------------------------------------------------ 126 | // 127 | // Listen() - 128 | // 129 | //------------------------------------------------------------------------------ 130 | bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBacklog) 131 | { 132 | bool bRetVal = false; 133 | #ifdef WIN32 134 | ULONG inAddr; 135 | #else 136 | in_addr_t inAddr; 137 | 138 | int32 nReuse; 139 | nReuse = IPTOS_LOWDELAY; 140 | 141 | //-------------------------------------------------------------------------- 142 | // Set the following socket option SO_REUSEADDR. This will allow the file 143 | // descriptor to be reused immediately after the socket is closed instead 144 | // of setting in a TIMED_WAIT state. 145 | //-------------------------------------------------------------------------- 146 | SETSOCKOPT(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nReuse, sizeof(int32)); 147 | SETSOCKOPT(m_socket, IPPROTO_TCP, IP_TOS, &nReuse, sizeof(int32)); 148 | #endif 149 | 150 | memset(&m_stServerSockaddr,0,sizeof(m_stServerSockaddr)); 151 | m_stServerSockaddr.sin_family = AF_INET; 152 | m_stServerSockaddr.sin_port = htons(nPort); 153 | 154 | //-------------------------------------------------------------------------- 155 | // If no IP Address (interface ethn) is supplied, or the loop back is 156 | // specified then bind to any interface, else bind to specified interface. 157 | //-------------------------------------------------------------------------- 158 | if ((pAddr == NULL) || (!strlen(pAddr))) 159 | { 160 | m_stServerSockaddr.sin_addr.s_addr = htonl(INADDR_ANY); 161 | } 162 | else 163 | { 164 | if ((inAddr = inet_addr(pAddr)) != INADDR_NONE) 165 | { 166 | m_stServerSockaddr.sin_addr.s_addr = inAddr; 167 | } 168 | } 169 | 170 | m_timer.Initialize(); 171 | m_timer.SetStartTime(); 172 | 173 | //-------------------------------------------------------------------------- 174 | // Bind to the specified port 175 | //-------------------------------------------------------------------------- 176 | if (bind(m_socket, (struct sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) 177 | { 178 | if (m_nSocketType == CSimpleSocket::SocketTypeTcp) 179 | { 180 | if (listen(m_socket, nConnectionBacklog) != CSimpleSocket::SocketError) 181 | { 182 | bRetVal = true; 183 | } 184 | } 185 | else 186 | { 187 | bRetVal = true; 188 | } 189 | } 190 | 191 | m_timer.SetEndTime(); 192 | 193 | //-------------------------------------------------------------------------- 194 | // If there was a socket error then close the socket to clean out the 195 | // connection in the backlog. 196 | //-------------------------------------------------------------------------- 197 | TranslateSocketError(); 198 | 199 | if (bRetVal == false) 200 | { 201 | CSocketError err = GetSocketError(); 202 | Close(); 203 | SetSocketError(err); 204 | } 205 | 206 | return bRetVal; 207 | } 208 | 209 | 210 | //------------------------------------------------------------------------------ 211 | // 212 | // Accept() - 213 | // 214 | //------------------------------------------------------------------------------ 215 | CActiveSocket *CPassiveSocket::Accept() 216 | { 217 | uint32 nSockLen; 218 | CActiveSocket *pClientSocket = NULL; 219 | SOCKET socket = CSimpleSocket::SocketError; 220 | 221 | if (m_nSocketType != CSimpleSocket::SocketTypeTcp) 222 | { 223 | SetSocketError(CSimpleSocket::SocketProtocolError); 224 | return pClientSocket; 225 | } 226 | 227 | pClientSocket = new CActiveSocket(); 228 | 229 | //-------------------------------------------------------------------------- 230 | // Wait for incoming connection. 231 | //-------------------------------------------------------------------------- 232 | if (pClientSocket != NULL) 233 | { 234 | CSocketError socketErrno = SocketSuccess; 235 | 236 | m_timer.Initialize(); 237 | m_timer.SetStartTime(); 238 | 239 | nSockLen = sizeof(m_stClientSockaddr); 240 | 241 | do 242 | { 243 | errno = 0; 244 | socket = accept(m_socket, (struct sockaddr *)&m_stClientSockaddr, (socklen_t *)&nSockLen); 245 | 246 | if (socket != -1) 247 | { 248 | pClientSocket->SetSocketHandle(socket); 249 | pClientSocket->TranslateSocketError(); 250 | socketErrno = pClientSocket->GetSocketError(); 251 | socklen_t nSockLen = sizeof(struct sockaddr); 252 | 253 | //------------------------------------------------------------- 254 | // Store client and server IP and port information for this 255 | // connection. 256 | //------------------------------------------------------------- 257 | getpeername(m_socket, (struct sockaddr *)&pClientSocket->m_stClientSockaddr, &nSockLen); 258 | memcpy((void *)&pClientSocket->m_stClientSockaddr, (void *)&m_stClientSockaddr, nSockLen); 259 | 260 | memset(&pClientSocket->m_stServerSockaddr, 0, nSockLen); 261 | getsockname(m_socket, (struct sockaddr *)&pClientSocket->m_stServerSockaddr, &nSockLen); 262 | } 263 | else 264 | { 265 | TranslateSocketError(); 266 | socketErrno = GetSocketError(); 267 | } 268 | 269 | } while (socketErrno == CSimpleSocket::SocketInterrupted); 270 | 271 | m_timer.SetEndTime(); 272 | 273 | if (socketErrno != CSimpleSocket::SocketSuccess) 274 | { 275 | delete pClientSocket; 276 | pClientSocket = NULL; 277 | } 278 | } 279 | 280 | return pClientSocket; 281 | } 282 | 283 | 284 | //------------------------------------------------------------------------------ 285 | // 286 | // Send() - Send data on a valid socket 287 | // 288 | //------------------------------------------------------------------------------ 289 | int32 CPassiveSocket::Send(const uint8 *pBuf, size_t bytesToSend) 290 | { 291 | SetSocketError(SocketSuccess); 292 | m_nBytesSent = 0; 293 | 294 | switch(m_nSocketType) 295 | { 296 | case CSimpleSocket::SocketTypeUdp: 297 | { 298 | if (IsSocketValid()) 299 | { 300 | if ((bytesToSend > 0) && (pBuf != NULL)) 301 | { 302 | m_timer.Initialize(); 303 | m_timer.SetStartTime(); 304 | 305 | m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, 306 | (const sockaddr *)&m_stClientSockaddr, 307 | sizeof(m_stClientSockaddr)); 308 | 309 | m_timer.SetEndTime(); 310 | 311 | if (m_nBytesSent == CSimpleSocket::SocketError) 312 | { 313 | TranslateSocketError(); 314 | } 315 | } 316 | } 317 | break; 318 | } 319 | case CSimpleSocket::SocketTypeTcp: 320 | CSimpleSocket::Send(pBuf, bytesToSend); 321 | break; 322 | default: 323 | SetSocketError(SocketProtocolError); 324 | break; 325 | } 326 | 327 | return m_nBytesSent; 328 | } 329 | -------------------------------------------------------------------------------- /src/SimpleSocket.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* SimpleSocket.h - Simple Socket base class decleration. */ 4 | /* */ 5 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*---------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #ifndef __SOCKET_H__ 44 | #define __SOCKET_H__ 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #if defined(_LINUX) || defined (_DARWIN) 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #endif 60 | #ifdef _LINUX 61 | #include 62 | #include 63 | #include 64 | #include 65 | #endif 66 | #ifdef _DARWIN 67 | #include 68 | #endif 69 | #if defined(_LINUX) || defined (_DARWIN) 70 | #include 71 | #include 72 | #include 73 | #include 74 | #endif 75 | 76 | #ifdef _WIN32 77 | #include 78 | #include 79 | #include 80 | 81 | #define IPTOS_LOWDELAY 0x10 82 | 83 | #endif 84 | #include "Host.h" 85 | #include "StatTimer.h" 86 | 87 | //----------------------------------------------------------------------------- 88 | // General class macro definitions and typedefs 89 | //----------------------------------------------------------------------------- 90 | #ifndef INVALID_SOCKET 91 | #define INVALID_SOCKET ~(0) 92 | #endif 93 | 94 | #define SOCKET_SENDFILE_BLOCKSIZE 8192 95 | 96 | /// Provides a platform independent class to for socket development. 97 | /// This class is designed to abstract socket communication development in a 98 | /// platform independent manner. 99 | /// - Socket types 100 | /// -# CActiveSocket Class 101 | /// -# CPassiveSocket Class 102 | class EXPORT CSimpleSocket { 103 | public: 104 | /// Defines the three possible states for shuting down a socket. 105 | typedef enum 106 | { 107 | Receives = SHUT_RD, ///< Shutdown passive socket. 108 | Sends = SHUT_WR, ///< Shutdown active socket. 109 | Both = SHUT_RDWR ///< Shutdown both active and passive sockets. 110 | } CShutdownMode; 111 | 112 | /// Defines the socket types defined by CSimpleSocket class. 113 | typedef enum 114 | { 115 | SocketTypeInvalid, ///< Invalid socket type. 116 | SocketTypeTcp, ///< Defines socket as TCP socket. 117 | SocketTypeUdp, ///< Defines socket as UDP socket. 118 | SocketTypeTcp6, ///< Defines socket as IPv6 TCP socket. 119 | SocketTypeUdp6, ///< Defines socket as IPv6 UDP socket. 120 | SocketTypeRaw ///< Provides raw network protocol access. 121 | } CSocketType; 122 | 123 | /// Defines all error codes handled by the CSimpleSocket class. 124 | typedef enum 125 | { 126 | SocketError = -1, ///< Generic socket error translates to error below. 127 | SocketSuccess = 0, ///< No socket error. 128 | SocketInvalidSocket, ///< Invalid socket handle. 129 | SocketInvalidAddress, ///< Invalid destination address specified. 130 | SocketInvalidPort, ///< Invalid destination port specified. 131 | SocketConnectionRefused, ///< No server is listening at remote address. 132 | SocketTimedout, ///< Timed out while attempting operation. 133 | SocketEwouldblock, ///< Operation would block if socket were blocking. 134 | SocketNotconnected, ///< Currently not connected. 135 | SocketEinprogress, ///< Socket is non-blocking and the connection cannot be completed immediately 136 | SocketInterrupted, ///< Call was interrupted by a signal that was caught before a valid connection arrived. 137 | SocketConnectionAborted, ///< The connection has been aborted. 138 | SocketProtocolError, ///< Invalid protocol for operation. 139 | SocketFirewallError, ///< Firewall rules forbid connection. 140 | SocketInvalidSocketBuffer, ///< The receive buffer point outside the process's address space. 141 | SocketConnectionReset, ///< Connection was forcibly closed by the remote host. 142 | SocketAddressInUse, ///< Address already in use. 143 | SocketInvalidPointer, ///< Pointer type supplied as argument is invalid. 144 | SocketEunknown ///< Unknown error please report to mark@carrierlabs.com 145 | } CSocketError; 146 | 147 | public: 148 | CSimpleSocket(CSocketType type = SocketTypeTcp); 149 | CSimpleSocket(CSimpleSocket &socket); 150 | 151 | virtual ~CSimpleSocket() 152 | { 153 | if (m_pBuffer != NULL) 154 | { 155 | delete [] m_pBuffer; 156 | m_pBuffer = NULL; 157 | } 158 | }; 159 | 160 | /// Initialize instance of CSocket. This method MUST be called before an 161 | /// object can be used. Errors : CSocket::SocketProtocolError, 162 | /// CSocket::SocketInvalidSocket, 163 | /// @return true if properly initialized. 164 | virtual bool Initialize(void); 165 | 166 | /// Close socket 167 | /// @return true if successfully closed otherwise returns false. 168 | virtual bool Close(void); 169 | 170 | /// Shutdown shut down socket send and receive operations 171 | /// CShutdownMode::Receives - Disables further receive operations. 172 | /// CShutdownMode::Sends - Disables further send operations. 173 | /// CShutdownBoth:: - Disables further send and receive operations. 174 | /// @param nShutdown specifies the type of shutdown. 175 | /// @return true if successfully shutdown otherwise returns false. 176 | virtual bool Shutdown(CShutdownMode nShutdown); 177 | 178 | /// Examine the socket descriptor sets currently owned by the instance of 179 | /// the socket class (the readfds, writefds, and errorfds parameters) to 180 | /// see whether some of their descriptors are ready for reading, are ready 181 | /// for writing, or have an exceptional condition pending, respectively. 182 | /// Block until an event happens on the specified file descriptors. 183 | /// @return true if socket has data ready, or false if not ready or timed out. 184 | virtual bool Select(void) { 185 | return Select(0,0); 186 | }; 187 | 188 | /// Examine the socket descriptor sets currently owned by the instance of 189 | /// the socket class (the readfds, writefds, and errorfds parameters) to 190 | /// see whether some of their descriptors are ready for reading, are ready 191 | /// for writing, or have an exceptional condition pending, respectively. 192 | /// @param nTimeoutSec timeout in seconds for select. 193 | /// @param nTimeoutUSec timeout in micro seconds for select. 194 | /// @return true if socket has data ready, or false if not ready or timed out. 195 | virtual bool Select(int32 nTimeoutSec, int32 nTimeoutUSec); 196 | 197 | /// Does the current instance of the socket object contain a valid socket 198 | /// descriptor. 199 | /// @return true if the socket object contains a valid socket descriptor. 200 | virtual bool IsSocketValid(void) { 201 | return (m_socket != SocketError); 202 | }; 203 | 204 | /// Provides a standard error code for cross platform development by 205 | /// mapping the operating system error to an error defined by the CSocket 206 | /// class. 207 | void TranslateSocketError(void); 208 | 209 | /// Returns a human-readable description of the given error code 210 | /// or the last error code of a socket 211 | static const char *DescribeError(CSocketError err); 212 | inline const char *DescribeError() { 213 | return DescribeError(m_socketErrno); 214 | }; 215 | 216 | /// Attempts to receive a block of data on an established connection. 217 | /// @param nMaxBytes maximum number of bytes to receive. 218 | /// @param pBuffer, memory where to receive the data, 219 | /// NULL receives to internal buffer returned with GetData() 220 | /// Non-NULL receives directly there, but GetData() will return WRONG ptr! 221 | /// @return number of bytes actually received. 222 | /// @return of zero means the connection has been shutdown on the other side. 223 | /// @return of -1 means that an error has occurred. 224 | virtual int32 Receive(int32 nMaxBytes = 1, uint8 * pBuffer = 0); 225 | 226 | /// Attempts to send a block of data on an established connection. 227 | /// @param pBuf block of data to be sent. 228 | /// @param bytesToSend size of data block to be sent. 229 | /// @return number of bytes actually sent. 230 | /// @return of zero means the connection has been shutdown on the other side. 231 | /// @return of -1 means that an error has occurred. 232 | virtual int32 Send(const uint8 *pBuf, size_t bytesToSend); 233 | 234 | /// Attempts to send at most nNumItem blocks described by sendVector 235 | /// to the socket descriptor associated with the socket object. 236 | /// @param sendVector pointer to an array of iovec structures 237 | /// @param nNumItems number of items in the vector to process 238 | ///
\b NOTE: Buffers are processed in the order specified. 239 | /// @return number of bytes actually sent, return of zero means the 240 | /// connection has been shutdown on the other side, and a return of -1 241 | /// means that an error has occurred. 242 | virtual int32 Send(const struct iovec *sendVector, int32 nNumItems); 243 | 244 | /// Copies data between one file descriptor and another. 245 | /// On some systems this copying is done within the kernel, and thus is 246 | /// more efficient than the combination of CSimpleSocket::Send and 247 | /// CSimpleSocket::Receive, which would require transferring data to and 248 | /// from user space. 249 | ///
\b Note: This is available on all implementations, but the kernel 250 | /// implementation is only available on Unix type systems. 251 | /// @param nOutFd descriptor opened for writing. 252 | /// @param nInFd descriptor opened for reading. 253 | /// @param pOffset from which to start reading data from input file. 254 | /// @param nCount number of bytes to copy between file descriptors. 255 | /// @return number of bytes written to the out socket descriptor. 256 | virtual int32 SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 nCount); 257 | 258 | /// Returns blocking/non-blocking state of socket. 259 | /// @return true if the socket is non-blocking, else return false. 260 | bool IsNonblocking(void) { 261 | return (m_bIsBlocking == false); 262 | }; 263 | 264 | /// Set the socket to blocking. 265 | /// @return true if successful set to blocking, else return false; 266 | bool SetBlocking(void); 267 | 268 | /// Set the socket as non-blocking. 269 | /// @return true if successful set to non-blocking, else return false; 270 | bool SetNonblocking(void); 271 | 272 | /// Get a pointer to internal receive buffer. The user MUST not free this 273 | /// pointer when finished. This memory is managed internally by the CSocket 274 | /// class. 275 | /// @return pointer to data if valid, else returns NULL. 276 | uint8 *GetData(void) { 277 | return m_pBuffer; 278 | }; 279 | 280 | /// Returns the number of bytes received on the last call to 281 | /// CSocket::Receive(). 282 | /// @return number of bytes received. 283 | int32 GetBytesReceived(void) { 284 | return m_nBytesReceived; 285 | }; 286 | 287 | /// Returns the number of bytes sent on the last call to 288 | /// CSocket::Send(). 289 | /// @return number of bytes sent. 290 | int32 GetBytesSent(void) { 291 | return m_nBytesSent; 292 | }; 293 | 294 | /// Controls the actions taken when CSimpleSocket::Close is executed on a 295 | /// socket object that has unsent data. The default value for this option 296 | /// is \b off. 297 | /// - Following are the three possible scenarios. 298 | /// -# \b bEnable is false, CSimpleSocket::Close returns immediately, but 299 | /// any unset data is transmitted (after CSimpleSocket::Close returns) 300 | /// -# \b bEnable is true and \b nTime is zero, CSimpleSocket::Close return 301 | /// immediately and any unsent data is discarded. 302 | /// -# \b bEnable is true and \b nTime is nonzero, CSimpleSocket::Close does 303 | /// not return until all unsent data is transmitted (or the connection is 304 | /// Closed by the remote system). 305 | ///

306 | /// @param bEnable true to enable option false to disable option. 307 | /// @param nTime time in seconds to linger. 308 | /// @return true if option successfully set 309 | bool SetOptionLinger(bool bEnable, uint16 nTime); 310 | 311 | /// Tells the kernel that even if this port is busy (in the TIME_WAIT state), 312 | /// go ahead and reuse it anyway. If it is busy, but with another state, 313 | /// you will still get an address already in use error. 314 | /// @return true if option successfully set 315 | bool SetOptionReuseAddr(); 316 | 317 | /// Gets the timeout value that specifies the maximum number of seconds a 318 | /// call to CSimpleSocket::Open waits until it completes. 319 | /// @return the length of time in seconds 320 | int32 GetConnectTimeoutSec(void) { 321 | return m_stConnectTimeout.tv_sec; 322 | }; 323 | 324 | /// Gets the timeout value that specifies the maximum number of microseconds 325 | /// a call to CSimpleSocket::Open waits until it completes. 326 | /// @return the length of time in microseconds 327 | int32 GetConnectTimeoutUSec(void) { 328 | return m_stConnectTimeout.tv_usec; 329 | }; 330 | 331 | /// Sets the timeout value that specifies the maximum amount of time a call 332 | /// to CSimpleSocket::Receive waits until it completes. Use the method 333 | /// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait. 334 | /// If a call to CSimpleSocket::Receive has blocked for the specified length of 335 | /// time without receiving additional data, it returns with a partial count 336 | /// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data 337 | /// were received. 338 | /// @param nConnectTimeoutSec of timeout in seconds. 339 | /// @param nConnectTimeoutUsec of timeout in microseconds. 340 | /// @return true if socket connection timeout was successfully set. 341 | void SetConnectTimeout(int32 nConnectTimeoutSec, int32 nConnectTimeoutUsec = 0) 342 | { 343 | m_stConnectTimeout.tv_sec = nConnectTimeoutSec; 344 | m_stConnectTimeout.tv_usec = nConnectTimeoutUsec; 345 | }; 346 | 347 | /// Gets the timeout value that specifies the maximum number of seconds a 348 | /// a call to CSimpleSocket::Receive waits until it completes. 349 | /// @return the length of time in seconds 350 | int32 GetReceiveTimeoutSec(void) { 351 | return m_stRecvTimeout.tv_sec; 352 | }; 353 | 354 | /// Gets the timeout value that specifies the maximum number of microseconds 355 | /// a call to CSimpleSocket::Receive waits until it completes. 356 | /// @return the length of time in microseconds 357 | int32 GetReceiveTimeoutUSec(void) { 358 | return m_stRecvTimeout.tv_usec; 359 | }; 360 | 361 | /// Sets the timeout value that specifies the maximum amount of time a call 362 | /// to CSimpleSocket::Receive waits until it completes. Use the method 363 | /// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait. 364 | /// If a call to CSimpleSocket::Receive has blocked for the specified length of 365 | /// time without receiving additional data, it returns with a partial count 366 | /// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data 367 | /// were received. 368 | /// @param nRecvTimeoutSec of timeout in seconds. 369 | /// @param nRecvTimeoutUsec of timeout in microseconds. 370 | /// @return true if socket timeout was successfully set. 371 | bool SetReceiveTimeout(int32 nRecvTimeoutSec, int32 nRecvTimeoutUsec = 0); 372 | 373 | /// Enable/disable multicast for a socket. This options is only valid for 374 | /// socket descriptors of type CSimpleSocket::SocketTypeUdp. 375 | /// @return true if multicast was enabled or false if socket type is not 376 | /// CSimpleSocket::SocketTypeUdp and the error will be set to 377 | /// CSimpleSocket::SocketProtocolError 378 | bool SetMulticast(bool bEnable, uint8 multicastTTL = 1); 379 | 380 | /// Return true if socket is multicast or false is socket is unicast 381 | /// @return true if multicast is enabled 382 | bool GetMulticast() { 383 | return m_bIsMulticast; 384 | }; 385 | 386 | /// Bind socket to a specific interface when using multicast. 387 | /// @return true if successfully bound to interface 388 | bool BindInterface(const char *pInterface); 389 | 390 | /// Gets the timeout value that specifies the maximum number of seconds a 391 | /// a call to CSimpleSocket::Send waits until it completes. 392 | /// @return the length of time in seconds 393 | int32 GetSendTimeoutSec(void) { 394 | return m_stSendTimeout.tv_sec; 395 | }; 396 | 397 | /// Gets the timeout value that specifies the maximum number of microseconds 398 | /// a call to CSimpleSocket::Send waits until it completes. 399 | /// @return the length of time in microseconds 400 | int32 GetSendTimeoutUSec(void) { 401 | return m_stSendTimeout.tv_usec; 402 | }; 403 | 404 | /// Gets the timeout value that specifies the maximum amount of time a call 405 | /// to CSimpleSocket::Send waits until it completes. 406 | /// @return the length of time in seconds 407 | bool SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec = 0); 408 | 409 | /// Returns the last error that occured for the instace of the CSimpleSocket 410 | /// instance. This method should be called immediately to retrieve the 411 | /// error code for the failing mehtod call. 412 | /// @return last error that occured. 413 | CSocketError GetSocketError(void) { 414 | return m_socketErrno; 415 | }; 416 | 417 | /// Get the total time the of the last operation in milliseconds. 418 | /// @return number of milliseconds of last operation. 419 | uint32 GetTotalTimeMs() { 420 | return m_timer.GetMilliSeconds(); 421 | }; 422 | 423 | /// Get the total time the of the last operation in microseconds. 424 | /// @return number of microseconds or last operation. 425 | uint32 GetTotalTimeUsec() { 426 | return m_timer.GetMicroSeconds(); 427 | }; 428 | 429 | /// Return Differentiated Services Code Point (DSCP) value currently set on the socket object. 430 | /// @return DSCP for current socket object. 431 | ///

\b NOTE: Windows special notes http://support.microsoft.com/kb/248611. 432 | int GetSocketDscp(void); 433 | 434 | /// Set Differentiated Services Code Point (DSCP) for socket object. 435 | /// @param nDscp value of TOS setting which will be converted to DSCP 436 | /// @return true if DSCP value was properly set 437 | ///

\b NOTE: Windows special notes http://support.microsoft.com/kb/248611. 438 | bool SetSocketDscp(int nDscp); 439 | 440 | /// Return socket descriptor 441 | /// @return socket descriptor which is a signed 32 bit integer. 442 | SOCKET GetSocketDescriptor() { 443 | return m_socket; 444 | }; 445 | 446 | /// Return socket descriptor 447 | /// @return socket descriptor which is a signed 32 bit integer. 448 | CSocketType GetSocketType() { 449 | return m_nSocketType; 450 | }; 451 | 452 | /// Returns clients Internet host address as a string in standard numbers-and-dots notation. 453 | /// @return NULL if invalid 454 | const char *GetClientAddr() { 455 | #pragma warning( disable : 4996 ) 456 | return inet_ntoa(m_stClientSockaddr.sin_addr); 457 | }; 458 | 459 | /// Returns the port number on which the client is connected. 460 | /// @return client port number. 461 | uint16 GetClientPort() { 462 | return m_stClientSockaddr.sin_port; 463 | }; 464 | 465 | /// Returns server Internet host address as a string in standard numbers-and-dots notation. 466 | /// @return NULL if invalid 467 | const char *GetServerAddr() { 468 | #pragma warning( disable : 4996 ) 469 | return inet_ntoa(m_stServerSockaddr.sin_addr); 470 | }; 471 | 472 | /// Returns the port number on which the server is connected. 473 | /// @return server port number. 474 | uint16 GetServerPort() { 475 | return ntohs(m_stServerSockaddr.sin_port); 476 | }; 477 | 478 | /// Get the TCP receive buffer window size for the current socket object. 479 | ///

\b NOTE: Linux will set the receive buffer to twice the value passed. 480 | /// @return zero on failure else the number of bytes of the TCP receive buffer window size if successful. 481 | uint32 GetReceiveWindowSize() { 482 | return GetWindowSize(SO_RCVBUF); 483 | }; 484 | 485 | /// Get the TCP send buffer window size for the current socket object. 486 | ///

\b NOTE: Linux will set the send buffer to twice the value passed. 487 | /// @return zero on failure else the number of bytes of the TCP receive buffer window size if successful. 488 | uint32 GetSendWindowSize() { 489 | return GetWindowSize(SO_SNDBUF); 490 | }; 491 | 492 | /// Set the TCP receive buffer window size for the current socket object. 493 | ///

\b NOTE: Linux will set the receive buffer to twice the value passed. 494 | /// @return zero on failure else the number of bytes of the TCP send buffer window size if successful. 495 | uint32 SetReceiveWindowSize(uint32 nWindowSize) { 496 | return SetWindowSize(SO_RCVBUF, nWindowSize); 497 | }; 498 | 499 | /// Set the TCP send buffer window size for the current socket object. 500 | ///

\b NOTE: Linux will set the send buffer to twice the value passed. 501 | /// @return zero on failure else the number of bytes of the TCP send buffer window size if successful. 502 | uint32 SetSendWindowSize(uint32 nWindowSize) { 503 | return SetWindowSize(SO_SNDBUF, nWindowSize); 504 | }; 505 | 506 | /// Disable the Nagle algorithm (Set TCP_NODELAY to true) 507 | /// @return false if failed to set socket option otherwise return true; 508 | bool DisableNagleAlgoritm(); 509 | 510 | /// Enable the Nagle algorithm (Set TCP_NODELAY to false) 511 | /// @return false if failed to set socket option otherwise return true; 512 | bool EnableNagleAlgoritm(); 513 | 514 | 515 | protected: 516 | /// Set internal socket error to that specified error 517 | /// @param error type of error 518 | void SetSocketError(CSimpleSocket::CSocketError error) { 519 | m_socketErrno = error; 520 | }; 521 | 522 | /// Set object socket handle to that specified as parameter 523 | /// @param socket value of socket descriptor 524 | void SetSocketHandle(SOCKET socket) { 525 | m_socket = socket; 526 | }; 527 | 528 | private: 529 | /// Generic function used to get the send/receive window size 530 | /// @return zero on failure else the number of bytes of the TCP window size if successful. 531 | uint32 GetWindowSize(uint32 nOptionName); 532 | 533 | /// Generic function used to set the send/receive window size 534 | /// @return zero on failure else the number of bytes of the TCP window size if successful. 535 | uint32 SetWindowSize(uint32 nOptionName, uint32 nWindowSize); 536 | 537 | 538 | /// Attempts to send at most nNumItem blocks described by sendVector 539 | /// to the socket descriptor associated with the socket object. 540 | /// @param sendVector pointer to an array of iovec structures 541 | /// @param nNumItems number of items in the vector to process 542 | ///
\b Note: This implementation is for systems that don't natively 543 | /// support this functionality. 544 | /// @return number of bytes actually sent, return of zero means the 545 | /// connection has been shutdown on the other side, and a return of -1 546 | /// means that an error has occurred. 547 | int32 Writev(const struct iovec *pVector, size_t nCount); 548 | 549 | /// Flush the socket descriptor owned by the object. 550 | /// @return true data was successfully sent, else return false; 551 | bool Flush(); 552 | 553 | CSimpleSocket *operator=(CSimpleSocket &socket); 554 | 555 | protected: 556 | SOCKET m_socket; /// socket handle 557 | CSocketError m_socketErrno; /// number of last error 558 | uint8 *m_pBuffer; /// internal send/receive buffer 559 | int32 m_nBufferSize; /// size of internal send/receive buffer 560 | int32 m_nSocketDomain; /// socket type PF_INET, PF_INET6 561 | CSocketType m_nSocketType; /// socket type - UDP, TCP or RAW 562 | int32 m_nBytesReceived; /// number of bytes received 563 | int32 m_nBytesSent; /// number of bytes sent 564 | uint32 m_nFlags; /// socket flags 565 | bool m_bIsBlocking; /// is socket blocking 566 | bool m_bIsMulticast; /// is the UDP socket multicast; 567 | struct timeval m_stConnectTimeout; /// connection timeout 568 | struct timeval m_stRecvTimeout; /// receive timeout 569 | struct timeval m_stSendTimeout; /// send timeout 570 | struct sockaddr_in m_stServerSockaddr; /// server address 571 | struct sockaddr_in m_stClientSockaddr; /// client address 572 | struct sockaddr_in m_stMulticastGroup; /// multicast group to bind to 573 | struct linger m_stLinger; /// linger flag 574 | CStatTimer m_timer; /// internal statistics. 575 | #ifdef WIN32 576 | WSADATA m_hWSAData; /// Windows 577 | #endif 578 | fd_set m_writeFds; /// write file descriptor set 579 | fd_set m_readFds; /// read file descriptor set 580 | fd_set m_errorFds; /// error file descriptor set 581 | }; 582 | 583 | 584 | #endif /* __SOCKET_H__ */ 585 | 586 | -------------------------------------------------------------------------------- /src/SimpleSocket.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------*/ 2 | /* */ 3 | /* CSimpleSocket.cpp - CSimpleSocket Implementation */ 4 | /* */ 5 | /* Author : Mark Carrier (mark@carrierlabs.com) */ 6 | /* */ 7 | /*---------------------------------------------------------------------------*/ 8 | /* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in 19 | * the documentation and/or other materials provided with the 20 | * distribution. 21 | * 22 | * 3. The name of the author may not be used to endorse or promote products 23 | * derived from this software without specific prior written permission. 24 | * 25 | * 4. The name "CarrierLabs" must not be used to 26 | * endorse or promote products derived from this software without 27 | * prior written permission. For written permission, please contact 28 | * mark@carrierlabs.com. 29 | * 30 | * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY 31 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR 34 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 | * OF THE POSSIBILITY OF SUCH DAMAGE. 42 | *----------------------------------------------------------------------------*/ 43 | #include "SimpleSocket.h" 44 | 45 | CSimpleSocket::CSimpleSocket(CSocketType nType) : 46 | m_socket(INVALID_SOCKET), 47 | m_socketErrno(CSimpleSocket::SocketInvalidSocket), 48 | m_pBuffer(NULL), m_nBufferSize(0), m_nSocketDomain(AF_INET), 49 | m_nSocketType(SocketTypeInvalid), m_nBytesReceived(-1), 50 | m_nBytesSent(-1), m_nFlags(0), 51 | m_bIsBlocking(true), m_bIsMulticast(false) 52 | { 53 | SetConnectTimeout(1, 0); 54 | memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); 55 | memset(&m_stSendTimeout, 0, sizeof(struct timeval)); 56 | memset(&m_stLinger, 0, sizeof(struct linger)); 57 | 58 | switch(nType) 59 | { 60 | //---------------------------------------------------------------------- 61 | // Declare socket type stream - TCP 62 | //---------------------------------------------------------------------- 63 | case CSimpleSocket::SocketTypeTcp: 64 | { 65 | m_nSocketDomain = AF_INET; 66 | m_nSocketType = CSimpleSocket::SocketTypeTcp; 67 | break; 68 | } 69 | case CSimpleSocket::SocketTypeTcp6: 70 | { 71 | m_nSocketDomain = AF_INET6; 72 | m_nSocketType = CSimpleSocket::SocketTypeTcp6; 73 | break; 74 | } 75 | //---------------------------------------------------------------------- 76 | // Declare socket type datagram - UDP 77 | //---------------------------------------------------------------------- 78 | case CSimpleSocket::SocketTypeUdp: 79 | { 80 | m_nSocketDomain = AF_INET; 81 | m_nSocketType = CSimpleSocket::SocketTypeUdp; 82 | break; 83 | } 84 | case CSimpleSocket::SocketTypeUdp6: 85 | { 86 | m_nSocketDomain = AF_INET6; 87 | m_nSocketType = CSimpleSocket::SocketTypeUdp6; 88 | break; 89 | } 90 | //---------------------------------------------------------------------- 91 | // Declare socket type raw Ethernet - Ethernet 92 | //---------------------------------------------------------------------- 93 | case CSimpleSocket::SocketTypeRaw: 94 | { 95 | #if defined(_LINUX) && !defined(_DARWIN) 96 | m_nSocketDomain = AF_PACKET; 97 | m_nSocketType = CSimpleSocket::SocketTypeRaw; 98 | #endif 99 | #ifdef _WIN32 100 | m_nSocketType = CSimpleSocket::SocketTypeInvalid; 101 | #endif 102 | break; 103 | } 104 | default: 105 | m_nSocketType = CSimpleSocket::SocketTypeInvalid; 106 | break; 107 | } 108 | } 109 | 110 | CSimpleSocket::CSimpleSocket(CSimpleSocket &socket) 111 | { 112 | m_pBuffer = new uint8[socket.m_nBufferSize]; 113 | m_nBufferSize = socket.m_nBufferSize; 114 | memcpy(m_pBuffer, socket.m_pBuffer, socket.m_nBufferSize); 115 | } 116 | 117 | CSimpleSocket *CSimpleSocket::operator=(CSimpleSocket &socket) 118 | { 119 | if (m_nBufferSize != socket.m_nBufferSize) 120 | { 121 | delete m_pBuffer; 122 | m_pBuffer = new uint8[socket.m_nBufferSize]; 123 | m_nBufferSize = socket.m_nBufferSize; 124 | memcpy(m_pBuffer, socket.m_pBuffer, socket.m_nBufferSize); 125 | } 126 | 127 | return this; 128 | } 129 | 130 | 131 | //------------------------------------------------------------------------------ 132 | // 133 | // Initialize() - Initialize socket class 134 | // 135 | //------------------------------------------------------------------------------ 136 | bool CSimpleSocket::Initialize() 137 | { 138 | errno = CSimpleSocket::SocketSuccess; 139 | 140 | #ifdef WIN32 141 | //------------------------------------------------------------------------- 142 | // Data structure containing general Windows Sockets Info 143 | //------------------------------------------------------------------------- 144 | memset(&m_hWSAData, 0, sizeof(m_hWSAData)); 145 | WSAStartup(MAKEWORD(2, 0), &m_hWSAData); 146 | #endif 147 | 148 | //------------------------------------------------------------------------- 149 | // Create the basic Socket Handle 150 | //------------------------------------------------------------------------- 151 | m_timer.Initialize(); 152 | m_timer.SetStartTime(); 153 | m_socket = socket(m_nSocketDomain, m_nSocketType, 0); 154 | m_timer.SetEndTime(); 155 | 156 | TranslateSocketError(); 157 | 158 | return (IsSocketValid()); 159 | } 160 | 161 | 162 | //------------------------------------------------------------------------------ 163 | // 164 | // BindInterface() 165 | // 166 | //------------------------------------------------------------------------------ 167 | bool CSimpleSocket::BindInterface(const char *pInterface) 168 | { 169 | bool bRetVal = false; 170 | struct in_addr stInterfaceAddr; 171 | 172 | if (GetMulticast() == true) 173 | { 174 | if (pInterface) 175 | { 176 | stInterfaceAddr.s_addr= inet_addr(pInterface); 177 | if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_MULTICAST_IF, &stInterfaceAddr, sizeof(stInterfaceAddr)) == SocketSuccess) 178 | { 179 | bRetVal = true; 180 | } 181 | } 182 | } 183 | else 184 | { 185 | SetSocketError(CSimpleSocket::SocketProtocolError); 186 | } 187 | 188 | return bRetVal; 189 | } 190 | 191 | 192 | //------------------------------------------------------------------------------ 193 | // 194 | // SetMulticast() 195 | // 196 | //------------------------------------------------------------------------------ 197 | bool CSimpleSocket::SetMulticast(bool bEnable, uint8 multicastTTL) 198 | { 199 | bool bRetVal = false; 200 | 201 | if (GetSocketType() == CSimpleSocket::SocketTypeUdp) 202 | { 203 | m_bIsMulticast = bEnable; 204 | if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&multicastTTL, sizeof(multicastTTL)) == SocketError) 205 | { 206 | TranslateSocketError(); 207 | bRetVal = false; 208 | } 209 | else 210 | { 211 | bRetVal = true; 212 | } 213 | } 214 | else 215 | { 216 | m_socketErrno = CSimpleSocket::SocketProtocolError; 217 | } 218 | 219 | return bRetVal; 220 | } 221 | 222 | 223 | //------------------------------------------------------------------------------ 224 | // 225 | // SetSocketDscp() 226 | // 227 | //------------------------------------------------------------------------------ 228 | bool CSimpleSocket::SetSocketDscp(int32 nDscp) 229 | { 230 | bool bRetVal = true; 231 | int32 nTempVal = nDscp; 232 | 233 | nTempVal <<= 4; 234 | nTempVal /= 4; 235 | 236 | if (IsSocketValid()) 237 | { 238 | if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_TOS, &nTempVal, sizeof(nTempVal)) == SocketError) 239 | { 240 | TranslateSocketError(); 241 | bRetVal = false; 242 | } 243 | } 244 | 245 | return bRetVal; 246 | } 247 | 248 | 249 | //------------------------------------------------------------------------------ 250 | // 251 | // GetSocketDscp() 252 | // 253 | //------------------------------------------------------------------------------ 254 | int32 CSimpleSocket::GetSocketDscp(void) 255 | { 256 | int32 nTempVal = 0; 257 | socklen_t nLen = 0; 258 | 259 | if (IsSocketValid()) 260 | { 261 | if (GETSOCKOPT(m_socket, IPPROTO_IP, IP_TOS, &nTempVal, &nLen) == SocketError) 262 | { 263 | TranslateSocketError(); 264 | } 265 | 266 | nTempVal *= 4; 267 | nTempVal >>= 4; 268 | } 269 | 270 | return nTempVal; 271 | } 272 | 273 | 274 | //------------------------------------------------------------------------------ 275 | // 276 | // GetWindowSize() 277 | // 278 | //------------------------------------------------------------------------------ 279 | uint32 CSimpleSocket::GetWindowSize(uint32 nOptionName) 280 | { 281 | uint32 nTcpWinSize = 0; 282 | 283 | //------------------------------------------------------------------------- 284 | // no socket given, return system default allocate our own new socket 285 | //------------------------------------------------------------------------- 286 | if (m_socket != CSimpleSocket::SocketError) 287 | { 288 | socklen_t nLen = sizeof(nTcpWinSize); 289 | 290 | //--------------------------------------------------------------------- 291 | // query for buffer size 292 | //--------------------------------------------------------------------- 293 | GETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nTcpWinSize, &nLen); 294 | TranslateSocketError(); 295 | } 296 | else 297 | { 298 | SetSocketError(CSimpleSocket::SocketInvalidSocket); 299 | } 300 | 301 | return nTcpWinSize; 302 | } 303 | 304 | 305 | //------------------------------------------------------------------------------ 306 | // 307 | // SetWindowSize() 308 | // 309 | //------------------------------------------------------------------------------ 310 | uint32 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize) 311 | { 312 | //------------------------------------------------------------------------- 313 | // no socket given, return system default allocate our own new socket 314 | //------------------------------------------------------------------------- 315 | if (m_socket != CSimpleSocket::SocketError) 316 | { 317 | SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); 318 | TranslateSocketError(); 319 | } 320 | else 321 | { 322 | SetSocketError(CSimpleSocket::SocketInvalidSocket); 323 | } 324 | 325 | return nWindowSize; 326 | } 327 | 328 | 329 | //------------------------------------------------------------------------------ 330 | // 331 | // DisableNagleAlgorithm() 332 | // 333 | //------------------------------------------------------------------------------ 334 | bool CSimpleSocket::DisableNagleAlgoritm() 335 | { 336 | bool bRetVal = false; 337 | int32 nTcpNoDelay = 1; 338 | 339 | //---------------------------------------------------------------------- 340 | // Set TCP NoDelay flag to true 341 | //---------------------------------------------------------------------- 342 | if (SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nTcpNoDelay, sizeof(int32)) == 0) 343 | { 344 | bRetVal = true; 345 | } 346 | 347 | TranslateSocketError(); 348 | 349 | return bRetVal; 350 | } 351 | 352 | 353 | //------------------------------------------------------------------------------ 354 | // 355 | // EnableNagleAlgorithm() 356 | // 357 | //------------------------------------------------------------------------------ 358 | bool CSimpleSocket::EnableNagleAlgoritm() 359 | { 360 | bool bRetVal = false; 361 | int32 nTcpNoDelay = 0; 362 | 363 | //---------------------------------------------------------------------- 364 | // Set TCP NoDelay flag to false 365 | //---------------------------------------------------------------------- 366 | if (SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nTcpNoDelay, sizeof(int32)) == 0) 367 | { 368 | bRetVal = true; 369 | } 370 | 371 | TranslateSocketError(); 372 | 373 | return bRetVal; 374 | } 375 | 376 | 377 | //------------------------------------------------------------------------------ 378 | // 379 | // Send() - Send data on a valid socket 380 | // 381 | //------------------------------------------------------------------------------ 382 | int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend) 383 | { 384 | SetSocketError(SocketSuccess); 385 | m_nBytesSent = 0; 386 | 387 | switch(m_nSocketType) 388 | { 389 | case CSimpleSocket::SocketTypeTcp: 390 | { 391 | if (IsSocketValid()) 392 | { 393 | if ((bytesToSend > 0) && (pBuf != NULL)) 394 | { 395 | m_timer.Initialize(); 396 | m_timer.SetStartTime(); 397 | 398 | //--------------------------------------------------------- 399 | // Check error condition and attempt to resend if call 400 | // was interrupted by a signal. 401 | //--------------------------------------------------------- 402 | do 403 | { 404 | m_nBytesSent = SEND(m_socket, pBuf, bytesToSend, 0); 405 | TranslateSocketError(); 406 | } while (GetSocketError() == CSimpleSocket::SocketInterrupted); 407 | 408 | m_timer.SetEndTime(); 409 | } 410 | } 411 | break; 412 | } 413 | case CSimpleSocket::SocketTypeUdp: 414 | { 415 | if (IsSocketValid()) 416 | { 417 | if ((bytesToSend > 0) && (pBuf != NULL)) 418 | { 419 | m_timer.Initialize(); 420 | m_timer.SetStartTime(); 421 | 422 | //--------------------------------------------------------- 423 | // Check error condition and attempt to resend if call 424 | // was interrupted by a signal. 425 | //--------------------------------------------------------- 426 | // if (GetMulticast()) 427 | // { 428 | // do 429 | // { 430 | // m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, (const sockaddr *)&m_stMulticastGroup, 431 | // sizeof(m_stMulticastGroup)); 432 | // TranslateSocketError(); 433 | // } while (GetSocketError() == CSimpleSocket::SocketInterrupted); 434 | // } 435 | // else 436 | { 437 | do 438 | { 439 | m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, (const sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr)); 440 | TranslateSocketError(); 441 | } while (GetSocketError() == CSimpleSocket::SocketInterrupted); 442 | } 443 | 444 | m_timer.SetEndTime(); 445 | } 446 | } 447 | break; 448 | } 449 | default: 450 | break; 451 | } 452 | 453 | return m_nBytesSent; 454 | } 455 | 456 | 457 | //------------------------------------------------------------------------------ 458 | // 459 | // Close() - Close socket and free up any memory allocated for the socket 460 | // 461 | //------------------------------------------------------------------------------ 462 | bool CSimpleSocket::Close(void) 463 | { 464 | bool bRetVal = false; 465 | 466 | //-------------------------------------------------------------------------- 467 | // delete internal buffer 468 | //-------------------------------------------------------------------------- 469 | if (m_pBuffer != NULL) 470 | { 471 | delete [] m_pBuffer; 472 | m_pBuffer = NULL; 473 | } 474 | 475 | //-------------------------------------------------------------------------- 476 | // if socket handle is currently valid, close and then invalidate 477 | //-------------------------------------------------------------------------- 478 | if (IsSocketValid()) 479 | { 480 | if (CLOSE(m_socket) != CSimpleSocket::SocketError) 481 | { 482 | m_socket = INVALID_SOCKET; 483 | bRetVal = true; 484 | } 485 | } 486 | 487 | TranslateSocketError(); 488 | 489 | return bRetVal; 490 | } 491 | 492 | 493 | //------------------------------------------------------------------------------ 494 | // 495 | // Shtudown() 496 | // 497 | //------------------------------------------------------------------------------ 498 | bool CSimpleSocket::Shutdown(CShutdownMode nShutdown) 499 | { 500 | CSocketError nRetVal = SocketEunknown; 501 | 502 | nRetVal = (CSocketError)shutdown(m_socket, nShutdown); 503 | TranslateSocketError(); 504 | 505 | return (nRetVal == CSimpleSocket::SocketSuccess) ? true: false; 506 | } 507 | 508 | 509 | //------------------------------------------------------------------------------ 510 | // 511 | // Flush() 512 | // 513 | //------------------------------------------------------------------------------ 514 | bool CSimpleSocket::Flush() 515 | { 516 | int32 nTcpNoDelay = 1; 517 | int32 nCurFlags = 0; 518 | uint8 tmpbuf = 0; 519 | bool bRetVal = false; 520 | 521 | //-------------------------------------------------------------------------- 522 | // Get the current setting of the TCP_NODELAY flag. 523 | //-------------------------------------------------------------------------- 524 | if (GETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nCurFlags, sizeof(int32)) == 0) 525 | { 526 | //---------------------------------------------------------------------- 527 | // Set TCP NoDelay flag 528 | //---------------------------------------------------------------------- 529 | if (SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nTcpNoDelay, sizeof(int32)) == 0) 530 | { 531 | //------------------------------------------------------------------ 532 | // Send empty byte stream to flush the TCP send buffer 533 | //------------------------------------------------------------------ 534 | if (Send(&tmpbuf, 0) != CSimpleSocket::SocketError) 535 | { 536 | bRetVal = true; 537 | } 538 | 539 | TranslateSocketError(); 540 | } 541 | 542 | //---------------------------------------------------------------------- 543 | // Reset the TCP_NODELAY flag to original state. 544 | //---------------------------------------------------------------------- 545 | SETSOCKOPT(m_socket, IPPROTO_TCP, TCP_NODELAY, &nCurFlags, sizeof(int32)); 546 | } 547 | 548 | return bRetVal; 549 | } 550 | 551 | 552 | //------------------------------------------------------------------------------ 553 | // 554 | // Writev - 555 | // 556 | //------------------------------------------------------------------------------ 557 | int32 CSimpleSocket::Writev(const struct iovec *pVector, size_t nCount) 558 | { 559 | int32 nBytes = 0; 560 | int32 nBytesSent = 0; 561 | int32 i = 0; 562 | 563 | //-------------------------------------------------------------------------- 564 | // Send each buffer as a separate send, windows does not support this 565 | // function call. 566 | //-------------------------------------------------------------------------- 567 | for (i = 0; i < (int32)nCount; i++) 568 | { 569 | if ((nBytes = Send((uint8 *)pVector[i].iov_base, pVector[i].iov_len)) == CSimpleSocket::SocketError) 570 | { 571 | break; 572 | } 573 | 574 | nBytesSent += nBytes; 575 | } 576 | 577 | if (i > 0) 578 | { 579 | Flush(); 580 | } 581 | 582 | return nBytesSent; 583 | } 584 | 585 | 586 | //------------------------------------------------------------------------------ 587 | // 588 | // Send() - Send data on a valid socket via a vector of buffers. 589 | // 590 | //------------------------------------------------------------------------------ 591 | int32 CSimpleSocket::Send(const struct iovec *sendVector, int32 nNumItems) 592 | { 593 | SetSocketError(SocketSuccess); 594 | m_nBytesSent = 0; 595 | 596 | if ((m_nBytesSent = WRITEV(m_socket, sendVector, nNumItems)) == CSimpleSocket::SocketError) 597 | { 598 | TranslateSocketError(); 599 | } 600 | 601 | return m_nBytesSent; 602 | } 603 | 604 | 605 | //------------------------------------------------------------------------------ 606 | // 607 | // SetReceiveTimeout() 608 | // 609 | //------------------------------------------------------------------------------ 610 | bool CSimpleSocket::SetReceiveTimeout(int32 nRecvTimeoutSec, int32 nRecvTimeoutUsec) 611 | { 612 | bool bRetVal = true; 613 | 614 | memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); 615 | 616 | m_stRecvTimeout.tv_sec = nRecvTimeoutSec; 617 | m_stRecvTimeout.tv_usec = nRecvTimeoutUsec; 618 | 619 | //-------------------------------------------------------------------------- 620 | // Sanity check to make sure the options are supported! 621 | //-------------------------------------------------------------------------- 622 | if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_RCVTIMEO, &m_stRecvTimeout, 623 | sizeof(struct timeval)) == CSimpleSocket::SocketError) 624 | { 625 | bRetVal = false; 626 | TranslateSocketError(); 627 | } 628 | 629 | return bRetVal; 630 | } 631 | 632 | 633 | //------------------------------------------------------------------------------ 634 | // 635 | // SetSendTimeout() 636 | // 637 | //------------------------------------------------------------------------------ 638 | bool CSimpleSocket::SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec) 639 | { 640 | bool bRetVal = true; 641 | 642 | memset(&m_stSendTimeout, 0, sizeof(struct timeval)); 643 | m_stSendTimeout.tv_sec = nSendTimeoutSec; 644 | m_stSendTimeout.tv_usec = nSendTimeoutUsec; 645 | 646 | //-------------------------------------------------------------------------- 647 | // Sanity check to make sure the options are supported! 648 | //-------------------------------------------------------------------------- 649 | if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_SNDTIMEO, &m_stSendTimeout, 650 | sizeof(struct timeval)) == CSimpleSocket::SocketError) 651 | { 652 | bRetVal = false; 653 | TranslateSocketError(); 654 | } 655 | 656 | return bRetVal; 657 | } 658 | 659 | 660 | //------------------------------------------------------------------------------ 661 | // 662 | // SetOptionReuseAddr() 663 | // 664 | //------------------------------------------------------------------------------ 665 | bool CSimpleSocket::SetOptionReuseAddr() 666 | { 667 | bool bRetVal = false; 668 | int32 nReuse = IPTOS_LOWDELAY; 669 | 670 | if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nReuse, sizeof(int32)) == 0) 671 | { 672 | bRetVal = true; 673 | } 674 | 675 | TranslateSocketError(); 676 | 677 | return bRetVal; 678 | } 679 | 680 | 681 | //------------------------------------------------------------------------------ 682 | // 683 | // SetOptionLinger() 684 | // 685 | //------------------------------------------------------------------------------ 686 | bool CSimpleSocket::SetOptionLinger(bool bEnable, uint16 nTime) 687 | { 688 | bool bRetVal = false; 689 | 690 | m_stLinger.l_onoff = (bEnable == true) ? 1: 0; 691 | m_stLinger.l_linger = nTime; 692 | 693 | if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_LINGER, &m_stLinger, sizeof(m_stLinger)) == 0) 694 | { 695 | bRetVal = true; 696 | } 697 | 698 | TranslateSocketError(); 699 | 700 | return bRetVal; 701 | } 702 | 703 | 704 | //------------------------------------------------------------------------------ 705 | // 706 | // Receive() - Attempts to receive a block of data on an established 707 | // connection. Data is received in an internal buffer managed 708 | // by the class. This buffer is only valid until the next call 709 | // to Receive(), a call to Close(), or until the object goes out 710 | // of scope. 711 | // 712 | //------------------------------------------------------------------------------ 713 | int32 CSimpleSocket::Receive(int32 nMaxBytes, uint8 * pBuffer ) 714 | { 715 | m_nBytesReceived = 0; 716 | 717 | //-------------------------------------------------------------------------- 718 | // If the socket is invalid then return false. 719 | //-------------------------------------------------------------------------- 720 | if (IsSocketValid() == false) 721 | { 722 | return m_nBytesReceived; 723 | } 724 | 725 | uint8 * pWorkBuffer = pBuffer; 726 | if ( pBuffer == NULL ) 727 | { 728 | //-------------------------------------------------------------------------- 729 | // Free existing buffer and allocate a new buffer the size of 730 | // nMaxBytes. 731 | //-------------------------------------------------------------------------- 732 | if ((m_pBuffer != NULL) && (nMaxBytes != m_nBufferSize)) 733 | { 734 | delete [] m_pBuffer; 735 | m_pBuffer = NULL; 736 | } 737 | 738 | //-------------------------------------------------------------------------- 739 | // Allocate a new internal buffer to receive data. 740 | //-------------------------------------------------------------------------- 741 | if (m_pBuffer == NULL) 742 | { 743 | m_nBufferSize = nMaxBytes; 744 | m_pBuffer = new uint8[nMaxBytes]; 745 | } 746 | 747 | pWorkBuffer = m_pBuffer; 748 | } 749 | 750 | SetSocketError(SocketSuccess); 751 | 752 | m_timer.Initialize(); 753 | m_timer.SetStartTime(); 754 | 755 | switch (m_nSocketType) 756 | { 757 | //---------------------------------------------------------------------- 758 | // If zero bytes are received, then return. If SocketERROR is 759 | // received, free buffer and return CSocket::SocketError (-1) to caller. 760 | //---------------------------------------------------------------------- 761 | case CSimpleSocket::SocketTypeTcp: 762 | { 763 | do 764 | { 765 | m_nBytesReceived = RECV(m_socket, (pWorkBuffer + m_nBytesReceived), 766 | nMaxBytes, m_nFlags); 767 | TranslateSocketError(); 768 | } while ((GetSocketError() == CSimpleSocket::SocketInterrupted)); 769 | 770 | break; 771 | } 772 | case CSimpleSocket::SocketTypeUdp: 773 | { 774 | uint32 srcSize; 775 | 776 | srcSize = sizeof(struct sockaddr_in); 777 | 778 | if (GetMulticast() == true) 779 | { 780 | do 781 | { 782 | m_nBytesReceived = RECVFROM(m_socket, pWorkBuffer, nMaxBytes, 0, 783 | &m_stMulticastGroup, &srcSize); 784 | TranslateSocketError(); 785 | } while (GetSocketError() == CSimpleSocket::SocketInterrupted); 786 | } 787 | else 788 | { 789 | do 790 | { 791 | m_nBytesReceived = RECVFROM(m_socket, pWorkBuffer, nMaxBytes, 0, 792 | &m_stClientSockaddr, &srcSize); 793 | TranslateSocketError(); 794 | } while (GetSocketError() == CSimpleSocket::SocketInterrupted); 795 | } 796 | 797 | break; 798 | } 799 | default: 800 | break; 801 | } 802 | 803 | m_timer.SetEndTime(); 804 | TranslateSocketError(); 805 | 806 | //-------------------------------------------------------------------------- 807 | // If we encounter an error translate the error code and return. One 808 | // possible error code could be EAGAIN (EWOULDBLOCK) if the socket is 809 | // non-blocking. This does not mean there is an error, but no data is 810 | // yet available on the socket. 811 | //-------------------------------------------------------------------------- 812 | if (m_nBytesReceived == CSimpleSocket::SocketError) 813 | { 814 | if (m_pBuffer != NULL) 815 | { 816 | delete [] m_pBuffer; 817 | m_pBuffer = NULL; 818 | } 819 | } 820 | 821 | return m_nBytesReceived; 822 | } 823 | 824 | 825 | //------------------------------------------------------------------------------ 826 | // 827 | // SetNonblocking() 828 | // 829 | //------------------------------------------------------------------------------ 830 | bool CSimpleSocket::SetNonblocking(void) 831 | { 832 | int32 nCurFlags; 833 | 834 | #if WIN32 835 | nCurFlags = 1; 836 | 837 | if (ioctlsocket(m_socket, FIONBIO, (ULONG *)&nCurFlags) != 0) 838 | { 839 | TranslateSocketError(); 840 | return false; 841 | } 842 | #else 843 | if ((nCurFlags = fcntl(m_socket, F_GETFL)) < 0) 844 | { 845 | TranslateSocketError(); 846 | return false; 847 | } 848 | 849 | nCurFlags |= O_NONBLOCK; 850 | 851 | if (fcntl(m_socket, F_SETFL, nCurFlags) != 0) 852 | { 853 | TranslateSocketError(); 854 | return false; 855 | } 856 | #endif 857 | 858 | m_bIsBlocking = false; 859 | 860 | return true; 861 | } 862 | 863 | 864 | //------------------------------------------------------------------------------ 865 | // 866 | // SetBlocking() 867 | // 868 | //------------------------------------------------------------------------------ 869 | bool CSimpleSocket::SetBlocking(void) 870 | { 871 | int32 nCurFlags; 872 | 873 | #if WIN32 874 | nCurFlags = 0; 875 | 876 | if (ioctlsocket(m_socket, FIONBIO, (ULONG *)&nCurFlags) != 0) 877 | { 878 | return false; 879 | } 880 | #else 881 | if ((nCurFlags = fcntl(m_socket, F_GETFL)) < 0) 882 | { 883 | TranslateSocketError(); 884 | return false; 885 | } 886 | 887 | nCurFlags &= (~O_NONBLOCK); 888 | 889 | if (fcntl(m_socket, F_SETFL, nCurFlags) != 0) 890 | { 891 | TranslateSocketError(); 892 | return false; 893 | } 894 | #endif 895 | m_bIsBlocking = true; 896 | 897 | return true; 898 | } 899 | 900 | 901 | //------------------------------------------------------------------------------ 902 | // 903 | // SendFile() - stands-in for system provided sendfile 904 | // 905 | //------------------------------------------------------------------------------ 906 | int32 CSimpleSocket::SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 nCount) 907 | { 908 | int32 nOutCount = CSimpleSocket::SocketError; 909 | 910 | static char szData[SOCKET_SENDFILE_BLOCKSIZE]; 911 | int32 nInCount = 0; 912 | 913 | if (lseek(nInFd, *pOffset, SEEK_SET) == -1) 914 | { 915 | return -1; 916 | } 917 | 918 | while (nOutCount < nCount) 919 | { 920 | nInCount = (nCount - nOutCount) < SOCKET_SENDFILE_BLOCKSIZE ? (nCount - nOutCount) : SOCKET_SENDFILE_BLOCKSIZE; 921 | 922 | if ((read(nInFd, szData, nInCount)) != (int32)nInCount) 923 | { 924 | return -1; 925 | } 926 | 927 | if ((SEND(nOutFd, szData, nInCount, 0)) != (int32)nInCount) 928 | { 929 | return -1; 930 | } 931 | 932 | nOutCount += nInCount; 933 | } 934 | 935 | *pOffset += nOutCount; 936 | 937 | TranslateSocketError(); 938 | 939 | return nOutCount; 940 | } 941 | 942 | 943 | //------------------------------------------------------------------------------ 944 | // 945 | // TranslateSocketError() - 946 | // 947 | //------------------------------------------------------------------------------ 948 | void CSimpleSocket::TranslateSocketError(void) 949 | { 950 | #if defined(_LINUX) || defined(_DARWIN) 951 | switch (errno) 952 | { 953 | case EXIT_SUCCESS: 954 | SetSocketError(CSimpleSocket::SocketSuccess); 955 | break; 956 | case ENOTCONN: 957 | SetSocketError(CSimpleSocket::SocketNotconnected); 958 | break; 959 | case ENOTSOCK: 960 | case EBADF: 961 | case EACCES: 962 | case EAFNOSUPPORT: 963 | case EMFILE: 964 | case ENFILE: 965 | case ENOBUFS: 966 | case ENOMEM: 967 | case EPROTONOSUPPORT: 968 | case EPIPE: 969 | case EOPNOTSUPP: 970 | SetSocketError(CSimpleSocket::SocketInvalidSocket); 971 | break; 972 | case ECONNREFUSED : 973 | SetSocketError(CSimpleSocket::SocketConnectionRefused); 974 | break; 975 | case ETIMEDOUT: 976 | SetSocketError(CSimpleSocket::SocketTimedout); 977 | break; 978 | case EINPROGRESS: 979 | SetSocketError(CSimpleSocket::SocketEinprogress); 980 | break; 981 | case EWOULDBLOCK: 982 | // case EAGAIN: 983 | SetSocketError(CSimpleSocket::SocketEwouldblock); 984 | break; 985 | case EINTR: 986 | SetSocketError(CSimpleSocket::SocketInterrupted); 987 | break; 988 | case ECONNABORTED: 989 | SetSocketError(CSimpleSocket::SocketConnectionAborted); 990 | break; 991 | case EINVAL: 992 | case EPROTO: 993 | SetSocketError(CSimpleSocket::SocketProtocolError); 994 | break; 995 | case EPERM: 996 | SetSocketError(CSimpleSocket::SocketFirewallError); 997 | break; 998 | case EFAULT: 999 | SetSocketError(CSimpleSocket::SocketInvalidSocketBuffer); 1000 | break; 1001 | case ECONNRESET: 1002 | case ENOPROTOOPT: 1003 | SetSocketError(CSimpleSocket::SocketConnectionReset); 1004 | break; 1005 | case EADDRINUSE: 1006 | SetSocketError(CSimpleSocket::SocketAddressInUse); 1007 | break; 1008 | default: 1009 | SetSocketError(CSimpleSocket::SocketEunknown); 1010 | break; 1011 | } 1012 | #endif 1013 | #ifdef WIN32 1014 | int32 nError = WSAGetLastError(); 1015 | switch (nError) 1016 | { 1017 | case EXIT_SUCCESS: 1018 | SetSocketError(CSimpleSocket::SocketSuccess); 1019 | break; 1020 | case WSAEBADF: 1021 | case WSAENOTCONN: 1022 | SetSocketError(CSimpleSocket::SocketNotconnected); 1023 | break; 1024 | case WSAEINTR: 1025 | SetSocketError(CSimpleSocket::SocketInterrupted); 1026 | break; 1027 | case WSAEACCES: 1028 | case WSAEAFNOSUPPORT: 1029 | case WSAEINVAL: 1030 | case WSAEMFILE: 1031 | case WSAENOBUFS: 1032 | case WSAEPROTONOSUPPORT: 1033 | SetSocketError(CSimpleSocket::SocketInvalidSocket); 1034 | break; 1035 | case WSAECONNREFUSED : 1036 | SetSocketError(CSimpleSocket::SocketConnectionRefused); 1037 | break; 1038 | case WSAETIMEDOUT: 1039 | SetSocketError(CSimpleSocket::SocketTimedout); 1040 | break; 1041 | case WSAEINPROGRESS: 1042 | SetSocketError(CSimpleSocket::SocketEinprogress); 1043 | break; 1044 | case WSAECONNABORTED: 1045 | SetSocketError(CSimpleSocket::SocketConnectionAborted); 1046 | break; 1047 | case WSAEWOULDBLOCK: 1048 | SetSocketError(CSimpleSocket::SocketEwouldblock); 1049 | break; 1050 | case WSAENOTSOCK: 1051 | SetSocketError(CSimpleSocket::SocketInvalidSocket); 1052 | break; 1053 | case WSAECONNRESET: 1054 | SetSocketError(CSimpleSocket::SocketConnectionReset); 1055 | break; 1056 | case WSANO_DATA: 1057 | SetSocketError(CSimpleSocket::SocketInvalidAddress); 1058 | break; 1059 | case WSAEADDRINUSE: 1060 | SetSocketError(CSimpleSocket::SocketAddressInUse); 1061 | break; 1062 | case WSAEFAULT: 1063 | SetSocketError(CSimpleSocket::SocketInvalidPointer); 1064 | break; 1065 | default: 1066 | SetSocketError(CSimpleSocket::SocketEunknown); 1067 | break; 1068 | } 1069 | #endif 1070 | } 1071 | 1072 | //------------------------------------------------------------------------------ 1073 | // 1074 | // DescribeError() 1075 | // 1076 | //------------------------------------------------------------------------------ 1077 | 1078 | const char *CSimpleSocket::DescribeError(CSocketError err) 1079 | { 1080 | switch (err) { 1081 | case CSimpleSocket::SocketError: 1082 | return "Generic socket error translates to error below."; 1083 | case CSimpleSocket::SocketSuccess: 1084 | return "No socket error."; 1085 | case CSimpleSocket::SocketInvalidSocket: 1086 | return "Invalid socket handle."; 1087 | case CSimpleSocket::SocketInvalidAddress: 1088 | return "Invalid destination address specified."; 1089 | case CSimpleSocket::SocketInvalidPort: 1090 | return "Invalid destination port specified."; 1091 | case CSimpleSocket::SocketConnectionRefused: 1092 | return "No server is listening at remote address."; 1093 | case CSimpleSocket::SocketTimedout: 1094 | return "Timed out while attempting operation."; 1095 | case CSimpleSocket::SocketEwouldblock: 1096 | return "Operation would block if socket were blocking."; 1097 | case CSimpleSocket::SocketNotconnected: 1098 | return "Currently not connected."; 1099 | case CSimpleSocket::SocketEinprogress: 1100 | return "Socket is non-blocking and the connection cannot be completed immediately"; 1101 | case CSimpleSocket::SocketInterrupted: 1102 | return "Call was interrupted by a signal that was caught before a valid connection arrived."; 1103 | case CSimpleSocket::SocketConnectionAborted: 1104 | return "The connection has been aborted."; 1105 | case CSimpleSocket::SocketProtocolError: 1106 | return "Invalid protocol for operation."; 1107 | case CSimpleSocket::SocketFirewallError: 1108 | return "Firewall rules forbid connection."; 1109 | case CSimpleSocket::SocketInvalidSocketBuffer: 1110 | return "The receive buffer point outside the process's address space."; 1111 | case CSimpleSocket::SocketConnectionReset: 1112 | return "Connection was forcibly closed by the remote host."; 1113 | case CSimpleSocket::SocketAddressInUse: 1114 | return "Address already in use."; 1115 | case CSimpleSocket::SocketInvalidPointer: 1116 | return "Pointer type supplied as argument is invalid."; 1117 | case CSimpleSocket::SocketEunknown: 1118 | return "Unknown error"; 1119 | default: 1120 | return "No such CSimpleSocket error"; 1121 | } 1122 | } 1123 | 1124 | //------------------------------------------------------------------------------ 1125 | // 1126 | // Select() 1127 | // 1128 | //------------------------------------------------------------------------------ 1129 | bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec) 1130 | { 1131 | bool bRetVal = false; 1132 | struct timeval *pTimeout = NULL; 1133 | struct timeval timeout; 1134 | int32 nNumDescriptors = -1; 1135 | int32 nError = 0; 1136 | 1137 | FD_ZERO(&m_errorFds); 1138 | FD_ZERO(&m_readFds); 1139 | FD_ZERO(&m_writeFds); 1140 | FD_SET(m_socket, &m_errorFds); 1141 | FD_SET(m_socket, &m_readFds); 1142 | FD_SET(m_socket, &m_writeFds); 1143 | 1144 | //--------------------------------------------------------------------- 1145 | // If timeout has been specified then set value, otherwise set timeout 1146 | // to NULL which will block until a descriptor is ready for read/write 1147 | // or an error has occurred. 1148 | //--------------------------------------------------------------------- 1149 | if ((nTimeoutSec > 0) || (nTimeoutUSec > 0)) 1150 | { 1151 | timeout.tv_sec = nTimeoutSec; 1152 | timeout.tv_usec = nTimeoutUSec; 1153 | pTimeout = &timeout; 1154 | } 1155 | 1156 | nNumDescriptors = SELECT(m_socket+1, &m_readFds, &m_writeFds, &m_errorFds, pTimeout); 1157 | // nNumDescriptors = SELECT(m_socket+1, &m_readFds, NULL, NULL, pTimeout); 1158 | 1159 | //---------------------------------------------------------------------- 1160 | // Handle timeout 1161 | //---------------------------------------------------------------------- 1162 | if (nNumDescriptors == 0) 1163 | { 1164 | SetSocketError(CSimpleSocket::SocketTimedout); 1165 | } 1166 | //---------------------------------------------------------------------- 1167 | // If a file descriptor (read/write) is set then check the 1168 | // socket error (SO_ERROR) to see if there is a pending error. 1169 | //---------------------------------------------------------------------- 1170 | else if ((FD_ISSET(m_socket, &m_readFds)) || (FD_ISSET(m_socket, &m_writeFds))) 1171 | { 1172 | int32 nLen = sizeof(nError); 1173 | 1174 | if (GETSOCKOPT(m_socket, SOL_SOCKET, SO_ERROR, &nError, &nLen) == 0) 1175 | { 1176 | errno = nError; 1177 | 1178 | if (nError == 0) 1179 | { 1180 | bRetVal = true; 1181 | } 1182 | } 1183 | 1184 | TranslateSocketError(); 1185 | } 1186 | 1187 | return bRetVal; 1188 | } 1189 | 1190 | --------------------------------------------------------------------------------