cdev-1.7.2n
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+87
@@ -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
@@ -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 )
|
||||
{
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
+148
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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; }
|
||||
|
||||
+1219
File diff suppressed because it is too large
Load Diff
+123
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1510
File diff suppressed because it is too large
Load Diff
+1022
File diff suppressed because it is too large
Load Diff
+76
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#define _FIFO_QUEUE_MASTER_ 1
|
||||
#include <fifo.h>
|
||||
Reference in New Issue
Block a user