Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

serverbase.h

Go to the documentation of this file.
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 

Generated on Tue May 6 09:16:10 2003 for Earthworm Libs by doxygen1.3-rc3