diff --git a/include/znc/Csocket.h b/include/znc/Csocket.h index c5ea37e7..1bbd88e4 100644 --- a/include/znc/Csocket.h +++ b/include/znc/Csocket.h @@ -1,6 +1,6 @@ /** * -* Copyright (c) 1999-2011 Jim Hull +* Copyright (c) 1999-2012 Jim Hull * All rights reserved * * Redistribution and use in source and binary forms, with or without modification, @@ -30,7 +30,13 @@ * */ -// note to compile with win32 need to link to winsock2, using gcc its -lws2_32 +/*** + * NOTES ... + * - You should always compile with -Woverloaded-virtual to detect callbacks that may have been redefined since your last update + * - If you want to use gethostbyname instead of getaddrinfo, the use -DUSE_GETHOSTBYNAME when compiling + * - To compile with win32 need to link to winsock2, using gcc its -lws2_32 + * - Code is formated with 'astyle --style=ansi -t4 --unpad-paren --pad-paren-in --keep-one-line-blocks' + ***/ #ifndef _HAS_CSOCKET_ #define _HAS_CSOCKET_ @@ -149,7 +155,7 @@ class CSCharBuffer public: CSCharBuffer( size_t iSize ) { - m_pBuffer = (char *)malloc( iSize ); + m_pBuffer = ( char * )malloc( iSize ); } ~CSCharBuffer() { @@ -167,9 +173,9 @@ public: CSSockAddr() { m_bIsIPv6 = false; - memset( (struct sockaddr_in *)&m_saddr, '\0', sizeof( m_saddr ) ); + memset(( struct sockaddr_in * )&m_saddr, '\0', sizeof( m_saddr ) ); #ifdef HAVE_IPV6 - memset( (struct sockaddr_in6 *)&m_saddr6, '\0', sizeof( m_saddr6 ) ); + memset(( struct sockaddr_in6 * )&m_saddr6, '\0', sizeof( m_saddr6 ) ); #endif /* HAVE_IPV6 */ m_iAFRequire = RAF_ANY; } @@ -193,11 +199,11 @@ public: socklen_t GetSockAddrLen() { return( sizeof( m_saddr ) ); } sockaddr_in * GetSockAddr() { return( &m_saddr ); } - in_addr * GetAddr() { return( &(m_saddr.sin_addr) ); } + in_addr * GetAddr() { return( &( m_saddr.sin_addr ) ); } #ifdef HAVE_IPV6 socklen_t GetSockAddrLen6() { return( sizeof( m_saddr6 ) ); } sockaddr_in6 * GetSockAddr6() { return( &m_saddr6 ); } - in6_addr * GetAddr6() { return( &(m_saddr6.sin6_addr) ); } + in6_addr * GetAddr6() { return( &( m_saddr6.sin6_addr ) ); } #endif /* HAVE_IPV6 */ void SetAFRequire( EAFRequire iWhich ) { m_iAFRequire = iWhich; } @@ -215,7 +221,8 @@ private: class Csock; /** - * @brief this function is a wrapper around gethostbyname and getaddrinfo (for ipv6) + * @class CGetAddrInfo + * @brief this function is a wrapper around getaddrinfo (for ipv6) * * in the event this code is using ipv6, it calls getaddrinfo, and it tries to start the connection on each iteration * in the linked list returned by getaddrinfo. if pSock is not NULL the following behavior happens. @@ -224,13 +231,38 @@ class Csock; * getaddrinfo might return multiple (possibly invalid depending on system configuration) ip addresses, so connect needs to try them all. * A classic example of this is a hostname that resolves to both ipv4 and ipv6 ip's. You still need to call Connect (and ConnectSSL) to finish * up the connection state - * - NOTE ... Once threading is reimplemented, this function will spin off a thread to resolve and return EAGAIN until its done. * - * @param sHostname the host to resolve - * @param pSock the sock being setup, this option can be NULL, if it is null csSockAddr is only setup - * @param csSockAddr the struct that sockaddr data is being copied to - * @return 0 on success, otherwise an error. EAGAIN if this needs to be called again at a later time, ETIMEDOUT if no host is found + * Process can be called in a thread, but Init and Finish must only be called from the parent once the thread is complete */ +class CGetAddrInfo +{ +public: + /** + * @brief ctor + * @param sHostname the host to resolve + * @param pSock the sock being setup, this option can be NULL, if it is null csSockAddr is only setup + * @param csSockAddr the struct that sockaddr data is being copied to + */ + CGetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockAddr ); + ~CGetAddrInfo(); + + //! simply sets up m_cHints for use in process + void Init(); + //! the simplest part of the function, only calls getaddrinfo and uses only m_sHostname, m_pAddrRes, and m_cHints. + int Process(); + //! finalizes and sets up csSockAddr (and pSock if not NULL), only needs to be called if Process returns 0, but can be called anyways if flow demands it + int Finish(); + +private: + CS_STRING m_sHostname; + Csock * m_pSock; + CSSockAddr & m_csSockAddr; + struct addrinfo * m_pAddrRes; + struct addrinfo m_cHints; + int m_iRet; +}; + +//! backwards compatible wrapper around CGetAddrInfo and gethostbyname int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockAddr ); //! used to retrieve the context position of the socket to its associated ssl connection. Setup once in InitSSL() via SSL_get_ex_new_index @@ -300,7 +332,7 @@ inline void TFD_SET( cs_sock_t iSock, fd_set *set ) inline bool TFD_ISSET( cs_sock_t iSock, fd_set *set ) { - if ( FD_ISSET( iSock, set ) ) + if( FD_ISSET( iSock, set ) ) return( true ); return( false ); @@ -320,7 +352,7 @@ unsigned long long millitime(); * @brief this is the main cron job class * * You should derive from this class, and override RunJob() with your code -* @author Jim Hull +* @author Jim Hull */ class CCron @@ -421,7 +453,7 @@ public: void Remove( int iFD ) { m_miiMonitorFDs.erase( iFD ); } //! causes this monitor to be removed void DisableMonitor() { m_bEnabled = false; } - + bool IsEnabled() const { return( m_bEnabled ); } protected: @@ -441,7 +473,7 @@ public: void CleanupCrons(); void CleanupFDMonitors(); - + //! returns a const reference to the crons associated to this socket const std::vector & GetCrons() const { return( m_vcCrons ); } //! This has a garbage collecter, and is used internall to call the jobs @@ -473,7 +505,7 @@ protected: }; #ifdef HAVE_LIBSSL -typedef int (*FPCertVerifyCB)( int, X509_STORE_CTX * ); +typedef int ( *FPCertVerifyCB )( int, X509_STORE_CTX * ); #endif /* HAVE_LIBSSL */ /** @@ -483,7 +515,7 @@ typedef int (*FPCertVerifyCB)( int, X509_STORE_CTX * ); * You can use this class directly for quick things * or use the socket manager * @see TSocketManager -* @author Jim Hull +* @author Jim Hull */ class Csock : public CSockCommon { @@ -586,11 +618,12 @@ public: * Listens for connections * * @param iPort the port to listen on - * @param iMaxConns the maximum amount of connections to allow + * @param iMaxConns the maximum amount of pending connections to allow * @param sBindHost the vhost on which to listen - * @param iTimeout i dont know what this does :( + * @param iTimeout if no connections come in by this timeout, the listener is closed + * @param bDetach don't block waiting for port to come up, instead detach and return immediately */ - virtual bool Listen( u_short 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, bool bDetach = false ); //! Accept an inbound connection, this is used internally virtual cs_sock_t Accept( CS_STRING & sHost, u_short & iRPort ); @@ -651,8 +684,6 @@ public: CS_STRING GetLocalIP(); CS_STRING GetRemoteIP(); - virtual CS_STRING ConvertAddress( void *addr, bool bIPv6 = false ); - //! Tells you if the socket is connected virtual bool IsConnected() const; //! Sets the sock, telling it its connected (internal use only) @@ -667,6 +698,12 @@ public: void SetSock( cs_sock_t iSock ); cs_sock_t & GetSock(); + /** + * @brief calls SockError, if sDescription is not set, then strerror is used to pull out a default description + * @param iErrno the errno to send + * @param sDescription the description of the error that occurred + */ + void CallSockError( int iErrno, const CS_STRING & sDescription = "" ); //! resets the time counter, this is virtual in the event you need an event on the timer being Reset virtual void ResetTimer(); @@ -817,12 +854,12 @@ public: //! Returns the peer's public key CS_STRING GetPeerPubKey(); //! Returns the peer's certificate finger print - long GetPeerFingerprint( CS_STRING & sFP); + long GetPeerFingerprint( CS_STRING & sFP ); unsigned int GetRequireClientCertFlags(); //! legacy, deprecated @see SetRequireClientCertFlags void SetRequiresClientCert( bool bRequiresCert ); - //! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert + //! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert void SetRequireClientCertFlags( unsigned int iRequireClientCertFlags ) { m_iRequireClientCertFlags = iRequireClientCertFlags; } #endif /* HAVE_LIBSSL */ @@ -904,7 +941,7 @@ public: * * A sock error occured event */ - virtual void SockError( int iErrno ) {} + virtual void SockError( int iErrno, const CS_STRING & sDescription ) {} /** * Override these functions for an easy interface when using the Socket Manager * Don't bother using these callbacks if you are using this class directly (without Socket Manager) @@ -917,6 +954,13 @@ public: */ virtual bool ConnectionFrom( const CS_STRING & sHost, u_short iPort ) { return( true ); } + /** + * @brief called when type is LISTENER and the listening port is up and running + * @param sBindIP the IP that is being bound to. Empty if no bind restriction + * @param uPort the listening port + */ + virtual void Listening( const CS_STRING & sBindIP, u_short uPort ) {} + /** * Override these functions for an easy interface when using the Socket Manager * Don't bother using these callbacks if you are using this class directly (without Socket Manager) @@ -1010,12 +1054,29 @@ public: */ virtual int GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ); + /** + * @brief retrieve name info (numeric only) for a given sockaddr_storage + * @param pAddr the sockaddr_storage + * @param iAddrLen the length + * @param sHostname filled with the IP from getnameinfo + * @param piPort if not null, filled with the port + * @return 0 on success. + * + * In the event you want to do additional work before or after getnameinfo is called, you can override this and do just that. + * One example is in the event that an ipv6 ip is a mapped ipv4 mapped, you can check like so. + * - if( pAddr->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED( &(((const struct sockaddr_in6 *)pAddr)->sin6_addr ) ) + */ + virtual int ConvertAddress( const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, u_short * piPort ); + #ifdef HAVE_C_ARES CSSockAddr * GetCurrentAddr() const { return( m_pCurrAddr ); } void SetAresFinished( int status ) { m_pCurrAddr = NULL; m_iARESStatus = status; } ares_channel GetAresChannel() { return( m_pARESChannel ); } #endif /* HAVE_C_ARES */ + //! returns the number of max pending connections when type is LISTENER + int GetMaxConns() const { return( m_iMaxConns ); } + private: //! making private for safety Csock( const Csock & cCopy ) : CSockCommon() {} @@ -1023,7 +1084,7 @@ private: // NOTE! if you add any new members, be sure to add them to Copy() u_short m_uPort, m_iRemotePort, m_iLocalPort; cs_sock_t m_iReadSock, m_iWriteSock; - int m_iTimeout, m_iConnType, m_iMethod, m_iTcount; + int m_iTimeout, m_iConnType, m_iMethod, m_iTcount, m_iMaxConns; bool m_bUseSSL, m_bIsConnected, m_bBLOCK; bool m_bsslEstablished, m_bEnableReadLine, m_bPauseRead; CS_STRING m_shostname, m_sbuffer, m_sSockName, m_sPemFile, m_sCipherType, m_sParentName; @@ -1165,8 +1226,9 @@ public: /** * @param iPort port to listen on. Set to 0 to listen on a random port * @param sBindHost host to bind to + * @param bDetach don't block while waiting for the port to come up, instead detach and return immediately */ - CSListener( u_short iPort, const CS_STRING & sBindHost = "" ) + CSListener( u_short iPort, const CS_STRING & sBindHost = "", bool bDetach = false ) { m_iPort = iPort; m_sBindHost = sBindHost; @@ -1174,6 +1236,7 @@ public: m_iMaxConns = SOMAXCONN; m_iTimeout = 0; m_iAFrequire = CSSockAddr::RAF_ANY; + m_bDetach = bDetach; #ifdef HAVE_LIBSSL m_sCipher = "HIGH"; m_iRequireCertFlags = 0; @@ -1181,6 +1244,8 @@ public: } virtual ~CSListener() {} + void SetDetach( bool b ) { m_bDetach = b; } + bool GetDetach() const { return( m_bDetach ); } u_short GetPort() const { return( m_iPort ); } const CS_STRING & GetSockName() const { return( m_sSockName ); } const CS_STRING & GetBindHost() const { return( m_sBindHost ); } @@ -1219,13 +1284,14 @@ public: void SetPemPass( const CS_STRING & s ) { m_sPemPass = s; } //! set to true if require a client certificate (deprecated @see SetRequireClientCertFlags) void SetRequiresClientCert( bool b ) { m_iRequireCertFlags = ( b ? SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0 ); } - //! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert + //! bitwise flags, 0 means don't require cert, SSL_VERIFY_PEER verifies peers, SSL_VERIFY_FAIL_IF_NO_PEER_CERT will cause the connection to fail if no cert void SetRequireClientCertFlags( unsigned int iRequireCertFlags ) { m_iRequireCertFlags = iRequireCertFlags; } #endif /* HAVE_LIBSSL */ private: u_short m_iPort; CS_STRING m_sSockName, m_sBindHost; bool m_bIsSSL; + bool m_bDetach; int m_iMaxConns; u_int m_iTimeout; CSSockAddr::EAFRequire m_iAFrequire; @@ -1268,7 +1334,7 @@ public: * * class CBlahSock : public TSocketManager * -* @author Jim Hull +* @author Jim Hull */ class CSocketManager : public std::vector, public CSockCommon @@ -1297,6 +1363,15 @@ public: */ void Connect( const CSConnection & cCon, Csock * pcSock = NULL ); + /** + * @brief Sets up a listening socket + * @param cListen the listener configuration + * @param pcSock preconfigured sock to use + * @param piRandPort if listener is set to port 0, then a random port is used and this is assigned. + * + * IF you provide piRandPort to be assigned, AND you set bDetach to true, then Listen() still blocks. If you don't want this + * behavior, then look for the port assignment to be called in Csock::Listening + */ virtual bool Listen( const CSListener & cListen, Csock * pcSock = NULL, u_short *piRandPort = NULL ); @@ -1408,7 +1483,7 @@ public: protected: - virtual int Select( std::map< int, short > & miiReadyFds, struct timeval *tvtimeout); + virtual int Select( std::map< int, short > & miiReadyFds, struct timeval *tvtimeout ); private: /** diff --git a/include/znc/HTTPSock.h b/include/znc/HTTPSock.h index 219bb8d1..34b5af61 100644 --- a/include/znc/HTTPSock.h +++ b/include/znc/HTTPSock.h @@ -24,7 +24,7 @@ public: virtual void ReadData(const char* data, size_t len); virtual void ReadLine(const CString& sData); virtual void ReachedMaxBuffer(); - virtual void SockError(int iErrno); + virtual void SockError(int iErrno, const CString& sDescription); virtual void Timeout(); virtual void Connected(); virtual void Disconnected(); diff --git a/include/znc/IRCSock.h b/include/znc/IRCSock.h index 3a4e05d7..a30a1172 100644 --- a/include/znc/IRCSock.h +++ b/include/znc/IRCSock.h @@ -49,7 +49,7 @@ public: virtual void Connected(); virtual void Disconnected(); virtual void ConnectionRefused(); - virtual void SockError(int iErrno); + virtual void SockError(int iErrno, const CString& sDescription); virtual void Timeout(); virtual void ReachedMaxBuffer(); diff --git a/include/znc/Listener.h b/include/znc/Listener.h index 063ac272..f66132c6 100644 --- a/include/znc/Listener.h +++ b/include/znc/Listener.h @@ -68,7 +68,7 @@ public: virtual bool ConnectionFrom(const CString& sHost, unsigned short uPort); virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); - virtual void SockError(int iErrno); + virtual void SockError(int iErrno, const CString& sDescription); private: CListener* m_pParent; diff --git a/include/znc/Socket.h b/include/znc/Socket.h index a1c258f6..058bb27e 100644 --- a/include/znc/Socket.h +++ b/include/znc/Socket.h @@ -20,7 +20,7 @@ public: CZNCSock(const CString& sHost, u_short port, int timeout = 60) : Csock(sHost, port, timeout) {} ~CZNCSock() {} - virtual CS_STRING ConvertAddress(void *addr, bool ipv6 = false); + virtual int ConvertAddress(const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, u_short * piPort); }; enum EAddrType { @@ -141,7 +141,7 @@ public: //! This defaults to closing the socket, feel free to override virtual void ReachedMaxBuffer(); - virtual void SockError(int iErrno); + virtual void SockError(int iErrno, const CString& sDescription); //! This limits the global connections from this IP to defeat DoS attacks, feel free to override. The ACL used is provided by the main interface @see CZNC::AllowConnectionFrom virtual bool ConnectionFrom(const CString& sHost, unsigned short uPort); diff --git a/modules/bouncedcc.cpp b/modules/bouncedcc.cpp index 9f041f88..3d51ced7 100644 --- a/modules/bouncedcc.cpp +++ b/modules/bouncedcc.cpp @@ -34,7 +34,7 @@ public: virtual void Timeout(); virtual void ConnectionRefused(); virtual void ReachedMaxBuffer(); - virtual void SockError(int iErrno); + virtual void SockError(int iErrno, const CString& sDescription); virtual void Connected(); virtual void Disconnected(); virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); @@ -377,7 +377,7 @@ void CDCCBounce::ConnectionRefused() { m_pModule->PutModule("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Connection Refused while connecting" + sHost); } -void CDCCBounce::SockError(int iErrno) { +void CDCCBounce::SockError(int iErrno, const CString& sDescription) { DEBUG(GetSockName() << " == SockError(" << iErrno << ")"); CString sType = (m_bIsChat) ? "Chat" : "Xfer"; @@ -387,9 +387,9 @@ void CDCCBounce::SockError(int iErrno) { sHost = "[" + sHost + " " + CString(Csock::GetPort()) + "]"; } - m_pModule->PutModule("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Socket error [" + CString(strerror(iErrno)) + "]" + sHost); + m_pModule->PutModule("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Socket error [" + sDescription + "]" + sHost); } else { - m_pModule->PutModule("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Socket error [" + CString(strerror(iErrno)) + "] [" + Csock::GetLocalIP() + ":" + CString(Csock::GetLocalPort()) + "]"); + m_pModule->PutModule("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Socket error [" + sDescription + "] [" + Csock::GetLocalIP() + ":" + CString(Csock::GetLocalPort()) + "]"); } } diff --git a/modules/extra/dcc.cpp b/modules/extra/dcc.cpp index 8198993f..4d19107d 100644 --- a/modules/extra/dcc.cpp +++ b/modules/extra/dcc.cpp @@ -22,7 +22,7 @@ public: virtual void ReadData(const char* data, size_t len); virtual void ConnectionRefused(); - virtual void SockError(int iErrno); + virtual void SockError(int iErrno, const CString& sDescription); virtual void Timeout(); virtual void Connected(); virtual void Disconnected(); @@ -326,9 +326,9 @@ void CDCCSock::Timeout() { m_pModule->PutModule(((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Timed Out."); } -void CDCCSock::SockError(int iErrno) { - DEBUG(GetSockName() << " == SockError(" << iErrno << ")"); - m_pModule->PutModule(((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Socket Error [" + CString(iErrno) + "]"); +void CDCCSock::SockError(int iErrno, const CString& sDescription) { + DEBUG(GetSockName() << " == SockError(" << iErrno << ", " << sDescription << ")"); + m_pModule->PutModule(((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Socket Error [" + sDescription + "]"); } void CDCCSock::Connected() { diff --git a/src/Csocket.cpp b/src/Csocket.cpp index 23129d6b..c5b2b6c0 100644 --- a/src/Csocket.cpp +++ b/src/Csocket.cpp @@ -1,6 +1,6 @@ /** @file * -* Copyright (c) 1999-2011 Jim Hull +* Copyright (c) 1999-2012 Jim Hull * All rights reserved * * Redistribution and use in source and binary forms, with or without modification, @@ -30,6 +30,14 @@ * */ +/*** + * doing this because there seems to be a bug that is losing the "short" on htons when in optimize mode turns into a macro + * gcc 4.3.4 + */ +#if defined(__OPTIMIZE__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 3 +#pragma GCC diagnostic warning "-Wconversion" +#endif /* defined(__OPTIMIZE__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 3 */ + #include #ifdef __NetBSD__ #include @@ -41,18 +49,6 @@ #include #endif /* HAVE_LIBSSL */ -/*** - * doing this because there seems to be a bug that is losing the "short" on htons when in optimize mode turns into a macro - * gcc 4.3.4 - */ -#ifdef __OPTIMIZE__ -#ifdef htons -#undef htons -#endif /* htons */ -#ifdef ntohs -#undef ntohs -#endif /* ntohs */ -#endif /* __OPTIMIZE__ */ #include @@ -75,28 +71,6 @@ int GetCsockClassIdx() } #ifdef _WIN32 -static const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) -{ - if( af == AF_INET ) - { - struct sockaddr_in in; - memset(&in, 0, sizeof(in)); - in.sin_family = AF_INET; - memcpy( &in.sin_addr, src, sizeof(struct in_addr) ); - getnameinfo( (struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST ); - return dst; - } - else if( af == AF_INET6 ) - { - struct sockaddr_in6 in; - memset( &in, 0, sizeof(in) ); - in.sin6_family = AF_INET6; - memcpy( &in.sin6_addr, src, sizeof(struct in_addr6) ); - getnameinfo( (struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST ); - return dst; - } - return( NULL ); -} #if defined(_WIN32) && (!defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)) //! thanks to KiNgMaR @ #znc for this wrapper @@ -108,21 +82,21 @@ static int inet_pton( int af, const char *src, void *dst ) char *pTmp = strdup( src ); aAddress.ss_family = af; // this is important: // The function fails if the sin_family member of the SOCKADDR_IN structure is not set to AF_INET or AF_INET6. - int iRet = WSAStringToAddressA( pTmp, af, NULL, (sockaddr *)&aAddress, &iAddrLen ); + int iRet = WSAStringToAddressA( pTmp, af, NULL, ( sockaddr * )&aAddress, &iAddrLen ); free( pTmp ); if( iRet == 0 ) { if( af == AF_INET6 ) - memcpy(dst, &((sockaddr_in6 *)&aAddress)->sin6_addr, sizeof(in6_addr)); + memcpy( dst, &(( sockaddr_in6 * )&aAddress )->sin6_addr, sizeof( in6_addr ) ); else - memcpy(dst, &((sockaddr_in *)&aAddress)->sin_addr, sizeof(in_addr)); + memcpy( dst, &(( sockaddr_in * )&aAddress )->sin_addr, sizeof( in_addr ) ); return( 1 ); } return( -1 ); } #endif -static inline void set_non_blocking(cs_sock_t fd) +static inline void set_non_blocking( cs_sock_t fd ) { u_long iOpts = 1; ioctlsocket( fd, FIONBIO, &iOpts ); @@ -137,17 +111,17 @@ static inline void set_blocking(cs_sock_t fd) } */ -static inline void set_close_on_exec(cs_sock_t 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(cs_sock_t fd) +static inline void set_non_blocking( cs_sock_t fd ) { - int fdflags = fcntl(fd, F_GETFL, 0); - if ( fdflags < 0 ) + int fdflags = fcntl( fd, F_GETFL, 0 ); + if( fdflags < 0 ) return; // Ignore errors fcntl( fd, F_SETFL, fdflags|O_NONBLOCK ); } @@ -164,12 +138,12 @@ static inline void set_blocking(cs_sock_t fd) } */ -static inline void set_close_on_exec(cs_sock_t fd) +static inline void set_close_on_exec( cs_sock_t fd ) { - int fdflags = fcntl(fd, F_GETFD, 0); - if ( fdflags < 0 ) + int fdflags = fcntl( fd, F_GETFD, 0 ); + if( fdflags < 0 ) return; // Ignore errors - fcntl( fd, F_SETFD, fdflags|FD_CLOEXEC); + fcntl( fd, F_SETFD, fdflags|FD_CLOEXEC ); } #endif /* _WIN32 */ @@ -202,19 +176,20 @@ void CSSockAddr::SetIPv6( bool b ) SinFamily(); } + #ifdef HAVE_LIBSSL Csock *GetCsockFromCTX( X509_STORE_CTX *pCTX ) { Csock *pSock = NULL; - SSL *pSSL = (SSL *)X509_STORE_CTX_get_ex_data( pCTX, SSL_get_ex_data_X509_STORE_CTX_idx() ); + SSL *pSSL = ( SSL * )X509_STORE_CTX_get_ex_data( pCTX, SSL_get_ex_data_X509_STORE_CTX_idx() ); if( pSSL ) - pSock = (Csock *)SSL_get_ex_data( pSSL, GetCsockClassIdx() ); + pSock = ( Csock * )SSL_get_ex_data( pSSL, GetCsockClassIdx() ); return( pSock ); } #endif /* HAVE_LIBSSL */ -#ifndef HAVE_IPV6 +#ifdef USE_GETHOSTBYNAME // this issue here is getaddrinfo has a significant behavior difference when dealing with round robin dns on an // ipv4 network. This is not desirable IMHO. so when this is compiled without ipv6 support backwards compatibility @@ -231,20 +206,20 @@ static int __GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr, int err; for( u_int a = 0; a < iNumRetries; a++ ) { - memset( (char *)hbuff, '\0', 2048 ); + memset(( char * )hbuff, '\0', 2048 ); iReturn = gethostbyname_r( sHostName.c_str(), &hentbuff, hbuff, 2048, &hent, &err ); - if ( iReturn == 0 ) + if( iReturn == 0 ) break; - if ( iReturn != TRY_AGAIN ) + if( iReturn != TRY_AGAIN ) { CS_DEBUG( "gethostyname_r: " << hstrerror( h_errno ) ); break; } } - if ( ( !hent ) && ( iReturn == 0 ) ) + if( !hent && iReturn == 0 ) iReturn = HOST_NOT_FOUND; #else for( u_int a = 0; a < iNumRetries; a++ ) @@ -252,7 +227,7 @@ static int __GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr, iReturn = HOST_NOT_FOUND; hent = gethostbyname( sHostName.c_str() ); - if ( hent ) + if( hent ) { iReturn = 0; break; @@ -269,12 +244,12 @@ static int __GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr, #endif /* __linux__ */ - if ( iReturn == 0 ) + if( iReturn == 0 ) memcpy( &paddr->s_addr, hent->h_addr_list[0], sizeof( paddr->s_addr ) ); return( iReturn == TRY_AGAIN ? EAGAIN : iReturn ); } -#endif /* !HAVE_IPV6 */ +#endif /* !USE_GETHOSTBYNAME */ #ifdef HAVE_C_ARES void Csock::FreeAres() @@ -290,20 +265,20 @@ void Csock::FreeAres() #ifdef HAVE_C_ARES static void AresHostCallback( void *pArg, int status, int timeouts, struct hostent *hent ) { - Csock *pSock = (Csock *)pArg; + Csock *pSock = ( Csock * )pArg; if( status == ARES_SUCCESS && hent && hent->h_addr_list[0] != NULL ) { CSSockAddr *pSockAddr = pSock->GetCurrentAddr(); if( hent->h_addrtype == AF_INET ) { pSock->SetIPv6( false ); - memcpy( pSockAddr->GetAddr(), hent->h_addr_list[0], sizeof( *(pSockAddr->GetAddr()) ) ); + memcpy( pSockAddr->GetAddr(), hent->h_addr_list[0], sizeof( *( pSockAddr->GetAddr() ) ) ); } #ifdef HAVE_IPV6 else if( hent->h_addrtype == AF_INET6 ) { pSock->SetIPv6( true ); - memcpy( pSockAddr->GetAddr6(), hent->h_addr_list[0], sizeof( *(pSockAddr->GetAddr6()) ) ); + memcpy( pSockAddr->GetAddr6(), hent->h_addr_list[0], sizeof( *( pSockAddr->GetAddr6() ) ) ); } #endif /* HAVE_IPV6 */ else @@ -316,7 +291,7 @@ static void AresHostCallback( void *pArg, int status, int timeouts, struct hoste CS_DEBUG( ares_strerror( status ) ); if( status == ARES_SUCCESS ) { - CS_DEBUG("Received ARES_SUCCESS without any useful reply, using NODATA instead"); + CS_DEBUG( "Received ARES_SUCCESS without any useful reply, using NODATA instead" ); status = ARES_ENODATA; } } @@ -324,66 +299,82 @@ static void AresHostCallback( void *pArg, int status, int timeouts, struct hoste } #endif /* HAVE_C_ARES */ -int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockAddr ) +CGetAddrInfo::CGetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockAddr ) + : m_pSock( pSock ), m_csSockAddr( csSockAddr ) { -#ifndef HAVE_IPV6 - // if ipv6 is not enabled, then simply use gethostbyname, nothing special outside of this is done - if( pSock ) - pSock->SetIPv6( false ); - csSockAddr.SetIPv6( false ); - if( __GetHostByName( sHostname, csSockAddr.GetAddr(), 3 ) == 0 ) - return( 0 ); + m_sHostname = sHostname; + m_pAddrRes = NULL; + m_iRet = ETIMEDOUT; +} +CGetAddrInfo::~CGetAddrInfo() +{ + if( m_pAddrRes ) + freeaddrinfo( m_pAddrRes ); + m_pAddrRes = NULL; +} -#else /* HAVE_IPV6 */ - struct addrinfo *res = NULL; - struct addrinfo hints; - memset( (struct addrinfo *)&hints, '\0', sizeof( hints ) ); - hints.ai_family = csSockAddr.GetAFRequire(); +void CGetAddrInfo::Init() +{ + memset(( struct addrinfo * )&m_cHints, '\0', sizeof( m_cHints ) ); + m_cHints.ai_family = m_csSockAddr.GetAFRequire(); - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; + m_cHints.ai_socktype = SOCK_STREAM; + m_cHints.ai_protocol = IPPROTO_TCP; #ifdef AI_ADDRCONFIG // this is suppose to eliminate host from appearing that this system can not support - hints.ai_flags = AI_ADDRCONFIG; + m_cHints.ai_flags = AI_ADDRCONFIG; #endif /* AI_ADDRCONFIG */ - if( pSock && ( pSock->GetType() == Csock::LISTENER || pSock->GetConState() == Csock::CST_BINDVHOST ) ) - { // when doing a dns for bind only, set the AI_PASSIVE flag as suggested by the man page - hints.ai_flags |= AI_PASSIVE; + if( m_pSock && ( m_pSock->GetType() == Csock::LISTENER || m_pSock->GetConState() == Csock::CST_BINDVHOST ) ) + { + // when doing a dns for bind only, set the AI_PASSIVE flag as suggested by the man page + m_cHints.ai_flags |= AI_PASSIVE; } +} - int iRet = getaddrinfo( sHostname.c_str(), NULL, &hints, &res ); - if( iRet == EAI_AGAIN ) - return( EAGAIN ); // need to return telling the user to try again - else if( ( iRet == 0 ) && ( res ) ) - { +int CGetAddrInfo::Process() +{ + m_iRet = getaddrinfo( m_sHostname.c_str(), NULL, &m_cHints, &m_pAddrRes ); + if( m_iRet == EAI_AGAIN ) + return( EAGAIN ); + else if( m_iRet == 0 ) + return( 0 ); + return( ETIMEDOUT ); +} + +int CGetAddrInfo::Finish() +{ + if( m_iRet == 0 && m_pAddrRes ) + { std::list lpTryAddrs; bool bFound = false; - for( struct addrinfo *pRes = res; pRes; pRes = pRes->ai_next ) - { // pass through the list building out a lean list of candidates to try. AI_CONFIGADDR doesn't always seem to work + for( struct addrinfo *pRes = m_pAddrRes; pRes; pRes = pRes->ai_next ) + { + // pass through the list building out a lean list of candidates to try. AI_CONFIGADDR doesn't always seem to work #ifdef __sun - if( ( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP && pRes->ai_protocol != IPPROTO_IP ) ) + if(( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP && pRes->ai_protocol != IPPROTO_IP ) ) #else - if( ( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP ) ) + if(( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP ) ) #endif /* __sun work around broken impl of getaddrinfo */ continue; - - if( ( csSockAddr.GetAFRequire() != CSSockAddr::RAF_ANY ) && ( pRes->ai_family != csSockAddr.GetAFRequire() ) ) + + if(( m_csSockAddr.GetAFRequire() != CSSockAddr::RAF_ANY ) && ( pRes->ai_family != m_csSockAddr.GetAFRequire() ) ) continue; // they requested a special type, so be certain we woop past anything unwanted lpTryAddrs.push_back( pRes ); } - for( std::list::iterator it = lpTryAddrs.begin(); it != lpTryAddrs.end(); ) - { // cycle through these, leaving the last iterator for the outside caller to call, so if there is an error it can call the events + for( std::list::iterator it = lpTryAddrs.begin(); it != lpTryAddrs.end(); ) + { + // cycle through these, leaving the last iterator for the outside caller to call, so if there is an error it can call the events struct addrinfo * pRes = *it; bool bTryConnect = false; if( pRes->ai_family == AF_INET ) { - if( pSock ) - pSock->SetIPv6( false ); - csSockAddr.SetIPv6( false ); - struct sockaddr_in *pTmp = (struct sockaddr_in *)pRes->ai_addr; - memcpy( csSockAddr.GetAddr(), &(pTmp->sin_addr), sizeof( *(csSockAddr.GetAddr()) ) ); - if( pSock && pSock->GetConState() == Csock::CST_DESTDNS && pSock->GetType() == Csock::OUTBOUND ) + if( m_pSock ) + m_pSock->SetIPv6( false ); + m_csSockAddr.SetIPv6( false ); + struct sockaddr_in *pTmp = ( struct sockaddr_in * )pRes->ai_addr; + memcpy( m_csSockAddr.GetAddr(), &( pTmp->sin_addr ), sizeof( *( m_csSockAddr.GetAddr() ) ) ); + if( m_pSock && m_pSock->GetConState() == Csock::CST_DESTDNS && m_pSock->GetType() == Csock::OUTBOUND ) { bTryConnect = true; } @@ -393,14 +384,15 @@ int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockA break; } } +#ifdef HAVE_IPV6 else if( pRes->ai_family == AF_INET6 ) { - if( pSock ) - pSock->SetIPv6( true ); - csSockAddr.SetIPv6( true ); - struct sockaddr_in6 *pTmp = (struct sockaddr_in6 *)pRes->ai_addr; - memcpy( csSockAddr.GetAddr6(), &(pTmp->sin6_addr), sizeof( *(csSockAddr.GetAddr6()) ) ); - if( pSock && pSock->GetConState() == Csock::CST_DESTDNS && pSock->GetType() == Csock::OUTBOUND ) + if( m_pSock ) + m_pSock->SetIPv6( true ); + m_csSockAddr.SetIPv6( true ); + struct sockaddr_in6 *pTmp = ( struct sockaddr_in6 * )pRes->ai_addr; + memcpy( m_csSockAddr.GetAddr6(), &( pTmp->sin6_addr ), sizeof( *( m_csSockAddr.GetAddr6() ) ) ); + if( m_pSock && m_pSock->GetConState() == Csock::CST_DESTDNS && m_pSock->GetType() == Csock::OUTBOUND ) { bTryConnect = true; } @@ -410,18 +402,20 @@ int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockA break; } } +#endif /* HAVE_IPV6 */ it++; // increment the iterator her so we know if its the last element or not if( bTryConnect && it != lpTryAddrs.end() ) - { // save the last attempt for the outer loop, the issue then becomes that the error is thrown on the last failure - if( pSock->CreateSocksFD() && pSock->Connect() ) + { + // save the last attempt for the outer loop, the issue then becomes that the error is thrown on the last failure + if( m_pSock->CreateSocksFD() && m_pSock->Connect() ) { - pSock->SetSkipConnect( true ); // this tells the socket that the connection state has been started + m_pSock->SetSkipConnect( true ); // this tells the socket that the connection state has been started bFound = true; break; } - pSock->CloseSocksFD(); + m_pSock->CloseSocksFD(); } else if( bTryConnect ) { @@ -429,16 +423,45 @@ int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockA } } - freeaddrinfo( res ); if( bFound ) // the data pointed to here is invalid now, but the pointer itself is a good test { return( 0 ); } } -#endif /* ! HAVE_IPV6 */ return( ETIMEDOUT ); } +int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockAddr ) +{ +#ifdef USE_GETHOSTBYNAME + if( pSock ) + pSock->SetIPv6( false ); + csSockAddr.SetIPv6( false ); + if( __GetHostByName( sHostname, csSockAddr.GetAddr(), 3 ) == 0 ) + return( 0 ); +#endif /* USE_GETHOSTBYNAME */ + CGetAddrInfo cInfo( sHostname, pSock, csSockAddr ); + cInfo.Init(); + int iRet = cInfo.Process(); + if( iRet != 0 ) + return( iRet ); + return( cInfo.Finish() ); +} + +int Csock::ConvertAddress( const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, u_short * piPort ) +{ + char szHostname[NI_MAXHOST]; + char szServ[NI_MAXSERV]; + int iRet = getnameinfo(( const struct sockaddr * )pAddr, iAddrLen, szHostname, NI_MAXHOST, szServ, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV ); + if( iRet == 0 ) + { + sIP = szHostname; + if( piPort ) + *piPort = ( u_short )atoi( szServ ); + } + return( iRet ); +} + bool InitCsocket() { #ifdef _WIN32 @@ -463,9 +486,9 @@ bool InitCsocket() void ShutdownCsocket() { #ifdef HAVE_LIBSSL - ERR_remove_state(0); + ERR_remove_state( 0 ); ENGINE_cleanup(); - CONF_modules_unload(1); + CONF_modules_unload( 1 ); ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); @@ -484,14 +507,14 @@ void ShutdownCsocket() bool InitSSL( ECompType eCompressionType ) { SSL_load_error_strings(); - if ( SSL_library_init() != 1 ) + if( SSL_library_init() != 1 ) { CS_DEBUG( "SSL_library_init() failed!" ); return( false ); } #ifndef _WIN32 - if ( access( "/dev/urandom", R_OK ) == 0 ) + if( access( "/dev/urandom", R_OK ) == 0 ) RAND_load_file( "/dev/urandom", 1024 ); else if( access( "/dev/random", R_OK ) == 0 ) RAND_load_file( "/dev/random", 1024 ); @@ -504,26 +527,41 @@ bool InitSSL( ECompType eCompressionType ) COMP_METHOD *cm = NULL; - if ( CT_ZLIB & eCompressionType ) + if( CT_ZLIB & eCompressionType ) { cm = COMP_zlib(); - if ( cm ) + if( cm ) SSL_COMP_add_compression_method( CT_ZLIB, cm ); } - if ( CT_RLE & eCompressionType ) + if( CT_RLE & eCompressionType ) { cm = COMP_rle(); - if ( cm ) + if( cm ) SSL_COMP_add_compression_method( CT_RLE, cm ); } // setting this up once in the begining - g_iCsockSSLIdx = SSL_get_ex_new_index( 0, (void *)"CsockGlobalIndex", NULL, NULL, NULL); + g_iCsockSSLIdx = SSL_get_ex_new_index( 0, ( void * )"CsockGlobalIndex", NULL, NULL, NULL ); return( true ); } +void SSLErrors( const char *filename, u_int iLineNum ) +{ + unsigned long iSSLError = 0; + while(( iSSLError = ERR_get_error() ) != 0 ) + { + CS_DEBUG( "at " << filename << ":" << iLineNum ); + char szError[512]; + memset(( char * ) szError, '\0', 512 ); + ERR_error_string_n( iSSLError, szError, 511 ); + if( *szError ) + CS_DEBUG( szError ); + } +} +#endif /* HAVE_LIBSSL */ + void CSAdjustTVTimeout( struct timeval & tv, long iTimeoutMS ) { if( iTimeoutMS >= 0 ) @@ -538,33 +576,27 @@ void CSAdjustTVTimeout( struct timeval & tv, long iTimeoutMS ) } } -void SSLErrors( const char *filename, u_int iLineNum ) +#define CS_UNKNOWN_ERROR "Unknown Error" +static const char * CS_StrError( int iErrno, char * pszBuff, size_t uBuffLen ) { - unsigned long iSSLError = 0; - while( ( iSSLError = ERR_get_error() ) != 0 ) - { - CS_DEBUG( "at " << filename << ":" << iLineNum ); - char szError[512]; - memset( (char *) szError, '\0', 512 ); - ERR_error_string_n( iSSLError, szError, 511 ); - if ( *szError ) - CS_DEBUG( szError ); - } +#if defined( sgi ) || defined(__sun) || defined(_WIN32) || (defined(__NetBSD_Version__) && __NetBSD_Version__ < 4000000000) + return( strerror( iErrno ) ); +#else + memset( pszBuff, '\0', uBuffLen ); +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined( _GNU_SOURCE ) + if( strerror_r( iErrno, pszBuff, uBuffLen ) == 0 ) + return( pszBuff ); +#else + return( strerror_r( iErrno, pszBuff, uBuffLen ) ); +#endif /* (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined( _GNU_SOURCE ) */ +#endif /* defined( sgi ) || defined(__sun) || defined(_WIN32) || (defined(__NetBSD_Version__) && __NetBSD_Version__ < 4000000000) */ + return( CS_UNKNOWN_ERROR ); } -#endif /* HAVE_LIBSSL */ void __Perror( const CS_STRING & s, const char *pszFile, unsigned int iLineNo ) { -#if defined( sgi ) || defined(__sun) || defined(_WIN32) || (defined(__NetBSD_Version__) && __NetBSD_Version__ < 4000000000) - std::cerr << s << "(" << pszFile << ":" << iLineNo << "): " << strerror( GetSockError() ) << endl; -#else - char buff[512]; - memset( (char *)buff, '\0', 512 ); - if ( strerror_r( GetSockError(), buff, 511 ) == 0 ) - std::cerr << s << "(" << pszFile << ":" << iLineNo << "): " << buff << endl; - else - std::cerr << s << "(" << pszFile << ":" << iLineNo << "): Unknown Error Occured " << endl; -#endif /* __sun */ + char szBuff[0xff]; + std::cerr << s << "(" << pszFile << ":" << iLineNo << "): " << CS_StrError( GetSockError(), szBuff, 0xff ) << endl; } unsigned long long millitime() @@ -578,8 +610,8 @@ unsigned long long millitime() #else struct timeval tv; gettimeofday( &tv, NULL ); - iTime = (unsigned long long )tv.tv_sec * 1000; - iTime += ( (unsigned long long)tv.tv_usec / 1000 ); + iTime = ( unsigned long long )tv.tv_sec * 1000; + iTime += (( unsigned long long )tv.tv_usec / 1000 ); #endif /* _WIN32 */ return( iTime ); } @@ -602,18 +634,18 @@ CCron::CCron() void CCron::run( time_t & iNow ) { - if ( m_bPause ) + if( m_bPause ) return; if( iNow == 0 ) iNow = time( NULL ); - if ( ( m_bActive ) && ( iNow >= m_iTime || m_bRunOnNextCall ) ) + if(( m_bActive ) && ( iNow >= m_iTime || m_bRunOnNextCall ) ) { m_bRunOnNextCall = false; // Setting this here because RunJob() could set it back to true RunJob(); - if ( ( m_iMaxCycles > 0 ) && ( ++m_iCycles >= m_iMaxCycles ) ) + if(( m_iMaxCycles > 0 ) && ( ++m_iCycles >= m_iMaxCycles ) ) m_bActive = false; else m_iTime = iNow + m_iTimeSequence; @@ -651,7 +683,7 @@ void CCron::UnPause() int CCron::GetInterval() const { return( m_iTimeSequence ); } u_int CCron::GetMaxCycles() const { return( m_iMaxCycles ); } -u_int CCron::GetCyclesLeft() const { return( ( m_iMaxCycles > m_iCycles ? ( m_iMaxCycles - m_iCycles ) : 0 ) ); } +u_int CCron::GetCyclesLeft() const { return(( m_iMaxCycles > m_iCycles ? ( m_iMaxCycles - m_iCycles ) : 0 ) ); } bool CCron::isValid() { return( m_bActive ); } const CS_STRING & CCron::GetName() const { return( m_sName ); } @@ -738,11 +770,12 @@ void CSockCommon::Cron() { CCron *pcCron = m_vcCrons[a]; - if ( !pcCron->isValid() ) + if( !pcCron->isValid() ) { CS_Delete( pcCron ); m_vcCrons.erase( m_vcCrons.begin() + a-- ); - } else + } + else pcCron->run( iNow ); } } @@ -756,8 +789,8 @@ void CSockCommon::DelCron( const CS_STRING & sName, bool bDeleteAll, bool bCaseS { for( u_int a = 0; a < m_vcCrons.size(); a++ ) { - int (*Cmp)(const char *, const char *) = ( bCaseSensitive ? strcmp : strcasecmp ); - if ( Cmp( m_vcCrons[a]->GetName().c_str(), sName.c_str() ) == 0 ) + int ( *Cmp )( const char *, const char * ) = ( bCaseSensitive ? strcmp : strcasecmp ); + if( Cmp( m_vcCrons[a]->GetName().c_str(), sName.c_str() ) == 0 ) { m_vcCrons[a]->Stop(); CS_Delete( m_vcCrons[a] ); @@ -770,7 +803,7 @@ void CSockCommon::DelCron( const CS_STRING & sName, bool bDeleteAll, bool bCaseS void CSockCommon::DelCron( u_int iPos ) { - if ( iPos < m_vcCrons.size() ) + if( iPos < m_vcCrons.size() ) { m_vcCrons[iPos]->Stop(); CS_Delete( m_vcCrons[iPos] ); @@ -782,7 +815,7 @@ void CSockCommon::DelCronByAddr( CCron *pcCron ) { for( u_int a = 0; a < m_vcCrons.size(); a++ ) { - if ( m_vcCrons[a] == pcCron ) + if( m_vcCrons[a] == pcCron ) { m_vcCrons[a]->Stop(); CS_Delete( m_vcCrons[a] ); @@ -822,6 +855,12 @@ Csock *Csock::GetSockObj( const CS_STRING & sHostname, u_short iPort ) Csock::~Csock() { +#ifdef _WIN32 + // prevent successful closesocket() calls and such from + // overwriting any possible previous errors. + int iOldError = ::WSAGetLastError(); +#endif /* _WIN32 */ + #ifdef HAVE_C_ARES if( m_pARESChannel ) ares_cancel( m_pARESChannel ); @@ -835,17 +874,21 @@ Csock::~Csock() CloseSocksFD(); +#ifdef _WIN32 + ::WSASetLastError( iOldError ); +#endif /* _WIN32 */ } void Csock::CloseSocksFD() { - if ( m_iReadSock != m_iWriteSock ) + if( m_iReadSock != m_iWriteSock ) { if( m_iReadSock != CS_INVALID_SOCK ) CS_CLOSE( m_iReadSock ); if( m_iWriteSock != CS_INVALID_SOCK ) CS_CLOSE( m_iWriteSock ); - } else if( m_iReadSock != CS_INVALID_SOCK ) + } + else if( m_iReadSock != CS_INVALID_SOCK ) CS_CLOSE( m_iReadSock ); m_iReadSock = CS_INVALID_SOCK; @@ -878,6 +921,7 @@ void Csock::Copy( const Csock & cCopy ) m_iReadSock = cCopy.m_iReadSock; m_iWriteSock = cCopy.m_iWriteSock; m_iTimeout = cCopy.m_iTimeout; + m_iMaxConns = cCopy.m_iMaxConns; m_iConnType = cCopy.m_iConnType; m_iMethod = cCopy.m_iMethod; m_bUseSSL = cCopy.m_bUseSSL; @@ -1007,30 +1051,37 @@ Csock & Csock::operator<<( double i ) bool Csock::Connect() { if( m_bSkipConnect ) - { // this was already called, so skipping now. this is to allow easy pass through - if ( m_eConState != CST_OK ) + { + // this was already called, so skipping now. this is to allow easy pass through + if( m_eConState != CST_OK ) { m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); } return( true ); } - // set it none blocking +#ifndef _WIN32 set_non_blocking( m_iReadSock ); +#else + if( !GetIPv6() ) + set_non_blocking( m_iReadSock ); + // non-blocking sockets on Win32 do *not* return ENETUNREACH/EHOSTUNREACH if there's no IPv6 gateway. + // we need those error codes for the v4 fallback in GetAddrInfo! +#endif /* _WIN32 */ m_iConnType = OUTBOUND; int ret = -1; if( !GetIPv6() ) - ret = connect( m_iReadSock, (struct sockaddr *)m_address.GetSockAddr(), m_address.GetSockAddrLen() ); + ret = connect( m_iReadSock, ( struct sockaddr * )m_address.GetSockAddr(), m_address.GetSockAddrLen() ); #ifdef HAVE_IPV6 else - ret = connect( m_iReadSock, (struct sockaddr *)m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ); + ret = connect( m_iReadSock, ( struct sockaddr * )m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ); #endif /* HAVE_IPV6 */ #ifndef _WIN32 - if ( ( ret == -1 ) && ( GetSockError() != EINPROGRESS ) ) + if( ret == -1 && GetSockError() != EINPROGRESS ) #else - if ( ( ret == -1 ) && ( GetSockError() != EINPROGRESS ) && ( GetSockError() != WSAEWOULDBLOCK ) ) + if( ret == -1 && GetSockError() != EINPROGRESS && GetSockError() != WSAEWOULDBLOCK ) #endif /* _WIN32 */ { @@ -1038,7 +1089,13 @@ bool Csock::Connect() return( false ); } - if ( m_eConState != CST_OK ) +#ifdef _WIN32 + // do what we didn't do above since connect() is now over! + if( GetIPv6() ) + set_non_blocking( m_iReadSock ); +#endif /* _WIN32 */ + + if( m_eConState != CST_OK ) { m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); } @@ -1047,58 +1104,110 @@ bool Csock::Connect() } -bool Csock::Listen( u_short 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, bool bDetach ) { m_iConnType = LISTENER; m_iTimeout = iTimeout; - m_sBindHost = sBindHost; - if ( !sBindHost.empty() ) + m_iMaxConns = iMaxConns; + + SetConState( Csock::CST_OK ); + if( !m_sBindHost.empty() ) { - // forcing this to block regardless of resolver overloading, because listen is not currently setup to - // to handle nonblocking operations. This is used to resolve local ip's for binding anyways and should be instant - if( ::GetAddrInfo( sBindHost, this, m_address ) != 0 ) - return( false ); + if( bDetach ) + { + int iRet = GetAddrInfo( m_sBindHost, m_address ); + if( iRet == ETIMEDOUT ) + { + CallSockError( EADDRNOTAVAIL ); + return( false ); + } + else if( iRet == EAGAIN ) + { + SetConState( Csock::CST_BINDVHOST ); + return( true ); + } + } + else + { + // if not detaching, then must block to do DNS resolution, so might as well use internal resolver + if( ::GetAddrInfo( m_sBindHost, this, m_address ) != 0 ) + { + CallSockError( EADDRNOTAVAIL ); + return( false ); + } + } } m_iReadSock = m_iWriteSock = CreateSocket( true ); - if ( m_iReadSock == CS_INVALID_SOCK ) + if( m_iReadSock == CS_INVALID_SOCK ) + { + CallSockError( EBADF ); return( false ); + } #ifdef HAVE_IPV6 -// there's no IPPROTO_IPV6 below Win XP. - KiNgMaR -#if (!defined(_WIN32) && defined(IPV6_V6ONLY)) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0501) - if( GetIPv6() ) +#ifdef _WIN32 +# ifndef IPPROTO_IPV6 +# define IPPROTO_IPV6 41 /* define for apps with _WIN32_WINNT < 0x0501 (XP) */ +# endif /* !IPPROTO_IPV6 */ + /* check for IPV6_V6ONLY support at runtime */ + OSVERSIONINFOW lvi = { sizeof( OSVERSIONINFOW ), 0 }; + if( ::GetVersionExW( &lvi ) && lvi.dwMajorVersion >= 6 ) // IPV6_V6ONLY is supported on Windows Vista or later. { - // per RFC3493#5.3 - const int on = ( m_address.GetAFRequire() == CSSockAddr::RAF_INET6 ? 1 : 0 ); - if( setsockopt( m_iReadSock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof( on ) ) != 0 ) - PERROR( "IPV6_V6ONLY" ); +#endif /* _WIN32 */ + if( GetIPv6() ) + { + // per RFC3493#5.3 + const int on = ( m_address.GetAFRequire() == CSSockAddr::RAF_INET6 ? 1 : 0 ); + if( setsockopt( m_iReadSock, IPPROTO_IPV6, IPV6_V6ONLY, ( char * )&on, sizeof( on ) ) != 0 ) + PERROR( "IPV6_V6ONLY" ); + } +#ifdef _WIN32 } -#endif /* IPV6_V6ONLY */ +#endif /* _WIN32 */ #endif /* HAVE_IPV6 */ m_address.SinFamily(); m_address.SinPort( iPort ); if( !GetIPv6() ) { - if ( bind( m_iReadSock, (struct sockaddr *) m_address.GetSockAddr(), m_address.GetSockAddrLen() ) == -1 ) + if( bind( m_iReadSock, ( struct sockaddr * ) m_address.GetSockAddr(), m_address.GetSockAddrLen() ) == -1 ) + { + CallSockError( GetSockError() ); return( false ); + } } #ifdef HAVE_IPV6 else { - if ( bind( m_iReadSock, (struct sockaddr *) m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ) == -1 ) + if( bind( m_iReadSock, ( struct sockaddr * ) m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ) == -1 ) + { + CallSockError( GetSockError() ); return( false ); + } } #endif /* HAVE_IPV6 */ - if ( listen( m_iReadSock, iMaxConns ) == -1 ) + if( listen( m_iReadSock, iMaxConns ) == -1 ) + { + CallSockError( GetSockError() ); return( false ); + } // set it none blocking set_non_blocking( m_iReadSock ); + if( m_uPort == 0 || m_sBindHost.size() ) + { + struct sockaddr_storage cAddr; + socklen_t iAddrLen = sizeof( cAddr ); + if( getsockname( m_iReadSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) + { + ConvertAddress( &cAddr, iAddrLen, m_sBindHost, &m_uPort ); + } + } + Listening( m_sBindHost, m_uPort ); return( true ); } @@ -1106,42 +1215,23 @@ bool Csock::Listen( u_short iPort, int iMaxConns, const CS_STRING & sBindHost, u cs_sock_t Csock::Accept( CS_STRING & sHost, u_short & iRPort ) { cs_sock_t iSock = CS_INVALID_SOCK; - if( !GetIPv6() ) + struct sockaddr_storage cAddr; + socklen_t iAddrLen = sizeof( cAddr ); + iSock = accept( m_iReadSock, ( struct sockaddr * )&cAddr, &iAddrLen ); + if( iSock != CS_INVALID_SOCK && getpeername( iSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { - struct sockaddr_in client; - socklen_t clen = sizeof( client ); - iSock = accept( m_iReadSock, (struct sockaddr *) &client, &clen ); - if( iSock != CS_INVALID_SOCK ) - { - getpeername( iSock, (struct sockaddr *) &client, &clen ); - sHost = ConvertAddress( &client.sin_addr, false ); - iRPort = ntohs( client.sin_port ); - } + ConvertAddress( &cAddr, iAddrLen, sHost, &iRPort ); } -#ifdef HAVE_IPV6 - else - { - struct sockaddr_in6 client; - socklen_t clen = sizeof( client ); - iSock = accept( m_iReadSock, (struct sockaddr *) &client, &clen ); - if( iSock != CS_INVALID_SOCK ) - { - getpeername( iSock, (struct sockaddr *) &client, &clen ); - sHost = ConvertAddress( &client.sin6_addr, true ); - iRPort = ntohs( client.sin6_port ); - } - } -#endif /* HAVE_IPV6 */ - if ( iSock != CS_INVALID_SOCK ) + if( iSock != CS_INVALID_SOCK ) { // Make it close-on-exec set_close_on_exec( iSock ); - // make it none blocking + // make it none blocking set_non_blocking( iSock ); - if ( !ConnectionFrom( sHost, iRPort ) ) + if( !ConnectionFrom( sHost, iRPort ) ) { CS_CLOSE( iSock ); iSock = CS_INVALID_SOCK; @@ -1155,20 +1245,20 @@ cs_sock_t Csock::Accept( CS_STRING & sHost, u_short & iRPort ) bool Csock::AcceptSSL() { #ifdef HAVE_LIBSSL - if ( !m_ssl ) - if ( !SSLServerSetup() ) + if( !m_ssl ) + if( !SSLServerSetup() ) return( false ); int err = SSL_accept( m_ssl ); - if ( err == 1 ) + if( err == 1 ) { return( true ); } int sslErr = SSL_get_error( m_ssl, err ); - if ( ( sslErr == SSL_ERROR_WANT_READ ) || ( sslErr == SSL_ERROR_WANT_WRITE ) ) + if( sslErr == SSL_ERROR_WANT_READ || sslErr == SSL_ERROR_WANT_WRITE ) return( true ); SSLErrors( __FILE__, __LINE__ ); @@ -1186,7 +1276,7 @@ bool Csock::SSLClientSetup() FREE_CTX(); #ifdef _WIN64 - if( m_iReadSock != (int)m_iReadSock || m_iWriteSock != (int)m_iWriteSock ) + 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" ); @@ -1196,61 +1286,62 @@ bool Csock::SSLClientSetup() switch( m_iMethod ) { - case SSL3: - m_ssl_ctx = SSL_CTX_new ( SSLv3_client_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... SSLv3_client_method failed!" ); - return( false ); - } - break; - case TLS1: - m_ssl_ctx = SSL_CTX_new ( TLSv1_client_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... TLSv1_client_method failed!" ); - return( false ); - } - break; - case SSL2: + case SSL3: + m_ssl_ctx = SSL_CTX_new( SSLv3_client_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... SSLv3_client_method failed!" ); + return( false ); + } + break; + case TLS1: + m_ssl_ctx = SSL_CTX_new( TLSv1_client_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... TLSv1_client_method failed!" ); + return( false ); + } + break; + case SSL2: #ifndef OPENSSL_NO_SSL2 - m_ssl_ctx = SSL_CTX_new ( SSLv2_client_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... SSLv2_client_method failed!" ); - return( false ); - } - break; + m_ssl_ctx = SSL_CTX_new( SSLv2_client_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... SSLv2_client_method failed!" ); + return( false ); + } + break; #endif - /* Fall through if SSL2 is disabled */ - case SSL23: - default: - m_ssl_ctx = SSL_CTX_new ( SSLv23_client_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... SSLv23_client_method failed!" ); - return( false ); - } - break; + /* Fall through if SSL2 is disabled */ + case SSL23: + default: + m_ssl_ctx = SSL_CTX_new( SSLv23_client_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... SSLv23_client_method failed!" ); + return( false ); + } + break; } SSL_CTX_set_default_verify_paths( m_ssl_ctx ); - if ( !m_sPemFile.empty() ) - { // are we sending a client cerificate ? + if( !m_sPemFile.empty() ) + { + // are we sending a client cerificate ? SSL_CTX_set_default_passwd_cb( m_ssl_ctx, PemPassCB ); - SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, (void *)this ); + SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, ( void * )this ); // // set up the CTX - if ( SSL_CTX_use_certificate_file( m_ssl_ctx, m_sPemFile.c_str() , SSL_FILETYPE_PEM ) <= 0 ) + if( SSL_CTX_use_certificate_file( m_ssl_ctx, m_sPemFile.c_str() , SSL_FILETYPE_PEM ) <= 0 ) { CS_DEBUG( "Error with PEM file [" << m_sPemFile << "]" ); SSLErrors( __FILE__, __LINE__ ); } - if ( SSL_CTX_use_PrivateKey_file( m_ssl_ctx, m_sPemFile.c_str(), SSL_FILETYPE_PEM ) <= 0 ) + if( SSL_CTX_use_PrivateKey_file( m_ssl_ctx, m_sPemFile.c_str(), SSL_FILETYPE_PEM ) <= 0 ) { CS_DEBUG( "Error with PEM file [" << m_sPemFile << "]" ); SSLErrors( __FILE__, __LINE__ ); @@ -1258,11 +1349,11 @@ bool Csock::SSLClientSetup() } m_ssl = SSL_new( m_ssl_ctx ); - if ( !m_ssl ) + if( !m_ssl ) return( false ); - SSL_set_rfd( m_ssl, (int)m_iReadSock ); - SSL_set_wfd( m_ssl, (int)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 ); @@ -1282,7 +1373,7 @@ bool Csock::SSLServerSetup() FREE_CTX(); #ifdef _WIN64 - if( m_iReadSock != (int)m_iReadSock || m_iWriteSock != (int)m_iWriteSock ) + 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" ); @@ -1293,52 +1384,52 @@ bool Csock::SSLServerSetup() switch( m_iMethod ) { - case SSL3: - m_ssl_ctx = SSL_CTX_new ( SSLv3_server_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... SSLv3_server_method failed!" ); - return( false ); - } - break; + case SSL3: + m_ssl_ctx = SSL_CTX_new( SSLv3_server_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... SSLv3_server_method failed!" ); + return( false ); + } + break; - case TLS1: - m_ssl_ctx = SSL_CTX_new ( TLSv1_server_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... TLSv1_server_method failed!" ); - return( false ); - } - break; + case TLS1: + m_ssl_ctx = SSL_CTX_new( TLSv1_server_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... TLSv1_server_method failed!" ); + return( false ); + } + break; #ifndef OPENSSL_NO_SSL2 - case SSL2: - m_ssl_ctx = SSL_CTX_new ( SSLv2_server_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... SSLv2_server_method failed!" ); - return( false ); - } - break; + case SSL2: + m_ssl_ctx = SSL_CTX_new( SSLv2_server_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... SSLv2_server_method failed!" ); + return( false ); + } + break; #endif - /* Fall through if SSL2 is disabled */ - case SSL23: - default: - m_ssl_ctx = SSL_CTX_new ( SSLv23_server_method() ); - if ( !m_ssl_ctx ) - { - CS_DEBUG( "WARNING: MakeConnection .... SSLv23_server_method failed!" ); - return( false ); - } - break; + /* Fall through if SSL2 is disabled */ + case SSL23: + default: + m_ssl_ctx = SSL_CTX_new( SSLv23_server_method() ); + if( !m_ssl_ctx ) + { + CS_DEBUG( "WARNING: MakeConnection .... SSLv23_server_method failed!" ); + return( false ); + } + break; } SSL_CTX_set_default_verify_paths( m_ssl_ctx ); // set the pemfile password SSL_CTX_set_default_passwd_cb( m_ssl_ctx, PemPassCB ); - SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, (void *)this ); + SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, ( void * )this ); - if ( ( m_sPemFile.empty() ) || ( access( m_sPemFile.c_str(), R_OK ) != 0 ) ) + if( m_sPemFile.empty() || access( m_sPemFile.c_str(), R_OK ) != 0 ) { CS_DEBUG( "There is a problem with [" << m_sPemFile << "]" ); return( false ); @@ -1384,7 +1475,8 @@ bool Csock::SSLServerSetup() DH_free( dhParams ); } else - { // Presumably PEM_read_DHparams failed, as there was no DH structure. Clearing those errors here so they are removed off the stack + { + // Presumably PEM_read_DHparams failed, as there was no DH structure. Clearing those errors here so they are removed off the stack ERR_clear_error(); } @@ -1397,14 +1489,14 @@ bool Csock::SSLServerSetup() // // setup the SSL m_ssl = SSL_new( m_ssl_ctx ); - if ( !m_ssl ) + if( !m_ssl ) return( false ); // Call for client Verification - SSL_set_rfd( m_ssl, (int)m_iReadSock ); - SSL_set_wfd( m_ssl, (int)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 ) + if( m_iRequireClientCertFlags ) { SSL_set_verify( m_ssl, m_iRequireClientCertFlags, ( m_pCerVerifyCB ? m_pCerVerifyCB : CertVerifyCB ) ); SSL_set_ex_data( m_ssl, GetCsockClassIdx(), this ); @@ -1438,7 +1530,7 @@ bool Csock::ConnectSSL() bool bPass = true; int iErr = SSL_connect( m_ssl ); - if ( iErr != 1 ) + if( iErr != 1 ) { int sslErr = SSL_get_error( m_ssl, iErr ); bPass = false; @@ -1446,7 +1538,7 @@ bool Csock::ConnectSSL() bPass = true; #ifdef _WIN32 else if( sslErr == SSL_ERROR_SYSCALL && iErr < 0 && GetLastError() == WSAENOTCONN ) - { + { // this seems to be an issue with win32 only. I've seen it happen on slow connections // the issue is calling this before select(), which isn't a problem on unix. Allowing this // to pass in this case is fine because subsequent ssl transactions will occur and the handshake @@ -1454,10 +1546,11 @@ bool Csock::ConnectSSL() bPass = true; } #endif /* _WIN32 */ - } else + } + else bPass = true; - if ( m_eConState != CST_OK ) + if( m_eConState != CST_OK ) m_eConState = CST_OK; return( bPass ); #else @@ -1467,14 +1560,14 @@ bool Csock::ConnectSSL() bool Csock::AllowWrite( unsigned long long & iNOW ) const { - if ( ( m_iMaxBytes > 0 ) && ( m_iMaxMilliSeconds > 0 ) ) + if( m_iMaxBytes > 0 && m_iMaxMilliSeconds > 0 ) { if( iNOW == 0 ) iNOW = millitime(); if( m_iLastSend < m_iMaxBytes ) return( true ); // allow sending if our out buffer was less than what we can send - if ( ( iNOW - m_iLastSendTime ) < m_iMaxMilliSeconds ) + if(( iNOW - m_iLastSendTime ) < m_iMaxMilliSeconds ) return( false ); } return( true ); @@ -1484,10 +1577,10 @@ bool Csock::Write( const char *data, size_t len ) { m_sSend.append( data, len ); - if ( m_sSend.empty() ) + if( m_sSend.empty() ) return( true ); - if ( m_eConState != CST_OK ) + if( m_eConState != CST_OK ) return( true ); // rate shaping @@ -1501,36 +1594,38 @@ bool Csock::Write( const char *data, size_t len ) } else #endif /* HAVE_LIBSSL */ - if ( ( m_iMaxBytes > 0 ) && ( m_iMaxMilliSeconds > 0 ) ) - { - unsigned long long iNOW = millitime(); - // figure out the shaping here - // if NOW - m_iLastSendTime > m_iMaxMilliSeconds then send a full length of ( iBytesToSend ) - if ( ( iNOW - m_iLastSendTime ) > m_iMaxMilliSeconds ) + if( m_iMaxBytes > 0 && m_iMaxMilliSeconds > 0 ) { - m_iLastSendTime = iNOW; - iBytesToSend = m_iMaxBytes; - m_iLastSend = 0; + unsigned long long iNOW = millitime(); + // figure out the shaping here + // if NOW - m_iLastSendTime > m_iMaxMilliSeconds then send a full length of ( iBytesToSend ) + if(( iNOW - m_iLastSendTime ) > m_iMaxMilliSeconds ) + { + m_iLastSendTime = iNOW; + iBytesToSend = m_iMaxBytes; + m_iLastSend = 0; - } else // otherwise send m_iMaxBytes - m_iLastSend - iBytesToSend = m_iMaxBytes - m_iLastSend; + } + else // otherwise send m_iMaxBytes - m_iLastSend + iBytesToSend = m_iMaxBytes - m_iLastSend; - // take which ever is lesser - if ( m_sSend.length() < iBytesToSend ) - iBytesToSend = m_sSend.length(); + // take which ever is lesser + if( m_sSend.length() < iBytesToSend ) + iBytesToSend = m_sSend.length(); - // add up the bytes sent - m_iLastSend += iBytesToSend; + // add up the bytes sent + m_iLastSend += iBytesToSend; - // so, are we ready to send anything ? - if ( iBytesToSend == 0 ) - return( true ); + // so, are we ready to send anything ? + if( iBytesToSend == 0 ) + return( true ); - } else - iBytesToSend = m_sSend.length(); + } + else + iBytesToSend = m_sSend.length(); #ifdef HAVE_LIBSSL - if ( m_bUseSSL ) + if( m_bUseSSL ) { if( !m_ssl ) { @@ -1538,12 +1633,12 @@ bool Csock::Write( const char *data, size_t len ) return( false ); } - if ( m_sSSLBuffer.empty() ) // on retrying to write data, ssl wants the data in the SAME spot and the SAME size + if( m_sSSLBuffer.empty() ) // on retrying to write data, ssl wants the data in the SAME spot and the SAME size m_sSSLBuffer.append( m_sSend.data(), iBytesToSend ); - int iErr = SSL_write( m_ssl, m_sSSLBuffer.data(), (int)m_sSSLBuffer.length() ); + int iErr = SSL_write( m_ssl, m_sSSLBuffer.data(), ( int )m_sSSLBuffer.length() ); - if ( ( iErr < 0 ) && ( GetSockError() == ECONNREFUSED ) ) + if( iErr < 0 && GetSockError() == ECONNREFUSED ) { // If ret == -1, the underlying BIO reported an I/O error (man SSL_get_error) ConnectionRefused(); @@ -1552,42 +1647,42 @@ bool Csock::Write( const char *data, size_t len ) switch( SSL_get_error( m_ssl, iErr ) ) { - case SSL_ERROR_NONE: + case SSL_ERROR_NONE: m_bsslEstablished = true; // all ok break; - case SSL_ERROR_ZERO_RETURN: - { - // weird closer alert - return( false ); - } - - case SSL_ERROR_WANT_READ: - // retry - break; - - case SSL_ERROR_WANT_WRITE: - // retry - break; - - case SSL_ERROR_SSL: - { - SSLErrors( __FILE__, __LINE__ ); - return( false ); - } + case SSL_ERROR_ZERO_RETURN: + { + // weird closer alert + return( false ); } - if ( iErr > 0 ) + case SSL_ERROR_WANT_READ: + // retry + break; + + case SSL_ERROR_WANT_WRITE: + // retry + break; + + case SSL_ERROR_SSL: + { + SSLErrors( __FILE__, __LINE__ ); + return( false ); + } + } + + if( iErr > 0 ) { m_sSSLBuffer.clear(); m_sSend.erase( 0, iErr ); // reset the timer on successful write (we have to set it here because the write // bit might not always be set, so need to trigger) - if ( TMO_WRITE & GetTimeoutType() ) + if( TMO_WRITE & GetTimeoutType() ) ResetTimer(); - m_iBytesWritten += (unsigned long long)iErr; + m_iBytesWritten += ( unsigned long long )iErr; } return( true ); @@ -1599,27 +1694,27 @@ bool Csock::Write( const char *data, size_t len ) cs_ssize_t bytes = write( m_iWriteSock, m_sSend.data(), iBytesToSend ); #endif /* _WIN32 */ - if ( ( bytes == -1 ) && ( GetSockError() == ECONNREFUSED ) ) + if( bytes == -1 && GetSockError() == ECONNREFUSED ) { ConnectionRefused(); return( false ); } #ifdef _WIN32 - if ( ( bytes <= 0 ) && ( GetSockError() != WSAEWOULDBLOCK ) ) + if( bytes <= 0 && GetSockError() != WSAEWOULDBLOCK ) return( false ); #else - if ( ( bytes <= 0 ) && ( GetSockError() != EAGAIN ) ) + if( bytes <= 0 && GetSockError() != EAGAIN ) return( false ); #endif /* _WIN32 */ // delete the bytes we sent - if ( bytes > 0 ) + if( bytes > 0 ) { m_sSend.erase( 0, bytes ); - if ( TMO_WRITE & GetTimeoutType() ) + if( TMO_WRITE & GetTimeoutType() ) ResetTimer(); // reset the timer on successful write - m_iBytesWritten += (unsigned long long)bytes; + m_iBytesWritten += ( unsigned long long )bytes; } return( true ); @@ -1634,7 +1729,7 @@ cs_ssize_t Csock::Read( char *data, size_t len ) { cs_ssize_t bytes = 0; - if ( IsReadPaused() && SslIsEstablished() ) + if( IsReadPaused() && SslIsEstablished() ) return( READ_EAGAIN ); // allow the handshake to complete first #ifdef HAVE_LIBSSL @@ -1646,7 +1741,7 @@ cs_ssize_t Csock::Read( char *data, size_t len ) return( READ_ERR ); } - bytes = SSL_read( m_ssl, data, (int)len ); + bytes = SSL_read( m_ssl, data, ( int )len ); if( bytes >= 0 ) m_bsslEstablished = true; // this means all is good in the realm of ssl } @@ -1657,27 +1752,27 @@ cs_ssize_t Csock::Read( char *data, size_t len ) #else bytes = read( m_iReadSock, data, len ); #endif /* _WIN32 */ - if ( bytes == -1 ) + if( bytes == -1 ) { - if ( GetSockError() == ECONNREFUSED ) + if( GetSockError() == ECONNREFUSED ) return( READ_CONNREFUSED ); - if ( GetSockError() == ETIMEDOUT ) + if( GetSockError() == ETIMEDOUT ) return( READ_TIMEDOUT ); - if ( ( GetSockError() == EINTR ) || ( GetSockError() == EAGAIN ) ) + if( GetSockError() == EINTR || GetSockError() == EAGAIN ) return( READ_EAGAIN ); #ifdef _WIN32 - if ( GetSockError() == WSAEWOULDBLOCK ) + if( GetSockError() == WSAEWOULDBLOCK ) return( READ_EAGAIN ); #endif /* _WIN32 */ #ifdef HAVE_LIBSSL - if ( m_ssl ) + if( m_ssl ) { - int iErr = SSL_get_error( m_ssl, (int)bytes ); - if ( ( iErr != SSL_ERROR_WANT_READ ) && ( iErr != SSL_ERROR_WANT_WRITE ) ) + int iErr = SSL_get_error( m_ssl, ( int )bytes ); + if( iErr != SSL_ERROR_WANT_READ && iErr != SSL_ERROR_WANT_WRITE ) return( READ_ERR ); else return( READ_EAGAIN ); @@ -1688,98 +1783,51 @@ cs_ssize_t Csock::Read( char *data, size_t len ) } if( bytes > 0 ) // becareful not to add negative bytes :P - m_iBytesRead += (unsigned long long)bytes; + m_iBytesRead += ( unsigned long long )bytes; return( bytes ); } CS_STRING Csock::GetLocalIP() { - if ( !m_sLocalIP.empty() ) + if( !m_sLocalIP.empty() ) return( m_sLocalIP ); cs_sock_t iSock = GetSock(); - if ( iSock == CS_INVALID_SOCK ) + if( iSock == CS_INVALID_SOCK ) return( "" ); - if( !GetIPv6() ) + struct sockaddr_storage cAddr; + socklen_t iAddrLen = sizeof( cAddr ); + if( getsockname( iSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { - char straddr[INET_ADDRSTRLEN]; - struct sockaddr_in mLocalAddr; - socklen_t mLocalLen = sizeof( mLocalAddr ); - if ( ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) - && ( inet_ntop( AF_INET, &mLocalAddr.sin_addr, straddr, sizeof(straddr) ) ) ) - { - m_sLocalIP = straddr; - } + ConvertAddress( &cAddr, iAddrLen, m_sLocalIP, &m_iLocalPort ); } -#ifdef HAVE_IPV6 - else - { - char straddr[INET6_ADDRSTRLEN]; - struct sockaddr_in6 mLocalAddr; - socklen_t mLocalLen = sizeof( mLocalAddr ); - if ( ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) - && ( inet_ntop( AF_INET6, &mLocalAddr.sin6_addr, straddr, sizeof(straddr) ) ) ) - { - m_sLocalIP = straddr; - } - } -#endif /* HAVE_IPV6 */ return( m_sLocalIP ); } CS_STRING Csock::GetRemoteIP() { - if ( !m_sRemoteIP.empty() ) + if( !m_sRemoteIP.empty() ) return( m_sRemoteIP ); cs_sock_t iSock = GetSock(); - if ( iSock == CS_INVALID_SOCK ) + if( iSock == CS_INVALID_SOCK ) return( "" ); - if( !GetIPv6() ) + struct sockaddr_storage cAddr; + socklen_t iAddrLen = sizeof( cAddr ); + if( getpeername( iSock, ( struct sockaddr * )&cAddr, &iAddrLen ) == 0 ) { - struct sockaddr_in mRemoteAddr; - socklen_t mRemoteLen = sizeof( mRemoteAddr ); - if ( getpeername( iSock, (struct sockaddr *) &mRemoteAddr, &mRemoteLen ) == 0 ) - m_sRemoteIP = ConvertAddress( &mRemoteAddr.sin_addr, false ); + ConvertAddress( &cAddr, iAddrLen, m_sRemoteIP, &m_iRemotePort ); } -#ifdef HAVE_IPV6 - else - { - struct sockaddr_in6 mRemoteAddr; - socklen_t mRemoteLen = sizeof( mRemoteAddr ); - if ( getpeername( iSock, (struct sockaddr *) &mRemoteAddr, &mRemoteLen ) == 0 ) - m_sRemoteIP = ConvertAddress( &mRemoteAddr.sin6_addr, true ); - } -#endif /* HAVE_IPV6 */ return( m_sRemoteIP ); } -CS_STRING Csock::ConvertAddress( void *addr, bool bIPv6 ) -{ - CS_STRING sRet; - - if( !bIPv6 ) - { - in_addr *p = (in_addr*) addr; - sRet = inet_ntoa(*p); - } - else - { - char straddr[INET6_ADDRSTRLEN]; - if( inet_ntop( AF_INET6, addr, straddr, sizeof(straddr) ) > 0 ) - sRet = straddr; - } - - return( sRet ); -} - bool Csock::IsConnected() const { return( m_bIsConnected ); } void Csock::SetIsConnected( bool b ) { m_bIsConnected = b; } @@ -1806,6 +1854,16 @@ void Csock::SetTimeout( int iTimeout, u_int iTimeoutType ) m_iTimeout = iTimeout; } +void Csock::CallSockError( int iErrno, const CS_STRING & sDescription ) +{ + if( sDescription.size() ) + SockError( iErrno, sDescription ); + else + { + char szBuff[0xff]; + SockError( iErrno, CS_StrError( iErrno, szBuff, 0xff ) ); + } +} void Csock::SetTimeoutType( u_int iTimeoutType ) { m_iTimeoutType = iTimeoutType; } int Csock::GetTimeout() const { return m_iTimeout; } u_int Csock::GetTimeoutType() const { return( m_iTimeoutType ); } @@ -1818,7 +1876,7 @@ bool Csock::CheckTimeout( time_t iNow ) return( false ); } - if ( IsReadPaused() ) + if( IsReadPaused() ) return( false ); time_t iDiff = 0; @@ -1832,7 +1890,7 @@ bool Csock::CheckTimeout( time_t iNow ) m_iLastCheckTimeoutTime = iNow; } - if ( m_iTimeout > 0 ) + if( m_iTimeout > 0 ) { // this is basically to help stop a clock adjust ahead, stuff could reset immediatly on a clock jump // otherwise @@ -1857,30 +1915,31 @@ bool Csock::CheckTimeout( time_t iNow ) void Csock::PushBuff( const char *data, size_t len, bool bStartAtZero ) { - if ( !m_bEnableReadLine ) + if( !m_bEnableReadLine ) return; // If the ReadLine event is disabled, just ditch here size_t iStartPos = ( m_sbuffer.empty() || bStartAtZero ? 0 : m_sbuffer.length() - 1 ); - if ( data ) + if( data ) m_sbuffer.append( data, len ); - while( !m_bPauseRead && GetCloseType() == CLT_DONT ) + while( !m_bPauseRead && GetCloseType() == CLT_DONT ) { CS_STRING::size_type iFind = m_sbuffer.find( "\n", iStartPos ); - if ( iFind != CS_STRING::npos ) + if( iFind != CS_STRING::npos ) { CS_STRING sBuff = m_sbuffer.substr( 0, iFind + 1 ); // read up to(including) the newline m_sbuffer.erase( 0, iFind + 1 ); // erase past the newline ReadLine( sBuff ); iStartPos = 0; // reset this back to 0, since we need to look for the next newline here. - } else + } + else break; } - if ( ( m_iMaxStoredBufferLength > 0 ) && ( m_sbuffer.length() > m_iMaxStoredBufferLength ) ) + if( m_iMaxStoredBufferLength > 0 && m_sbuffer.length() > m_iMaxStoredBufferLength ) ReachedMaxBuffer(); // call the max read buffer event } @@ -1906,79 +1965,35 @@ double Csock::GetAvgRead( unsigned long long iSample ) { unsigned long long iDifference = ( millitime() - m_iStartTime ); - if ( ( m_iBytesRead == 0 ) || ( iSample > iDifference ) ) - return( (double)m_iBytesRead ); + if( m_iBytesRead == 0 || iSample > iDifference ) + return(( double )m_iBytesRead ); - return( ( (double)m_iBytesRead / ( (double)iDifference / (double)iSample ) ) ); + return((( double )m_iBytesRead / (( double )iDifference / ( double )iSample ) ) ); } double Csock::GetAvgWrite( unsigned long long iSample ) { unsigned long long iDifference = ( millitime() - m_iStartTime ); - if ( ( m_iBytesWritten == 0 ) || ( iSample > iDifference ) ) - return( (double)m_iBytesWritten ); + if( m_iBytesWritten == 0 || iSample > iDifference ) + return(( double )m_iBytesWritten ); - return( ( (double)m_iBytesWritten / ( (double)iDifference / (double)iSample ) ) ); + return((( double )m_iBytesWritten / (( double )iDifference / ( double )iSample ) ) ); } u_short Csock::GetRemotePort() { - if ( m_iRemotePort > 0 ) + if( m_iRemotePort > 0 ) return( m_iRemotePort ); - - cs_sock_t iSock = GetSock(); - - if ( iSock != CS_INVALID_SOCK ) - { - if( !GetIPv6() ) - { - struct sockaddr_in mAddr; - socklen_t mLen = sizeof( mAddr ); - if ( getpeername( iSock, (struct sockaddr *) &mAddr, &mLen ) == 0 ) - m_iRemotePort = ntohs( mAddr.sin_port ); - } -#ifdef HAVE_IPV6 - else - { - struct sockaddr_in6 mAddr; - socklen_t mLen = sizeof( mAddr ); - if ( getpeername( iSock, (struct sockaddr *) &mAddr, &mLen ) == 0 ) - m_iRemotePort = ntohs( mAddr.sin6_port ); - } -#endif /* HAVE_IPV6 */ - } - + GetRemoteIP(); return( m_iRemotePort ); } u_short Csock::GetLocalPort() { - if ( m_iLocalPort > 0 ) + if( m_iLocalPort > 0 ) return( m_iLocalPort ); - - cs_sock_t iSock = GetSock(); - - if ( iSock != CS_INVALID_SOCK ) - { - if( !GetIPv6() ) - { - struct sockaddr_in mLocalAddr; - socklen_t mLocalLen = sizeof( mLocalAddr ); - if ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) - m_iLocalPort = ntohs( mLocalAddr.sin_port ); - } -#ifdef HAVE_IPV6 - else - { - struct sockaddr_in6 mLocalAddr; - socklen_t mLocalLen = sizeof( mLocalAddr ); - if ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) - m_iLocalPort = ntohs( mLocalAddr.sin6_port ); - } -#endif /* HAVE_IPV6 */ - } - + GetLocalIP(); return( m_iLocalPort ); } @@ -1993,7 +2008,7 @@ void Csock::NonBlockingIO() { set_non_blocking( m_iReadSock ); - if ( m_iReadSock != m_iWriteSock ) + if( m_iReadSock != m_iWriteSock ) { set_non_blocking( m_iWriteSock ); } @@ -2012,12 +2027,12 @@ const CS_STRING & Csock::GetPemPass() const { return( m_sPemPass ); } int Csock::PemPassCB( char *buf, int size, int rwflag, void *pcSocket ) { - Csock *pSock = (Csock *)pcSocket; + Csock *pSock = ( Csock * )pcSocket; const CS_STRING & sPassword = pSock->GetPemPass(); memset( buf, '\0', size ); strncpy( buf, sPassword.c_str(), size ); buf[size-1] = '\0'; - return( (int)strlen( buf ) ); + return(( int )strlen( buf ) ); } int Csock::CertVerifyCB( int preverify_ok, X509_STORE_CTX *x509_ctx ) @@ -2040,7 +2055,7 @@ void Csock::SetCTXObject( SSL_CTX *sslCtx ) { m_ssl_ctx = sslCtx; } SSL_SESSION * Csock::GetSSLSession() { - if ( m_ssl ) + if( m_ssl ) return( SSL_get_session( m_ssl ) ); return( NULL ); @@ -2053,15 +2068,15 @@ bool Csock::SslIsEstablished() { return ( m_bsslEstablished ); } bool Csock::ConnectInetd( bool bIsSSL, const CS_STRING & sHostname ) { - if ( !sHostname.empty() ) + if( !sHostname.empty() ) m_sSockName = sHostname; // set our hostname - if ( m_sSockName.empty() ) + if( m_sSockName.empty() ) { struct sockaddr_in client; socklen_t clen = sizeof( client ); - if ( getpeername( 0, (struct sockaddr *)&client, &clen ) < 0 ) + if( getpeername( 0, ( struct sockaddr * )&client, &clen ) < 0 ) m_sSockName = "0.0.0.0:0"; else { @@ -2076,7 +2091,7 @@ bool Csock::ConnectInetd( bool bIsSSL, const CS_STRING & sHostname ) bool Csock::ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool bIsSSL, ETConn eDirection ) { - if ( eDirection == LISTENER ) + if( eDirection == LISTENER ) { CS_DEBUG( "You can not use a LISTENER type here!" ); return( false ); @@ -2095,7 +2110,7 @@ bool Csock::ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool // set it up as non-blocking io NonBlockingIO(); - if ( bIsSSL ) + if( bIsSSL ) { if( eDirection == INBOUND && !AcceptSSL() ) return( false ); @@ -2109,7 +2124,7 @@ bool Csock::ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool #ifdef HAVE_LIBSSL X509 *Csock::GetX509() { - if ( m_ssl ) + if( m_ssl ) return( SSL_get_peer_certificate( m_ssl ) ); return( NULL ); @@ -2121,31 +2136,31 @@ CS_STRING Csock::GetPeerPubKey() SSL_SESSION *pSession = GetSSLSession(); - if ( ( pSession ) && ( pSession->peer ) ) + if( pSession && pSession->peer ) { EVP_PKEY *pKey = X509_get_pubkey( pSession->peer ); - if ( pKey ) + if( pKey ) { char *hxKey = NULL; switch( pKey->type ) { - case EVP_PKEY_RSA: - { - hxKey = BN_bn2hex( pKey->pkey.rsa->n ); - break; - } - case EVP_PKEY_DSA: - { - hxKey = BN_bn2hex( pKey->pkey.dsa->pub_key ); - break; - } - default: - { - CS_DEBUG( "Not Prepared for Public Key Type [" << pKey->type << "]" ); - break; - } + case EVP_PKEY_RSA: + { + hxKey = BN_bn2hex( pKey->pkey.rsa->n ); + break; } - if ( hxKey ) + case EVP_PKEY_DSA: + { + hxKey = BN_bn2hex( pKey->pkey.dsa->pub_key ); + break; + } + default: + { + CS_DEBUG( "Not Prepared for Public Key Type [" << pKey->type << "]" ); + break; + } + } + if( hxKey ) { sKey = hxKey; OPENSSL_free( hxKey ); @@ -2159,21 +2174,21 @@ long Csock::GetPeerFingerprint( CS_STRING & sFP ) { sFP.clear(); - if ( !m_ssl ) + if( !m_ssl ) return( 0 ); X509* pCert = GetX509(); // Inspired by charybdis - if ( pCert ) + if( pCert ) { - for (int i = 0; i < SHA_DIGEST_LENGTH; i++) + for( int i = 0; i < SHA_DIGEST_LENGTH; i++ ) { char buf[3]; - snprintf(buf, 3, "%02x", pCert->sha1_hash[i]); + snprintf( buf, 3, "%02x", pCert->sha1_hash[i] ); sFP += buf; } - X509_free(pCert); + X509_free( pCert ); } return( SSL_get_verify_result( m_ssl ) ); @@ -2197,7 +2212,8 @@ unsigned long long Csock::GetRateTime() { return( m_iMaxMilliSeconds ); } void Csock::EnableReadLine() { m_bEnableReadLine = true; } -void Csock::DisableReadLine() { +void Csock::DisableReadLine() +{ m_bEnableReadLine = false; m_sbuffer.clear(); } @@ -2212,10 +2228,10 @@ time_t Csock::GetTimeSinceLastDataTransaction( time_t iNow ) { if( m_iLastCheckTimeoutTime == 0 ) return( 0 ); - return( ( iNow > 0 ? iNow : time( NULL ) ) - m_iLastCheckTimeoutTime ); + return(( iNow > 0 ? iNow : time( NULL ) ) - m_iLastCheckTimeoutTime ); } -time_t Csock::GetNextCheckTimeout( time_t iNow ) +time_t Csock::GetNextCheckTimeout( time_t iNow ) { if( iNow == 0 ) iNow = time( NULL ); @@ -2247,7 +2263,7 @@ int Csock::GetPending() int iBytes = SSL_pending( m_ssl ); ERR_pop_to_mark(); return( iBytes ); -#else +#else int iBytes = SSL_pending( m_ssl ); ERR_clear_error(); // to get safer handling, upgrade your openssl version! return( iBytes ); @@ -2266,7 +2282,7 @@ bool Csock::CreateSocksFD() return( true ); m_iReadSock = m_iWriteSock = CreateSocket(); - if ( m_iReadSock == CS_INVALID_SOCK ) + if( m_iReadSock == CS_INVALID_SOCK ) return( false ); m_address.SinFamily(); @@ -2275,6 +2291,7 @@ bool Csock::CreateSocksFD() return( true ); } + int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) { #ifdef HAVE_IPV6 @@ -2293,79 +2310,83 @@ int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) } #ifdef HAVE_C_ARES - if( GetType() != LISTENER ) - { // right now the current function in Listen() is it blocks, the easy way around this at the moment is to use ip - // need to compute this up here - if( !m_pARESChannel ) + // need to compute this up here + if( !m_pARESChannel ) + { + if( ares_init( &m_pARESChannel ) != ARES_SUCCESS ) { - if( ares_init( &m_pARESChannel ) != ARES_SUCCESS ) - { // TODO throw some debug? - FreeAres(); - return( ETIMEDOUT ); - } - m_pCurrAddr = &csSockAddr; // flag its starting + // TODO throw some debug? + FreeAres(); + return( ETIMEDOUT ); + } + m_pCurrAddr = &csSockAddr; // flag its starting - int iFamily = AF_INET; + int iFamily = AF_INET; #ifdef HAVE_IPV6 #if ARES_VERSION >= CREATE_ARES_VER( 1, 7, 5 ) - // as of ares 1.7.5, it falls back to af_inet only when AF_UNSPEC is specified - // so this can finally let the code flow through as anticipated :) - iFamily = csSockAddr.GetAFRequire(); + // as of ares 1.7.5, it falls back to af_inet only when AF_UNSPEC is specified + // so this can finally let the code flow through as anticipated :) + iFamily = csSockAddr.GetAFRequire(); #else - // 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(); + // 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 /* CREATE_ARES_VER( 1, 7, 5 ) */ #endif /* HAVE_IPV6 */ - ares_gethostbyname( m_pARESChannel, sHostname.c_str(), iFamily, AresHostCallback, this ); - } - if( !m_pCurrAddr ) - { // this means its finished - FreeAres(); + ares_gethostbyname( m_pARESChannel, sHostname.c_str(), iFamily, AresHostCallback, this ); + } + if( !m_pCurrAddr ) + { + // this means its finished + FreeAres(); #ifdef HAVE_IPV6 - if( m_iARESStatus == ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY && GetIPv6() ) + if( GetType() != LISTENER && m_iARESStatus == ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY && GetIPv6() ) + { + // this means that ares_host returned an ipv6 host, so try a connect right away + if( CreateSocksFD() && Connect() ) { - // this means that ares_host returned an ipv6 host, so try a connect right away - if( CreateSocksFD() && Connect() ) - { - SetSkipConnect( true ); - } - else if( GetSockError() == ENETUNREACH ) - { - // the Connect() failed, so throw a retry back in with ipv4, and let it process normally - CS_DEBUG( "Failed ipv6 connection with PF_UNSPEC, falling back to ipv4" ); - m_iARESStatus = -1; - CloseSocksFD(); - SetAFRequire( CSSockAddr::RAF_INET ); - return( GetAddrInfo( sHostname, csSockAddr ) ); - } + SetSkipConnect( true ); } -#if ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) - if( m_iARESStatus != ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ) - { // this is a workaround for ares < 1.5.3 where the builtin retry on failed AF_INET6 isn't there yet - CS_DEBUG( "Retry for older version of c-ares with AF_INET only" ); - // this means we tried previously with AF_INET6 and failed, so force AF_INET and retry +#ifndef _WIN32 + else if( GetSockError() == ENETUNREACH ) +#else + else if( GetSockError() == WSAENETUNREACH || GetSockError() == WSAEHOSTUNREACH ) +#endif /* !_WIN32 */ + { + // the Connect() failed, so throw a retry back in with ipv4, and let it process normally + CS_DEBUG( "Failed ipv6 connection with PF_UNSPEC, falling back to ipv4" ); + m_iARESStatus = -1; + CloseSocksFD(); SetAFRequire( CSSockAddr::RAF_INET ); return( GetAddrInfo( sHostname, csSockAddr ) ); } + } +#if ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) + if( m_iARESStatus != ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ) + { + // this is a workaround for ares < 1.5.3 where the builtin retry on failed AF_INET6 isn't there yet + CS_DEBUG( "Retry for older version of c-ares with AF_INET only" ); + // this means we tried previously with AF_INET6 and failed, so force AF_INET and retry + SetAFRequire( CSSockAddr::RAF_INET ); + return( GetAddrInfo( sHostname, csSockAddr ) ); + } #endif /* ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) */ #endif /* HAVE_IPV6 */ - return( m_iARESStatus == ARES_SUCCESS ? 0 : ETIMEDOUT ); - } - return( EAGAIN ); + return( m_iARESStatus == ARES_SUCCESS ? 0 : ETIMEDOUT ); } -#endif /* HAVE_C_ARES */ - + return( EAGAIN ); +#else /* HAVE_C_ARES */ return( ::GetAddrInfo( sHostname, this, csSockAddr ) ); +#endif /* HAVE_C_ARES */ } int Csock::DNSLookup( EDNSLType eDNSLType ) { - if ( eDNSLType == DNS_VHOST ) + if( eDNSLType == DNS_VHOST ) { - if ( m_sBindHost.empty() ) + if( m_sBindHost.empty() ) { - if ( m_eConState != CST_OK ) + if( m_eConState != CST_OK ) m_eConState = CST_DESTDNS; // skip binding, there is no vhost return( 0 ); } @@ -2375,7 +2396,7 @@ int Csock::DNSLookup( EDNSLType eDNSLType ) } int iRet = ETIMEDOUT; - if ( eDNSLType == DNS_VHOST ) + if( eDNSLType == DNS_VHOST ) { iRet = GetAddrInfo( m_sBindHost, m_bindhost ); #ifdef HAVE_IPV6 @@ -2394,23 +2415,23 @@ int Csock::DNSLookup( EDNSLType eDNSLType ) iRet = GetAddrInfo( m_shostname, m_address ); } - if ( iRet == 0 ) + if( iRet == 0 ) { if( !CreateSocksFD() ) { m_iDNSTryCount = 0; return( ETIMEDOUT ); } - if ( m_eConState != CST_OK ) - m_eConState = ( ( eDNSLType == DNS_VHOST ) ? CST_BINDVHOST : CST_CONNECT ); + if( m_eConState != CST_OK ) + m_eConState = (( eDNSLType == DNS_VHOST ) ? CST_BINDVHOST : CST_CONNECT ); m_iDNSTryCount = 0; return( 0 ); } - else if ( iRet == EAGAIN ) + else if( iRet == EAGAIN ) { #ifndef HAVE_C_ARES m_iDNSTryCount++; - if ( m_iDNSTryCount > 20 ) + if( m_iDNSTryCount > 20 ) { m_iDNSTryCount = 0; return( ETIMEDOUT ); @@ -2424,28 +2445,28 @@ int Csock::DNSLookup( EDNSLType eDNSLType ) bool Csock::SetupVHost() { - if ( m_sBindHost.empty() ) + if( m_sBindHost.empty() ) { - if ( m_eConState != CST_OK ) + if( m_eConState != CST_OK ) m_eConState = CST_DESTDNS; return( true ); } int iRet = -1; if( !GetIPv6() ) - iRet = bind( m_iReadSock, (struct sockaddr *) m_bindhost.GetSockAddr(), m_bindhost.GetSockAddrLen() ); + iRet = bind( m_iReadSock, ( struct sockaddr * ) m_bindhost.GetSockAddr(), m_bindhost.GetSockAddrLen() ); #ifdef HAVE_IPV6 else - iRet = bind( m_iReadSock, (struct sockaddr *) m_bindhost.GetSockAddr6(), m_bindhost.GetSockAddrLen6() ); + iRet = bind( m_iReadSock, ( struct sockaddr * ) m_bindhost.GetSockAddr6(), m_bindhost.GetSockAddrLen6() ); #endif /* HAVE_IPV6 */ - if ( iRet == 0 ) + if( iRet == 0 ) { - if ( m_eConState != CST_OK ) + if( m_eConState != CST_OK ) m_eConState = CST_DESTDNS; return( true ); } m_iCurBindCount++; - if ( m_iCurBindCount > 3 ) + if( m_iCurBindCount > 3 ) { CS_DEBUG( "Failure to bind to " << m_sBindHost ); return( false ); @@ -2457,7 +2478,7 @@ bool Csock::SetupVHost() #ifdef HAVE_LIBSSL void Csock::FREE_SSL() { - if ( m_ssl ) + if( m_ssl ) { SSL_shutdown( m_ssl ); SSL_free( m_ssl ); @@ -2467,7 +2488,7 @@ void Csock::FREE_SSL() void Csock::FREE_CTX() { - if ( m_ssl_ctx ) + if( m_ssl_ctx ) SSL_CTX_free( m_ssl_ctx ); m_ssl_ctx = NULL; @@ -2478,23 +2499,23 @@ void Csock::FREE_CTX() cs_sock_t Csock::CreateSocket( bool bListen ) { #ifdef HAVE_IPV6 - cs_sock_t 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 cs_sock_t iRet = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); #endif /* HAVE_IPV6 */ - if ( iRet != CS_INVALID_SOCK ) + if( iRet != CS_INVALID_SOCK ) { set_close_on_exec( iRet ); - if ( bListen ) + if( bListen ) { const int on = 1; - if ( setsockopt( iRet, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof( on ) ) != 0 ) + if( setsockopt( iRet, SOL_SOCKET, SO_REUSEADDR, ( char * )&on, sizeof( on ) ) != 0 ) PERROR( "SO_REUSEADDR" ); } - } + } else PERROR( "socket" ); @@ -2512,6 +2533,7 @@ void Csock::Init( const CS_STRING & sHostname, u_short uPort, int iTimeout ) m_iReadSock = CS_INVALID_SOCK; m_iWriteSock = CS_INVALID_SOCK; m_iTimeout = iTimeout; + m_iMaxConns = SOMAXCONN; m_bUseSSL = false; m_bIsConnected = false; m_uPort = uPort; @@ -2565,7 +2587,7 @@ CSocketManager::~CSocketManager() void CSocketManager::clear() { - while ( this->size() ) + while( this->size() ) DelSock( 0 ); } @@ -2584,7 +2606,7 @@ Csock * CSocketManager::GetSockObj( const CS_STRING & sHostname, u_short uPort, void CSocketManager::Connect( const CSConnection & cCon, Csock * pcSock ) { // create the new object - if ( !pcSock ) + if( !pcSock ) pcSock = GetSockObj( cCon.GetHostname(), cCon.GetPort(), cCon.GetTimeout() ); else { @@ -2621,7 +2643,7 @@ void CSocketManager::Connect( const CSConnection & cCon, Csock * pcSock ) bool CSocketManager::Listen( const CSListener & cListen, Csock * pcSock, u_short *piRandPort ) { - if ( !pcSock ) + if( !pcSock ) pcSock = GetSockObj( "", 0 ); if( cListen.GetAFRequire() != CSSockAddr::RAF_ANY ) @@ -2635,12 +2657,12 @@ bool CSocketManager::Listen( const CSListener & cListen, Csock * pcSock, u_short #ifdef HAVE_IPV6 else { - pcSock->SetIPv6( true ); + pcSock->SetIPv6( true ); } #endif /* HAVE_IPV6 */ #ifdef HAVE_LIBSSL pcSock->SetSSL( cListen.GetIsSSL() ); - if( ( cListen.GetIsSSL() ) && ( !cListen.GetPemLocation().empty() ) ) + if( cListen.GetIsSSL() && !cListen.GetPemLocation().empty() ) { pcSock->SetPemLocation( cListen.GetPemLocation() ); pcSock->SetPemPass( cListen.GetPemPass() ); @@ -2652,14 +2674,16 @@ bool CSocketManager::Listen( const CSListener & cListen, Csock * pcSock, u_short if( piRandPort ) *piRandPort = 0; - if ( pcSock->Listen( cListen.GetPort(), cListen.GetMaxConns(), cListen.GetBindHost(), cListen.GetTimeout() ) ) + bool bDetach = ( cListen.GetDetach() && !piRandPort ); // can't detach if we're waiting for the port to come up right now + + if( pcSock->Listen( cListen.GetPort(), cListen.GetMaxConns(), cListen.GetBindHost(), cListen.GetTimeout(), bDetach ) ) { AddSock( pcSock, cListen.GetSockName() ); - if( ( piRandPort ) && ( cListen.GetPort() == 0 ) ) + if( piRandPort && cListen.GetPort() == 0 ) { cs_sock_t iSock = pcSock->GetSock(); - if ( iSock == CS_INVALID_SOCK ) + if( iSock == CS_INVALID_SOCK ) { CS_DEBUG( "Failed to attain a valid file descriptor" ); pcSock->Close(); @@ -2667,7 +2691,7 @@ bool CSocketManager::Listen( const CSListener & cListen, Csock * pcSock, u_short } struct sockaddr_in mLocalAddr; socklen_t mLocalLen = sizeof( mLocalAddr ); - getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ); + getsockname( iSock, ( struct sockaddr * ) &mLocalAddr, &mLocalLen ); *piRandPort = ntohs( mLocalAddr.sin_port ); } return( true ); @@ -2687,47 +2711,47 @@ void CSocketManager::Loop() { for( u_int a = 0; a < this->size(); a++ ) { - Csock *pcSock = (*this)[a]; + Csock *pcSock = ( *this )[a]; - if ( ( pcSock->GetType() != Csock::OUTBOUND ) || ( pcSock->GetConState() == Csock::CST_OK ) ) + if( pcSock->GetType() != Csock::OUTBOUND || pcSock->GetConState() == Csock::CST_OK ) continue; - if ( pcSock->GetConState() == Csock::CST_DNS ) + if( pcSock->GetConState() == Csock::CST_DNS ) { - if ( pcSock->DNSLookup( Csock::DNS_VHOST ) == ETIMEDOUT ) + if( pcSock->DNSLookup( Csock::DNS_VHOST ) == ETIMEDOUT ) { - pcSock->SockError( EDOM ); + pcSock->CallSockError( EDOM, "DNS Lookup for bind host failed" ); DelSock( a-- ); continue; } } - if ( pcSock->GetConState() == Csock::CST_BINDVHOST ) + if( pcSock->GetConState() == Csock::CST_BINDVHOST ) { - if ( !pcSock->SetupVHost() ) + if( !pcSock->SetupVHost() ) { - pcSock->SockError( GetSockError() ); + pcSock->CallSockError( GetSockError(), "Failed to setup bind host" ); DelSock( a-- ); continue; } } - if ( pcSock->GetConState() == Csock::CST_DESTDNS ) + if( pcSock->GetConState() == Csock::CST_DESTDNS ) { - if ( pcSock->DNSLookup( Csock::DNS_DEST ) == ETIMEDOUT ) + if( pcSock->DNSLookup( Csock::DNS_DEST ) == ETIMEDOUT ) { - pcSock->SockError( EADDRNOTAVAIL ); + pcSock->CallSockError( EADDRNOTAVAIL, "Unable to resolve requested address" ); DelSock( a-- ); continue; } } - if ( pcSock->GetConState() == Csock::CST_CONNECT ) + if( pcSock->GetConState() == Csock::CST_CONNECT ) { - if ( !pcSock->Connect() ) + if( !pcSock->Connect() ) { - if ( GetSockError() == ECONNREFUSED ) + if( GetSockError() == ECONNREFUSED ) pcSock->ConnectionRefused(); else - pcSock->SockError( GetSockError() ); + pcSock->CallSockError( GetSockError() ); DelSock( a-- ); continue; @@ -2736,14 +2760,14 @@ void CSocketManager::Loop() #ifdef HAVE_LIBSSL if( pcSock->GetConState() == Csock::CST_CONNECTSSL ) { - if ( pcSock->GetSSL() ) + if( pcSock->GetSSL() ) { - if ( !pcSock->ConnectSSL() ) + if( !pcSock->ConnectSSL() ) { - if ( GetSockError() == ECONNREFUSED ) + if( GetSockError() == ECONNREFUSED ) pcSock->ConnectionRefused(); else - pcSock->SockError( GetSockError() == 0 ? ECONNABORTED : GetSockError() ); + pcSock->CallSockError( GetSockError() == 0 ? ECONNABORTED : GetSockError() ); DelSock( a-- ); continue; @@ -2758,102 +2782,103 @@ void CSocketManager::Loop() switch( m_errno ) { - case SUCCESS: + case SUCCESS: + { + for( std::map::iterator itSock = mpeSocks.begin(); itSock != mpeSocks.end(); itSock++ ) { - for( std::map::iterator itSock = mpeSocks.begin(); itSock != mpeSocks.end(); itSock++ ) + Csock * pcSock = itSock->first; + EMessages iErrno = itSock->second; + + if( iErrno == SUCCESS ) { - Csock * pcSock = itSock->first; - EMessages iErrno = itSock->second; + // read in data + // if this is a + int iLen = 0; - if ( iErrno == SUCCESS ) + if( pcSock->GetSSL() ) + iLen = pcSock->GetPending(); + + if( iLen <= 0 ) + iLen = CS_BLOCKSIZE; + + CSCharBuffer cBuff( iLen ); + + cs_ssize_t bytes = pcSock->Read( cBuff(), iLen ); + + if( bytes != Csock::READ_TIMEDOUT && bytes != Csock::READ_CONNREFUSED && bytes != Csock::READ_ERR && !pcSock->IsConnected() ) { - // read in data - // if this is a - int iLen = 0; - - if ( pcSock->GetSSL() ) - iLen = pcSock->GetPending(); - - if ( iLen <= 0 ) - iLen = CS_BLOCKSIZE; - - CSCharBuffer cBuff( iLen ); - - cs_ssize_t bytes = pcSock->Read( cBuff(), iLen ); - - if ( bytes != Csock::READ_TIMEDOUT && bytes != Csock::READ_CONNREFUSED && bytes != Csock::READ_ERR && !pcSock->IsConnected() ) - { - pcSock->SetIsConnected( true ); - pcSock->Connected(); - } - - switch( bytes ) - { - case Csock::READ_EOF: - { - DelSockByAddr( pcSock ); - break; - } - - case Csock::READ_ERR: - { - pcSock->SockError( GetSockError() ); - DelSockByAddr( pcSock ); - break; - } - - case Csock::READ_EAGAIN: - break; - - case Csock::READ_CONNREFUSED: - pcSock->ConnectionRefused(); - DelSockByAddr( pcSock ); - break; - - case Csock::READ_TIMEDOUT: - pcSock->Timeout(); - DelSockByAddr( pcSock ); - break; - - default: - { - if ( Csock::TMO_READ & pcSock->GetTimeoutType() ) - pcSock->ResetTimer(); // reset the timeout timer - - pcSock->ReadData( cBuff(), bytes ); // Call ReadData() before PushBuff() so that it is called before the ReadLine() event - LD 07/18/05 - pcSock->PushBuff( cBuff(), bytes ); - break; - } - } - - } else if ( iErrno == SELECT_ERROR ) - { - // a socket came back with an error - // usually means it was closed - DelSockByAddr( pcSock ); + pcSock->SetIsConnected( true ); + pcSock->Connected(); } - } - break; - } - case SELECT_TIMEOUT: - case SELECT_TRYAGAIN: - case SELECT_ERROR: - default : - break; + switch( bytes ) + { + case Csock::READ_EOF: + { + DelSockByAddr( pcSock ); + break; + } + + case Csock::READ_ERR: + { + pcSock->CallSockError( GetSockError() ); + DelSockByAddr( pcSock ); + break; + } + + case Csock::READ_EAGAIN: + break; + + case Csock::READ_CONNREFUSED: + pcSock->ConnectionRefused(); + DelSockByAddr( pcSock ); + break; + + case Csock::READ_TIMEDOUT: + pcSock->Timeout(); + DelSockByAddr( pcSock ); + break; + + default: + { + if( Csock::TMO_READ & pcSock->GetTimeoutType() ) + pcSock->ResetTimer(); // reset the timeout timer + + pcSock->ReadData( cBuff(), bytes ); // Call ReadData() before PushBuff() so that it is called before the ReadLine() event - LD 07/18/05 + pcSock->PushBuff( cBuff(), bytes ); + break; + } + } + + } + else if( iErrno == SELECT_ERROR ) + { + // a socket came back with an error + // usually means it was closed + DelSockByAddr( pcSock ); + } + } + break; + } + + case SELECT_TIMEOUT: + case SELECT_TRYAGAIN: + case SELECT_ERROR: + default : + break; } unsigned long long iMilliNow = millitime(); - if ( ( iMilliNow - m_iCallTimeouts ) >= 1000 ) + if(( iMilliNow - m_iCallTimeouts ) >= 1000 ) { m_iCallTimeouts = iMilliNow; // call timeout on all the sockets that recieved no data for( unsigned int i = 0; i < this->size(); i++ ) { - if ( (*this)[i]->GetConState() != Csock::CST_OK ) + if(( *this )[i]->GetConState() != Csock::CST_OK ) continue; - if ( (*this)[i]->CheckTimeout( (time_t)(iMilliNow / 1000 ) ) ) + if(( *this )[i]->CheckTimeout(( time_t )( iMilliNow / 1000 ) ) ) DelSock( i-- ); } } @@ -2865,7 +2890,8 @@ void CSocketManager::DynamicSelectLoop( u_long iLowerBounds, u_long iUpperBounds { SetSelectTimeout( iLowerBounds ); if( m_errno == SELECT_TIMEOUT ) - { // only do this if the previous call to select was a timeout + { + // only do this if the previous call to select was a timeout time_t iNow = time( NULL ); u_long iSelectTimeout = GetDynamicSleepTime( iNow, iMaxResolution ); iSelectTimeout *= 1000000; @@ -2887,8 +2913,8 @@ Csock * CSocketManager::FindSockByRemotePort( u_short iPort ) { for( unsigned int i = 0; i < this->size(); i++ ) { - if ( (*this)[i]->GetRemotePort() == iPort ) - return( (*this)[i] ); + if(( *this )[i]->GetRemotePort() == iPort ) + return(( *this )[i] ); } return( NULL ); @@ -2897,8 +2923,8 @@ Csock * CSocketManager::FindSockByRemotePort( u_short iPort ) Csock * CSocketManager::FindSockByLocalPort( u_short iPort ) { for( unsigned int i = 0; i < this->size(); i++ ) - if ( (*this)[i]->GetLocalPort() == iPort ) - return( (*this)[i] ); + if(( *this )[i]->GetLocalPort() == iPort ) + return(( *this )[i] ); return( NULL ); } @@ -2908,7 +2934,7 @@ Csock * CSocketManager::FindSockByName( const CS_STRING & sName ) std::vector::iterator it; std::vector::iterator it_end = this->end(); for( it = this->begin(); it != it_end; it++ ) - if ( (*it)->GetSockName() == sName ) + if(( *it )->GetSockName() == sName ) return( *it ); return( NULL ); @@ -2917,8 +2943,8 @@ Csock * CSocketManager::FindSockByName( const CS_STRING & sName ) Csock * CSocketManager::FindSockByFD( cs_sock_t iFD ) { for( unsigned int i = 0; i < this->size(); i++ ) - if ( ( (*this)[i]->GetRSock() == iFD ) || ( (*this)[i]->GetWSock() == iFD ) ) - return( (*this)[i] ); + if(( *this )[i]->GetRSock() == iFD || ( *this )[i]->GetWSock() == iFD ) + return(( *this )[i] ); return( NULL ); } @@ -2928,8 +2954,8 @@ std::vector CSocketManager::FindSocksByName( const CS_STRING & sName ) std::vector vpSocks; for( unsigned int i = 0; i < this->size(); i++ ) - if ( (*this)[i]->GetSockName() == sName ) - vpSocks.push_back( (*this)[i] ); + if(( *this )[i]->GetSockName() == sName ) + vpSocks.push_back(( *this )[i] ); return( vpSocks ); } @@ -2939,8 +2965,8 @@ std::vector CSocketManager::FindSocksByRemoteHost( const CS_STRING & sH std::vector vpSocks; for( unsigned int i = 0; i < this->size(); i++ ) - if ( (*this)[i]->GetHostName() == sHostname ) - vpSocks.push_back( (*this)[i] ); + if(( *this )[i]->GetHostName() == sHostname ) + vpSocks.push_back(( *this )[i] ); return( vpSocks ); } @@ -2949,7 +2975,7 @@ void CSocketManager::DelSockByAddr( Csock *pcSock ) { for( u_int a = 0; a < this->size(); a++ ) { - if ( pcSock == (*this)[a] ) + if( pcSock == ( *this )[a] ) { DelSock( a ); return; @@ -2958,17 +2984,17 @@ void CSocketManager::DelSockByAddr( Csock *pcSock ) } void CSocketManager::DelSock( u_int iPos ) { - if ( iPos >= this->size() ) + if( iPos >= this->size() ) { CS_DEBUG( "Invalid Sock Position Requested! [" << iPos << "]" ); return; } - Csock * pSock = (*this)[iPos]; + Csock * pSock = ( *this )[iPos]; if( pSock->GetCloseType() != Csock::CLT_DEREFERENCE ) { - if ( pSock->IsConnected() ) + if( pSock->IsConnected() ) pSock->Disconnected(); // only call disconnected event if connected event was called (IE IsConnected was set) m_iBytesRead += pSock->GetBytesRead(); @@ -2987,11 +3013,11 @@ bool CSocketManager::SwapSockByIdx( Csock *pNewSock, u_long iOrginalSockIdx ) return( false ); } - Csock *pSock = (*this)[iOrginalSockIdx]; + Csock *pSock = ( *this )[iOrginalSockIdx]; pNewSock->Copy( *pSock ); pSock->Dereference(); - (*this)[iOrginalSockIdx] = (Csock *)pNewSock; - this->push_back( (Csock *)pSock ); // this allows it to get cleaned up + ( *this )[iOrginalSockIdx] = ( Csock * )pNewSock; + this->push_back(( Csock * )pSock ); // this allows it to get cleaned up return( true ); } @@ -2999,7 +3025,7 @@ bool CSocketManager::SwapSockByAddr( Csock *pNewSock, Csock *pOrigSock ) { for( u_long a = 0; a < this->size(); a++ ) { - if( (*this)[a] == pOrigSock ) + if(( *this )[a] == pOrigSock ) return( SwapSockByIdx( pNewSock, a ) ); } return( false ); @@ -3012,7 +3038,7 @@ unsigned long long CSocketManager::GetBytesRead() const // Add in the outstanding bytes read from active sockets for( u_int a = 0; a < this->size(); a++ ) - iRet += (*this)[a]->GetBytesRead(); + iRet += ( *this )[a]->GetBytesRead(); return( iRet ); } @@ -3024,7 +3050,7 @@ unsigned long long CSocketManager::GetBytesWritten() const // Add in the outstanding bytes written to active sockets for( u_int a = 0; a < this->size(); a++ ) - iRet += (*this)[a]->GetBytesWritten(); + iRet += ( *this )[a]->GetBytesWritten(); return( iRet ); } @@ -3033,7 +3059,7 @@ void CSocketManager::FDSetCheck( int iFd, std::map< int, short > & miiReadyFds, { std::map< int, short >::iterator it = miiReadyFds.find( iFd ); if( it != miiReadyFds.end() ) - it->second = (short)(it->second | eType ); // TODO need to figure out why |= throws 'short int' from 'int' may alter its value + it->second = ( short )( it->second | eType ); // TODO need to figure out why |= throws 'short int' from 'int' may alter its value else miiReadyFds[iFd] = eType; } @@ -3041,18 +3067,18 @@ bool CSocketManager::FDHasCheck( int iFd, std::map< int, short > & miiReadyFds, { std::map< int, short >::iterator it = miiReadyFds.find( iFd ); if( it != miiReadyFds.end() ) - return( (it->second & eType) ); + return(( it->second & eType ) ); return( false ); } -int CSocketManager::Select( std::map< int, short > & miiReadyFds, struct timeval *tvtimeout) +int CSocketManager::Select( std::map< int, short > & miiReadyFds, struct timeval *tvtimeout ) { AssignFDs( miiReadyFds, tvtimeout ); #ifdef CSOCK_USE_POLL if( miiReadyFds.empty() ) return( select( 0, NULL, NULL, NULL, tvtimeout ) ); - struct pollfd * pFDs = (struct pollfd *)malloc( sizeof( struct pollfd ) * miiReadyFds.size() ); + struct pollfd * pFDs = ( struct pollfd * )malloc( sizeof( struct pollfd ) * miiReadyFds.size() ); size_t uCurrPoll = 0; for( std::map< int, short >::iterator it = miiReadyFds.begin(); it != miiReadyFds.end(); ++it, ++uCurrPoll ) { @@ -3065,21 +3091,21 @@ int CSocketManager::Select( std::map< int, short > & miiReadyFds, struct timeval pFDs[uCurrPoll].events = iEvents; pFDs[uCurrPoll].revents = 0; } - int iTimeout = (int)(tvtimeout->tv_usec / 1000); - iTimeout += (int)(tvtimeout->tv_sec * 1000); + int iTimeout = ( int )( tvtimeout->tv_usec / 1000 ); + iTimeout += ( int )( tvtimeout->tv_sec * 1000 ); size_t uMaxFD = miiReadyFds.size(); int iRet = poll( pFDs, uMaxFD, iTimeout ); miiReadyFds.clear(); for( uCurrPoll = 0; uCurrPoll < uMaxFD; ++uCurrPoll ) { short iEvents = 0; - if( (pFDs[uCurrPoll].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL) ) ) + if(( pFDs[uCurrPoll].revents & ( POLLIN|POLLERR|POLLHUP|POLLNVAL ) ) ) iEvents |= ECT_Read; - if( (pFDs[uCurrPoll].revents & POLLOUT ) ) + if(( pFDs[uCurrPoll].revents & POLLOUT ) ) iEvents |= ECT_Write; std::map< int, short >::iterator it = miiReadyFds.find( pFDs[uCurrPoll].fd ); if( it != miiReadyFds.end() ) - it->second |= iEvents; + it->second = ( short )( it->second | iEvents ); // TODO need to figure out why |= throws 'short int' from 'int' may alter its value else miiReadyFds[pFDs[uCurrPoll].fd] = iEvents; } @@ -3111,9 +3137,9 @@ int CSocketManager::Select( std::map< int, short > & miiReadyFds, struct timeval { for( std::map< int, short >::iterator it = miiReadyFds.begin(); it != miiReadyFds.end(); ++it ) { - if( (it->second & ECT_Read) && !TFD_ISSET( it->first, &rfds ) ) + if(( it->second & ECT_Read ) && !TFD_ISSET( it->first, &rfds ) ) it->second &= ~ECT_Read; - if( (it->second & ECT_Write) && !TFD_ISSET( it->first, &wfds ) ) + if(( it->second & ECT_Write ) && !TFD_ISSET( it->first, &wfds ) ) it->second &= ~ECT_Write; } } @@ -3121,7 +3147,7 @@ int CSocketManager::Select( std::map< int, short > & miiReadyFds, struct timeval return( iRet ); } - + void CSocketManager::Select( std::map & mpeSocks ) { mpeSocks.clear(); @@ -3131,14 +3157,14 @@ void CSocketManager::Select( std::map & mpeSocks ) tv.tv_sec = m_iSelectWait / 1000000; tv.tv_usec = m_iSelectWait % 1000000; u_int iQuickReset = 1000; - if ( m_iSelectWait == 0 ) + if( m_iSelectWait == 0 ) iQuickReset = 0; bool bHasAvailSocks = false; unsigned long long iNOW = 0; for( unsigned int i = 0; i < this->size(); i++ ) { - Csock *pcSock = (*this)[i]; + Csock *pcSock = ( *this )[i]; Csock::ECloseType eCloseType = pcSock->GetCloseType(); @@ -3152,7 +3178,7 @@ void CSocketManager::Select( std::map & mpeSocks ) cs_sock_t & iRSock = pcSock->GetRSock(); cs_sock_t & iWSock = pcSock->GetWSock(); -#ifndef CSOCK_USE_POLL +#if !defined(CSOCK_USE_POLL) && !defined(_WIN32) if( iRSock > FD_SETSIZE || iWSock > FD_SETSIZE ) { CS_DEBUG( "FD is larger than select() can handle" ); @@ -3160,7 +3186,7 @@ void CSocketManager::Select( std::map & mpeSocks ) continue; } #endif /* CSOCK_USE_POLL */ - + #ifdef HAVE_C_ARES ares_channel pChannel = pcSock->GetAresChannel(); if( pChannel ) @@ -3176,21 +3202,30 @@ void CSocketManager::Select( std::map & mpeSocks ) ares_timeout( pChannel, &tv, &tv ); } #endif /* HAVE_C_ARES */ + if( pcSock->GetType() == Csock::LISTENER && pcSock->GetConState() == Csock::CST_BINDVHOST ) + { + if( !pcSock->Listen( pcSock->GetPort(), pcSock->GetMaxConns(), pcSock->GetBindHost(), pcSock->GetTimeout(), true ) ) + { + pcSock->Close(); + DelSock( i-- ); + } + continue; + } pcSock->AssignFDs( miiReadyFds, &tv ); - if ( pcSock->GetConState() != Csock::CST_OK ) + if( pcSock->GetConState() != Csock::CST_OK ) continue; bHasAvailSocks = true; bool bIsReadPaused = pcSock->IsReadPaused(); - if ( bIsReadPaused ) + if( bIsReadPaused ) { pcSock->ReadPaused(); bIsReadPaused = pcSock->IsReadPaused(); // re-read it again, incase it changed status) } - if ( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) + if( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) { SelectSock( mpeSocks, SUCCESS, pcSock ); continue; // invalid sock fd @@ -3200,31 +3235,35 @@ void CSocketManager::Select( std::map & mpeSocks ) { bool bHasWriteBuffer = !pcSock->GetWriteBuffer().empty(); - if ( !bIsReadPaused ) + if( !bIsReadPaused ) FDSetCheck( iRSock, miiReadyFds, ECT_Read ); if( pcSock->AllowWrite( iNOW ) && ( !pcSock->IsConnected() || bHasWriteBuffer ) ) - { + { if( !pcSock->IsConnected() ) - { // set the write bit if not connected yet + { + // set the write bit if not connected yet FDSetCheck( iWSock, miiReadyFds, ECT_Write ); } else if( bHasWriteBuffer && !pcSock->GetSSL() ) - { // always set the write bit if there is data to send when NOT ssl + { + // always set the write bit if there is data to send when NOT ssl FDSetCheck( iWSock, miiReadyFds, ECT_Write ); } else if( bHasWriteBuffer && pcSock->GetSSL() && pcSock->SslIsEstablished() ) - { // ONLY set the write bit if there is data to send and the SSL handshake is finished + { + // ONLY set the write bit if there is data to send and the SSL handshake is finished FDSetCheck( iWSock, miiReadyFds, ECT_Write ); } } if( pcSock->GetSSL() && !pcSock->SslIsEstablished() && bHasWriteBuffer ) - { // if this is an unestabled SSL session with data to send ... try sending it + { + // if this is an unestabled SSL session with data to send ... try sending it // do this here, cause otherwise ssl will cause a small // cpu spike waiting for the handshake to finish // resend this data - if ( !pcSock->Write( "" ) ) + if( !pcSock->Write( "" ) ) { pcSock->Close(); } @@ -3233,16 +3272,16 @@ void CSocketManager::Select( std::map & mpeSocks ) // however, we can set the select WAY down and it will retry quickly, but keep it from spinning at 100% tv.tv_usec = iQuickReset; tv.tv_sec = 0; - } - } + } + } else { FDSetCheck( iRSock, miiReadyFds, ECT_Read ); } - + if( pcSock->GetSSL() && pcSock->GetType() != Csock::LISTENER ) { - if ( ( pcSock->GetPending() > 0 ) && ( !pcSock->IsReadPaused() ) ) + if(( pcSock->GetPending() > 0 ) && ( !pcSock->IsReadPaused() ) ) SelectSock( mpeSocks, SUCCESS, pcSock ); } } @@ -3255,7 +3294,7 @@ void CSocketManager::Select( std::map & mpeSocks ) tv.tv_usec = iQuickReset; tv.tv_sec = 0; } - else if ( !this->empty() && !bHasAvailSocks ) + else if( !this->empty() && !bHasAvailSocks ) { tv.tv_usec = iQuickReset; tv.tv_sec = 0; @@ -3263,9 +3302,9 @@ void CSocketManager::Select( std::map & mpeSocks ) iSel = Select( miiReadyFds, &tv ); - if ( iSel == 0 ) + if( iSel == 0 ) { - if ( mpeSocks.empty() ) + if( mpeSocks.empty() ) m_errno = SELECT_TIMEOUT; else m_errno = SUCCESS; @@ -3283,24 +3322,24 @@ void CSocketManager::Select( std::map & mpeSocks ) return; } - if ( ( iSel == -1 ) && ( errno == EINTR ) ) + if(( iSel == -1 ) && ( errno == EINTR ) ) { - if ( mpeSocks.empty() ) + if( mpeSocks.empty() ) m_errno = SELECT_TRYAGAIN; else m_errno = SUCCESS; return; - } - else if ( iSel == -1 ) + } + else if( iSel == -1 ) { - if ( mpeSocks.empty() ) + if( mpeSocks.empty() ) m_errno = SELECT_ERROR; else m_errno = SUCCESS; return; - } + } else { m_errno = SUCCESS; @@ -3311,7 +3350,7 @@ void CSocketManager::Select( std::map & mpeSocks ) // find out wich one is ready for( unsigned int i = 0; i < this->size(); i++ ) { - Csock *pcSock = (*this)[i]; + Csock *pcSock = ( *this )[i]; #ifdef HAVE_C_ARES ares_channel pChannel = pcSock->GetAresChannel(); @@ -3326,14 +3365,14 @@ void CSocketManager::Select( std::map & mpeSocks ) #endif /* HAVE_C_ARES */ pcSock->CheckFDs( miiReadyFds ); - if ( pcSock->GetConState() != Csock::CST_OK ) + if( pcSock->GetConState() != Csock::CST_OK ) continue; cs_sock_t & iRSock = pcSock->GetRSock(); cs_sock_t & iWSock = pcSock->GetWSock(); EMessages iErrno = SUCCESS; - if ( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) + if( iRSock == CS_INVALID_SOCK || iWSock == CS_INVALID_SOCK ) { // trigger a success so it goes through the normal motions // and an error is produced @@ -3341,33 +3380,35 @@ void CSocketManager::Select( std::map & mpeSocks ) continue; // watch for invalid socks } - if ( FDHasCheck( iWSock, miiReadyFds, ECT_Write ) ) + if( FDHasCheck( iWSock, miiReadyFds, ECT_Write ) ) { - if ( iSel > 0 ) + if( iSel > 0 ) { iErrno = SUCCESS; - if ( ( !pcSock->GetWriteBuffer().empty() ) && ( pcSock->IsConnected() ) ) - { // write whats in the socks send buffer - if ( !pcSock->Write( "" ) ) + if(( !pcSock->GetWriteBuffer().empty() ) && ( pcSock->IsConnected() ) ) + { + // write whats in the socks send buffer + if( !pcSock->Write( "" ) ) { // write failed, sock died :( iErrno = SELECT_ERROR; } } - } else + } + else iErrno = SELECT_ERROR; SelectSock( mpeSocks, iErrno, pcSock ); - } - else if ( FDHasCheck( iRSock, miiReadyFds, ECT_Read ) ) + } + else if( FDHasCheck( iRSock, miiReadyFds, ECT_Read ) ) { - if ( iSel > 0 ) + if( iSel > 0 ) iErrno = SUCCESS; else iErrno = SELECT_ERROR; - if ( pcSock->GetType() != Csock::LISTENER ) + if( pcSock->GetType() != Csock::LISTENER ) SelectSock( mpeSocks, iErrno, pcSock ); else // someone is coming in! { @@ -3375,15 +3416,15 @@ void CSocketManager::Select( std::map & mpeSocks ) u_short port; cs_sock_t inSock = pcSock->Accept( sHost, port ); - if ( inSock != CS_INVALID_SOCK ) + if( inSock != CS_INVALID_SOCK ) { - if ( Csock::TMO_ACCEPT & pcSock->GetTimeoutType() ) + if( Csock::TMO_ACCEPT & pcSock->GetTimeoutType() ) pcSock->ResetTimer(); // let them now it got dinged // if we have a new sock, then add it - Csock *NewpcSock = (Csock *)pcSock->GetSockObj( sHost, port ); + Csock *NewpcSock = ( Csock * )pcSock->GetSockObj( sHost, port ); - if ( !NewpcSock ) + if( !NewpcSock ) NewpcSock = GetSockObj( sHost, port ); NewpcSock->SetType( Csock::INBOUND ); @@ -3395,7 +3436,7 @@ void CSocketManager::Select( std::map & mpeSocks ) #ifdef HAVE_LIBSSL // // is this ssl ? - if ( pcSock->GetSSL() ) + if( pcSock->GetSSL() ) { NewpcSock->SetCipher( pcSock->GetCipher() ); NewpcSock->SetPemLocation( pcSock->GetPemLocation() ); @@ -3405,20 +3446,22 @@ void CSocketManager::Select( std::map & mpeSocks ) } #endif /* HAVE_LIBSSL */ - if ( bAddSock ) + if( bAddSock ) { // set the name of the listener NewpcSock->SetParentSockName( pcSock->GetSockName() ); NewpcSock->SetRate( pcSock->GetRateBytes(), pcSock->GetRateTime() ); - if ( NewpcSock->GetSockName().empty() ) + if( NewpcSock->GetSockName().empty() ) { std::stringstream s; s << sHost << ":" << port; AddSock( NewpcSock, s.str() ); - } else + } + else AddSock( NewpcSock, NewpcSock->GetSockName() ); - } else + } + else CS_Delete( NewpcSock ); } #ifdef _WIN32 @@ -3427,7 +3470,7 @@ void CSocketManager::Select( std::map & mpeSocks ) else if( GetSockError() != EAGAIN ) #endif /* _WIN32 */ { - pcSock->SockError( GetSockError() ); + pcSock->CallSockError( GetSockError() ); } } } @@ -3441,7 +3484,7 @@ time_t CSocketManager::GetDynamicSleepTime( time_t iNow, time_t iMaxResolution ) // This is safe, because we don't modify the vector. std::vector::const_iterator it_end = this->end(); - for (it = this->begin(); it != it_end; it++) + for( it = this->begin(); it != it_end; it++ ) { Csock* pSock = *it; @@ -3458,13 +3501,13 @@ time_t CSocketManager::GetDynamicSleepTime( time_t iNow, time_t iMaxResolution ) const std::vector & vCrons = pSock->GetCrons(); std::vector::const_iterator cit; std::vector::const_iterator cit_end = vCrons.end(); - for (cit = vCrons.begin(); cit != cit_end; cit++) - iNextRunTime = std::min( iNextRunTime, (*cit)->GetNextRun() ); + for( cit = vCrons.begin(); cit != cit_end; cit++ ) + iNextRunTime = std::min( iNextRunTime, ( *cit )->GetNextRun() ); } std::vector::const_iterator cit; std::vector::const_iterator cit_end = m_vcCrons.end(); - for (cit = m_vcCrons.begin(); cit != cit_end; cit++) - iNextRunTime = std::min( iNextRunTime, (*cit)->GetNextRun() ); + for( cit = m_vcCrons.begin(); cit != cit_end; cit++ ) + iNextRunTime = std::min( iNextRunTime, ( *cit )->GetNextRun() ); if( iNextRunTime < iNow ) return( 0 ); // smallest unit possible @@ -3473,7 +3516,7 @@ time_t CSocketManager::GetDynamicSleepTime( time_t iNow, time_t iMaxResolution ) void CSocketManager::SelectSock( std::map & mpeSocks, EMessages eErrno, Csock * pcSock ) { - if ( mpeSocks.find( pcSock ) != mpeSocks.end() ) + if( mpeSocks.find( pcSock ) != mpeSocks.end() ) return; mpeSocks[pcSock] = eErrno; diff --git a/src/HTTPSock.cpp b/src/HTTPSock.cpp index 1b83893e..3752e082 100644 --- a/src/HTTPSock.cpp +++ b/src/HTTPSock.cpp @@ -536,7 +536,7 @@ bool CHTTPSock::Redirect(const CString& sURL) { void CHTTPSock::Timeout() { } -void CHTTPSock::SockError(int iErrno) { +void CHTTPSock::SockError(int iErrno, const CString& sDescription) { } void CHTTPSock::Connected() { diff --git a/src/IRCSock.cpp b/src/IRCSock.cpp index b74d3403..496ce0cc 100644 --- a/src/IRCSock.cpp +++ b/src/IRCSock.cpp @@ -953,22 +953,8 @@ void CIRCSock::Disconnected() { m_scUserModes.clear(); } -void CIRCSock::SockError(int iErrno) { - CString sError; - - if (iErrno == EDOM) { - sError = "Your bind host could not be resolved"; - } else if (iErrno == EADDRNOTAVAIL) { - // Csocket uses this if it can't resolve the dest host name - // ...but it also does generate this if bind() fails -.- - sError = strerror(iErrno); - if (GetBindHost().empty()) - sError += " (Is your IRC server's host name valid?)"; - else - sError += " (Is your IRC server's host name and ZNC bind host valid?)"; - } else { - sError = strerror(iErrno); - } +void CIRCSock::SockError(int iErrno, const CString& sDescription) { + CString sError = sDescription; DEBUG(GetSockName() << " == SockError(" << iErrno << " " << sError << ")"); @@ -976,7 +962,7 @@ void CIRCSock::SockError(int iErrno) { if (GetConState() != CST_OK) { m_pNetwork->PutStatus("Cannot connect to IRC (" + sError + "). Retrying..."); } else { - m_pNetwork->PutStatus("Disconnected from IRC (" + sError + "). Reconnecting..."); + m_pNetwork->PutStatus("Disconnected from IRC (" + sError + "). Reconnecting..."); } } m_pNetwork->ClearRawBuffer(); diff --git a/src/Listener.cpp b/src/Listener.cpp index fcf1fd9b..e54747a7 100644 --- a/src/Listener.cpp +++ b/src/Listener.cpp @@ -64,8 +64,8 @@ Csock* CRealListener::GetSockObj(const CString& sHost, unsigned short uPort) { return pClient; } -void CRealListener::SockError(int iErrno) { - DEBUG(GetSockName() << " == SockError(" << strerror(iErrno) << ")"); +void CRealListener::SockError(int iErrno, const CString& sDescription) { + DEBUG(GetSockName() << " == SockError(" << sDescription << ", " << strerror(iErrno) << ")"); if (iErrno == EMFILE) { // We have too many open fds, let's close this listening port to be able to continue // to work, next rehash will (try to) reopen it. diff --git a/src/Socket.cpp b/src/Socket.cpp index 1c926c40..ab06a1b4 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -29,10 +29,11 @@ unsigned int CSockManager::GetAnonConnectionCount(const CString &sIP) const { return ret; } -CS_STRING CZNCSock::ConvertAddress(void *addr, bool ipv6) { - CString sRet = Csock::ConvertAddress(addr, ipv6); - sRet.TrimPrefix("::ffff:"); - return sRet; +int CZNCSock::ConvertAddress(const struct sockaddr_storage * pAddr, socklen_t iAddrLen, CS_STRING & sIP, u_short * piPort) { + int ret = Csock::ConvertAddress(pAddr, iAddrLen, sIP, piPort); + if (ret == 0) + sIP.TrimPrefix("::ffff:"); + return ret; } /////////////////// CSocket /////////////////// @@ -74,8 +75,8 @@ void CSocket::ReachedMaxBuffer() { Close(); } -void CSocket::SockError(int iErrno) { - DEBUG(GetSockName() << " == SockError(" << strerror(iErrno) << ")"); +void CSocket::SockError(int iErrno, const CString& sDescription) { + DEBUG(GetSockName() << " == SockError(" << sDescription << ", " << strerror(iErrno) << ")"); if (iErrno == EMFILE) { // We have too many open fds, this can cause a busy loop. Close();