From 25ef34398d6dc8d4d49eb0990e12e805bb3d23ff Mon Sep 17 00:00:00 2001 From: cflakes Date: Tue, 12 Jan 2010 00:28:24 +0000 Subject: [PATCH] Update to latest Csocket. A Thank You goes out to DGandalf for noticing a bug in Csocket's c-ares code and another one of course to Imaginos for promptly looking into and fixing this. The issue was that a timeout was being applied when c-ares really takes care of timeouts. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1707 726aef4b-f618-498e-8847-2d620e286838 --- Csocket.cpp | 89 ++++++++++++++++++++++++++++++++++------------------- Csocket.h | 76 ++++++++++++++++++++++++++++----------------- 2 files changed, 105 insertions(+), 60 deletions(-) diff --git a/Csocket.cpp b/Csocket.cpp index 93e30f26..cc901b44 100644 --- a/Csocket.cpp +++ b/Csocket.cpp @@ -28,7 +28,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * -* $Revision: 1.108 $ +* $Revision: 1.115 $ */ #include "Csocket.h" @@ -42,6 +42,7 @@ using namespace std; + #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace namespace Csocket { @@ -77,26 +78,26 @@ static const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) return( NULL ); } -static inline void set_non_blocking(int fd) +static inline void set_non_blocking(cs_sock_t fd) { u_long iOpts = 1; ioctlsocket( fd, FIONBIO, &iOpts ); } -static inline void set_blocking(int fd) +static inline void set_blocking(cs_sock_t fd) { u_long iOpts = 0; ioctlsocket( fd, FIONBIO, &iOpts ); } -static inline void set_close_on_exec(int fd) +static inline void set_close_on_exec(cs_sock_t fd) { // TODO add this for windows // see http://gcc.gnu.org/ml/java-patches/2002-q1/msg00696.html // for infos on how to do this } #else -static inline void set_non_blocking(int fd) +static inline void set_non_blocking(cs_sock_t fd) { int fdflags = fcntl(fd, F_GETFL, 0); if ( fdflags < 0 ) @@ -104,7 +105,7 @@ static inline void set_non_blocking(int fd) fcntl( fd, F_SETFL, fdflags|O_NONBLOCK ); } -static inline void set_blocking(int fd) +static inline void set_blocking(cs_sock_t fd) { int fdflags = fcntl(fd, F_GETFL, 0); if ( fdflags < 0 ) @@ -113,7 +114,7 @@ static inline void set_blocking(int fd) fcntl( fd, F_SETFL, fdflags ); } -static inline void set_close_on_exec(int fd) +static inline void set_close_on_exec(cs_sock_t fd) { int fdflags = fcntl(fd, F_GETFD, 0); if ( fdflags < 0 ) @@ -592,8 +593,8 @@ Csock::~Csock() } else if( m_iReadSock >= 0 ) CS_CLOSE( m_iReadSock ); - m_iReadSock = -1; - m_iWriteSock = -1; + m_iReadSock = CS_INVALID_SOCK; + m_iWriteSock = CS_INVALID_SOCK; // delete any left over crons for( vector::size_type i = 0; i < m_vcCrons.size(); i++ ) @@ -602,7 +603,7 @@ Csock::~Csock() void Csock::Dereference() { - m_iWriteSock = m_iReadSock = -1; + m_iWriteSock = m_iReadSock = CS_INVALID_SOCK; #ifdef HAVE_LIBSSL m_ssl = NULL; @@ -617,7 +618,7 @@ void Csock::Copy( const Csock & cCopy ) { m_iTcount = cCopy.m_iTcount; m_iLastCheckTimeoutTime = cCopy.m_iLastCheckTimeoutTime; - m_iport = cCopy.m_iport; + m_uPort = cCopy.m_uPort; m_iRemotePort = cCopy.m_iRemotePort; m_iLocalPort = cCopy.m_iLocalPort; m_iReadSock = cCopy.m_iReadSock; @@ -916,9 +917,9 @@ bool Csock::Listen( u_short iPort, int iMaxConns, const CS_STRING & sBindHost, u return( false ); } - m_iReadSock = m_iWriteSock = SOCKET( true ); + m_iReadSock = m_iWriteSock = CreateSocket( true ); - if ( m_iReadSock == -1 ) + if ( m_iReadSock == CS_INVALID_SOCK ) return( false ); m_address.SinFamily(); @@ -1041,6 +1042,15 @@ bool Csock::SSLClientSetup() FREE_SSL(); FREE_CTX(); +#ifdef _WIN64 + if( m_iReadSock != (int)m_iReadSock || m_iWriteSock != (int)m_iWriteSock ) + { + // sanity check the FD to be sure its compatible with openssl + CS_DEBUG( "ERROR: sockfd larger than OpenSSL can handle" ); + return( false ); + } +#endif /* _WIN32 */ + switch( m_iMethod ) { case SSL2: @@ -1106,8 +1116,8 @@ bool Csock::SSLClientSetup() if ( !m_ssl ) return( false ); - SSL_set_rfd( m_ssl, m_iReadSock ); - SSL_set_wfd( m_ssl, m_iWriteSock ); + SSL_set_rfd( m_ssl, (int)m_iReadSock ); + SSL_set_wfd( m_ssl, (int)m_iWriteSock ); SSL_set_verify( m_ssl, SSL_VERIFY_PEER, ( m_pCerVerifyCB ? m_pCerVerifyCB : CertVerifyCB ) ); SSL_set_ex_data( m_ssl, GetCsockClassIdx(), this ); @@ -1126,6 +1136,16 @@ bool Csock::SSLServerSetup() FREE_SSL(); FREE_CTX(); +#ifdef _WIN64 + if( m_iReadSock != (int)m_iReadSock || m_iWriteSock != (int)m_iWriteSock ) + { + // sanity check the FD to be sure its compatible with openssl + CS_DEBUG( "ERROR: sockfd larger than OpenSSL can handle" ); + return( false ); + } +#endif /* _WIN32 */ + + switch( m_iMethod ) { case SSL2: @@ -1207,8 +1227,8 @@ bool Csock::SSLServerSetup() return( false ); // Call for client Verification - SSL_set_rfd( m_ssl, m_iReadSock ); - SSL_set_wfd( m_ssl, m_iWriteSock ); + SSL_set_rfd( m_ssl, (int)m_iReadSock ); + SSL_set_wfd( m_ssl, (int)m_iWriteSock ); SSL_set_accept_state( m_ssl ); if ( m_iRequireClientCertFlags ) { @@ -1226,7 +1246,7 @@ bool Csock::SSLServerSetup() bool Csock::ConnectSSL( const CS_STRING & sBindhost ) { #ifdef HAVE_LIBSSL - if ( m_iReadSock == -1 ) + if ( m_iReadSock == CS_INVALID_SOCK ) if ( !Connect( sBindhost ) ) return( false ); if ( !m_ssl ) @@ -1580,12 +1600,12 @@ CS_STRING Csock::GetRemoteIP() bool Csock::IsConnected() { return( m_bIsConnected ); } void Csock::SetIsConnected( bool b ) { m_bIsConnected = b; } -int & Csock::GetRSock() { return( m_iReadSock ); } -void Csock::SetRSock( int iSock ) { m_iReadSock = iSock; } -int & Csock::GetWSock() { return( m_iWriteSock ); } -void Csock::SetWSock( int iSock ) { m_iWriteSock = iSock; } -void Csock::SetSock( int iSock ) { m_iWriteSock = iSock; m_iReadSock = iSock; } -int & Csock::GetSock() { return( m_iReadSock ); } +cs_sock_t & Csock::GetRSock() { return( m_iReadSock ); } +void Csock::SetRSock( cs_sock_t iSock ) { m_iReadSock = iSock; } +cs_sock_t & Csock::GetWSock() { return( m_iWriteSock ); } +void Csock::SetWSock( cs_sock_t iSock ) { m_iWriteSock = iSock; } +void Csock::SetSock( cs_sock_t iSock ) { m_iWriteSock = iSock; m_iReadSock = iSock; } +cs_sock_t & Csock::GetSock() { return( m_iReadSock ); } void Csock::ResetTimer() { m_iLastCheckTimeoutTime = 0; m_iTcount = 0; } void Csock::PauseRead() { m_bPauseRead = true; } bool Csock::IsReadPaused() { return( m_bPauseRead ); } @@ -1779,8 +1799,8 @@ u_short Csock::GetLocalPort() return( m_iLocalPort ); } -u_short Csock::GetPort() { return( m_iport ); } -void Csock::SetPort( u_short iPort ) { m_iport = iPort; } +u_short Csock::GetPort() { return( m_uPort ); } +void Csock::SetPort( u_short iPort ) { m_uPort = iPort; } void Csock::Close( ECloseType eCloseType ) { m_eCloseType = eCloseType; @@ -2059,6 +2079,7 @@ int Csock::GetPending() int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) { +#ifndef _WIN32 #ifdef HAVE_IPV6 if( csSockAddr.GetAFRequire() != AF_INET && inet_pton( AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6() ) > 0 ) { @@ -2073,6 +2094,7 @@ int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) #endif /* HAVE_IPV6 */ return( 0 ); } +#endif /* _WIN32 */ #ifdef HAVE_C_ARES if( GetType() != LISTENER ) @@ -2088,6 +2110,7 @@ int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) int iFamily = AF_INET; #ifdef HAVE_IPV6 + // as of ares 1.6.0 if it fails on af_inet6, it falls back to af_inet, this code was here in the previous Csocket version, just adding the comment as a reminder iFamily = csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ? AF_INET6 : csSockAddr.GetAFRequire(); #endif /* HAVE_IPV6 */ ares_gethostbyname( m_pARESChannel, sHostname.c_str(), iFamily, AresHostCallback, this ); @@ -2153,12 +2176,14 @@ int Csock::DNSLookup( EDNSLType eDNSLType ) } else if ( iRet == EAGAIN ) { +#ifndef HAVE_C_ARES m_iDNSTryCount++; if ( m_iDNSTryCount > 20 ) { m_iDNSTryCount = 0; return( ETIMEDOUT ); } +#endif /* HAVE_C_ARES */ return( EAGAIN ); } m_iDNSTryCount = 0; @@ -2218,12 +2243,12 @@ void Csock::FREE_CTX() #endif /* HAVE_LIBSSL */ -int Csock::SOCKET( bool bListen ) +cs_sock_t Csock::CreateSocket( bool bListen ) { #ifdef HAVE_IPV6 - int iRet = socket( ( GetIPv6() ? PF_INET6 : PF_INET ), SOCK_STREAM, IPPROTO_TCP ); + cs_sock_t iRet = socket( ( GetIPv6() ? PF_INET6 : PF_INET ), SOCK_STREAM, IPPROTO_TCP ); #else - int iRet = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); + cs_sock_t iRet = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); #endif /* HAVE_IPV6 */ if ( iRet >= 0 ) { @@ -2250,12 +2275,12 @@ void Csock::Init( const CS_STRING & sHostname, u_short uPort, int itimeout ) m_iRequireClientCertFlags = 0; #endif /* HAVE_LIBSSL */ m_iTcount = 0; - m_iReadSock = -1; - m_iWriteSock = -1; + m_iReadSock = CS_INVALID_SOCK; + m_iWriteSock = CS_INVALID_SOCK; m_itimeout = itimeout; m_bssl = false; m_bIsConnected = false; - m_iport = uPort; + m_uPort = uPort; m_shostname = sHostname; m_sbuffer.clear(); m_eCloseType = CLT_DONT; diff --git a/Csocket.h b/Csocket.h index 5e6a9f83..dcde6756 100644 --- a/Csocket.h +++ b/Csocket.h @@ -28,7 +28,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * -* $Revision: 1.213 $ +* $Revision: 1.216 $ */ // note to compile with win32 need to link to winsock2, using gcc its -lws2_32 @@ -83,6 +83,7 @@ #endif /* __sun */ #include +#include #include #include #include @@ -115,6 +116,14 @@ #endif /* __DEBUG__ */ #endif /* PERROR */ +#ifdef _WIN32 +typedef SOCKET cs_sock_t; +#define CS_INVALID_SOCK INVALID_SOCKET +#else +typedef int cs_sock_t; +#define CS_INVALID_SOCK -1 +#endif /* _WIN32 */ + #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace namespace Csocket { @@ -412,10 +421,10 @@ public: * Advanced constructor, for creating a simple connection * * @param sHostname the hostname your are connecting to - * @param iport the port you are connectint to + * @param uPort the port you are connectint to * @param itimeout how long to wait before ditching the connection, default is 60 seconds */ - Csock( const CS_STRING & sHostname, u_short iport, int itimeout = 60 ); + Csock( const CS_STRING & sHostname, u_short uPort, int itimeout = 60 ); //! override this for accept sockets virtual Csock *GetSockObj( const CS_STRING & sHostname, u_short iPort ); @@ -588,13 +597,13 @@ public: virtual void SetIsConnected( bool b ); //! returns a reference to the sock - int & GetRSock(); - void SetRSock( int iSock ); - int & GetWSock(); - void SetWSock( int iSock ); + cs_sock_t & GetRSock(); + void SetRSock( cs_sock_t iSock ); + cs_sock_t & GetWSock(); + void SetWSock( cs_sock_t iSock ); - void SetSock( int iSock ); - int & GetSock(); + void SetSock( cs_sock_t iSock ); + cs_sock_t & GetSock(); //! resets the time counter, this is virtual in the event you need an event on the timer being Reset virtual void ResetTimer(); @@ -909,15 +918,15 @@ public: //! grabs fd's for the sockets bool CreateSocksFD() { - if( m_iReadSock != -1 ) + if( m_iReadSock != CS_INVALID_SOCK ) return( true ); - m_iReadSock = m_iWriteSock = SOCKET(); - if ( m_iReadSock == -1 ) + m_iReadSock = m_iWriteSock = CreateSocket(); + if ( m_iReadSock == CS_INVALID_SOCK ) return( false ); m_address.SinFamily(); - m_address.SinPort( m_iport ); + m_address.SinPort( m_uPort ); return( true ); } @@ -981,8 +990,9 @@ private: Csock( const Csock & cCopy ) {} // NOTE! if you add any new members, be sure to add them to Copy() - u_short m_iport, m_iRemotePort, m_iLocalPort; - int m_iReadSock, m_iWriteSock, m_itimeout, m_iConnType, m_iMethod, m_iTcount; + u_short m_uPort, m_iRemotePort, m_iLocalPort; + cs_sock_t m_iReadSock, m_iWriteSock; + int m_itimeout, m_iConnType, m_iMethod, m_iTcount; bool m_bssl, m_bIsConnected, m_bBLOCK, m_bFullsslAccept; bool m_bsslEstablished, m_bEnableReadLine, m_bPauseRead; CS_STRING m_shostname, m_sbuffer, m_sSockName, m_sPemFile, m_sCipherType, m_sParentName; @@ -1012,8 +1022,8 @@ private: std::vector m_vcCrons; //! Create the socket - int SOCKET( bool bListen = false ); - void Init( const CS_STRING & sHostname, u_short iport, int itimeout = 60 ); + cs_sock_t CreateSocket( bool bListen = false ); + void Init( const CS_STRING & sHostname, u_short uPort, int itimeout = 60 ); // Connection State Info @@ -1631,7 +1641,7 @@ public: } //! returns a pointer to the FIRST sock found by filedescriptor or NULL on no match - virtual T * FindSockByFD( int iFD ) + virtual T * FindSockByFD( cs_sock_t iFD ) { for( unsigned int i = 0; i < this->size(); i++ ) if ( ( (*this)[i]->GetRSock() == iFD ) || ( (*this)[i]->GetWSock() == iFD ) ) @@ -1840,7 +1850,7 @@ protected: { return( select( nfds, readfds, writefds, exceptfds, timeout ) ); } -protected: +private: /** * fills a map of socks to a message for check * map is empty if none are ready, check GetErrno() for the error, if not SUCCESS Select() failed @@ -1893,15 +1903,15 @@ protected: bHasAvailSocks = true; - int & iRSock = pcSock->GetRSock(); - int & iWSock = pcSock->GetWSock(); + cs_sock_t & iRSock = pcSock->GetRSock(); + cs_sock_t & iWSock = pcSock->GetWSock(); bool bIsReadPaused = pcSock->IsReadPaused(); if ( bIsReadPaused ) { pcSock->ReadPaused(); bIsReadPaused = pcSock->IsReadPaused(); // re-read it again, incase it changed status) } - if ( ( iRSock < 0 ) || ( iWSock < 0 ) ) + if ( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) { SelectSock( mpeSocks, SUCCESS, pcSock ); continue; // invalid sock fd @@ -1996,7 +2006,8 @@ protected: m_errno = SUCCESS; return; - } else if ( iSel == -1 ) + } + else if ( iSel == -1 ) { if ( mpeSocks.empty() ) m_errno = SELECT_ERROR; @@ -2004,7 +2015,8 @@ protected: m_errno = SUCCESS; return; - } else + } + else { m_errno = SUCCESS; } @@ -2017,17 +2029,25 @@ protected: #ifdef HAVE_C_ARES ares_channel pChannel = pcSock->GetAresChannel(); if( pChannel ) - ares_process( pChannel, &rfds, &wfds ); + { + int iAresFD; + ares_getsock( pChannel, &iAresFD, 1 ); + // only process the channels that are actually set in the read/write set + // this should effectively be the same as finding the max timeout amongst ares fd's + // as this fd is either ready or its not + if( TFD_ISSET( iAresFD, &rfds ) || TFD_ISSET( iAresFD, &wfds ) ) + ares_process( pChannel, &rfds, &wfds ); + } #endif /* HAVE_C_ARES */ if ( pcSock->GetConState() != T::CST_OK ) continue; - int & iRSock = pcSock->GetRSock(); - int & iWSock = pcSock->GetWSock(); + cs_sock_t & iRSock = pcSock->GetRSock(); + cs_sock_t & iWSock = pcSock->GetWSock(); EMessages iErrno = SUCCESS; - if ( ( iRSock < 0 ) || ( iWSock < 0 ) ) + if ( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) { // trigger a success so it goes through the normal motions // and an error is produced