From 6dbb196ed7260a8569b2a635e00eff7ac6537668 Mon Sep 17 00:00:00 2001 From: prozacx Date: Wed, 1 Jun 2005 21:01:26 +0000 Subject: [PATCH] Changed port from int to ushort git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@376 726aef4b-f618-498e-8847-2d620e286838 --- Csocket.cpp | 350 ++++++++++++++++++++++++++++++++++++++++---------- Csocket.h | 319 ++++++++++++++++++++++++++++++++++++++------- DCCBounce.cpp | 6 +- DCCBounce.h | 4 +- DCCSock.cpp | 2 +- DCCSock.h | 4 +- User.cpp | 6 +- UserSock.cpp | 8 +- UserSock.h | 6 +- znc.h | 2 +- 10 files changed, 575 insertions(+), 132 deletions(-) diff --git a/Csocket.cpp b/Csocket.cpp index 77077148..7f0d315f 100644 --- a/Csocket.cpp +++ b/Csocket.cpp @@ -40,7 +40,121 @@ namespace Csocket { #endif /* _NO_CSOCKET_NS */ +#ifdef ___DO_THREADS +CSMutex::CSMutex() +{ + pthread_mutexattr_init( &m_mattrib ); + if ( pthread_mutexattr_settype( &m_mattrib, PTHREAD_MUTEX_FAST_NP ) != 0 ) + throw CS_STRING( "ERROR: pthread_mutexattr_settype failed!" ); + + if ( pthread_mutex_init( &m_mutex, &m_mattrib ) != 0 ) + throw CS_STRING( "ERROR: pthread_mutex_init failed!" ); +} +CSMutex::~CSMutex() +{ + pthread_mutexattr_destroy( &m_mattrib ); + pthread_mutex_destroy( &m_mutex ); +} + +bool CSThread::start() +{ + // mark the job as running + lock(); + m_eStatus = RUNNING; + unlock(); + + pthread_attr_t attr; + if ( pthread_attr_init( &attr ) != 0 ) + { + WARN( "pthread_attr_init failed" ); + lock(); + m_eStatus = FINISHED; + unlock(); + return( false ); + } + + if ( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ) != 0 ) + { + WARN( "pthread_attr_setdetachstate failed" ); + lock(); + m_eStatus = FINISHED; + unlock(); + return( false ); + } + + int iRet = pthread_create( &m_ppth, &attr, start_thread, this ); + if ( iRet != 0 ) + { + WARN( "pthread_create failed " ); + lock(); + m_eStatus = FINISHED; + unlock(); + return( false ); + } + + return( true ); +} + +void CSThread::wait() +{ + while( true ) + { + lock(); + EStatus e = Status(); + unlock(); + if ( e == FINISHED ) + break; + usleep( 100 ); + } +} + +void *CSThread::start_thread( void *args ) +{ + CSThread *curThread = (CSThread *)args; + curThread->run(); + curThread->lock(); + curThread->SetStatus( CSThread::FINISHED ); + curThread->unlock(); + pthread_exit( NULL ); +} + +void CDNSResolver::Lookup( const CS_STRING & sHostname ) +{ + m_bSuccess = false; + m_sHostname = sHostname; + memset( (struct in_addr *)&m_inAddr, '\0', sizeof( m_inAddr ) ); + start(); +} + +void CDNSResolver::run() +{ + if ( GetHostByName( m_sHostname, &m_inAddr ) != 0 ) + m_bSuccess = false; + else + { + m_bSuccess = true; + } +} + +bool CDNSResolver::IsCompleted() +{ + lock(); + EStatus e = Status(); + unlock(); + if ( e == FINISHED ) + return( true ); + return( false ); +} + +CS_STRING CDNSResolver::CreateIP( const struct in_addr *pAddr ) +{ + struct in_addr inAddr; + memcpy( (struct in_addr *)&inAddr, pAddr, sizeof( inAddr ) ); + return( inet_ntoa( inAddr ) ); +} + +#endif /* ___DO_THREADS */ #ifdef HAVE_LIBSSL bool InitSSL( ECompType eCompressionType ) { @@ -128,47 +242,43 @@ unsigned long long millitime() return( iTime ); } -bool GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr ) +int GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr, u_int iNumRetries ) { - bool bRet = false; + int iReturn = HOST_NOT_FOUND; struct hostent *hent = NULL; #ifdef __linux__ char hbuff[2048]; struct hostent hentbuff; int err; - for( u_int a = 0; a < 20; a++ ) + for( u_int a = 0; a < iNumRetries; a++ ) { memset( (char *)hbuff, '\0', 2048 ); - int iRet = gethostbyname_r( sHostName.c_str(), &hentbuff, hbuff, 2048, &hent, &err ); + iReturn = gethostbyname_r( sHostName.c_str(), &hentbuff, hbuff, 2048, &hent, &err ); - if ( iRet == 0 ) - { - bRet = true; + if ( iReturn == 0 ) break; - } - if ( iRet != TRY_AGAIN ) + if ( iReturn != TRY_AGAIN ) break; PERROR( "gethostbyname_r" ); } - - if ( !hent ) - bRet = false; + if ( ( !hent ) && ( iReturn == 0 ) ) + iReturn = HOST_NOT_FOUND; #else hent = gethostbyname( sHostName.c_str() ); PERROR( "gethostbyname" ); if ( hent ) - bRet = true; + iReturn = 0; #endif /* __linux__ */ - if ( bRet ) - memcpy( &paddr->s_addr, hent->h_addr_list[0], 4 ); + if ( iReturn == 0 ) + memcpy( &paddr->s_addr, hent->h_addr_list[0], sizeof( paddr->s_addr ) ); - return( bRet ); + return( iReturn ); } #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace @@ -255,13 +365,13 @@ Csock::Csock( int itimeout ) Init( "", 0, itimeout ); } -Csock::Csock( const CS_STRING & sHostname, int iport, int itimeout ) +Csock::Csock( const CS_STRING & sHostname, u_short iport, int itimeout ) { Init( sHostname, iport, itimeout ); } // override this for accept sockets -Csock *Csock::GetSockObj( const CS_STRING & sHostname, int iPort ) +Csock *Csock::GetSockObj( const CS_STRING & sHostname, u_short iPort ) { return( NULL ); } @@ -274,6 +384,14 @@ Csock *Csock::GetSockObj( const CS_STRING & sHostname, int iPort ) Csock::~Csock() { +#ifdef ___DO_THREADS + m_cResolver.lock(); + CDNSResolver::EStatus eStatus = m_cResolver.Status(); + m_cResolver.unlock(); + if ( eStatus == CDNSResolver::RUNNING ) + m_cResolver.cancel(); +#endif /* __DO_THREADS_ */ + if ( m_iReadSock != m_iWriteSock ) { CS_CLOSE( m_iReadSock ); @@ -356,51 +474,47 @@ Csock & Csock::operator<<( double i ) return( *this ); } -bool Csock::Connect( const CS_STRING & sBindHost ) +bool Csock::Connect( const CS_STRING & sBindHost, bool bSkipSetup ) { - // create the socket - m_iReadSock = m_iWriteSock = SOCKET(); - - if ( m_iReadSock == -1 ) - return( false ); - - m_address.sin_family = PF_INET; - m_address.sin_port = htons( m_iport ); - - if ( !GetHostByName( m_shostname, &(m_address.sin_addr) ) ) - return( false ); - - // bind to a hostname if requested - if ( !sBindHost.empty() ) + if ( !bSkipSetup ) { - struct sockaddr_in vh; - - vh.sin_family = PF_INET; - vh.sin_port = htons( 0 ); - - if ( !GetHostByName( sBindHost, &(vh.sin_addr) ) ) + if ( !CreateSocksFD() ) return( false ); - // try to bind 3 times, otherwise exit failure - bool bBound = false; - for( int a = 0; a < 3; a++ ) + int iDNSRet = ETIMEDOUT; + while( true ) { - if ( bind( m_iReadSock, (struct sockaddr *) &vh, sizeof( vh ) ) == 0 ) - { - bBound = true; - break; - } -#ifdef _WIN32 - Sleep( 5000 ); -#else - usleep( 5000 ); // quick pause, common lets BIND!)(!*! -#endif /* _WIN32 */ + iDNSRet = DNSLookup( DNS_VHOST ); + if ( iDNSRet == EAGAIN ) + continue; + + break; } - - if ( !bBound ) - { - CS_DEBUG( "Failure to bind to " << sBindHost ); + if ( iDNSRet != 0 ) return( false ); + + // bind to a hostname if requested + m_sBindHost = sBindHost; + if ( !sBindHost.empty() ) + { + // try to bind 3 times, otherwise exit failure + bool bBound = false; + for( int a = 0; a < 3 && !bBound; a++ ) + { + if ( SetupVHost() ) + bBound = true; +#ifdef _WIN32 + Sleep( 5000 ); +#else + usleep( 5000 ); // quick pause, common lets BIND!)(!*! +#endif /* _WIN32 */ + } + + if ( !bBound ) + { + CS_DEBUG( "Failure to bind to " << sBindHost ); + return( false ); + } } } @@ -441,6 +555,9 @@ bool Csock::Connect( const CS_STRING & sBindHost ) #endif /* _WIN32 */ } + if ( m_eConState != CST_OK ) + m_eConState = CST_OK; + return( true ); } @@ -504,7 +621,7 @@ int Csock::ReadSelect() return( SEL_OK ); } -bool Csock::Listen( int iPort, int iMaxConns, const CS_STRING & sBindHost, u_int iTimeout ) +bool Csock::Listen( u_short iPort, int iMaxConns, const CS_STRING & sBindHost, u_int iTimeout ) { m_iReadSock = m_iWriteSock = SOCKET( true ); m_iConnType = LISTENER; @@ -513,17 +630,18 @@ bool Csock::Listen( int iPort, int iMaxConns, const CS_STRING & sBindHost, u_int if ( m_iReadSock == -1 ) return( false ); + m_sBindHost = sBindHost; + m_address.sin_family = PF_INET; if ( sBindHost.empty() ) m_address.sin_addr.s_addr = htonl( INADDR_ANY ); else { - if ( !GetHostByName( sBindHost, &(m_address.sin_addr) ) ) + if ( GetHostByName( sBindHost, &(m_address.sin_addr) ) != 0 ) return( false ); } m_address.sin_port = htons( iPort ); memset( &(m_address.sin_zero), '\0', sizeof( m_address.sin_zero ) ); -// TODO bzero(&(m_address.sin_zero), 8); if ( bind( m_iReadSock, (struct sockaddr *) &m_address, sizeof( m_address ) ) == -1 ) return( false ); @@ -546,7 +664,7 @@ bool Csock::Listen( int iPort, int iMaxConns, const CS_STRING & sBindHost, u_int return( true ); } -int Csock::Accept( CS_STRING & sHost, int & iRPort ) +int Csock::Accept( CS_STRING & sHost, u_short & iRPort ) { struct sockaddr_in client; socklen_t clen = sizeof(struct sockaddr); @@ -846,6 +964,9 @@ bool Csock::Write( const char *data, int len ) if ( m_sSend.empty() ) return( true ); + if ( m_eConState != CST_OK ) + return( true ); + if ( m_bBLOCK ) { if ( WriteSelect() != SEL_OK ) @@ -1198,7 +1319,7 @@ double Csock::GetAvgWrite( unsigned long long iSample ) return( ( (double)m_iBytesWritten / ( (double)iDifference / (double)iSample ) ) ); } -int Csock::GetRemotePort() +u_short Csock::GetRemotePort() { if ( m_iRemotePort > 0 ) return( m_iRemotePort ); @@ -1216,7 +1337,7 @@ int Csock::GetRemotePort() return( m_iRemotePort ); } -int Csock::GetLocalPort() +u_short Csock::GetLocalPort() { if ( m_iLocalPort > 0 ) return( m_iLocalPort ); @@ -1234,8 +1355,8 @@ int Csock::GetLocalPort() return( m_iLocalPort ); } -int Csock::GetPort() { return( m_iport ); } -void Csock::SetPort( int iPort ) { m_iport = iPort; } +u_short Csock::GetPort() { return( m_iport ); } +void Csock::SetPort( u_short iPort ) { m_iport = iPort; } void Csock::Close() { m_bClosed = true; } bool Csock::isClosed() { return( m_bClosed ); } void Csock::BlockIO( bool bBLOCK ) { m_bBLOCK = bBLOCK; } @@ -1516,6 +1637,102 @@ int Csock::GetPending() #endif /* HAVE_LIBSSL */ } +int Csock::DNSLookup( EDNSLType eDNSLType ) +{ + if ( eDNSLType == DNS_VHOST ) + { + if ( m_sBindHost.empty() ) + { + if ( m_eConState != CST_OK ) + m_eConState = CST_BINDVHOST; + return( 0 ); + } + + m_bindhost.sin_family = PF_INET; + m_bindhost.sin_port = htons( 0 ); + } + +#ifdef ___DO_THREADS + if ( m_iDNSTryCount == 0 ) + { + m_cResolver.Lookup( ( eDNSLType == DNS_VHOST ) ? m_sBindHost : m_shostname ); + m_iDNSTryCount++; + } + + if ( m_cResolver.IsCompleted() ) + { + m_iDNSTryCount = 0; + if ( m_cResolver.Suceeded() ) + { + if ( eDNSLType == DNS_VHOST ) + memcpy( &(m_bindhost.sin_addr), m_cResolver.GetAddr(), sizeof( m_bindhost.sin_addr ) ); + else + memcpy( &(m_address.sin_addr), m_cResolver.GetAddr(), sizeof( m_address.sin_addr ) ); + + if ( m_eConState != CST_OK ) + m_eConState = ( ( eDNSLType == DNS_VHOST ) ? CST_BINDVHOST : CST_VHOSTDNS ); + + return( 0 ); + } + + return( ETIMEDOUT ); + } + return( EAGAIN ); + +#else + int iRet; + if ( eDNSLType == DNS_VHOST ) + iRet = GetHostByName( m_sBindHost, &(m_bindhost.sin_addr), 1 ); + else + iRet = GetHostByName( m_shostname, &(m_address.sin_addr), 1 ); + + if ( iRet == 0 ) + { + if ( m_eConState != CST_OK ) + m_eConState = ( ( eDNSLType == DNS_VHOST ) ? CST_BINDVHOST : CST_VHOSTDNS ); + m_iDNSTryCount = 0; + return( 0 ); + } + else if ( iRet == TRY_AGAIN ) + { + m_iDNSTryCount++; + if ( m_iDNSTryCount > 20 ) + { + m_iDNSTryCount = 0; + return( ETIMEDOUT ); + } + return( EAGAIN ); + } + m_iDNSTryCount = 0; + return( ETIMEDOUT ); +#endif /* ___DO_THREADS */ +} + +bool Csock::SetupVHost() +{ + if ( m_sBindHost.empty() ) + { + if ( m_eConState != CST_OK ) + m_eConState = CST_CONNECT; + + return( true ); + } + if ( bind( m_iReadSock, (struct sockaddr *) &m_bindhost, sizeof( m_bindhost ) ) == 0 ) + { + if ( m_eConState != CST_OK ) + m_eConState = CST_CONNECT; + return( true ); + } + m_iCurBindCount++; + if ( m_iCurBindCount > 3 ) + { + CS_DEBUG( "Failure to bind to " << m_sBindHost ); + return( false ); + } + + return( true ); +} + #ifdef HAVE_LIBSSL void Csock::FREE_SSL() { @@ -1555,7 +1772,7 @@ int Csock::SOCKET( bool bListen ) return( iRet ); } -void Csock::Init( const CS_STRING & sHostname, int iport, int itimeout ) +void Csock::Init( const CS_STRING & sHostname, u_short iport, int itimeout ) { #ifdef HAVE_LIBSSL m_ssl = NULL; @@ -1591,5 +1808,8 @@ void Csock::Init( const CS_STRING & sHostname, int iport, int itimeout ) m_iStartTime = millitime(); m_bPauseRead = false; m_iTimeoutType = TMO_ALL; + m_eConState = CST_OK; // default should be ok + m_iDNSTryCount = 0; + m_iCurBindCount = 0; } diff --git a/Csocket.h b/Csocket.h index 674ff3dd..254c79fa 100644 --- a/Csocket.h +++ b/Csocket.h @@ -83,7 +83,7 @@ #include #include -#include "main.h" +#include "main.h" // require this as a general rule, most projects have a defines.h or the like #ifndef CS_STRING # ifdef _HAS_CSTRING_ @@ -112,6 +112,89 @@ namespace Csocket { #endif /* _NO_CSOCKET_NS */ +int GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr, u_int iNumRetries = 20 ); + +#if defined( _REENTRANT ) && defined( _USE_THREADED_DNS ) +#define ___DO_THREADS +#include + +#ifndef PTHREAD_MUTEX_FAST_NP +#define PTHREAD_MUTEX_FAST_NP PTHREAD_MUTEX_NORMAL +#endif /* PTHREAD_MUTEX_FAST_NP */ + +class CSMutex +{ +public: + CSMutex (); + virtual ~CSMutex(); + int lock() { return( pthread_mutex_lock( &m_mutex ) ); } + int unlock() { return( pthread_mutex_unlock( &m_mutex ) ); } + int trylock() { return( pthread_mutex_trylock( &m_mutex ) ); } +private: + pthread_mutex_t m_mutex; + pthread_mutexattr_t m_mattrib; + +}; + +class CSThread +{ +public: + CSThread() { m_eStatus = WAITING; } + virtual ~CSThread() {} + + enum EStatus + { + WAITING = 1, + RUNNING = 2, + FINISHED = 3 + }; + + bool start(); + void wait(); + virtual void run() = 0; + static void *start_thread( void *args ); + EStatus Status() { return( m_eStatus ); } + void SetStatus( EStatus e ) { m_eStatus = e; } + int lock() { return( m_mutex.lock() ); } + int unlock() { return( m_mutex.unlock() ); } + int cancel() { return( pthread_cancel( m_ppth ) ); } + +private: + pthread_t m_ppth; + EStatus m_eStatus; + CSMutex m_mutex; +}; + +class CDNSResolver : public CSThread +{ +public: + CDNSResolver() : CSThread() { m_bSuccess = false; } + virtual ~CDNSResolver() {} + //! returns imediatly, from here out check if IsCompleted() returns true before looking at ANY of the data + void Lookup( const CS_STRING & sHostname ); + + virtual void run(); + + //! returns the underlying in_addr structure containing the resolved hostname + const struct in_addr * GetAddr() const { return( &m_inAddr ); } + //! true if dns entry was successfuly found + bool Suceeded() const { return( m_bSuccess ); } + + //! true if task is finished, this function is thread safe + bool IsCompleted(); + + //! note!! inet_ntoa uses an internally static buffer, its not thread safe + static CS_STRING CreateIP( const struct in_addr *pAddr ); + +private: + bool m_bSuccess; + CS_STRING m_sHostname; + struct in_addr m_inAddr; +}; + + +#endif /* ___DO_THREADS */ + const u_int CS_BLOCKSIZE = 4096; template inline void CS_Delete( T * & p ) { if( p ) { delete p; p = NULL; } } @@ -184,7 +267,7 @@ inline void TFD_CLR( u_int iSock, fd_set *set ) void __Perror( const CS_STRING & s ); unsigned long long millitime(); -bool GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr ); + /** * @class CCron @@ -264,10 +347,10 @@ public: * @param iport 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, int iport, int itimeout = 60 ); + Csock( const CS_STRING & sHostname, u_short iport, int itimeout = 60 ); // override this for accept sockets - virtual Csock *GetSockObj( const CS_STRING & sHostname, int iPort ); + virtual Csock *GetSockObj( const CS_STRING & sHostname, u_short iPort ); virtual ~Csock(); @@ -302,6 +385,16 @@ public: SSL3 = 3 }; + enum ECONState + { + CST_START = 0, + CST_DNS = CST_START, + CST_VHOSTDNS = 1, + CST_BINDVHOST = 2, + CST_CONNECT = 3, + CST_OK = 4 + }; + Csock & operator<<( const CS_STRING & s ); Csock & operator<<( std::ostream & ( *io )( std::ostream & ) ); Csock & operator<<( int i ); @@ -318,7 +411,7 @@ public: * @param sBindHost the ip you want to bind to locally * @return true on success */ - virtual bool Connect( const CS_STRING & sBindHost = "" ); + virtual bool Connect( const CS_STRING & sBindHost = "", bool bSkipSetup = false ); /** * WriteSelect on this socket @@ -338,10 +431,10 @@ public: * @param iPort the port to listen on * @param iMaxConns the maximum amount of connections to allow */ - virtual bool Listen( int iPort, int iMaxConns = SOMAXCONN, const CS_STRING & sBindHost = "", u_int iTimeout = 0 ); + virtual bool Listen( u_short iPort, int iMaxConns = SOMAXCONN, const CS_STRING & sBindHost = "", u_int iTimeout = 0 ); //! Accept an inbound connection, this is used internally - virtual int Accept( CS_STRING & sHost, int & iRPort ); + virtual int Accept( CS_STRING & sHost, u_short & iRPort ); //! Accept an inbound SSL connection, this is used internally and called after Accept virtual bool AcceptSSL(); @@ -490,14 +583,14 @@ public: double GetAvgWrite( unsigned long long iSample = 1000 ); //! Returns the remote port - int GetRemotePort(); + u_short GetRemotePort(); //! Returns the local port - int GetLocalPort(); + u_short GetLocalPort(); //! Returns the port - int GetPort(); - void SetPort( int iPort ); + u_short GetPort(); + void SetPort( u_short iPort ); //! just mark us as closed, the parent can pick it up void Close(); @@ -664,7 +757,7 @@ public: * return false and the connection will fail * default returns true */ - virtual bool ConnectionFrom( const CS_STRING & sHost, int iPort ) { return( true ); } + virtual bool ConnectionFrom( const CS_STRING & sHost, u_short iPort ) { return( true ); } /** * Override these functions for an easy interface when using the Socket Manager @@ -683,10 +776,50 @@ public: //! return the data imediatly ready for read virtual int GetPending(); + ////////////////////////// + // Connection State Stuff + //! returns the current connection state + ECONState GetConState() const { return( m_eConState ); } + //! sets the connection state to eState + void SetConState( ECONState eState ) { m_eConState = eState; } + + //! grabs fd's for the sockets + bool CreateSocksFD() + { + m_iReadSock = m_iWriteSock = SOCKET(); + if ( m_iReadSock == -1 ) + return( false ); + + m_address.sin_family = PF_INET; + m_address.sin_port = htons( m_iport ); + + return( true ); + } + + const CS_STRING & GetBindHost() const { return( m_sBindHost ); } + void SetBindHost( const CS_STRING & sBindHost ) { m_sBindHost = sBindHost; } + + enum EDNSLType + { + DNS_VHOST, + DNS_DEST + }; + + /** + * DNSLookup nonblocking dns lookup (when -pthread is set to compile + * + * @return 0 for success, EAGAIN to check back again (same arguments as before, ETIMEDOUT on failure + */ + int DNSLookup( EDNSLType eDNSLType ); + + //! this is only used on outbound connections, listeners bind in a different spot + bool SetupVHost(); + ////////////////////////////////////////////////// private: - int m_iReadSock, m_iWriteSock, m_itimeout, m_iport, m_iConnType, m_iTcount, m_iMethod, m_iRemotePort, m_iLocalPort; + u_short m_iport, m_iRemotePort, m_iLocalPort; + int m_iReadSock, m_iWriteSock, m_itimeout, m_iConnType, m_iTcount, m_iMethod; bool m_bssl, m_bIsConnected, m_bClosed, m_bBLOCK, m_bFullsslAccept; bool m_bsslEstablished, m_bEnableReadLine, m_bRequireClientCert, m_bPauseRead; CS_STRING m_shostname, m_sbuffer, m_sSockName, m_sPemFile, m_sCipherType, m_sParentName; @@ -695,7 +828,7 @@ private: unsigned long long m_iMaxMilliSeconds, m_iLastSendTime, m_iBytesRead, m_iBytesWritten, m_iStartTime; unsigned int m_iMaxBytes, m_iLastSend, m_iMaxStoredBufferLength, m_iTimeoutType; - struct sockaddr_in m_address; + struct sockaddr_in m_address, m_bindhost; #ifdef HAVE_LIBSSL SSL *m_ssl; @@ -711,7 +844,18 @@ private: //! Create the socket virtual int SOCKET( bool bListen = false ); - virtual void Init( const CS_STRING & sHostname, int iport, int itimeout = 60 ); + virtual void Init( const CS_STRING & sHostname, u_short iport, int itimeout = 60 ); + + + // Connection State Info + ECONState m_eConState; + CS_STRING m_sBindHost; + u_int m_iCurBindCount, m_iDNSTryCount; + +#ifdef ___DO_THREADS + CDNSResolver m_cResolver; +#endif /* ___DO_THREADS */ + }; /** @@ -789,7 +933,7 @@ public: * \param sBindHost the host to bind too * \return true on success */ - virtual bool Connect( const CS_STRING & sHostname, int iPort , const CS_STRING & sSockName, int iTimeout = 60, bool isSSL = false, const CS_STRING & sBindHost = "", T *pcSock = NULL ) + virtual bool Connect( const CS_STRING & sHostname, u_short iPort , const CS_STRING & sSockName, int iTimeout = 60, bool isSSL = false, const CS_STRING & sBindHost = "", T *pcSock = NULL ) { // create the new object if ( !pcSock ) @@ -804,43 +948,34 @@ public: // make it NON-Blocking IO pcSock->BlockIO( false ); - if ( !pcSock->Connect( sBindHost ) ) - { - if ( GetSockError() == ECONNREFUSED ) - pcSock->ConnectionRefused(); - - CS_Delete( pcSock ); - return( false ); - } - #ifdef HAVE_LIBSSL - if ( isSSL ) - { - if ( !pcSock->ConnectSSL() ) - { - if ( GetSockError() == ECONNREFUSED ) - pcSock->ConnectionRefused(); - - CS_Delete( pcSock ); - return( false ); - } - } + pcSock->SetSSL( isSSL ); #endif /* HAVE_LIBSSL */ + if ( !pcSock->CreateSocksFD() ) + return( false ); + + pcSock->SetType( T::OUTBOUND ); + + pcSock->SetConState( T::CST_START ); AddSock( pcSock, sSockName ); return( true ); } /** - * Create a listening socket + * @brief Create a listening socket * - * \param iPort the port to listen on - * \param sSockName the name of the socket - * \param isSSL if the sockets created require an ssl layer - * \param iMaxConns the maximum amount of connections to accept - * \return true on success + * Given the design of this function, when binding to a hostname, its best to use an + * since dns lookups are blocking, but since your binding to a local ip, it should never be + * problem anyhow. + * + * @param iPort the port to listen on + * @param sSockName the name of the socket + * @param isSSL if the sockets created require an ssl layer + * @param iMaxConns the maximum amount of connections to accept + * @return pointer to sock, NULL if not successfull */ - virtual T * ListenHost( int iPort, const CS_STRING & sSockName, const CS_STRING & sBindHost, int isSSL = false, int iMaxConns = SOMAXCONN, T *pcSock = NULL, u_int iTimeout = 0 ) + virtual T * ListenHost( u_short iPort, const CS_STRING & sSockName, const CS_STRING & sBindHost, int isSSL = false, int iMaxConns = SOMAXCONN, T *pcSock = NULL, u_int iTimeout = 0 ) { if ( !pcSock ) pcSock = new T(); @@ -858,7 +993,7 @@ public: return( NULL ); } - virtual bool ListenAll( int iPort, const CS_STRING & sSockName, int isSSL = false, int iMaxConns = SOMAXCONN, T *pcSock = NULL, u_int iTimeout = 0 ) + virtual bool ListenAll( u_short iPort, const CS_STRING & sSockName, int isSSL = false, int iMaxConns = SOMAXCONN, T *pcSock = NULL, u_int iTimeout = 0 ) { return( ListenHost( iPort, sSockName, "", isSSL, iMaxConns, pcSock, iTimeout ) ); } @@ -1000,6 +1135,74 @@ public: break; } + for( u_int a = 0; a < this->size(); a++ ) + { + T *pcSock = (*this)[a]; + + if ( ( pcSock->GetType() != T::OUTBOUND ) || ( pcSock->GetConState() == T::CST_OK ) ) + continue; + + if ( pcSock->GetConState() == T::CST_DNS ) + { + if ( pcSock->DNSLookup( T::DNS_DEST ) == ETIMEDOUT ) + { + pcSock->SockError( EDOM ); + DelSock( a-- ); + continue; + } + } + + if ( pcSock->GetConState() == T::CST_VHOSTDNS ) + { + if ( pcSock->DNSLookup( T::DNS_VHOST ) == ETIMEDOUT ) + { + pcSock->SockError( EADDRNOTAVAIL ); + DelSock( a-- ); + continue; + } + } + + if ( pcSock->GetConState() == T::CST_BINDVHOST ) + { + if ( !pcSock->SetupVHost() ) + { + pcSock->SockError( errno ); + DelSock( a-- ); + continue; + } + } + + if ( pcSock->GetConState() == T::CST_CONNECT ) + { + + if ( !pcSock->Connect( pcSock->GetBindHost(), true ) ) + { + if ( GetSockError() == ECONNREFUSED ) + pcSock->ConnectionRefused(); + else + pcSock->SockError( ECONNABORTED ); + + DelSock( a-- ); + continue; + } + +#ifdef HAVE_LIBSSL + if ( pcSock->GetSSL() ) + { + if ( !pcSock->ConnectSSL() ) + { + if ( GetSockError() == ECONNREFUSED ) + pcSock->ConnectionRefused(); + else + pcSock->SockError( ECONNABORTED ); + + DelSock( a-- ); + continue; + } + } +#endif /* HAVE_LIBSSL */ + } + } unsigned long long iMilliNow = millitime(); if ( ( iMilliNow - m_iCallTimeouts ) > 1000 ) { @@ -1007,6 +1210,9 @@ public: // call timeout on all the sockets that recieved no data for( unsigned int i = 0; i < this->size(); i++ ) { + if ( (*this)[i]->GetConState() != T::CST_OK ) + continue; + if ( (*this)[i]->CheckTimeout() ) DelSock( i-- ); } @@ -1026,7 +1232,7 @@ public: } //! returns a pointer to the FIRST sock found by port or NULL on no match - virtual T * FindSockByRemotePort( int iPort ) + virtual T * FindSockByRemotePort( u_short iPort ) { for( unsigned int i = 0; i < this->size(); i++ ) { @@ -1038,7 +1244,7 @@ public: } //! returns a pointer to the FIRST sock found by port or NULL on no match - virtual T * FindSockByLocalPort( int iPort ) + virtual T * FindSockByLocalPort( u_short iPort ) { for( unsigned int i = 0; i < this->size(); i++ ) if ( (*this)[i]->GetLocalPort() == iPort ) @@ -1217,9 +1423,11 @@ private: for( unsigned int i = 0; i < this->size(); i++ ) { - T *pcSock = (*this)[i]; + if ( pcSock->GetConState() != T::CST_OK ) + continue; + int & iRSock = pcSock->GetRSock(); int & iWSock = pcSock->GetWSock(); bool bIsReadPaused = pcSock->IsReadPaused(); @@ -1277,6 +1485,9 @@ private: { T *pcSock = (*this)[i]; + if ( pcSock->GetConState() != T::CST_OK ) + continue; + if ( ( pcSock->GetSSL() ) && ( pcSock->GetType() != Csock::LISTENER ) ) { if ( ( pcSock->GetPending() > 0 ) && ( !pcSock->IsReadPaused() ) ) @@ -1330,6 +1541,10 @@ private: for( unsigned int i = 0; i < this->size(); i++ ) { T *pcSock = (*this)[i]; + + if ( pcSock->GetConState() != T::CST_OK ) + continue; + int & iRSock = pcSock->GetRSock(); int & iWSock = pcSock->GetWSock(); EMessages iErrno = SUCCESS; @@ -1372,7 +1587,7 @@ private: else // someone is coming in! { CS_STRING sHost; - int port; + u_short port; int inSock = pcSock->Accept( sHost, port ); if ( inSock != -1 ) @@ -1452,6 +1667,14 @@ private: } } + //////// + // Connection State Functions + + + + + /////////// + // members EMessages m_errno; std::vector m_vcCrons; unsigned long long m_iCallTimeouts; diff --git a/DCCBounce.cpp b/DCCBounce.cpp index 57431beb..cf96bbc1 100644 --- a/DCCBounce.cpp +++ b/DCCBounce.cpp @@ -81,7 +81,7 @@ void CDCCBounce::Shutdown() { Close(); } -Csock* CDCCBounce::GetSockObj(const CString& sHost, int iPort) { +Csock* CDCCBounce::GetSockObj(const CString& sHost, unsigned short uPort) { Close(); if (!m_pManager) { @@ -92,8 +92,8 @@ Csock* CDCCBounce::GetSockObj(const CString& sHost, int iPort) { m_sRemoteIP = sHost; } - CDCCBounce* pSock = new CDCCBounce(sHost, iPort, m_pUser, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat); - CDCCBounce* pRemoteSock = new CDCCBounce(sHost, iPort, m_pUser, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat); + CDCCBounce* pSock = new CDCCBounce(sHost, uPort, m_pUser, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat); + CDCCBounce* pRemoteSock = new CDCCBounce(sHost, uPort, m_pUser, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat); pSock->SetPeer(pRemoteSock); pRemoteSock->SetPeer(pSock); pRemoteSock->SetRemote(true); diff --git a/DCCBounce.h b/DCCBounce.h index 4c598d15..f24b7590 100644 --- a/DCCBounce.h +++ b/DCCBounce.h @@ -25,7 +25,7 @@ public: } } - CDCCBounce(const CString& sHostname, int iport, CUser* pUser, const CString& sRemoteNick, const CString& sRemoteIP, const CString& sFileName, int itimeout = 60, bool bIsChat = false) : Csock(sHostname, iport, itimeout) { + CDCCBounce(const CString& sHostname, unsigned short uPort, CUser* pUser, const CString& sRemoteNick, const CString& sRemoteIP, const CString& sFileName, int itimeout = 60, bool bIsChat = false) : Csock(sHostname, uPort, itimeout) { m_uRemotePort = 0; m_bIsChat = bIsChat; m_pManager = pUser->GetManager(); @@ -57,7 +57,7 @@ public: virtual void Connected(); virtual void Disconnected(); void Shutdown(); - Csock* GetSockObj(const CString& sHost, int iPort); + Csock* GetSockObj(const CString& sHost, unsigned short uPort); void PutServ(const CString& sLine); void PutPeer(const CString& sLine); bool IsPeerConnected() { return (m_pPeer) ? m_pPeer->IsConnected() : false; } diff --git a/DCCSock.cpp b/DCCSock.cpp index 3e0d8806..b1134465 100644 --- a/DCCSock.cpp +++ b/DCCSock.cpp @@ -96,7 +96,7 @@ void CDCCSock::SendPacket() { } } -Csock* CDCCSock::GetSockObj(const CString& sHost, int iPort) { +Csock* CDCCSock::GetSockObj(const CString& sHost, unsigned short uPort) { Close(); CDCCSock* pSock = new CDCCSock(m_pUser, m_sRemoteNick, m_sLocalFile, m_sModuleName, m_uFileSize, m_pFile); diff --git a/DCCSock.h b/DCCSock.h index 834fddd1..1e6f861a 100644 --- a/DCCSock.h +++ b/DCCSock.h @@ -35,7 +35,7 @@ public: m_bNoDelFile = false; } -/* CDCCSock(CUser* pUser, const CString& sHostname, int iport, int itimeout = 60) : Csock(sHostname, iport, itimeout) { +/* CDCCSock(CUser* pUser, const CString& sHostname, unsigned short uPort, int itimeout = 60) : Csock(sHostname, uPort, itimeout) { m_uRemotePort = 0; m_uBytesSoFar = 0; m_uFileSize = 0; @@ -58,7 +58,7 @@ public: virtual void Connected(); virtual void Disconnected(); void SendPacket(); - Csock* GetSockObj(const CString& sHost, int iPort); + Csock* GetSockObj(const CString& sHost, unsigned short uPort); CFile* OpenFile(bool bWrite = true); bool Seek(unsigned int uPos) { if (m_pFile) { diff --git a/User.cpp b/User.cpp index 18ced3ee..10aa9b50 100644 --- a/User.cpp +++ b/User.cpp @@ -390,14 +390,14 @@ bool CUser::SendFile(const CString& sRemoteNick, const CString& sFileName, const return false; } - int iPort = GetManager()->ListenAllRand("DCC::LISTEN::" + sRemoteNick, false, SOMAXCONN, pSock, 120); + unsigned short uPort = GetManager()->ListenAllRand("DCC::LISTEN::" + sRemoteNick, false, SOMAXCONN, pSock, 120); if (GetNick().CaseCmp(sRemoteNick) == 0) { PutUser(":" + GetStatusPrefix() + "status!znc@znc.com PRIVMSG " + sRemoteNick + " :\001DCC SEND " + pFile->GetShortName() + " " + CString::ToString(CUtils::GetLongIP(GetLocalIP())) + " " - + CString::ToString(iPort) + " " + CString::ToString(pFile->GetSize()) + "\001"); + + CString::ToString(uPort) + " " + CString::ToString(pFile->GetSize()) + "\001"); } else { PutIRC("PRIVMSG " + sRemoteNick + " :\001DCC SEND " + pFile->GetShortName() + " " + CString::ToString(CUtils::GetLongIP(GetLocalIP())) + " " - + CString::ToString(iPort) + " " + CString::ToString(pFile->GetSize()) + "\001"); + + CString::ToString(uPort) + " " + CString::ToString(pFile->GetSize()) + "\001"); } PutModule(sModuleName, "DCC -> [" + sRemoteNick + "][" + pFile->GetShortName() + "] - Attempting Send."); diff --git a/UserSock.cpp b/UserSock.cpp index aae666f6..da8b3007 100644 --- a/UserSock.cpp +++ b/UserSock.cpp @@ -893,8 +893,8 @@ void CUserSock::HelpUser() { } } -bool CUserSock::ConnectionFrom(const CString& sHost, int iPort) { - DEBUG_ONLY(cout << GetSockName() << " == ConnectionFrom(" << sHost << ", " << iPort << ")" << endl); +bool CUserSock::ConnectionFrom(const CString& sHost, unsigned short uPort) { + DEBUG_ONLY(cout << GetSockName() << " == ConnectionFrom(" << sHost << ", " << uPort << ")" << endl); return m_pZNC->IsHostAllowed(sHost); } @@ -970,8 +970,8 @@ void CUserSock::IRCDisconnected() { m_pIRCSock = NULL; } -Csock* CUserSock::GetSockObj(const CString& sHost, int iPort) { - CUserSock* pSock = new CUserSock(sHost, iPort); +Csock* CUserSock::GetSockObj(const CString& sHost, unsigned short uPort) { + CUserSock* pSock = new CUserSock(sHost, uPort); pSock->SetZNC(m_pZNC); return pSock; diff --git a/UserSock.h b/UserSock.h index 2f8b23bf..707404dc 100644 --- a/UserSock.h +++ b/UserSock.h @@ -15,7 +15,7 @@ public: CUserSock() : Csock() { Init(); } - CUserSock(const CString& sHostname, int iport, int itimeout = 60) : Csock(sHostname, iport, itimeout) { + CUserSock(const CString& sHostname, unsigned short uPort, int itimeout = 60) : Csock(sHostname, uPort, itimeout) { Init(); } virtual ~CUserSock() {} @@ -55,8 +55,8 @@ public: virtual void Connected(); virtual void Disconnected(); virtual void ConnectionRefused(); - virtual bool ConnectionFrom(const CString& sHost, int iPort); - virtual Csock* GetSockObj(const CString& sHost, int iPort); + virtual bool ConnectionFrom(const CString& sHost, unsigned short uPort); + virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); void SetZNC(CZNC* pZNC) { m_pZNC = pZNC; } void SetNick(const CString& s); diff --git a/znc.h b/znc.h index da292b14..636adbc3 100644 --- a/znc.h +++ b/znc.h @@ -34,7 +34,7 @@ public: // Getters TSocketManager& GetManager() { return m_Manager; } CGlobalModules& GetModules() { return *m_pModules; } - unsigned int GetListenPort() const { return m_uListenPort; } + unsigned short GetListenPort() const { return m_uListenPort; } const CString& GetCurPath() const { if (!CFile::Exists(m_sCurPath)) { CUtils::MakeDir(m_sCurPath); } return m_sCurPath; } const CString& GetDLPath() const { if (!CFile::Exists(m_sDLPath)) { CUtils::MakeDir(m_sDLPath); } return m_sDLPath; } const CString& GetModPath() const { if (!CFile::Exists(m_sModPath)) { CUtils::MakeDir(m_sModPath); } return m_sModPath; }