Files
2022-12-13 12:44:04 +01:00

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