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
Binary file not shown.
Binary file not shown.
+87
View File
@@ -0,0 +1,87 @@
#include "ClientAcceptor.h"
#include "ClientHandler.h"
// *****************************************************************************
// * ClientAcceptor:
// * Default constructor for the ClientAcceptor class
// *****************************************************************************
ClientAcceptor::ClientAcceptor (cdevSessionManager & s)
: server(s)
{
}
// *****************************************************************************
// * ClientAcceptor::~ClientAcceptor:
// * Destructor for the ClientAcceptor class
// *****************************************************************************
ClientAcceptor::~ClientAcceptor (void)
{
if(reactor) reactor->extractHandler(this);
handleClose();
}
// *****************************************************************************
// * open:
// * Initializes the listening socket
// *****************************************************************************
int ClientAcceptor::open (const cdevInetAddr &addr)
{
int result = -1;
if (this->acceptor.open (addr, TRUE) == -1)
{
outputError(CDEV_SEVERITY_SEVERE, (char *)getName(),
"Failed to open listening port");
}
else if (acceptor.setFlags (O_NONBLOCK) == -1)
{
outputError(CDEV_SEVERITY_ERROR, (char *)getName(),
"Could not enable non-blocking I/O");
}
else result = 0;
return result;
}
// *****************************************************************************
// * getHandle:
// * Returns the device descriptor of the listening socket
// *****************************************************************************
int ClientAcceptor::getHandle (void) const
{
return acceptor.getHandle ();
}
// *****************************************************************************
// * handleInput:
// * Accepts a connection on a listening socket and then creates a
// * ClientHandler class to manage the connection.
// *****************************************************************************
int ClientAcceptor::handleInput (void)
{
cdevInetAddr addr;
ClientHandler *svc_handler = new ClientHandler(server);
if (acceptor.accept (*svc_handler, &addr) != -1)
{
svc_handler->open(this);
}
else
{
outputError(CDEV_SEVERITY_ERROR, (char *)getName(),
"Failed to accept connection");
}
// *********************************************************************
// * Always return 0... Otherwise, the accepting socket will
// * be destroyed and a crippled server is all that will remain.
// *********************************************************************
return 0;
}
// *****************************************************************************
// * handleClose:
// * Closes the listening socket
// *****************************************************************************
int ClientAcceptor::handleClose (void)
{
acceptor.close ();
return 0;
}
+268
View File
@@ -0,0 +1,268 @@
#include "ClientHandler.h"
#include "ClientAcceptor.h"
#include <clipMagicNumber.h>
// *****************************************************************************
// * ClientHandler:
// * Default constructor for the ClientHandler class
// *****************************************************************************
ClientHandler::ClientHandler (cdevSessionManager & s)
: server(s), queue(NULL), clientQuitFlag(0),
SocketReader(CLIP_MAGIC_NUMBER), SocketWriter(CLIP_MAGIC_NUMBER),
packetsSent(0), packetsRecv(0)
{
hostName[0] = 0;
}
// *****************************************************************************
// * ClientHandler::getHostName:
// * This function returns the name of the remote host.
// *****************************************************************************
char * ClientHandler::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;
}
// *****************************************************************************
// * open:
// * Initializes the new socket and adds this ClientHandler class to
// * the reactor
// *****************************************************************************
int ClientHandler::open (class ClientAcceptor * )
{
cdevInetAddr addr;
int result = 0;
if (stream.getRemoteAddress (addr) == -1)
{
outputError(CDEV_SEVERITY_SEVERE, (char *)getName(),
"Couldn't get local address");
result = -1;
}
else
{
if (server.Reactor.registerHandler (this, READ_MASK|WRITE_MASK|EXCEPT_MASK)!=0)
{
outputError(CDEV_SEVERITY_SEVERE, (char *)getName(),
"Cannot register handler with reactor");
result = -1;
}
else {
// *****************************************************
// * Get the socket number and use it to identify the
// * socket within the cdevSessionManager.
// *****************************************************
int handle = getHandle();
if((queue = server.findSocket(handle))!=NULL)
{
server.removeSocket(handle);
}
queue = server.addSocket(handle);
outputError(CDEV_SEVERITY_INFO, (char *)getName(),
"Establishing connection to %s on socket %i",
getHostName(), handle);
}
}
return result;
}
// *****************************************************************************
// * getHandle:
// * Returns the device descriptor for the underlying socket
// *****************************************************************************
int ClientHandler::getHandle (void) const
{
return stream.getHandle ();
}
// *****************************************************************************
// * ~ClientHandler:
// * Destructor for the ClientHandler object
// *****************************************************************************
ClientHandler::~ClientHandler (void)
{
if(stream.getHandle()>0 && clientQuitFlag==0) writeGoodbye();
if(reactor) reactor->extractHandler(this);
handleClose();
}
// *****************************************************************************
// * handleClose:
// * Removes the object from the reactor class and then deletes it.
// *****************************************************************************
int ClientHandler::handleClose (void)
{
outputError(CDEV_SEVERITY_INFO, (char *)getName(),
"Terminating connection to %s on socket %i",
getHostName(), queue?queue->getSocketID():0);
stream.close();
if(queue)
{
server.removeSocket(queue->getSocketID());
queue = NULL;
}
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 processIncomingPacket function for processing.
// *****************************************************************************
int ClientHandler::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)
{
if(buf==NULL) result = read(&buf, (int *)&len);
else result = readNextPacket(&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 buffer object.
// *************************************************************
default:
server.enqueue(getHandle(), buf, len);
packetsSent++;
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 ClientHandler::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() && queue!=NULL && queue->peek(&buf, &len)==0)
{
int full = 0;
while(!full)
{
full = writeEnqueue(buf, len);
if(!full)
{
queue->dequeue(&buf, &len);
delete buf;
buf = NULL;
len = 0;
if(queue->peek(&buf, &len)!=0) full=-1;
packetsRecv++;
}
}
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(retval!=0 || ((queue==NULL || queue->empty()) && !writing()))
{
setMask(READ_MASK|EXCEPT_MASK);
}
// *****************************************************************************
// * Return the value specified by retval.
// *****************************************************************************
return retval;
}
// *****************************************************************************
// * ClientHandler::handleExcept :
// * This function is called when out of band data is ready to be received
// * from the socket.
// *****************************************************************************
int ClientHandler::handleExcept(void)
{
clientQuitFlag=1;
return -1;
}
@@ -0,0 +1,13 @@
#include <IntHash.h>
IntHashNode::IntHashNode ( int HashInt, void * HashData)
: next(NULL)
{
hashInt = HashInt;
hashData = HashData;
}
IntHashNode::~IntHashNode ( void )
{
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+148
View File
@@ -0,0 +1,148 @@
ARCH = OS
SHOBJ = YES
#include ../include/makeinclude/Makefile.$(ARCH)
include ../include/makeinclude/Makefile.linux
APPNAME = "CDEV Generic Client/Server Engine"
TEMPLINKS = ClientAcceptor.cc\
ClientHandler.cc\
cdevServer.cc\
cdevServerTools.cc\
cdevSessionManager.cc\
ServerInterface.cc\
ServerHandler.cc\
cdevClientRequestObject.cc\
cdevClientService.cc\
cdevMessage.cc\
cdevMessageBinary.cc\
cdevPacket.cc\
cdevContextMap.cc\
cdevMonitorTable.cc\
cdevTagMap.cc\
SignalManager.cc\
cdevAddr.cc\
cdevEventHandler.cc\
cdevHandleSet.cc\
cdevReactor.cc\
cdevSocket.cc\
cdevSocketAcceptor.cc\
cdevSocketConnector.cc\
cdevSocketDatagram.cc\
cdevSocketStream.cc\
cdevStreamNode.cc\
cdevStreamQueue.cc\
cdevTime.cc\
fifo.cc\
IntHash.cc
LIBS = $(CDEVLIBS) $(OSLIBS)
SERVER_OBJS = $(OBJDIR)/cdevServer.o\
$(OBJDIR)/cdevServerTools.o\
$(OBJDIR)/cdevSessionManager.o\
$(OBJDIR)/ClientHandler.o\
$(OBJDIR)/ClientAcceptor.o\
$(OBJDIR)/cdevTagMap.o\
$(OBJDIR)/cdevMonitorTable.o
CLIENT_OBJS = $(OBJDIR)/cdevClientService.o\
$(OBJDIR)/cdevClientRequestObject.o\
$(OBJDIR)/ServerInterface.o\
$(OBJDIR)/ServerHandler.o
COMMON_OBJS = $(OBJDIR)/cdevPacket.o\
$(OBJDIR)/cdevMessageBinary.o\
$(OBJDIR)/cdevMessage.o\
$(OBJDIR)/cdevContextMap.o\
$(OBJDIR)/SignalManager.o\
$(OBJDIR)/fifo.o\
$(OBJDIR)/IntHash.o
ACE_OBJS = $(OBJDIR)/cdevAddr.o\
$(OBJDIR)/cdevEventHandler.o\
$(OBJDIR)/cdevHandleSet.o\
$(OBJDIR)/cdevReactor.o\
$(OBJDIR)/cdevSocket.o\
$(OBJDIR)/cdevSocketAcceptor.o\
$(OBJDIR)/cdevSocketConnector.o\
$(OBJDIR)/cdevSocketDatagram.o\
$(OBJDIR)/cdevSocketStream.o\
$(OBJDIR)/cdevStreamNode.o\
$(OBJDIR)/cdevStreamQueue.o\
$(OBJDIR)/cdevTime.o
OBJS = $(SERVER_OBJS) $(CLIENT_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
# ******************************************************************************
# * The BINARIES definition names all of the binary files that should be deleted
# * whenever "make clean" is executed.
# ******************************************************************************
BINARIES = $(CDEVLIB)/libcdevGenericServer.$(SHARED_EXT) \
$(CDEVLIB)/libcdevGenericServer.a
ifeq ($(SHOBJ),YES)
TARGETS = $(TEMPLINKS) \
$(CDEVLIB)/libcdevGenericServer.$(SHARED_EXT)
else
TARGETS = $(TEMPLINKS) \
$(CDEVLIB)/libcdevGenericServer.a
endif
targets : $(TARGETS)
$(TEMPLINKS) :
@cp $^ $@
$(CDEVLIB)/libcdevGenericServer.a : $(OBJS)
$(LINK.a) $@ $^
@$(RANLIB) $@ > /dev/null
$(CDEVLIB)/libcdevGenericServer.$(SHARED_EXT) : $(OBJS)
$(LINK.so) -o $@ $^ -L$(CDEVLIB) -lrsvc $(NETLIBS)
$(CDEVLIB)/libcdevServer.a : $(SERVER_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
$(LINK.a) $@ $^
@$(RANLIB) $@ > /dev/null
$(CDEVLIB)/libcdevServer.$(SHARED_EXT) : $(SERVER_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
$(LINK.so) -o $@ $^ -L$(CDEVLIB) -lrsvc $(NETLIBS)
$(CDEVLIB)/libcdevClient.a : $(CLIENT_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
$(LINK.a) $@ $^
@$(RANLIB) $@ > /dev/null
$(CDEVLIB)/libcdevClient.$(SHARED_EXT) : $(CLIENT_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
$(LINK.so) -o $@ $^ -L$(CDEVLIB) -lrsvc $(NETLIBS)
ClientAcceptor.cc : ../cdevServer/ClientAcceptor.cc
ClientHandler.cc : ../cdevServer/ClientHandler.cc
cdevServer.cc : ../cdevServer/cdevServer.cc
cdevServerTools.cc : ../cdevServer/cdevServerTools.cc
cdevSessionManager.cc : ../cdevServer/cdevSessionManager.cc
ServerHandler.cc : ../cdevClient/ServerHandler.cc
ServerInterface.cc : ../cdevClient/ServerInterface.cc
cdevClientRequestObject.cc : ../cdevClient/cdevClientRequestObject.cc
cdevClientService.cc : ../cdevClient/cdevClientService.cc
cdevMessage.cc : ../cdevPacket/cdevMessage.cc
cdevMessageBinary.cc : ../cdevPacket/cdevMessageBinary.cc
cdevPacket.cc : ../cdevPacket/cdevPacket.cc
cdevContextMap.cc : ../cdevContextMap/cdevContextMap.cc
cdevMonitorTable.cc : ../cdevMonitorTable/cdevMonitorTable.cc
cdevTagMap.cc : ../cdevTagMap/cdevTagMap.cc
SignalManager.cc : ../common/SignalManager.cc
cdevAddr.cc : ../cdevReactor/cdevAddr.cc
cdevEventHandler.cc : ../cdevReactor/cdevEventHandler.cc
cdevHandleSet.cc : ../cdevReactor/cdevHandleSet.cc
cdevReactor.cc : ../cdevReactor/cdevReactor.cc
cdevSocket.cc : ../cdevReactor/cdevSocket.cc
cdevSocketAcceptor.cc : ../cdevReactor/cdevSocketAcceptor.cc
cdevSocketConnector.cc : ../cdevReactor/cdevSocketConnector.cc
cdevSocketDatagram.cc : ../cdevReactor/cdevSocketDatagram.cc
cdevSocketStream.cc : ../cdevReactor/cdevSocketStream.cc
cdevStreamNode.cc : ../cdevReactor/cdevStreamNode.cc
cdevStreamQueue.cc : ../cdevReactor/cdevStreamQueue.cc
cdevTime.cc : ../cdevReactor/cdevTime.cc
fifo.cc : ../common/fifo.cc
IntHash.cc : ../common/IntHash.cc
+526
View 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;
}
}
+506
View 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;
}
+257
View File
@@ -0,0 +1,257 @@
#include <SignalManager.h>
#ifdef __linux
#ifndef SIGSYS
#define SIGSYS SIGUNUSED
#endif
#endif
// *****************************************************************************
// * SignalManager::reporter :
// * This is the declaration for the error reporter.
// *****************************************************************************
ErrorReporter SignalManager::reporter;
// *****************************************************************************
// * SignalHandler::SignalHandler :
// * This is the initializer for a SignalHandler class. It holds the
// * information needed to handle a single signal number.
// *****************************************************************************
_SignalHandler_::_SignalHandler_ ( void )
: signo(0), handler(NULL), oldHandler(NULL)
{
}
// *****************************************************************************
// * SignalHandler::~SignalHandler :
// * This is the destructor for the SignlaHandler class. It will call the
// * uninstall method to remove the handler that was imposed for the signal.
// *****************************************************************************
_SignalHandler_::~_SignalHandler_ ( void )
{
uninstall ();
}
// *****************************************************************************
// * SignalHandler::install :
// * This method will install the specified signal handler function on the
// * signal number specified by signo. The old handler will be preserved
// * for later restoration.
// *****************************************************************************
void _SignalHandler_::install ( int newSigno, SignalHandlerFunc newHandler )
{
// *********************************************************************
// * If a local signal handler has already been installed on the
// * specified signal number, uninstall it before proceeding.
// *********************************************************************
if(handler!=NULL && signo==newSigno) uninstall();
// *********************************************************************
// * Setup the control variables.
// *********************************************************************
signo = newSigno;
handler = newHandler;
// *********************************************************************
// * Install the new signal handler, preserving the old handler in the
// * oact sigaction structure.
// *********************************************************************
oldHandler = signal(signo, handler);
}
// *****************************************************************************
// * SignalHandler::uninstall :
// * This method will remove a user specified signal handler and will restore
// * the previously installed handler.
// *****************************************************************************
void _SignalHandler_::uninstall ( void )
{
// *********************************************************************
// * Check to see if the signal handler has been installed. If so,
// * call sigaction to confirm that the current signal handler is the
// * one that was installed.
// *********************************************************************
if(signo!=0 && handler!=NULL)
{
SignalHandlerFunc current = signal(signo, SIG_DFL);
if(current==handler) signal(signo, oldHandler);
else signal(signo, current);
}
signo = 0;
handler = NULL;
}
// *****************************************************************************
// * SignalManager::installHandler :
// * This method will install the specified signal handler.
// *****************************************************************************
void SignalManager::installHandler (int signo, SignalHandlerFunc handler )
{
if(signo>0 && signo<=MAXSIGNAL) signals[signo-1].install(signo, handler);
}
// *****************************************************************************
// * SignalManager::uninstallHandler :
// * This method will remove a signal handler that was previously installed.
// *****************************************************************************
void SignalManager::uninstallHandler ( int signo )
{
if(signo>0 && signo<=MAXSIGNAL) signals[signo-1].uninstall();
}
// *****************************************************************************
// * SignalManager::installDefaults :
// * This method will install a default collection of signal handlers.
// *****************************************************************************
void SignalManager::installDefaults ( void )
{
static int sigList[] =
{
#if !defined (_WIN32)
SIGFPE, // Erroneous arithmetic operation.
SIGHUP, // Hangup.
SIGILL, // Illegal instruction.
SIGINT, // Terminal interrupt signal.
SIGPIPE, // Write on a socket with no one to read
SIGQUIT, // Terminal quit signal.
SIGSEGV, // Invalid memory reference.
SIGTERM, // Termination signal.
SIGBUS, // Bus error.
SIGSYS, // Bad system call.
#else
SIGABRT, // Process abort signal.
SIGFPE, // Erroneous arithmetic operation.
SIGILL, // Illegal instruction.
SIGINT, // Terminal interrupt signal.
SIGSEGV, // Invalid memory reference.
SIGTERM, // Termination signal.
#endif
0
};
for(int i=0; sigList[i]!=0; i++) installHandler(sigList[i], defaultHandler);
}
// *****************************************************************************
// * SignalManager::defaultHandler :
// * This is the default signal handler method.
// *****************************************************************************
void SignalManager::defaultHandler( int signo )
{
switch(signo)
{
// *************************************************************
// * Process the interrupt signal by reporting it and exiting.
// *************************************************************
case SIGINT:
reporter.outputError (
CDEV_SEVERITY_INFO,
"Signal Manager",
"[SIGINT] Terminating at user's request");
exit(0);
// *************************************************************
// * Process the terminate signal by reporting it and exiting.
// *************************************************************
case SIGTERM:
reporter.outputError (
CDEV_SEVERITY_INFO,
"Signal Manager",
"[SIGTERM] Terminating normally");
exit(0);
// *************************************************************
// * Process abort signal by reporting the error and exiting.
// *************************************************************
case SIGABRT:
reporter.outputError (
CDEV_SEVERITY_SEVERE,
"Signal Manager",
"[SIGABRT] Application terminating due to abort signal");
abort();
// *************************************************************
// * Process erroneous arithmetic operations by reporting them
// * and exiting.
// *************************************************************
case SIGFPE:
reporter.outputError (
CDEV_SEVERITY_SEVERE,
"Signal Manager",
"[SIGFPE] Floating point error - terminating\n");
abort();
// *************************************************************
// * Process illegal instructions by reporting them and exiting.
// *************************************************************
case SIGILL:
reporter.outputError (
CDEV_SEVERITY_SEVERE,
"Signal Manager",
"[SIGILL] Illegal instruction");
abort();
// *************************************************************
// * Process the segmentation fault signal by reporting the
// * error and terminating.
// *************************************************************
case SIGSEGV:
reporter.outputError (
CDEV_SEVERITY_SEVERE,
"Signal Manager",
"[SIGSEGV] Segmentation fault");
abort();
#if !defined(_WIN32)
// *************************************************************
// * Report pipe errors, however, do not terminate.
// *************************************************************
case SIGPIPE:
reporter.outputError (
CDEV_SEVERITY_ERROR,
"Signal Manager",
"[SIGPIPE] Write on a pipe with no one to read it");
errno = SIGPIPE;
break;
// *************************************************************
// * Process a bus error by reporting it and exiting.
// *************************************************************
case SIGBUS:
reporter.outputError (
CDEV_SEVERITY_SEVERE,
"Signal Manager",
"[SIGBUS] Bus error");
abort();
// *************************************************************
// * Process a bad system call by reporting it and exiting.
// *************************************************************
case SIGSYS:
reporter.outputError (
CDEV_SEVERITY_SEVERE,
"Signal Manager",
"[SIGSYS] Bad system call");
abort();
// *************************************************************
// * Ignore the following signals:
// * SIGHUP: hangup signal.
// * SIGQUIT: terminal quit signal
// * default: All other signals
// *************************************************************
case SIGHUP:
case SIGQUIT:
#endif
default:
break;
}
signal(signo, SignalManager::defaultHandler);
}
@@ -0,0 +1,190 @@
#include "cdevAddr.h"
// *****************************************************************************
// * cdevInetAddr::set :
// * Allows the caller to set the address using a port number and
// * internet address.
// *****************************************************************************
int cdevInetAddr::set (unsigned short portnum, long ip_addr)
{
setType(AF_INET);
setSize(sizeof(inet_addr));
inet_addr.sin_family = AF_INET;
inet_addr.sin_port = htons(portnum);
if(ip_addr == INADDR_ANY) inet_addr.sin_addr.s_addr=INADDR_ANY;
else memcpy((void *)&inet_addr.sin_addr,
(void *)&ip_addr,
sizeof(inet_addr.sin_addr));
return 0;
}
// *****************************************************************************
// * cdevInetAddr::set :
// * Allows the caller to set the address using a port number and host name.
// *****************************************************************************
int cdevInetAddr::set (unsigned short portnum, const char hostname[])
{
hostent * server_info;
long addr;
int retval;
setType(AF_INET);
setSize(sizeof(inet_addr));
memset((void *)&inet_addr, 0, sizeof(inet_addr));
if(hostname==NULL || *hostname==0)
{
errno = EINVAL;
retval = -1;
}
else if((addr=::inet_addr(hostname))!=-1 ||
::strcmp(hostname, "255.255.255.255")==0)
{
retval = set(portnum, addr);
}
else if((server_info=::gethostbyname(hostname)) != 0)
{
::memcpy((void *)&addr, (void *)server_info->h_addr, server_info->h_length);
retval = set(portnum, addr);
}
else retval = -1;
return retval;
}
// *****************************************************************************
// * cdevInetAddr::set :
// * Allows the caller to set the address using a sockaddr_in structure
// * and its length.
// *****************************************************************************
int cdevInetAddr::set (const sockaddr_in *addr, int len)
{
setType(AF_INET);
setSize(len);
memcpy((void *)&inet_addr, (void *)addr, len);
return 0;
}
// *****************************************************************************
// * cdevInetAddr::cdevInetAddr :
// * This constructor creates an empty address object.
// *****************************************************************************
cdevInetAddr::cdevInetAddr ( void )
: cdevAddr(AF_INET, sizeof(sockaddr_in))
{
::memset((void *)&inet_addr, 0, sizeof(inet_addr));
}
// *****************************************************************************
// * cdevInetAddr::cdevInetAddr :
// * This constructor copies the contents of one cdevInetAddr object to
// * the new cdevInetAddr object.
// *****************************************************************************
cdevInetAddr::cdevInetAddr ( const cdevInetAddr & addr )
: cdevAddr(AF_INET, sizeof(inet_addr))
{
memcpy((void *)&inet_addr, (void *)&addr.inet_addr, sizeof(inet_addr));
}
// *****************************************************************************
// * cdevInetAddr::cdevInetAddr :
// * This constructor creates a new cdevInetAddr object that contains the
// * address provided in the sockaddr_in object.
// *****************************************************************************
cdevInetAddr::cdevInetAddr (const sockaddr_in *addr, int len)
{
set(addr, len);
}
// *****************************************************************************
// * cdevInetAddr::cdevInetAddr :
// * This constructor initializes the new cdevInetAddr object using the
// * specified port number and host name.
// *****************************************************************************
cdevInetAddr::cdevInetAddr (unsigned short portnum, char hostname[])
{
set(portnum, hostname);
}
// *****************************************************************************
// * cdevInetAddr::cdevInetAddr :
// * This constructor initializes the new cdevInetAddr object with the
// * specified port number and ip address.
// *****************************************************************************
cdevInetAddr::cdevInetAddr (unsigned short portnum, long ip_addr)
{
set(portnum, ip_addr);
}
// *****************************************************************************
// * cdevInetAddr::getHostName :
// * This method allows the caller to return the name of the host that
// * the cdevInetAddr structure identifies.
// *****************************************************************************
const char * cdevInetAddr::getHostName ( void ) const
{
char * retval;
hostent * hp;
int len = sizeof(inet_addr.sin_addr.s_addr);
if((hp = ::gethostbyaddr((char *)&inet_addr.sin_addr, len, addr_type))==0)
{
retval = NULL;
}
else retval = hp->h_name;
return retval;
}
// *****************************************************************************
// * cdevInetAddr::getHostAddr :
// * This method allows the caller to retrieve the internet address (in
// * string format) of the host that the cdevInetAddr object identifies.
// *****************************************************************************
const char * cdevInetAddr::getHostAddr ( void ) const
{
return ::inet_ntoa(inet_addr.sin_addr);
}
// *****************************************************************************
// * cdevInetAddr::getInetAddr :
// * This method allows the caller to obtain the internet address of the
// * host that the cdevInetAddr object identifies.
// *****************************************************************************
unsigned long cdevInetAddr::getInetAddr ( void ) const
{
return ntohl((unsigned long)inet_addr.sin_addr.s_addr);
}
// *****************************************************************************
// * cdevInetAddr::getPortNum :
// * This method allows the caller to retrieve the port number that is
// * associated with this cdevInetAddr.
// *****************************************************************************
unsigned short cdevInetAddr::getPortNum ( void ) const
{
return ntohs (inet_addr.sin_port);
}
// *****************************************************************************
// * cdevInetAddr::getAddress :
// * Returns the address of the sockaddr_in structure.
// *****************************************************************************
void * cdevInetAddr::getAddress ( void ) const
{
return (void *)&inet_addr;
}
+432
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; }
File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
#include <cdevContextMap.h>
// *****************************************************************************
// * cdevContextMap::cdevContextMap :
// * This is the constructor for the class and it initializes all
// * data items to 0 or NULL...
// *****************************************************************************
cdevContextMap::cdevContextMap ( void )
: entries(NULL), maximum(0), cnt(0)
{}
// *****************************************************************************
// * cdevContextMap::~cdevContextMap :
// * This is the destructor for the class and it will delete any
// * cdevData objects that have been allocated using new and will
// * then free the array that was allocated using malloc or realloc.
// *****************************************************************************
cdevContextMap::~cdevContextMap ( void )
{
if(entries!=NULL)
{
for(int i=0; i<maximum; i++) if(entries[i]!=NULL) delete entries[i];
free(entries);
}
entries = NULL;
maximum = 0;
cnt = 0;
}
// *****************************************************************************
// * cdevContextMap::resize :
// * This method is called to double the number of pointers that
// * are available to store context items in...
// *****************************************************************************
void cdevContextMap::resize ( void )
{
if(maximum<=0)
{
maximum = 64;
entries = (cdevData **)malloc(maximum * sizeof(cdevData *));
memset(entries, 0, maximum*sizeof(cdevData *));
}
else {
entries = (cdevData **)realloc(entries, 2*maximum*sizeof(cdevData *));
memset(&entries[maximum], 0, maximum*sizeof(cdevData *));
maximum *= 2;
}
}
// *****************************************************************************
// * cdevContextMap::insert :
// * This method is used to add a new cdevData object to the
// * cdevContextMap table... If a matching cdevData object already
// * exists in the class, then its identifier will be returned...
// * otherwise, a new cdevData object will be added to the list and
// * the index of the new item will be returned...
// *****************************************************************************
int cdevContextMap::insert ( cdevData & context )
{
int i;
int found = 0;
for(i=0;
i<cnt && (entries[i]==NULL || !(found=(*entries[i]==context)));
i++);
if(!found)
{
if(i>=maximum) resize();
entries[i] = new cdevData(context);
cnt++;
}
return i;
}
// *****************************************************************************
// * cdevContextMap::find :
// * This method allows the caller to obtain the index of a context
// * cdevData object that matches the cdevData object he provides...
// * If a matching context object cannot be found, then -1 will be
// * returned.
// *****************************************************************************
int cdevContextMap::find ( cdevData & context )
{
int i;
int found;
for(i=0;
i<cnt && (entries[i]==NULL || !(found=(*entries[i]==context)));
i++);
return (i<cnt)?i:-1;
}
// *****************************************************************************
// * cdevContextMap::asciiDump :
// * This is a diagnostic method that allows the caller to dump the
// * contents of the cdevContextMap table to a file descriptor...
// *****************************************************************************
void cdevContextMap::asciiDump ( FILE * fp )
{
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, " Diagnostic Dump of CDEV Context Map\n");
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, "Number of Entries : %i\n", cnt);
fprintf(fp, "Allocated Maximum Entries : %i\n", maximum);
for(int i=0; i<cnt; i++)
{
fprintf(fp, "\n\t------------------------------------------------\n");
fprintf(fp, "\tContext at Entry Number %i\n", i);
fprintf(fp, "\t------------------------------------------------\n");
if(entries[i]==NULL) fprintf(fp, "\t(not specified)\n");
else entries[i]->asciiDump(fp);
fflush(fp);
}
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, " End of Diagnostic Dump of CDEV Context Map\n");
fprintf(fp, "----------------------------------------------------------\n\n");
fflush(fp);
}
+96
View File
@@ -0,0 +1,96 @@
#include "cdevReactor.h"
#include "cdevEventHandler.h"
#include <math.h>
cdevEventHandler::cdevEventHandler ( void )
: mask(0),
next(NULL),
timeoutRate(0, 0),
nextTimeout(0, 0),
reactor(NULL)
{
}
cdevEventHandler::~cdevEventHandler ( void )
{
if(reactor!=NULL) reactor->extractHandler(this);
handleClose();
}
void cdevEventHandler::setHandle ( int )
{
}
int cdevEventHandler::getHandle ( void ) const
{
return -1;
}
void cdevEventHandler::setReactor (cdevReactor * r)
{
reactor = r;
}
cdevEventHandler * cdevEventHandler::getNext (void )
{
return next;
}
void cdevEventHandler::setNext (cdevEventHandler * n)
{
next = n;
}
int cdevEventHandler::getMask ( void )
{
return mask;
}
cdevReactor * cdevEventHandler::getReactor ( void )
{
return reactor;
}
cdevTime & cdevEventHandler::getTimeoutRate ( void )
{
return timeoutRate;
}
cdevTime & cdevEventHandler::getNextTimeout ( void )
{
return nextTimeout;
}
void cdevEventHandler::setMask ( unsigned Mask )
{
mask = (Mask&(READ_MASK|WRITE_MASK|EXCEPT_MASK|DONT_CALL));
}
void cdevEventHandler::setTimeoutRate ( cdevTime time )
{
timeoutRate = time;
resetTimer();
}
void cdevEventHandler::resetTimer ( void )
{
nextTimeout.setTime();
nextTimeout = nextTimeout+getTimeoutRate();
}
int cdevEventHandler::handleInput ( void ) { return 0; }
int cdevEventHandler::handleOutput ( void ) { return 0; }
int cdevEventHandler::handleExcept ( void ) { return 0; }
int cdevEventHandler::handleTimeout ( void ) { return 0; }
int cdevEventHandler::handleSignal ( void ) { return -1; }
int cdevEventHandler::handleClose ( void ) { return 0; }
@@ -0,0 +1,304 @@
//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
// Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
//
// Description:
// FD_Set Wrapper Based on ACE
//
#include "cdevHandleSet.h"
#ifndef __VMS
#ifndef __linux
extern "C" bzero (char *, int);
#endif
#else
extern "C" bzero (char *, unsigned int);
#endif
#if defined(__VMS) && defined(_TGV_MULTINET)
// *********************************************************************
// * Unfortunately when you use TGV Multinet, the bit offsets in the
// * file * descriptor bitmasks used by select() cannot be found by
// * simply using the value of the file descriptor. Fortunately, there
// * is a simple relationship between the file descriptor value and the
// * desired bit offset.
// * (These macros are required because this file accesses the file
// * descriptor bitmasks directly, without using the FD_SET(), FD_CLR(),
// * FD_ISSSET() macros).
// *********************************************************************
#define FD_TO_BIT_OFFSET( fd ) ((fd)/CHANNELSIZE)
#define FD_FROM_BIT_OFFSET( ibit ) ((ibit)*CHANNELSIZE)
#else
// *********************************************************************
// * Under most operating systems the file descriptor value and the
// * associated bit offset are one and the same.
// *********************************************************************
#define FD_TO_BIT_OFFSET( fd ) (fd)
#define FD_FROM_BIT_OFFSET( ibit ) (ibit)
#endif
#ifdef CDEV_HAS_UNDERSCORE_FDBITS
#define fds_bits __fds_bits
#endif
inline int BIT_ENABLED (unsigned long word, int bit = 1) { return (word & bit) != 0; }
inline int BIT_DISABLED (unsigned long word, int bit = 1) { return (word & bit) == 0; }
inline void SET_BIT (unsigned long &word, int bit) { word |= bit; }
inline void CLR_BIT (unsigned long &word, int bit) { word &= ~bit; }
const char cdevHandleSet::nbits_[256] =
{
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
};
// *****************************************************************************
// * Counts the number of bits enabled in N. Uses a table lookup to speed up
// * the count.
// *****************************************************************************
int cdevHandleSet::count_bits (unsigned long n) const
{
return (cdevHandleSet::nbits_[n & 0xff] + cdevHandleSet::nbits_[(n >> 8) & 0xff] +
cdevHandleSet::nbits_[(n >> 16) & 0xff] + cdevHandleSet::nbits_[n >> 24]);
}
void cdevHandleSetIterator::operator++ (void)
{
#ifdef _WIN32
this->index_++;
#else
this->val_ = (this->val_ >> 1) & cdevHandleSet::MSB_MASK;
this->num_++;
if (this->val_ == 0)
{
for (this->index_++;
this->index_ < cdevHandleSet::NUM_WORDS && fds_.mask_.fds_bits[this->index_] == 0;
this->index_++);
if (this->index_ == cdevHandleSet::NUM_WORDS)
{
this->num_ = fds_.max_handle_ + 1;
return;
}
else
{
this->val_ = fds_.mask_.fds_bits[this->index_];
this->num_ = this->index_ * cdevHandleSet::WORD_SIZE;
}
}
for (; BIT_DISABLED (this->val_); this->num_++)
this->val_ = (this->val_ >> 1) & cdevHandleSet::MSB_MASK;
#endif
}
cdevHandleSetIterator::cdevHandleSetIterator (cdevHandleSet &f)
: fds_ (f), index_ (0), num_ (f.size_ == 0 ? f.max_handle_ + 1 : 0)
{
#ifndef _WIN32
for (; fds_.mask_.fds_bits[this->index_] == 0; this->index_++)
this->num_ += cdevHandleSet::WORD_SIZE;
for (this->val_ = this->fds_.mask_.fds_bits[this->index_];
(BIT_DISABLED (this->val_)) && this->num_ < cdevHandleSet::MAX_SIZE;
this->num_++)
this->val_ = (this->val_ >> 1) & cdevHandleSet::MSB_MASK;
#endif
}
// *****************************************************************************
// * Synchronize the underlying FD_SET with the MAX_FD and the SIZE.
// *****************************************************************************
void cdevHandleSet::sync (int max)
{
#ifndef _WIN32
this->size_ = 0;
for (int i = max / cdevHandleSet::WORD_SIZE; i >= 0; i--)
this->size_ += count_bits (this->mask_.fds_bits[i]);
this->set_max (max);
#endif
}
// *****************************************************************************
// * Resets the MAX_FD after a clear of the original MAX_FD.
// *****************************************************************************
void cdevHandleSet::set_max (int current_max)
{
#ifndef _WIN32
int i = 0;
if (this->size_ == 0)
this->max_handle_ = -1;
else
{
for (i = current_max / cdevHandleSet::WORD_SIZE;
this->mask_.fds_bits[i] == 0;
i--)
;
this->max_handle_ = i * cdevHandleSet::WORD_SIZE;
for (fd_mask val = this->mask_.fds_bits[i];
(val & ~1) != 0;
val = (val >> 1) & cdevHandleSet::MSB_MASK)
this->max_handle_++;
}
#endif
}
// *****************************************************************************
// * Debugging method that prints out the underlying mask.
// *****************************************************************************
int cdevHandleSet::asciiDump (FILE * fp)
{
fprintf(fp, "[ ");
for (int i = 0; i < this->max_handle_ + 1; i++)
if (this->is_set (i))
fprintf(fp," %d ", i);
fprintf(fp, " ]");
return this->size_;
}
void cdevHandleSet::reset (void)
{
this->max_handle_ = -1;
this->size_ = 0;
FD_ZERO (&this->mask_);
}
// *****************************************************************************
// * Constructor, initializes the bitmask to all 0s.
// *****************************************************************************
cdevHandleSet::cdevHandleSet (void)
{
this->reset ();
}
cdevHandleSet::cdevHandleSet (const fd_set &fd_mask): size_ (0)
{
memcpy ((void *) &this->mask_, (void *) &fd_mask, sizeof this->mask_);
// sync is empty for WIN32
this->sync (FD_SETSIZE);
}
// *****************************************************************************
// * Returns the number of the large bit.
// *****************************************************************************
int cdevHandleSet::max_set (void) const
{
return this->max_handle_;
}
// *****************************************************************************
// * Checks whether FD is enabled.
// *****************************************************************************
int cdevHandleSet::is_set (int fd) const
{
#ifdef _WIN32
return FD_ISSET ((SOCKET)fd, &this->mask_);
#else
return FD_ISSET (fd, &this->mask_);
#endif
}
// *****************************************************************************
// * Enables the FD.
// *****************************************************************************
void cdevHandleSet::set_bit (int fd)
{
if (!this->is_set (fd))
{
#ifdef _WIN32
FD_SET ((SOCKET)fd, &this->mask_);
#else
FD_SET (fd, &this->mask_);
this->size_++;
// *****************************************************
// * again VMS system has different idea
// *****************************************************
#if defined(__VMS) && defined(_TGV_MULTINET)
if (FD_TO_BIT_OFFSET(fd) > this->max_handle_)
this->max_handle_ = FD_TO_BIT_OFFSET(fd);
#else
if (fd > this->max_handle_)
this->max_handle_ = fd;
#endif
#endif
}
}
// *****************************************************************************
// * Disables the FD.
// *****************************************************************************
void cdevHandleSet::clr_bit (int fd)
{
if (this->is_set (fd))
{
#ifdef _WIN32
FD_CLR ((SOCKET)fd, &this->mask_);
#else
FD_CLR (fd, &this->mask_);
this->size_--;
#if defined(__VMS) && defined(_TGV_MULTINET)
if (FD_TO_BIT_OFFSET(fd) == this->max_handle_)
this->set_max (this->max_handle_);
#else
if (fd == this->max_handle_)
this->set_max (this->max_handle_);
#endif
#endif
}
}
// *****************************************************************************
// * Returns a count of the number of enabled bits.
// *****************************************************************************
int cdevHandleSet::num_set (void) const
{
#ifdef _WIN32
return this->mask_.fd_count;
#else
return this->size_;
#endif
}
int cdevHandleSetIterator::operator () (void)
{
#ifdef _WIN32
return this->index_ < this->fds_.mask_.fd_count
? fds_.mask_.fd_array[this->index_] : -1;
#else
#if defined(__VMS) && defined(_TGV_MULTINET)
return FD_FROM_BIT_OFFSET(this->num_ <= this->fds_.max_handle_
? this->num_ :-1);
#else
return this->num_ <= this->fds_.max_handle_
? this->num_ : -1;
#endif
#endif
}
+310
View File
@@ -0,0 +1,310 @@
#include <cdevMessage.h>
// *****************************************************************************
// * cdevMessage::import :
// * This metod is used by the cdevPacket class to generate a cdevMessage
// * object from a cdevBinaryPacket object. In order for the cdevPacket
// * class to perform this task, the import method and the
// * CDEV_PACKET_VERSION must be registered using the
// * cdevPacket::registerImportMethod function.
// *****************************************************************************
cdevPacket * cdevMessage::import( cdevPacketBinary & packet)
{
char * binary = NULL;
size_t binaryLen = 0;
packet.streamOut(&binary, &binaryLen);
return new cdevMessage(binary, binaryLen);
}
// *****************************************************************************
// * cdevMessage::cdevMessage :
// * This is a parameterized constructor for the cdevMessage object. If none
// * of the parameters are specified then this constructor will build a
// * cdevMessage object made completely from defaults.
// *****************************************************************************
cdevMessage::cdevMessage ( short ClientID,
unsigned TransIndex,
unsigned CancelTransIndex,
unsigned LocalDataIndex,
unsigned ForeignDataIndex,
unsigned OperationCode,
int CompletionCode,
unsigned DeviceCount,
char ** DeviceList,
char * Message,
cdevData * Data,
cdevData * Context,
cdevData * TagMap)
: clientID (ClientID),
transIndex (TransIndex),
cancelTransIndex (CancelTransIndex),
localDataIndex (LocalDataIndex),
foreignDataIndex (ForeignDataIndex),
operationCode (OperationCode),
completionCode (CompletionCode),
deviceCount (DeviceCount),
deviceList (NULL),
message (NULL),
data (NULL),
context (NULL),
tagMap (NULL)
{
saveTbl.rawData=0;
if(DeviceCount>0 && DeviceList!=NULL)
{
deviceList = (char **)new char * [deviceCount];
for(int i=0; i<deviceCount; i++)
{
deviceList[i] = strdup(DeviceList[i]);
}
}
if(Message!=NULL) message = strdup(Message);
if(Data!=NULL) data = new cdevData(*Data);
if(Context!=NULL) context = new cdevData(*Context);
if(TagMap!=NULL) tagMap = new cdevData(*TagMap);
}
// *****************************************************************************
// * cdevMessage::cdevMessage :
// * This is the constructor for the object. It serves to initialize the
// * internals of the object with default values or the user specified
// * binary data if provided.
// *****************************************************************************
cdevMessage::cdevMessage ( char * binary, size_t binaryLen )
: deviceCount(0), deviceList(NULL), message(NULL),
data(NULL), context(NULL), tagMap(NULL)
{
saveTbl.rawData = 0;
streamIn(binary, binaryLen);
}
// *****************************************************************************
// * cdevMessage::cdevMessage :
// * This is the copy constructor for the object. It creates a new
// * cdevMessage object that contains all of the data specified in the
// * user provided object.
// *****************************************************************************
cdevMessage::cdevMessage ( cdevMessage & Message )
: clientID (Message.clientID),
transIndex (Message.transIndex),
cancelTransIndex (Message.cancelTransIndex),
localDataIndex (Message.localDataIndex),
foreignDataIndex (Message.foreignDataIndex),
operationCode (Message.operationCode),
completionCode (Message.completionCode),
deviceCount (Message.deviceCount),
deviceList (NULL),
message (NULL),
data (NULL),
context (NULL),
tagMap (NULL)
{
saveTbl.rawData = 0;
if(Message.deviceCount>0 && Message.deviceList!=NULL)
{
deviceList = (char **)new char * [deviceCount];
for(int i=0; i<deviceCount; i++)
{
deviceList[i] = strdup(Message.deviceList[i]);
}
}
if(Message.message!=NULL) message = strdup(Message.message);
if(Message.data!=NULL) data = new cdevData(*Message.data);
if(Message.context!=NULL) context = new cdevData(*Message.context);
if(Message.tagMap!=NULL) tagMap = new cdevData(*Message.tagMap);
}
// *****************************************************************************
// * cdevMessage::~cdevMessage :
// * This is the destructor for the class. It releases any previously
// * allocated memory prior to the destruction of the object.
// *****************************************************************************
cdevMessage::~cdevMessage ( void )
{
clear();
}
// *****************************************************************************
// * cdevMessage::clear :
// * This is the clear mechanism for the object. It is used to deallocate
// * any memory that has been allocated and set all data items to their
// * initial default values.
// *****************************************************************************
void cdevMessage::clear ( void )
{
setClientID(-1);
setTransIndex(0);
setCancelTransIndex(0);
setLocalDataIndex(0);
setForeignDataIndex(0);
setOperationCode(0);
setCompletionCode(0);
setDeviceList(NULL, 0, 0);
setMessage(NULL);
setData(NULL);
setContext(NULL);
setTagMap(NULL);
}
// *****************************************************************************
// * cdevMessage::streamIn :
// * This mechanism is used to use a binary packet to populate the
// * cdevMessage object.
// *
// * The binary stream remains the property of the caller and must be
// * delete by him.
// *****************************************************************************
int cdevMessage::streamIn( char * binary, size_t binaryLen )
{
int result = 0;
cdevMessageBinary packet;
clear();
packet.attachData(binary, binaryLen);
if(packet.hasClientID()) result+=packet.getClientID(clientID);
if(packet.hasTransIndex()) result+=packet.getTransIndex(transIndex);
if(packet.hasCancelTransIndex()) result+=packet.getCancelTransIndex(cancelTransIndex);
if(packet.hasLocalDataIndex()) result+=packet.getLocalDataIndex(localDataIndex);
if(packet.hasForeignDataIndex()) result+=packet.getForeignDataIndex(foreignDataIndex);
if(packet.hasOperationCode()) result+=packet.getOperationCode(operationCode);
if(packet.hasCompletionCode()) result+=packet.getCompletionCode(completionCode);
if(packet.hasDeviceList()) result+=packet.getDeviceList(deviceList, deviceCount);
if(packet.hasMessage()) result+=packet.getMessage(message);
if(packet.hasData())
{
data = new cdevData;
result+=packet.getData(*data);
}
if(packet.hasContext())
{
context = new cdevData;
result+=packet.getContext(*context);
}
if(packet.hasTagMap())
{
tagMap = new cdevData;
result+=packet.getTagMap(*tagMap);
}
packet.detachData();
return result;
}
// *****************************************************************************
// * cdevMessage::streamOut :
// * This mechanism is used to generate a binary representation of the
// * cdevMessage object.
// *
// * The binary stream becomes the property of the caller and he must delete
// * it when it is no longer needed.
// *****************************************************************************
int cdevMessage::streamOut( char ** binary, size_t * binaryLen )
{
cdevMessageBinary packet;
packet.set(clientID, transIndex, cancelTransIndex,
localDataIndex, foreignDataIndex, operationCode,
completionCode, deviceCount, deviceList,
message, data, context, tagMap);
packet.streamOut (binary, binaryLen);
packet.detachData();
return 0;
}
// *****************************************************************************
// * cdevMessage::asciiDump :
// * This mechanism is included to provide the ability to generate a
// * diagnostic dump of the cdevMessage object.
// *****************************************************************************
void cdevMessage::asciiDump ( FILE * fp )
{
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, " Diagnostic Dump of CDEV Message\n");
fprintf(fp, "----------------------------------------------------------\n\n");
fprintf(fp, "Client Identifier : %s\n", clientID==-1?"(not specified)":ltoa(clientID));
fprintf(fp, "Transaction Index : %s\n", transIndex==0?"(not specified)":ultoa(transIndex));
fprintf(fp, "Cancel Transaction : %s\n", cancelTransIndex==0?"(not specified)":ultoa(cancelTransIndex));
fprintf(fp, "Local Data Index : %s\n", localDataIndex==0?"(not specified)":ultoa(localDataIndex));
fprintf(fp, "Foreign Data Index : %s\n", foreignDataIndex==0?"(not specified)":ultoa(foreignDataIndex));
fprintf(fp, "Operation Code : %s\n", operationCode==0?"(not specified)":ultoa(operationCode));
fprintf(fp, "Completion Code : %i\n", completionCode);
fprintf(fp, "Save Table :\n");
fprintf(fp, " Device List %s Permanent\n", saveTbl.value.saveDeviceList?"IS":"IS NOT");
fprintf(fp, " Message %s Permanent\n", saveTbl.value.saveMessage?"IS":"IS NOT");
fprintf(fp, " Data %s Permanent\n", saveTbl.value.saveData?"IS":"IS NOT");
fprintf(fp, " Context %s Permanent\n", saveTbl.value.saveContext?"IS":"IS NOT");
fprintf(fp, " Tag Map %s Permanent\n", saveTbl.value.saveTagMap?"IS":"IS NOT");
fprintf(fp, "Number of Devices : %s\n", deviceCount==0?"(not specified)":ultoa(deviceCount));
fprintf(fp, "List of Devices : ");
if(deviceCount==0) fprintf(fp, "(not specified)\n");
else fprintf(fp, "%s\n", deviceList[0]);
for(int i=1; i<deviceCount; i++)
{
fprintf(fp, " %s\n", deviceList[i]);
}
fprintf(fp, "Message String : %s\n", message==NULL?"(not specified)":message);
fprintf(fp, "Data Object : %s", data!=NULL?"\n":"(not specified)\n");
fflush(fp);
if(data) data->asciiDump(fp);
fprintf(fp, "Context Object : %s", context!=NULL?"\n":"(not specified)\n");
fflush(fp);
if(context) context->asciiDump(fp);
fprintf(fp, "Tag Map : %s", tagMap!=NULL?"\n":"(not specified)\n");
if(tagMap)
{
size_t tagNumCnt = 0;
int * tagNums = NULL;
size_t tagNameCnt = 0;
char ** tagNames = NULL;
if(tagMap->getElems(1, &tagNumCnt)==CDEV_SUCCESS &&
tagMap->getElems(2, &tagNameCnt)==CDEV_SUCCESS &&
tagMap->getType (2)==CDEV_STRING &&
tagNumCnt==tagNameCnt)
{
char ** tagNames = NULL;
char * singleName = NULL;
tagNums = new int[tagNumCnt];
tagMap->get(1, tagNums);
if(tagNameCnt==1)
{
tagNames = &singleName;
tagMap->find(2, (void *&)singleName);
}
else tagMap->find(2, (void *&)tagNames);
for(int i=0; i<tagNumCnt; i++)
{
fprintf(fp, "\t%-26.26s= %i\n", tagNames[i], tagNums[i]);
}
delete tagNums;
}
}
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, " End of Diagnostic Dump of CDEV Message\n");
fprintf(fp, "----------------------------------------------------------\n\n");
fflush(fp);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+76
View File
@@ -0,0 +1,76 @@
#include <cdevPacket.h>
cdevPacket::ImportTable * cdevPacket::importTables = NULL;
int cdevPacket::maxTables = 0;
// *****************************************************************************
// * cdevPacket::import :
// * The import mechanism will walk through the importTables and attempt to
// * locate an entry that has the same packet version as the cdevPacketBinary
// * parameter. If a matching netry is found, then it will be used to decode
// * the binary and create a cdevPacket object from it, otherwise NULL will
// * be returned.
// *
// * Note: Subclasses of the cdevPacket class that wish to employ this
// * functionality must register their import methods and their packet
// * versions using the registerImportMethod mechanism.
// *****************************************************************************
cdevPacket * cdevPacket::import ( cdevPacketBinary & packet )
{
short packetVersion = 0;
int idx = 0;
int found = 0;
cdevPacket * result = NULL;
packet.getVersion(packetVersion);
while(idx<maxTables &&
importTables[idx].packetVersion!=0 &&
!found)
{
if(packetVersion == importTables[idx].packetVersion)
{
result = (*importTables[idx].importMethod)(packet);
found = 1;
}
else idx++;
}
return result;
}
// *****************************************************************************
// * cdevPacket::registerImportMethod :
// * This mechanism allows the user to associate an import method with a
// * particular packet version. The ImportMethod must take a reference to
// * a cdevPacketBinary as an argument and produce a pointer to a new
// * cdevPacket object.
// *****************************************************************************
void cdevPacket::registerImportMethod(short version, ImportMethod method)
{
int idx = 0;
for(idx = 0;
idx<maxTables &&
importTables[idx].packetVersion != 0 &&
importTables[idx].packetVersion != version;
idx++);
if(idx==maxTables)
{
if(maxTables==0)
{
importTables = (ImportTable *)malloc(sizeof(ImportTable));
memset(importTables, 0, sizeof(ImportTable));
maxTables = 1;
}
else {
importTables = (ImportTable *)realloc(importTables, maxTables*2*sizeof(ImportTable));
memset(&importTables[maxTables], 0, maxTables*sizeof(ImportTable));
maxTables *= 2;
}
}
importTables[idx].packetVersion = version;
importTables[idx].importMethod = method;
}
+585
View File
@@ -0,0 +1,585 @@
#include <stdio.h>
#include <string.h>
#include "cdevReactor.h"
// *****************************************************************************
// * This is the number of times that InitializeNetwork was called to perform
// * network initialization. The InitializeNetwork and corresponding
// * TerminateNetwork methods are wrappers to provide support for WIN32
// * WSAStartup and WSACleanup methods. They perform no actiual function on
// * UNIX platforms.
// *****************************************************************************
int cdevReactor::netInitCount = 0;
// *****************************************************************************
// * cdevReactor::cdevReactor :
// * This is the constructor for the cdevReactor class. It takes no
// * arguments. It will set maxEntries to the value of the MAX_SIZE
// * variable and the size variable (the highest fd installed) will be set
// * to zero.
// *
// * The method will allocate space in the handlers array for the
// * cdevEventHandlers that will be installed during operation. The
// * read_set, write_set and except_set masks will be cleared. These masks
// * will be populated later as file descriptors are added to the
// * cdevReactor.
// *****************************************************************************
cdevReactor::cdevReactor ( void )
: maxEntries(cdevHandleSet::MAX_SIZE),
size (0),
handlers (NULL),
timers (NULL)
{
if(!netInitCount)
{
if(InitializeNetwork()==0) netInitCount++;
}
else netInitCount++;
handlers = (cdevEventHandler **)malloc((maxEntries+1)*sizeof(cdevEventHandler *));
memset(handlers, 0, sizeof(cdevEventHandler *)*(maxEntries+1));
read_set.reset();
write_set.reset();
except_set.reset();
}
// *****************************************************************************
// * cdevReactor::~cdevReactor :
// * This is the destructor for the cdevReactor class. It wil first remove
// * all of the timer cdevEventHandlers from the timer array, it will then
// * remove all of the file-descriptor based cdevEventHandlers from the
// * handlers array. It will finish by deleteing the handlers array that
// * was allocated in the constructor.
// *****************************************************************************
cdevReactor::~cdevReactor ( void )
{
if(netInitCount && (-netInitCount)==0) TerminateNetwork();
while(timers!=NULL) removeHandler(timers);
for(int i=0; i<=maxEntries; i++)
{
if(handlers[i]!=NULL) removeHandler(handlers[i]);
}
delete handlers;
}
// *****************************************************************************
// * cdevReactor::calculateMask :
// * This method will walk through the handlers array and setup the read_set,
// * write_set and except_set masks.
// *****************************************************************************
void cdevReactor::calculateMask ( void )
{
int i;
read_set.reset();
write_set.reset();
except_set.reset();
size = 0;
for(i=0; i<=maxEntries; i++)
{
unsigned mask;
if(handlers[i]!=NULL)
{
mask = handlers[i]->getMask();
if(!(mask&cdevEventHandler::DONT_CALL))
{
if(mask&cdevEventHandler::READ_MASK)
{
read_set.set_bit(i);
size = i+1;
}
if(mask&cdevEventHandler::WRITE_MASK)
{
write_set.set_bit(i);
size = i+1;
}
if(mask&cdevEventHandler::EXCEPT_MASK)
{
except_set.set_bit(i);
size = i+1;
}
}
}
}
}
// *****************************************************************************
// * cdevReactor::calculateTimeout :
// * This method will walk through the timers and determine the duration of
// * time that the cdevReactor should wait for events on the file
// * descriptors before automatically terminating.
// *****************************************************************************
int cdevReactor::calculateTimeout ( cdevTime defaultPeriod, struct timeval &timeout )
{
if(defaultPeriod==cdevTime(0,0)) timeout.tv_sec=(timeout.tv_usec=0);
else {
cdevTime now;
cdevTime target;
cdevEventHandler * timer;
if(defaultPeriod<cdevTime(0,0)) defaultPeriod.setTime(60, 0);
now.setTime();
target.setTime(now+defaultPeriod);
for(timer=timers; timer!=NULL && target>now; timer=timer->getNext())
{
cdevTime nextTimeout = timer->getNextTimeout();
if(!(timer->getMask()&cdevEventHandler::DONT_CALL) &&
(double)nextTimeout > 0.0)
{
if(nextTimeout<target) target = nextTimeout;
}
}
if(target<=now) timeout.tv_sec=(timeout.tv_usec=0);
else timeout=target-now+(cdevTime)0.01;
}
return SUCCESS;
}
// *****************************************************************************
// * cdevReactor::checkHandlers :
// * This method is used to remove any cdevEventHandlers that have dead
// * sockets from the cdevReactor prior to beginning I/O operations. The
// * method calls select with all of the file handles installed. If select
// * returns a -1, then each of the file handles is checked independently.
// * When the bad handler is identified, its cdevEventHandler object will
// * be elliminated.
// * This method returns the number of cdevEventHandlers that were deleted.
// *****************************************************************************
int cdevReactor::checkHandlers ( void )
{
int i;
int eventCnt = 0;
struct timeval t;
read_set.reset();
write_set.reset();
except_set.reset();
t.tv_sec = 0;
t.tv_usec = 0;
for(i=0; i<maxEntries; i++)
{
if(handlers[i]!=NULL)
{
read_set.set_bit(i);
size = i+1;
}
}
if(cdevSelect(size, read_set, write_set, except_set, &t)<0)
{
for(i=0; i<maxEntries; i++)
{
if(handlers[i]!=NULL)
{
read_set.set_bit(i);
if(cdevSelect(i, read_set, write_set, except_set, &t)<0)
{
if(handlers[i]->handleSignal()<0)
{
removeHandler(handlers[i]);
eventCnt++;
}
}
read_set.clr_bit(i);
}
}
}
return eventCnt;
}
// *****************************************************************************
// * cdevReactor::registerHandler :
// * This method is called to register a file-descriptor based
// * cdevEventHandler with the reactor. It will first check the validity
// * of the handler and its file descriptor. It will then determine if
// * another handler already occupies the position associated with the
// * specified handle.
// *
// * If the handler is valid, it will install it in the handlers array and
// * will add it to the read_set, write_set and except_set masks as
// * required. The size variable will be incremented if the new handler
// * has the highest file-descriptor in the array.
// *****************************************************************************
int cdevReactor::registerHandler ( cdevEventHandler * handler, unsigned mask )
{
int fd = -1;
REACTOR_RESULT result = SUCCESS;
if(handler == NULL)
{
result = INVALID_HANDLER;
}
else if(handler->getReactor()!=NULL && handler->getReactor()!=this)
{
result = UNKNOWN_HANDLER;
}
else if((fd = handler->getHandle())<=0)
{
result = INVALID_HANDLE;
}
else if(fd<maxEntries && handlers[handler->getHandle()]!=NULL)
{
result = HANDLE_EXISTS;
}
else {
if(fd>=maxEntries)
{
int oldMaxEntries = maxEntries;
maxEntries = fd+1;
handlers = (cdevEventHandler **)realloc(handlers, (maxEntries+1) * sizeof(cdevEventHandler *));
memset(&handlers[oldMaxEntries], 0, sizeof(cdevEventHandler *)*((maxEntries+1)-oldMaxEntries));
}
handler->setReactor(this);
handler->setMask (mask);
handlers[fd] = handler;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::removeHandler :
// * This method allows the caller to remove an cdevEventHandler from the
// * cdevReactor and delete it. The method will call the extractHandler
// * method to remove the cdevEventHandler from the cdevReactor after which
// * the handler will be deleted.
// *****************************************************************************
int cdevReactor::removeHandler ( cdevEventHandler * handler )
{
REACTOR_RESULT result = INVALID_HANDLER;
if(handler!=NULL)
{
extractHandler(handler);
delete handler;
result = SUCCESS;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::removeHandler :
// * This method will remove the specified handler using the file descriptor
// * provided by the caller.
// *****************************************************************************
int cdevReactor::removeHandler ( int fd )
{
REACTOR_RESULT result = SUCCESS;
if(fd>0 && fd<=maxEntries)
{
result = (REACTOR_RESULT)removeHandler(handlers[fd]);
}
else result = INVALID_HANDLE;
return (int) result;
}
// *****************************************************************************
// * cdevReactor::extractHandler :
// * This method will remove the specified cdevEventHandler from the
// * cdevReactor, however, it will not delete the cdevEventHandler when
// * finished.
// *****************************************************************************
int cdevReactor::extractHandler ( cdevEventHandler * handler )
{
int fd = -1;
REACTOR_RESULT result = UNKNOWN_HANDLER;
if(handler == NULL) result = INVALID_HANDLER;
else {
cdevEventHandler * currTimer = timers;
cdevEventHandler * prevTimer = NULL;
while(currTimer!=NULL && currTimer!=handler)
{
prevTimer = currTimer;
currTimer = prevTimer->getNext();
}
if(currTimer)
{
if(prevTimer) prevTimer->setNext(currTimer->getNext());
else timers = currTimer->getNext();
result = SUCCESS;
}
if((fd = handler->getHandle())>=0 &&
fd<=maxEntries &&
handlers[fd]==handler)
{
handlers[fd] = NULL;
result = SUCCESS;
}
else for(fd=0; fd<=maxEntries; fd++)
{
if(handlers[fd]==handler)
{
handlers[fd] = NULL;
result = SUCCESS;
}
}
if(result==SUCCESS)
{
handler->setMask(0);
handler->setReactor(NULL);
}
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::getHandler :
// * This method allows the caller to retrieve the cdevEventHandler
// * associated with a specific file descriptor.
// *****************************************************************************
int cdevReactor::getHandler ( int fd, cdevEventHandler * & handler )
{
REACTOR_RESULT result = SUCCESS;
handler = NULL;
if(fd<=0 || fd>maxEntries) result = INVALID_HANDLE;
else if((handler = handlers[fd])==NULL) result = INVALID_HANDLE;
return (int) result;
}
// *****************************************************************************
// * cdevReactor::registerTimer :
// * This method will install a timer cdevEventHandler in the timers array.
// * The handleTimeout method of this class will be called each time the
// * timer expires. The timer's handleTimeout method will be called
// * immediately, and then the timer will be set to expire at the next
// * time period.
// *****************************************************************************
int cdevReactor::registerTimer ( cdevEventHandler * timer )
{
REACTOR_RESULT result = SUCCESS;
if(timer==NULL)
{
result = INVALID_HANDLER;
}
else if(timer->getReactor()!=NULL && timer->getReactor()!=this)
{
result = UNKNOWN_HANDLER;
}
else if((double)timer->getTimeoutRate()<=0.0)
{
result = INVALID_TIMEOUT;
}
else {
timer->setReactor(this);
timer->resetTimer();
timer->setNext(timers);
timers = timer;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::cancelTimer :
// * This method will remove the timer from the array of timers that are
// * being serviced by the reactor, however, it will NOT delete the
// * cdevEventHandler. Additionally, if the handler is also being used
// * for file-descriptor based operations - it will be not be removed from
// * that array.
// *
// * The user is responsible for deleteing the cdevEventHandler if it will
// * no longer be needed.
// *****************************************************************************
int cdevReactor::cancelTimer ( cdevEventHandler * timer )
{
REACTOR_RESULT result = SUCCESS;
if(timer==NULL) result = INVALID_HANDLER;
else
{
cdevEventHandler * currTimer = timers;
cdevEventHandler * prevTimer = NULL;
while(currTimer!=NULL && currTimer!=timer)
{
prevTimer = currTimer;
currTimer = prevTimer->getNext();
}
if(currTimer)
{
if(prevTimer) prevTimer->setNext(currTimer->getNext());
else timers = currTimer->getNext();
currTimer->setNext(NULL);
}
else result = UNKNOWN_HANDLER;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::handleFileEvent :
// * This method will process the events that have occurred on a single
// * file descriptor. The caller must provide two arguments...
// *
// * fd_set * fds : The fd_set to be checked
// * REACTOR_EVENT event : The type of event being processed...
// * INPUT, OUTPUT, EXCEPTION, or SIGNAL.
// *
// * This method will return the number of events that have been processed
// * to completion. Note that if a cdevEventHandler returns a value greater
// * than 0, it will be called again after all other ready file descriptors
// * have been called - therefore, its occurance will not be included in the
// * number of events returned by this method.
// *****************************************************************************
int cdevReactor::handleFileEvent ( cdevHandleSet * fds, REACTOR_EVENT event)
{
int result = 0;
int eventCnt = 0;
int i;
for(i=0; i<=size; i++)
{
if(fds->is_set(i))
{
if(handlers[i])
{
if(event==INPUT) result = handlers[i]->handleInput();
else if(event==OUTPUT) result = handlers[i]->handleOutput();
else if(event==EXCEPTION) result = handlers[i]->handleExcept();
else if(event==SIGNAL) result = handlers[i]->handleSignal();
if(result<=0)
{
if(result<0) removeHandler(handlers[i]);
eventCnt++;
fds->clr_bit(i);
}
}
else eventCnt++;
}
}
return eventCnt;
}
// *****************************************************************************
// * cdevReactor::handleEvents :
// * This method is called to allow the cdevReactor to wait for events to
// * occur on the cdevEventHandler objects. This method will process events
// * until the specified time period has expired - if a negative time period
// * (or no time period) has been specified, then it will process messages
// * until the next event occurs.
// *
// * The flags parameter was added to allow the caller to specify either
// * UNTIL_TIMEOUT or UNTIL_EVENT. If the caller specifies UNTIL_TIMEOUT,
// * the cdevReactor will continue to handle events until the time period
// * has expired. If the caller specifies UNTIL_EVENT, the cdevReactor will
// * return after the first SOCKET-BASED EVENT occurs or after the time
// * expires, whichever comes first.
// *
// * Note: If the cdevEventHandler may return a -1, 0, or 1. These return
// * codes will have the following effect.
// *
// * -1 : The cdevEventHandler will be removed from the cdevReactor
// * and deleted.
// * 0 : The bit associated with the cdevEventHandler will be
// * cleared and processing will continue.
// * 1 : The bit associated with the cdevEventHandler will not be
// * cleared and it will be called to process more data after
// * after all of the subsequent cdevEventHandlers have been
// * called - this allows the cdevEventHandler in a lengthy
// * process to yeild time back for processing other events.
// *****************************************************************************
int cdevReactor::handleEvents ( cdevTime period, int flags )
{
int result = 0;
int finished = 0;
cdevTime startTime, currTime;
struct timeval timeout;
startTime.setTime();
do
{
int i;
calculateMask ();
calculateTimeout(period, timeout);
result=cdevSelect(size, read_set, write_set, except_set, &timeout);
if(result<0)
{
finished = 1;
checkHandlers();
}
else {
if(result>0)
{
int cnt = 0;
while(cnt<result)
{
cnt+=handleFileEvent(&read_set, INPUT);
cnt+=handleFileEvent(&write_set, OUTPUT);
cnt+=handleFileEvent(&except_set, EXCEPTION);
}
if(flags==UNTIL_EVENT && cnt>0) finished = 1;
}
if(timers!=NULL)
{
cdevEventHandler * timer=timers;
currTime.setTime();
while(timer!=NULL)
{
cdevTime nextTimeout = timer->getNextTimeout();
if((timer->getMask()&cdevEventHandler::DONT_CALL)==0 &&
(double)nextTimeout>0.0 && nextTimeout<=currTime)
{
if(timer->handleTimeout()<0)
{
cdevEventHandler *temp = timer->getNext();
removeHandler(timer);
timer = temp;
}
else
{
timer->resetTimer();
timer = timer->getNext();
}
currTime.setTime();
}
else timer = timer->getNext();
}
}
}
currTime.setTime();
period = period-(currTime-startTime);
} while(!finished && period>cdevTime(0,0));
return result;
}
+692
View File
@@ -0,0 +1,692 @@
#include "cdevServer.h"
#include "ClientAcceptor.h"
#include "ClientHandler.h"
sig_atomic_t cdevServer::Finished = 0;
SignalManager cdevServer::SigManager;
cdevGenericServerTagDef cdevServer::tags;
// *****************************************************************************
// * This function is an interrupt handler that will be executed whenever the
// * program receives a SIGINT. When called it will set the finished flag to 1
// * and trigger the termination of the program.
// *****************************************************************************
static void SIGINT_handler (int signo)
{
cdevServer::Finished = 1;
signal(signo, SIGINT_handler);
}
// *****************************************************************************
// * cdevServer::cdevServer :
// * This is the constructor for the class. It will post the listening
// * socket, establish registration with the name server and record all
// * other pertinent information.
// *****************************************************************************
cdevServer::cdevServer (char * DomainName, char * ServerName, unsigned short Port, double Rate)
: cdevSessionManager(),
serverName (NULL),
acceptor (NULL),
timer (NULL),
status (UNINITIALIZED),
serverInfo (NULL)
{
// *********************************************************************
// * Register the import method for the cdevMessage class with the
// * cdevPacket class.
// *********************************************************************
cdevPacket::registerImportMethod(cdevMessage::CDEV_PACKET_VERSION,
cdevMessage::import);
startServer(DomainName, ServerName, Port, Rate, 0);
}
// *****************************************************************************
// * cdevServer::cdevServer :
// * This is the do nothing constructor for the class.
// *****************************************************************************
cdevServer::cdevServer ( void )
: cdevSessionManager (),
serverName (NULL),
acceptor (NULL),
timer (NULL),
status (UNINITIALIZED),
serverInfo (NULL)
{
// *********************************************************************
// * Register the import method for the cdevMessage class with the
// * cdevPacket class.
// *********************************************************************
cdevPacket::registerImportMethod(cdevMessage::CDEV_PACKET_VERSION,
cdevMessage::import);
}
// *****************************************************************************
// * cdevServer::~cdevServer :
// * This is the destructor for the object. It will close all listening
// * sockets and will delete all allocated items.
// *****************************************************************************
cdevServer::~cdevServer ( void )
{
outputError ( CDEV_SEVERITY_INFO, "CDEV Server",
"Server %s is Terminating...",
serverName);
Reactor.extractHandler(this);
if(timer!=NULL) delete timer;
if(serverName!=NULL) delete serverName;
if(acceptor!=NULL) delete acceptor;
}
// *****************************************************************************
// * cdevServer::startServer :
// * This method will initialize a cdevServer within a given name, will
// * register it within the CDEV Name Server and will commence listening
// * for connections on the specified port.
// *****************************************************************************
int cdevServer::startServer (char * DomainName, char * ServerName, unsigned short Port, double Rate, int searchForPort)
{
if(acceptor!=NULL)
{
delete acceptor;
acceptor=NULL;
}
if(timer)
{
delete timer;
timer=NULL;
}
if(serverName)
{
delete serverName;
serverName = NULL;
}
if(serverInfo)
{
delete serverInfo;
serverInfo = NULL;
}
Reactor.extractHandler(this);
setTimeoutRate(Rate);
serverName = strdup(ServerName);
status = UNINITIALIZED;
acceptor = new ClientAcceptor(*this);
// *********************************************************************
// * Attempt to open the acceptor to receive new connections.
// *********************************************************************
if(searchForPort) Port = 0;
cdevInetAddr addr(Port);
int initialized=!(acceptor->open(addr));
// *********************************************************************
// * Call getLocalAddress to retrieve the actual port number that was
// * opened. This value will differ from the specified port if...
// * 1) the user specified 0 for the port number -or-
// * 2) the user set the searchForPort flag to non-zero.
// *********************************************************************
if(acceptor->getLocalAddress(addr)==0) Port = addr.getPortNum();
else Port = (unsigned short)-1;
// *********************************************************************
// * ServerInfo must be created after the port has been searched for
// * and found. Otherwise, the server will report the original port
// * number rather than the actual port number.
// *********************************************************************
serverInfo = new ServerInfo(DomainName, ServerName, Port);
if(initialized)
{
// *************************************************************
// * Register the acceptor with the Reactor.
// *************************************************************
if(Reactor.registerHandler(acceptor, READ_MASK)!=-1)
{
// *****************************************************
// * Register this event handler with the Reactor.
// *****************************************************
if(Reactor.registerHandler(this, READ_MASK)!=-1)
{
// *********************************************
// * Schedule the periodic timer if it is
// * greater than 0.
// *********************************************
if(Rate <= 0.0 ||
Reactor.registerTimer(this)!=-1)
{
// *************************************
// * Install a name server timer to
// * continuously register this server
// * with the Name Server.
// *************************************
timer = new cdevNameServerManager(Reactor, DomainName, ServerName, Port);
outputError (CDEV_SEVERITY_INFO, "CDEV Server",
"Server %s is operational and servicing requests...",
serverName);
}
else
{
outputError ( CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to register server timer with cdevReactor",
serverName);
status = CANT_REGISTER_TIMER;
}
}
else
{
outputError ( CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to register server handler with cdevReactor",
serverName);
status = CANT_REGISTER_SERVER;
}
}
else
{
outputError (CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to register listening service with cdevReactor",
serverName);
status = CANT_REGISTER_LISTENER;
}
}
else
{
outputError ( CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to open listening socket",
serverName);
status = CANT_OPEN_SOCKET;
}
switch (status)
{
case CANT_REGISTER_TIMER:
Reactor.extractHandler(this);
case CANT_REGISTER_SERVER:
Reactor.extractHandler(acceptor);
case CANT_REGISTER_LISTENER:
case CANT_OPEN_SOCKET:
delete acceptor;
acceptor = NULL;
break;
case SUCCESS:
default:
status = SUCCESS;
break;
}
return status;
}
// ***************************************************************************
// * cdevServer::runServer :
// * This method is called to simultaneously execute all servers that
// * reside in the system.
// ***************************************************************************
void cdevServer::runServer ( void )
{
SigManager.installDefaults();
SigManager.installHandler (SIGINT, SIGINT_handler);
while (!Finished) Reactor.handleEvents ();
}
// *****************************************************************************
// * cdevServer::registerClient :
// * This is the cdevMessage specific method that is used to send a
// * "register" message to the server.
// *****************************************************************************
void cdevServer::registerClient ( short localID )
{
cdevMessage message(localID,0,0,0,0,0,0,0,NULL,"register");
cdevPacketBinary * packet = new cdevPacketBinary;
char * binary;
size_t binaryLen;
message.streamOut (&binary, &binaryLen);
packet->attachData(binary, binaryLen);
inbound.enqueue (packet);
}
// *****************************************************************************
// * cdevServer::unregisterClient :
// * This is the cdevMessage specific method that is used to send an
// * "unregister" message to the server.
// *****************************************************************************
void cdevServer::unregisterClient ( short localID )
{
cdevMessage message(localID,0,0,0,0,0,0,0,NULL,"unregister");
cdevPacketBinary * packet = new cdevPacketBinary;
char * binary;
size_t binaryLen;
message.streamOut (&binary, &binaryLen);
packet->attachData(binary, binaryLen);
inbound.enqueue (packet);
trigger.insertEvent();
}
// *****************************************************************************
// * cdevServer::newClientSession :
// * This method allows the caller to create a new ClientSession object. The
// * ClientSession object functions primarily as a pointer to the queue that
// * holds packets destined for a specific client, however, the developer
// * can create a subclass of the ClientSession that may be used to associate
// * additional, client specific information to the structure.
// *
// * The CLIPClientSession class allows the developer to associate a context
// * with the clientID.
// *****************************************************************************
ClientSession * cdevServer::newClientSession ( int SocketID, int ClientID, int LocalID )
{
return new CLIPClientSession (SocketID, ClientID, LocalID);
}
// *****************************************************************************
// * cdevServer::newSocketSession :
// * This method allows the caller to create a new SocketSession object. The
// * SocketSession object functions primarily as a pointer to the queue that
// * holds packets destined for a specific socket, however, the developer
// * can create a subclass of the SocketSession that may be used to associate
// * additional, socket specific information to the structure.
// *
// * The CLIPSocketSession class allows the developer to associate a
// * context map and a tag table with the socket number.
// *****************************************************************************
SocketSession * cdevServer::newSocketSession ( int SocketID )
{
if(serverInfo) serverInfo->clientCnt++;
return new CLIPSocketSession (SocketID);
}
// *****************************************************************************
// * cdevServer::deleteSocketSession :
// * This method is called to delete an existing socket session.
// *****************************************************************************
void cdevServer::deleteSocketSession ( SocketSession *socket )
{
if(socket)
{
if(serverInfo)
{
if(serverInfo->clientCnt>0) serverInfo->clientCnt--;
else serverInfo->clientCnt=0;
}
sockets.remove(socket->getSocketID());
delete socket;
}
}
// *****************************************************************************
// * cdevServer::dequeue :
// * This method provides a mechanism for the cdevServer object to only
// * dequeue packets that are of the type cdevMessage.
// *****************************************************************************
int cdevServer::dequeue ( cdevMessage * &message )
{
cdevPacket * packet = NULL;
while(packet==NULL && cdevSessionManager::dequeue(packet)==0)
{
if(packet->getVersion()!=cdevMessage::CDEV_PACKET_VERSION)
{
delete packet;
packet = NULL;
}
else if(((cdevMessage *)packet)->getOperationCode()==CDEV_SERVER_OP)
{
processLocal((cdevMessage * &)packet);
delete packet;
packet = NULL;
}
}
message = (cdevMessage *)packet;
return message==NULL?-1:0;
}
// *****************************************************************************
// * cdevServer::processLocal :
// * This method is called to process requests that are being transmitted
// * directly to the cdev Generic Server Engine to set or retrieve statistics
// * about the operation of the server or its clients.
// *****************************************************************************
void cdevServer::processLocal ( cdevMessage * & message )
{
CLIPClientSession * client = NULL;
CLIPSocketSession * socket = NULL;
if((client = (CLIPClientSession *)findLocalClient(message->getClientID()))!=NULL)
{
socket = (CLIPSocketSession *)findSocket(client->getSocketID());
}
if(!strcmp(message->getMessage(), "set ClientInfo"))
{
cdevData * data = message->getData();
if(data && socket) socket->updateClientInfo(*data);
}
else if(!strcmp(message->getMessage(), "get ServerInfo"))
{
if(serverInfo)
{
message->setOperationCode(CDEV_NORMAL_OP);
message->setData(&serverInfo->getServerData(), 1);
}
else {
message->setOperationCode(CDEV_NORMAL_OP);
message->setCompletionCode(-1);
}
enqueue(message);
}
else if(!strcmp(message->getMessage(), "get ClientInfo"))
{
IntHashIterator iter(&sockets);
ClientHandler * handler = NULL;
int socketCnt = 0;
int index = 0;
cdevData result;
iter.first();
while(iter.data()!=NULL)
{
iter++;
socketCnt++;
}
if(socketCnt)
{
char ** username = new char *[socketCnt];
char ** group = new char *[socketCnt];
unsigned * uid = new unsigned [socketCnt];
unsigned * gid = new unsigned [socketCnt];
unsigned * pid = new unsigned [socketCnt];
char ** program = new char *[socketCnt];
char ** commandline = new char *[socketCnt];
unsigned * starttime = new unsigned [socketCnt];
unsigned * connecttime = new unsigned [socketCnt];
char ** host = new char *[socketCnt];
char ** os = new char *[socketCnt];
char ** osrelease = new char *[socketCnt];
char ** osversion = new char *[socketCnt];
char ** machine = new char *[socketCnt];
char ** shell = new char *[socketCnt];
unsigned * socketNum = new unsigned[socketCnt];
unsigned * sendPktCnt = new unsigned[socketCnt];
unsigned * recvPktCnt = new unsigned[socketCnt];
iter.first();
while(index<socketCnt && (socket = (CLIPSocketSession *)iter.data())!=NULL)
{
username[index] = socket->getUsername();
group[index] = socket->getGroup();
uid[index] = socket->getUid();
gid[index] = socket->getGid();
pid[index] = socket->getPid();
program[index] = socket->getProgram();
commandline[index] = socket->getCommandLine();
starttime[index] = (unsigned)socket->getStartTime();
connecttime[index] = (unsigned)socket->getConnectTime();
host[index] = socket->getHost();
os[index] = socket->getOs();
osrelease[index] = socket->getOsRelease();
osversion[index] = socket->getOsVersion();
machine[index] = socket->getMachine();
shell[index] = socket->getShell();
socketNum[index] = socket->getSocketID();
if(Reactor.getHandler(socketNum[index], (cdevEventHandler *&)handler)==0)
{
sendPktCnt[index] = handler->getPacketsSent();
recvPktCnt[index] = handler->getPacketsRecv();
}
else {
sendPktCnt[index] = 0;
recvPktCnt[index] = 0;
}
index++;
iter++;
}
result.insert("username", username, socketCnt); delete username;
result.insert("group", group, socketCnt); delete group;
result.insert("uid", uid, socketCnt); delete uid;
result.insert("gid", gid, socketCnt); delete gid;
result.insert("pid", pid, socketCnt); delete pid;
result.insert("program", program, socketCnt); delete program;
result.insert("commandline", commandline, socketCnt); delete commandline;
result.insert("starttime", starttime, socketCnt); delete starttime;
result.insert("connecttime", connecttime, socketCnt); delete connecttime;
result.insert("host", host, socketCnt); delete host;
result.insert("os", os, socketCnt); delete os;
result.insert("osrelease", osrelease, socketCnt); delete osrelease;
result.insert("osversion", osversion, socketCnt); delete osversion;
result.insert("machine", machine, socketCnt); delete machine;
result.insert("shell", shell, socketCnt); delete shell;
result.insert("socket", socketNum, socketCnt); delete socketNum;
result.insert("sendPktCnt", sendPktCnt, socketCnt); delete sendPktCnt;
result.insert("recvPktCnt", recvPktCnt, socketCnt); delete recvPktCnt;
}
message->setOperationCode(CDEV_NORMAL_OP);
message->setData(&result, 1);
enqueue(message);
}
}
// *****************************************************************************
// * cdevServer::decodePacket :
// * This method is used to perform preprocessing on a newly dequeued binary
// * packet before it is provided to the caller. This method allows the
// * developer to perform special preparations on the packet before providing
// * it to the caller.
// *****************************************************************************
cdevPacket * cdevServer::decodePacket( cdevPacketBinary * input )
{
cdevPacket * packet = NULL;
if(input!=NULL)
{
short version;
input->getVersion(version);
switch (version)
{
// *****************************************************
// * If it is a cdevMessage object, I want to call the
// * cdevMessage specific decodePacket method.
// *****************************************************
case cdevMessage::CDEV_PACKET_VERSION:
packet = decodePacket ((cdevMessage *)cdevPacket::import(*input));
break;
// *****************************************************
// * Use the cdevSessionManager::decodePacket method
// * to handle any other type of packet.
// *****************************************************
default:
packet = cdevSessionManager::decodePacket(input);
break;
}
if(serverInfo) serverInfo->recvPktCnt++;
}
return packet;
}
// *****************************************************************************
// * cdevServer::decodePacket :
// * This decodePacket method is designed specifically to preprocess the
// * data associated with a cdevMessage object.
// *****************************************************************************
cdevPacket * cdevServer::decodePacket (cdevMessage * message )
{
CLIPClientSession * client = NULL;
CLIPSocketSession * socket = NULL;
if(message!=NULL &&
(client = (CLIPClientSession *)findLocalClient(message->getClientID()))!=NULL &&
(socket = (CLIPSocketSession *)findSocket(client->getSocketID()))!=NULL)
{
// *************************************************************
// * If a tagMap has been provided... use it to update
// * the tagMap stored in the SocketSession object.
// *************************************************************
if(message->getTagMap()!=NULL)
{
socket->TagMap().updateTagMap(*message->getTagMap());
message->setTagMap(NULL);
}
// *************************************************************
// * Pass the data and context objects through the tag map to
// * convert their tags from the remote integers to the local
// * integers.
// *************************************************************
if(message->getData()!=NULL)
socket->TagMap().remoteToLocal(*message->getData());
if(message->getContext()!=NULL)
socket->TagMap().remoteToLocal(*message->getContext());
// *************************************************************
// * If a context has been provided by the client side
// * of the connection - perform the following steps...
// *
// * 1) Add the context to the cdevContextMap for this
// * socketID if it does not already exist, and
// * obtain the index that identifies the new
// * context.
// *
// * 2) Delete the context from within the message.
// *
// * 3) Set the context within the message to the
// * current context that is specified in the
// * ClientSession object.
// *
// * 4) Set the saveContext flag in the message to
// * prevent its inadvertant destruction when the
// * message is deleted.
// *************************************************************
if(message->getContext()!=NULL)
{
cdevData * lastContext = client->getContext();
if(lastContext==NULL || *lastContext!=*message->getContext())
{
int contextID = socket->ContextMap().insert(*message->getContext());
client->setContext(socket->ContextMap().find(contextID));
}
}
message->setContext(client->getContext(), 1);
// *************************************************************
// * Toggle the local and foreign data indices.
// *************************************************************
unsigned int index = message->getForeignDataIndex();
message->setForeignDataIndex(message->getLocalDataIndex());
message->setLocalDataIndex (index);
}
return message;
}
// *****************************************************************************
// * cdevSessionManager::encodePacket :
// * This method is used to perform postprocessing on a packet that has been
// * enqueued to be sent to a client. This method allows the developer to
// * perform special preparations on the packet before providing it to the
// * client.
// *****************************************************************************
cdevPacketBinary * cdevServer::encodePacket ( cdevPacket * input )
{
cdevPacketBinary * packet = NULL;
if(input!=NULL)
{
switch(input->getVersion())
{
case cdevMessage::CDEV_PACKET_VERSION:
packet = encodePacket ((cdevMessage *)input);
break;
default:
packet = cdevSessionManager::encodePacket(input);
break;
}
if(serverInfo) serverInfo->sendPktCnt++;
}
return packet;
}
// *****************************************************************************
// * cdevServer::encodePacket :
// * This encodePacket method is designed specifically to postprocess the
// * data associated with a cdevMessage object.
// *****************************************************************************
cdevPacketBinary * cdevServer::encodePacket (cdevMessage * message )
{
cdevPacketBinary * result = NULL;
CLIPClientSession * client = NULL;
CLIPSocketSession * socket = NULL;
if(message!=NULL &&
message->getClientID()>0 &&
message->getTransIndex()>0 &&
(client = (CLIPClientSession *)findLocalClient(message->getClientID()))!=NULL &&
(socket = (CLIPSocketSession *)findSocket(client->getSocketID()))!=NULL)
{
char * binary = NULL;
size_t binaryLen = 0;
static cdevMessage outBound;
// *************************************************************
// * Remap the data to its foreign design.
// *************************************************************
if(message->getData()!=NULL)
socket->TagMap().localToRemote(*message->getData());
// *************************************************************
// * Transfer the critical data items into the class. Note that
// * we are not returning the deviceList, message, context,
// * cancelTransIndex, or operationCode with the return packet.
// *
// * Also note that the cdevData object is marked as permanent
// * and is using a pointer to the same cdevData object that is
// * in the message object.
// *************************************************************
outBound.clear();
outBound.setClientID (client->getClientID()&0xFFFF);
outBound.setTransIndex (message->getTransIndex());
outBound.setLocalDataIndex (message->getForeignDataIndex());
outBound.setForeignDataIndex (message->getLocalDataIndex());
outBound.setOperationCode (message->getOperationCode());
outBound.setCompletionCode (message->getCompletionCode());
outBound.setData (message->getData(), 1);
// *************************************************************
// * Create a binary stream from the cdevMessage object and then
// * place it into the outbound queue system.
// *************************************************************
outBound.streamOut(&binary, &binaryLen);
outBound.clear ();
result = new cdevPacketBinary;
result->attachData(binary, binaryLen);
// *************************************************************
// * Remap the data to its local design.
// *************************************************************
if(message->getData()!=NULL)
socket->TagMap().remoteToLocal(*message->getData());
}
return result;
}
+403
View File
@@ -0,0 +1,403 @@
#include "cdevServerTools.h"
// ****************************************************************************
// cdevSimpleTimer::cdevSimpleTimer :
// Constructor.
// ****************************************************************************
cdevSimpleTimer::cdevSimpleTimer ( cdevReactor & Reactor, double Rate)
{
setTimeoutRate(Rate);
if(Reactor.registerTimer (this) == -1)
{
outputError ( CDEV_SEVERITY_SEVERE, "cdevSimpleTimer",
"Unable to register timer with cdevReactor");
}
}
// ****************************************************************************
// cdevSimpleTimer::~cdevSimpleTimer :
// Destructor.
// ****************************************************************************
cdevSimpleTimer::~cdevSimpleTimer ( void )
{
if(reactor) reactor->extractHandler(this);
handleClose();
}
// ****************************************************************************
// cdevSimpleTimer::handle_timeout :
// Called when the timer expires.
// ****************************************************************************
int cdevSimpleTimer::handleTimeout(void)
{
return execute();
}
// *****************************************************************************
// * cdevNameServerManager::cdevNameServerManager :
// * This method will read the CDEV_NAME_SERVER environment variable to
// * obtain a list of one or more cdev name servers that should be notified
// * that this server is operational. The class will create a
// * cdevNameServerHandler event handler to manage the connection to each of
// * the specified name servers. If a connection is lost to one of the
// * name servers, the cdevNameServerManager will attempt periodically to
// * reconnect to the specific name server.
// *****************************************************************************
cdevNameServerManager::cdevNameServerManager ( cdevReactor & Reactor,
char * DomainName,
char * ServerName,
unsigned short ServerPort )
: domainName(strdup(DomainName)),
serverName(strdup(ServerName)),
serverPort(ServerPort),
nameServerList(NULL),
nameServerHandlers(NULL),
nameServerCnt(0)
{
// *********************************************************************
// * Prior to establishing any connections, the class must first install
// * all of the necessary data into the serverInfo and updateInfo
// * objects.
// *********************************************************************
char * userName = getenv("USER");
char hostname[255];
struct hostent * hostPtr;
struct timeval tv;
gettimeofday (&tv);
gethostname(hostname, 255);
hostPtr = gethostbyname(hostname);
serverInfo.insert ("name", serverName);
serverInfo.insert ("domain", domainName);
serverInfo.insert ("host", (char *)hostPtr->h_name);
serverInfo.insert ("owner", userName?userName:(char *)"UNKNOWN");
serverInfo.insert ("time", (long)tv.tv_sec);
serverInfo.insert ("port", (long)serverPort);
serverInfo.insert ("pid", getpid ());
updateInfo.insert ("name", serverName);
updateInfo.insert ("domain", domainName);
// *********************************************************************
// * First obtain a list of name servers from the CDEV_NAME_SERVER
// * environment variable. If this list is empty, then report an
// * error once and then never call the handler again.
// *********************************************************************
char * nsList = getenv("CDEV_NAME_SERVER");
int idx;
int length;
if(nsList!=NULL)
{
char * nsPtr = nsList;
char * endPtr = nsList;
// *************************************************************
// * Determine the number of name servers that have been
// * defined in the CDEV_NAME_SERVER environment variable.
// *************************************************************
while(*nsPtr==':' && *nsPtr!=0) nsPtr++;
if(*nsPtr!=0)
{
nameServerCnt = 1;
while(nsPtr!=NULL && *nsPtr!=0)
{
if((nsPtr = strchr(nsPtr, ':'))!=NULL)
{
while(*(++nsPtr)==':' && *nsPtr!=0);
if(*nsPtr!=0) nameServerCnt++;
}
}
}
// *************************************************************
// * Copy each of the defined cdev name server host names into
// * the nameServerList.
// *************************************************************
if(nameServerCnt>0)
{
nameServerList = new char *[nameServerCnt];
nameServerHandlers = new cdevNameServerHandler *[nameServerCnt];
for(nsPtr = nsList, idx=0; idx<nameServerCnt && *nsPtr!=0; idx++)
{
while(*nsPtr==':' && *nsPtr!=0) nsPtr++;
for(endPtr=nsPtr; *endPtr && *endPtr!=':'; endPtr++);
length = endPtr-nsPtr;
nameServerList[idx] = new char[length+1];
strncpy(nameServerList[idx], nsPtr, length);
nameServerList[idx][length] = 0;
nsPtr = endPtr;
}
}
}
// *********************************************************************
// * If no cdev name servers have been defined in the cdev name server
// * list, print a warning message.
// ********************************************************************
if(nameServerCnt<=0)
{
outputError(CDEV_SEVERITY_WARN, "CDEV Name Server Manager",
"\n%s\n%s\n%s",
" => No name servers have been specified in the CDEV_NAME_SERVER",
" => environment variable.",
" => This server WILL NOT be registered with any name servers...");
}
// *********************************************************************
// * Otherwise, set all of the cdevNameServerHandler pointers to NULL
// * so that they will be connected when the execute timeout method
// * is called.
// *********************************************************************
else {
for(idx=0; idx<nameServerCnt; idx++)
{
nameServerHandlers[idx] = NULL;
}
}
// *********************************************************************
// * Register this class with the cdevReactor so that it will be called
// * every thirty seconds. If any of the cdevNameServerHandlers have
// * become disconnected, it will attempt to reestablish the connection
// * at that time.
// *********************************************************************
setTimeoutRate(15.0);
Reactor.registerTimer(this);
handleTimeout();
}
// *****************************************************************************
// * cdevNameServerManager::~cdevNameServerManager :
// * This is the destructor for the cdevNameServerManager class. When called
// * it will remove and delete any cdevNameServerHandlers that have been
// * registered with the cdevReactor.
// *****************************************************************************
cdevNameServerManager::~cdevNameServerManager ( void )
{
int idx;
for(idx = 0; idx<nameServerCnt; idx++)
{
if(nameServerHandlers[idx]!=0) delete nameServerHandlers[idx];
if(nameServerList[idx]!=NULL) delete nameServerList[idx];
}
if(nameServerList!=NULL) delete nameServerList;
if(nameServerHandlers!=NULL) delete nameServerHandlers;
if(domainName!=NULL) delete domainName;
if(serverName!=NULL) delete serverName;
}
// *****************************************************************************
// * cdevNameServerManager::handleTimeout :
// * This method will be called every thirty seconds to make sure that all
// * connections to the cdev name servers are established. If a
// * cdevNameServerHandler has become disconnected, this method will attempt
// * to reconnect to the specified handler.
// *****************************************************************************
int cdevNameServerManager::handleTimeout ( void )
{
int idx;
for(idx=0; idx<nameServerCnt; idx++)
{
if(nameServerHandlers[idx]==NULL &&
nameServerList[idx]!=NULL)
{
int error = 0;
rsvcClient * client = new rsvcClient;
rsvcUdpClient * udpClient = new rsvcUdpClient;
if(client->connect(nameServerList[idx], RSVC_SERVER_PORT, 2.0)!=RSVC_SUCCESS)
{
outputError ( CDEV_SEVERITY_ERROR, "CDEV Name Server Manager",
"Failed to connect to name server on host %s",
nameServerList[idx]);
error = -1;
}
else if(udpClient->connect(nameServerList[idx], RSVC_SERVER_PORT+1024)!=RSVC_SUCCESS)
{
outputError ( CDEV_SEVERITY_ERROR, "CDEV Name Server Manager",
"Failed to open UDP port to name server on host %s",
nameServerList[idx]);
error = -1;
}
else if(client->insertValue ("cdevServers", serverInfo, rsvcCallback, nameServerList[idx], 1)!=RSVC_SUCCESS)
{
outputError ( CDEV_SEVERITY_ERROR, "CDEV Name Server Manager",
"Error transmitting to name server on host %s",
nameServerList[idx]);
error = -1;
}
if(!error) nameServerHandlers[idx] = new cdevNameServerHandler(*this, *reactor, idx, client, udpClient);
else {
client->disconnect();
udpClient->disconnect();
delete client;
delete udpClient;
}
}
}
return 0;
}
// *****************************************************************************
// * cdevNameServerManager::unregisterHandler:
// * This method is called whenever a cdevNameServerHandler needs to
// * unregister itself from the cdevNameServerManager. The handlers index
// * will be set to 0 and the connection will be reestablished the next time
// * the handleTimeout method is called.
// *****************************************************************************
void cdevNameServerManager::unregisterHandler ( size_t index )
{
if(index < nameServerCnt) nameServerHandlers[index] = NULL;
}
// *****************************************************************************
// * cdevNameServerManager::rsvcCallback :
// * This is the method that is called when the register server method
// * is executed.
// *****************************************************************************
void cdevNameServerManager::rsvcCallback (int status, void* arg, rsvcData* /* data */)
{
char * nameServer = (char *)arg;
if (status != RSVC_SUCCESS)
{
#ifndef _WIN32
fprintf(stderr, "CDEV Name Server Manager Error: %s %s\n",
"Failed to register with name server on host",
nameServer?nameServer:"UNKNOWN");
#endif
}
}
// *****************************************************************************
// * cdevNameServerHandler::cdevNameServerHandler :
// * This is the constructor for the cdevNameServerHandler class. It is
// * called by the cdevNameServerManager when a new cdevNameServerHandler
// * must be created to communicate with a name server. The connected
// * rsvcClient and rsvcUdpClient objects are provided to the class.
// ******************************************************************************
cdevNameServerHandler::cdevNameServerHandler ( cdevNameServerManager & Manager,
cdevReactor & Reactor,
int index,
rsvcClient * tcpClient,
rsvcUdpClient * udpClient )
: nameServerTCP(tcpClient), nameServerUDP(udpClient),
nameServerIndex(index), nameServerManager(Manager)
{
setTimeoutRate(5.0);
setMask(WRITE_MASK);
Reactor.registerHandler(this, WRITE_MASK);
Reactor.registerTimer (this);
}
// *****************************************************************************
// * cdevNameServerHandler::~cdevNameServerHandler :
// * This is the destructor for the class. this method is responsible for
// * disconnecting and closing the tcp and udp client connections and
// * sending notification to the cdevNameServerManager that it is
// * terminating.
// *****************************************************************************
cdevNameServerHandler::~cdevNameServerHandler ( void )
{
nameServerTCP->disconnect();
nameServerUDP->disconnect();
delete nameServerTCP;
delete nameServerUDP;
if(reactor) reactor->extractHandler(this);
nameServerManager.unregisterHandler(nameServerIndex);
}
// *****************************************************************************
// * cdevNameServerHandler::handleInput :
// * This method is called whenever data is ready to be read from the
// * nameServerTCP rsvcClient connection.
// *****************************************************************************
int cdevNameServerHandler::handleInput ( void )
{
return (nameServerTCP->pendIO()==RSVC_IOERROR)?-1:0;
}
// *****************************************************************************
// * cdevNameServerHandler::handleOutput :
// * This method is called whenever data is ready to be written to the
// * nameServerTCP rsvcClient connection.
// *****************************************************************************
int cdevNameServerHandler::handleOutput ( void )
{
setMask(READ_MASK);
return (nameServerTCP->pendIO()==RSVC_IOERROR)?-1:0;
}
// *****************************************************************************
// * cdevNameServerHandler::handleTimeout :
// * This method is called every five seconds to allow the object to emit
// * a UDP packet to the name server to notify it that the server is alive.
// *****************************************************************************
int cdevNameServerHandler::handleTimeout ( void )
{
if(nameServerUDP->update(*nameServerManager.getUpdateInfo())!=RSVC_SUCCESS)
{
outputError(CDEV_SEVERITY_ERROR, "CDEV Name Server Handler",
"Failed to update name server on host %s",
nameServerManager.getHostName(nameServerIndex));
}
return 0;
}
// *****************************************************************************
// * cdevNameServerHandler::getHandle :
// * This method allows the caller to obtain the file handle that is being
// * used by the nameServerTCP rsvcClient connection. This handle is used
// * by the cdevReactor to detect when an event has occured.
// *****************************************************************************
int cdevNameServerHandler::getHandle ( void ) const
{
return nameServerTCP->getFd();
}
#ifndef DONT_SUPPORT_CDEV_CALLS
// *********************************************************************
// * cdevSystemHandler::cdevSystemHandler :
// * This is the constructor for the cdevSystemHandler object.
// *********************************************************************
cdevSystemHandler::cdevSystemHandler (cdevReactor & Reactor,
double pollRate,
cdevSystem & System)
: cdevSimpleTimer(Reactor, pollRate), system(System)
{
execute();
}
#endif
#ifndef DONT_SUPPORT_CDEV_CALLS
// *********************************************************************
// * cdevSystemHandler::~cdevSystemHandler :
// * This is the destructor for the cdevSystemHandler object.
// *********************************************************************
cdevSystemHandler::~cdevSystemHandler (void)
{
}
#endif
#ifndef DONT_SUPPORT_CDEV_CALLS
// *********************************************************************
// * cdevSystemHandler::execute :
// * This is the method that is executed when the specified timer
// * expires.
// *********************************************************************
int cdevSystemHandler::execute (void)
{
system.poll();
return 0;
}
#endif
+635
View File
@@ -0,0 +1,635 @@
#include <cdevSessionManager.h>
cdevReactor cdevSessionManager::Reactor;
IntHash cdevSessionManager::localIdx;
// *****************************************************************************
// * ClientSession::ClientSession :
// * This method serves only to initialize the internals of the class.
// *****************************************************************************
ClientSession::ClientSession ( int SocketID, int ClientID, int LocalID )
: socketID(SocketID), clientID(ClientID), localID(LocalID)
{
}
// *****************************************************************************
// * ClientSession::~ClientSession :
// * This method deletes all unprocessed binary packets that are stored
// * within the queue.
// *****************************************************************************
ClientSession::~ClientSession ( void )
{
}
// *****************************************************************************
// * SocketSession::SocketSession :
// * This is the constructor for the SocketSession object, it serves only
// * to initialize internal variables.
// *****************************************************************************
SocketSession::SocketSession( int SocketID )
: FifoQueue(), socketID(SocketID)
{
}
// *****************************************************************************
// * SocketSession::~SocketSession :
// * This method deletes all unprocessed binary packets that are stored
// * within the queue.
// *****************************************************************************
SocketSession::~SocketSession ( void )
{
char * binary;
size_t binaryLen;
while(dequeue(&binary, &binaryLen)==0) delete binary;
}
// *****************************************************************************
// * cdevSessionManager::~cdevSessionManager :
// * This method deletes all entries from the client and socket queues
// * and then deletes all queue objects...
// *****************************************************************************
cdevSessionManager::~cdevSessionManager ( void )
{
int socketID;
int clientID;
IntHashIterator clientIter(&clients);
IntHashIterator socketIter(&sockets);
ClientSession * clientPtr;
SocketSession * socketPtr;
cdevPacketBinary * packet;
while((packet = (cdevPacketBinary *)inbound.dequeue())!=NULL)
{
delete packet;
}
clientIter.first();
while((clientPtr=(ClientSession *)clientIter.data())!=NULL)
{
clientID = clientPtr->getClientID();
clientIter++;
removeClient(clientID, 0);
}
socketIter.first();
while((socketPtr=(SocketSession *)socketIter.data())!=NULL)
{
socketID = socketIter.key();
socketIter++;
removeSocket(socketID);
}
}
// *****************************************************************************
// * cdevSessionManager::newClientSession :
// * This method allows the caller to create a new ClientSession object. The
// * ClientSession object functions primarily as a pointer to the queue that
// * holds packets destined for a specific client, however, the developer
// * can create a subclass of the ClientSession that may be used to associate
// * additional, client specific information to the structure.
// *****************************************************************************
ClientSession * cdevSessionManager::newClientSession ( int SocketID, int ClientID, int LocalID )
{
return new ClientSession (SocketID, ClientID, LocalID);
}
// *****************************************************************************
// * cdevSessionManager::newSocketSession :
// * This method allows the caller to create a new SocketSession object. The
// * SocketSession object functions primarily as a pointer to the queue that
// * holds packets destined for a specific socket, however, the developer
// * can create a subclass of the SocketSession that may be used to associate
// * additional, socket specific information to the structure.
// *****************************************************************************
SocketSession * cdevSessionManager::newSocketSession ( int SocketID )
{
return new SocketSession (SocketID);
}
// *****************************************************************************
// * cdevSessionManager::deleteSocketSession :
// * This method is called to delete a SocketSession object.
// *****************************************************************************
void cdevSessionManager::deleteSocketSession ( SocketSession *socket )
{
if(socket)
{
sockets.remove(socket->getSocketID());
delete socket;
}
}
// *****************************************************************************
// * cdevSessionManager::findLocalClient :
// * This method allows the caller to locate a ClientSession using the local
// * client identifier that is assigned by the cdevSessionManager class.
// *****************************************************************************
ClientSession * cdevSessionManager::findLocalClient( short localID )
{
return (ClientSession *)localIdx.find(localID);
}
// *****************************************************************************
// * cdevSessionManager::findClient :
// * This method allows the caller to locate a ClientSession using its
// * clientID.
// *****************************************************************************
ClientSession * cdevSessionManager::findClient( int clientID )
{
return (ClientSession *)clients.find(clientID);
}
// *****************************************************************************
// * cdevSessionManager::findSocket :
// * This method allows the caller to locate a SocketSession using its
// * socketID.
// *****************************************************************************
SocketSession * cdevSessionManager::findSocket( int socketID )
{
return (SocketSession *)sockets.find(socketID);
}
// *****************************************************************************
// * cdevSessionManager::addClient :
// * This method allows the caller to add a new clientID and construct a
// * ClientSession object for it.
// *
// * The socketID must have already been registered using the addSocket
// * method. If the clientID already exists or if an error occurs NULL will
// * be returned.
// *****************************************************************************
ClientSession * cdevSessionManager::addClient( int socketID, int clientID )
{
ClientSession * session = NULL;
if(findSocket(socketID)!=NULL && findClient(clientID)==NULL)
{
short localID = getNextLocalID();
if(localID>0 &&
(session = newClientSession(socketID, clientID, localID))!=NULL)
{
clients.insert (clientID, session);
localIdx.insert((int)localID, session);
}
}
return session;
}
// *****************************************************************************
// * cdevSessionManager::addSocket :
// * This method allows the caller to add a new socketID and construct a
// * SocketSession object to service it.
// *
// * This function will fail if the socketID has already been registered...
// * On failure this method will return NULL.
// *****************************************************************************
SocketSession * cdevSessionManager::addSocket ( int socketID )
{
SocketSession * session = NULL;
if(findSocket(socketID)==NULL &&
(session = newSocketSession(socketID))!=NULL)
{
sockets.insert(socketID, session);
}
return session;
}
// *****************************************************************************
// * cdevSessionManager::removeClient :
// * This method will remove the specified clientID from the clients list
// * and will delete the associated ClientSession object.
// *****************************************************************************
void cdevSessionManager::removeClient ( int clientID, int unregisterFlag)
{
ClientSession * session;
if((session = (ClientSession *)clients.find(clientID))!=NULL)
{
// *****************************************************
// * Submit an unregister command to notify the server
// *****************************************************
if(unregisterFlag) unregisterClient(session->getLocalID());
localIdx.remove((int)session->getLocalID());
clients.remove (clientID);
delete session;
}
}
// *****************************************************************************
// * cdevSessionManager::removeSocket :
// * This method will remove the specified socketID from the sockets list
// * and will delete the associated SocketSession object. It will then
// * ascend the clients list and will remove all ClientSessions that are
// * associated with the socketID.
// *****************************************************************************
void cdevSessionManager::removeSocket ( int socketID )
{
cdevEventHandler * handler = NULL;
SocketSession * socket;
ClientSession * client;
int clientID;
if(Reactor.getHandler(socketID, handler)==0 && handler!=NULL)
{
delete handler;
}
if((socket = (SocketSession *)sockets.find(socketID))!=NULL)
{
IntHashIterator clientIter(&clients);
clientIter.first();
while((client=(ClientSession *)clientIter.data())!=NULL)
{
if(client->getSocketID()==socketID)
{
clientID = client->getClientID();
clientIter++;
removeClient(clientID);
}
else clientIter++;
}
deleteSocketSession(socket);
}
}
// *****************************************************************************
// * cdevSessionManager::getNextLocalID :
// * This method allows the caller to retrieve a unique localID to be
// * assigned to a client. The nextLocalID value is automatically
// * incremented.
// *****************************************************************************
short cdevSessionManager::getNextLocalID ( void )
{
static short nextLocalID = 0;
short startingPoint = nextLocalID;
ClientSession *session = NULL;
if(nextLocalID>=32767) nextLocalID = 1;
else nextLocalID++;
startingPoint = nextLocalID;
do {
session=(ClientSession *)localIdx.find((int)nextLocalID);
if(session!=NULL)
{
if(nextLocalID>=32767) nextLocalID = 1;
else nextLocalID++;
}
} while(session!=NULL && nextLocalID!=startingPoint);
return session==NULL?nextLocalID:-1;
}
// *****************************************************************************
// * cdevSessionManager::enqueue :
// * This method is used to enqueue a binary packet into the inbound
// * fifoQueue. This method is called by the client handler objects.
// *
// * The binary data item becomes the property of the queue and should not
// * be accessed later by the caller.
// *****************************************************************************
int cdevSessionManager::enqueue( int socketID, char * binary, unsigned binaryLen )
{
int result = -1;
SocketSession * socket = NULL;
ClientSession * client = NULL;
cdevPacketBinary * packet = new cdevPacketBinary;
// *********************************************************************
// * Make sure its a valid packet.
// *********************************************************************
if(packet->streamIn(binary, binaryLen)==0)
{
// *************************************************************
// * Add the socketID if it does not already exist.
// *************************************************************
if((socket = findSocket(socketID))==NULL)
{
socket = addSocket(socketID);
}
// *************************************************************
// * Combine the (short)clientID and the (short)socketID to
// * create a unique identifier for this client.
// *
// * < HIGH WORD > < LOW WORD >
// * SSSSSSSS CCCCCCCCC
// *************************************************************
short packetClientID;
int clientID;
packet->getClientID(packetClientID);
clientID = ((socketID<<16)|packetClientID);
// *************************************************************
// * Add a clientID if it does not already exist.
// *************************************************************
if((client = findClient(clientID))==NULL &&
(client = addClient(socketID, clientID))!=NULL)
{
registerClient ( client->getLocalID() );
}
// *************************************************************
// * This would only fail if the clientID had already been used
// * by another socket.
// *************************************************************
if(client!=NULL && client->getSocketID()==socketID)
{
result = 0;
// *****************************************************
// * At this point everything necessary is known to
// * submit the packet for processing...
// *****************************************************
// *****************************************************
// * Set the clientID to the localClientID to be used
// * by the server side of the connection.
// *****************************************************
packet->setClientID(client->getLocalID());
// *****************************************************
// * Enqueue the packet and set the pointer to NULL to
// * prevent its later deletion.
// *****************************************************
inbound.enqueue((void *)packet);
packet = NULL;
}
}
if(packet!=NULL) delete packet;
// *********************************************************************
// * If a packet was successfully added to the inbound queue and the
// * queue is not empty , then add an event to the FDTrigger to cause
// * the handle_input mechanism to be called.
// *********************************************************************
if(result==0 && !inbound.empty()) trigger.insertEvent();
// *********************************************************************
// * Due to the new design of the SocketUtil class, the binary should
// * never be deleted.
// *********************************************************************
return result;
}
// *****************************************************************************
// * cdevSessionManager::enqueue :
// * This method is used to enqueue a cdevPacket packet into an outbound
// * queue. The method will first identify the target client and place the
// * packet into its queue... then it will identify the socket and place the
// * packet into its queue.
// *
// * This method will return -1 if either the socket or the client is
// * undefined.
// *
// * The packet remains the property of the caller who must delete it.
// *****************************************************************************
int cdevSessionManager::enqueue ( cdevPacket * input )
{
cdevPacketBinary * packet = encodePacket(input);
ClientSession * client = NULL;
SocketSession * socket = NULL;
int result = -1;
// *********************************************************************
// * Note that this condition makes sure that a queue exists for both
// * the client ID and the socketID. If both of these conditions are
// * met, then it checks to ensure that the socket has not been overrun
// * with data (500 or more packets).
// *********************************************************************
if(packet!=NULL &&
input->getClientID()>0 &&
(client = findLocalClient(input->getClientID()))!=NULL &&
(socket = findSocket(client->getSocketID()))!=NULL)
{
cdevEventHandler * handler = NULL;
Reactor.getHandler(client->getSocketID(), handler);
// *************************************************************
// * Attempt to flush the handler if more than 500 packets
// * have already been inserted.
// *************************************************************
if(handler && socket->getCount()>=500)
{
outputError(CDEV_SEVERITY_WARN, "CDEV Server",
"Forcing flush of socket %i to prevent overflow...",
client->getSocketID());
// *****************************************************
// * Call handleOutput to cause the handler to attempt
// * to write its contents.
// *****************************************************
if(handler->handleOutput()<0)
{
Reactor.removeHandler(handler);
handler = NULL;
}
}
if(handler && socket->getCount()<500)
{
char * binary = NULL;
size_t binaryLen = 0;
// *****************************************************
// * Create a binary stream from the cdevPacketBinary
// * object and then use the detachData method to
// * prevent the buffer from being deleted when the
// * cdevPacketBinary is destroyed.
// *****************************************************
packet->streamOut(&binary, &binaryLen);
packet->detachData();
// *****************************************************
// * Populate the cdevServerBinary object with the data
// * that was extracted from the cdevPacketBinary object
// *****************************************************
socket->enqueue(binary, binaryLen);
// *****************************************************
// * Set the event mask for the outbound socket to read/
// * write to force it to attempt to write to the socket
// * until data is transmitted.
// *****************************************************
if(handler) handler->setMask(READ_MASK|WRITE_MASK);
result = 0;
}
else if(handler)
{
outputError ( CDEV_SEVERITY_ERROR, "CDEV Server",
"Dropping packet to socket %i : queue is full...",
client->getSocketID());
}
}
// *********************************************************************
// * Delete the cdevPacketBinary if it was generated.
// *********************************************************************
if(packet) delete packet;
return result;
}
// *****************************************************************************
// * cdevSessionManager::dequeue :
// * This method is used to by the server engine to extract a message from
// * the inbound queue. Once the packet has been enqueue it will be sent to
// * the decodePacket method which will perform any preprocessing that the
// * developer may deem necessary before returning the packet to the caller.
// *
// * The cdevPacket object becomes the property of the caller and must
// * be deleted when it is no longer needed.
// *****************************************************************************
int cdevSessionManager::dequeue ( cdevPacket * &packet )
{
cdevPacketBinary * binary = NULL;
packet = NULL;
// *********************************************************************
// * Conitnue this loop unitl a valid packet has been extracted, or
// * until there are no more binary packets left in the queue.
// *********************************************************************
do {
// *************************************************************
// * Attempt to dequeue the cdevPacketBinary from the queue...
// * If it is not NULL, then begin processing.
// *************************************************************
if((binary = (cdevPacketBinary *)inbound.dequeue())!=NULL)
{
// *****************************************************
// * Call the decodePacket mechanism... This will use
// * the factory mechanisms of the cdevPacket class to
// * import the data and then will complete any required
// * preprocessing...
// *****************************************************
packet = decodePacket(binary);
// *****************************************************
// * Delete the binary as it is no longer needed.
// *****************************************************
delete binary;
}
} while(binary!=NULL && packet==NULL);
// *********************************************************************
// * Return 0 if a cdevPacket was successfully dequeued, otherwise,
// * return -1.
// *********************************************************************
return packet?0:-1;
}
// *****************************************************************************
// * cdevServer::decodePacket :
// * This method is used to perform preprocessing on a newly dequeued binary
// * packet before it is provided to the caller. This method allows the
// * developer to perform special preparations on the packet before providing
// * it to the caller.
// *****************************************************************************
cdevPacket * cdevSessionManager::decodePacket (cdevPacketBinary * input)
{
return input?cdevPacket::import(*input):(cdevPacket *)NULL;
}
// *****************************************************************************
// * cdevSessionManager::encodePacket :
// * This method is used to perform postprocessing on a packet that has been
// * enqueued to be sent to a client. This method allows the developer to
// * perform special preparations on the packet before providing it to the
// * client.
// *****************************************************************************
cdevPacketBinary * cdevSessionManager::encodePacket ( cdevPacket * input )
{
cdevPacketBinary *result;
if(input)
{
char * binary;
size_t binaryLen;
input->streamOut(&binary, &binaryLen);
if(binary && binaryLen)
{
result = new cdevPacketBinary;
result->attachData(binary, binaryLen);
}
}
return result;
}
// *****************************************************************************
// * cdevSessionManager::getHandle :
// * This method is used to obtain a copy of the file handle that is used
// * to poll for events. In this case it will be the read file descriptor
// * of the FD_Trigger object.
// *****************************************************************************
int cdevSessionManager::getHandle ( void ) const
{
return trigger.readfd();
}
// *****************************************************************************
// * cdevSessionManager::handleInput :
// * This method is called whenever there is a read event pending on the
// * FD_Trigger object.
// *****************************************************************************
int cdevSessionManager::handleInput ( void )
{
processMessages();
if(inbound.empty()) trigger.purge();
return 0;
}
// ****************************************************************************
// cdevSessionManager::handleClose :
// Shuts down the timer - this will result in the destruction of the
// * cdevSessionManager object.
// ****************************************************************************
int cdevSessionManager::handleClose(void)
{
return -1;
}
// ****************************************************************************
// * cdevSessionManager::handleTimeout :
// * Called when the timer expires... This method serves only to call the
// * processMessages function.
// ****************************************************************************
int cdevSessionManager::handleTimeout(void)
{
processMessages();
if(inbound.empty()) trigger.purge();
return 0;
}
// ***************************************************************************
// * cdevServer::processMessages :
// * This is a simple stand-in function that retrieves a message from the
// * queue and then immediately returns it to the outbound queue. This
// * function should be overloaded by the developers mechanism for
// * processing messages.
// ***************************************************************************
void cdevSessionManager::processMessages ( void )
{
cdevPacket * packet;
while(dequeue(packet)==0)
{
enqueue(packet);
delete packet;
}
}
@@ -0,0 +1,157 @@
#include "cdevSocket.h"
void cdevSocket::setHandle ( int fd )
{
handle = fd;
}
int cdevSocket::getHandle ( void ) const
{
return handle;
}
int cdevSocket::open (int type, int protocol_family, int protocol)
{
setHandle(::socket(protocol_family, type, protocol));
return getHandle();
}
int cdevSocket::close (void)
{
int result = ::close(getHandle());
setHandle(INVALID_HANDLE);
return result;
}
int cdevSocket::unsetFlags ( int flags )
{
int retval = -1;
int fd = getHandle();
if(fd!=cdevSocket::INVALID_HANDLE)
{
#ifdef WIN32
if(flags==O_NONBLOCK)
{
unsigned long val = 0;
retval = ::ioctlsocket(fd, FIONBIO, &val);
}
#else
int val;
if((val=::fcntl(fd, F_GETFL, 0)) != -1)
{
val &= ~flags;
retval = (::fcntl(fd, F_SETFL, val)!=-1)?0:1;
}
#endif
}
return retval;
}
int cdevSocket::setFlags ( int flags )
{
int retval = -1;
int fd = getHandle();
if(fd!=cdevSocket::INVALID_HANDLE)
{
#ifdef WIN32
if(flags==O_NONBLOCK)
{
unsigned long val = 1;
retval = ::ioctlsocket(fd, FIONBIO, &val);
}
#else
int val;
if ((val=::fcntl(fd, F_GETFL, 0)) != -1)
{
val |= flags;
if(::fcntl(fd, F_SETFL, val) != -1) retval = 0;
}
#endif
}
return retval;
}
int cdevSocket::getFlags ( void )
{
int retval = -1;
int fd = getHandle();
#ifdef WIN32
retval = 0;
#else
if(fd!=cdevSocket::INVALID_HANDLE)
{
retval=::fcntl(fd, F_GETFL, 0);
}
#endif
return retval;
}
int cdevSocket::setOption (int level, int option, void *optval, int optlen) const
{
return ::setsockopt(getHandle(), level, option, (char *)optval, (SOCKOPT_SIZE_PARM)optlen);
}
int cdevSocket::getOption (int level, int option, void *optval, int *optlen) const
{
return ::getsockopt(getHandle(), level, option, (char *)optval, (SOCKOPT_SIZE_PARM *)optlen);
}
int cdevSocket::getLocalAddress (cdevAddr & addr)
{
int retval;
int len=addr.getSize();
if(::getsockname(getHandle(), (sockaddr *)addr.getAddress(), (SOCKOPT_SIZE_PARM *)&len)==INVALID_HANDLE)
{
retval = INVALID_HANDLE;
}
else {
addr.setSize(len);
retval = 0;
}
return retval;
}
int cdevSocket::getRemoteAddress (cdevAddr & addr)
{
int retval;
int len = addr.getSize();
if(::getpeername(getHandle(), (sockaddr *)addr.getAddress(), (SOCKOPT_SIZE_PARM *)&len)==INVALID_HANDLE)
{
retval = INVALID_HANDLE;
}
else {
addr.setSize(len);
retval = 0;
}
return retval;
}
cdevSocket::cdevSocket ( void )
: handle(INVALID_HANDLE)
{
}
cdevSocket::cdevSocket(int type, int protocol_family, int protocol)
: handle(INVALID_HANDLE)
{
setHandle(open(type, protocol_family, protocol));
}
@@ -0,0 +1,93 @@
#include "cdevSocketAcceptor.h"
// *****************************************************************************
// * cdevSocketAcceptor::cdevSocketAcceptor :
// * Do nothing routine for constructor.
// *****************************************************************************
cdevSocketAcceptor::cdevSocketAcceptor(void)
{
}
// *****************************************************************************
// * cdevSocketAcceptor::open :
// * General purpose routine for performing server cdevSocket creation.
// *****************************************************************************
int cdevSocketAcceptor::open
(
const cdevAddr &addr,
int reuse_addr,
int protocol_family,
int backlog,
int protocol,
int reopen)
{
int one = 1;
int retval;
if(reopen) cdevSocket::open(SOCK_STREAM, protocol_family, protocol);
if(this->getHandle() == cdevSocket::INVALID_HANDLE)
{
retval = cdevSocket::INVALID_HANDLE;
close();
}
else {
if(reuse_addr && setOption(SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == cdevSocket::INVALID_HANDLE)
{
close();
}
else if(::bind(getHandle(), (sockaddr *)addr.getAddress(),
addr.getSize()) == cdevSocket::INVALID_HANDLE ||
::listen(getHandle(), backlog) == cdevSocket::INVALID_HANDLE)
{
close();
}
retval = getHandle();
}
return retval;
}
// *****************************************************************************
// * cdevSocketAcceptor::cdevSocketAcceptor :
// * General purpose routine for performing server cdevSocket creation.
// *****************************************************************************
cdevSocketAcceptor::cdevSocketAcceptor (
const cdevAddr &addr,
int reuse_addr,
int protocol_family,
int backlog,
int protocol)
: cdevSocket(SOCK_STREAM, protocol_family, protocol)
{
open(addr, reuse_addr, protocol_family, backlog, protocol, 0);
}
// *****************************************************************************
// * cdevSocketAcceptor::accept :
// * General purpose routine for accepting new connections.
// *****************************************************************************
int cdevSocketAcceptor::accept(cdevSocketStream &new_stream, cdevAddr *addr) const
{
sockaddr *sock_addr=0;
int *len_ptr=0;
int len;
int new_handle;
if(addr != 0)
{
len=addr->getSize();
len_ptr= &len;
sock_addr=(sockaddr *) addr->getAddress();
}
do {
new_handle=::accept(this->getHandle(), sock_addr, (SOCKOPT_SIZE_PARM *)len_ptr);
} while(new_handle==cdevSocket::INVALID_HANDLE && errno==EINTR);
if(addr != 0) addr->setSize(*len_ptr);
new_stream.setHandle(new_handle);
new_stream.configureHandle();
return new_handle;
}
@@ -0,0 +1,65 @@
#include "cdevSocketConnector.h"
#include "cdevHandleSet.h"
// *****************************************************************************
// * cdevSocketConnector::connect :
// * Actively connect and produce a new cdevSocketStream if things go well...
// *****************************************************************************
int cdevSocketConnector::connect ( const cdevAddr & remote_addr )
{
int retval = 0;
if(getHandle() == cdevSocket::INVALID_HANDLE &&
cdevSocket::open(SOCK_STREAM, PF_INET, 0) == cdevSocket::INVALID_HANDLE)
{
retval = -1;
}
else
{
double secondsWaited = 0.0;
sockaddr *addr=(sockaddr *) remote_addr.getAddress();
size_t size=remote_addr.getSize();
if(configureHandle()<0)
{
retval = -1;
}
else if(::connect(getHandle(), addr, size) == cdevSocket::INVALID_HANDLE)
{
int errCode = GetSocketErrno();
if(getBlockingSemantics()==O_NONBLOCK && errCode==EINPROGRESS)
{
errCode=EWOULDBLOCK;
}
if(errCode == EISCONN)
{
retval = 0;
}
else if(errCode != EWOULDBLOCK)
{
close();
setHandle(cdevSocket::INVALID_HANDLE);
retval = -1;
}
else {
cdevHandleSet ws;
cdevHandleSet es;
struct timeval tv;
int fd = getHandle();
ws.set_bit(fd);
es.set_bit(fd);
tv.tv_sec = 3;
tv.tv_usec = 0;
if(cdevSelect(fd+1, NULL, ws, es, &tv)>0 && ws.is_set(fd)) retval = 0;
else retval = -1;
}
}
}
return retval;
}
@@ -0,0 +1,44 @@
#include "cdevSocketDatagram.h"
int cdevSocketDatagram::open ( const cdevAddr &addr, int protocol_family, int protocol )
{
int result = 0;
if((result = cdevSocket::open(SOCK_DGRAM, protocol_family, protocol))!=-1)
{
result = bind(getHandle(), (sockaddr *)addr.getAddress(), addr.getSize());
}
if(result!=0) close();
return result;
}
ssize_t cdevSocketDatagram::send (const void *buf, size_t n, const cdevAddr &addr, int flags) const
{
sockaddr *saddr = (sockaddr *) addr.getAddress ();
size_t len = addr.getSize ();
return sendto (this->getHandle (), (const char *) buf, n, flags, (struct sockaddr *) saddr, len);
}
ssize_t cdevSocketDatagram::recv (void *buf, size_t n, cdevAddr &addr, int flags) const
{
sockaddr *saddr = (sockaddr *) addr.getAddress();
int len = addr.getSize();
ssize_t status = recvfrom (this->getHandle(), (char *)buf, n, flags, (sockaddr *) saddr, (SOCKOPT_SIZE_PARM *)&len);
addr.setSize (len);
return status;
}
cdevSocketDatagram::cdevSocketDatagram ( void )
{
}
cdevSocketDatagram::cdevSocketDatagram ( const cdevAddr &addr, int protocol_family, int protocol )
{
open(addr, protocol_family, protocol);
}
+177
View File
@@ -0,0 +1,177 @@
#include "cdevSocketStream.h"
// *****************************************************************************
// * cdevSocketStream::cdevSocketStream :
// * Constructor for the cdevSocketStream class. Only serves to initialize
// * the readRetryCount variable.
// *****************************************************************************
cdevSocketStream::cdevSocketStream ( void )
{
}
// *****************************************************************************
// * cdevSocketStream::send :
// * Send an n byte message to the connected socket.
// *****************************************************************************
ssize_t cdevSocketStream::send(const void *buf, size_t n, int flags) const
{
int retval;
if((retval = ::send(getHandle(), (const char *) buf, n, flags))<=0)
{
int errCode = GetSocketErrno();
if(errCode==EAGAIN || errCode==EWOULDBLOCK) retval = 0;
}
return retval;
}
// *****************************************************************************
// * cdevSocketStream::send_n :
// * This method will transmit an n byte message to a connected socket,
// * waiting until all data has been transmitted or an error occurs.
// *****************************************************************************
ssize_t cdevSocketStream::send_n(const void *buf, size_t n, int flags) const
{
ssize_t amntsent = 0;
int result = 0;
while(amntsent<(ssize_t)n && result>=0)
{
if((result = ::send(getHandle(), (const char *)buf+amntsent, n-amntsent, flags))<=0)
{
int errCode = GetSocketErrno();
if(errCode==EAGAIN || errCode==EWOULDBLOCK) result = 0;
else result = -1;
}
else amntsent+=result;
}
return (amntsent>=(ssize_t)n)?amntsent:-1;
}
// *****************************************************************************
// * cdevSocketStream::recv :
// * Recv an n byte message from the connected socket.
// *****************************************************************************
ssize_t cdevSocketStream::recv(void *buf, size_t n, int flags)
{
int retval = 0;
if((retval = ::recv(getHandle(), (char *)buf, n, flags))<=0)
{
int errCode = GetSocketErrno();
if(errCode==EAGAIN || errCode==EWOULDBLOCK) retval = 0;
}
return retval;
}
// *****************************************************************************
// * cdevSocketStream::recv_n :
// * This method will receive an n byte message from a connected socket,
// * waiting until all data has been received or an error occurs.
// *****************************************************************************
ssize_t cdevSocketStream::recv_n(void *buf, size_t n, int flags)
{
ssize_t amntrecv = 0;
int result = 0;
while(amntrecv < (ssize_t)n)
{
if((result = ::recv(getHandle(), (char *)buf+amntrecv, n-amntrecv, flags)) < 0)
{
return -1;
}
else if (result == 0)
break;
else amntrecv+=result;
}
return amntrecv;
}
// *****************************************************************************
// * cdevSocketStream::closeReader :
// * Shut down just the reading end of a cdevSocket.
// *****************************************************************************
int cdevSocketStream::closeReader(void)
{
return ::shutdown(getHandle(), 0);
}
// *****************************************************************************
// * cdevSocketStream::closeWriter :
// * Shut down just the writing end of a cdevSocket.
// *****************************************************************************
int cdevSocketStream::closeWriter(void)
{
return ::shutdown(getHandle(), 1);
}
int cdevSocketStream::getBlockingSemantics ( void ) const
{
return O_NONBLOCK;
}
int cdevSocketStream::getRcvLowWaterMark ( void ) const
{
return 0;
}
int cdevSocketStream::getRcvBufferSize ( void ) const
{
return 56000;
}
int cdevSocketStream::getSndLowWaterMark ( void ) const
{
return 16000;
}
int cdevSocketStream::getSndBufferSize ( void ) const
{
return 56000;
}
int cdevSocketStream::configureHandle ( void )
{
int retval = 0;
int parm = 1;
if(getBlockingSemantics()==O_NONBLOCK && setFlags(O_NONBLOCK)==-1)
{
retval = -1;
}
setOption(IPPROTO_TCP, TCP_NODELAY, &parm, sizeof(parm));
if((parm = getRcvBufferSize())>0)
{
setOption(SOL_SOCKET, SO_RCVBUF, &parm, sizeof(parm));
}
#ifndef __linux
if((parm = getRcvLowWaterMark())>0)
{
setOption(SOL_SOCKET, SO_RCVLOWAT, &parm, sizeof(parm));
}
#endif
if((parm = getSndBufferSize())>0)
{
setOption(SOL_SOCKET, SO_SNDBUF, &parm, sizeof(parm));
}
#ifndef __linux
if((parm = getSndLowWaterMark())>0)
{
setOption(SOL_SOCKET, SO_SNDLOWAT, &parm, sizeof(parm));
}
#endif
return retval;
}
@@ -0,0 +1,20 @@
#include "cdevStreamNode.h"
cdevStreamNode::cdevStreamNode ( void )
: nextStreamNode(NULL)
{
}
cdevStreamNode::~cdevStreamNode ( void )
{
}
cdevStreamNode * cdevStreamNode::getNext( void ) const
{
return nextStreamNode;
}
void cdevStreamNode::setNext (cdevStreamNode * node)
{
nextStreamNode = node;
}
@@ -0,0 +1,35 @@
#include "cdevStreamQueue.h"
cdevSimpleStreamNode::cdevSimpleStreamNode( char * buffer, size_t size)
: cdevStreamNode(), buf(buffer), len(size)
{
}
cdevSimpleStreamNode::~cdevSimpleStreamNode ( void )
{
if(buf) delete buf;
}
size_t cdevSimpleStreamNode::getLen (void) const
{
return len;
}
void cdevSimpleStreamNode:: setLen (size_t size)
{
len=size;
}
char * cdevSimpleStreamNode::getBuf (void) const
{
return buf;
}
void cdevSimpleStreamNode::setBuf (char * buffer, size_t size)
{
buf=buffer; len=size;
}
cdevNodeFactory::~cdevNodeFactory ( void )
{
}
+221
View File
@@ -0,0 +1,221 @@
#include <cdevTagMap.h>
// *****************************************************************************
// * cdevTagMap::cdevTagMap :
// * This is the constructor for the cdevTagMap class.
// *****************************************************************************
cdevTagMap::cdevTagMap ( void )
: cnt(0),
maximum(0),
local(NULL),
remote(NULL)
{
}
// *****************************************************************************
// * cdevTagMap::cdevTagMap :
// * This is the destructor for the cdevTagMap class.
// *****************************************************************************
cdevTagMap::~cdevTagMap ( void )
{
if(local !=NULL) free(local);
if(remote!=NULL) free(remote);
}
// *****************************************************************************
// * cdevTagMap::updateTagMap :
// * This method will read the names and integers from a cdevData object and
// * will then pass these values to the updateTagMap method for processing.
// *
// * For standardization the tag integers are placed in tag 1, and the
// * tag strings are placed in tag 2...
// *****************************************************************************
void cdevTagMap::updateTagMap ( cdevData & data )
{
char ** names;
int * tags;
size_t nameCnt=0, tagCnt=0;
if(data.getElems(1, &tagCnt)==CDEV_SUCCESS &&
data.getElems(2, &nameCnt)==CDEV_SUCCESS &&
tagCnt>0 && tagCnt==nameCnt)
{
names = new char *[nameCnt];
tags = new int [tagCnt];
memset(names, 0, sizeof(char *)*nameCnt);
data.get(1, tags);
data.get(2, names);
updateTagMap(names, tags, nameCnt);
while(nameCnt>0)
{
--nameCnt;
delete names[nameCnt];
}
delete names;
delete tags;
}
}
// *****************************************************************************
// * cdevTagMap::updateTagMap :
// * This method will create a mapping of the differences between the tags
// * specified in the user provided array and the tags that are stored
// * within cdevData.
// *****************************************************************************
void cdevTagMap::updateTagMap ( char ** names, int * tags, int count )
{
// *********************************************************************
// * Process each item in the names array from last to first.
// *********************************************************************
while((--count)>=0)
{
int localTag = -1;
// *************************************************************
// * Determine if a tag that is identified by the names[count]
// * string exists in the cdevData Global Tag Table. If it
// * does, copy its integer representation into the localTag
// * variable.
// *************************************************************
if(cdevData::tagC2I(names[count], &localTag)!=CDEV_SUCCESS)
{
// *****************************************************
// * If the string does not already exist in the
// * cdevData Global Tag Table, then attempt to add it.
// *
// * If the specified integer is in use locally by
// * another cdevData tag - then the value will be
// * incremented until an open slot is found.
// *****************************************************
char * s;
localTag = tags[count];
while(cdevData::tagI2C(localTag, s)==CDEV_SUCCESS)
{
localTag++;
}
cdevData::insertTag(localTag, names[count]);
}
// *************************************************************
// * If the local integer tag value differs from the remote
// * integer tag value, then this tag must be added to the
// * list.
// *************************************************************
if(localTag != tags[count])
{
int idx;
// *****************************************************
// * Walk through the list and determine if the tag
// * has already been added to the list...
// *****************************************************
for(idx=0; idx<cnt && remote[idx]!=tags[count]; idx++);
// *****************************************************
// * If the tag does not already exist in the list,
// * then do the following.
// *****************************************************
if(idx>=cnt)
{
// *********************************************
// * If the internal arrays have not yet been
// * allocated, then allocate a default number
// * of entries (64).
// *********************************************
if(maximum==0)
{
maximum=64;
local = (int *)malloc(maximum*sizeof(int));
remote = (int *)malloc(maximum*sizeof(int));
}
// *********************************************
// * If the internal arrays are already filled
// * by the existing entries, then double the
// * size of the arrays.
// *********************************************
else if(idx>=maximum)
{
maximum*=2;
local = (int *)realloc(local, maximum*sizeof(int));
remote = (int *)realloc(remote, maximum*sizeof(int));
}
// *********************************************
// * Populate the new entry with the mismatch
// * data and increment the total number of
// * mismatches.
// *********************************************
local [idx] = localTag;
remote[idx] = tags[count];
cnt = idx+1;
}
}
}
}
// *****************************************************************************
// * cdevTagMap::swapTags :
// * This method is used to swap between two sets of tags... If a tag
// * listed in the outTags array is used in the cdevData item, its tag will
// * be converted to the corresponding value in the inTags array.
// *****************************************************************************
void cdevTagMap::swapTags ( cdevData & data, int *inTags, int *outTags, int count)
{
int tag;
int changeCount = 0;
cdevDataIterator iter(&data);
iter.init();
do {
int idx;
for(idx=0, tag=iter.tag(); idx<count && tag!=outTags[idx]; idx++);
if(idx<count)
{
data.changeTag(tag, -1*inTags[idx]);
changeCount++;
}
} while(++iter != 0);
if(changeCount)
{
iter.init();
do
{
if((tag=iter.tag())<0) data.changeTag(tag, -1*tag);
} while(++iter!=0);
}
}
// *****************************************************************************
// * cdevTagMap::asciiDump :
// * This mechanism is used to perform an ascii dump of the contents of a
// * cdevtagMap structure.
// *****************************************************************************
void cdevTagMap::asciiDump (FILE * fp )
{
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, " Diagnostic Dump of CDEV Tag Map\n");
fprintf(fp, "----------------------------------------------------------\n\n");
fprintf(fp, "Number of Mismatches : %i\n", cnt);
fprintf(fp, "Allocated Maximum Mismatches : %i\n", maximum);
if(cnt) {
fprintf(fp, "\nMismatch Table:\n\n");
fprintf(fp, "\tTag Name Local ID Remote ID\n");
fprintf(fp, "\t--------------------------------------------------\n");
for(int i=0; i<cnt; i++)
{
char * s;
cdevData::tagI2C(local[i], s);
fprintf(fp, "\t%-26.26s%-13i%i\n", s, local[i], remote[i]);
}
fprintf(fp, "\t--------------------------------------------------\n\n");
}
fprintf(fp, "----------------------------------------------------------\n");
fprintf(fp, " End of Diagnostic Dump of CDEV Tag Map\n");
fprintf(fp, "----------------------------------------------------------\n\n");
fflush(fp);
}
@@ -0,0 +1,210 @@
#include "cdevTime.h"
cdevTime::cdevTime ( long sec, long usec )
{
setTime(sec, usec);
}
cdevTime::cdevTime ( double t )
{
setTime(t);
}
cdevTime::cdevTime ( timeval & t )
{
setTime(t);
}
cdevTime::cdevTime ( const cdevTime & t )
{
setTime(t);
}
void cdevTime::getTime ( double * t ) const
{
if(t) *t = (double)tv_sec+(double)tv_usec/(double)ONE_SECOND;
}
void cdevTime::getTime ( long * sec, long * usec) const
{
if(sec && usec)
{
*sec = tv_sec;
*usec = tv_usec;
}
}
void cdevTime::getTime ( timeval * t ) const
{
if(t) {
t->tv_sec = tv_sec;
t->tv_usec = tv_usec;
}
}
void cdevTime::setTime ( void )
{
struct timeval tv_time;
gettimeofday(&tv_time);
tv_sec = tv_time.tv_sec;
tv_usec = tv_time.tv_usec;
}
void cdevTime::setTime ( double t )
{
tv_sec = (long)t;
tv_usec = (long)((double)fmod(t, 1.0)*(double)ONE_SECOND);
normalize();
}
void cdevTime::setTime ( long sec, long usec )
{
tv_sec = sec;
tv_usec = usec;
normalize();
}
void cdevTime::setTime ( timeval & t )
{
tv_sec = t.tv_sec;
tv_usec = t.tv_usec;
normalize();
}
void cdevTime::setTime ( const cdevTime & t )
{
t.getTime(&tv_sec, &tv_usec);
normalize();
}
void cdevTime::clear ( void )
{
tv_sec = 0;
tv_usec = 0;
}
int cdevTime::isSet ( void ) const
{
return (tv_sec||tv_usec)?1:0;
}
int cdevTime::normalize ( void )
{
while ((this->tv_usec >= ONE_SECOND)
|| (this->tv_sec < 0 && this->tv_usec > 0 ))
{
this->tv_usec -= ONE_SECOND;
this->tv_sec++;
}
while ((this->tv_usec <= -ONE_SECOND)
|| (this->tv_sec > 0 && this->tv_usec < 0))
{
this->tv_usec += ONE_SECOND;
this->tv_sec--;
}
return isSet();
}
cdevTime & cdevTime::operator = ( const cdevTime & t )
{
if (this != &t)
{
tv_sec = t.tv_sec;
tv_usec = t.tv_usec;
}
return *this;
}
cdevTime::operator double ( void )
{
return (double)tv_sec+(double)tv_usec/(double)ONE_SECOND;
}
cdevTime::operator timeval ( void )
{
timeval tv_time;
tv_time.tv_sec = tv_sec;
tv_time.tv_usec = tv_usec;
return tv_time;
}
cdevTime operator + (cdevTime t1, cdevTime t2)
{
cdevTime sum (t1.tv_sec + t2.tv_sec, t1.tv_usec + t2.tv_usec);
sum.normalize ();
return sum;
}
cdevTime operator - (cdevTime t1, cdevTime t2)
{
cdevTime delta (t1.tv_sec - t2.tv_sec, t1.tv_usec - t2.tv_usec);
delta.normalize ();
return delta;
}
int operator > (cdevTime t1, cdevTime t2)
{
if (t1.tv_sec > t2.tv_sec) return 1;
else if (t1.tv_sec == t2.tv_sec && t1.tv_usec > t2.tv_usec) return 1;
else return 0;
}
int operator >= (cdevTime t1, cdevTime t2)
{
if (t1.tv_sec > t2.tv_sec) return 1;
else if (t1.tv_sec == t2.tv_sec && t1.tv_usec >= t2.tv_usec) return 1;
else return 0;
}
int operator < (cdevTime t1, cdevTime t2)
{
return t2 > t1;
}
int operator <= (cdevTime t1, cdevTime t2)
{
return t2 >= t1;
}
int operator == (cdevTime t1, cdevTime t2)
{
return t1.tv_sec == t2.tv_sec && t1.tv_usec == t2.tv_usec;
}
int operator != (cdevTime t1, cdevTime t2)
{
return !(t1 == t2);
}
+2
View File
@@ -0,0 +1,2 @@
#define _FIFO_QUEUE_MASTER_ 1
#include <fifo.h>