cdev-1.7.2n
This commit is contained in:
506
extensions/cdevGenericServer/cdevClient/ServerInterface.cc
Executable file
506
extensions/cdevGenericServer/cdevClient/ServerInterface.cc
Executable file
@@ -0,0 +1,506 @@
|
||||
#include "cdevClock.h"
|
||||
#include "ServerInterface.h"
|
||||
|
||||
cdevReactor ServerInterface::Reactor;
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerConnectionList::ServerConnectionList :
|
||||
// * Constructor for the list of active connections that is being managed
|
||||
// * by the ServerHandler.
|
||||
// *****************************************************************************
|
||||
ServerConnectionList::ServerConnectionList ( void )
|
||||
{
|
||||
maxItems = ALLOCATION_COUNT;
|
||||
items = (ServerHandler **)malloc(maxItems*sizeof(ServerHandler *));
|
||||
memset(items, 0, maxItems*sizeof(ServerHandler *));
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerConnectionList::~ServerConnectionList :
|
||||
// * Destructor for the list of active connections that is being managed
|
||||
// * by the ServerHandler.
|
||||
// *****************************************************************************
|
||||
ServerConnectionList::~ServerConnectionList ( void )
|
||||
{
|
||||
free (items);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerConnectionList::find :
|
||||
// * Locates a ServerHandler object that is associated with the specified
|
||||
// * server name.
|
||||
// *****************************************************************************
|
||||
ServerHandler * ServerConnectionList::find ( char * server )
|
||||
{
|
||||
int i;
|
||||
for(i=0;
|
||||
i<maxItems &&
|
||||
items[i]!=NULL &&
|
||||
strcmp(server, items[i]->getServer());
|
||||
i++);
|
||||
return (i<maxItems && items[i]!=NULL)?items[i]:(ServerHandler *)NULL;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerConnectionList::insert :
|
||||
// * Inserts the new ServerHandler object specified by handler into the
|
||||
// * server connection list if it does not already exist there...
|
||||
// *****************************************************************************
|
||||
int ServerConnectionList::insert ( ServerHandler * handler )
|
||||
{
|
||||
int result = -1;
|
||||
if(handler!=NULL)
|
||||
{
|
||||
int i;
|
||||
char * server = handler->getServer();
|
||||
for(i=0;
|
||||
i<maxItems &&
|
||||
items[i]!=NULL &&
|
||||
items[i]!=handler &&
|
||||
strcmp(server, items[i]->getServer());
|
||||
i++);
|
||||
|
||||
if(i>=maxItems)
|
||||
{
|
||||
items = (ServerHandler **) realloc(items, 2*maxItems*sizeof(ServerHandler *));
|
||||
memset(&items[maxItems], 0, maxItems*sizeof(ServerHandler *));
|
||||
maxItems*=2;
|
||||
}
|
||||
|
||||
if(items[i]==NULL)
|
||||
{
|
||||
items[i] = handler;
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerConnectionList::remove :
|
||||
// * Removes the ServerHandler object specified by handler if it exists in
|
||||
// * list.
|
||||
// *****************************************************************************
|
||||
int ServerConnectionList::remove ( ServerHandler * handler )
|
||||
{
|
||||
int result = -1;
|
||||
if(handler!=NULL)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<maxItems && items[i]!=NULL && items[i]!=handler; i++);
|
||||
if(i<maxItems && items[i]==handler)
|
||||
{
|
||||
items[i] = NULL;
|
||||
if(i<maxItems-1) memmove(&items[i], &items[i+1], (maxItems-(i+1))*sizeof(ServerHandler *));
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerConnectionList::remove :
|
||||
// * locates and removes the ServerHandler specified by server and returns
|
||||
// * a pointer to the handler that was removed.
|
||||
// *****************************************************************************
|
||||
ServerHandler * ServerConnectionList::remove ( char * server )
|
||||
{
|
||||
ServerHandler * handler = find(server);
|
||||
if(handler!=NULL) remove(handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::ServerInterface :
|
||||
// * This is the constructor for the ServerInterface class. This class
|
||||
// * will establish and maintain a collection of connections to cdevServers.
|
||||
// *****************************************************************************
|
||||
ServerInterface::ServerInterface ( void )
|
||||
: connections(),
|
||||
connectionQueues(),
|
||||
defaultServer(NULL),
|
||||
defaultServerHandler(NULL),
|
||||
maxFd(32)
|
||||
{
|
||||
fdList = (int *)malloc( sizeof(int)*maxFd);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::~ServerInterface :
|
||||
// * This is the destructor for the class. It is responsible for releasing
|
||||
// * any memory that might have been previously allocated to the class.
|
||||
// *****************************************************************************
|
||||
ServerInterface::~ServerInterface ( void )
|
||||
{
|
||||
if(defaultServer) delete defaultServer;
|
||||
free (fdList);
|
||||
|
||||
// *********************************************************************
|
||||
// * Remove each of the ServerHandlers from the list and delete them.
|
||||
// * This will remove them from the global reactor and will terminate
|
||||
// * the connections.
|
||||
// *
|
||||
// * Note: When deleting a ServerHandler - it submits a FAILED_TO_SEND
|
||||
// * message for each of the packets that it could not send. Because
|
||||
// * destroying this class implies that the cdevService is being
|
||||
// * destroyed also, this class will simply delete each of the packets
|
||||
// * and will not forward any other information.
|
||||
// *********************************************************************
|
||||
ServerHandler * handler;
|
||||
char * buf;
|
||||
size_t len;
|
||||
while((handler = connections[0])!=NULL)
|
||||
{
|
||||
while(handler->dequeue(&buf, &len)==0) delete buf;
|
||||
connections.remove(handler);
|
||||
delete handler;
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * Iterate through the queues associated with servers and remove
|
||||
// * all messages that have not been transmitted.
|
||||
// *********************************************************************
|
||||
StringHashIterator iter(&connectionQueues);
|
||||
iter.first();
|
||||
while((buf = iter.key())!=NULL)
|
||||
{
|
||||
FifoQueue * queue = (FifoQueue *)iter.data();
|
||||
connectionQueues.remove(buf);
|
||||
while(queue->dequeue(&buf, &len)==0) delete buf;
|
||||
delete queue;
|
||||
iter.first();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::getDefault :
|
||||
// * This method allows the caller to obtain a pointer to the name of the
|
||||
// * default server.
|
||||
// *****************************************************************************
|
||||
char * ServerInterface::getDefault ( void )
|
||||
{
|
||||
return defaultServer;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::setDefault :
|
||||
// * This method allows the caller to set the name of the default server.
|
||||
// *****************************************************************************
|
||||
void ServerInterface::setDefault ( char * Default )
|
||||
{
|
||||
if(defaultServer!=NULL)
|
||||
{
|
||||
delete defaultServer;
|
||||
defaultServer = NULL;
|
||||
defaultServerHandler = NULL;
|
||||
}
|
||||
if(Default!=NULL && *Default)
|
||||
{
|
||||
defaultServer = strdup(Default);
|
||||
defaultServerHandler = connect(defaultServer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::connect :
|
||||
// * This is a stub method that should be overridden by the developer in
|
||||
// * a child class.
|
||||
// *****************************************************************************
|
||||
ServerHandler * ServerInterface::connect ( char *, char *, unsigned short )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::disconnect :
|
||||
// * This is a stub method that should be overridden by the developer in
|
||||
// * a child class.
|
||||
// *****************************************************************************
|
||||
ServerHandler * ServerInterface::disconnect ( char * )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::enqueue :
|
||||
// * This enqueue mechanism is called by the client if they have already
|
||||
// * identified the server that they wish to communicate with and have
|
||||
// * obtained a pointer to its ServerHandler object.
|
||||
// *
|
||||
// * If the specified server handler is NULL then the message will be
|
||||
// * submitted to the default server.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::enqueue( ServerHandler * handler, char * binary, size_t binaryLen )
|
||||
{
|
||||
int result;
|
||||
|
||||
if(handler!=NULL || (handler=defaultServerHandler)!=NULL ||
|
||||
(defaultServer!=NULL && (handler=(defaultServerHandler=connect(defaultServer)))!=NULL))
|
||||
{
|
||||
handler->enqueue(binary, binaryLen);
|
||||
result = CDEV_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
outputError(CDEV_SEVERITY_ERROR,
|
||||
"ServerInterface::enqueue",
|
||||
"No default server has been specified");
|
||||
result = CDEV_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::getQueue :
|
||||
// * This method allows the caller to obtain a pointer to the FifoQueue
|
||||
// * associated with a specific server. This queue is then attached to
|
||||
// * the ServerHandler that is connected to that server.
|
||||
// *****************************************************************************
|
||||
FifoQueue * ServerInterface::getQueue ( char * server )
|
||||
{
|
||||
FifoQueue * queue = (FifoQueue *)connectionQueues.find(server);
|
||||
if(queue==NULL)
|
||||
{
|
||||
queue=new FifoQueue;
|
||||
connectionQueues.insert(server, (void *)queue);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::isPacketValid :
|
||||
// * This method is called by the ServerHandler after it has been restarted.
|
||||
// * If the ServerHandler inherits packets that are already in the queue, it
|
||||
// * will call this method for each pcket in order to determine if they are
|
||||
// * valid. If the packets are no longer valid (i.e., there is no longer
|
||||
// * a cdevTransObj associated with them, they will be deleted. Otherwise,
|
||||
// * they will be submitted to the server.
|
||||
// *
|
||||
// * Because this functionality will be handled in a derived class, this
|
||||
// * method will always return 1 to indicate that the packet is valid.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::isPacketValid ( char * binary, size_t binaryLen )
|
||||
{
|
||||
return (binary!=NULL && binaryLen>0)?1:0;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::getFd :
|
||||
// * This mechanism is used to obtain a list of the file descriptors that
|
||||
// * are used by the ServerInterface. These file descriptors may then be
|
||||
// * used for polling.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::getFd (int * &fd, int &numFd )
|
||||
{
|
||||
int idx = 0;
|
||||
|
||||
numFd = 0;
|
||||
|
||||
while(connections[idx]!=NULL)
|
||||
{
|
||||
if((numFd+1)>maxFd)
|
||||
{
|
||||
maxFd*=2;
|
||||
fdList = (int *)realloc(fdList, maxFd*sizeof(int));
|
||||
}
|
||||
fdList[numFd++] = connections[idx++]->getHandle();
|
||||
}
|
||||
|
||||
if(numFd) fd = fdList;
|
||||
else fd = NULL;
|
||||
|
||||
return CDEV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::flush :
|
||||
// * This mechanism is used to flush all outbound buffers to their respective
|
||||
// * servers.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::flush ( void )
|
||||
{
|
||||
// *********************************************************************
|
||||
// * First - determine if there is any outbound data that needs to be
|
||||
// * processed. Walk through the connectionQueue objects - which exist
|
||||
// * even if the connection has been lost - and count up the number of
|
||||
// * queues that are not empty.
|
||||
// *********************************************************************
|
||||
StringHashIterator iter(&connectionQueues);
|
||||
FifoQueue * queue = NULL;
|
||||
int needsFlush = 0;
|
||||
|
||||
// *********************************************************************
|
||||
// * Invoke a brief reactor.checkHandlers in order to cause any
|
||||
// * dead ServerHandlers to be removed from the Reactor. Then
|
||||
// * attempt to reattach to any ServerHandlers that have
|
||||
// * outbound data.
|
||||
// *********************************************************************
|
||||
char * server;
|
||||
Reactor.checkHandlers();
|
||||
|
||||
for(iter.first(); (server=iter.key())!=NULL; iter++)
|
||||
{
|
||||
queue = (FifoQueue *)iter.data();
|
||||
if(queue && !queue->empty())
|
||||
{
|
||||
needsFlush++;
|
||||
connect(server);
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * At this point he needsFlush variable will be non-zero if any of
|
||||
// * the queues contain outbound data. The remainder of this code
|
||||
// * only needs to be performed if this is the case.
|
||||
// *********************************************************************
|
||||
if(needsFlush)
|
||||
{
|
||||
// *************************************************************
|
||||
// * Provide a maximum timeout value of 5 seconds. If the system
|
||||
// * cannot be flushed in that amount of time - then an error or
|
||||
// * a hang must exist on the other side.
|
||||
// *************************************************************
|
||||
cdevTimeValue t(5.0);
|
||||
cdevClock timer;
|
||||
timer.schedule(NULL, t);
|
||||
|
||||
// *************************************************************
|
||||
// * While there are sockets that have outbound data AND the
|
||||
// * timer has not expired - process events.
|
||||
// *************************************************************
|
||||
int idx = 0;
|
||||
while(needsFlush && !timer.expired())
|
||||
{
|
||||
needsFlush = 0;
|
||||
for(idx=0; connections[idx]!=NULL; idx++)
|
||||
{
|
||||
if(!connections[idx]->empty())
|
||||
{
|
||||
connections[idx]->setMask(cdevEventHandler::WRITE_MASK|cdevEventHandler::EXCEPT_MASK);
|
||||
needsFlush++;
|
||||
}
|
||||
else connections[idx]->setMask(cdevEventHandler::READ_MASK|cdevEventHandler::EXCEPT_MASK);
|
||||
}
|
||||
if(needsFlush) Reactor.handleEvents(1.0, cdevReactor::UNTIL_EVENT);
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * Walk through all of the ServerHandlers and restore them to
|
||||
// * READ_MASK mode.
|
||||
// *********************************************************************
|
||||
if(needsFlush)
|
||||
{
|
||||
for(idx=0; connections[idx]!=NULL; idx++)
|
||||
{
|
||||
connections[idx]->setMask(cdevEventHandler::READ_MASK|cdevEventHandler::EXCEPT_MASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CDEV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::flush :
|
||||
// * This mechanism is used to flush all outbound buffers to their respective
|
||||
// * servers.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::flush ( int fd )
|
||||
{
|
||||
// *********************************************************************
|
||||
// * Walk through each item and locate the handler that needs to be
|
||||
// * flushed. If the connection is located, then handle events until
|
||||
// * it is empty.
|
||||
// *********************************************************************
|
||||
int i;
|
||||
for(i=0; connections[i]!=NULL && connections[i]->getHandle()!=fd; i++);
|
||||
if(connections[i]!=NULL)
|
||||
{
|
||||
cdevTimeValue t(5.0);
|
||||
cdevClock timer;
|
||||
timer.schedule(NULL, t);
|
||||
|
||||
connections[i]->setMask(cdevEventHandler::WRITE_MASK|cdevEventHandler::EXCEPT_MASK);
|
||||
while(connections[i]!=NULL && !connections[i]->empty() && !timer.expired())
|
||||
{
|
||||
Reactor.handleEvents(1.0, cdevReactor::UNTIL_EVENT);
|
||||
}
|
||||
// *************************************************************
|
||||
// * If an error occurs during the write, the ServerHandler may
|
||||
// * have been deleted - therefore, check to ensure that the
|
||||
// * connection is valid prior to restoring its mask.
|
||||
// *************************************************************
|
||||
if(connections[i]!=NULL)
|
||||
{
|
||||
connections[i]->setMask(cdevEventHandler::READ_MASK|cdevEventHandler::EXCEPT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
return CDEV_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::pend :
|
||||
// * Pends for the specified period of time. The int parameter is not used
|
||||
// * in this implementation. In later designs it may be used to allow the
|
||||
// * interface to pend on a specific file descriptor.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::pend ( double seconds, int )
|
||||
{
|
||||
// *********************************************************************
|
||||
// * Test to determine if there are any ServerHandlers in operation.
|
||||
// *********************************************************************
|
||||
if(connections[0]!=NULL)
|
||||
{
|
||||
// *************************************************************
|
||||
// * Flush outbound requests if necessary.
|
||||
// *************************************************************
|
||||
flush();
|
||||
|
||||
// *************************************************************
|
||||
// * Handle events for the specified period.
|
||||
// *************************************************************
|
||||
Reactor.handleEvents(seconds);
|
||||
}
|
||||
|
||||
return CDEV_SUCCESS;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerInterface::poll :
|
||||
// * This method polls the cdevReactor to see if any events are ready to be
|
||||
// * processed on any of the sockets. If events are ready, then they are
|
||||
// * processed immediately - otherwise, the function returns immediately.
|
||||
// *****************************************************************************
|
||||
int ServerInterface::poll ( void )
|
||||
{
|
||||
// *********************************************************************
|
||||
// * Test to determine if there are any ServerHandlers in operation.
|
||||
// *********************************************************************
|
||||
if(connections[0]!=NULL)
|
||||
{
|
||||
// *************************************************************
|
||||
// * Flush outbound requests if necessary.
|
||||
// *************************************************************
|
||||
flush();
|
||||
|
||||
// *************************************************************
|
||||
// * Handle events for 0 seconds - effectively polling.
|
||||
// *************************************************************
|
||||
Reactor.handleEvents(0.0001, cdevReactor::UNTIL_EVENT);
|
||||
}
|
||||
|
||||
return CDEV_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user