cdev-1.7.2n
This commit is contained in:
526
extensions/cdevGenericServer/cdevClient/ServerHandler.cc
Executable file
526
extensions/cdevGenericServer/cdevClient/ServerHandler.cc
Executable file
@@ -0,0 +1,526 @@
|
||||
#include <cdevClock.h>
|
||||
#include <ServerInterface.h>
|
||||
#include <xdrClass.h>
|
||||
#include <SignalManager.h>
|
||||
#include <clipMagicNumber.h>
|
||||
|
||||
#define _CDEV_CONNECTION_RETRIES 5
|
||||
|
||||
SignalManager ServerHandler::signalManager;
|
||||
int ServerHandler::signalManagerInit = 0;
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandlerCallbackNode:
|
||||
// * This is a node of a linked list that isolates the ServerHandlerCallback
|
||||
// * object from inadverntently being corrupted by being placed in more
|
||||
// * than one ServerHandler object.
|
||||
// *
|
||||
// * The ALLOCATION_COUNT of 128 forces the allocation of blocks that are
|
||||
// * close to 1 kilobyte in size.
|
||||
// *****************************************************************************
|
||||
class ServerHandlerCallbackNode
|
||||
{
|
||||
friend class ServerHandler;
|
||||
private:
|
||||
static ServerHandlerCallbackNode * freeList_;
|
||||
ServerHandlerCallbackNode * next;
|
||||
ServerHandlerCallback * callback;
|
||||
enum { ALLOCATION_COUNT=128 };
|
||||
|
||||
ServerHandlerCallbackNode ( void );
|
||||
public:
|
||||
ServerHandlerCallbackNode ( ServerHandlerCallback * Callback );
|
||||
~ServerHandlerCallbackNode( void );
|
||||
void * operator new ( size_t );
|
||||
void operator delete ( void * ptr );
|
||||
};
|
||||
|
||||
ServerHandlerCallbackNode * ServerHandlerCallbackNode::freeList_;
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::ServerHandler
|
||||
// * Default constructor for the ServerHandler class
|
||||
// *****************************************************************************
|
||||
ServerHandler::ServerHandler ( char * Server, ServerInterface * Interface )
|
||||
: SocketReader(CLIP_MAGIC_NUMBER), SocketWriter(CLIP_MAGIC_NUMBER),
|
||||
queue(*(Interface->getQueue(Server))), serverface(Interface), callbacks(NULL),
|
||||
enqueuedPackets(0), enqueuedBytes(0), clientID(-1), contextID(-1),
|
||||
tagChanged(1), serverQuitFlag(0)
|
||||
{
|
||||
strncpy(server, Server, 256);
|
||||
server[255] = 0;
|
||||
hostName[0] = 0;
|
||||
clientID = getNextClientID();
|
||||
|
||||
if(!signalManagerInit) signalManager.installDefaults();
|
||||
|
||||
// *********************************************************************
|
||||
// * If any data exists in the queue for this server, walk through each
|
||||
// * entry and determine if it is valid - if so, reenqueue it,
|
||||
// * otherwise, delete it.
|
||||
// *********************************************************************
|
||||
if(!queue.empty())
|
||||
{
|
||||
FifoQueue tempQueue;
|
||||
char * binary;
|
||||
size_t len;
|
||||
while(queue.dequeue(&binary, &len)==0)
|
||||
{
|
||||
if(serverface->isPacketValid(binary, len))
|
||||
{
|
||||
tempQueue.enqueue(binary, len);
|
||||
}
|
||||
else delete binary;
|
||||
}
|
||||
while(tempQueue.dequeue(&binary, &len)==0)
|
||||
{
|
||||
enqueue(binary, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::outputError :
|
||||
// * This mechanism is used to report errors to the system.
|
||||
// *****************************************************************************
|
||||
int ServerHandler::outputError(int severity, char *name, char *formatString, ...)
|
||||
{
|
||||
va_list argp;
|
||||
static char msg[1024];
|
||||
|
||||
va_start (argp, formatString);
|
||||
vsprintf (msg, formatString, argp);
|
||||
va_end (argp);
|
||||
|
||||
return serverface->outputError(severity, name, msg);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * open:
|
||||
// * Established a connection with the host specified by remote_sap
|
||||
// *****************************************************************************
|
||||
int ServerHandler::open ( const cdevAddr & addr )
|
||||
{
|
||||
int result = 0;
|
||||
int count = 0;
|
||||
|
||||
result = stream.connect (addr);
|
||||
|
||||
if (result != -1)
|
||||
{
|
||||
if((result = serverface->Reactor.registerHandler(this, READ_MASK|WRITE_MASK|EXCEPT_MASK))==-1)
|
||||
{
|
||||
handleClose();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ~ServerHandler:
|
||||
// * Default destructor for the ServerHandler object.
|
||||
// *****************************************************************************
|
||||
ServerHandler::~ServerHandler (void)
|
||||
{
|
||||
ServerHandlerCallbackNode * cb = callbacks;
|
||||
|
||||
// *********************************************************************
|
||||
// * Write a -1 as the packetLength to the connection in order to
|
||||
// * terminate.
|
||||
// *********************************************************************
|
||||
if(stream.getHandle()>0 && serverQuitFlag==0)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
void (*action)(int) = signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
writeGoodbye();
|
||||
|
||||
#ifndef _WIN32
|
||||
signal(SIGPIPE, action);
|
||||
#endif
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * Contact all of the objects that rely on the existance of this
|
||||
// * class.
|
||||
// *********************************************************************
|
||||
while(cb!=NULL)
|
||||
{
|
||||
ServerHandlerCallbackNode * oldCB = cb;
|
||||
cb = cb->next;
|
||||
oldCB->callback->executeServerHandlerCallback(this);
|
||||
delete oldCB;
|
||||
}
|
||||
|
||||
// *********************************************************************
|
||||
// * Perform standard shutdown steps.
|
||||
// *********************************************************************
|
||||
if(reactor) reactor->extractHandler(this);
|
||||
handleClose();
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::getHostName:
|
||||
// * This function returns the name of the remote host.
|
||||
// *****************************************************************************
|
||||
char * ServerHandler::getHostName( void )
|
||||
{
|
||||
if(*hostName==0)
|
||||
{
|
||||
cdevInetAddr addr;
|
||||
if(stream.getRemoteAddress (addr)==0)
|
||||
{
|
||||
const char * ptr=addr.getHostName();
|
||||
if(ptr) strncpy (hostName, ptr, MAXHOSTNAMELEN+1);
|
||||
}
|
||||
}
|
||||
return hostName;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::getName :
|
||||
// * Allows the caller to obtain the name of the class.
|
||||
// *****************************************************************************
|
||||
char * ServerHandler::getName (void) const
|
||||
{
|
||||
return "ServerHandler";
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::getHandle
|
||||
// * Allows the caller to obtain the file identifier of the socket.
|
||||
// *****************************************************************************
|
||||
int ServerHandler::getHandle (void) const
|
||||
{
|
||||
return stream.getHandle();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::getServer:
|
||||
// * Allows the caller to obtain the name of the connected server.
|
||||
// *****************************************************************************
|
||||
char * ServerHandler::getServer (void) const
|
||||
{
|
||||
return (char *)server;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * handleClose:
|
||||
// * Closes the stream.
|
||||
// *****************************************************************************
|
||||
int ServerHandler::handleClose (void)
|
||||
{
|
||||
serverface->disconnect(server);
|
||||
stream.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * handleInput :
|
||||
// * This function is called when data is ready to be read from a connected
|
||||
// * socket. This function will read the data from the socket, and will then
|
||||
// * submit the buffer to the ServerInterface class for processing.
|
||||
// *****************************************************************************
|
||||
int ServerHandler::handleInput (void)
|
||||
{
|
||||
int retval = 0;
|
||||
char * buf = NULL;
|
||||
size_t len = 0;
|
||||
int result = 1;
|
||||
|
||||
// *****************************************************************************
|
||||
// * Record oriented semantics dictate that the length of the transmission
|
||||
// * always preceeds the actual data. Therefore, read the length of the
|
||||
// * transmission into the len variable.
|
||||
// *****************************************************************************
|
||||
while(result>0)
|
||||
{
|
||||
result = read(&buf, (int *)&len);
|
||||
|
||||
switch(result)
|
||||
{
|
||||
// *************************************************************
|
||||
// * A return value of SHUTDOWN_CODE indicates that a negative
|
||||
// * one was provided as the packet length - indicating a
|
||||
// * shutdown...
|
||||
// *************************************************************
|
||||
case SHUTDOWN_CODE:
|
||||
outputError(CDEV_SEVERITY_INFO, (char *)getName(),
|
||||
"Connection to %s terminated by client", getHostName());
|
||||
retval = -1;
|
||||
break;
|
||||
|
||||
// *************************************************************
|
||||
// * A return value of -1 indicates an error occured while
|
||||
// * reading from the socket. A value of -1 is returned to
|
||||
// * shutdown the socket and remove it from the reactor.
|
||||
// *************************************************************
|
||||
case -1:
|
||||
outputError(CDEV_SEVERITY_WARN, (char *)getName(),
|
||||
"Error reading from connection to client %s", getHostName());
|
||||
retval = -1;
|
||||
break;
|
||||
|
||||
// *************************************************************
|
||||
// * A return value of 0 means that no data was ready to be
|
||||
// * retrieved from the socket.
|
||||
// *************************************************************
|
||||
case 0:
|
||||
break;
|
||||
|
||||
// *************************************************************
|
||||
// * Any other value returned from the socket represents the
|
||||
// * number of bytes actually read into the local Session object.
|
||||
// *************************************************************
|
||||
default:
|
||||
serverface->enqueue(ServerInterface::COMPLETED, this, buf, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * Return the value specified by retval.
|
||||
// *****************************************************************************
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * handleOutput :
|
||||
// * This function is called when data is ready to be transmitted to a
|
||||
// * connected socket. This function will read the data from the queue,
|
||||
// * translate it to XDR, and then transmit it to the client.
|
||||
// *****************************************************************************
|
||||
int ServerHandler::handleOutput ( void )
|
||||
{
|
||||
int retval = 0;
|
||||
char * buf = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
// *****************************************************************************
|
||||
// * Attempt to transmit or continue transmitting the data. Note, the peek
|
||||
// * method is used to attempt to writeEnqueue a data item without actually
|
||||
// * removing it from the outbound queue. If the item can be writeEnqueued,
|
||||
// * then the dequeue method is called to remove it from the queue...
|
||||
// * This method is repeated until the output buffer is fully populated.
|
||||
// *****************************************************************************
|
||||
if(!writing() && dequeue(&buf, &len)==0)
|
||||
{
|
||||
int full = 0;
|
||||
while(!full)
|
||||
{
|
||||
if(!(full = writeEnqueue(buf, len)))
|
||||
{
|
||||
delete buf;
|
||||
full = dequeue(&buf, &len);
|
||||
}
|
||||
else undequeue(buf, len);
|
||||
}
|
||||
if(writeContinue()<0) retval = -1;
|
||||
}
|
||||
else if(writing())
|
||||
{
|
||||
if(writeContinue()<0) retval = -1;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * Display an error message if the transmission failed.
|
||||
// *****************************************************************************
|
||||
if(retval!=0)
|
||||
{
|
||||
outputError(CDEV_SEVERITY_WARN, (char *)getName(),
|
||||
"Error transmitting to %s", getHostName());
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * If there are no further messages in the outbound queue and the
|
||||
// * ACE_Event_Handler has finished servicing the current message, turn off the
|
||||
// * WRITE_MASK for this ACE_Event_Handler.
|
||||
// *****************************************************************************
|
||||
if(empty() && !writing())
|
||||
{
|
||||
setMask(READ_MASK|EXCEPT_MASK);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * Return the value specified by retval.
|
||||
// *****************************************************************************
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * handleExcept :
|
||||
// * This function is called when out of band data has been received from
|
||||
// * the server. It will terminate the connection with the server.
|
||||
// *****************************************************************************
|
||||
int ServerHandler::handleExcept ( void )
|
||||
{
|
||||
stream.close();
|
||||
serverQuitFlag=1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * registerServerCallback :
|
||||
// * This method is called to add a ServerHandlerCallback object to the list
|
||||
// * of objects that the ServerHandler will notify when it is destroyed...
|
||||
// * This notification process protects objects that use this class for
|
||||
// * communications from using a pointer to a ServerHandler that has been
|
||||
// * deleted.
|
||||
// *****************************************************************************
|
||||
void ServerHandler::registerServerCallback(ServerHandlerCallback * cb)
|
||||
{
|
||||
ServerHandlerCallbackNode *cbPrev=NULL, *cbNext=callbacks;
|
||||
|
||||
while(cbNext!=NULL && cbNext->callback!=cb)
|
||||
{
|
||||
cbPrev = cbNext;
|
||||
cbNext = cbNext->next;
|
||||
}
|
||||
if(cbNext==NULL)
|
||||
{
|
||||
if(cbPrev==NULL) callbacks = new ServerHandlerCallbackNode(cb);
|
||||
else cbPrev->next = new ServerHandlerCallbackNode(cb);
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// * unregisterServerCallback :
|
||||
// * This method is used to remove a ServerHandlerCallback object from the
|
||||
// * list of objects that will be notified when the ServerHandler object
|
||||
// * is destroyed.
|
||||
// *****************************************************************************
|
||||
void ServerHandler::unregisterServerCallback (ServerHandlerCallback * cb)
|
||||
{
|
||||
ServerHandlerCallbackNode *cbPrev=NULL, *cbNext=callbacks;
|
||||
|
||||
while(cbNext!=NULL && cbNext->callback!=cb)
|
||||
{
|
||||
cbPrev = cbNext;
|
||||
cbNext = cbNext->next;
|
||||
}
|
||||
if(cbNext->callback==cb)
|
||||
{
|
||||
if(cbPrev==NULL) callbacks = cbNext->next;
|
||||
else cbPrev->next = cbNext->next;
|
||||
delete cbNext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * enqueue :
|
||||
// * This method places an object into the embedded FifoQueue and will force
|
||||
// * a flush of the socket if it reaches the high water mark.
|
||||
// *****************************************************************************
|
||||
void ServerHandler::enqueue (char * buf, size_t len)
|
||||
{
|
||||
enqueuedPackets++;
|
||||
enqueuedBytes+=len;
|
||||
queue.enqueue(buf, len);
|
||||
if(enqueuedPackets>100 || enqueuedBytes>16000)
|
||||
{
|
||||
serverface->flush(getHandle());
|
||||
enqueuedPackets=0;
|
||||
enqueuedBytes=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandler::getNextClientID :
|
||||
// * This method allows the caller to retrieve a unique clientID to be
|
||||
// * assigned to a client. The nextClientID value is automatically
|
||||
// * incremented.
|
||||
// *****************************************************************************
|
||||
short ServerHandler::getNextClientID ( void )
|
||||
{
|
||||
static short nextClientID = 0;
|
||||
|
||||
nextClientID++;
|
||||
if(nextClientID<=0) nextClientID = 1;
|
||||
return nextClientID;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandlerCallbackNode::ServerHandlerCallbackNode :
|
||||
// * Default constructor for the ServerHandlerCallbackNode class.
|
||||
// *****************************************************************************
|
||||
ServerHandlerCallbackNode::ServerHandlerCallbackNode ( void )
|
||||
: callback(NULL), next(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandlerCallbackNode::ServerHandlerCallbackNode :
|
||||
// * Parameterized constructor for the ServerHandlerCallbackNode class.
|
||||
// *****************************************************************************
|
||||
ServerHandlerCallbackNode::ServerHandlerCallbackNode( ServerHandlerCallback * Callback )
|
||||
: callback(Callback), next(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandlerCallbackNode::~ServerHandlerCallbackNode :
|
||||
// * Destructor for the ServerHandlerCallbackNode class.
|
||||
// *****************************************************************************
|
||||
ServerHandlerCallbackNode::~ServerHandlerCallbackNode( void )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandlerCallbackNode::operator new :
|
||||
// * Gets a ServerHandlerCallbackNode instance from the freelist.
|
||||
// *****************************************************************************
|
||||
void * ServerHandlerCallbackNode::operator new ( size_t )
|
||||
{
|
||||
ServerHandlerCallbackNode * result = NULL;
|
||||
|
||||
if(freeList_==NULL)
|
||||
{
|
||||
freeList_ = ::new ServerHandlerCallbackNode[ALLOCATION_COUNT];
|
||||
for(int i=0; i<ALLOCATION_COUNT; i++)
|
||||
{
|
||||
freeList_[i].next =
|
||||
(i<(ALLOCATION_COUNT-1))?&freeList_[i+1]:(ServerHandlerCallbackNode *)NULL;
|
||||
}
|
||||
}
|
||||
if(freeList_!=NULL)
|
||||
{
|
||||
result = freeList_;
|
||||
freeList_ = result->next;
|
||||
result->next = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// * ServerHandlerCallbackNode::operator delete :
|
||||
// * Returns a ServerHandlerCallbackNode instance to the freelist.
|
||||
// *****************************************************************************
|
||||
void ServerHandlerCallbackNode::operator delete ( void * ptr )
|
||||
{
|
||||
ServerHandlerCallbackNode * node = (ServerHandlerCallbackNode *)ptr;
|
||||
if(node != NULL)
|
||||
{
|
||||
node->next = freeList_;
|
||||
freeList_ = node;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user