From 322c9526c213d94a5ec0ff4e0d049fed403f158d Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Fri, 17 Jun 2016 08:29:42 +0200 Subject: [PATCH 01/19] made mingw platform compile statically without dependency to libwinpthread, libstdc++, .. build examples also on mingw Signed-off-by: hayati ayguen --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ad61c9..1fb4f8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(clsocket) + # set up versioning. set(BUILD_MAJOR "1") set(BUILD_MINOR "4") @@ -44,6 +45,12 @@ elseif(WIN32) SET(PROJECT_LIBS Ws2_32.lib) if(MINGW) # Special MINGW stuff here + # see https://cmake.org/pipermail/cmake/2012-September/051970.html + # see http://stackoverflow.com/questions/13768515/how-to-do-static-linking-of-libwinpthread-1-dll-in-mingw + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -static-libgcc") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++") + set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static -static-libgcc -s") + set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static -static-libgcc -static-libstdc++ -s") elseif(MSVC) # Special MSVC stuff here add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) @@ -83,7 +90,7 @@ endif() set_target_properties(clsocket PROPERTIES VERSION ${BUILD_VERSION} SOVERSION ${BUILD_MAJOR}) -if(UNIX) +if(UNIX OR (WIN32 AND MINGW)) OPTION(CLSOCKET_EXAMPLES "Build the examples" OFF) if(CLSOCKET_EXAMPLES) From a3194760fb05f2bbaf9a7e8fad3df3cc0ad2ba83 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Fri, 17 Jun 2016 08:37:27 +0200 Subject: [PATCH 02/19] reduced to 2 classes: PassiveSocket and SimpleSocket moved Open() and ConnectXX methods from ActiveSocket into SimpleSocket PassiveSocket now returns SimpleSocket at Accept() ActiveSocket got unnecessary .. but kept file for compatibility Signed-off-by: hayati ayguen --- CMakeLists.txt | 1 - examples/EchoServer.cpp | 2 +- src/ActiveSocket.cpp | 310 ---------------------------------------- src/ActiveSocket.h | 37 +---- src/PassiveSocket.cpp | 12 +- src/PassiveSocket.h | 10 +- src/SimpleSocket.cpp | 294 ++++++++++++++++++++++++++++++++++++- src/SimpleSocket.h | 58 ++++++-- 8 files changed, 352 insertions(+), 372 deletions(-) delete mode 100644 src/ActiveSocket.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fb4f8a..adef434 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,6 @@ src/StatTimer.h SET(CLSOCKET_SOURCES src/SimpleSocket.cpp -src/ActiveSocket.cpp src/PassiveSocket.cpp ) diff --git a/examples/EchoServer.cpp b/examples/EchoServer.cpp index 4a27d27..ae141e3 100644 --- a/examples/EchoServer.cpp +++ b/examples/EchoServer.cpp @@ -6,7 +6,7 @@ int main(int argc, char **argv) { CPassiveSocket socket; - CActiveSocket *pClient = NULL; + CSimpleSocket *pClient = NULL; //-------------------------------------------------------------------------- // Initialize our socket object diff --git a/src/ActiveSocket.cpp b/src/ActiveSocket.cpp deleted file mode 100644 index 3dd5b12..0000000 --- a/src/ActiveSocket.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/*---------------------------------------------------------------------------*/ -/* */ -/* CActiveSocket.cpp - Active Socket Implementation */ -/* */ -/* Author : Mark Carrier (mark@carrierlabs.com) */ -/* */ -/*---------------------------------------------------------------------------*/ -/* Copyright (c) 2007-2009 CarrierLabs, LLC. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 4. The name "CarrierLabs" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * mark@carrierlabs.com. - * - * THIS SOFTWARE IS PROVIDED BY MARK CARRIER ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK CARRIER OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - *----------------------------------------------------------------------------*/ -#include "ActiveSocket.h" - -CActiveSocket::CActiveSocket(CSocketType nType) : CSimpleSocket(nType) -{ -} - -//------------------------------------------------------------------------------ -// -// ConnectTCP() - -// -//------------------------------------------------------------------------------ -bool CActiveSocket::ConnectTCP(const char *pAddr, uint16 nPort) -{ - bool bRetVal = false; - struct in_addr stIpAddress; - - //------------------------------------------------------------------ - // Preconnection setup that must be preformed - //------------------------------------------------------------------ - memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); - m_stServerSockaddr.sin_family = AF_INET; - - if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL) - { -#ifdef WIN32 - TranslateSocketError(); -#else - if (h_errno == HOST_NOT_FOUND) - { - SetSocketError(SocketInvalidAddress); - } -#endif - return bRetVal; - } - - memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length); - m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; - - if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) - { - TranslateSocketError(); - return bRetVal; - } - - m_stServerSockaddr.sin_port = htons(nPort); - - //------------------------------------------------------------------ - // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. - // - //------------------------------------------------------------------ - m_timer.Initialize(); - m_timer.SetStartTime(); - - if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) == - CSimpleSocket::SocketError) - { - //-------------------------------------------------------------- - // Get error value this might be a non-blocking socket so we - // must first check. - //-------------------------------------------------------------- - TranslateSocketError(); - - //-------------------------------------------------------------- - // If the socket is non-blocking and the current socket error - // is SocketEinprogress or SocketEwouldblock then poll connection - // with select for designated timeout period. - // Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK. - //-------------------------------------------------------------- - if ((IsNonblocking()) && - ((GetSocketError() == CSimpleSocket::SocketEwouldblock) || - (GetSocketError() == CSimpleSocket::SocketEinprogress))) - { - bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec()); - } - } - else - { - TranslateSocketError(); - bRetVal = true; - } - - m_timer.SetEndTime(); - - return bRetVal; -} - -//------------------------------------------------------------------------------ -// -// ConnectUDP() - -// -//------------------------------------------------------------------------------ -bool CActiveSocket::ConnectUDP(const char *pAddr, uint16 nPort) -{ - bool bRetVal = false; - struct in_addr stIpAddress; - - //------------------------------------------------------------------ - // Pre-connection setup that must be preformed - //------------------------------------------------------------------ - memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); - m_stServerSockaddr.sin_family = AF_INET; - - if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL) - { -#ifdef WIN32 - TranslateSocketError(); -#else - if (h_errno == HOST_NOT_FOUND) - { - SetSocketError(SocketInvalidAddress); - } -#endif - return bRetVal; - } - - memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length); - m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; - - if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) - { - TranslateSocketError(); - return bRetVal; - } - - m_stServerSockaddr.sin_port = htons(nPort); - - //------------------------------------------------------------------ - // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. - // - //------------------------------------------------------------------ - m_timer.Initialize(); - m_timer.SetStartTime(); - - if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) - { - bRetVal = true; - } - - TranslateSocketError(); - - m_timer.SetEndTime(); - - return bRetVal; -} - -//------------------------------------------------------------------------------ -// -// ConnectRAW() - -// -//------------------------------------------------------------------------------ -bool CActiveSocket::ConnectRAW(const char *pAddr, uint16 nPort) -{ - bool bRetVal = false; - struct in_addr stIpAddress; - //------------------------------------------------------------------ - // Pre-connection setup that must be preformed - //------------------------------------------------------------------ - memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); - m_stServerSockaddr.sin_family = AF_INET; - - if ((m_pHE = GETHOSTBYNAME(pAddr)) == NULL) - { -#ifdef WIN32 - TranslateSocketError(); -#else - if (h_errno == HOST_NOT_FOUND) - { - SetSocketError(SocketInvalidAddress); - } -#endif - return bRetVal; - } - - memcpy(&stIpAddress, m_pHE->h_addr_list[0], m_pHE->h_length); - m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; - - if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) - { - TranslateSocketError(); - return bRetVal; - } - - m_stServerSockaddr.sin_port = htons(nPort); - - //------------------------------------------------------------------ - // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. - // - //------------------------------------------------------------------ - m_timer.Initialize(); - m_timer.SetStartTime(); - - if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) - { - bRetVal = true; - } - - TranslateSocketError(); - - m_timer.SetEndTime(); - - return bRetVal; -} - - -//------------------------------------------------------------------------------ -// -// Open() - Create a connection to a specified address on a specified port -// -//------------------------------------------------------------------------------ -bool CActiveSocket::Open(const char *pAddr, uint16 nPort) -{ - bool bRetVal = false; - - if (IsSocketValid() == false) - { - SetSocketError(CSimpleSocket::SocketInvalidSocket); - return bRetVal; - } - - if (pAddr == NULL) - { - SetSocketError(CSimpleSocket::SocketInvalidAddress); - return bRetVal; - } - - if (nPort == 0) - { - SetSocketError(CSimpleSocket::SocketInvalidPort); - return bRetVal; - } - - switch (m_nSocketType) - { - case CSimpleSocket::SocketTypeTcp : - { - bRetVal = ConnectTCP(pAddr, nPort); - break; - } - case CSimpleSocket::SocketTypeUdp : - { - bRetVal = ConnectUDP(pAddr, nPort); - break; - } - case CSimpleSocket::SocketTypeRaw : - break; - default: - break; - } - - //-------------------------------------------------------------------------- - // If successful then create a local copy of the address and port - //-------------------------------------------------------------------------- - if (bRetVal) - { - socklen_t nSockLen = sizeof(struct sockaddr); - - memset(&m_stServerSockaddr, 0, nSockLen); - getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen); - - nSockLen = sizeof(struct sockaddr); - memset(&m_stClientSockaddr, 0, nSockLen); - getsockname(m_socket, (struct sockaddr *)&m_stClientSockaddr, &nSockLen); - - SetSocketError(SocketSuccess); - } - - return bRetVal; -} diff --git a/src/ActiveSocket.h b/src/ActiveSocket.h index 14e0ad9..8db9c28 100644 --- a/src/ActiveSocket.h +++ b/src/ActiveSocket.h @@ -45,47 +45,12 @@ #include "SimpleSocket.h" -class CPassiveSocket; - /// Provides a platform independent class to create an active socket. /// An active socket is used to create a socket which connects to a server. /// This type of object would be used when an application needs to send/receive /// data from a server. -class EXPORT CActiveSocket : public CSimpleSocket { -public: - friend class CPassiveSocket; - - CActiveSocket(CSocketType type = SocketTypeTcp); - virtual ~CActiveSocket() { - Close(); - }; - - /// Established a connection to the address specified by pAddr. - /// Connection-based protocol sockets (CSocket::SocketTypeTcp) may - /// successfully call Open() only once, however; connectionless protocol - /// sockets (CSocket::SocketTypeUdp) may use Open() multiple times to - /// change their association. - /// @param pAddr specifies the destination address to connect. - /// @param nPort specifies the destination port. - /// @return true if successful connection made, otherwise false. - virtual bool Open(const char *pAddr, uint16 nPort); - -private: - /// Utility function used to create a TCP connection, called from Open(). - /// @return true if successful connection made, otherwise false. - bool ConnectTCP(const char *pAddr, uint16 nPort); - - /// Utility function used to create a UDP connection, called from Open(). - /// @return true if successful connection made, otherwise false. - bool ConnectUDP(const char *pAddr, uint16 nPort); - - /// Utility function used to create a RAW connection, called from Open(). - /// @return true if successful connection made, otherwise false. - bool ConnectRAW(const char *pAddr, uint16 nPort); -private: - struct hostent *m_pHE; -}; +typedef CSimpleSocket CActiveSocket; #endif /* __ACTIVESOCKET_H__ */ diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index b9dce77..ed49317 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -48,6 +48,12 @@ CPassiveSocket::CPassiveSocket(CSocketType nType) : CSimpleSocket(nType) { } +CPassiveSocket::~CPassiveSocket() +{ + Close(); +} + + bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, uint16 nPort) { bool bRetVal = false; @@ -212,10 +218,10 @@ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBa // Accept() - // //------------------------------------------------------------------------------ -CActiveSocket *CPassiveSocket::Accept() +CSimpleSocket *CPassiveSocket::Accept() { uint32 nSockLen; - CActiveSocket *pClientSocket = NULL; + CSimpleSocket *pClientSocket = NULL; SOCKET socket = CSimpleSocket::SocketError; if (m_nSocketType != CSimpleSocket::SocketTypeTcp) @@ -224,7 +230,7 @@ CActiveSocket *CPassiveSocket::Accept() return pClientSocket; } - pClientSocket = new CActiveSocket(); + pClientSocket = new CSimpleSocket(); //-------------------------------------------------------------------------- // Wait for incoming connection. diff --git a/src/PassiveSocket.h b/src/PassiveSocket.h index e958777..768121e 100644 --- a/src/PassiveSocket.h +++ b/src/PassiveSocket.h @@ -55,22 +55,20 @@ class EXPORT CPassiveSocket : public CSimpleSocket { public: CPassiveSocket(CSocketType type = SocketTypeTcp); - virtual ~CPassiveSocket() { - Close(); - }; + virtual ~CPassiveSocket(); /// Extracts the first connection request on the queue of pending /// connections and creates a newly connected socket. Used with /// CSocketType CSimpleSocket::SocketTypeTcp. It is the responsibility of /// the caller to delete the returned object when finished. - /// @return if successful a pointer to a newly created CActiveSocket object + /// @return if successful a pointer to a newly created CSimpleSocket object /// will be returned and the internal error condition of the CPassiveSocket /// object will be CPassiveSocket::SocketSuccess. If an error condition was encountered /// the NULL will be returned and one of the following error conditions will be set: /// CPassiveSocket::SocketEwouldblock, CPassiveSocket::SocketInvalidSocket, /// CPassiveSocket::SocketConnectionAborted, CPassiveSocket::SocketInterrupted /// CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketFirewallError - virtual CActiveSocket *Accept(void); + virtual CSimpleSocket *Accept(void); /// Bind to a multicast group on a specified interface, multicast group, and port /// @@ -109,7 +107,7 @@ class EXPORT CPassiveSocket : public CSimpleSocket { /// CPassiveSocket::SocketProtocolError, CPassiveSocket::SocketNotconnected ///
\b Note: This function is used only for a socket of type /// CSimpleSocket::SocketTypeUdp - virtual int32 Send(const uint8 *pBuf, size_t bytesToSend); + virtual int32 Send(const uint8 *pBuf, size_t bytesToSend) CLSOCKET_OVERRIDE; private: struct ip_mreq m_stMulticastRequest; /// group address for multicast diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 38b8fea..32370b7 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -114,6 +114,17 @@ CSimpleSocket::CSimpleSocket(CSimpleSocket &socket) memcpy(m_pBuffer, socket.m_pBuffer, socket.m_nBufferSize); } +CSimpleSocket::~CSimpleSocket() +{ + if (m_pBuffer != NULL) + { + delete [] m_pBuffer; + m_pBuffer = NULL; + } + + Close(); +} + CSimpleSocket *CSimpleSocket::operator=(CSimpleSocket &socket) { if (m_nBufferSize != socket.m_nBufferSize) @@ -128,6 +139,207 @@ CSimpleSocket *CSimpleSocket::operator=(CSimpleSocket &socket) } +//------------------------------------------------------------------------------ +// +// ConnectTCP() - +// +//------------------------------------------------------------------------------ +bool CSimpleSocket::ConnectTCP(const char *pAddr, uint16 nPort) +{ + bool bRetVal = false; + struct in_addr stIpAddress; + + //------------------------------------------------------------------ + // Preconnection setup that must be preformed + //------------------------------------------------------------------ + memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); + m_stServerSockaddr.sin_family = AF_INET; + + struct hostent *pHE = GETHOSTBYNAME(pAddr); + if (pHE == NULL) + { +#ifdef WIN32 + TranslateSocketError(); +#else + if (h_errno == HOST_NOT_FOUND) + { + SetSocketError(SocketInvalidAddress); + } +#endif + return bRetVal; + } + + memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); + m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; + + if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) + { + TranslateSocketError(); + return bRetVal; + } + + m_stServerSockaddr.sin_port = htons(nPort); + + //------------------------------------------------------------------ + // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. + // + //------------------------------------------------------------------ + m_timer.Initialize(); + m_timer.SetStartTime(); + + if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) == + CSimpleSocket::SocketError) + { + //-------------------------------------------------------------- + // Get error value this might be a non-blocking socket so we + // must first check. + //-------------------------------------------------------------- + TranslateSocketError(); + + //-------------------------------------------------------------- + // If the socket is non-blocking and the current socket error + // is SocketEinprogress or SocketEwouldblock then poll connection + // with select for designated timeout period. + // Linux returns EINPROGRESS and Windows returns WSAEWOULDBLOCK. + //-------------------------------------------------------------- + if ((IsNonblocking()) && + ((GetSocketError() == CSimpleSocket::SocketEwouldblock) || + (GetSocketError() == CSimpleSocket::SocketEinprogress))) + { + bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec()); + } + } + else + { + TranslateSocketError(); + bRetVal = true; + } + + m_timer.SetEndTime(); + + return bRetVal; +} + +//------------------------------------------------------------------------------ +// +// ConnectUDP() - +// +//------------------------------------------------------------------------------ +bool CSimpleSocket::ConnectUDP(const char *pAddr, uint16 nPort) +{ + bool bRetVal = false; + struct in_addr stIpAddress; + + //------------------------------------------------------------------ + // Pre-connection setup that must be preformed + //------------------------------------------------------------------ + memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); + m_stServerSockaddr.sin_family = AF_INET; + + struct hostent *pHE = GETHOSTBYNAME(pAddr); + if (pHE == NULL) + { +#ifdef WIN32 + TranslateSocketError(); +#else + if (h_errno == HOST_NOT_FOUND) + { + SetSocketError(SocketInvalidAddress); + } +#endif + return bRetVal; + } + + memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); + m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; + + if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) + { + TranslateSocketError(); + return bRetVal; + } + + m_stServerSockaddr.sin_port = htons(nPort); + + //------------------------------------------------------------------ + // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. + // + //------------------------------------------------------------------ + m_timer.Initialize(); + m_timer.SetStartTime(); + + if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) + { + bRetVal = true; + } + + TranslateSocketError(); + + m_timer.SetEndTime(); + + return bRetVal; +} + +//------------------------------------------------------------------------------ +// +// ConnectRAW() - +// +//------------------------------------------------------------------------------ +bool CSimpleSocket::ConnectRAW(const char *pAddr, uint16 nPort) +{ + bool bRetVal = false; + struct in_addr stIpAddress; + //------------------------------------------------------------------ + // Pre-connection setup that must be preformed + //------------------------------------------------------------------ + memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); + m_stServerSockaddr.sin_family = AF_INET; + + struct hostent *pHE = GETHOSTBYNAME(pAddr); + if (pHE == NULL) + { +#ifdef WIN32 + TranslateSocketError(); +#else + if (h_errno == HOST_NOT_FOUND) + { + SetSocketError(SocketInvalidAddress); + } +#endif + return bRetVal; + } + + memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); + m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; + + if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) + { + TranslateSocketError(); + return bRetVal; + } + + m_stServerSockaddr.sin_port = htons(nPort); + + //------------------------------------------------------------------ + // Connect to address "xxx.xxx.xxx.xxx" (IPv4) address only. + // + //------------------------------------------------------------------ + m_timer.Initialize(); + m_timer.SetStartTime(); + + if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) + { + bRetVal = true; + } + + TranslateSocketError(); + + m_timer.SetEndTime(); + + return bRetVal; +} + + //------------------------------------------------------------------------------ // // Initialize() - Initialize socket class @@ -159,6 +371,72 @@ bool CSimpleSocket::Initialize() } +//------------------------------------------------------------------------------ +// +// Open() - Create a connection to a specified address on a specified port +// +//------------------------------------------------------------------------------ +bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) +{ + bool bRetVal = false; + + if (IsSocketValid() == false) + { + SetSocketError(CSimpleSocket::SocketInvalidSocket); + return bRetVal; + } + + if (pAddr == NULL) + { + SetSocketError(CSimpleSocket::SocketInvalidAddress); + return bRetVal; + } + + if (nPort == 0) + { + SetSocketError(CSimpleSocket::SocketInvalidPort); + return bRetVal; + } + + switch (m_nSocketType) + { + case CSimpleSocket::SocketTypeTcp : + { + bRetVal = ConnectTCP(pAddr, nPort); + break; + } + case CSimpleSocket::SocketTypeUdp : + { + bRetVal = ConnectUDP(pAddr, nPort); + break; + } + case CSimpleSocket::SocketTypeRaw : + break; + default: + break; + } + + //-------------------------------------------------------------------------- + // If successful then create a local copy of the address and port + //-------------------------------------------------------------------------- + if (bRetVal) + { + socklen_t nSockLen = sizeof(struct sockaddr); + + memset(&m_stServerSockaddr, 0, nSockLen); + getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen); + + nSockLen = sizeof(struct sockaddr); + memset(&m_stClientSockaddr, 0, nSockLen); + getsockname(m_socket, (struct sockaddr *)&m_stClientSockaddr, &nSockLen); + + SetSocketError(SocketSuccess); + } + + return bRetVal; +} + + //------------------------------------------------------------------------------ // // BindInterface() @@ -436,7 +714,9 @@ int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend) { do { - m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, (const sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr)); + m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, + (const sockaddr *)&m_stServerSockaddr, + sizeof(m_stServerSockaddr)); TranslateSocketError(); } while (GetSocketError() == CSimpleSocket::SocketInterrupted); } @@ -506,6 +786,12 @@ bool CSimpleSocket::Shutdown(CShutdownMode nShutdown) } +bool CSimpleSocket::Select(void) +{ + return Select(0,0); +} + + //------------------------------------------------------------------------------ // // Flush() @@ -940,6 +1226,12 @@ int32 CSimpleSocket::SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 n } +bool CSimpleSocket::IsSocketValid(void) +{ + return (m_socket != SocketError); +} + + //------------------------------------------------------------------------------ // // TranslateSocketError() - diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 4a5a9be..8c30e0b 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -93,6 +93,24 @@ #define SOCKET_SENDFILE_BLOCKSIZE 8192 + +#ifndef __cplusplus + #error C++ compiler required! +#else + #if ( __cplusplus >= 201103L ) + #define CLSOCKET_OVERRIDE override + #elif ( 0 && defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 7 || \ + (__GNUC_MINOR__ == 7 && __GNUC_PATCHLEVEL__ > 1)) ) + #define CLSOCKET_OVERRIDE override + #elif ( defined(_MSC_VER) && ( _MSC_VER >= 1400) ) + #define CLSOCKET_OVERRIDE override + #else + #define CLSOCKET_OVERRIDE + #endif +#endif + + + /// Provides a platform independent class to for socket development. /// This class is designed to abstract socket communication development in a /// platform independent manner. @@ -100,6 +118,7 @@ /// -# CActiveSocket Class /// -# CPassiveSocket Class class EXPORT CSimpleSocket { + friend class CPassiveSocket; public: /// Defines the three possible states for shuting down a socket. typedef enum @@ -148,14 +167,7 @@ class EXPORT CSimpleSocket { CSimpleSocket(CSocketType type = SocketTypeTcp); CSimpleSocket(CSimpleSocket &socket); - virtual ~CSimpleSocket() - { - if (m_pBuffer != NULL) - { - delete [] m_pBuffer; - m_pBuffer = NULL; - } - }; + virtual ~CSimpleSocket(); /// Initialize instance of CSocket. This method MUST be called before an /// object can be used. Errors : CSocket::SocketProtocolError, @@ -163,6 +175,16 @@ class EXPORT CSimpleSocket { /// @return true if properly initialized. virtual bool Initialize(void); + /// Established a connection to the address specified by pAddr. + /// Connection-based protocol sockets (CSocket::SocketTypeTcp) may + /// successfully call Open() only once, however; connectionless protocol + /// sockets (CSocket::SocketTypeUdp) may use Open() multiple times to + /// change their association. + /// @param pAddr specifies the destination address to connect. + /// @param nPort specifies the destination port. + /// @return true if successful connection made, otherwise false. + virtual bool Open(const char *pAddr, uint16 nPort); + /// Close socket /// @return true if successfully closed otherwise returns false. virtual bool Close(void); @@ -181,9 +203,7 @@ class EXPORT CSimpleSocket { /// for writing, or have an exceptional condition pending, respectively. /// Block until an event happens on the specified file descriptors. /// @return true if socket has data ready, or false if not ready or timed out. - virtual bool Select(void) { - return Select(0,0); - }; + virtual bool Select(void); /// Examine the socket descriptor sets currently owned by the instance of /// the socket class (the readfds, writefds, and errorfds parameters) to @@ -197,9 +217,7 @@ class EXPORT CSimpleSocket { /// Does the current instance of the socket object contain a valid socket /// descriptor. /// @return true if the socket object contains a valid socket descriptor. - virtual bool IsSocketValid(void) { - return (m_socket != SocketError); - }; + virtual bool IsSocketValid(void); /// Provides a standard error code for cross platform development by /// mapping the operating system error to an error defined by the CSocket @@ -550,6 +568,18 @@ class EXPORT CSimpleSocket { CSimpleSocket *operator=(CSimpleSocket &socket); + /// Utility function used to create a TCP connection, called from Open(). + /// @return true if successful connection made, otherwise false. + bool ConnectTCP(const char *pAddr, uint16 nPort); + + /// Utility function used to create a UDP connection, called from Open(). + /// @return true if successful connection made, otherwise false. + bool ConnectUDP(const char *pAddr, uint16 nPort); + + /// Utility function used to create a RAW connection, called from Open(). + /// @return true if successful connection made, otherwise false. + bool ConnectRAW(const char *pAddr, uint16 nPort); + protected: SOCKET m_socket; /// socket handle CSocketError m_socketErrno; /// number of last error From 2c2edeb0c0e9c7a728aae80d4cc51c62d022c750 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Sun, 19 Jun 2016 16:13:41 +0200 Subject: [PATCH 03/19] added examples, added inlines/aliases and a few fixes * added example DelayedEchoServer - sends back received data after some delay * added console/log output to EchoServer example * added example TxToServer - sends tcp data to echo server utilizes SetSendWindowSize() and fixed Select()/WaitUntilReadable() * added example UdpServer - prints received data to stderr * added example TxToUdpServer - sends udp data to udp server * added alias (inline) CPassiveSocket::Bind() for BindMulticast() without multicast group * fixed BindMulticast() for NULL ptr to mulicast group * added alias (inline) CSimpleSocket::ConnectTo() for Open() * added aliases CloseForXX() for Shutdown() variants * fixed SetReceiveTimeout() and SetSendTimeout() for Windows: Windows does not expect/support struct timeval - only milliseconds * added aliases SetReceiveTimeoutMillis() and SetSendTimeoutMillis() * added extra options bAwakeWhenReadable and bAwakeWhenWritable for Select(), both defaulting to true - as before, but usually not making much sense! * added aliases WaitUntilReadable() and WaitUntilWritable() with milliseconds * added aliases GetSocketErrorText() for DescribeError) * added alias Reveive() with 'char*' * added alias Send() with 'const char*' * added aliases Transmit() with 'const uint8*' and 'const char*' * renamed SetOptionLinger()'s nTime parameter to nTimeInSeconds Signed-off-by: hayati ayguen --- CMakeLists.txt | 13 +++++++ examples/DelayedEchoServer.cpp | 63 +++++++++++++++++++++++++++++++ examples/EchoServer.cpp | 13 +++++-- examples/TxToServer.cpp | 63 +++++++++++++++++++++++++++++++ examples/TxToUdpServer.cpp | 34 +++++++++++++++++ examples/UdpServer.cpp | 44 ++++++++++++++++++++++ src/PassiveSocket.cpp | 6 +-- src/PassiveSocket.h | 17 ++++++++- src/SimpleSocket.cpp | 68 ++++++++++++++++++++++++++++------ src/SimpleSocket.h | 66 +++++++++++++++++++++++++++++++-- 10 files changed, 364 insertions(+), 23 deletions(-) create mode 100644 examples/DelayedEchoServer.cpp create mode 100644 examples/TxToServer.cpp create mode 100644 examples/TxToUdpServer.cpp create mode 100644 examples/UdpServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index adef434..b6588b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,19 @@ if(UNIX OR (WIN32 AND MINGW)) ADD_EXECUTABLE(echoserver-example examples/EchoServer.cpp) TARGET_LINK_LIBRARIES(echoserver-example clsocket) + + ADD_EXECUTABLE(delayedechoserver-example examples/DelayedEchoServer.cpp) + TARGET_LINK_LIBRARIES(delayedechoserver-example clsocket) + + ADD_EXECUTABLE(txtoserver-example examples/TxToServer.cpp) + TARGET_LINK_LIBRARIES(txtoserver-example clsocket) + + ADD_EXECUTABLE(udpserver-example examples/UdpServer.cpp) + TARGET_LINK_LIBRARIES(udpserver-example clsocket) + + ADD_EXECUTABLE(txtoudpserver-example examples/TxToUdpServer.cpp) + TARGET_LINK_LIBRARIES(txtoudpserver-example clsocket) + endif() endif() diff --git a/examples/DelayedEchoServer.cpp b/examples/DelayedEchoServer.cpp new file mode 100644 index 0000000..3a320a1 --- /dev/null +++ b/examples/DelayedEchoServer.cpp @@ -0,0 +1,63 @@ + +#include "PassiveSocket.h" // Include header for active socket object definition + +#define MAX_PACKET 4096 + + +#ifdef WIN32 +#include + + static void sleep( unsigned int seconds ) + { + Sleep( seconds * 1000 ); + } +#elif defined(_LINUX) || defined (_DARWIN) + #include +#endif + +int main(int argc, char **argv) +{ + CPassiveSocket socket; + CSimpleSocket *pClient = NULL; + + //-------------------------------------------------------------------------- + // Initialize our socket object + //-------------------------------------------------------------------------- + socket.Initialize(); + socket.Listen("127.0.0.1", 6789); + + while (true) + { + if ((pClient = socket.Accept()) != NULL) + { + //---------------------------------------------------------------------- + // Receive request from the client. + //---------------------------------------------------------------------- + if (pClient->Receive(MAX_PACKET)) + { + //------------------------------------------------------------------ + // Send response to client and close connection to the client. + //------------------------------------------------------------------ + int32 rx = pClient->GetBytesReceived(); + uint8 *txt = pClient->GetData(); + fprintf(stderr, "received %d bytes:\n", rx ); + for ( int k = 0; k < rx; ++k ) + fprintf(stderr, "%c", txt[k]); + fprintf(stderr, "\n"); + sleep(5); + pClient->Send( txt, rx ); + fprintf(stderr, "sent back after 5 seconds\n" ); + pClient->Close(); + } + + delete pClient; + } + } + + //----------------------------------------------------------------------------- + // Receive request from the client. + //----------------------------------------------------------------------------- + socket.Close(); + + return 1; +} diff --git a/examples/EchoServer.cpp b/examples/EchoServer.cpp index ae141e3..43b5658 100644 --- a/examples/EchoServer.cpp +++ b/examples/EchoServer.cpp @@ -1,18 +1,17 @@ #include "PassiveSocket.h" // Include header for active socket object definition -#define MAX_PACKET 4096 +#define MAX_PACKET 4096 int main(int argc, char **argv) { CPassiveSocket socket; - CSimpleSocket *pClient = NULL; + CActiveSocket *pClient = NULL; //-------------------------------------------------------------------------- // Initialize our socket object //-------------------------------------------------------------------------- socket.Initialize(); - socket.Listen("127.0.0.1", 6789); while (true) @@ -27,7 +26,13 @@ int main(int argc, char **argv) //------------------------------------------------------------------ // Send response to client and close connection to the client. //------------------------------------------------------------------ - pClient->Send( pClient->GetData(), pClient->GetBytesReceived() ); + int32 rx = pClient->GetBytesReceived(); + uint8 *txt = pClient->GetData(); + pClient->Send( txt, rx ); + fprintf(stderr, "received and sent %d bytes:\n", rx ); + for ( int k = 0; k < rx; ++k ) + fprintf(stderr, "%c", txt[k]); + fprintf(stderr, "\n"); pClient->Close(); } diff --git a/examples/TxToServer.cpp b/examples/TxToServer.cpp new file mode 100644 index 0000000..94feb2e --- /dev/null +++ b/examples/TxToServer.cpp @@ -0,0 +1,63 @@ + +#include "SimpleSocket.h" // Include header for active socket object definition + +#include + +#define MAX_PACKET 4096 + +int main(int argc, char **argv) +{ + CSimpleSocket socket; + + if ( argc < 3 ) + { + fprintf(stderr, "usage: %s \n", argv[0] ); + return 10; + } + + //-------------------------------------------------------------------------- + // Initialize our socket object + //-------------------------------------------------------------------------- + socket.Initialize(); + + bool bConnOK = socket.Open( argv[1], 6789 ); + if ( !bConnOK ) + { + fprintf(stderr, "error connecting to '%s'!\n", argv[1] ); + return 10; + } + + uint32 nSendBufSize = socket.GetSendWindowSize(); + fprintf(stderr, "default Send Buffer Size %u\n", nSendBufSize ); + nSendBufSize = socket.SetSendWindowSize( 80000 ); + fprintf(stderr, "new Send Buffer Size %u\n", nSendBufSize ); + + size_t sendSize = strlen( argv[2] ); + socket.Transmit( (const uint8 *)argv[2], (int32)sendSize ); + + socket.SetNonblocking(); + //socket.SetBlocking(); + + int32 rxSize = 0; + char rxBuffer[16]; + while (rxSize < sendSize) + { + if ( !socket.WaitUntilReadable(500) ) + { + fprintf(stderr, "."); + continue; + } + + int32 rx = socket.Receive( 15, rxBuffer ); + if ( rx > 0 ) + { + rxBuffer[rx] = '\0'; + fprintf(stderr, "\nreceived %d bytes: '%s'\n", rx, rxBuffer ); + rxSize += rx; + } + else if ( !socket.IsSocketValid() ) + break; + } + + return 1; +} diff --git a/examples/TxToUdpServer.cpp b/examples/TxToUdpServer.cpp new file mode 100644 index 0000000..6efdc80 --- /dev/null +++ b/examples/TxToUdpServer.cpp @@ -0,0 +1,34 @@ + +#include "SimpleSocket.h" // Include header for active socket object definition + +#include + +#define MAX_PACKET 4096 + +int main(int argc, char **argv) +{ + CSimpleSocket socket( CSimpleSocket::SocketTypeUdp ); + + if ( argc < 3 ) + { + fprintf(stderr, "usage: %s \n", argv[0] ); + return 10; + } + + //-------------------------------------------------------------------------- + // Initialize our socket object + //-------------------------------------------------------------------------- + socket.Initialize(); + + bool bConnOK = socket.Open( argv[1], 6789 ); + if ( !bConnOK ) + { + fprintf(stderr, "error connecting to '%s'!\n", argv[1] ); + return 10; + } + + size_t sendSize = strlen( argv[2] ); + socket.Send( argv[2], (int32)sendSize ); + + return 1; +} diff --git a/examples/UdpServer.cpp b/examples/UdpServer.cpp new file mode 100644 index 0000000..8324dd3 --- /dev/null +++ b/examples/UdpServer.cpp @@ -0,0 +1,44 @@ + +#include "PassiveSocket.h" // Include header for active socket object definition + +#define MAX_PACKET 4096 + +int main(int argc, char **argv) +{ + char buffer[ MAX_PACKET ]; + CPassiveSocket passiveSocket( CSimpleSocket::SocketTypeUdp ); + + //-------------------------------------------------------------------------- + // Initialize our socket object + //-------------------------------------------------------------------------- + passiveSocket.Initialize(); + passiveSocket.Bind( "127.0.0.1", 6789 ); + CSimpleSocket &socket = passiveSocket; + + socket.SetReceiveTimeoutMillis(500); + + while (true) + { + //---------------------------------------------------------------------- + // Receive request from the client. + //---------------------------------------------------------------------- + int32 rx = socket.Receive(MAX_PACKET, buffer); + if (rx > 0) + { + fprintf(stderr, "\nreceived %d bytes:\n", rx ); + for ( int k = 0; k < rx; ++k ) + fprintf(stderr, "%c", buffer[k]); + fprintf(stderr, "\n"); + if ( 0 == memcmp(buffer, "quit", 4) ) + break; + } + else if ( socket.IsNonblocking() && CSimpleSocket::SocketEwouldblock == socket.GetSocketError() ) + fprintf(stderr, "."); + else if ( !socket.IsNonblocking() && CSimpleSocket::SocketTimedout == socket.GetSocketError() ) + fprintf(stderr, "."); + else + fprintf(stderr, "Error: %s\n", socket.DescribeError() ); + } + + return 1; +} diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index ed49317..44b18bd 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -99,9 +99,9 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup); m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr; - if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (void *)&m_stMulticastRequest, - sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess) + if (!pGroup || SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&m_stMulticastRequest, + sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess) { bRetVal = true; } diff --git a/src/PassiveSocket.h b/src/PassiveSocket.h index 768121e..d9629e7 100644 --- a/src/PassiveSocket.h +++ b/src/PassiveSocket.h @@ -77,11 +77,26 @@ class EXPORT CPassiveSocket : public CSimpleSocket { /// @param nPort - port on which multicast /// @return true if able to bind to interface and multicast group. /// If not successful, the false is returned and one of the following error - /// condiitions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, + /// conditions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, /// CPassiveSocket::SocketInvalidSocket. The following socket errors are for Linux/Unix /// derived systems only: CPassiveSocket::SocketInvalidSocketBuffer bool BindMulticast(const char *pInterface, const char *pGroup, uint16 nPort); + /// Bind to a specified interface and port + /// + /// @param pInterface - interface on which to bind. + /// @param nPort - port on which multicast + /// @return true if able to bind to interface. + /// If not successful, the false is returned and one of the following error + /// conditions will be set: CPassiveSocket::SocketAddressInUse, CPassiveSocket::SocketProtocolError, + /// CPassiveSocket::SocketInvalidSocket. The following socket errors are for Linux/Unix + /// derived systems only: CPassiveSocket::SocketInvalidSocketBuffer + inline bool Bind(const char *pInterface, uint16 nPort) + { + const char *pNoGroup = 0; + return BindMulticast(pInterface, pNoGroup, nPort); + } + /// Create a listening socket at local ip address 'x.x.x.x' or 'localhost' /// if pAddr is NULL on port nPort. /// diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 32370b7..555118c 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -353,8 +353,21 @@ bool CSimpleSocket::Initialize() //------------------------------------------------------------------------- // Data structure containing general Windows Sockets Info //------------------------------------------------------------------------- + // use WinSock 2.2 + // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx + // Windows Sockets version 2.2 is supported on + // Windows Server 2008, + // Windows Vista, + // Windows Server 2003, + // Windows XP, + // Windows 2000, + // Windows NT 4.0 with Service Pack 4 (SP4) and later, + // Windows Me, + // Windows 98, + // Windows 95 OSR2, + // Windows 95 with the Windows Socket 2 Update memset(&m_hWSAData, 0, sizeof(m_hWSAData)); - WSAStartup(MAKEWORD(2, 0), &m_hWSAData); + WSAStartup(MAKEWORD(2, 2), &m_hWSAData); #endif //------------------------------------------------------------------------- @@ -592,7 +605,9 @@ uint32 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize) //------------------------------------------------------------------------- if (m_socket != CSimpleSocket::SocketError) { - SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); + nRetVal = SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); + if ( !nRetVal ) + return GetWindowSize(nOptionName); TranslateSocketError(); } else @@ -897,16 +912,29 @@ bool CSimpleSocket::SetReceiveTimeout(int32 nRecvTimeoutSec, int32 nRecvTimeoutU { bool bRetVal = true; - memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); +#ifdef WIN32 + uint32 nMillis = nRecvTimeoutSec * 1000 + nRecvTimeoutUsec / 1000; + if ( nMillis == 0 && ( nRecvTimeoutUsec > 0 || nRecvTimeoutSec > 0 ) ) + nMillis = 1; + nRecvTimeoutSec = nMillis / 1000; + nRecvTimeoutUsec = nMillis % 1000; +#endif + memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); m_stRecvTimeout.tv_sec = nRecvTimeoutSec; m_stRecvTimeout.tv_usec = nRecvTimeoutUsec; //-------------------------------------------------------------------------- // Sanity check to make sure the options are supported! //-------------------------------------------------------------------------- +#ifdef WIN32 + // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx + if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_RCVTIMEO, &nMillis, + sizeof(nMillis)) == CSimpleSocket::SocketError) +#else if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_RCVTIMEO, &m_stRecvTimeout, sizeof(struct timeval)) == CSimpleSocket::SocketError) +#endif { bRetVal = false; TranslateSocketError(); @@ -925,6 +953,14 @@ bool CSimpleSocket::SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec { bool bRetVal = true; +#ifdef WIN32 + uint32 nMillis = nSendTimeoutSec * 1000 + nSendTimeoutUsec / 1000; + if ( nMillis == 0 && ( nSendTimeoutUsec > 0 || nSendTimeoutSec > 0 ) ) + nMillis = 1; + nSendTimeoutSec = nMillis / 1000; + nSendTimeoutUsec = nMillis % 1000; +#endif + memset(&m_stSendTimeout, 0, sizeof(struct timeval)); m_stSendTimeout.tv_sec = nSendTimeoutSec; m_stSendTimeout.tv_usec = nSendTimeoutUsec; @@ -932,8 +968,14 @@ bool CSimpleSocket::SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec //-------------------------------------------------------------------------- // Sanity check to make sure the options are supported! //-------------------------------------------------------------------------- +#ifdef WIN32 + // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx + if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_SNDTIMEO, &nMillis, + sizeof(nMillis)) == CSimpleSocket::SocketError) +#else if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_SNDTIMEO, &m_stSendTimeout, sizeof(struct timeval)) == CSimpleSocket::SocketError) +#endif { bRetVal = false; TranslateSocketError(); @@ -969,12 +1011,12 @@ bool CSimpleSocket::SetOptionReuseAddr() // SetOptionLinger() // //------------------------------------------------------------------------------ -bool CSimpleSocket::SetOptionLinger(bool bEnable, uint16 nTime) +bool CSimpleSocket::SetOptionLinger(bool bEnable, uint16 nTimeInSeconds) { bool bRetVal = false; m_stLinger.l_onoff = (bEnable == true) ? 1: 0; - m_stLinger.l_linger = nTime; + m_stLinger.l_linger = nTimeInSeconds; if (SETSOCKOPT(m_socket, SOL_SOCKET, SO_LINGER, &m_stLinger, sizeof(m_stLinger)) == 0) { @@ -1301,8 +1343,7 @@ void CSimpleSocket::TranslateSocketError(void) SetSocketError(CSimpleSocket::SocketEunknown); break; } -#endif -#ifdef WIN32 +#elif defined(WIN32) int32 nError = WSAGetLastError(); switch (nError) { @@ -1358,6 +1399,8 @@ void CSimpleSocket::TranslateSocketError(void) SetSocketError(CSimpleSocket::SocketEunknown); break; } +#else +#error unsupported platform! #endif } @@ -1418,7 +1461,7 @@ const char *CSimpleSocket::DescribeError(CSocketError err) // Select() // //------------------------------------------------------------------------------ -bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec) +bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec, bool bAwakeWhenReadable, bool bAwakeWhenWritable) { bool bRetVal = false; struct timeval *pTimeout = NULL; @@ -1429,9 +1472,13 @@ bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec) FD_ZERO(&m_errorFds); FD_ZERO(&m_readFds); FD_ZERO(&m_writeFds); + + if ( bAwakeWhenReadable ) + FD_SET(m_socket, &m_readFds); + if ( bAwakeWhenWritable ) + FD_SET(m_socket, &m_writeFds); + FD_SET(m_socket, &m_errorFds); - FD_SET(m_socket, &m_readFds); - FD_SET(m_socket, &m_writeFds); //--------------------------------------------------------------------- // If timeout has been specified then set value, otherwise set timeout @@ -1446,7 +1493,6 @@ bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec) } nNumDescriptors = SELECT(m_socket+1, &m_readFds, &m_writeFds, &m_errorFds, pTimeout); -// nNumDescriptors = SELECT(m_socket+1, &m_readFds, NULL, NULL, pTimeout); //---------------------------------------------------------------------- // Handle timeout diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 8c30e0b..33a513d 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -185,6 +185,10 @@ class EXPORT CSimpleSocket { /// @return true if successful connection made, otherwise false. virtual bool Open(const char *pAddr, uint16 nPort); + inline bool ConnectTo( const char * pAddr, uint16 nPort ) { + return Open(pAddr, nPort); + }; + /// Close socket /// @return true if successfully closed otherwise returns false. virtual bool Close(void); @@ -192,11 +196,20 @@ class EXPORT CSimpleSocket { /// Shutdown shut down socket send and receive operations /// CShutdownMode::Receives - Disables further receive operations. /// CShutdownMode::Sends - Disables further send operations. - /// CShutdownBoth:: - Disables further send and receive operations. + /// CShutdownMode::Both - Disables further send and receive operations. + /// see http://stackoverflow.com/questions/4160347/close-vs-shutdown-socket /// @param nShutdown specifies the type of shutdown. /// @return true if successfully shutdown otherwise returns false. virtual bool Shutdown(CShutdownMode nShutdown); + inline bool CloseForReads() { + return Shutdown( CSimpleSocket::Receives ); + }; + + inline bool CloseForWrites() { + return Shutdown( CSimpleSocket::Sends ); + }; + /// Examine the socket descriptor sets currently owned by the instance of /// the socket class (the readfds, writefds, and errorfds parameters) to /// see whether some of their descriptors are ready for reading, are ready @@ -212,7 +225,16 @@ class EXPORT CSimpleSocket { /// @param nTimeoutSec timeout in seconds for select. /// @param nTimeoutUSec timeout in micro seconds for select. /// @return true if socket has data ready, or false if not ready or timed out. - virtual bool Select(int32 nTimeoutSec, int32 nTimeoutUSec); + virtual bool Select(int32 nTimeoutSec, int32 nTimeoutUSec, + bool bAwakeWhenReadable = true, bool bAwakeWhenWritable = true ); + + inline bool WaitUntilReadable( int32 nTimeoutMillis ) { + return Select( nTimeoutMillis / 1000 , 1000 * (nTimeoutMillis % 1000), true, false ); + } + + inline bool WaitUntilWritable( int32 nTimeoutMillis ) { + return Select( nTimeoutMillis / 1000 , 1000 * (nTimeoutMillis % 1000), false, true ); + } /// Does the current instance of the socket object contain a valid socket /// descriptor. @@ -231,6 +253,14 @@ class EXPORT CSimpleSocket { return DescribeError(m_socketErrno); }; + static inline const char * GetSocketErrorText(CSocketError err) { + return DescribeError(err); + } + + inline const char * GetSocketErrorText() { + return DescribeError(m_socketErrno); + } + /// Attempts to receive a block of data on an established connection. /// @param nMaxBytes maximum number of bytes to receive. /// @param pBuffer, memory where to receive the data, @@ -241,6 +271,10 @@ class EXPORT CSimpleSocket { /// @return of -1 means that an error has occurred. virtual int32 Receive(int32 nMaxBytes = 1, uint8 * pBuffer = 0); + inline int32 Receive(int32 nMaxBytes, char * pBuffer) { + return Receive(nMaxBytes, (uint8*)pBuffer); + }; + /// Attempts to send a block of data on an established connection. /// @param pBuf block of data to be sent. /// @param bytesToSend size of data block to be sent. @@ -249,6 +283,18 @@ class EXPORT CSimpleSocket { /// @return of -1 means that an error has occurred. virtual int32 Send(const uint8 *pBuf, size_t bytesToSend); + inline int32 Send(const char *pBuf, size_t bytesToSend) { + return Send( (const uint8 *)pBuf, bytesToSend ); + }; + + inline int32 Transmit(const uint8 *pBuf, size_t bytesToSend) { + return Send( pBuf, bytesToSend ); + }; + + inline int32 Transmit(const char *pBuf, size_t bytesToSend) { + return Send( (const uint8 *)pBuf, bytesToSend ); + }; + /// Attempts to send at most nNumItem blocks described by sendVector /// to the socket descriptor associated with the socket object. /// @param sendVector pointer to an array of iovec structures @@ -322,9 +368,9 @@ class EXPORT CSimpleSocket { /// Closed by the remote system). ///

/// @param bEnable true to enable option false to disable option. - /// @param nTime time in seconds to linger. + /// @param nTimeInSeconds time in seconds to linger. /// @return true if option successfully set - bool SetOptionLinger(bool bEnable, uint16 nTime); + bool SetOptionLinger(bool bEnable, uint16 nTimeInSeconds); /// Tells the kernel that even if this port is busy (in the TIME_WAIT state), /// go ahead and reuse it anyway. If it is busy, but with another state, @@ -362,6 +408,10 @@ class EXPORT CSimpleSocket { m_stConnectTimeout.tv_usec = nConnectTimeoutUsec; }; + inline bool SetConnectTimeoutMillis(int32 nConnectTimeoutMillis) { + return SetReceiveTimeout( nConnectTimeoutMillis / 1000 , 1000 * (nConnectTimeoutMillis % 1000) ); + }; + /// Gets the timeout value that specifies the maximum number of seconds a /// a call to CSimpleSocket::Receive waits until it completes. /// @return the length of time in seconds @@ -388,6 +438,10 @@ class EXPORT CSimpleSocket { /// @return true if socket timeout was successfully set. bool SetReceiveTimeout(int32 nRecvTimeoutSec, int32 nRecvTimeoutUsec = 0); + inline bool SetReceiveTimeoutMillis(int32 nRecvTimeoutMillis) { + return SetReceiveTimeout( nRecvTimeoutMillis / 1000 , 1000 * (nRecvTimeoutMillis % 1000) ); + }; + /// Enable/disable multicast for a socket. This options is only valid for /// socket descriptors of type CSimpleSocket::SocketTypeUdp. /// @return true if multicast was enabled or false if socket type is not @@ -424,6 +478,10 @@ class EXPORT CSimpleSocket { /// @return the length of time in seconds bool SetSendTimeout(int32 nSendTimeoutSec, int32 nSendTimeoutUsec = 0); + inline bool SetSendTimeoutMillis(int32 nSendTimeoutMillis) { + return SetSendTimeout( nSendTimeoutMillis / 1000 , 1000 * (nSendTimeoutMillis % 1000) ); + }; + /// Returns the last error that occured for the instace of the CSimpleSocket /// instance. This method should be called immediately to retrieve the /// error code for the failing mehtod call. From e71b00342f06721d58c948bd162d5176e116b66d Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Fri, 8 Jul 2016 17:23:10 +0200 Subject: [PATCH 04/19] silence compiler warnings for switch cases Signed-off-by: hayati ayguen --- src/PassiveSocket.cpp | 4 ++++ src/SimpleSocket.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index 44b18bd..5247221 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -325,6 +325,10 @@ int32 CPassiveSocket::Send(const uint8 *pBuf, size_t bytesToSend) case CSimpleSocket::SocketTypeTcp: CSimpleSocket::Send(pBuf, bytesToSend); break; + case CSimpleSocket::SocketTypeInvalid: + case CSimpleSocket::SocketTypeTcp6: + case CSimpleSocket::SocketTypeUdp6: + case CSimpleSocket::SocketTypeRaw: default: SetSocketError(SocketProtocolError); break; diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 555118c..92f133b 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -101,6 +101,7 @@ CSimpleSocket::CSimpleSocket(CSocketType nType) : #endif break; } + case CSimpleSocket::SocketTypeInvalid: default: m_nSocketType = CSimpleSocket::SocketTypeInvalid; break; @@ -425,6 +426,9 @@ bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) } case CSimpleSocket::SocketTypeRaw : break; + case CSimpleSocket::SocketTypeInvalid: + case CSimpleSocket::SocketTypeTcp6: + case CSimpleSocket::SocketTypeUdp6: default: break; } @@ -741,6 +745,10 @@ int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend) } break; } + case CSimpleSocket::SocketTypeInvalid: + case CSimpleSocket::SocketTypeTcp6: + case CSimpleSocket::SocketTypeUdp6: + case CSimpleSocket::SocketTypeRaw: default: break; } @@ -1124,6 +1132,10 @@ int32 CSimpleSocket::Receive(int32 nMaxBytes, uint8 * pBuffer ) break; } + case CSimpleSocket::SocketTypeInvalid: + case CSimpleSocket::SocketTypeTcp6: + case CSimpleSocket::SocketTypeUdp6: + case CSimpleSocket::SocketTypeRaw: default: break; } From 56ddebb28724e684cc0f010108024abb8b1f9dc0 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Wed, 13 Jul 2016 09:21:42 +0200 Subject: [PATCH 05/19] added extra interface functions and extended the examples added GetNumReceivableBytes() added IsServerSide() added Get(Peer/Local)(Addr/Port) allow examples to connect from remote computers this is for testing examples (server/client) on different OS/machines rebase amended bugfix patch from lethosor for DARWIN/OS X Signed-off-by: hayati ayguen --- examples/DelayedEchoServer.cpp | 2 +- examples/EchoServer.cpp | 16 +++- examples/QueryDayTime.cpp | 5 +- examples/RecvAsync.cpp | 28 +++++-- examples/TxToServer.cpp | 12 ++- examples/TxToUdpServer.cpp | 6 ++ examples/UdpServer.cpp | 22 +++++- src/PassiveSocket.cpp | 35 ++++++--- src/SimpleSocket.cpp | 131 +++++++++++++++++++++++++++++++-- src/SimpleSocket.h | 51 +++++++++---- 10 files changed, 267 insertions(+), 41 deletions(-) diff --git a/examples/DelayedEchoServer.cpp b/examples/DelayedEchoServer.cpp index 3a320a1..2e8e0dd 100644 --- a/examples/DelayedEchoServer.cpp +++ b/examples/DelayedEchoServer.cpp @@ -24,7 +24,7 @@ int main(int argc, char **argv) // Initialize our socket object //-------------------------------------------------------------------------- socket.Initialize(); - socket.Listen("127.0.0.1", 6789); + socket.Listen( 0, 6789 ); // NULL (not "127.0.0.1") to allow testing with remotes while (true) { diff --git a/examples/EchoServer.cpp b/examples/EchoServer.cpp index 43b5658..b491e3c 100644 --- a/examples/EchoServer.cpp +++ b/examples/EchoServer.cpp @@ -12,7 +12,7 @@ int main(int argc, char **argv) // Initialize our socket object //-------------------------------------------------------------------------- socket.Initialize(); - socket.Listen("127.0.0.1", 6789); + socket.Listen( 0, 6789 ); // NULL (not "127.0.0.1") to allow testing with remotes while (true) { @@ -21,12 +21,26 @@ int main(int argc, char **argv) //---------------------------------------------------------------------- // Receive request from the client. //---------------------------------------------------------------------- + + pClient->WaitUntilReadable(100); + int32 peekRx = pClient->GetNumReceivableBytes(); + if (pClient->Receive(MAX_PACKET)) { + fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" + , ( pClient->IsServerSide() ? "Local is Server" : "Local is Client" ) + , pClient->GetLocalAddr(), (unsigned)pClient->GetLocalPort() + , pClient->GetPeerAddr(), (unsigned)pClient->GetPeerPort() + ); + //------------------------------------------------------------------ // Send response to client and close connection to the client. //------------------------------------------------------------------ int32 rx = pClient->GetBytesReceived(); + + if ( peekRx != rx && !( peekRx == 0 && rx < 0 ) ) + fprintf( stderr, "GetNumReceivableBytes() = %d != %d = Receive() !\n", peekRx, rx ); + uint8 *txt = pClient->GetData(); pClient->Send( txt, rx ); fprintf(stderr, "received and sent %d bytes:\n", rx ); diff --git a/examples/QueryDayTime.cpp b/examples/QueryDayTime.cpp index 7abf7aa..254d6e1 100644 --- a/examples/QueryDayTime.cpp +++ b/examples/QueryDayTime.cpp @@ -18,7 +18,10 @@ int main(int argc, char **argv) // Create a connection to the time server so that data can be sent // and received. //-------------------------------------------------------------------------- - if (socket.Open("time-C.timefreq.bldrdoc.gov", 13)) + const char * timeServer = ( argc >= 2 ) ? argv[1] : "time-C.timefreq.bldrdoc.gov"; + int PortNo = ( argc >= 3 ) ? atoi(argv[2]) : 13; + fprintf(stderr, "trying to connect to timeserver %s:%d ..\n", timeServer, PortNo); + if (socket.Open(timeServer, (uint16)PortNo)) { //---------------------------------------------------------------------- // Send a requtest the server requesting the current time. diff --git a/examples/RecvAsync.cpp b/examples/RecvAsync.cpp index d4e415f..7f31211 100644 --- a/examples/RecvAsync.cpp +++ b/examples/RecvAsync.cpp @@ -43,7 +43,7 @@ void *CreateTCPEchoServer(void *param) } } - sleep(100); + sleep(1); delete pClient; } @@ -78,23 +78,41 @@ int main(int argc, char **argv) int numBytes = -1; int bytesReceived = 0; - client.Select(); + client.WaitUntilReadable(100); // wait up to 100 ms - while (bytesReceived != strlen(TEST_PACKET)) + //while (bytesReceived != strlen(TEST_PACKET)) + while ( numBytes != 0 ) // Receive() until socket gets closed { + int32 peekRx = client.GetNumReceivableBytes(); + numBytes = client.Receive(MAX_PACKET); + if ( peekRx != numBytes && !( peekRx == 0 && numBytes < 0 ) ) + fprintf( stderr, "\nGetNumReceivableBytes() = %d != %d = Receive() !\n", peekRx, numBytes ); + if (numBytes > 0) { bytesReceived += numBytes; memset(result, 0, 1024); memcpy(result, client.GetData(), numBytes); - printf("received %d bytes: '%s'\n", numBytes, result); + printf("\nreceived %d bytes: '%s'\n", numBytes, result); } + else if ( CSimpleSocket::SocketEwouldblock == client.GetSocketError() ) + fprintf(stderr, "."); + else if ( !client.IsNonblocking() && CSimpleSocket::SocketTimedout == client.GetSocketError() ) + fprintf(stderr, "w"); else { - printf("Received %d bytes\n", numBytes); + printf("\nreceived %d bytes\n", numBytes); + + fprintf(stderr, "Error: %s\n", client.DescribeError() ); + fprintf(stderr, "Error: %s, code %d\n" + , ( client.IsNonblocking() ? "NonBlocking socket" : "Blocking socket" ) + , (int) client.GetSocketError() + ); } + + client.WaitUntilReadable(100); // wait up to 100 ms } } } diff --git a/examples/TxToServer.cpp b/examples/TxToServer.cpp index 94feb2e..4fd7064 100644 --- a/examples/TxToServer.cpp +++ b/examples/TxToServer.cpp @@ -27,6 +27,12 @@ int main(int argc, char **argv) return 10; } + fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" + , ( socket.IsServerSide() ? "Local is Server" : "Local is Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort() + , socket.GetPeerAddr(), (unsigned)socket.GetPeerPort() + ); + uint32 nSendBufSize = socket.GetSendWindowSize(); fprintf(stderr, "default Send Buffer Size %u\n", nSendBufSize ); nSendBufSize = socket.SetSendWindowSize( 80000 ); @@ -40,7 +46,7 @@ int main(int argc, char **argv) int32 rxSize = 0; char rxBuffer[16]; - while (rxSize < sendSize) + while (rxSize < (int32)sendSize) { if ( !socket.WaitUntilReadable(500) ) { @@ -48,7 +54,11 @@ int main(int argc, char **argv) continue; } + int32 peekRx = socket.GetNumReceivableBytes(); int32 rx = socket.Receive( 15, rxBuffer ); + if ( peekRx != rx && !( peekRx == 0 && rx < 0 ) ) + fprintf( stderr, "GetNumReceivableBytes() = %d != %d = Receive() !\n", peekRx, rx ); + if ( rx > 0 ) { rxBuffer[rx] = '\0'; diff --git a/examples/TxToUdpServer.cpp b/examples/TxToUdpServer.cpp index 6efdc80..66bff2d 100644 --- a/examples/TxToUdpServer.cpp +++ b/examples/TxToUdpServer.cpp @@ -27,6 +27,12 @@ int main(int argc, char **argv) return 10; } + fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" + , ( socket.IsServerSide() ? "Local is Server" : "Local is Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort() + , socket.GetPeerAddr(), (unsigned)socket.GetPeerPort() + ); + size_t sendSize = strlen( argv[2] ); socket.Send( argv[2], (int32)sendSize ); diff --git a/examples/UdpServer.cpp b/examples/UdpServer.cpp index 8324dd3..cbe7105 100644 --- a/examples/UdpServer.cpp +++ b/examples/UdpServer.cpp @@ -12,7 +12,7 @@ int main(int argc, char **argv) // Initialize our socket object //-------------------------------------------------------------------------- passiveSocket.Initialize(); - passiveSocket.Bind( "127.0.0.1", 6789 ); + passiveSocket.Bind( 0, 6789 ); // NULL (not "127.0.0.1") to allow testing with remotes CSimpleSocket &socket = passiveSocket; socket.SetReceiveTimeoutMillis(500); @@ -22,9 +22,21 @@ int main(int argc, char **argv) //---------------------------------------------------------------------- // Receive request from the client. //---------------------------------------------------------------------- + + //socket.WaitUntilReadable(100); + + int32 peekRx = socket.GetNumReceivableBytes(); int32 rx = socket.Receive(MAX_PACKET, buffer); + if ( peekRx != rx && !( peekRx == 0 && rx < 0 ) ) + fprintf( stderr, "GetNumReceivableBytes() = %d != %d = Receive() !\n", peekRx, rx ); if (rx > 0) { + fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" + , ( passiveSocket.IsServerSide() ? "Local is Server" : "Local is Client" ) + , passiveSocket.GetLocalAddr(), (unsigned)passiveSocket.GetLocalPort() + , passiveSocket.GetPeerAddr(), (unsigned)passiveSocket.GetPeerPort() + ); + fprintf(stderr, "\nreceived %d bytes:\n", rx ); for ( int k = 0; k < rx; ++k ) fprintf(stderr, "%c", buffer[k]); @@ -32,12 +44,18 @@ int main(int argc, char **argv) if ( 0 == memcmp(buffer, "quit", 4) ) break; } - else if ( socket.IsNonblocking() && CSimpleSocket::SocketEwouldblock == socket.GetSocketError() ) + else if ( CSimpleSocket::SocketEwouldblock == socket.GetSocketError() ) fprintf(stderr, "."); else if ( !socket.IsNonblocking() && CSimpleSocket::SocketTimedout == socket.GetSocketError() ) fprintf(stderr, "."); else + { fprintf(stderr, "Error: %s\n", socket.DescribeError() ); + fprintf(stderr, "Error: %s, code %d\n" + , ( socket.IsNonblocking() ? "NonBlocking socket" : "Blocking socket" ) + , (int) socket.GetSocketError() + ); + } } return 1; diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index 5247221..ec47cce 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -46,6 +46,8 @@ CPassiveSocket::CPassiveSocket(CSocketType nType) : CSimpleSocket(nType) { + // PassiveSocket is intended for "Server" purpose + m_bIsServerSide = true; } CPassiveSocket::~CPassiveSocket() @@ -88,22 +90,34 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u } } + // multicast address/port is the server + memcpy(&m_stServerSockaddr,&m_stMulticastGroup,sizeof(m_stServerSockaddr)); + //-------------------------------------------------------------------------- // Bind to the specified port //-------------------------------------------------------------------------- + m_bIsServerSide = true; if (bind(m_socket, (struct sockaddr *)&m_stMulticastGroup, sizeof(m_stMulticastGroup)) == 0) { - //---------------------------------------------------------------------- - // Join the multicast group - //---------------------------------------------------------------------- - m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup); - m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr; - - if (!pGroup || SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (void *)&m_stMulticastRequest, - sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess) + if ( pGroup ) { - bRetVal = true; + //---------------------------------------------------------------------- + // Join the multicast group + //---------------------------------------------------------------------- + m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup); + m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr; + + if ( SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (void *)&m_stMulticastRequest, + sizeof(m_stMulticastRequest)) == CSimpleSocket::SocketSuccess) + { + bRetVal = true; + } + } + else + { + // all OK, if we shall not join to a group + bRetVal = true; } m_timer.SetEndTime(); @@ -179,6 +193,7 @@ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBa //-------------------------------------------------------------------------- // Bind to the specified port //-------------------------------------------------------------------------- + m_bIsServerSide = true; if (bind(m_socket, (struct sockaddr *)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) { if (m_nSocketType == CSimpleSocket::SocketTypeTcp) diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 92f133b..9511f41 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -42,13 +42,19 @@ *----------------------------------------------------------------------------*/ #include "SimpleSocket.h" +#if defined(_LINUX) || defined(_DARWIN) +#include +#endif + + CSimpleSocket::CSimpleSocket(CSocketType nType) : m_socket(INVALID_SOCKET), m_socketErrno(CSimpleSocket::SocketInvalidSocket), m_pBuffer(NULL), m_nBufferSize(0), m_nSocketDomain(AF_INET), m_nSocketType(SocketTypeInvalid), m_nBytesReceived(-1), m_nBytesSent(-1), m_nFlags(0), - m_bIsBlocking(true) + m_bIsBlocking(true), + m_bIsServerSide(false) { SetConnectTimeout(1, 0); memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); @@ -150,8 +156,11 @@ bool CSimpleSocket::ConnectTCP(const char *pAddr, uint16 nPort) bool bRetVal = false; struct in_addr stIpAddress; + // this is the Client + m_bIsServerSide = false; + //------------------------------------------------------------------ - // Preconnection setup that must be preformed + // Preconnection setup that must be performed //------------------------------------------------------------------ memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); m_stServerSockaddr.sin_family = AF_INET; @@ -231,8 +240,11 @@ bool CSimpleSocket::ConnectUDP(const char *pAddr, uint16 nPort) bool bRetVal = false; struct in_addr stIpAddress; + // this is the Client + m_bIsServerSide = false; + //------------------------------------------------------------------ - // Pre-connection setup that must be preformed + // Pre-connection setup that must be performed //------------------------------------------------------------------ memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); m_stServerSockaddr.sin_family = AF_INET; @@ -290,8 +302,12 @@ bool CSimpleSocket::ConnectRAW(const char *pAddr, uint16 nPort) { bool bRetVal = false; struct in_addr stIpAddress; + + // this is the Client + m_bIsServerSide = false; + //------------------------------------------------------------------ - // Pre-connection setup that must be preformed + // Pre-connection setup that must be performed //------------------------------------------------------------------ memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); m_stServerSockaddr.sin_family = AF_INET; @@ -393,6 +409,7 @@ bool CSimpleSocket::Initialize() bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) { bool bRetVal = false; + m_bIsServerSide = false; if (IsSocketValid() == false) { @@ -566,6 +583,71 @@ int32 CSimpleSocket::GetSocketDscp(void) } +/// Returns clients Internet host address as a string in standard numbers-and-dots notation. +/// @return NULL if invalid +const char * CSimpleSocket::GetClientAddr() const +{ + return inet_ntoa(m_stClientSockaddr.sin_addr); +} + +/// Returns the port number on which the client is connected. +/// @return client port number. +uint16 CSimpleSocket::GetClientPort() const +{ + return m_stClientSockaddr.sin_port; +} + +/// Returns server Internet host address as a string in standard numbers-and-dots notation. +/// @return NULL if invalid +const char * CSimpleSocket::GetServerAddr() const +{ + return inet_ntoa(m_stServerSockaddr.sin_addr); +} + +/// Returns the port number on which the server is connected. +/// @return server port number. +uint16 CSimpleSocket::GetServerPort() const +{ + return ntohs(m_stServerSockaddr.sin_port); +} + + +/// Returns if this is the Server side of the connection +bool CSimpleSocket::IsServerSide() const +{ + return m_bIsServerSide; +} + +/// Returns local Internet host address as a string in standard numbers-and-dots notation. +/// @return NULL if invalid +const char * CSimpleSocket::GetLocalAddr() const +{ + return (m_bIsServerSide) ? GetServerAddr() : GetClientAddr(); +} + +/// Returns the port number on which the local socket is connected. +/// @return client port number. +uint16 CSimpleSocket::GetLocalPort() const +{ + return (m_bIsServerSide) ? GetServerPort() : GetClientPort(); +} + + +/// Returns Peer's Internet host address as a string in standard numbers-and-dots notation. +/// @return NULL if invalid +const char * CSimpleSocket::GetPeerAddr() const +{ + return (m_bIsServerSide) ? GetClientAddr() : GetServerAddr(); +} + +/// Returns the port number on which the peer is connected. +/// @return client port number. +uint16 CSimpleSocket::GetPeerPort() const +{ + return (m_bIsServerSide) ? GetClientPort() : GetServerPort(); +} + + //------------------------------------------------------------------------------ // // GetWindowSize() @@ -609,7 +691,7 @@ uint32 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize) //------------------------------------------------------------------------- if (m_socket != CSimpleSocket::SocketError) { - nRetVal = SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); + int nRetVal = SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); if ( !nRetVal ) return GetWindowSize(nOptionName); TranslateSocketError(); @@ -671,6 +753,15 @@ bool CSimpleSocket::EnableNagleAlgoritm() } +/// Set object socket handle to that specified as parameter +/// @param socket value of socket descriptor +void CSimpleSocket::SetSocketHandle(SOCKET socket, bool bIsServerSide ) +{ + m_socket = socket; + m_bIsServerSide = bIsServerSide; +} + + //------------------------------------------------------------------------------ // // Send() - Send data on a valid socket @@ -1162,6 +1253,36 @@ int32 CSimpleSocket::Receive(int32 nMaxBytes, uint8 * pBuffer ) } +/// Attempts to return the number of Bytes waiting at next Receive() +/// @return number of bytes ready for Receive() +/// @return of -1 means that an error has occurred. +int32 CSimpleSocket::GetNumReceivableBytes() +{ + //-------------------------------------------------------------------------- + // If the socket is invalid then return false. + //-------------------------------------------------------------------------- + if (IsSocketValid() == false) + { + return -1; + } + +#if WIN32 + u_long numBytesInSocket = 0; + if ( ::ioctlsocket(m_socket, FIONREAD, &numBytesInSocket) < 0 ) + return -1; + + return (int32)numBytesInSocket; +#elif defined(_LINUX) || defined(_DARWIN) + int32 numBytesInSocket = 0; + if ( ioctl(m_socket, FIONREAD, (char*)&numBytesInSocket) < 0 ) + return -1; + + return numBytesInSocket; +#else +#error missing implementation for GetNumReceivableBytes() +#endif +} + //------------------------------------------------------------------------------ // // SetNonblocking() diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 33a513d..758cbf3 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -275,6 +275,13 @@ class EXPORT CSimpleSocket { return Receive(nMaxBytes, (uint8*)pBuffer); }; + + /// Attempts to return the number of Bytes waiting at next Receive() + /// @return number of bytes ready for Receive() + /// @return of -1 means that an error has occurred. + virtual int32 GetNumReceivableBytes(); + + /// Attempts to send a block of data on an established connection. /// @param pBuf block of data to be sent. /// @param bytesToSend size of data block to be sent. @@ -527,27 +534,40 @@ class EXPORT CSimpleSocket { /// Returns clients Internet host address as a string in standard numbers-and-dots notation. /// @return NULL if invalid - const char *GetClientAddr() { - return inet_ntoa(m_stClientSockaddr.sin_addr); - }; + const char * GetClientAddr() const; /// Returns the port number on which the client is connected. /// @return client port number. - uint16 GetClientPort() { - return m_stClientSockaddr.sin_port; - }; + uint16 GetClientPort() const; /// Returns server Internet host address as a string in standard numbers-and-dots notation. /// @return NULL if invalid - const char *GetServerAddr() { - return inet_ntoa(m_stServerSockaddr.sin_addr); - }; + const char * GetServerAddr() const; /// Returns the port number on which the server is connected. /// @return server port number. - uint16 GetServerPort() { - return ntohs(m_stServerSockaddr.sin_port); - }; + uint16 GetServerPort() const; + + /// Returns if this is the Server side of the connection + bool IsServerSide() const; + + /// Returns local Internet host address as a string in standard numbers-and-dots notation. + /// @return NULL if invalid + const char * GetLocalAddr() const; + + /// Returns the port number on which the local socket is connected. + /// @return client port number. + uint16 GetLocalPort() const; + + + /// Returns Peer's Internet host address as a string in standard numbers-and-dots notation. + /// @return NULL if invalid + const char * GetPeerAddr() const; + + /// Returns the port number on which the peer is connected. + /// @return client port number. + uint16 GetPeerPort() const; + /// Get the TCP receive buffer window size for the current socket object. ///

\b NOTE: Linux will set the receive buffer to twice the value passed. @@ -595,9 +615,7 @@ class EXPORT CSimpleSocket { /// Set object socket handle to that specified as parameter /// @param socket value of socket descriptor - void SetSocketHandle(SOCKET socket) { - m_socket = socket; - }; + void SetSocketHandle(SOCKET socket, bool bIsServerSide = true ); private: /// Generic function used to get the send/receive window size @@ -650,6 +668,9 @@ class EXPORT CSimpleSocket { uint32 m_nFlags; /// socket flags bool m_bIsBlocking; /// is socket blocking bool m_bIsMulticast; /// is the UDP socket multicast; + bool m_bIsServerSide; /// is this the server? => m_stServerSockaddr == localAddr() + /// and m_stClientSockaddr == peerAddr() + /// else: m_stClientSockaddr == localAddr() struct timeval m_stConnectTimeout; /// connection timeout struct timeval m_stRecvTimeout; /// receive timeout struct timeval m_stSendTimeout; /// send timeout From 3fa3ff26cbccb2f61dde38853498144359394f5f Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Fri, 15 Jul 2016 17:00:03 +0200 Subject: [PATCH 06/19] bugfix in SetConnectTimeoutMillis(), optimization and minor enhancements * SetConnectTimeoutMillis() was setting the receive timeout * optimization: CPassiveSocket::Accept() does now waits for result of accept() before creating CSimpleSocket() - that's interesting for a NonBlocking CPassiveSocket * added bool CSimpleSocket::IsSocketPeerClosed() returning if remote side closed the socket * made IsBlocking() const * added inlines for IsSocketPeerOpen(), IsSocketInvalid() and IsNonblocking() simplifying logic in if expressions * added internal PRINT_CLOSE macro for debugging Signed-off-by: hayati ayguen --- src/PassiveSocket.cpp | 79 ++++++++++++++++++++----------------------- src/SimpleSocket.cpp | 51 +++++++++++++++++++++++++--- src/SimpleSocket.h | 35 ++++++++++++++----- 3 files changed, 110 insertions(+), 55 deletions(-) diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index ec47cce..32737f7 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -245,58 +245,51 @@ CSimpleSocket *CPassiveSocket::Accept() return pClientSocket; } - pClientSocket = new CSimpleSocket(); - //-------------------------------------------------------------------------- // Wait for incoming connection. //-------------------------------------------------------------------------- - if (pClientSocket != NULL) - { - CSocketError socketErrno = SocketSuccess; - - m_timer.Initialize(); - m_timer.SetStartTime(); - - nSockLen = sizeof(m_stClientSockaddr); - - do - { - errno = 0; - socket = accept(m_socket, (struct sockaddr *)&m_stClientSockaddr, (socklen_t *)&nSockLen); + CSocketError socketErrno = SocketSuccess; - if (socket != -1) - { - pClientSocket->SetSocketHandle(socket); - pClientSocket->TranslateSocketError(); - socketErrno = pClientSocket->GetSocketError(); - socklen_t nSockLen = sizeof(struct sockaddr); - - //------------------------------------------------------------- - // Store client and server IP and port information for this - // connection. - //------------------------------------------------------------- - getpeername(m_socket, (struct sockaddr *)&pClientSocket->m_stClientSockaddr, &nSockLen); - memcpy((void *)&pClientSocket->m_stClientSockaddr, (void *)&m_stClientSockaddr, nSockLen); - - memset(&pClientSocket->m_stServerSockaddr, 0, nSockLen); - getsockname(m_socket, (struct sockaddr *)&pClientSocket->m_stServerSockaddr, &nSockLen); - } - else - { - TranslateSocketError(); - socketErrno = GetSocketError(); - } + m_timer.Initialize(); + m_timer.SetStartTime(); - } while (socketErrno == CSimpleSocket::SocketInterrupted); + nSockLen = sizeof(m_stClientSockaddr); - m_timer.SetEndTime(); + do + { + errno = 0; + socket = accept(m_socket, (struct sockaddr *)&m_stClientSockaddr, (socklen_t *)&nSockLen); - if (socketErrno != CSimpleSocket::SocketSuccess) + if (socket != -1) { - delete pClientSocket; - pClientSocket = NULL; + pClientSocket = new CSimpleSocket(); + if ( !pClientSocket ) + break; + + pClientSocket->SetSocketHandle(socket); + pClientSocket->TranslateSocketError(); + socketErrno = pClientSocket->GetSocketError(); + socklen_t nSockLen = sizeof(struct sockaddr); + + //------------------------------------------------------------- + // Store client and server IP and port information for this + // connection. + //------------------------------------------------------------- + getpeername(m_socket, (struct sockaddr *)&pClientSocket->m_stClientSockaddr, &nSockLen); + memcpy((void *)&pClientSocket->m_stClientSockaddr, (void *)&m_stClientSockaddr, nSockLen); + + memset(&pClientSocket->m_stServerSockaddr, 0, nSockLen); + getsockname(m_socket, (struct sockaddr *)&pClientSocket->m_stServerSockaddr, &nSockLen); } - } + else + { + TranslateSocketError(); + socketErrno = GetSocketError(); + } + + } while (socketErrno == CSimpleSocket::SocketInterrupted); + + m_timer.SetEndTime(); return pClientSocket; } diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 9511f41..8952b92 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -46,6 +46,8 @@ #include #endif +#define PRINT_CLOSE 0 + CSimpleSocket::CSimpleSocket(CSocketType nType) : m_socket(INVALID_SOCKET), @@ -54,9 +56,10 @@ CSimpleSocket::CSimpleSocket(CSocketType nType) : m_nSocketType(SocketTypeInvalid), m_nBytesReceived(-1), m_nBytesSent(-1), m_nFlags(0), m_bIsBlocking(true), - m_bIsServerSide(false) + m_bIsServerSide(false), + m_bPeerHasClosed(true) { - SetConnectTimeout(1, 0); + SetConnectTimeout(1, 0); // default timeout for connection memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); memset(&m_stSendTimeout, 0, sizeof(struct timeval)); memset(&m_stLinger, 0, sizeof(struct linger)); @@ -216,7 +219,7 @@ bool CSimpleSocket::ConnectTCP(const char *pAddr, uint16 nPort) ((GetSocketError() == CSimpleSocket::SocketEwouldblock) || (GetSocketError() == CSimpleSocket::SocketEinprogress))) { - bRetVal = Select(GetConnectTimeoutSec(), GetConnectTimeoutUSec()); + bRetVal = Select( m_stConnectTimeout.tv_sec, m_stConnectTimeout.tv_usec ); } } else @@ -226,6 +229,8 @@ bool CSimpleSocket::ConnectTCP(const char *pAddr, uint16 nPort) } m_timer.SetEndTime(); + if ( bRetVal ) + m_bPeerHasClosed = false; return bRetVal; } @@ -284,6 +289,7 @@ bool CSimpleSocket::ConnectUDP(const char *pAddr, uint16 nPort) if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) { bRetVal = true; + m_bPeerHasClosed = false; } TranslateSocketError(); @@ -347,6 +353,7 @@ bool CSimpleSocket::ConnectRAW(const char *pAddr, uint16 nPort) if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) { bRetVal = true; + m_bPeerHasClosed = false; } TranslateSocketError(); @@ -390,6 +397,7 @@ bool CSimpleSocket::Initialize() //------------------------------------------------------------------------- // Create the basic Socket Handle //------------------------------------------------------------------------- + m_bPeerHasClosed = true; m_timer.Initialize(); m_timer.SetStartTime(); m_socket = socket(m_nSocketDomain, m_nSocketType, 0); @@ -410,6 +418,7 @@ bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) { bool bRetVal = false; m_bIsServerSide = false; + m_bPeerHasClosed = true; if (IsSocketValid() == false) { @@ -692,9 +701,9 @@ uint32 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize) if (m_socket != CSimpleSocket::SocketError) { int nRetVal = SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); + TranslateSocketError(); if ( !nRetVal ) return GetWindowSize(nOptionName); - TranslateSocketError(); } else { @@ -759,6 +768,7 @@ void CSimpleSocket::SetSocketHandle(SOCKET socket, bool bIsServerSide ) { m_socket = socket; m_bIsServerSide = bIsServerSide; + m_bPeerHasClosed = false; } @@ -1002,6 +1012,18 @@ int32 CSimpleSocket::Send(const struct iovec *sendVector, int32 nNumItems) } +//------------------------------------------------------------------------------ +// +// SetConnectTimeout() +// +//------------------------------------------------------------------------------ +void CSimpleSocket::SetConnectTimeout(int32 nConnectTimeoutSec, int32 nConnectTimeoutUsec) +{ + m_stConnectTimeout.tv_sec = nConnectTimeoutSec; + m_stConnectTimeout.tv_usec = nConnectTimeoutUsec; +} + + //------------------------------------------------------------------------------ // // SetReceiveTimeout() @@ -1191,6 +1213,13 @@ int32 CSimpleSocket::Receive(int32 nMaxBytes, uint8 * pBuffer ) { m_nBytesReceived = RECV(m_socket, (pWorkBuffer + m_nBytesReceived), nMaxBytes, m_nFlags); + if ( 0 == m_nBytesReceived ) + { +#if PRINT_CLOSE + fprintf(stderr, "CSimpleSocket::Receive() = 0 Bytes ==> peer closed connection!\n"); +#endif + m_bPeerHasClosed = true; + } TranslateSocketError(); } while ((GetSocketError() == CSimpleSocket::SocketInterrupted)); @@ -1403,10 +1432,24 @@ int32 CSimpleSocket::SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 n bool CSimpleSocket::IsSocketValid(void) { +#if PRINT_CLOSE + if ( m_socket == SocketError ) + fprintf(stderr, "reporting CSimpleSocket::IsSocketValid() == false.\n" ); +#endif return (m_socket != SocketError); } +bool CSimpleSocket::IsSocketPeerClosed(void) +{ +#if PRINT_CLOSE + if ( m_bPeerHasClosed ) + fprintf(stderr, "reporting CSimpleSocket::IsSocketPeerClosed() == true.\n" ); +#endif + return m_bPeerHasClosed; +} + + //------------------------------------------------------------------------------ // // TranslateSocketError() - diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 758cbf3..68d4fd3 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -241,6 +241,23 @@ class EXPORT CSimpleSocket { /// @return true if the socket object contains a valid socket descriptor. virtual bool IsSocketValid(void); + + inline bool IsSocketInvalid(void) { + return !IsSocketValid(); + }; + + + /// Is the current instance of the socket already closed from peer? + /// Information is updated on Receive() ! + /// @return true if the socket was closed + virtual bool IsSocketPeerClosed(void); + + + inline bool IsSocketPeerOpen(void) { + return !IsSocketPeerClosed(); + }; + + /// Provides a standard error code for cross platform development by /// mapping the operating system error to an error defined by the CSocket /// class. @@ -328,10 +345,15 @@ class EXPORT CSimpleSocket { /// Returns blocking/non-blocking state of socket. /// @return true if the socket is non-blocking, else return false. - bool IsNonblocking(void) { + bool IsNonblocking(void) const { return (m_bIsBlocking == false); }; + inline bool IsBlocking(void) const { + return !IsNonblocking(); + } + + /// Set the socket to blocking. /// @return true if successful set to blocking, else return false; bool SetBlocking(void); @@ -409,14 +431,10 @@ class EXPORT CSimpleSocket { /// @param nConnectTimeoutSec of timeout in seconds. /// @param nConnectTimeoutUsec of timeout in microseconds. /// @return true if socket connection timeout was successfully set. - void SetConnectTimeout(int32 nConnectTimeoutSec, int32 nConnectTimeoutUsec = 0) - { - m_stConnectTimeout.tv_sec = nConnectTimeoutSec; - m_stConnectTimeout.tv_usec = nConnectTimeoutUsec; - }; + void SetConnectTimeout(int32 nConnectTimeoutSec, int32 nConnectTimeoutUsec = 0); - inline bool SetConnectTimeoutMillis(int32 nConnectTimeoutMillis) { - return SetReceiveTimeout( nConnectTimeoutMillis / 1000 , 1000 * (nConnectTimeoutMillis % 1000) ); + inline void SetConnectTimeoutMillis(int32 nConnectTimeoutMillis) { + SetConnectTimeout( nConnectTimeoutMillis / 1000, 1000 * ( nConnectTimeoutMillis % 1000 ) ); }; /// Gets the timeout value that specifies the maximum number of seconds a @@ -671,6 +689,7 @@ class EXPORT CSimpleSocket { bool m_bIsServerSide; /// is this the server? => m_stServerSockaddr == localAddr() /// and m_stClientSockaddr == peerAddr() /// else: m_stClientSockaddr == localAddr() + bool m_bPeerHasClosed; /// is socket closed from peer? struct timeval m_stConnectTimeout; /// connection timeout struct timeval m_stRecvTimeout; /// receive timeout struct timeval m_stSendTimeout; /// send timeout From ba677f5affaaf025da7a20ace2661f479399fa34 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Wed, 20 Jul 2016 13:33:42 +0200 Subject: [PATCH 07/19] fixed error handling problem scenario: when there's already an error outside the clsocket lib, then TranslateSocketError() could pick up the error, which was not caused by the clsocket-operation added ClearSystemError() and use it in some cases call/use TranslateSocketError() when necessary Signed-off-by: hayati ayguen --- src/PassiveSocket.cpp | 6 +++ src/SimpleSocket.cpp | 89 ++++++++++++++++++++++++++++++++++--------- src/SimpleSocket.h | 4 ++ 3 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index 32737f7..b64496c 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -93,6 +93,8 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u // multicast address/port is the server memcpy(&m_stServerSockaddr,&m_stMulticastGroup,sizeof(m_stServerSockaddr)); + ClearSystemError(); + //-------------------------------------------------------------------------- // Bind to the specified port //-------------------------------------------------------------------------- @@ -149,6 +151,8 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u //------------------------------------------------------------------------------ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBacklog) { + ClearSystemError(); + bool bRetVal = false; #ifdef WIN32 ULONG inAddr; @@ -255,6 +259,8 @@ CSimpleSocket *CPassiveSocket::Accept() nSockLen = sizeof(m_stClientSockaddr); + ClearSystemError(); + do { errno = 0; diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 8952b92..34d0b98 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -162,6 +162,8 @@ bool CSimpleSocket::ConnectTCP(const char *pAddr, uint16 nPort) // this is the Client m_bIsServerSide = false; + ClearSystemError(); + //------------------------------------------------------------------ // Preconnection setup that must be performed //------------------------------------------------------------------ @@ -248,6 +250,8 @@ bool CSimpleSocket::ConnectUDP(const char *pAddr, uint16 nPort) // this is the Client m_bIsServerSide = false; + ClearSystemError(); + //------------------------------------------------------------------ // Pre-connection setup that must be performed //------------------------------------------------------------------ @@ -312,6 +316,8 @@ bool CSimpleSocket::ConnectRAW(const char *pAddr, uint16 nPort) // this is the Client m_bIsServerSide = false; + ClearSystemError(); + //------------------------------------------------------------------ // Pre-connection setup that must be performed //------------------------------------------------------------------ @@ -371,7 +377,7 @@ bool CSimpleSocket::ConnectRAW(const char *pAddr, uint16 nPort) //------------------------------------------------------------------------------ bool CSimpleSocket::Initialize() { - errno = CSimpleSocket::SocketSuccess; + ClearSystemError(); #ifdef WIN32 //------------------------------------------------------------------------- @@ -676,8 +682,10 @@ uint32 CSimpleSocket::GetWindowSize(uint32 nOptionName) //--------------------------------------------------------------------- // query for buffer size //--------------------------------------------------------------------- - GETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nTcpWinSize, &nLen); - TranslateSocketError(); + if (GETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nTcpWinSize, &nLen) == SocketError) + { + TranslateSocketError(); + } } else { @@ -700,10 +708,12 @@ uint32 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize) //------------------------------------------------------------------------- if (m_socket != CSimpleSocket::SocketError) { - int nRetVal = SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)); - TranslateSocketError(); - if ( !nRetVal ) - return GetWindowSize(nOptionName); + if (SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)) == SocketError) + { + TranslateSocketError(); + } + + return GetWindowSize(nOptionName); } else { @@ -731,8 +741,10 @@ bool CSimpleSocket::DisableNagleAlgoritm() { bRetVal = true; } - - TranslateSocketError(); + else + { + TranslateSocketError(); + } return bRetVal; } @@ -755,8 +767,10 @@ bool CSimpleSocket::EnableNagleAlgoritm() { bRetVal = true; } - - TranslateSocketError(); + else + { + TranslateSocketError(); + } return bRetVal; } @@ -779,6 +793,7 @@ void CSimpleSocket::SetSocketHandle(SOCKET socket, bool bIsServerSide ) //------------------------------------------------------------------------------ int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend) { + ClearSystemError(); SetSocketError(SocketSuccess); m_nBytesSent = 0; @@ -881,15 +896,15 @@ bool CSimpleSocket::Close(void) //-------------------------------------------------------------------------- if (IsSocketValid()) { + ClearSystemError(); if (CLOSE(m_socket) != CSimpleSocket::SocketError) { m_socket = INVALID_SOCKET; bRetVal = true; } + TranslateSocketError(); } - TranslateSocketError(); - return bRetVal; } @@ -904,7 +919,10 @@ bool CSimpleSocket::Shutdown(CShutdownMode nShutdown) CSocketError nRetVal = SocketEunknown; nRetVal = (CSocketError)shutdown(m_socket, CSimpleSocket::Sends); - TranslateSocketError(); + if (nRetVal == SocketError) + { + TranslateSocketError(); + } return (nRetVal == CSimpleSocket::SocketSuccess) ? true: false; } @@ -1120,8 +1138,10 @@ bool CSimpleSocket::SetOptionReuseAddr() { bRetVal = true; } - - TranslateSocketError(); + else + { + TranslateSocketError(); + } return bRetVal; } @@ -1143,8 +1163,10 @@ bool CSimpleSocket::SetOptionLinger(bool bEnable, uint16 nTimeInSeconds) { bRetVal = true; } - - TranslateSocketError(); + else + { + TranslateSocketError(); + } return bRetVal; } @@ -1196,6 +1218,7 @@ int32 CSimpleSocket::Receive(int32 nMaxBytes, uint8 * pBuffer ) pWorkBuffer = m_pBuffer; } + ClearSystemError(); SetSocketError(SocketSuccess); m_timer.Initialize(); @@ -1365,6 +1388,7 @@ bool CSimpleSocket::SetBlocking(void) if (ioctlsocket(m_socket, FIONBIO, (ULONG *)&nCurFlags) != 0) { + TranslateSocketError(); return false; } #else @@ -1397,6 +1421,8 @@ int32 CSimpleSocket::SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 n { int32 nOutCount = CSimpleSocket::SocketError; + ClearSystemError(); + static char szData[SOCKET_SENDFILE_BLOCKSIZE]; int32 nInCount = 0; @@ -1450,6 +1476,24 @@ bool CSimpleSocket::IsSocketPeerClosed(void) } +//------------------------------------------------------------------------------ +// +// ClearSystemError() - +// +//------------------------------------------------------------------------------ + +void CSimpleSocket::ClearSystemError(void) +{ +#if defined(_LINUX) || defined(_DARWIN) + errno = EXIT_SUCCESS; +#elif defined(WIN32) + WSASetLastError( EXIT_SUCCESS ); +#else +#error unsupported platform! +#endif +} + + //------------------------------------------------------------------------------ // // TranslateSocketError() - @@ -1668,6 +1712,8 @@ bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec, bool bAwakeWhe pTimeout = &timeout; } + ClearSystemError(); + nNumDescriptors = SELECT(m_socket+1, &m_readFds, &m_writeFds, &m_errorFds, pTimeout); //---------------------------------------------------------------------- @@ -1678,6 +1724,13 @@ bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec, bool bAwakeWhe SetSocketError(CSimpleSocket::SocketTimedout); } //---------------------------------------------------------------------- + // Handle error + //---------------------------------------------------------------------- + else if ( nNumDescriptors == SocketError ) + { + TranslateSocketError(); + } + //---------------------------------------------------------------------- // If a file descriptor (read/write) is set then check the // socket error (SO_ERROR) to see if there is a pending error. //---------------------------------------------------------------------- diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 68d4fd3..a516226 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -258,6 +258,10 @@ class EXPORT CSimpleSocket { }; + /// Clear "last" system error + /// - so that TranslateSocketError() does not try to translate someone else's error! + void ClearSystemError(void); + /// Provides a standard error code for cross platform development by /// mapping the operating system error to an error defined by the CSocket /// class. From f8bbdeaee15846b60c19d98aeb0b357d5af003c8 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Wed, 20 Jul 2016 16:21:08 +0200 Subject: [PATCH 08/19] added EADDRINUSE and printfs (deactivated) for debugging Signed-off-by: hayati ayguen --- src/SimpleSocket.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 34d0b98..36f8f15 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -45,8 +45,10 @@ #if defined(_LINUX) || defined(_DARWIN) #include #endif +#include -#define PRINT_CLOSE 0 +#define PRINT_CLOSE 0 +#define PRINT_ERRORS 0 CSimpleSocket::CSimpleSocket(CSocketType nType) : @@ -1502,7 +1504,8 @@ void CSimpleSocket::ClearSystemError(void) void CSimpleSocket::TranslateSocketError(void) { #if defined(_LINUX) || defined(_DARWIN) - switch (errno) + int systemErrno = errno; + switch (systemErrno) { case EXIT_SUCCESS: SetSocketError(CSimpleSocket::SocketSuccess); @@ -1560,9 +1563,19 @@ void CSimpleSocket::TranslateSocketError(void) SetSocketError(CSimpleSocket::SocketAddressInUse); break; default: + #if PRINT_ERRORS + fprintf( stderr, "\nCSimpleSocket::SocketEunknown: errno=%d: %s\n", systemErrno, strerror(systemErrno) ); + #endif SetSocketError(CSimpleSocket::SocketEunknown); break; } + #if PRINT_ERRORS + if ( systemErrno != EXIT_SUCCESS && systemErrno != EWOULDBLOCK ) + { + fprintf( stderr, "\nCSimpleSocket Error: %s == system %s\n", DescribeError(), strerror(systemErrno) ); + } + #endif + #elif defined(WIN32) int32 nError = WSAGetLastError(); switch (nError) From 3bee58488e7ccf1a421ac92df51bbe4ec0ef8ac1 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Thu, 3 May 2018 14:52:47 +0200 Subject: [PATCH 09/19] several bugfixes/enhancements from 'PROCITEC GmbH' company with kind permission of Procitec: * bugfixes in multicast UDP operation * enhancend for multithreaded use: - use GetAddrInfo[Static]() instead of deprecated GETHOSTBYNAME() - GetIPv4AddrInfoStatic() to allow address resolution without a connection instance * docs and other minor enhancements Signed-off-by: hayati ayguen --- src/PassiveSocket.cpp | 34 +++-- src/PassiveSocket.h | 3 +- src/SimpleSocket.cpp | 303 +++++++++++++++++++++++++++++++++++------- src/SimpleSocket.h | 31 +++-- 4 files changed, 304 insertions(+), 67 deletions(-) diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index b64496c..4806b1a 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -78,21 +78,26 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u // If no IP Address (interface ethn) is supplied, or the loop back is // specified then bind to any interface, else bind to specified interface. //-------------------------------------------------------------------------- - if ((pInterface == NULL) || (!strlen(pInterface))) + if (pInterface && pInterface[0]) { - m_stMulticastGroup.sin_addr.s_addr = htonl(INADDR_ANY); + inet_pton(AF_INET, pInterface, &inAddr); } else { - if ((inAddr = inet_addr(pInterface)) != INADDR_NONE) - { - m_stMulticastGroup.sin_addr.s_addr = inAddr; - } + inAddr = INADDR_ANY; + } + + if (pGroup && pGroup[0] != 0) + { + m_stMulticastGroup.sin_addr.s_addr = htonl(INADDR_ANY); + } + else + { + m_stMulticastGroup.sin_addr.s_addr = inAddr; } // multicast address/port is the server memcpy(&m_stServerSockaddr,&m_stMulticastGroup,sizeof(m_stServerSockaddr)); - ClearSystemError(); //-------------------------------------------------------------------------- @@ -101,13 +106,13 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u m_bIsServerSide = true; if (bind(m_socket, (struct sockaddr *)&m_stMulticastGroup, sizeof(m_stMulticastGroup)) == 0) { - if ( pGroup ) + if ( pGroup && pGroup[0] != 0 ) { //---------------------------------------------------------------------- // Join the multicast group //---------------------------------------------------------------------- - m_stMulticastRequest.imr_multiaddr.s_addr = inet_addr(pGroup); - m_stMulticastRequest.imr_interface.s_addr = m_stMulticastGroup.sin_addr.s_addr; + inet_pton(AF_INET, pGroup, &m_stMulticastRequest.imr_multiaddr.s_addr); + m_stMulticastRequest.imr_interface.s_addr = inAddr; if ( SETSOCKOPT(m_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&m_stMulticastRequest, @@ -146,7 +151,9 @@ bool CPassiveSocket::BindMulticast(const char *pInterface, const char *pGroup, u //------------------------------------------------------------------------------ // -// Listen() - +// Listen() - Create a listening socket (server) at local ip address 'x.x.x.x' or 'localhost' +// waiting for an incoming connection from client(s) +// also see .h // //------------------------------------------------------------------------------ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBacklog) @@ -185,7 +192,8 @@ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBa } else { - if ((inAddr = inet_addr(pAddr)) != INADDR_NONE) + inet_pton(AF_INET, pAddr, &inAddr); + if (inAddr != INADDR_NONE) { m_stServerSockaddr.sin_addr.s_addr = inAddr; } @@ -266,7 +274,7 @@ CSimpleSocket *CPassiveSocket::Accept() errno = 0; socket = accept(m_socket, (struct sockaddr *)&m_stClientSockaddr, (socklen_t *)&nSockLen); - if (socket != -1) + if (socket != INVALID_SOCKET) { pClientSocket = new CSimpleSocket(); if ( !pClientSocket ) diff --git a/src/PassiveSocket.h b/src/PassiveSocket.h index d9629e7..308c555 100644 --- a/src/PassiveSocket.h +++ b/src/PassiveSocket.h @@ -97,7 +97,8 @@ class EXPORT CPassiveSocket : public CSimpleSocket { return BindMulticast(pInterface, pNoGroup, nPort); } - /// Create a listening socket at local ip address 'x.x.x.x' or 'localhost' + /// Create a listening socket (server) at local ip address 'x.x.x.x' or 'localhost' + /// waiting for an incoming connection from client(s) /// if pAddr is NULL on port nPort. /// /// @param pAddr specifies the IP address on which to listen. diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 36f8f15..80d9ad7 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -46,9 +46,30 @@ #include #endif #include +#include + +#ifdef _MSC_VER +#pragma warning( disable : 4996 ) +#define snprintf _snprintf +#endif #define PRINT_CLOSE 0 #define PRINT_ERRORS 0 +#define CHECK_PRINT_RUNTIME_ERR 0 + + +#if CHECK_PRINT_RUNTIME_ERR + +#include + +static void CoreDump() +{ + int * ptr = nullptr; + while (1) + *ptr++ = -1; +} + +#endif CSimpleSocket::CSimpleSocket(CSocketType nType) : @@ -151,6 +172,155 @@ CSimpleSocket *CSimpleSocket::operator=(CSimpleSocket &socket) } +bool CSimpleSocket::GetAddrInfoStatic(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress, CSocketType nSocketType ) +{ + char aServ[64]; + char * pServ = aServ; + struct addrinfo hints, *servinfo, *p; + int rv; + int nSocketDomain = 0; + + memset(&hints, 0, sizeof(hints)); + switch ( nSocketType ) + { + default: + case SocketTypeInvalid: +#ifdef _WIN32 + case SocketTypeRaw: +#endif + return false; + case SocketTypeTcp6: + hints.ai_family = nSocketDomain = AF_INET6; + hints.ai_socktype = SOCK_STREAM; + break; + case SocketTypeTcp: + hints.ai_family = nSocketDomain = AF_INET; + hints.ai_socktype = SOCK_STREAM; + break; + case SocketTypeUdp6: + hints.ai_family = nSocketDomain = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + break; + case SocketTypeUdp: + hints.ai_family = nSocketDomain = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + break; +#if defined(_LINUX) && !defined(_DARWIN) + case SocketTypeRaw: + hints.ai_family = nSocketDomain = AF_PACKET; + hints.ai_socktype = SOCK_RAW; + break; +#endif + } + + if ( nPort ) + snprintf( aServ, 63, "%d", (int)nPort ); + else + pServ = 0; + + rv = ::getaddrinfo(pAddr, pServ, &hints, &servinfo ); + if ( rv != 0 ) + return false; + + // loop through all the results + for ( p = servinfo; p != NULL; p = p->ai_next ) + { + // creation of socket already done in Initialize() + // check, that protocol and socktype fit + if ( p->ai_family != nSocketDomain || p->ai_socktype != nSocketType + || p->ai_addr->sa_family != nSocketDomain ) + { + continue; + } + + // struct sockaddr_in * pOutSin + //*pOutSin = *( (struct sockaddr_in *) p->ai_addr ); + + // struct in_addr * pOutIpAddress + *pOutIpAddress = ( (struct sockaddr_in *)p->ai_addr )->sin_addr; + + freeaddrinfo(servinfo); // all done with this structure + return true; + } + + freeaddrinfo(servinfo); // all done with this structure + return false; +} + + +bool CSimpleSocket::GetAddrInfo(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress ) +{ + char aServ[64]; + char * pServ = aServ; + struct addrinfo hints, *servinfo, *p; + int rv; + + if (m_socket == INVALID_SOCKET) + { + return false; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = m_nSocketDomain; // AF_INET for IPv4, AF_UNSPEC for any, AF_INET6 to force IPv6 + switch ( m_nSocketType ) + { + default: + case SocketTypeInvalid: + return false; + case SocketTypeTcp6: + case SocketTypeTcp: + hints.ai_socktype = SOCK_STREAM; + break; + case SocketTypeUdp6: + case SocketTypeUdp: + hints.ai_socktype = SOCK_DGRAM; + break; + case SocketTypeRaw: + hints.ai_socktype = SOCK_RAW; + break; + } + + if ( nPort ) + snprintf( aServ, 63, "%d", (int)nPort ); + else + pServ = 0; + + rv = ::getaddrinfo(pAddr, pServ, &hints, &servinfo ); + if ( rv != 0 ) + { + // gai_strerror(rv); + SetSocketError(CSimpleSocket::SocketInvalidAddress); + return false; + } + + // loop through all the results + for ( p = servinfo; p != NULL; p = p->ai_next ) + { + // creation of socket already done in Initialize() + // check, that protocol and socktype fit + if ( p->ai_family != m_nSocketDomain || p->ai_socktype != m_nSocketType + || p->ai_addr->sa_family != m_nSocketDomain ) + { + continue; + } + + // struct sockaddr_in * pOutSin + //*pOutSin = *( (struct sockaddr_in *) p->ai_addr ); + + // struct in_addr * pOutIpAddress + *pOutIpAddress = ( (struct sockaddr_in *)p->ai_addr )->sin_addr; + + freeaddrinfo(servinfo); // all done with this structure + return true; + } + + freeaddrinfo(servinfo); // all done with this structure + + SetSocketError(CSimpleSocket::SocketInvalidAddress); + return false; +} + + //------------------------------------------------------------------------------ // // ConnectTCP() - @@ -172,21 +342,9 @@ bool CSimpleSocket::ConnectTCP(const char *pAddr, uint16 nPort) memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); m_stServerSockaddr.sin_family = AF_INET; - struct hostent *pHE = GETHOSTBYNAME(pAddr); - if (pHE == NULL) - { -#ifdef WIN32 - TranslateSocketError(); -#else - if (h_errno == HOST_NOT_FOUND) - { - SetSocketError(SocketInvalidAddress); - } -#endif - return bRetVal; - } + if ( ! GetAddrInfo(pAddr, nPort, &stIpAddress) ) + return bRetVal; - memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) @@ -260,21 +418,9 @@ bool CSimpleSocket::ConnectUDP(const char *pAddr, uint16 nPort) memset(&m_stServerSockaddr, 0, sizeof(m_stServerSockaddr)); m_stServerSockaddr.sin_family = AF_INET; - struct hostent *pHE = GETHOSTBYNAME(pAddr); - if (pHE == NULL) - { -#ifdef WIN32 - TranslateSocketError(); -#else - if (h_errno == HOST_NOT_FOUND) - { - SetSocketError(SocketInvalidAddress); - } -#endif - return bRetVal; - } + if ( ! GetAddrInfo(pAddr, nPort, &stIpAddress) ) + return bRetVal; - memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) @@ -292,11 +438,8 @@ bool CSimpleSocket::ConnectUDP(const char *pAddr, uint16 nPort) m_timer.Initialize(); m_timer.SetStartTime(); - if (connect(m_socket, (struct sockaddr*)&m_stServerSockaddr, sizeof(m_stServerSockaddr)) != CSimpleSocket::SocketError) - { - bRetVal = true; - m_bPeerHasClosed = false; - } + bRetVal = true; + m_bPeerHasClosed = false; TranslateSocketError(); @@ -340,8 +483,32 @@ bool CSimpleSocket::ConnectRAW(const char *pAddr, uint16 nPort) return bRetVal; } - memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); - m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; + if ( pHE->h_addrtype == AF_INET && (int)sizeof(stIpAddress) >= pHE->h_length ) + { + memcpy(&stIpAddress, pHE->h_addr_list[0], pHE->h_length); + m_stServerSockaddr.sin_addr.s_addr = stIpAddress.s_addr; + } + else + { +#if CHECK_PRINT_RUNTIME_ERR + fprintf(stderr, "\nERROR at ConnectRAW(): hostent * result of gethostbyname(\"%s\"): h_addrtype = %s , sizeof(in_addr) = %d < %d = h_length !\n\n" + , pAddr + , ( pHE->h_addrtype == AF_INET ? "IPv4" : ( pHE->h_addrtype == AF_INET6 ? "IPv6!" : "unknown" ) ) + , (int)sizeof(stIpAddress) + , pHE->h_length + ); + fprintf(stdout, "\nERROR at ConnectRAW(): hostent * result of gethostbyname(\"%s\"): h_addrtype = %s , sizeof(in_addr) = %d < %d = h_length !\n\n" + , pAddr + , ( pHE->h_addrtype == AF_INET ? "IPv4" : ( pHE->h_addrtype == AF_INET6 ? "IPv6!" : "unknown" ) ) + , (int)sizeof(stIpAddress) + , pHE->h_length + ); + fflush(stdout); + CoreDump(); + assert(0); // check, when this happens +#endif + memset(&m_stServerSockaddr.sin_addr.s_addr, CSimpleSocket::SocketError, sizeof(m_stServerSockaddr.sin_addr.s_addr)); + } if ((int32)m_stServerSockaddr.sin_addr.s_addr == CSimpleSocket::SocketError) { @@ -420,6 +587,7 @@ bool CSimpleSocket::Initialize() //------------------------------------------------------------------------------ // // Open() - Create a connection to a specified address on a specified port +// also see .h // //------------------------------------------------------------------------------ bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) @@ -472,10 +640,14 @@ bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) //-------------------------------------------------------------------------- if (bRetVal) { - socklen_t nSockLen = sizeof(struct sockaddr); + socklen_t nSockLen; + if(m_nSocketType != CSimpleSocket::SocketTypeUdp) + { + nSockLen = sizeof(struct sockaddr); - memset(&m_stServerSockaddr, 0, nSockLen); - getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen); + memset(&m_stServerSockaddr, 0, nSockLen); + getpeername(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen); + } nSockLen = sizeof(struct sockaddr); memset(&m_stClientSockaddr, 0, nSockLen); @@ -502,7 +674,7 @@ bool CSimpleSocket::BindInterface(const char *pInterface) { if (pInterface) { - stInterfaceAddr.s_addr= inet_addr(pInterface); + inet_pton(AF_INET, pInterface, &stInterfaceAddr.s_addr); if (SETSOCKOPT(m_socket, IPPROTO_IP, IP_MULTICAST_IF, &stInterfaceAddr, sizeof(stInterfaceAddr)) == SocketSuccess) { bRetVal = true; @@ -677,7 +849,7 @@ uint32 CSimpleSocket::GetWindowSize(uint32 nOptionName) //------------------------------------------------------------------------- // no socket given, return system default allocate our own new socket //------------------------------------------------------------------------- - if (m_socket != CSimpleSocket::SocketError) + if (m_socket != INVALID_SOCKET) { socklen_t nLen = sizeof(nTcpWinSize); @@ -708,7 +880,7 @@ uint32 CSimpleSocket::SetWindowSize(uint32 nOptionName, uint32 nWindowSize) //------------------------------------------------------------------------- // no socket given, return system default allocate our own new socket //------------------------------------------------------------------------- - if (m_socket != CSimpleSocket::SocketError) + if (m_socket != INVALID_SOCKET) { if (SETSOCKOPT(m_socket, SOL_SOCKET, nOptionName, &nWindowSize, sizeof(nWindowSize)) == SocketError) { @@ -778,6 +950,26 @@ bool CSimpleSocket::EnableNagleAlgoritm() } +uint32 CSimpleSocket::GetIPv4AddrInfoStatic( const char *pAddr, CSocketType nSocketType ) +{ + struct in_addr stIpAddress; + bool ret = GetAddrInfoStatic( pAddr, 0, &stIpAddress, nSocketType ); + if (!ret) + return 0; + return ntohl(stIpAddress.s_addr); +} + + +uint32 CSimpleSocket::GetIPv4AddrInfo( const char *pAddr ) +{ + struct in_addr stIpAddress; + bool ret = GetAddrInfo( pAddr, 0, &stIpAddress ); + if (!ret) + return 0; + return ntohl(stIpAddress.s_addr); +} + + /// Set object socket handle to that specified as parameter /// @param socket value of socket descriptor void CSimpleSocket::SetSocketHandle(SOCKET socket, bool bIsServerSide ) @@ -920,7 +1112,7 @@ bool CSimpleSocket::Shutdown(CShutdownMode nShutdown) { CSocketError nRetVal = SocketEunknown; - nRetVal = (CSocketError)shutdown(m_socket, CSimpleSocket::Sends); + nRetVal = (CSocketError)shutdown(m_socket, nShutdown); if (nRetVal == SocketError) { TranslateSocketError(); @@ -1458,17 +1650,17 @@ int32 CSimpleSocket::SendFile(int32 nOutFd, int32 nInFd, off_t *pOffset, int32 n } -bool CSimpleSocket::IsSocketValid(void) +bool CSimpleSocket::IsSocketValid(void) const { #if PRINT_CLOSE if ( m_socket == SocketError ) fprintf(stderr, "reporting CSimpleSocket::IsSocketValid() == false.\n" ); #endif - return (m_socket != SocketError); + return (m_socket != INVALID_SOCKET); } -bool CSimpleSocket::IsSocketPeerClosed(void) +bool CSimpleSocket::IsSocketPeerClosed(void) const { #if PRINT_CLOSE if ( m_bPeerHasClosed ) @@ -1503,6 +1695,11 @@ void CSimpleSocket::ClearSystemError(void) //------------------------------------------------------------------------------ void CSimpleSocket::TranslateSocketError(void) { + // see + // * http://man7.org/linux/man-pages/man3/errno.3.html + // * https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx# + // for the system's error code's + // it's quite difficult to map all of them to some CSocketError! #if defined(_LINUX) || defined(_DARWIN) int systemErrno = errno; switch (systemErrno) @@ -1559,9 +1756,16 @@ void CSimpleSocket::TranslateSocketError(void) case ENOPROTOOPT: SetSocketError(CSimpleSocket::SocketConnectionReset); break; + case EADDRNOTAVAIL: case EADDRINUSE: SetSocketError(CSimpleSocket::SocketAddressInUse); break; + case ESHUTDOWN: + case EHOSTUNREACH: + case ENETUNREACH: + case ENETDOWN: + SetSocketError(CSimpleSocket::SocketNetworkError); + break; default: #if PRINT_ERRORS fprintf( stderr, "\nCSimpleSocket::SocketEunknown: errno=%d: %s\n", systemErrno, strerror(systemErrno) ); @@ -1623,11 +1827,18 @@ void CSimpleSocket::TranslateSocketError(void) SetSocketError(CSimpleSocket::SocketInvalidAddress); break; case WSAEADDRINUSE: + case WSAEADDRNOTAVAIL: SetSocketError(CSimpleSocket::SocketAddressInUse); break; case WSAEFAULT: SetSocketError(CSimpleSocket::SocketInvalidPointer); break; + case WSAENETDOWN: + case WSAENETUNREACH: + case WSAENETRESET: + case WSAESHUTDOWN: + SetSocketError(CSimpleSocket::SocketNetworkError); + break; default: SetSocketError(CSimpleSocket::SocketEunknown); break; @@ -1684,6 +1895,8 @@ const char *CSimpleSocket::DescribeError(CSocketError err) return "Pointer type supplied as argument is invalid."; case CSimpleSocket::SocketEunknown: return "Unknown error"; + case CSimpleSocket::SocketNetworkError: + return "Network error"; default: return "No such CSimpleSocket error"; } diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index a516226..8085ed1 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -149,9 +149,10 @@ class EXPORT CSimpleSocket { SocketInvalidPort, ///< Invalid destination port specified. SocketConnectionRefused, ///< No server is listening at remote address. SocketTimedout, ///< Timed out while attempting operation. - SocketEwouldblock, ///< Operation would block if socket were blocking. + SocketEwouldblock, ///< Operation would block if socket were blocking. On Accept/Receive/Send/ SocketNotconnected, ///< Currently not connected. - SocketEinprogress, ///< Socket is non-blocking and the connection cannot be completed immediately + SocketEinprogress, ///< Socket is non-blocking and the connection cannot be completed immediately. + /// only on Open/ConnectTo/.. SocketInterrupted, ///< Call was interrupted by a signal that was caught before a valid connection arrived. SocketConnectionAborted, ///< The connection has been aborted. SocketProtocolError, ///< Invalid protocol for operation. @@ -160,7 +161,8 @@ class EXPORT CSimpleSocket { SocketConnectionReset, ///< Connection was forcibly closed by the remote host. SocketAddressInUse, ///< Address already in use. SocketInvalidPointer, ///< Pointer type supplied as argument is invalid. - SocketEunknown ///< Unknown error please report to mark@carrierlabs.com + SocketEunknown, ///< Unknown error + SocketNetworkError ///< Several network errors } CSocketError; public: @@ -175,7 +177,8 @@ class EXPORT CSimpleSocket { /// @return true if properly initialized. virtual bool Initialize(void); - /// Established a connection to the address specified by pAddr. + /// Establishes a connection to the (server-)address specified by pAddr + /// and (server-)port specified by nPort. /// Connection-based protocol sockets (CSocket::SocketTypeTcp) may /// successfully call Open() only once, however; connectionless protocol /// sockets (CSocket::SocketTypeUdp) may use Open() multiple times to @@ -239,10 +242,10 @@ class EXPORT CSimpleSocket { /// Does the current instance of the socket object contain a valid socket /// descriptor. /// @return true if the socket object contains a valid socket descriptor. - virtual bool IsSocketValid(void); + virtual bool IsSocketValid(void) const; - inline bool IsSocketInvalid(void) { + inline bool IsSocketInvalid(void) const { return !IsSocketValid(); }; @@ -250,10 +253,10 @@ class EXPORT CSimpleSocket { /// Is the current instance of the socket already closed from peer? /// Information is updated on Receive() ! /// @return true if the socket was closed - virtual bool IsSocketPeerClosed(void); + virtual bool IsSocketPeerClosed(void) const; - inline bool IsSocketPeerOpen(void) { + inline bool IsSocketPeerOpen(void) const { return !IsSocketPeerClosed(); }; @@ -627,6 +630,14 @@ class EXPORT CSimpleSocket { /// @return false if failed to set socket option otherwise return true; bool EnableNagleAlgoritm(); + /// retrieve IPv4 address via getaddrinfo() as uint32 in HostByteOrder + /// as static member + /// @return 0 if failed + static uint32 GetIPv4AddrInfoStatic( const char *pAddr, CSocketType nSocketType = SocketTypeTcp ); + + /// retrieve IPv4 address via getaddrinfo() as uint32 in HostByteOrder + /// @return 0 if failed + uint32 GetIPv4AddrInfo( const char *pAddr ); protected: /// Set internal socket error to that specified error @@ -666,6 +677,10 @@ class EXPORT CSimpleSocket { CSimpleSocket *operator=(CSimpleSocket &socket); + static bool GetAddrInfoStatic(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress, CSocketType nSocketType = SocketTypeTcp ); + + bool GetAddrInfo(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress ); + /// Utility function used to create a TCP connection, called from Open(). /// @return true if successful connection made, otherwise false. bool ConnectTCP(const char *pAddr, uint16 nPort); From 2e20bfb7960dcc31dddb7ba24458b7e3729333a8 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Fri, 4 May 2018 00:08:30 +0200 Subject: [PATCH 10/19] compiler/linker options for build with mingw and msvc * mingw is missing inet_pton() function. - added replacement implementation - switched on with cmake option CLSOCKET_OWN_INET_PTON * msvc: static build against c runtime with cmake CLSOCKET_SHARED off * build examples with msvc - except clsocket-example requiring pthread Signed-off-by: hayati ayguen --- CMakeLists.txt | 36 +++++++-- src/PassiveSocket.cpp | 5 +- src/SimpleSocket.cpp | 174 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6588b4..fd8103f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,10 +44,16 @@ elseif(WIN32) SET(PROJECT_LIBS Ws2_32.lib) if(MINGW) # Special MINGW stuff here + OPTION(CLSOCKET_OWN_INET_PTON "Use own inet_pton() implementation (required on MINGW)" ON) + if(CLSOCKET_OWN_INET_PTON) + add_definitions(-DCLSOCKET_OWN_INET_PTON) + endif() # see https://cmake.org/pipermail/cmake/2012-September/051970.html # see http://stackoverflow.com/questions/13768515/how-to-do-static-linking-of-libwinpthread-1-dll-in-mingw - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -static-libgcc") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++") + # looks, the following compiler options produce linker errors. -static, .. options should only be used for linker + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -static-libgcc") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++") + # commenting out upper two CMAKE_C[XX]_FLAG now compiles and links with and without CLSOCKET_SHARED cmake option set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static -static-libgcc -s") set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static -static-libgcc -static-libstdc++ -s") elseif(MSVC) @@ -75,6 +81,18 @@ else() else() ADD_LIBRARY(clsocket STATIC ${CLSOCKET_SOURCES}) endif() + + if(MSVC) + # Special MSVC stuff here + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -MT") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -MT") + set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -MT") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -MT") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -MT") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -MTd") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -MTd") + endif() endif() TARGET_LINK_LIBRARIES(clsocket ${PROJECT_LIBS}) @@ -89,14 +107,18 @@ endif() set_target_properties(clsocket PROPERTIES VERSION ${BUILD_VERSION} SOVERSION ${BUILD_MAJOR}) -if(UNIX OR (WIN32 AND MINGW)) +if(UNIX OR (WIN32 OR MINGW)) OPTION(CLSOCKET_EXAMPLES "Build the examples" OFF) if(CLSOCKET_EXAMPLES) - ADD_EXECUTABLE(clsocket-example examples/RecvAsync.cpp) - TARGET_LINK_LIBRARIES(clsocket-example clsocket pthread) - if(NOT CLSOCKET_DEP_ONLY) - install(TARGETS clsocket-example DESTINATION bin) + + if (NOT MSVC) + # pthread not available with MSVC + ADD_EXECUTABLE(clsocket-example examples/RecvAsync.cpp) + TARGET_LINK_LIBRARIES(clsocket-example clsocket pthread) + if(NOT CLSOCKET_DEP_ONLY) + install(TARGETS clsocket-example DESTINATION bin) + endif() endif() ADD_EXECUTABLE(querydaytime-example examples/QueryDayTime.cpp) diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index 4806b1a..ab36819 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -42,7 +42,10 @@ *----------------------------------------------------------------------------*/ #include "PassiveSocket.h" - +#ifdef CLSOCKET_OWN_INET_PTON +// implemented in SimpleSocket.cpp +extern int inet_pton(int af, const char *src, void *dst); +#endif CPassiveSocket::CPassiveSocket(CSocketType nType) : CSimpleSocket(nType) { diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 80d9ad7..9624b33 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -48,6 +48,10 @@ #include #include +#ifdef CLSOCKET_OWN_INET_PTON +#include +#endif + #ifdef _MSC_VER #pragma warning( disable : 4996 ) #define snprintf _snprintf @@ -71,6 +75,176 @@ static void CoreDump() #endif +#ifdef CLSOCKET_OWN_INET_PTON +// source from +// https://stackoverflow.com/questions/15370033/how-to-use-inet-pton-with-the-mingw-compiler +// Author: Paul Vixie, 1996. +// added "static" for inet_pton4() and inet_pton6() + +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 +#define NS_INT16SZ 2 + +static +int inet_pton4(const char *src, char *dst) +{ + uint8_t tmp[NS_INADDRSZ], *tp; + + int saw_digit = 0; + int octets = 0; + *(tp = tmp) = 0; + + int ch; + while ((ch = *src++) != '\0') + { + if (ch >= '0' && ch <= '9') + { + uint32_t n = *tp * 10 + (ch - '0'); + + if (saw_digit && *tp == 0) + return 0; + + if (n > 255) + return 0; + + *tp = n; + if (!saw_digit) + { + if (++octets > 4) + return 0; + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return 0; + *++tp = 0; + saw_digit = 0; + } + else + return 0; + } + if (octets < 4) + return 0; + + memcpy(dst, tmp, NS_INADDRSZ); + + return 1; +} + +static +int inet_pton6(const char *src, char *dst) +{ + static const char xdigits[] = "0123456789abcdef"; + uint8_t tmp[NS_IN6ADDRSZ]; + + uint8_t *tp = (uint8_t*) memset(tmp, '\0', NS_IN6ADDRSZ); + uint8_t *endp = tp + NS_IN6ADDRSZ; + uint8_t *colonp = NULL; + + /* Leading :: requires some special handling. */ + if (*src == ':') + { + if (*++src != ':') + return 0; + } + + const char *curtok = src; + int saw_xdigit = 0; + uint32_t val = 0; + int ch; + while ((ch = tolower(*src++)) != '\0') + { + const char *pch = strchr(xdigits, ch); + if (pch != NULL) + { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return 0; + saw_xdigit = 1; + continue; + } + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) + return 0; + colonp = tp; + continue; + } + else if (*src == '\0') + { + return 0; + } + if (tp + NS_INT16SZ > endp) + return 0; + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, (char*) tp) > 0) + { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return 0; + } + if (saw_xdigit) + { + if (tp + NS_INT16SZ > endp) + return 0; + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + } + if (colonp != NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + + if (tp == endp) + return 0; + + for (int i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return 0; + + memcpy(dst, tmp, NS_IN6ADDRSZ); + + return 1; +} + +int inet_pton(int af, const char *src, void *dst) +{ + switch (af) + { + case AF_INET: + return inet_pton4(src, (char*)dst); + case AF_INET6: + return inet_pton6(src, (char*)dst); + default: + return -1; + } +} + +#endif + CSimpleSocket::CSimpleSocket(CSocketType nType) : m_socket(INVALID_SOCKET), From f011324f8d3dbf102c4cf4fde465a8b80ece319e Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Sun, 13 May 2018 01:03:32 +0200 Subject: [PATCH 11/19] bugfixes and enhancements on local/peer and bind() * fixed CSimpleSocket::GetClientPort() * fixed peer/local address in CPassiveSocket::Accept() * fixed Linux compilation in CPassiveSocket::Listen() * added CSimpleSocket::Bind() for tcp/udp client connections * enhanced all examples: all print local/peer address and port * fixed output of GetLocalAddr() and GetPeerAddr() in examples * examples txtoserver and txtoudpserver with optional local binding Signed-off-by: hayati ayguen --- examples/DelayedEchoServer.cpp | 17 ++++++- examples/EchoServer.cpp | 23 ++++++--- examples/QueryDayTime.cpp | 5 ++ examples/TxToServer.cpp | 18 ++++--- examples/TxToUdpServer.cpp | 18 ++++--- examples/UdpServer.cpp | 26 +++++++--- src/SimpleSocket.cpp | 90 ++++++++++++++++++++++++++-------- src/SimpleSocket.h | 25 ++++++++-- 8 files changed, 173 insertions(+), 49 deletions(-) diff --git a/examples/DelayedEchoServer.cpp b/examples/DelayedEchoServer.cpp index 2e8e0dd..84f1c10 100644 --- a/examples/DelayedEchoServer.cpp +++ b/examples/DelayedEchoServer.cpp @@ -20,16 +20,31 @@ int main(int argc, char **argv) CPassiveSocket socket; CSimpleSocket *pClient = NULL; + const char * bindAddr = 0; + unsigned bindPort = 6789; + if ( argc <= 1 ) + fprintf(stderr, "usage: %s [ []]\n", argv[0] ); + if ( 1 < argc ) + bindAddr = argv[1]; + if ( 2 < argc ) + bindPort = atoi(argv[2]) & 65535; + //-------------------------------------------------------------------------- // Initialize our socket object //-------------------------------------------------------------------------- socket.Initialize(); - socket.Listen( 0, 6789 ); // NULL (not "127.0.0.1") to allow testing with remotes + fprintf(stderr, "binding to %s:%u\n", bindAddr, bindPort); + socket.Listen( bindAddr, uint16(bindPort) ); // not "127.0.0.1" to allow testing with remotes while (true) { if ((pClient = socket.Accept()) != NULL) { + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( pClient->IsServerSide() ? "Server" : "Client" ) + , pClient->GetLocalAddr(), (unsigned)pClient->GetLocalPort()); + fprintf(stderr, "Peer: %s:%u\n", pClient->GetPeerAddr(), (unsigned)pClient->GetPeerPort()); + //---------------------------------------------------------------------- // Receive request from the client. //---------------------------------------------------------------------- diff --git a/examples/EchoServer.cpp b/examples/EchoServer.cpp index b491e3c..b99dae9 100644 --- a/examples/EchoServer.cpp +++ b/examples/EchoServer.cpp @@ -8,16 +8,31 @@ int main(int argc, char **argv) CPassiveSocket socket; CActiveSocket *pClient = NULL; + const char * bindAddr = 0; + unsigned bindPort = 6789; + if ( argc <= 1 ) + fprintf(stderr, "usage: %s [ []]\n", argv[0] ); + if ( 1 < argc ) + bindAddr = argv[1]; + if ( 2 < argc ) + bindPort = atoi(argv[2]) & 65535; + //-------------------------------------------------------------------------- // Initialize our socket object //-------------------------------------------------------------------------- socket.Initialize(); - socket.Listen( 0, 6789 ); // NULL (not "127.0.0.1") to allow testing with remotes + fprintf(stderr, "binding to %s:%u\n", bindAddr, bindPort); + socket.Listen( bindAddr, uint16(bindPort) ); // not "127.0.0.1" to allow testing with remotes while (true) { if ((pClient = socket.Accept()) != NULL) { + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( pClient->IsServerSide() ? "Server" : "Client" ) + , pClient->GetLocalAddr(), (unsigned)pClient->GetLocalPort()); + fprintf(stderr, "Peer: %s:%u\n", pClient->GetPeerAddr(), (unsigned)pClient->GetPeerPort()); + //---------------------------------------------------------------------- // Receive request from the client. //---------------------------------------------------------------------- @@ -27,12 +42,6 @@ int main(int argc, char **argv) if (pClient->Receive(MAX_PACKET)) { - fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" - , ( pClient->IsServerSide() ? "Local is Server" : "Local is Client" ) - , pClient->GetLocalAddr(), (unsigned)pClient->GetLocalPort() - , pClient->GetPeerAddr(), (unsigned)pClient->GetPeerPort() - ); - //------------------------------------------------------------------ // Send response to client and close connection to the client. //------------------------------------------------------------------ diff --git a/examples/QueryDayTime.cpp b/examples/QueryDayTime.cpp index 254d6e1..a914cf5 100644 --- a/examples/QueryDayTime.cpp +++ b/examples/QueryDayTime.cpp @@ -23,6 +23,11 @@ int main(int argc, char **argv) fprintf(stderr, "trying to connect to timeserver %s:%d ..\n", timeServer, PortNo); if (socket.Open(timeServer, (uint16)PortNo)) { + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( socket.IsServerSide() ? "Server" : "Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); + fprintf(stderr, "Peer: %s:%u\n", socket.GetPeerAddr(), (unsigned)socket.GetPeerPort()); + //---------------------------------------------------------------------- // Send a requtest the server requesting the current time. //---------------------------------------------------------------------- diff --git a/examples/TxToServer.cpp b/examples/TxToServer.cpp index 4fd7064..0706ac5 100644 --- a/examples/TxToServer.cpp +++ b/examples/TxToServer.cpp @@ -11,7 +11,7 @@ int main(int argc, char **argv) if ( argc < 3 ) { - fprintf(stderr, "usage: %s \n", argv[0] ); + fprintf(stderr, "usage: %s [ ]\n", argv[0] ); return 10; } @@ -20,6 +20,13 @@ int main(int argc, char **argv) //-------------------------------------------------------------------------- socket.Initialize(); + if ( 4 < argc ) + { + unsigned bindPort = atoi(argv[4]); + bool ret = socket.Bind( argv[3], uint16(bindPort) ); + fprintf(stderr, "bind to %s:%u %s\n", argv[3], bindPort, (ret ? "successful":"failed") ); + } + bool bConnOK = socket.Open( argv[1], 6789 ); if ( !bConnOK ) { @@ -27,11 +34,10 @@ int main(int argc, char **argv) return 10; } - fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" - , ( socket.IsServerSide() ? "Local is Server" : "Local is Client" ) - , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort() - , socket.GetPeerAddr(), (unsigned)socket.GetPeerPort() - ); + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( socket.IsServerSide() ? "Server" : "Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); + fprintf(stderr, "Peer: %s:%u\n", socket.GetPeerAddr(), (unsigned)socket.GetPeerPort()); uint32 nSendBufSize = socket.GetSendWindowSize(); fprintf(stderr, "default Send Buffer Size %u\n", nSendBufSize ); diff --git a/examples/TxToUdpServer.cpp b/examples/TxToUdpServer.cpp index 66bff2d..5b75eb5 100644 --- a/examples/TxToUdpServer.cpp +++ b/examples/TxToUdpServer.cpp @@ -11,7 +11,7 @@ int main(int argc, char **argv) if ( argc < 3 ) { - fprintf(stderr, "usage: %s \n", argv[0] ); + fprintf(stderr, "usage: %s [ ]\n", argv[0] ); return 10; } @@ -20,6 +20,13 @@ int main(int argc, char **argv) //-------------------------------------------------------------------------- socket.Initialize(); + if ( 4 < argc ) + { + unsigned bindPort = atoi(argv[4]); + bool ret = socket.Bind( argv[3], uint16(bindPort) ); + fprintf(stderr, "bind to %s:%u %s\n", argv[3], bindPort, (ret ? "successful":"failed") ); + } + bool bConnOK = socket.Open( argv[1], 6789 ); if ( !bConnOK ) { @@ -27,11 +34,10 @@ int main(int argc, char **argv) return 10; } - fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" - , ( socket.IsServerSide() ? "Local is Server" : "Local is Client" ) - , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort() - , socket.GetPeerAddr(), (unsigned)socket.GetPeerPort() - ); + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( socket.IsServerSide() ? "Server" : "Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); + fprintf(stderr, "Peer: %s:%u\n", socket.GetPeerAddr(), (unsigned)socket.GetPeerPort()); size_t sendSize = strlen( argv[2] ); socket.Send( argv[2], (int32)sendSize ); diff --git a/examples/UdpServer.cpp b/examples/UdpServer.cpp index cbe7105..3e0bbc3 100644 --- a/examples/UdpServer.cpp +++ b/examples/UdpServer.cpp @@ -8,13 +8,28 @@ int main(int argc, char **argv) char buffer[ MAX_PACKET ]; CPassiveSocket passiveSocket( CSimpleSocket::SocketTypeUdp ); + const char * bindAddr = 0; + unsigned bindPort = 6789; + if ( argc <= 1 ) + fprintf(stderr, "usage: %s [ []]\n", argv[0] ); + if ( 1 < argc ) + bindAddr = argv[1]; + if ( 2 < argc ) + bindPort = atoi(argv[2]) & 65535; + //-------------------------------------------------------------------------- // Initialize our socket object //-------------------------------------------------------------------------- passiveSocket.Initialize(); - passiveSocket.Bind( 0, 6789 ); // NULL (not "127.0.0.1") to allow testing with remotes + fprintf(stderr, "binding to %s:%u\n", bindAddr, bindPort); + passiveSocket.Bind( bindAddr, uint16(bindPort) ); // not "127.0.0.1" to allow testing with remotes CSimpleSocket &socket = passiveSocket; + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( socket.IsServerSide() ? "Server" : "Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); + fprintf(stderr, "(invalid) Peer: %s:%u\n", socket.GetPeerAddr(), (unsigned)socket.GetPeerPort()); + socket.SetReceiveTimeoutMillis(500); while (true) @@ -31,11 +46,10 @@ int main(int argc, char **argv) fprintf( stderr, "GetNumReceivableBytes() = %d != %d = Receive() !\n", peekRx, rx ); if (rx > 0) { - fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" - , ( passiveSocket.IsServerSide() ? "Local is Server" : "Local is Client" ) - , passiveSocket.GetLocalAddr(), (unsigned)passiveSocket.GetLocalPort() - , passiveSocket.GetPeerAddr(), (unsigned)passiveSocket.GetPeerPort() - ); + fprintf(stderr, "\nLocal is %s. Local: %s:%u " + , ( socket.IsServerSide() ? "Server" : "Client" ) + , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); + fprintf(stderr, "Peer: %s:%u\n", socket.GetPeerAddr(), (unsigned)socket.GetPeerPort()); fprintf(stderr, "\nreceived %d bytes:\n", rx ); for ( int k = 0; k < rx; ++k ) diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 9624b33..525fbb0 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -256,10 +256,15 @@ CSimpleSocket::CSimpleSocket(CSocketType nType) : m_bIsServerSide(false), m_bPeerHasClosed(true) { - SetConnectTimeout(1, 0); // default timeout for connection + memset(&m_stConnectTimeout, 0, sizeof(struct timeval)); memset(&m_stRecvTimeout, 0, sizeof(struct timeval)); memset(&m_stSendTimeout, 0, sizeof(struct timeval)); memset(&m_stLinger, 0, sizeof(struct linger)); + SetConnectTimeout(1, 0); // default timeout for connection + + memset(&m_stServerSockaddr, 0, sizeof(struct sockaddr)); + memset(&m_stClientSockaddr, 0, sizeof(struct sockaddr)); + memset(&m_stMulticastGroup, 0, sizeof(struct sockaddr)); switch(nType) { @@ -834,6 +839,63 @@ bool CSimpleSocket::Open(const char *pAddr, uint16 nPort) } +//------------------------------------------------------------------------------ +// +// Bind() +// +//------------------------------------------------------------------------------ +bool CSimpleSocket::Bind(const char *pInterface, uint16 nPort) +{ + bool bRetVal = false; +#ifdef WIN32 + ULONG inAddr; +#else + in_addr_t inAddr; +#endif + + memset(&m_stClientSockaddr,0,sizeof(m_stClientSockaddr)); + m_stClientSockaddr.sin_family = AF_INET; + m_stClientSockaddr.sin_port = htons(nPort); + + //-------------------------------------------------------------------------- + // If no IP Address (interface ethn) is supplied, or the loop back is + // specified then bind to any interface, else bind to specified interface. + //-------------------------------------------------------------------------- + if (pInterface && pInterface[0]) + { + inet_pton(AF_INET, pInterface, &inAddr); + } + else + { + inAddr = INADDR_ANY; + } + + m_stClientSockaddr.sin_addr.s_addr = inAddr; + + ClearSystemError(); + + //-------------------------------------------------------------------------- + // Bind to the specified port + //-------------------------------------------------------------------------- + if (bind(m_socket, (struct sockaddr *)&m_stClientSockaddr, sizeof(m_stClientSockaddr)) == 0) + { + bRetVal = true; + } + + //-------------------------------------------------------------------------- + // If there was a socket error then close the socket to clean out the + // connection in the backlog. + //-------------------------------------------------------------------------- + TranslateSocketError(); + + if (bRetVal == false) + { + Close(); + } + + return bRetVal; +} + //------------------------------------------------------------------------------ // // BindInterface() @@ -957,7 +1019,7 @@ const char * CSimpleSocket::GetClientAddr() const /// @return client port number. uint16 CSimpleSocket::GetClientPort() const { - return m_stClientSockaddr.sin_port; + return ntohs(m_stClientSockaddr.sin_port); } /// Returns server Internet host address as a string in standard numbers-and-dots notation. @@ -1204,25 +1266,13 @@ int32 CSimpleSocket::Send(const uint8 *pBuf, size_t bytesToSend) // Check error condition and attempt to resend if call // was interrupted by a signal. //--------------------------------------------------------- - // if (GetMulticast()) - // { - // do - // { - // m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, (const sockaddr *)&m_stMulticastGroup, - // sizeof(m_stMulticastGroup)); - // TranslateSocketError(); - // } while (GetSocketError() == CSimpleSocket::SocketInterrupted); - // } - // else + do { - do - { - m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, - (const sockaddr *)&m_stServerSockaddr, - sizeof(m_stServerSockaddr)); - TranslateSocketError(); - } while (GetSocketError() == CSimpleSocket::SocketInterrupted); - } + m_nBytesSent = SENDTO(m_socket, pBuf, bytesToSend, 0, + (const sockaddr *)&m_stServerSockaddr, + sizeof(m_stServerSockaddr)); + TranslateSocketError(); + } while (GetSocketError() == CSimpleSocket::SocketInterrupted); m_timer.SetEndTime(); } diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 8085ed1..3a965e1 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -316,15 +316,15 @@ class EXPORT CSimpleSocket { inline int32 Send(const char *pBuf, size_t bytesToSend) { return Send( (const uint8 *)pBuf, bytesToSend ); - }; + } inline int32 Transmit(const uint8 *pBuf, size_t bytesToSend) { return Send( pBuf, bytesToSend ); - }; + } inline int32 Transmit(const char *pBuf, size_t bytesToSend) { return Send( (const uint8 *)pBuf, bytesToSend ); - }; + } /// Attempts to send at most nNumItem blocks described by sendVector /// to the socket descriptor associated with the socket object. @@ -491,6 +491,13 @@ class EXPORT CSimpleSocket { /// @return true if successfully bound to interface bool BindInterface(const char *pInterface); + + /// Bind socket to a specific interface in general for tcp/udp clients + /// @param pInterface - interface on which to bind. + /// @param nPort - port on which multicast + /// @return true if able to bind to interface. + bool Bind(const char *pInterface, uint16 nPort); + /// Gets the timeout value that specifies the maximum number of seconds a /// a call to CSimpleSocket::Send waits until it completes. /// @return the length of time in seconds @@ -558,14 +565,20 @@ class EXPORT CSimpleSocket { }; /// Returns clients Internet host address as a string in standard numbers-and-dots notation. + /// on TCP Server the Client and Peer Address/Port get valid with successful Accept() + /// on UDP Server the Client and Peer Address/Port get valid with successful Receive() + /// ATTENTION: return is same static buffer as in inet_ntoa(), GetClientAddr(), GetServerAddr(), GetLocalAddr(), GetPeerAddr() /// @return NULL if invalid const char * GetClientAddr() const; /// Returns the port number on which the client is connected. + /// on TCP Server the Client and Peer Address/Port get valid with successful Accept() + /// on UDP Server the Client and Peer Address/Port get valid with successful Receive() /// @return client port number. uint16 GetClientPort() const; /// Returns server Internet host address as a string in standard numbers-and-dots notation. + /// ATTENTION: return is same static buffer as in inet_ntoa(), GetClientAddr(), GetServerAddr(), GetLocalAddr(), GetPeerAddr() /// @return NULL if invalid const char * GetServerAddr() const; @@ -577,6 +590,7 @@ class EXPORT CSimpleSocket { bool IsServerSide() const; /// Returns local Internet host address as a string in standard numbers-and-dots notation. + /// ATTENTION: return is same static buffer as in inet_ntoa(), GetClientAddr(), GetServerAddr(), GetLocalAddr(), GetPeerAddr() /// @return NULL if invalid const char * GetLocalAddr() const; @@ -586,10 +600,15 @@ class EXPORT CSimpleSocket { /// Returns Peer's Internet host address as a string in standard numbers-and-dots notation. + /// on TCP Server the Client and Peer Address/Port get valid with successful Accept() + /// on UDP Server the Client and Peer Address/Port get valid with successful Receive() + /// ATTENTION: return is same static buffer as in inet_ntoa(), GetClientAddr(), GetServerAddr(), GetLocalAddr(), GetPeerAddr() /// @return NULL if invalid const char * GetPeerAddr() const; /// Returns the port number on which the peer is connected. + /// on TCP Server the Client and Peer Address/Port get valid with successful Accept() + /// on UDP Server the Client and Peer Address/Port get valid with successful Receive() /// @return client port number. uint16 GetPeerPort() const; From 72220784661ac993877a808d2d95e3c859ed193b Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Sun, 13 May 2018 11:47:17 +0200 Subject: [PATCH 12/19] fix GetIPv4AddrInfo[Static]() with no/empty address string * looks, some systems return random value! directly return 0 in this case Signed-off-by: hayati ayguen --- src/SimpleSocket.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 525fbb0..8060c02 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -1188,6 +1188,8 @@ bool CSimpleSocket::EnableNagleAlgoritm() uint32 CSimpleSocket::GetIPv4AddrInfoStatic( const char *pAddr, CSocketType nSocketType ) { + if (!pAddr || !pAddr[0]) + return 0; struct in_addr stIpAddress; bool ret = GetAddrInfoStatic( pAddr, 0, &stIpAddress, nSocketType ); if (!ret) @@ -1198,6 +1200,8 @@ uint32 CSimpleSocket::GetIPv4AddrInfoStatic( const char *pAddr, CSocketType nSoc uint32 CSimpleSocket::GetIPv4AddrInfo( const char *pAddr ) { + if (!pAddr || !pAddr[0]) + return 0; struct in_addr stIpAddress; bool ret = GetAddrInfo( pAddr, 0, &stIpAddress ); if (!ret) From 9cbb2e75467748a454307930a9c84713d0458406 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Wed, 12 Aug 2020 23:30:05 +0200 Subject: [PATCH 13/19] define export/visibility - and it's import for shared library * renamed EXPORT to CLSOCKET_API, it's for export and import * added definition CLSOCKET_NO_EXPORT for not exporting private methods * cmake: export symbols only for shared library: EXPORT_CLSOCKET_SYMBOLS * have default visibility hidden - also on linux .. Signed-off-by: hayati ayguen --- CMakeLists.txt | 5 +++++ src/Host.h | 30 +++++++++++++++++++++++++++--- src/PassiveSocket.h | 2 +- src/SimpleSocket.cpp | 20 ++++++++++++++++++++ src/SimpleSocket.h | 40 ++++++++++++++++------------------------ src/StatTimer.h | 2 +- 6 files changed, 70 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fd8103f..269d400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,12 +75,17 @@ if(CLSOCKET_SHARED) else() ADD_LIBRARY(clsocket SHARED ${CLSOCKET_SOURCES}) endif() + # linking against shared library requires the symbols + target_compile_definitions(clsocket PRIVATE EXPORT_CLSOCKET_SYMBOLS) + # have internal symbols hidden by default + set_target_properties(clsocket PROPERTIES CXX_VISIBILITY_PRESET hidden) else() if(CLSOCKET_DEP_ONLY) ADD_LIBRARY(clsocket STATIC EXCLUDE_FROM_ALL ${CLSOCKET_SOURCES}) else() ADD_LIBRARY(clsocket STATIC ${CLSOCKET_SOURCES}) endif() + # no need for export symbols with a static library if(MSVC) # Special MSVC stuff here diff --git a/src/Host.h b/src/Host.h index 91b3d16..8aaa568 100644 --- a/src/Host.h +++ b/src/Host.h @@ -251,11 +251,35 @@ extern "C" #endif #ifdef _MSC_VER - #define EXPORT __declspec(dllexport) -#else - #define EXPORT + #ifdef EXPORT_CLSOCKET_SYMBOLS + #define CLSOCKET_API __declspec(dllexport) + #else + #define CLSOCKET_API __declspec(dllimport) + #endif +#elif defined(_LINUX) || defined(_DARWIN) + #ifdef EXPORT_CLSOCKET_SYMBOLS + #define CLSOCKET_API __attribute__ ((visibility("default"))) + #endif +#endif + +#ifndef CLSOCKET_API + #define CLSOCKET_API +#endif + + +#if defined(_LINUX) || defined(_DARWIN) + #ifdef EXPORT_CLSOCKET_SYMBOLS + #define CLSOCKET_NO_EXPORT __attribute__ ((visibility("hidden"))) + #endif +#endif + +#ifndef CLSOCKET_NO_EXPORT + #define CLSOCKET_NO_EXPORT #endif + + + #ifdef __cplusplus } #endif diff --git a/src/PassiveSocket.h b/src/PassiveSocket.h index 308c555..8023b42 100644 --- a/src/PassiveSocket.h +++ b/src/PassiveSocket.h @@ -52,7 +52,7 @@ /// in a similar fashion. The big difference is that the method /// CPassiveSocket::Accept should not be called on the latter two socket /// types. -class EXPORT CPassiveSocket : public CSimpleSocket { +class CLSOCKET_API CPassiveSocket : public CSimpleSocket { public: CPassiveSocket(CSocketType type = SocketTypeTcp); virtual ~CPassiveSocket(); diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index 8060c02..c74ba6e 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -1072,6 +1072,26 @@ uint16 CSimpleSocket::GetPeerPort() const return (m_bIsServerSide) ? GetClientPort() : GetServerPort(); } +uint32 CSimpleSocket::GetReceiveWindowSize() +{ + return GetWindowSize(SO_RCVBUF); +} + +uint32 CSimpleSocket::GetSendWindowSize() +{ + return GetWindowSize(SO_SNDBUF); +} + +uint32 CSimpleSocket::SetReceiveWindowSize(uint32 nWindowSize) +{ + return SetWindowSize(SO_RCVBUF, nWindowSize); +} + +uint32 CSimpleSocket::SetSendWindowSize(uint32 nWindowSize) +{ + return SetWindowSize(SO_SNDBUF, nWindowSize); +} + //------------------------------------------------------------------------------ // diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 3a965e1..82d2107 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -117,7 +117,7 @@ /// - Socket types /// -# CActiveSocket Class /// -# CPassiveSocket Class -class EXPORT CSimpleSocket { +class CLSOCKET_API CSimpleSocket { friend class CPassiveSocket; public: /// Defines the three possible states for shuting down a socket. @@ -207,11 +207,11 @@ class EXPORT CSimpleSocket { inline bool CloseForReads() { return Shutdown( CSimpleSocket::Receives ); - }; + } inline bool CloseForWrites() { return Shutdown( CSimpleSocket::Sends ); - }; + } /// Examine the socket descriptor sets currently owned by the instance of /// the socket class (the readfds, writefds, and errorfds parameters) to @@ -616,30 +616,22 @@ class EXPORT CSimpleSocket { /// Get the TCP receive buffer window size for the current socket object. ///

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

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

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

\b NOTE: Linux will set the send buffer to twice the value passed. /// @return zero on failure else the number of bytes of the TCP send buffer window size if successful. - uint32 SetSendWindowSize(uint32 nWindowSize) { - return SetWindowSize(SO_SNDBUF, nWindowSize); - }; + uint32 SetSendWindowSize(uint32 nWindowSize); /// Disable the Nagle algorithm (Set TCP_NODELAY to true) /// @return false if failed to set socket option otherwise return true; @@ -672,11 +664,11 @@ class EXPORT CSimpleSocket { private: /// Generic function used to get the send/receive window size /// @return zero on failure else the number of bytes of the TCP window size if successful. - uint32 GetWindowSize(uint32 nOptionName); + CLSOCKET_NO_EXPORT uint32 GetWindowSize(uint32 nOptionName); /// Generic function used to set the send/receive window size /// @return zero on failure else the number of bytes of the TCP window size if successful. - uint32 SetWindowSize(uint32 nOptionName, uint32 nWindowSize); + CLSOCKET_NO_EXPORT uint32 SetWindowSize(uint32 nOptionName, uint32 nWindowSize); /// Attempts to send at most nNumItem blocks described by sendVector @@ -688,29 +680,29 @@ class EXPORT CSimpleSocket { /// @return number of bytes actually sent, return of zero means the /// connection has been shutdown on the other side, and a return of -1 /// means that an error has occurred. - int32 Writev(const struct iovec *pVector, size_t nCount); + CLSOCKET_NO_EXPORT int32 Writev(const struct iovec *pVector, size_t nCount); /// Flush the socket descriptor owned by the object. /// @return true data was successfully sent, else return false; - bool Flush(); + CLSOCKET_NO_EXPORT bool Flush(); - CSimpleSocket *operator=(CSimpleSocket &socket); + CLSOCKET_NO_EXPORT CSimpleSocket *operator=(CSimpleSocket &socket); static bool GetAddrInfoStatic(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress, CSocketType nSocketType = SocketTypeTcp ); - bool GetAddrInfo(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress ); + CLSOCKET_NO_EXPORT bool GetAddrInfo(const char *pAddr, uint16 nPort, struct in_addr * pOutIpAddress ); /// Utility function used to create a TCP connection, called from Open(). /// @return true if successful connection made, otherwise false. - bool ConnectTCP(const char *pAddr, uint16 nPort); + CLSOCKET_NO_EXPORT bool ConnectTCP(const char *pAddr, uint16 nPort); /// Utility function used to create a UDP connection, called from Open(). /// @return true if successful connection made, otherwise false. - bool ConnectUDP(const char *pAddr, uint16 nPort); + CLSOCKET_NO_EXPORT bool ConnectUDP(const char *pAddr, uint16 nPort); /// Utility function used to create a RAW connection, called from Open(). /// @return true if successful connection made, otherwise false. - bool ConnectRAW(const char *pAddr, uint16 nPort); + CLSOCKET_NO_EXPORT bool ConnectRAW(const char *pAddr, uint16 nPort); protected: SOCKET m_socket; /// socket handle diff --git a/src/StatTimer.h b/src/StatTimer.h index c8097b1..9f30e04 100644 --- a/src/StatTimer.h +++ b/src/StatTimer.h @@ -68,7 +68,7 @@ /// Class to abstract socket communications in a cross platform manner. /// This class is designed -class EXPORT CStatTimer { +class CLSOCKET_API CStatTimer { public: CStatTimer() { From 4936c8728d342755eb94b713f78b864d84bc18ac Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Mon, 23 Aug 2021 21:11:28 +0200 Subject: [PATCH 14/19] added options to allow testing udp multicast Signed-off-by: hayati ayguen --- examples/TxToUdpServer.cpp | 10 +++++++++- examples/UdpServer.cpp | 19 ++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/examples/TxToUdpServer.cpp b/examples/TxToUdpServer.cpp index 5b75eb5..e14231c 100644 --- a/examples/TxToUdpServer.cpp +++ b/examples/TxToUdpServer.cpp @@ -11,7 +11,8 @@ int main(int argc, char **argv) if ( argc < 3 ) { - fprintf(stderr, "usage: %s [ ]\n", argv[0] ); + fprintf(stderr, "usage: %s [-m [] | ]\n", argv[0] ); + fprintf(stderr, " -m : activate multicast on socket\n"); return 10; } @@ -34,6 +35,13 @@ int main(int argc, char **argv) return 10; } + if ( 3 < argc && !strcmp(argv[3], "-m") ) + { + uint8 multicastTTL = ( 4 < argc ) ? atoi(argv[4]) : 1; + bool ret = socket.SetMulticast(true, 3); + fprintf(stderr, "Setting Multicast with TTL 3 %s\n", ret ? "was successful" : "failed"); + } + fprintf(stderr, "\nLocal is %s. Local: %s:%u " , ( socket.IsServerSide() ? "Server" : "Client" ) , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); diff --git a/examples/UdpServer.cpp b/examples/UdpServer.cpp index 3e0bbc3..4484955 100644 --- a/examples/UdpServer.cpp +++ b/examples/UdpServer.cpp @@ -9,20 +9,33 @@ int main(int argc, char **argv) CPassiveSocket passiveSocket( CSimpleSocket::SocketTypeUdp ); const char * bindAddr = 0; + const char * multicastGroup = 0; unsigned bindPort = 6789; + bool bindRet; + if ( argc <= 1 ) - fprintf(stderr, "usage: %s [ []]\n", argv[0] ); + { + fprintf(stderr, "usage: %s [ [ []]]\n", argv[0] ); + fprintf(stderr, " do not use '127.0.0.1' if you want to accept reception from remotes\n"); + fprintf(stderr, " suggestion for : 224.0.0.1\n"); + } if ( 1 < argc ) bindAddr = argv[1]; if ( 2 < argc ) bindPort = atoi(argv[2]) & 65535; + if ( 3 < argc ) + multicastGroup = argv[3]; //-------------------------------------------------------------------------- // Initialize our socket object //-------------------------------------------------------------------------- passiveSocket.Initialize(); - fprintf(stderr, "binding to %s:%u\n", bindAddr, bindPort); - passiveSocket.Bind( bindAddr, uint16(bindPort) ); // not "127.0.0.1" to allow testing with remotes + if (!multicastGroup) + fprintf(stderr, "binding to %s:%u\n", bindAddr, bindPort); + else + fprintf(stderr, "binding to %s:%u for multicast-group %s\n", bindAddr, bindPort, multicastGroup); + bindRet = passiveSocket.BindMulticast( bindAddr, multicastGroup, uint16(bindPort) ); + fprintf(stderr, "bind %s\n", bindRet ? "was successful" : "failed"); CSimpleSocket &socket = passiveSocket; fprintf(stderr, "\nLocal is %s. Local: %s:%u " From 1929412162c4e80285b35ef4f2e4a0878ccac4e8 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Thu, 28 Oct 2021 22:08:28 +0200 Subject: [PATCH 15/19] definition CLSOCKET_STATIC_LIB for MSVC to skip dllexport/import Signed-off-by: hayati ayguen --- src/Host.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Host.h b/src/Host.h index 8aaa568..d333dc2 100644 --- a/src/Host.h +++ b/src/Host.h @@ -251,7 +251,9 @@ extern "C" #endif #ifdef _MSC_VER - #ifdef EXPORT_CLSOCKET_SYMBOLS + #ifdef CLSOCKET_STATIC_LIB + #define CLSOCKET_API + #elif defined(EXPORT_CLSOCKET_SYMBOLS) #define CLSOCKET_API __declspec(dllexport) #else #define CLSOCKET_API __declspec(dllimport) From cae012dd0fe24040c9a6852a829cdcb7180f37b4 Mon Sep 17 00:00:00 2001 From: hayati ayguen Date: Sat, 22 Jul 2023 13:35:03 +0200 Subject: [PATCH 16/19] added TestMaxConnections example - to test file-descriptor limit of select() Signed-off-by: hayati ayguen --- CMakeLists.txt | 12 ++ examples/TestMaxConnections.cpp | 279 ++++++++++++++++++++++++++++++++ src/PassiveSocket.cpp | 1 + src/SimpleSocket.cpp | 7 + 4 files changed, 299 insertions(+) create mode 100644 examples/TestMaxConnections.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 269d400..4c45873 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,18 @@ if(UNIX OR (WIN32 OR MINGW)) endif() endif() + ADD_EXECUTABLE(testmaxconnections-example examples/TestMaxConnections.cpp) + TARGET_LINK_LIBRARIES(testmaxconnections-example clsocket) + if(NOT CLSOCKET_DEP_ONLY) + install(TARGETS testmaxconnections-example DESTINATION bin) + endif() + set_target_properties(testmaxconnections-example + PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO + ) + ADD_EXECUTABLE(querydaytime-example examples/QueryDayTime.cpp) TARGET_LINK_LIBRARIES(querydaytime-example clsocket) diff --git a/examples/TestMaxConnections.cpp b/examples/TestMaxConnections.cpp new file mode 100644 index 0000000..9df35d8 --- /dev/null +++ b/examples/TestMaxConnections.cpp @@ -0,0 +1,279 @@ + +#include "PassiveSocket.h" + +#include +#include +#include +#include + +#define MAX_CLIENTS 8192 +#define MAX_PACKET 4096 +//#define TEST_PACKET "Test Packet" +#define TEST_PACKET "Test" + + +struct thread_data +{ + const int max_clients; + const char * pszServerAddr; + short int nPort; + int nNumBytesToReceive; + int nTotalPayloadSize; + CPassiveSocket server_socket; + int nClients; + CSimpleSocket * client_sockets[MAX_CLIENTS]; + bool terminate; + bool ready; + + thread_data(int max_clients_) + : max_clients(max_clients_) + { + pszServerAddr = "127.0.0.1"; + nPort = 6789; + nNumBytesToReceive = 1; + nTotalPayloadSize = (int)strlen(TEST_PACKET); + nClients = 0; + terminate = false; + ready = false; + for (int k=0; k < MAX_CLIENTS; ++k) + client_sockets[k] = 0; + if (!server_socket.Initialize()) + { + fprintf(stderr, "Error: initializing socket!\n"); + return; + } + if (!server_socket.SetNonblocking()) + { + fprintf(stderr, "Error: server/listen socket could set Nonblocking!\n"); + return; + } + if (!server_socket.Listen(pszServerAddr, nPort)) + { + fprintf(stderr, "Error: listen failed!\n"); + return; + } + ready = true; + } + + ~thread_data() + { + printf("\nserver: shutting down server!\n"); + server_socket.Close(); + printf("server: cleanup/delete connections ..\n"); + for (int k = 0; k < nClients; ++k) + delete client_sockets[k]; + } + + bool serve(); +}; + + +bool thread_data::serve() +{ + if (!ready) + return false; + while (!terminate) + { + if (nClients >= max_clients) + { + fprintf(stderr, "\nserver: have served %d clients. shut down\n", nClients); + return false; + } + if (!server_socket.Select(0, 100000)) // 100ms + { + // fprintf(stderr, "server: wait select\n"); + continue; + } + + // printf("server: accept next connection %d ..\n", nClients); + CSimpleSocket *pClient = server_socket.Accept(); + if (!pClient) + { + if (server_socket.GetSocketError() == CPassiveSocket::SocketEwouldblock) + { + fprintf(stderr, "server: accept() would block\n"); + continue; + } + + fprintf(stderr, "server: Error at accept() for %d: code %d: %s\n", + nClients, (int)server_socket.GetSocketError(), server_socket.DescribeError() ); + break; + } + printf("server: accepted %d ..\n", nClients); + + client_sockets[nClients++] = pClient; + int nBytesReceived = 0; + while (!terminate && nBytesReceived < nTotalPayloadSize) + { + if (nBytesReceived += pClient->Receive(nNumBytesToReceive)) + { + pClient->Send((const uint8 *)pClient->GetData(), pClient->GetBytesReceived()); + } + } + // keep the new connection open! + } + + return true; +} + + +bool connect_new_client(CActiveSocket &client, int k, const thread_data &thData) +{ + bool conn_ok = client.Open("127.0.0.1", 6789); + if (!conn_ok) + { + fprintf(stderr, "Error: %d could not connect to server!\n", k); + return false; + } + + int32 r = client.Send((uint8 *)TEST_PACKET, strlen(TEST_PACKET)); + if (!r) + { + fprintf(stderr, "Error: connection %d closed from peer while sending packet!\n", k); + return false; + } + + int numBytes = -1; + int bytesReceived = 0; + char result[1024]; + + client.WaitUntilReadable(100); // wait up to 100 ms + + // Receive() until socket gets closed or we already received the full packet + while ( numBytes != 0 && bytesReceived < thData.nTotalPayloadSize ) + { + numBytes = client.Receive(MAX_PACKET); + + if (numBytes > 0) + { + bytesReceived += numBytes; + // memcpy(result, client.GetData(), numBytes); + // printf("\nreceived %d bytes: '%s'\n", numBytes, result); + } + else if ( CSimpleSocket::SocketEwouldblock == client.GetSocketError() ) + fprintf(stderr, "."); + else if ( !client.IsNonblocking() && CSimpleSocket::SocketTimedout == client.GetSocketError() ) + fprintf(stderr, "w"); + else + { + printf("\n%d: received %d bytes\n", k, numBytes); + + fprintf(stderr, "Error: %s\n", client.DescribeError() ); + fprintf(stderr, "Error: %s, code %d\n" + , ( client.IsNonblocking() ? "NonBlocking socket" : "Blocking socket" ) + , (int) client.GetSocketError() + ); + } + + if ( bytesReceived >= thData.nTotalPayloadSize ) + return true; // no need to wait + // else + // printf("read %d of %d\n", bytesReceived, thData.nTotalPayloadSize); + + client.WaitUntilReadable(100); // wait up to 100 ms + } + + if (bytesReceived >= thData.nTotalPayloadSize) + ; // printf("%d: received %d bytes response.\n", k, bytesReceived); + else + { + fprintf(stderr, "Error at %d: received %d bytes - expected %d!\n", k, bytesReceived, thData.nTotalPayloadSize); + return false; + } + if (!numBytes) + { + fprintf(stderr, "Error: connection %d closed from peer\n", k); + return false; + } + return true; +} + + + +int main(int argc, char **argv) +{ + int max_clients = MAX_CLIENTS; + int init_sockets_at_startup = 1; + + if ( 1 < argc ) + { + if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "-h") || !strcmp(argv[1], "/h")) + { + printf("usage: %s [ [] ]\n", argv[0]); + printf(" max_num_connections: number of connections to test. default = %d, max = %d\n", max_clients, max_clients); + printf(" init_sockets_at_startup: 0 or 1. default = %d\n", init_sockets_at_startup); + return 0; + } + max_clients = atoi(argv[1]); + } + + if ( 2 < argc ) + init_sockets_at_startup = atoi(argv[2]); + + if (max_clients >= MAX_CLIENTS) + max_clients = MAX_CLIENTS; + + thread_data thData{max_clients}; + if (!thData.ready) + return 1; + std::thread server_thread(&thread_data::serve, &thData); + + CActiveSocket * clients = new CActiveSocket[MAX_CLIENTS]; + printf("try to setup/communicate %d conncections ..\n", max_clients); + + bool have_err = false; + if (init_sockets_at_startup) + { + for (int k = 0; k < max_clients; ++k) + { + CActiveSocket &client = clients[k]; + printf("init socket %d ..\n", k); + if (!client.Initialize()) + { + fprintf(stderr, "Error: socket %d could get initialized!\n", k); + have_err = true; + break; + } + if (!client.SetNonblocking()) + { + fprintf(stderr, "Error: socket %d could set Nonblocking!\n", k); + have_err = true; + break; + } + } + } + + for (int k = 0; !have_err && k < max_clients; ++k) + { + CActiveSocket &client = clients[k]; + printf("\nclient %d ..\n", k); + if (!init_sockets_at_startup) + { + if (!client.Initialize()) + { + fprintf(stderr, "Error: socket %d could get initialized!\n", k); + break; + } + if (!client.SetNonblocking()) + { + fprintf(stderr, "Error: socket %d could set Nonblocking!\n", k); + break; + } + } + have_err = !connect_new_client(client, k, thData); + } + + thData.terminate = true; + printf("trigger server to terminate ..\n"); + + printf("cleanup clients connections ..\n"); + for (int k=0; k < MAX_CLIENTS; ++k) + { + CActiveSocket &client = clients[k]; + if (client.IsSocketValid()) + client.Close(); + } + delete []clients; + + server_thread.join(); +} diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index ab36819..51e3937 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -300,6 +300,7 @@ CSimpleSocket *CPassiveSocket::Accept() } else { + // fprintf(stderr, "error at accept(): got socket %d\n", socket); TranslateSocketError(); socketErrno = GetSocketError(); } diff --git a/src/SimpleSocket.cpp b/src/SimpleSocket.cpp index c74ba6e..4001d53 100644 --- a/src/SimpleSocket.cpp +++ b/src/SimpleSocket.cpp @@ -2163,6 +2163,13 @@ bool CSimpleSocket::Select(int32 nTimeoutSec, int32 nTimeoutUSec, bool bAwakeWhe int32 nNumDescriptors = -1; int32 nError = 0; + // if (m_socket >= 1024) + // { + // SetSocketError(CSimpleSocket::SocketEunknown); + // fprintf(stderr, "error: select() with socket %d >= 1024\n", m_socket); + // // return false; + // } + FD_ZERO(&m_errorFds); FD_ZERO(&m_readFds); FD_ZERO(&m_writeFds); From 0ed5dffb284a570be4125863d0ed6cdc00f4cddc Mon Sep 17 00:00:00 2001 From: Hayati Ayguen Date: Tue, 15 Aug 2023 12:59:50 +0200 Subject: [PATCH 17/19] minor, typos, .. Signed-off-by: Hayati Ayguen --- src/ActiveSocket.h | 1 - src/PassiveSocket.cpp | 4 +--- src/SimpleSocket.h | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ActiveSocket.h b/src/ActiveSocket.h index 8db9c28..c0ed796 100644 --- a/src/ActiveSocket.h +++ b/src/ActiveSocket.h @@ -53,4 +53,3 @@ typedef CSimpleSocket CActiveSocket; #endif /* __ACTIVESOCKET_H__ */ - diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index 51e3937..b28d7c6 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -168,9 +168,7 @@ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBa ULONG inAddr; #else in_addr_t inAddr; - - int32 nReuse; - nReuse = IPTOS_LOWDELAY; + int32 nReuse = IPTOS_LOWDELAY; //-------------------------------------------------------------------------- // Set the following socket option SO_REUSEADDR. This will allow the file diff --git a/src/SimpleSocket.h b/src/SimpleSocket.h index 82d2107..423a57d 100644 --- a/src/SimpleSocket.h +++ b/src/SimpleSocket.h @@ -521,10 +521,10 @@ class CLSOCKET_API CSimpleSocket { return SetSendTimeout( nSendTimeoutMillis / 1000 , 1000 * (nSendTimeoutMillis % 1000) ); }; - /// Returns the last error that occured for the instace of the CSimpleSocket + /// Returns the last error that occurred for the instance of the CSimpleSocket /// instance. This method should be called immediately to retrieve the /// error code for the failing mehtod call. - /// @return last error that occured. + /// @return last error that occurred. CSocketError GetSocketError(void) { return m_socketErrno; }; From cf3def459634b981c012c4583b54b0084cdb618a Mon Sep 17 00:00:00 2001 From: Hayati Ayguen Date: Thu, 17 Aug 2023 16:31:55 +0200 Subject: [PATCH 18/19] update/enhance/fix examples Signed-off-by: Hayati Ayguen --- examples/EchoServer.cpp | 6 ++++ examples/TxToUdpServer.cpp | 59 +++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/examples/EchoServer.cpp b/examples/EchoServer.cpp index b99dae9..7d39486 100644 --- a/examples/EchoServer.cpp +++ b/examples/EchoServer.cpp @@ -42,6 +42,12 @@ int main(int argc, char **argv) if (pClient->Receive(MAX_PACKET)) { + fprintf(stderr, "\n%s. Local: %s:%u Peer: %s:%u\n" + , ( pClient->IsServerSide() ? "Local is Server" : "Local is Client" ) + , pClient->GetLocalAddr(), (unsigned)pClient->GetLocalPort() + , pClient->GetPeerAddr(), (unsigned)pClient->GetPeerPort() + ); + //------------------------------------------------------------------ // Send response to client and close connection to the client. //------------------------------------------------------------------ diff --git a/examples/TxToUdpServer.cpp b/examples/TxToUdpServer.cpp index e14231c..f10c019 100644 --- a/examples/TxToUdpServer.cpp +++ b/examples/TxToUdpServer.cpp @@ -1,5 +1,5 @@ -#include "SimpleSocket.h" // Include header for active socket object definition +#include "SimpleSocket.h" #include @@ -7,11 +7,35 @@ int main(int argc, char **argv) { - CSimpleSocket socket( CSimpleSocket::SocketTypeUdp ); + const char *pcHostname = 0; + const char *pcSendText = 0; + const char *pcBindAddr = 0; + const uint16 portno = 6789; + int bindPort = -1; + int mcastTTL = -1; + int argidx = 1; + + if ( argidx < argc ) + pcHostname = argv[argidx++]; + + if ( argidx < argc ) + pcSendText = argv[argidx++]; + + if ( argidx + 1 < argc && !strcmp(argv[argidx], "-m") ) + { + argidx++; + mcastTTL = atoi(argv[argidx++]); + } - if ( argc < 3 ) + if ( argidx + 1 < argc ) { - fprintf(stderr, "usage: %s [-m [] | ]\n", argv[0] ); + pcBindAddr = argv[argidx++]; + bindPort = atoi(argv[argidx++]); + } + + if ( !pcHostname || !pcSendText ) + { + fprintf(stderr, "usage: %s [-m ] [ ]\n", argv[0] ); fprintf(stderr, " -m : activate multicast on socket\n"); return 10; } @@ -19,36 +43,39 @@ int main(int argc, char **argv) //-------------------------------------------------------------------------- // Initialize our socket object //-------------------------------------------------------------------------- + CSimpleSocket socket( CSimpleSocket::SocketTypeUdp ); socket.Initialize(); - if ( 4 < argc ) + if ( pcBindAddr && bindPort >= 0 ) { - unsigned bindPort = atoi(argv[4]); - bool ret = socket.Bind( argv[3], uint16(bindPort) ); - fprintf(stderr, "bind to %s:%u %s\n", argv[3], bindPort, (ret ? "successful":"failed") ); + bool ret = socket.Bind( pcBindAddr, uint16(bindPort) ); + fprintf(stderr, "bind to %s:%u %s\n", pcBindAddr, bindPort, (ret ? "successful":"failed") ); } + else + fprintf(stderr, "binding not parametrized\n"); - bool bConnOK = socket.Open( argv[1], 6789 ); + bool bConnOK = socket.Open( pcHostname, portno ); if ( !bConnOK ) { - fprintf(stderr, "error connecting to '%s'!\n", argv[1] ); + fprintf(stderr, "error connecting to '%s'!\n", pcHostname ); return 10; } - if ( 3 < argc && !strcmp(argv[3], "-m") ) + if ( mcastTTL >= 0 && mcastTTL < 256 ) { - uint8 multicastTTL = ( 4 < argc ) ? atoi(argv[4]) : 1; - bool ret = socket.SetMulticast(true, 3); - fprintf(stderr, "Setting Multicast with TTL 3 %s\n", ret ? "was successful" : "failed"); + bool ret = socket.SetMulticast(true, uint8(mcastTTL)); + fprintf(stderr, "Setting Multicast with TTL %d %s\n", mcastTTL, ret ? "was successful" : "failed"); } + else + fprintf(stderr, "multicast not parametrized\n"); fprintf(stderr, "\nLocal is %s. Local: %s:%u " , ( socket.IsServerSide() ? "Server" : "Client" ) , socket.GetLocalAddr(), (unsigned)socket.GetLocalPort()); fprintf(stderr, "Peer: %s:%u\n", socket.GetPeerAddr(), (unsigned)socket.GetPeerPort()); - size_t sendSize = strlen( argv[2] ); - socket.Send( argv[2], (int32)sendSize ); + size_t sendSize = strlen( pcSendText ); + socket.Send( pcSendText, (int32)sendSize ); return 1; } From d7af35c3833e7d89a4d03613d793b8eca8b082e7 Mon Sep 17 00:00:00 2001 From: Hayati Ayguen Date: Thu, 12 Sep 2024 15:22:51 +0200 Subject: [PATCH 19/19] CPassiveSocket::Listen() for nPort == 0 --- src/PassiveSocket.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PassiveSocket.cpp b/src/PassiveSocket.cpp index b28d7c6..959ca93 100644 --- a/src/PassiveSocket.cpp +++ b/src/PassiveSocket.cpp @@ -236,6 +236,13 @@ bool CPassiveSocket::Listen(const char *pAddr, uint16 nPort, int32 nConnectionBa Close(); SetSocketError(err); } + else if (nPort == 0) + { + // for later GetLocalPort() - after system choosed a free port + socklen_t nSockLen = sizeof(struct sockaddr); + memset(&m_stServerSockaddr, 0, nSockLen); + getsockname(m_socket, (struct sockaddr *)&m_stServerSockaddr, &nSockLen); + } return bRetVal; }