bool CCCBot :: Update( ) { unsigned int NumFDs = 0; // take every socket we own and throw it in one giant select statement so we can block on all sockets int nfds = 0; fd_set fd; fd_set send_fd; FD_ZERO( &fd ); FD_ZERO( &send_fd ); // all battle.net sockets for( vector<CBNET *> :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); ++i ) NumFDs += (*i)->SetFD( &fd, &send_fd, &nfds ); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 50000; #ifdef WIN32 select( 1, &fd, &send_fd, NULL, &tv ); #else select( nfds + 1, &fd, &send_fd, NULL, &tv ); #endif if( NumFDs == 0 ) { // we don't have any sockets (i.e. we aren't connected to battle.net maybe due to a lost connection) // select will return immediately and we'll chew up the CPU if we let it loop so just sleep for 200ms to kill some time MILLISLEEP( 200 ); } // update battle.net connections for( vector<CBNET *> :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); ++i ) { if( (*i)->Update( &fd, &send_fd ) ) m_Exiting = true; } return m_Exiting; }
CServer :: ~CServer( ) { closesocket( m_sckServer ); unsigned long iStart = GetTime( ); while( 1 ) { for( vector<CClient *> :: iterator i = m_vecClients.begin( ); i != m_vecClients.end( ); ) { if( (*i)->m_iState == CS_WAITING1 || (*i)->m_iState == CS_WAITING2 || (*i)->m_iState == CS_DEAD ) { delete *i; i = m_vecClients.erase( i ); } else i++; } if( m_vecClients.size( ) > 0 ) { UTIL_LogPrint( "server - waiting for %d clients to disconnect\n", m_vecClients.size( ) ); MILLISLEEP( 1000 ); } else break; if( GetTime( ) - iStart > 60 ) { UTIL_LogPrint( "server - waited 60 seconds, exiting anyway\n" ); break; } } if( m_pTracker ) delete m_pTracker; m_pTracker = NULL; UTIL_LogPrint( "server - exit\n" ); }
void CGHostDBMySQL :: CreateThread( CBaseCallable *callable ) { try { boost :: thread Thread( boost :: ref( *callable ) ); } catch( boost :: thread_resource_error tre ) { CONSOLE_Print( "[MYSQL] error spawning thread on attempt #1 [" + string( tre.what( ) ) + "], pausing execution and trying again in 50ms" ); MILLISLEEP( 50 ); try { boost :: thread Thread( boost :: ref( *callable ) ); } catch( boost :: thread_resource_error tre2 ) { CONSOLE_Print( "[MYSQL] error spawning thread on attempt #2 [" + string( tre2.what( ) ) + "], giving up" ); callable->SetReady( true ); } } }
int bnbtmain( ) { gmtxOutput.Initialize( ); srand( time( NULL ) ); giStartTime = time( NULL ); CFG_Open( CFG_FILE ); CFG_SetDefaults( ); CFG_Close( CFG_FILE ); gstrErrorLogDir = CFG_GetString( "bnbt_error_log_dir", string( ) ); if( !gstrErrorLogDir.empty( ) && gstrErrorLogDir[gstrErrorLogDir.size( ) - 1] != PATH_SEP ) gstrErrorLogDir += PATH_SEP; gpErrorLog = NULL; gstrAccessLogDir = CFG_GetString( "bnbt_access_log_dir", string( ) ); if( !gstrAccessLogDir.empty( ) && gstrAccessLogDir[gstrAccessLogDir.size( ) - 1] != PATH_SEP ) gstrAccessLogDir += PATH_SEP; gpAccessLog = NULL; giErrorLogCount = 0; giAccessLogCount = 0; giFlushInterval = CFG_GetInt( "bnbt_flush_interval", 100 ); gbDebug = CFG_GetInt( "bnbt_debug", 1 ) == 0 ? false : true; giMaxConns = CFG_GetInt( "bnbt_max_conns", 64 ); gstrStyle = CFG_GetString( "bnbt_style_sheet", string( ) ); gstrCharSet = CFG_GetString( "bnbt_charset", "iso-8859-1" ); gstrRealm = CFG_GetString( "bnbt_realm", "BNBT" ); // The Trinity Edition - Addition Begins // Sets the value for the Custom NT Service Name variable gstrNTServiceName = CFG_GetString( "trinity_nt_service_name", "BNBT Service" ); // Sets the "bnbt_alt_signup_url" value gstrAltSignupURL = CFG_GetString( "bnbt_alt_signup_url", string( ) ); // Sets the "bnbt_tracker_title" value gstrTrackerTitle = CFG_GetString( "bnbt_tracker_title", string( ) ); // Sets the "bnbt_external_js" value gstrExternalJavascript = CFG_GetString( "bnbt_external_js", string( ) ); // --------------------------------------- End of Addition // start winsock #ifdef WIN32 WSADATA wsadata; if( WSAStartup( MAKEWORD( 2, 0 ), &wsadata ) != 0 ) { UTIL_LogPrint( "error - unable to start winsock (error %d)\n", GetLastError( ) ); if( gpAccessLog ) fclose( gpAccessLog ); if( gpErrorLog ) fclose( gpErrorLog ); gmtxOutput.Destroy( ); return 1; } #endif gpServer = new CServer( ); gpLink = NULL; gpLinkServer = NULL; if( CFG_GetInt( "bnbt_tlink_server", 0 ) != 0 ) gpLinkServer = new CLinkServer( ); else { if( !CFG_GetString( "bnbt_tlink_connect", string( ) ).empty( ) ) { #ifdef WIN32 if( _beginthread( ( void (*)(void *) )StartLink, 0, NULL ) == -1 ) UTIL_LogPrint( "error - unable to spawn link thread\n" ); #else pthread_t thread; // set detached state since we don't need to join with any threads pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); int c = pthread_create( &thread, &attr, ( void * (*)(void *) )StartLink, NULL ); if( c != 0 ) UTIL_LogPrint( "error - unable to spawn link thread (error %s)\n", strerror( c ) ); #endif } } while( 1 ) { if( gpServer->Update( true ) ) { delete gpServer; gpServer = NULL; if( gpLinkServer ) { delete gpLinkServer; gpLinkServer = NULL; } break; } if( gpLinkServer ) gpLinkServer->Update( ); } // wait for the link or it might make a big mess if( gpLink ) gpLink->Kill( ); unsigned long iStart = GetTime( ); while( gpLink ) { UTIL_LogPrint( "server - waiting for link to disconnect\n" ); MILLISLEEP( 1000 ); if( GetTime( ) - iStart > 60 ) { UTIL_LogPrint( "server - waited 60 seconds, exiting anyway\n" ); break; } } if( gpAccessLog ) fclose( gpAccessLog ); if( gpErrorLog ) fclose( gpErrorLog ); gmtxOutput.Destroy( ); #ifdef WIN32 WSACleanup( ); #endif return 0; }
bool CServer :: Update( const bool &bBlock ) { if( m_vecClients.size( ) < guiMaxConns ) { // tphogan - check every listener for new connections fd_set fdServer; FD_ZERO( &fdServer ); struct timeval tv; struct sockaddr_in6 adrFrom; int iAddrLen = 0; SOCKET sckClient = 0; for( vector<SOCKET> :: iterator itListener = m_vecListeners.begin( ); itListener != m_vecListeners.end( ); itListener++ ) { FD_CLR( *itListener, &fdServer ); FD_SET( *itListener, &fdServer ); // tphogan - only block on the first listener // this is actually a bit of a hack but it don't feel like doing it "right" :) if( bBlock && itListener == m_vecListeners.begin( ) ) { // block for 100 ms to keep from eating up all cpu time tv.tv_sec = 0; tv.tv_usec = 100000; } else { tv.tv_sec = 0; tv.tv_usec = 0; } #ifdef WIN32 if( select( 1, &fdServer, 0, 0, &tv ) == SOCKET_ERROR ) #else if( select( *itListener + 1, &fdServer, 0, 0, &tv ) == SOCKET_ERROR ) #endif { UTIL_LogPrint( ( gmapLANG_CFG["select_error"] + "\n" ).c_str( ), GetLastErrorString( ) ); FD_CLR( *itListener, &fdServer ); } if( FD_ISSET( *itListener, &fdServer ) !=0 ) { iAddrLen = sizeof( adrFrom ); #ifdef WIN32 sckClient = accept( *itListener, (struct sockaddr *)&adrFrom, &iAddrLen ); if( sckClient == INVALID_SOCKET ) #else sckClient = accept( *itListener, (struct sockaddr *)&adrFrom, (socklen_t *)&iAddrLen ); if( sckClient == INVALID_SOCKET ) #endif UTIL_LogPrint( ( gmapLANG_CFG["accept_error"] + "\n" ).c_str( ), GetLastErrorString( ) ); else m_vecClients.push_back( new CClient( sckClient, adrFrom, m_uiSocketTimeOut, m_cCompression ) ); } } } else { // maximum connections reached // tphogan - reduced from 100 ms to 10 ms // it's very difficult to tell if the backlog is due to legitimate load or hung clients // hung clients don't eat CPU time so the server's CPU usage will skyrocket // but if it's due to load then sleeping for 100 ms is a terrible idea! // someone should take a look at this and rewrite it eventually UTIL_LogPrint( "Server Info - Max. connections reached\n" ); MILLISLEEP( 10 ); } // process the clients for( vector<CClient *> :: iterator itClient = m_vecClients.begin( ); itClient != m_vecClients.end( ); ) { if( (*itClient)->Update( ) ) { delete *itClient; itClient = m_vecClients.erase( itClient ); } else itClient++; } if( m_pTracker ) m_pTracker->Update( ); return m_bKill; }
bool CServer :: Update( bool bBlock ) { if( m_vecClients.size( ) < (unsigned int)giMaxConns ) { fd_set fdServer; FD_ZERO( &fdServer ); FD_SET( m_sckServer, &fdServer ); struct timeval tv; if( bBlock ) { // block for 100 ms to keep from eating up all cpu time tv.tv_sec = 0; tv.tv_usec = 100000; } else { tv.tv_sec = 0; tv.tv_usec = 0; } #ifdef WIN32 if( select( 1, &fdServer, NULL, NULL, &tv ) == SOCKET_ERROR ) #else if( select( m_sckServer + 1, &fdServer, NULL, NULL, &tv ) == SOCKET_ERROR ) #endif { UTIL_LogPrint( "server warning - select error (error %d)\n", GetLastError( ) ); FD_ZERO( &fdServer ); MILLISLEEP( 100 ); } if( FD_ISSET( m_sckServer, &fdServer ) ) { struct sockaddr_in adrFrom; int iAddrLen = sizeof( adrFrom ); SOCKET sckClient; #ifdef WIN32 if( ( sckClient = accept( m_sckServer, (struct sockaddr *)&adrFrom, &iAddrLen ) ) == INVALID_SOCKET ) #else if( ( sckClient = accept( m_sckServer, (struct sockaddr *)&adrFrom, (socklen_t *)&iAddrLen ) ) == INVALID_SOCKET ) #endif UTIL_LogPrint( "server warning - accept error (error %d)\n", GetLastError( ) ); else { // reuse the old timeval structure just because tv.tv_sec = m_iSocketTimeOut; tv.tv_usec = 0; CClient *pClient = new CClient( sckClient, adrFrom, tv, m_iCompression ); #ifdef WIN32 if( _beginthread( ( void (*)(void *) )StartReceiving, 0, (void *)pClient ) == -1 ) { UTIL_LogPrint( "server warning - unable to spawn receiver thread\n" ); pClient->m_iState = CS_DEAD; } #else pthread_t thread; // set detached state since we don't need to join with any threads pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); int c = pthread_create( &thread, &attr, ( void * (*)(void *) )StartReceiving, (void *)pClient ); if( c != 0 ) { UTIL_LogPrint( "server warning - unable to spawn receiver thread (error %s)\n", strerror( c ) ); pClient->m_iState = CS_DEAD; } #endif m_vecClients.push_back( pClient ); } } } else { // maximum connections reached MILLISLEEP( 100 ); } // process for( vector<CClient *> :: iterator i = m_vecClients.begin( ); i != m_vecClients.end( ); ) { if( (*i)->m_iState == CS_WAITING1 ) { (*i)->Process( ); i++; } else if( (*i)->m_iState == CS_WAITING2 ) { (*i)->m_iState = CS_SENDING; #ifdef WIN32 if( _beginthread( ( void (*)(void *) )StartSending, 0, (void *)(*i) ) == -1 ) { UTIL_LogPrint( "server warning - unable to spawn sender thread\n" ); (*i)->m_iState = CS_DEAD; } #else pthread_t thread; // set detached state since we don't need to join with any threads pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); int c = pthread_create( &thread, &attr, ( void * (*)(void *) )StartSending, (void *)(*i) ); if( c != 0 ) { UTIL_LogPrint( "server warning - unable to spawn sender thread (error %s)\n", strerror( c ) ); (*i)->m_iState = CS_DEAD; } #endif i++; } else if( (*i)->m_iState == CS_DEAD ) { delete *i; i = m_vecClients.erase( i ); } else i++; } if( m_pTracker ) m_pTracker->Update( ); return m_bKill; }
int bnbtmain( ) { gmtxOutput.Initialize( ); srand( time( NULL ) ); giStartTime = time( NULL ); CFG_Open( CFG_FILE ); CFG_SetDefaults( ); CFG_Close( CFG_FILE ); gstrErrorLogFilePattern = CFG_GetString( "bnbt_error_log_file_pattern", "%Y-%m-%de.log" ); gstrErrorLogDir = CFG_GetString( "bnbt_error_log_dir", string( ) ); if( !gstrErrorLogDir.empty( ) && gstrErrorLogDir[gstrErrorLogDir.size( ) - 1] != PATH_SEP ) gstrErrorLogDir += PATH_SEP; gpErrorLog = NULL; gstrAccessLogFilePattern = CFG_GetString( "bnbt_access_log_file_pattern", "%Y-%m-%d.log" ); gstrAccessLogDir = CFG_GetString( "bnbt_access_log_dir", string( ) ); if( !gstrAccessLogDir.empty( ) && gstrAccessLogDir[gstrAccessLogDir.size( ) - 1] != PATH_SEP ) gstrAccessLogDir += PATH_SEP; gpAccessLog = NULL; giErrorLogCount = 0; giAccessLogCount = 0; giFlushInterval = CFG_GetInt( "bnbt_flush_interval", 100 ); gbDebug = CFG_GetInt( "bnbt_debug", 1 ) == 0 ? false : true; giMaxConns = CFG_GetInt( "bnbt_max_conns", 64 ); giMaxRecvSize = CFG_GetInt( "bnbt_max_recv_size", 524288 ); gstrStyle = CFG_GetString( "bnbt_style_sheet", string( ) ); gstrCharSet = CFG_GetString( "bnbt_charset", "iso-8859-1" ); gstrRealm = CFG_GetString( "bnbt_realm", "BNBT" ); // start winsock // TCP window size giSO_RECBUF = CFG_GetInt( "xbnbt_so_recbuf", 128 ) * 1024; giSO_SNDBUF = CFG_GetInt( "xbnbt_so_sndbuf", 128 ) * 1024; #ifdef WIN32 WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ) { UTIL_LogPrint( "error - unable to start winsock (error %d)\n", GetLastError( ) ); if( gpAccessLog ) fclose( gpAccessLog ); if( gpErrorLog ) fclose( gpErrorLog ); gmtxOutput.Destroy( ); return 1; } #endif // start mysql #ifdef BNBT_MYSQL if( !( gpMySQL = mysql_init( NULL ) ) ) { UTIL_LogPrint( "mysql error - %s\n", mysql_error( gpMySQL ) ); if( gpAccessLog ) fclose( gpAccessLog ); if( gpErrorLog ) fclose( gpErrorLog ); gmtxOutput.Destroy( ); return 1; } gstrMySQLHost = CFG_GetString( "mysql_host", string( ) ); gstrMySQLDatabase = CFG_GetString( "mysql_database", "bnbt" ); gstrMySQLUser = CFG_GetString( "mysql_user", string( ) ); gstrMySQLPassword = CFG_GetString( "mysql_password", string( ) ); giMySQLPort = CFG_GetInt( "mysql_port", 0 ); if( !( mysql_real_connect( gpMySQL, gstrMySQLHost.c_str( ), gstrMySQLUser.c_str( ), gstrMySQLPassword.c_str( ), gstrMySQLDatabase.c_str( ), giMySQLPort, NULL, 0 ) ) ) { UTIL_LogPrint( "mysql error - %s\n", mysql_error( gpMySQL ) ); if( gpAccessLog ) fclose( gpAccessLog ); if( gpErrorLog ) fclose( gpErrorLog ); gmtxOutput.Destroy( ); return 1; } UTIL_LogPrint( "mysql - connected\n" ); #endif gpServer = new CServer( ); gpLink = NULL; gpLinkServer = NULL; if( CFG_GetInt( "bnbt_tlink_server", 0 ) != 0 ) gpLinkServer = new CLinkServer( ); else { if( !CFG_GetString( "bnbt_tlink_connect", string( ) ).empty( ) ) { #ifdef WIN32 if( _beginthread( ( void (*)(void *) )StartLink, 0, NULL ) == -1 ) UTIL_LogPrint( "error - unable to spawn link thread\n" ); #else pthread_t thread; // set detached state since we don't need to join with any threads pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); int c = pthread_create( &thread, &attr, ( void * (*)(void *) )StartLink, NULL ); if( c != 0 ) UTIL_LogPrint( "error - unable to spawn link thread (error %s)\n", strerror( c ) ); #endif } } while( 1 ) { if( gpServer->Update( true ) ) { delete gpServer; gpServer = NULL; if( gpLinkServer ) { delete gpLinkServer; gpLinkServer = NULL; } break; } if( gpLinkServer ) gpLinkServer->Update( ); } // wait for the link or it might make a big mess if( gpLink ) gpLink->Kill( ); unsigned long iStart = GetTime( ); while( gpLink ) { UTIL_LogPrint( "server - waiting for link to disconnect\n" ); MILLISLEEP( 1000 ); if( GetTime( ) - iStart > 60 ) { UTIL_LogPrint( "server - waited 60 seconds, exiting anyway\n" ); break; } } #ifdef BNBT_MYSQL mysql_close( gpMySQL ); #endif if( gpAccessLog ) fclose( gpAccessLog ); if( gpErrorLog ) fclose( gpErrorLog ); gmtxOutput.Destroy( ); #ifdef WIN32 WSACleanup( ); #endif return 0; }