// ----------------------------------------------------------------------------- // Copyright (c) 1995 Southeastern Universities Research Association, // Continuous Electron Beam Accelerator Facility // // This software was developed under a United States Government license // described in the NOTICE file included as part of this distribution. // // ----------------------------------------------------------------------------- // // Description: // This header file contains the class definitions for the classes // associated with the construction of a service. // // Author: Walt Akers // // Revision History: // cdevSimpleService.cc,v // Revision 1.1 1996/11/21 18:22:24 akers // Non-Server Oriented Service // // Revision 1.1 1996/04/30 15:37:38 akers // Simple CDEV Service // // Revision 1.2 1996/03/21 13:57:55 akers // Major Modifications // // Revision 1.1.1.1 1996/02/28 16:36:21 akers // Initial release of support for ACE Services // // ----------------------------------------------------------------------------- #include #include #include #include // ***************************************************************************** // * defaultCallback: // * This static function is the default callback function that will be // * utilized for send and sendNoBlock. // ***************************************************************************** static void defaultCallback(int, void *, cdevRequestObject &, cdevData &) { } // ***************************************************************************** // * trim : // * This method is used to remove any extraneous spaces from a message. // ***************************************************************************** static char * trim ( char * ptr ) { char * s1 = ptr; char * s2; if(ptr!=NULL) { // ************************************************************* // * Remove leading space from the string. // ************************************************************* for(s1=ptr; isspace(*s1) && s1!=0; s1++); if(s1!=ptr) memmove(ptr, s1, strlen(s1)+1); // ************************************************************* // * Remove any multi-space entries from the string. // ************************************************************* for(s1=ptr; *s1; s1++) if(isspace(*s1)) { for(s2=s1; *s2 && isspace(*s2); s2++); if(s2>s1+1) memmove(s1+1, s2, strlen(s2)+1); } // ************************************************************* // * Remove trailing space from the string. // ************************************************************* for(s1=&ptr[strlen(ptr)-1]; s1>=ptr && isspace(*s1); s1--) *s1=0; } return ptr; } // ***************************************************************************** // * cdevSimpleService::cdevSimpleService : // * This constructor is responsible for performing all service // * initialization. // ***************************************************************************** cdevSimpleService::cdevSimpleService ( char * name, cdevSystem & system ) : serviceFD(-1), queue(), selector(), callback(defaultCallback, NULL), cdevService(name, system) { // ********************************************************************* // * Install the ACE_service specific flags // ********************************************************************* installTags(); // ********************************************************************* // * Clear local variables // ********************************************************************* memset(&serviceFD, 0, sizeof(serviceFD)); // ********************************************************************* // * Assign the value of the read file descriptor for the selector to // * the serviceFD variable. // ********************************************************************* serviceFD = selector.readfd(); } // ***************************************************************************** // * cdevSimpleService::~cdevSimpleService : // * The destructor is protected to prevent it from being called directly. // * The destructor performs any clean-up or shutdown operations. // * // * Returns nothing. // ***************************************************************************** cdevSimpleService::~cdevSimpleService ( void ) { // ********************************************************************* // * Call flush to process all outbound messages. // ********************************************************************* flush(); // ********************************************************************* // * Clear the file descriptors used by cdev for polling. // ********************************************************************* memset(&serviceFD, 0, sizeof(serviceFD)); } // ***************************************************************************** // * cdevSimpleService::installTags : // * Installs the tags that the service and service applications // * will use. This function is static to allow servers to setup // * the necessary tags without having to instanciate a cdevSimpleService object. // ***************************************************************************** void cdevSimpleService::installTags ( void ) { } // ********************************************************************* // * cdevSimpleService::getRequestObject : // * This is the interface that cdev objects will use to obtain a // * cdevSimpleRequestObject object. The cdevSimpleRequestObject // * represents a combined device and message pair that is associated // * with the cdevSimpleService. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ********************************************************************* int cdevSimpleService::getRequestObject ( char * device, char * message, cdevRequestObject * &req) { req = new cdevSimpleRequestObject (device, message, system_); return (req ? CDEV_SUCCESS : CDEV_ERROR); } // ***************************************************************************** // * cdevSimpleService::getFd // * This function will return the list of file descriptors that the // * cdevSimpleService is using. This will allow the file descriptors to be // * used in global select and poll calls performed at the cdevSystem class // * level. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ***************************************************************************** int cdevSimpleService::getFd ( int * &fd, int & numFd ) { fd = &serviceFD; numFd = 1; return CDEV_SUCCESS; } // ********************************************************************* // * cdevSimpleService::flush : // * This function flushes all communications buffers that the // * service may have open. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ********************************************************************* int cdevSimpleService::flush ( void ) { return CDEV_SUCCESS; } // ***************************************************************************** // * cdevSimpleService::poll : // * This function polls the file descriptors used by the service // * until one of them becomes active or a discrete amount of time // * has expired. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ***************************************************************************** int cdevSimpleService::poll ( void ) { return pend(0.0001); } // ***************************************************************************** // * cdevSimpleService::pend : // * Pends until the named file descriptor (or any file descriptor // * if fd = -1) is ready. Will pend forever if the descriptor does // * not become active. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ***************************************************************************** int cdevSimpleService::pend ( int ) { while(!queue.empty()) handleOneEvent(); // ********************************************************************* // * Empty the contents of the cdevSelector object. // ********************************************************************* selector.purge(); return CDEV_SUCCESS; } // ***************************************************************************** // * cdevSimpleService::pend : // * Pends until the named file descriptor (or any file descriptor // * if fd = -1) is ready. Will pend for no longer than the user // * specified number of seconds. // * // * Returns CDEV_SUCCESS on success or CDEV_ERROR on error. // ***************************************************************************** int cdevSimpleService::pend ( double seconds, int ) { cdevTimeValue sec = seconds; cdevClock timer; timer.schedule(NULL, sec); do { handleOneEvent(); } while(!timer.expired() && !queue.empty()); // ********************************************************************* // * Empty the contents of the cdevSelector object. // ********************************************************************* return CDEV_SUCCESS; } // ***************************************************************************** // * cdevSimpleService::submit : // * This is the mechanism that the request object will use to submit a // * message to the service. It is important to note that all of the // * data provided to this object becomes the property of the service and // * must not be accessed afterwords. // ***************************************************************************** int cdevSimpleService::submit (cdevTranNode *node, char *device, char *message, cdevData *data) { cdevTransaction * transaction = new cdevTransaction; cdevServiceMessage * packet; // ********************************************************************* // * Populate the cdevTransaction structure with data. // ********************************************************************* transaction->transnum = node->transaction(); transaction->transobj = node; // ********************************************************************* // * Call trim on the device and message to remove any extra spaces. // ********************************************************************* trim(device); trim(message); // ********************************************************************* // * Populate the packet variable with the data. // ********************************************************************* packet = new cdevServiceMessage(transaction, device, message, data); // ********************************************************************* // * Place the cdevServiceMessage into the queue. // ********************************************************************* queue.enqueue(packet); // ********************************************************************* // * Add an event to the cdevSelector object in order to trigger polling // ********************************************************************* selector.insertEvent(); return CDEV_SUCCESS; } // ***************************************************************************** // * cdevSimpleService::dequeue : // * The handleOneEvent method uses this function to extract a single // * message from the service and process it. All data objects obtained // * through this function become the property of the caller and must // * be deleted. // ***************************************************************************** int cdevSimpleService::dequeue (cdevTransaction * &transaction, char * &device, char * &message, cdevData * &data) { int result = CDEV_ERROR; cdevServiceMessage * packet = (cdevServiceMessage *)queue.dequeue(); if(packet!=NULL) { transaction = packet->transaction; device = packet->device; message = packet->message; data = packet->data; result = CDEV_SUCCESS; delete packet; } return result; } // ***************************************************************************** // * cdevSimpleService::enqueue : // * The handleOneEvent method uses this function to dispatch callbacks // * after the function has been processed. // ***************************************************************************** int cdevSimpleService::enqueue (int status, cdevTransaction * trans, char * device, char * message, cdevData * data) { cdevTranNode * node = trans?trans->transobj:NULL; if(node!=NULL && node->validate(trans->transnum)==CDEV_SUCCESS) { cdevData localData; // ************************************************************* // * cdevData must be returned to the caller. // ************************************************************* if(node->resultData_==NULL) node->resultData_ = (data?data:&localData); else *(node->resultData_) = (data?*data:localData); // ************************************************************* // * Call the user provided callback function. // ************************************************************* (node->userCallback_->callbackFunction()) (status, node->userCallback_->userarg(), *node->reqObj_, *node->resultData_); // ************************************************************* // * Tag the transaction as finished // ************************************************************* node->finished(1); // ************************************************************* // * Delete the cdevTranNode if it is not permanent. // ************************************************************* if(!node->permanent()) delete node; // ************************************************************* // * Remove the event from the selector object. // ************************************************************* selector.removeEvent(); } // ********************************************************************* // * Delete the components of the message. // ********************************************************************* if(trans != NULL) delete trans; if(device != NULL) delete device; if(message != NULL) delete message; if(data != NULL) delete data; return CDEV_SUCCESS; } // ***************************************************************************** // * cdevSimpleService::handleOneEvent : // * This method allows the caller to handle individual events. This handler // * only processes one event and then returns to the caller. // ***************************************************************************** void cdevSimpleService::handleOneEvent ( void ) { cdevTransaction * transaction; char * device; char * message; cdevData * data; if(dequeue(transaction, device, message, data)==CDEV_SUCCESS) { enqueue(CDEV_SUCCESS, transaction, device, message, data); } } // ***************************************************************************** // * cdevSimpleService::getNameServer : // * This function should obtain the default name server for this object. // * It does nothing for now. // ***************************************************************************** int cdevSimpleService::getNameServer(cdevDevice * &ns) { ns = 0; return CDEV_SUCCESS; }