00001
00002 #include "serverbase.h"
00003
00004
00005 #include <worm_signal.h>
00006 #include <worm_exceptions.h>
00007 #include <logger.h>
00008 #include <timefuncs.h>
00009
00010
00011
00012 #pragma package(smart_init)
00013
00014
00015 #define ACCEPTABLE_SEC_TO_WAIT_FOR_SERVICE_THREAD_TO_START 10
00016
00017
00018
00019
00020
00021 bool WormServerBase::DoSCNLsMatch( const char * p_s1
00022 , const char * p_c1
00023 , const char * p_n1
00024 , const char * p_l1
00025 , const char * p_s2
00026 , const char * p_c2
00027 , const char * p_n2
00028 , const char * p_l2
00029 )
00030 {
00031
00032
00033
00034
00035 if ( ! ( p_s1[0] == '*'
00036 || p_s2[0] == '*'
00037 || strcmp( p_s1, p_s2 ) == 0
00038 ) )
00039 {
00040 return false;
00041 }
00042
00043 if ( ! ( p_c1[0] == '*'
00044 || p_c2[0] == '*'
00045 || strcmp( p_c1, p_c2 ) == 0
00046 ) )
00047 {
00048 return false;
00049 }
00050
00051 if ( ! ( p_n1[0] == '*'
00052 || p_n2[0] == '*'
00053 || strcmp( p_n1, p_n2 ) == 0
00054 ) )
00055 {
00056 return false;
00057 }
00058
00059 if ( ! ( p_l1[0] == '-'
00060 || p_l2[0] == '-'
00061 || strcmp( p_l1, p_l2 ) == 0
00062 ) )
00063 {
00064 return false;
00065 }
00066
00067 return true;
00068 }
00069
00070
00071
00072
00073 WormServerBase::WormServerBase()
00074 {
00075 Running = false;
00076 CommandRingKey = WORM_RING_INVALID;
00077 CommandRegion.addr = NULL;
00078 strcpy( ServerIPAddr, "" );
00079 ServerPort = -1;
00080 SocketDebug = false;
00081 PassiveSocket = INVALID_SOCKET;
00082 MaxServiceThreads = 10;
00083 SendTimeoutMS = -2;
00084 RecvTimeoutMS = -1;
00085
00086 try
00087 {
00088 if ( TGlobalUtils::LookupMessageTypeId("TYPE_HEARTBEAT") == WORM_MSGTYPE_INVALID )
00089 {
00090 throw worm_exception("message type <TYPE_HEARTBEAT> not defined");
00091 }
00092
00093 if ( TGlobalUtils::LookupMessageTypeId("TYPE_ERROR") == WORM_MSGTYPE_INVALID )
00094 {
00095 throw worm_exception("message type <TYPE_ERROR> not defined");
00096 }
00097
00098 SocketSysInit();
00099 }
00100 catch( worm_exception _we )
00101 {
00102 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00103 , "WormServerBase(): error: %s\n"
00104 , _we.what()
00105 );
00106 }
00107 }
00108
00109 WormServerBase::~WormServerBase()
00110 {
00111
00112 Running = false;
00113
00114 TTimeFuncs::MSecSleep(1000);
00115 WSACleanup();
00116 }
00117
00118 int WormServerBase::ListenForMsg( SOCKET p_descriptor
00119 , char * p_rcv_buffer
00120 , int * p_length
00121 , int p_timeoutms
00122 )
00123 {
00124
00125
00126
00127
00128
00129
00130
00131
00132 int r_status = 0;
00133
00134 int r_readcount = 0;
00135
00136 int _readmax = *p_length;
00137
00138
00139
00140
00141
00142
00143 int _timeoutms = ( p_timeoutms < 1 ? RecvTimeoutMS : p_timeoutms );
00144
00145
00146 *p_length = 0;
00147
00148 bool _stillreading = true;
00149
00150 try
00151 {
00152 if ( _timeoutms == -1 )
00153 {
00154
00155
00156
00157 ThreadsInfo[p_descriptor].status = THREAD_BLOCKINGSOCKET;
00158 }
00159
00160
00161
00162
00163 do
00164 {
00165
00166 if ( r_readcount == _readmax )
00167 {
00168
00169 r_status = -4;
00170 throw worm_exception("message buffer overflow");
00171 }
00172
00173
00174 ThreadsInfo[p_descriptor].lastpulse = time(NULL);
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 int _err;
00198 switch( recv_ew( p_descriptor, &p_rcv_buffer[r_readcount], 1, 0, _timeoutms ) )
00199 {
00200 case 1:
00201 if ( p_rcv_buffer[r_readcount] == '\n' )
00202 {
00203
00204
00205 p_rcv_buffer[r_readcount] = '\0';
00206 _stillreading = false;
00207 }
00208 (*p_length)++;
00209 r_readcount++;
00210 break;
00211
00212 case 0:
00213 r_status = -2;
00214 if ( WORM_LOG_DETAILS <= TGlobalUtils::GetLoggingLevel() )
00215 {
00216 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00217 , "WormServerBase.ListenForMsg(): Client closed socket %d\n"
00218 , p_descriptor
00219 );
00220 }
00221 _stillreading = false;
00222 break;
00223
00224 case SOCKET_ERROR:
00225 #if defined(_WINNT) || defined(_Windows)
00226 switch( (_err = WSAGetLastError()) )
00227 {
00228 case WSAEWOULDBLOCK:
00229
00230 r_status = -1;
00231 _stillreading = false;
00232 break;
00233
00234 case WSAECONNRESET:
00235 r_status = -2;
00236 if ( WORM_LOG_DETAILS <= TGlobalUtils::GetLoggingLevel() )
00237 {
00238 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00239 , "WormServerBase.ListenForMsg(): Other end closed socket %d\n"
00240 , p_descriptor
00241 );
00242 }
00243 _stillreading = false;
00244 break;
00245
00246 default:
00247 r_status = -3;
00248 throw worm_socket_exception( WSF_RECV
00249 , _err
00250 , "Socket error from recv()"
00251 );
00252 }
00253 break;
00254 #endif
00255
00256
00257 }
00258
00259 } while( _stillreading );
00260 }
00261 catch( worm_socket_exception & _se )
00262 {
00263 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00264 , "WormServerBase::ListenForMsg(): socket exception:\n%s\n"
00265 , _se.DecodeError()
00266 );
00267 }
00268 catch( worm_exception & _we )
00269 {
00270 if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
00271 {
00272 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00273 , "WormServerBase.ListenForMsg(): Error - %s\n"
00274 , _we.what()
00275 );
00276 }
00277 }
00278
00279
00280 ThreadsInfo[p_descriptor].lastpulse = time(NULL);
00281 if ( _timeoutms == -1 )
00282 {
00283
00284
00285
00286 ThreadsInfo[p_descriptor].status = THREAD_PROCESSING;
00287 }
00288
00289 return r_status;
00290 }
00291
00292 WORM_STATUS_CODE WormServerBase::SendMessage( const SOCKET p_descriptor
00293 , const char * p_msg
00294 , int * p_length
00295 )
00296 {
00297 WORM_STATUS_CODE r_status = WORM_STAT_SUCCESS;
00298
00299 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00300 {
00301 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00302 , "WormServerBase.SendMessage(): sending message to %s (timeout %d):\n%s<\n"
00303 , ThreadsInfo[p_descriptor].ipaddr
00304 , SendTimeoutMS
00305 , p_msg
00306 );
00307 }
00308
00309
00310 try
00311 {
00312 if ( p_msg == NULL )
00313 {
00314 throw worm_exception( "WormServerBase.SendMessage(): message string is NULL" );
00315 }
00316
00317 int _sendcount = *p_length;
00318 if ( (*p_length = send_ew(p_descriptor, p_msg, _sendcount, 0, SendTimeoutMS)) == SOCKET_ERROR )
00319 {
00320 throw worm_socket_exception( WSF_SEND
00321 , socketGetError_ew()
00322 , "send_ew returned error"
00323 );
00324 }
00325
00326 if ( _sendcount != *p_length )
00327 {
00328 throw worm_exception("bytes sent does not match message size");
00329 }
00330 }
00331 catch( worm_socket_exception& _se )
00332 {
00333 if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
00334 {
00335 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00336 , "WormServerBase.SendMessage(): failed sending message to %s:\n %s\n"
00337 , ThreadsInfo[p_descriptor].ipaddr
00338 , _se.DecodeError()
00339 );
00340 }
00341 r_status = WORM_STAT_FAILURE;
00342 }
00343 catch( worm_exception _we )
00344 {
00345 if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
00346 {
00347 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00348 , "WormServerBase.SendMessage(): Error - %s\n"
00349 , _we.what()
00350 );
00351 }
00352 r_status = WORM_STAT_FAILURE;
00353 }
00354 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00355 {
00356 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00357 , "WormServerBase.SendMessage(): exiting\n"
00358 );
00359 }
00360 return r_status;
00361 }
00362
00363 void WormServerBase::CheckConfig()
00364 {
00365
00366 if ( TGlobalUtils::GetHeartbeatInt() < 1 )
00367 {
00368 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00369 , "WormServerBase::CheckConfig(): No <HeartBeatInt> value from the config file\n"
00370 );
00371 ConfigState = WORM_STAT_BADSTATE;
00372 }
00373
00374 if ( RecvTimeoutMS < MIN_RECV_TIMEOUT_MS )
00375 {
00376 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00377 , "WormServerBase::CheckConfig(): <RecvTimeoutMSecs> too low in config file, using %d\n"
00378 , MIN_RECV_TIMEOUT_MS
00379 );
00380 RecvTimeoutMS = MIN_RECV_TIMEOUT_MS;
00381 }
00382
00383 if ( CommandRingKey == WORM_RING_INVALID )
00384 {
00385 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00386 , "WormServerBase::CheckConfig(): No <CmdRingName> value from the config file\n"
00387 );
00388 ConfigState = WORM_STAT_BADSTATE;
00389 }
00390
00391 if ( strlen(ServerIPAddr) == 0 )
00392 {
00393 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00394 , "WormServerBase::CheckConfig(): No <ServerIPAddr> value from the config file\n"
00395 );
00396 ConfigState = WORM_STAT_BADSTATE;
00397 }
00398
00399 if ( ServerPort == -1 )
00400 {
00401 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00402 , "WormServerBase::CheckConfig(): No <ServerPort> value from the config file\n"
00403 );
00404 ConfigState = WORM_STAT_BADSTATE;
00405 }
00406
00407 if ( SendTimeoutMS == -2 )
00408 {
00409 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00410 , "WormServerBase::CheckConfig(): No <SendTimeoutMSecs> value from the config file\n"
00411 );
00412 ConfigState = WORM_STAT_BADSTATE;
00413 }
00414 }
00415
00416 HANDLE_STATUS WormServerBase::HandleConfigLine( ConfigSource * p_parser )
00417 {
00418
00419
00420 HANDLE_STATUS r_handled = HANDLER_USED;
00421
00422 try
00423 {
00424 char * _token;
00425
00426 do
00427 {
00428
00429 if ( p_parser->Its("CmdRingName") )
00430 {
00431 _token = p_parser->String();
00432 if ( strlen(_token) == 0 )
00433 {
00434 throw worm_exception("missing <CmdRingName> value");
00435 }
00436 strncpy( CommandRingName, _token, MAX_RINGNAME_LEN );
00437
00438 if ( (CommandRingKey = TGlobalUtils::LookupRingKey(CommandRingName)) == WORM_RING_INVALID )
00439 {
00440 throw worm_exception("invalid <CmdRingName> value");
00441 }
00442
00443 continue;
00444 }
00445
00446 if( p_parser->Its( "ServerIPAddr" ) )
00447 {
00448 _token = p_parser->String();
00449
00450 if ( strlen(_token) == 0 )
00451 {
00452 throw worm_exception("missing <ServerIPAddr> value");
00453 }
00454
00455 if ( 20 <= strlen(_token) )
00456 {
00457 throw worm_exception("<ServerIPAddr> name too long");
00458 }
00459
00460 strcpy( ServerIPAddr, _token );
00461 continue;
00462 }
00463
00464 if ( p_parser->Its("ServerPort") )
00465 {
00466 if ( (ServerPort = p_parser->Int()) == ConfigSource::INVALID_INT )
00467 {
00468 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00469 , "WormServerBase::HandleConfigLine(): Invalid <ServerPort> value in line\n%s\n"
00470 , p_parser->GetCurrentLine()
00471 );
00472 }
00473 continue;
00474 }
00475
00476 if( p_parser->Its("SendTimeoutMSecs") )
00477 {
00478
00479 if ( (SendTimeoutMS = p_parser->Int()) < 0 )
00480 {
00481 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00482 , "WormServerBase::HandleConfigLine(): Invalid <SendTimeoutMSecs> line (must be > 0), reverting to 10000 ms\n"
00483 );
00484 SendTimeoutMS = 10000;
00485 }
00486 continue;
00487 }
00488
00489 if( p_parser->Its("RecvTimeoutMSecs") )
00490 {
00491 RecvTimeoutMS = p_parser->Int();
00492 if ( RecvTimeoutMS < -1 )
00493 {
00494 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00495 , "WormServerBase::HandleConfigLine(): Invalid <RecvTimeoutSecs> line, reverting to 200 ms\n"
00496 );
00497 RecvTimeoutMS = 200;
00498 }
00499 continue;
00500 }
00501
00502
00503 if ( p_parser->Its("MaxServerThreads") )
00504 {
00505 MaxServiceThreads = p_parser->Int();
00506 if ( MaxServiceThreads <= 0 || SERVE_MAX_THREADS < MaxServiceThreads )
00507 {
00508 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00509 , "WormServerBase::HandleConfigLine(): <MaxServiceThreads> (%d) out of range (0 - %d)\n%s %d\n"
00510 , MaxServiceThreads
00511 , SERVE_MAX_THREADS
00512 , " setting to "
00513 , SERVE_MAX_THREADS
00514 );
00515 MaxServiceThreads = SERVE_MAX_THREADS;
00516 }
00517 continue;
00518 }
00519
00520 if( p_parser->Its("SocketDebug") )
00521 {
00522 SocketDebug = true;
00523 continue;
00524 }
00525
00526 r_handled = HANDLER_UNUSED;
00527
00528 } while ( false );
00529 }
00530 catch( worm_exception _we )
00531 {
00532 r_handled = HANDLER_INVALID;
00533 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00534 , "WormServerBase::HandleConfigLine(): configuration error:\n%s%s\n"
00535 , " "
00536 , _we.what()
00537 );
00538 }
00539
00540 return r_handled;
00541 }
00542
00543
00544
00545
00546
00547 void WormServerBase::SendStatus( unsigned char type, short p_ierr, char * p_text )
00548 {
00549 if ( CommandRingKey != WORM_RING_INVALID )
00550 {
00551 MSG_LOGO logo;
00552 char msg[256];
00553 long size;
00554 long t;
00555
00556
00557
00558 logo.instid = TGlobalUtils::GetThisInstallationId();
00559 logo.mod = TGlobalUtils::GetThisModuleId();
00560 logo.type = type;
00561
00562 time( &t );
00563
00564 strcpy( msg, "" );
00565
00566 if( type == TGlobalUtils::LookupMessageTypeId("TYPE_HEARTBEAT") )
00567 {
00568 sprintf( msg, "%ld %ld\n\0", t, TGlobalUtils::GetPID());
00569 }
00570 else if( type == TGlobalUtils::LookupMessageTypeId("TYPE_ERROR") )
00571 {
00572 sprintf( msg, "%ld %hd %s\n\0", t, p_ierr, p_text);
00573 }
00574 else
00575 {
00576 return;
00577 }
00578
00579 size = strlen( msg );
00580
00581
00582
00583
00584 if( tport_putmsg( &CommandRegion, &logo, size, msg ) != PUT_OK )
00585 {
00586 if( type == TGlobalUtils::LookupMessageTypeId("TYPE_HEARTBEAT") )
00587 {
00588 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00589 , "WormServerBase::SendStatus(): Error sending heartbeat.\n"
00590 );
00591 }
00592 else
00593 {
00594 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00595 , "WormServerBase::SendStatus(): Error sending error: %d.\n"
00596 , p_ierr
00597 );
00598 }
00599 }
00600 }
00601 }
00602
00603 WORM_STATUS_CODE WormServerBase::Run()
00604 {
00605 WORM_STATUS_CODE r_status = WORM_STAT_SUCCESS;
00606
00607 static long CurrentTime
00608 , LastBeatTime
00609 ;
00610
00611 try
00612 {
00613 if ( ConfigState != WORM_STAT_SUCCESS )
00614 {
00615 throw worm_exception("WormServerBase::Run() Server not configured");
00616 }
00617
00618 if ( SocketDebug )
00619 {
00620
00621 setSocket_ewDebug(1);
00622 }
00623
00624 tport_attach( &CommandRegion, CommandRingKey );
00625
00626 #ifdef _SOLARIS
00627
00628 (void)sigignore(SIGPIPE);
00629 #endif
00630
00631
00632
00633 signal(SIGINT, (SIG_HANDLR_PTR)SignalHandler);
00634 signal(SIGTERM, (SIG_HANDLR_PTR)SignalHandler);
00635 signal(SIGABRT, (SIG_HANDLR_PTR)SignalHandler);
00636 #ifdef SIGBREAK
00637 signal(SIGBREAK, (SIG_HANDLR_PTR)SignalHandler);
00638 #endif
00639
00640 if ( ! PrepareToRun() )
00641 {
00642 throw worm_exception("PrepareToRun() reported not ready");
00643 }
00644
00645
00646
00647
00648
00649 LastListenerPulse = time(NULL) + 5;
00650 if ( StartThread( THREAD_STACK, &ListenerThreadId ) == WORM_STAT_FAILURE )
00651 {
00652 throw worm_exception("failed starting listener thread");
00653 }
00654
00655
00656 int flag;
00657
00658
00659
00660 time(&CurrentTime);
00661 LastBeatTime = CurrentTime;
00662
00663 Running = true;
00664 do
00665 {
00666
00667 flag = tport_getflag(&CommandRegion);
00668 if( flag == TERMINATE || flag == (int)TGlobalUtils::GetPID() )
00669 {
00670 Running = false;
00671 continue;
00672 }
00673
00674
00675 if ( (LastListenerPulse + ACCEPTABLE_SEC_TO_WAIT_FOR_SERVICE_THREAD_TO_START + 2) < time(NULL) )
00676 {
00677 SendStatus( TGlobalUtils::LookupMessageTypeId("TYPE_ERROR"), 0, "listener thread stopped" );
00678 throw worm_exception("Listener thread stopped pulsing");
00679 }
00680
00681
00682 if( TGlobalUtils::GetHeartbeatInt() <= (time(&CurrentTime) - LastBeatTime) )
00683 {
00684 LastBeatTime = CurrentTime;
00685 SendStatus( TGlobalUtils::LookupMessageTypeId("TYPE_HEARTBEAT"), 0, "" );
00686 }
00687
00688
00689
00690
00691 if ( MainThreadActions() == WORM_STAT_SUCCESS )
00692 {
00693
00694 TTimeFuncs::MSecSleep(500);
00695 }
00696 else
00697 {
00698 Running = false;
00699 }
00700
00701 } while( Running );
00702
00703 }
00704 catch( worm_exception _we )
00705 {
00706 r_status = WORM_STAT_FAILURE;
00707 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00708 , "WormServerBase::Run(): error: %s\n"
00709 , _we.what()
00710 );
00711 }
00712
00713 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDOUT|WORM_LOG_TIMESTAMP
00714 , "WormServerBase::Run(): calling FinishedRunning()\n"
00715 );
00716
00717
00718 FinishedRunning();
00719
00720 if ( CommandRegion.addr != NULL )
00721 {
00722 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00723 , "WormServerBase::Listener(): detaching from command ring\n"
00724 );
00725 tport_detach( &CommandRegion );
00726 CommandRegion.addr = NULL;
00727 }
00728
00729 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDOUT|WORM_LOG_TIMESTAMP
00730 , "WormServerBase::Run(): returning.\n"
00731 );
00732
00733 return r_status;
00734 }
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 THREAD_RETURN WormServerBase::Listener( void * p_dummy )
00768 {
00769
00770 if ( WORM_LOG_TRACKING <= TGlobalUtils::GetLoggingLevel() )
00771 {
00772 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDOUT|WORM_LOG_TIMESTAMP
00773 , "WormServerBase::Listener(): Starting\n"
00774 );
00775 }
00776
00777 try
00778 {
00779 int _clientaddrlength;
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812 while( Running )
00813 {
00814 LastListenerPulse = time(NULL);
00815
00816
00817 if ( PassiveSocket == INVALID_SOCKET )
00818 {
00819 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00820 {
00821 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00822 , "WormServerBase::Listener(): calling socket_ew()\n"
00823 );
00824 }
00825
00826 if ( ( PassiveSocket = socket_ew(AF_INET, SOCK_STREAM, 0) ) == INVALID_SOCKET )
00827 {
00828 throw worm_exception("socket_ew() returned error");
00829 }
00830
00831 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00832 {
00833 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00834 , "WormServerBase::Listener(): calling setsockopt(SO_REUSEADDR)\n"
00835 );
00836 }
00837
00838
00839
00840
00841 char _value = 1;
00842 if( setsockopt( PassiveSocket, SOL_SOCKET, SO_REUSEADDR, &_value, sizeof(char *) ) != 0 )
00843 {
00844 if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
00845 {
00846 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00847 , "setsockopt() failed setting SO_REUSEADDR, can't reuse socket if crash.\n"
00848 );
00849 }
00850 }
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863 struct sockaddr_in _serverstruct;
00864
00865
00866
00867 memset( (char *)&_serverstruct, '\0', sizeof(_serverstruct) );
00868
00869 _serverstruct.sin_family = AF_INET;
00870 _serverstruct.sin_port = htons( (short)ServerPort );
00871
00872 if ((int)(_serverstruct.sin_addr.S_un.S_addr = inet_addr(ServerIPAddr)) == -1)
00873 {
00874 worm_exception _expt( "inet_addr(" );
00875 _expt += ServerIPAddr;
00876 _expt += ") failed";
00877 throw _expt;
00878 }
00879
00880
00881
00882 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00883 {
00884 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00885 , "WormServerBase::Listener(): calling bind_ew()\n"
00886 );
00887 }
00888
00889
00890 if ( bind_ew( PassiveSocket, (struct sockaddr *)&_serverstruct, sizeof(_serverstruct)) )
00891 {
00892 closesocket_ew( PassiveSocket, SOCKET_CLOSE_IMMEDIATELY_EW );
00893 PassiveSocket = INVALID_SOCKET;
00894 throw worm_exception("bind_ew() returned error");
00895 }
00896
00897 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00898 {
00899 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00900 , "WormServerBase::Listener(): calling listen_ew(%d, %d)\n"
00901 , PassiveSocket
00902 , MaxServiceThreads
00903 );
00904 }
00905
00906
00907 if ( listen_ew( PassiveSocket, MaxServiceThreads ) )
00908 {
00909 closesocket_ew( PassiveSocket, SOCKET_CLOSE_IMMEDIATELY_EW );
00910 PassiveSocket = INVALID_SOCKET;
00911 throw worm_exception("listen_ew() returned error");
00912 }
00913
00914 LastListenerPulse = time(NULL);
00915
00916 }
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 SERVICETHREADID_VECTOR _vec;
00929 _vec.reserve(ThreadsInfo.size());
00930
00931 SERVICETHREAD_MAP_ITERATOR _sttitr = ThreadsInfo.begin()
00932 , _enditr = ThreadsInfo.end()
00933 ;
00934 while ( _sttitr != _enditr )
00935 {
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 switch ( _sttitr->second.status )
00946 {
00947 case THREAD_ERROR:
00948 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00949 , "WormServerBase::Listener(): service thread %d reported error\n"
00950 , _sttitr->second.threadid
00951 );
00952 case THREAD_COMPLETED:
00953 case THREAD_DISCONNECTED:
00954 _vec.push_back( _sttitr->second.descriptor );
00955 break;
00956
00957 default:
00958 if ( (_sttitr->second.lastpulse + SERVICE_THREAD_PULSE_MAX) < time(NULL)
00959 && (_sttitr->second.status != THREAD_BLOCKINGSOCKET)
00960 )
00961 {
00962
00963
00964
00965 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
00966 , "WormServerBase::Listener(): service thread %d found hung, killing it\n"
00967 , _sttitr->second.threadid
00968 );
00969 try
00970 {
00971 closesocket_ew( _sttitr->second.descriptor, SOCKET_CLOSE_SIMPLY_EW );
00972 }
00973 catch( ... ) { }
00974 KillThread( _sttitr->second.threadid );
00975 _vec.push_back( _sttitr->second.descriptor );
00976 }
00977 break;
00978 }
00979
00980
00981 _sttitr++;
00982 }
00983
00984 for ( SOCKET _t = 0 ; _t < _vec.size() ; _t++ )
00985 {
00986 if ( TGlobalUtils::GetLoggingLevel() == WORM_LOG_DEBUG )
00987 {
00988 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
00989 , "WormServerBase::Listener(): erasing thread %d\n"
00990 , _vec[_t]
00991 );
00992 }
00993 ThreadsInfo.erase(_vec[_t]);
00994 }
00995
00996
00997
00998
00999
01000 if ( ThreadsInfo.size() == MaxServiceThreads )
01001 {
01002 if ( WORM_LOG_STATUS <= TGlobalUtils::GetLoggingLevel() )
01003 {
01004 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
01005 , "WormServerBase::Listener(): maxed out on service threads, cannot service client\n"
01006 );
01007 }
01008 TTimeFuncs::MSecSleep(WAIT_FOR_SERVICE_THREAD);
01009 }
01010 else
01011 {
01012
01013
01014
01015
01016
01017
01018
01019
01020 _ServiceThreadInfoStruct _newconn_info;
01021 _newconn_info.status = THREAD_STARTING;
01022
01023 _clientaddrlength = sizeof(_newconn_info.sock_addr);
01024
01025
01026
01027 _newconn_info.descriptor = accept_ew( PassiveSocket
01028 , (struct sockaddr*)&_newconn_info.sock_addr
01029 , &_clientaddrlength
01030 , 100
01031 );
01032
01033 if( _newconn_info.descriptor == INVALID_SOCKET )
01034 {
01035 #if defined(_WINNT) || defined(_Windows)
01036
01037 int _err = socketGetError_ew();
01038 switch( _err )
01039 {
01040 case WSAEMFILE:
01041 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01042 , "WormServerBase::Listener(): accept_ew() returned error: no descriptors available\n"
01043 );
01044
01045 break;
01046 case WSAEWOULDBLOCK:
01047
01048
01049
01050
01051
01052
01053 TTimeFuncs::MSecSleep(500);
01054 break;
01055 default:
01056 throw worm_socket_exception( WSF_ACCEPT
01057 , _err
01058 , "Socket error returned from accept_ew()"
01059 );
01060 }
01061 #else
01062
01063 closesocket_ew( PassiveSocket, SOCKET_CLOSE_IMMEDIATELY_EW );
01064 PassiveSocket = INVALID_SOCKET;
01065 continue;
01066 #endif
01067 }
01068 else
01069 {
01070 strcpy( _newconn_info.ipaddr, inet_ntoa(_newconn_info.sock_addr.sin_addr) );
01071
01072
01073
01074 if ( WORM_LOG_STATUS <= TGlobalUtils::GetLoggingLevel() )
01075 {
01076 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01077 , "WormServerBase::Listener(): Connection accepted from IP address %s\n"
01078 , _newconn_info.ipaddr
01079 );
01080 }
01081
01082 ThreadsInfo[_newconn_info.descriptor] = _newconn_info;
01083
01084 TO_THREAD_ID _newthreadid;
01085
01086 if ( StartThreadWithArg( (unsigned int)THREAD_STACK
01087 , &_newthreadid
01088 , &_newconn_info.descriptor
01089 ) == WORM_STAT_FAILURE )
01090 {
01091 closesocket_ew( _newconn_info.descriptor, SOCKET_CLOSE_IMMEDIATELY_EW );
01092 ThreadsInfo.erase(_newconn_info.descriptor);
01093 if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
01094 {
01095 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01096 , "WormServerBase::Listener(): failed to start service thread\n"
01097 , _newconn_info.ipaddr
01098 );
01099 }
01100 continue;
01101 }
01102
01103 ThreadsInfo[_newconn_info.descriptor].threadid = _newthreadid;
01104
01105
01106 if ( WORM_LOG_DETAILS <= TGlobalUtils::GetLoggingLevel() )
01107 {
01108 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01109 , "WormServerBase::Listener(): waiting for thread %d to come alive\n"
01110 , _newthreadid
01111 );
01112 }
01113
01114 LastListenerPulse = time(NULL);
01115 TTimeFuncs::MSecSleep(ACCEPTABLE_SEC_TO_WAIT_FOR_SERVICE_THREAD_TO_START);
01116
01117 if ( 0 < ThreadsInfo.count(_newconn_info.descriptor)
01118 && ThreadsInfo[_newconn_info.descriptor].status == THREAD_STARTING
01119 )
01120 {
01121 if ( WORM_LOG_ERRORS <= TGlobalUtils::GetLoggingLevel() )
01122 {
01123 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01124 , "WormServerBase::Listener(): Thread %d never went to busy, killing it\n"
01125 , _newthreadid
01126 );
01127 }
01128
01129
01130
01131 KillThread( _newthreadid );
01132 closesocket_ew( _newconn_info.descriptor, SOCKET_CLOSE_IMMEDIATELY_EW );
01133 ThreadsInfo.erase(_newconn_info.descriptor);
01134 }
01135
01136 }
01137
01138 }
01139
01140 }
01141 }
01142 catch( worm_socket_exception& _se )
01143 {
01144 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01145 , "WormServerBase::Listener(): socket exception:\n%s\n"
01146 , _se.DecodeError()
01147 );
01148 }
01149 catch( worm_exception& _we )
01150 {
01151 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR|WORM_LOG_TIMESTAMP
01152 , "WormServerBase::Listener(): %s\n"
01153 , _we.what()
01154 );
01155 }
01156
01157
01158 if ( PassiveSocket != INVALID_SOCKET )
01159 {
01160 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
01161 , "WormServerBase::Listener(): closing passive socket\n"
01162 );
01163 closesocket_ew( PassiveSocket, SOCKET_CLOSE_IMMEDIATELY_EW );
01164 PassiveSocket = INVALID_SOCKET;
01165 }
01166
01167 TLogger::Logit( WORM_LOG_TOFILE|WORM_LOG_TOSTDERR
01168 , "WormServerBase::Listener(): returning\n"
01169 );
01170
01171 }