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