cdev-1.7.2n

This commit is contained in:
2022-12-13 12:44:04 +01:00
commit b3b88fc333
1357 changed files with 338883 additions and 0 deletions

View 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; }