527 lines
17 KiB
C++
Executable File
527 lines
17 KiB
C++
Executable File
#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;
|
|
}
|
|
}
|
|
|