cdev-1.7.2n
This commit is contained in:
432
extensions/cdevGenericServer/cdevClient/cdevClientRequestObject.cc
Executable file
432
extensions/cdevGenericServer/cdevClient/cdevClientRequestObject.cc
Executable file
@@ -0,0 +1,432 @@
|
||||
#include <ctype.h>
|
||||
#include <cdevDirectory.h>
|
||||
#include <cdevClientRequestObject.h>
|
||||
#include <cdevClock.h>
|
||||
#include <cdevTranObj.h>
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::cdevClientRequestObject :
|
||||
// * This constructor initializes the internals of a device/message
|
||||
// * pair associated with a cdevClientService based service.
|
||||
// *
|
||||
// * Returns nothing.
|
||||
// *
|
||||
// * Remember it is the responsibility of the requestObject to ensure
|
||||
// * that the message is not laden with extraneous spaces.
|
||||
// *****************************************************************************
|
||||
cdevClientRequestObject::cdevClientRequestObject ( char * device, char * msg, cdevSystem & system)
|
||||
: cdevRequestObject(device, msg, system),
|
||||
syncCallback(defaultCallback, (void *)&sendStatus),
|
||||
handler(NULL), contextID(-1)
|
||||
{
|
||||
char message[256];
|
||||
char * ptr;
|
||||
|
||||
*server = 0;
|
||||
*DDL_server = 0;
|
||||
|
||||
// *********************************************************************
|
||||
// * Remove any extra spaces from the message.
|
||||
// * Copy user supplied msg to a message buffer to allow
|
||||
// * modification in this routine since the user supplied
|
||||
// * msg could be a constant string
|
||||
// *********************************************************************
|
||||
strncpy (message, msg, sizeof (message) - 1);
|
||||
message[255] = 0;
|
||||
|
||||
for(ptr=message; *ptr!=0; ptr++)
|
||||
{
|
||||
if(isspace(*ptr))
|
||||
{
|
||||
char * nextChar;
|
||||
|
||||
for(nextChar=ptr+1; isspace(*nextChar) && *nextChar!=0; nextChar++);
|
||||
if(nextChar!=ptr+1) strcpy(ptr+1, nextChar);
|
||||
*ptr=' ';
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * Remove all trailing spaces from the message.
|
||||
// *********************************************************************
|
||||
for(ptr = message+(strlen(message)-1); ptr>=message && isspace(*ptr); ptr--)
|
||||
{
|
||||
*ptr=0;
|
||||
}
|
||||
// *********************************************************************
|
||||
// * Determine the commandCode from the message string.
|
||||
// *********************************************************************
|
||||
if(!strncmp(message, "get ", 4)) commandCode = GET_COMMAND;
|
||||
else if(!strncmp(message, "set ", 4)) commandCode = SET_COMMAND;
|
||||
else if(!strncmp(message, "monitorOn ", 10)) commandCode = MONITOR_ON_COMMAND;
|
||||
else if(!strncmp(message, "monitorOff ", 11)) commandCode = MONITOR_OFF_COMMAND;
|
||||
else commandCode = OTHER_COMMAND;
|
||||
|
||||
// *********************************************************************
|
||||
// * Determine the messageCode from the message string.
|
||||
// *********************************************************************
|
||||
if(!strcmp(message, "get servers")) messageCode = GET_SERVERS_MESSAGE;
|
||||
else if(!strcmp(message, "get default")) messageCode = GET_DEFAULT_MESSAGE;
|
||||
else if(!strcmp(message, "set default")) messageCode = SET_DEFAULT_MESSAGE;
|
||||
else if(!strcmp(message, "disconnect")) messageCode = DISCONNECT_MESSAGE;
|
||||
else if(!strcmp(message, "get ClientInfo")) messageCode = GET_CLIENTINFO_MESSAGE;
|
||||
else if(!strcmp(message, "get ServerInfo")) messageCode = GET_SERVERINFO_MESSAGE;
|
||||
else messageCode = OTHER_MESSAGE;
|
||||
|
||||
// *********************************************************************
|
||||
// * Attempt to read the server name from the DDL file.
|
||||
// *********************************************************************
|
||||
cdevData output;
|
||||
|
||||
sprintf (DDL_server, "resolveServiceData %s %s", device, message);
|
||||
if((system.nameServer()).send(DDL_server, NULL, &output)==CDEV_SUCCESS)
|
||||
{
|
||||
*DDL_server = 0;
|
||||
output.get ("server", DDL_server, 256);
|
||||
}
|
||||
else *DDL_server = 0;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::~cdevClientRequestObject:
|
||||
// * This is the destructor for the object. It will free any memory that it
|
||||
// * has allocated and remove itself from its associated ServerHandler
|
||||
// * callback.
|
||||
// *****************************************************************************
|
||||
cdevClientRequestObject::~cdevClientRequestObject ( void )
|
||||
{
|
||||
if(handler!=NULL) handler->unregisterServerCallback(this);
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::getState :
|
||||
// * Returns the connection state of the cdevClientRequestObject.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::getState ( void )
|
||||
{
|
||||
ServerHandler * Handler = NULL;
|
||||
return (getServerHandler(&Handler)==CDEV_SUCCESS)?CDEV_STATE_NOTCONNECTED:CDEV_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::className :
|
||||
// * Obtains the name of this class as a string.
|
||||
// *****************************************************************************
|
||||
const char * cdevClientRequestObject::className ( void ) const
|
||||
{
|
||||
return "cdevClientRequestObject";
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::setContext :
|
||||
// * This method is called to set the context of the request object. The
|
||||
// * first step in this process is to determine if the caller has specified
|
||||
// * a server in the context. If so, the server name should be set to that
|
||||
// * value. Next call the setContext method of the underlying
|
||||
// * cdevRequestObject...
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::setContext (cdevData& cxt)
|
||||
{
|
||||
cdevClientService * svc = (cdevClientService *)service_;
|
||||
int result = CDEV_SUCCESS;
|
||||
int newContextID = 0;
|
||||
|
||||
if((newContextID = svc->contexts.insert(cxt))!=contextID)
|
||||
{
|
||||
ServerHandler * Handler = NULL;
|
||||
|
||||
if(handler!=NULL) handler->unregisterServerCallback(this);
|
||||
|
||||
contextID = newContextID;
|
||||
*server = 0;
|
||||
handler = NULL;
|
||||
|
||||
cxt.get ("server", server, 256);
|
||||
getServerHandler(&Handler);
|
||||
|
||||
result = cdevRequestObject::setContext(cxt);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::sendNoBlock :
|
||||
// * This function allows the caller to submit an asynchronous message to the
|
||||
// * server for processing.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::sendNoBlock (cdevData & in, cdevData & out)
|
||||
{ return sendNoBlock(&in, &out); }
|
||||
int cdevClientRequestObject::sendNoBlock (cdevData * in, cdevData & out)
|
||||
{ return sendNoBlock(in, &out); }
|
||||
int cdevClientRequestObject::sendNoBlock (cdevData & in, cdevData * out)
|
||||
{ return sendNoBlock(&in, out); }
|
||||
int cdevClientRequestObject::sendNoBlock (cdevData * in, cdevData * out)
|
||||
{
|
||||
cdevClientService * svc = (cdevClientService *)service_;
|
||||
cdevTranObj * xobj = new cdevTranObj(&system_, this, out, &svc->syncCallback);
|
||||
ServerHandler * Handler = NULL;
|
||||
int status = CDEV_SUCCESS;
|
||||
|
||||
xobj->disableDeleteCbk();
|
||||
|
||||
if((status=getServerHandler(&Handler))==CDEV_SUCCESS)
|
||||
{
|
||||
status = svc->enqueue(Handler, in, *xobj);
|
||||
}
|
||||
else delete xobj;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::sendCallback :
|
||||
// * This function allows the caller to submit an asynchronous message to the
|
||||
// * server for processing.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::sendCallback (cdevData & in, cdevCallback & callback)
|
||||
{ return sendCallback(&in, callback); }
|
||||
int cdevClientRequestObject::sendCallback (cdevData * in, cdevCallback & callback)
|
||||
{
|
||||
cdevCallback * cb = new cdevCallback(callback);
|
||||
cdevClientService * svc = (cdevClientService *)service_;
|
||||
cdevTranObj * xobj = new cdevTranObj(&system_, this, NULL, cb);
|
||||
ServerHandler * Handler = NULL;
|
||||
int status = CDEV_SUCCESS;
|
||||
|
||||
xobj->enableDeleteCbk();
|
||||
|
||||
if((status=getServerHandler(&Handler))==CDEV_SUCCESS)
|
||||
{
|
||||
status = svc->enqueue(Handler, in, *xobj);
|
||||
}
|
||||
else delete xobj;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::send :
|
||||
// * The send interface is used to provide synchronous I/O with the service.
|
||||
// *
|
||||
// * Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::send ( cdevData & in, cdevData & out )
|
||||
{ return send(&in, &out); }
|
||||
int cdevClientRequestObject::send ( cdevData * in, cdevData & out )
|
||||
{ return send(in, &out); }
|
||||
int cdevClientRequestObject::send ( cdevData & in, cdevData * out )
|
||||
{ return send(&in, out); }
|
||||
int cdevClientRequestObject::send ( cdevData * in, cdevData * out )
|
||||
{
|
||||
int status = CDEV_SUCCESS;
|
||||
cdevClientService * svc = (cdevClientService *)service_;
|
||||
cdevTranObj * xobj = new cdevTranObj(&system_, this, out, &syncCallback);
|
||||
ServerHandler * Handler;
|
||||
|
||||
sendStatus.completionCode = 0;
|
||||
sendStatus.finished = 0;
|
||||
xobj->disableDeleteCbk();
|
||||
|
||||
if((status=getServerHandler(&Handler))==CDEV_SUCCESS)
|
||||
{
|
||||
if((status = svc->enqueue(Handler, in, *xobj))==CDEV_SUCCESS)
|
||||
{
|
||||
// *****************************************************
|
||||
// * I used to wait for a response here only if the outbound
|
||||
// * cdevData object was non-null. However, that provided
|
||||
// * unexpected behavior to the client. Now I wait whether
|
||||
// * output data is expected or not.
|
||||
// *****************************************************
|
||||
cdevTimeValue t(waitPeriod());
|
||||
cdevClock timer;
|
||||
timer.schedule(NULL,t);
|
||||
|
||||
// *****************************************************
|
||||
// * WAITING WITH system_.pend():
|
||||
// * Previously I was using system_.pend() to process
|
||||
// * events while waiting for the service to respond.
|
||||
// * This resulted in a lock-up when the connection
|
||||
// * could not be established or if the connection
|
||||
// * collapsed while in use.
|
||||
// *
|
||||
// * WAITING WITH system_.poll():
|
||||
// * When in a heavy inbound traffic situation, the
|
||||
// * calls from other services will trample all over
|
||||
// * the inbound data coming from the server.
|
||||
// * This results in unreliable delivery and processing
|
||||
// * of messages from the server.
|
||||
// *
|
||||
// * WAITING WITH service_.poll():
|
||||
// * So far so good.
|
||||
// *****************************************************
|
||||
|
||||
while(!sendStatus.finished && !timer.expired()) service_->poll();
|
||||
if (!sendStatus.finished)
|
||||
{
|
||||
svc->cancel(*xobj);
|
||||
status = CDEV_ERROR;
|
||||
system_.reportError(
|
||||
CDEV_SEVERITY_ERROR,
|
||||
"cdevRequestObject",
|
||||
this,
|
||||
"Server failed to respond after %.1f seconds",
|
||||
(float)waitPeriod());
|
||||
}
|
||||
else
|
||||
{
|
||||
status = sendStatus.completionCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
else delete xobj;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::defaultCallback :
|
||||
// * This is the callback function that is used by the object to
|
||||
// * receive callbacks for send operations.
|
||||
// *****************************************************************************
|
||||
void cdevClientRequestObject::defaultCallback (int status, void * user, cdevRequestObject &, cdevData &)
|
||||
{
|
||||
SendStatus * result = (SendStatus *)user;
|
||||
|
||||
if(result)
|
||||
{
|
||||
result->completionCode = status;
|
||||
result->finished = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::executeServerHandlerCallback :
|
||||
// * The requestObject registers itself with the ServerHandler when it
|
||||
// * attaches to it... If the Serverhandler is destroyed, it will
|
||||
// * call this method on all of the registered request objects in order
|
||||
// * to notify them that it is going away. This allows the request
|
||||
// * object to clear the pointer to the ServerHandler.
|
||||
// *****************************************************************************
|
||||
void cdevClientRequestObject::executeServerHandlerCallback (ServerHandler * Handler)
|
||||
{
|
||||
if(Handler==handler)
|
||||
{
|
||||
/*
|
||||
* system_.reportError(CDEV_SEVERITY_INFO, "cdevRequestObject",
|
||||
* this, "Connection to %s broken for %s:%s",
|
||||
* Handler->get_server(), device().name(), message());
|
||||
*/
|
||||
handler=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::getServerHandler :
|
||||
// * This method is used to obtain the ServerHandler for this request
|
||||
// * object...
|
||||
// *
|
||||
// * The following rules will be followed:
|
||||
// *
|
||||
// * 1) If a server has been specified in the context, then that
|
||||
// * server will be used.
|
||||
// *
|
||||
// * - otherwise -
|
||||
// *
|
||||
// * 2) If a server has been specified in the service data of the
|
||||
// * DDL file, then that server will be used.
|
||||
// *
|
||||
// * - otherwise -
|
||||
// *
|
||||
// * 3) The default server as specified at the cdevClientService will
|
||||
// * be used.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::getServerHandler (ServerHandler ** Handler)
|
||||
{
|
||||
cdevClientService * svc = (cdevClientService *)service_;
|
||||
int result = CDEV_SUCCESS;
|
||||
|
||||
*Handler = NULL;
|
||||
|
||||
if (*server==0 && *DDL_server!=0) strcpy(server, DDL_server);
|
||||
if (*server!=0 && handler==NULL)
|
||||
{
|
||||
if((*Handler = svc->connect(server))==NULL) result = CDEV_ERROR;
|
||||
else
|
||||
{
|
||||
handler = *Handler;
|
||||
handler->registerServerCallback(this);
|
||||
}
|
||||
}
|
||||
else *Handler = handler;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::isRequestRestartable :
|
||||
// * This method allows the caller to determine if the request object
|
||||
// * is restartable. If a server goes down and then a new server comes
|
||||
// * up in its place, this method will be called for each request object
|
||||
// * that has an outstanding request that has not been serviced.
|
||||
// * If the isRequestRestartable method returns 1, the request will be
|
||||
// * sent to the new server - otherwise, the request will be terminated.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::isRequestRestartable ( void )
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
switch(getCommandCode())
|
||||
{
|
||||
case GET_COMMAND:
|
||||
case MONITOR_ON_COMMAND:
|
||||
result = 1;
|
||||
break;
|
||||
|
||||
case SET_COMMAND:
|
||||
case MONITOR_OFF_COMMAND:
|
||||
default:
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * cdevClientRequestObject::getContextID :
|
||||
// * This method will retrieve the identifier of the context that is
|
||||
// * currently in use by this object.
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::getContextID ( void )
|
||||
{
|
||||
return contextID;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * getCommandCode :
|
||||
// * This method will return the current value of the commandCode variable.
|
||||
// * This variable is used to identify the VERB that is utilized by this
|
||||
// * cdevClientRequestObject. The default set of verbs are "get", "set",
|
||||
// * "monitorOn", and "monitorOff".
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::getCommandCode ( void ) { return commandCode; }
|
||||
|
||||
// *****************************************************************************
|
||||
// * getMessageCode :
|
||||
// * This method will return the current value of the messageCode variable.
|
||||
// * This variable is used to identify the message that is utilized by this
|
||||
// * cdevClientRequestObject. The default set of supported messages are
|
||||
// * "get servers", "get default", "set default", and "disconnect".
|
||||
// *****************************************************************************
|
||||
int cdevClientRequestObject::getMessageCode ( void ) { return messageCode; }
|
||||
|
||||
Reference in New Issue
Block a user