00001 /* 00002 ** ServerBase -- a Earthworm base class for any TCP/Stream server 00003 */ 00004 //--------------------------------------------------------------------------- 00005 #if !defined(EWserverbaseH) 00006 #define EWserverbaseH 00007 //--------------------------------------------------------------------------- 00008 00009 #include <socket_exception.h> 00010 00011 #if defined(_WINNT) || defined(_Windows) 00012 #include <winsock2.h> // prevent conflicts with winsock.h 00013 #endif 00014 00015 extern "C" { 00016 #include <platform.h> 00017 // C++ compilers don't like the earthworm def for thr_ret 00018 #undef thr_ret 00019 #define thr_ret void fun 00020 #include <socket_ew.h> 00021 #include <transport.h> 00022 } 00023 #define _USING_EW_XPORT 1 // prevent conflict between EW & MW 00024 00025 00026 // microsoft pragma to avoid 157 messages in some cases 00027 #pragma warning(disable:4786) 00028 00029 // following includes must follow the winsock2.h include, etc. 00030 #include <threadableobject.h> 00031 #include <time.h> // time() -- for interthread heartbeats 00032 #include <configurable.h> 00033 #include <map> 00034 #include <vector> 00035 #include <worm_types.h> 00036 #include <worm_defs.h> 00037 #include <worm_signal.h> 00038 #include <logger.h> 00039 #include <globalutils.h> 00040 #include <configsource.h> 00041 00042 00043 00044 #define SERVE_MAX_THREADS 100 00045 #define WAIT_FOR_SERVICE_THREAD 3000 // milliseconds to wait for a service thread to come free 00046 00047 #define SERVICE_THREAD_SLEEP_MS 1000 // milliseconds for client to sleep between loop passes 00048 00049 #define SERVICE_THREAD_PULSE_MAX 10 // maximum seconds that the main thread will allow a service 00050 // thread to exist without getting a valid pulse before it 00051 // kills the service thread 00052 00053 #define THREAD_STACK (unsigned int)8096 00054 00055 // Absolute minumum time to listen for a message if specified 00056 #define MIN_RECV_TIMEOUT_MS 50 00057 00058 00059 enum WORM_SERVER_THREAD_STATE // Server Thread States 00060 { 00061 THREAD_ERROR = -1 00062 , THREAD_STARTING = 0 00063 , THREAD_INITIALIZING = 1 00064 , THREAD_WAITING = 2 // waiting for something to do 00065 , THREAD_PROCESSING = 3 // doing something 00066 , THREAD_BLOCKINGSOCKET = 4 00067 , THREAD_DISCONNECTED = 5 00068 , THREAD_COMPLETED = 10 00069 }; 00070 00071 typedef char CLIENT_IPADDR[16]; 00072 00073 typedef struct _ServiceThreadInfoStruct 00074 { 00075 SOCKET descriptor; // Socket descriptors 00076 TO_THREAD_ID threadid; 00077 CLIENT_IPADDR ipaddr; 00078 struct sockaddr_in sock_addr; 00079 WORM_SERVER_THREAD_STATE status; 00080 time_t lastpulse; // = time(NULL) during each pass of ClientServicer() loop 00081 } ServiceThreadInfoStruct; 00082 00083 typedef std::map<SOCKET, ServiceThreadInfoStruct> SERVICETHREAD_MAP; 00084 typedef SERVICETHREAD_MAP::iterator SERVICETHREAD_MAP_ITERATOR; 00085 00086 typedef std::vector<SOCKET> SERVICETHREADID_VECTOR; 00087 00088 //--------------------------------------------------------------------------- 00089 00090 class WormServerBase : public ThreadableObject 00091 , public TConfigurable 00092 { 00093 private: 00094 // Members in the private: area cannot be accessed by deriving classes 00095 // (except through accessor methods in the protected area) 00096 00097 // Socketing 00098 SOCKET PassiveSocket; 00099 00100 unsigned int MaxServiceThreads; // both max allowed and max waiting in listen queue 00101 00102 protected: 00103 00104 bool SocketDebug; 00105 00106 char ServerIPAddr[20]; // IP address of wave_server machine 00107 int ServerPort; // Server port for requests & replies 00108 00109 int SendTimeoutMS; // Timeout milliseconds for send_ew() calls, blocking if -1 00110 00111 // Listen() -- listens to the passive socket, starts client server threads 00112 // as requests arrive. 00113 // 00114 THREAD_RETURN Listener( void * p_dummy ); 00115 TO_THREAD_ID ListenerThreadId; 00116 long LastListenerPulse; 00117 00118 static bool DoSCNLsMatch( const char * p_s1 00119 , const char * p_c1 00120 , const char * p_n1 00121 , const char * p_l1 00122 , const char * p_s2 00123 , const char * p_c2 00124 , const char * p_n2 00125 , const char * p_l2 00126 ); 00127 00128 00129 // ======================================================================= 00130 // from TConfigurable 00131 // ======================================================================= 00132 00133 /* CheckConfig() -- allows derivative classes to report the status of their 00134 ** the lookup values. 00135 ** 00136 ** From within any deriving class, or further derivation, ALWAYS contain a call to 00137 ** <super_class>::CheckConfig() in their own CheckConfig() method... 00138 ** this ensures that all classes in the heirarchy get their chance to report status. 00139 ** 00140 ** All implementations should set ConfigStatus value to WORM_STAT_BADSTATE if there 00141 ** is a configuration problem, otherwise leave it alone. 00142 */ 00143 void CheckConfig(); 00144 00145 00146 // ======================================================================= 00147 // WormServerBase 00148 // ======================================================================= 00149 00150 // Accessor to private data 00151 // 00152 bool SetMaxThreads( unsigned short p_count ) 00153 { 00154 // Check for a sane value 00155 if ( SERVE_MAX_THREADS < p_count ) 00156 { 00157 return false; 00158 } 00159 MaxServiceThreads = p_count; 00160 return true; 00161 } 00162 00163 // not valid until after PrepToRun() 00164 int LoggingLevel; 00165 00166 00167 SERVICETHREAD_MAP ThreadsInfo; 00168 00169 int RecvTimeoutMS; // Timeout (milliseconds) to wait for message from client in ListenForMsg(), 00170 // -1 == ignored and socket made blocking during recv_ew() 00171 00172 // Ring to check for shutdown flags, to post heartbeats, etc. 00173 WORM_RING_NAME CommandRingName; // name of transport ring 00174 WORM_RING_ID CommandRingKey; // key to transport ring 00175 SHM_INFO CommandRegion; // Info structure for shared memory (command ring) 00176 00177 /* 00178 ** ListenForMsg() 00179 ** 00180 ** Listens on an active socket for a message ('\n' terminated) 00181 ** from the client. 00182 ** 00183 ** PARAMETERS: 00184 ** p_descriptor = socket descriptor for recv() 00185 ** p_rcv_buffer = buffer to receive data 00186 ** p_length = on call set to maximum chars to read, 00187 ** on return will be actual number read 00188 ** p_timeoutms = used to override RecvTimeoutMS 00189 ** If greater than zero, then use it for the 00190 ** timeout, otherwise RecvTimeoutMS is used. 00191 ** 00192 ** RETURNS 0 = read completed successfully 00193 ** -1 = read timed-out (check if p_length == 0 else p_rcv_buffer[p_length-1] == '\n') 00194 ** -2 = client closed socket (terminate service thread) 00195 ** -3 = socket error (other then time-out) 00196 ** -4 = abort to prevent buffer overrun 00197 ** 00198 ** WARNING: This method will support blocking client sockets (config 00199 ** parm RecvTimeoutMSecs not set or -1), however, if used then 00200 ** can only send a single pulse to the main thread before entering 00201 ** the client thread a potentially blocked state. 00202 ** This prevents the main thread from identifying, reporting and 00203 ** terminating hung threads. Therefore, use blocking sockets 00204 ** with caution. 00205 */ 00206 int ListenForMsg( SOCKET p_descriptor 00207 , char * p_rcv_buffer 00208 , int * p_length 00209 , int p_timeoutms = -1 // uses RecvTimeoutMS if not included in the function call (or -1) 00210 ); 00211 00212 /* 00213 ** 00214 ** RETURNS WORM_STAT_SUCCESS 00215 ** WORM_STAT_FAILURE 00216 */ 00217 WORM_STATUS_CODE SendMessage( const SOCKET p_descriptor, const char * p_msg, int * p_length ); 00218 00219 00220 /* Running -- flag indicating if the main loop is running, 00221 ** set to false by terminate message, or various 00222 ** errors, to tell all threads to exit. 00223 ** 00224 ** changed by main thread, read by others, may need to be volatile 00225 */ 00226 bool Running; 00227 00228 void SendStatus( unsigned char type, short ierr, char *note ); 00229 00230 // ReleaseServiceThreadInfo() -- enables 00231 void ReleaseServiceThreadInfo( SOCKET p_descriptor ) 00232 { 00233 if ( 0 < ThreadsInfo.count(p_descriptor) ) 00234 { 00235 ThreadsInfo.erase(p_descriptor); 00236 } 00237 } 00238 00239 00240 /* PrepareToRun() -- actions to take prior to entering main loop 00241 ** 00242 ** ALWAYS call base class's PrepareToRun() at the top 00243 ** 00244 ** RETURN: true if ready 00245 ** false if some condition prevents proper execution 00246 */ 00247 virtual bool PrepareToRun() 00248 { 00249 LoggingLevel = TGlobalUtils::GetLoggingLevel(); 00250 return true; 00251 } 00252 00253 /* MainThreadActions() -- override to implements actions performed during the main 00254 ** thread's loop (other than sending heartbeats, which are 00255 ** handled by other code. 00256 ** This is made virtual since some servers may look for input 00257 ** from a ring, some may look into the database, while others 00258 ** may only respond to requests from clients. 00259 */ 00260 virtual WORM_STATUS_CODE MainThreadActions() { return WORM_STAT_SUCCESS; } 00261 00262 /* FinishedRunning() -- actions to take after exiting main loop 00263 ** 00264 ** ALWAYS call base class's FinishedRunning() at the top 00265 */ 00266 virtual void FinishedRunning() { } 00267 00268 /* ClientServicer() -- method to perform the work of servicing a client 00269 ** 00270 ** note: THREAD_RETURN is some kind of void, so just return or leave block 00271 */ 00272 // note: THREAD_RETURN is some kind of void, so just return or leave block 00273 // 00274 virtual THREAD_RETURN ClientServicer( void * p_socketdescriptor ) = 0; 00275 00276 // MyThreadFunction is a pointer to one of the member functions of this class 00277 // (WormServerBase) that takes no parameters and returns THREAD_RETURN 00278 // THREAD_RETURN (WormServerBase::*MyThreadFunction)(void * p_argument); 00279 00280 00281 public: 00282 00283 // ======================================================================= 00284 // from TConfigurable 00285 // ======================================================================= 00286 00287 /* 00288 ** HandleConfigLine() 00289 ** 00290 ** PARMS: 00291 ** p_parser -- the parser being used, command string already 00292 ** in the current token for comparison with Its() 00293 ** 00294 ** RETURN: 00295 ** HANDLE_INVALID -- line invalid 00296 ** HANDLE_UNUSED -- line not used 00297 ** HANDLE_USED -- line used okay 00298 ** 00299 ** Override for child classes to handle command lines 00300 */ 00301 HANDLE_STATUS HandleConfigLine( ConfigSource * p_parser ); 00302 00303 // ======================================================================= 00304 // from ThreadableObject 00305 // ======================================================================= 00306 00307 /* StartThreadFunc -- used by ThreadableObject global function to reenter 00308 ** this class in a new thread 00309 */ 00310 void StartThreadFunc( void * p_arg ) 00311 { 00312 // Determining which method to enter for this server is simple: 00313 // if p_arg is NULL, then this is the call to start the 00314 // listener thread. 00315 // if p_arg is not null, then this is a call to start a 00316 // client service thread (p_arg is the socket descriptor, 00317 // used to access the thread info in the map) 00318 if ( p_arg == NULL ) 00319 { 00320 Listener(p_arg); // p_arg is ignored 00321 } 00322 else 00323 { 00324 ClientServicer(p_arg); 00325 } 00326 } 00327 00328 // ======================================================================= 00329 // WormServerBase 00330 // ======================================================================= 00331 00332 // Call this base class constructor before the constructors 00333 // for any derived classes, thusly: 00334 // 00335 // <derived-class>(const char * p_filename) : WormServerBase(p_filename) 00336 // { 00337 // .... code for derived class constructor 00338 // } 00339 // 00340 WormServerBase(); 00341 00342 ~WormServerBase(); 00343 00344 // Run() -- starts the listener thread, then parses incoming messages, 00345 // shutting everything down as needed. 00346 WORM_STATUS_CODE Run(); 00347 00348 }; 00349 00350 #endif // EWserverbaseH 00351 00352