cdev-1.7.2n

This commit is contained in:
2022-12-13 12:44:04 +01:00
commit b3b88fc333
1357 changed files with 338883 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
ARCH = OS
SHOBJ = YES
include ../include/makeinclude/Makefile.$(ARCH)
APPNAME = "CDEV Generic Client Engine"
TEMPLINKS = cdevPacket.cc\
cdevMessageBinary.cc\
cdevMessage.cc\
cdevContextMap.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
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
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 = $(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)/libcdevClient.$(SHARED_EXT) \
$(CDEVLIB)/libcdevClient.a
ifeq ($(SHOBJ),YES)
TARGETS = $(TEMPLINKS) $(CDEVLIB)/libcdevClient.$(SHARED_EXT)
else
TARGETS = $(TEMPLINKS) $(CDEVLIB)/libcdevClient.a
endif
targets : $(TARGETS)
$(TEMPLINKS) :
@cp $^ $@
$(CDEVLIB)/libcdevClient.a : $(CLIENT_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
$(LINK.a) $@ $^
@$(RANLIB) $@ > /dev/null
@cp $@ $(CDEVLIB)
$(CDEVLIB)/libcdevClient.$(SHARED_EXT) : $(CLIENT_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
$(LINK.so) -o $@ $^ $(NETLIBS)
@cp $@ $(CDEVLIB)
cdevMessage.cc : ../cdevPacket/cdevMessage.cc
cdevMessageBinary.cc : ../cdevPacket/cdevMessageBinary.cc
cdevPacket.cc : ../cdevPacket/cdevPacket.cc
cdevContextMap.cc : ../cdevContextMap/cdevContextMap.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

View File

@@ -0,0 +1,139 @@
.SUFFIXES: .cc .obj
APPNAME = CDEV Generic Client Engine
ARCH = WINNT-4.0
TEMPLINKS = cdevPacket.cc\
cdevMessageBinary.cc\
cdevMessage.cc\
cdevContextMap.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
BINARIES = $(CDEVLIB)\cdevClient.dll \
$(CDEVLIB)\cdevClient.lib \
$(TEMPLINKS)
include ..\include\makeinclude\Makefile.WINNT-4.0
CLIENT_OBJS = $(OBJDIR)\cdevClientService.obj\
$(OBJDIR)\cdevClientRequestObject.obj\
$(OBJDIR)\ServerInterface.obj\
$(OBJDIR)\ServerHandler.obj
COMMON_OBJS = $(OBJDIR)\cdevPacket.obj\
$(OBJDIR)\cdevMessageBinary.obj\
$(OBJDIR)\cdevMessage.obj\
$(OBJDIR)\cdevContextMap.obj\
$(OBJDIR)\SignalManager.obj\
$(OBJDIR)\fifo.obj
ACE_OBJS = $(OBJDIR)\cdevAddr.obj\
$(OBJDIR)\cdevEventHandler.obj\
$(OBJDIR)\cdevHandleSet.obj\
$(OBJDIR)\cdevReactor.obj\
$(OBJDIR)\cdevSocket.obj\
$(OBJDIR)\cdevSocketAcceptor.obj\
$(OBJDIR)\cdevSocketConnector.obj\
$(OBJDIR)\cdevSocketDatagram.obj\
$(OBJDIR)\cdevSocketStream.obj\
$(OBJDIR)\cdevStreamNode.obj\
$(OBJDIR)\cdevStreamQueue.obj\
$(OBJDIR)\cdevTime.obj
OBJS = $(CLIENT_OBJS) $(COMMON_OBJS) $(ACE_OBJS)
CXXEXTRA = /D "_CDEV_REACTOR_EXPORTS_=1" /D "_GENERIC_SERVER_EXPORTS_=1"
!IF "$(SHOBJ)" == "YES"
TARGETS = $(TEMPLINKS) $(CDEVLIB)\cdevClient.dll
!ELSE
TARGETS = $(TEMPLINKS) $(CDEVLIB)\cdevClient.lib
!ENDIF
targets : $(TARGETS)
@erase $(TEMPLINKS)
$(CDEVLIB)\cdevClient.lib : $(OBJS)
@echo ^ ^ ^ =^> Linking $(@F)
-@if exist $@ erase $@
-@if not exist $(@D) mkdir $(@D)
@$(LIB32) $(CDEVLIB)\cdev.lib\
$(LINK_LIB_FLAGS) /out:$@ $(OBJS)
@echo ^ ^ ^ ^ ^ ^ Done...
$(CDEVLIB)\cdevClient.dll : $(OBJS)
@echo ^ ^ ^ =^> Linking $(@F)
-@if exist $@ erase $@
-@if not exist $(@D) mkdir $(@D)
@$(LIB32) $(CDEVLIB)\cdev.lib\
$(LINK_DLL_FLAGS) /out:$@ /implib:$(@D)\$(@B).lib $(OBJS)
@echo ^ ^ ^ ^ ^ ^ Done...
cdevMessage.cc : ..\cdevPacket\cdevMessage.cc
-@$(CREATE_LINK)
cdevMessageBinary.cc : ..\cdevPacket\cdevMessageBinary.cc
-@$(CREATE_LINK)
cdevPacket.cc : ..\cdevPacket\cdevPacket.cc
-@$(CREATE_LINK)
cdevContextMap.cc : ..\cdevContextMap\cdevContextMap.cc
-@$(CREATE_LINK)
SignalManager.cc : ..\common\SignalManager.cc
-@$(CREATE_LINK)
cdevAddr.cc : ..\cdevReactor\cdevAddr.cc
-@$(CREATE_LINK)
cdevEventHandler.cc : ..\cdevReactor\cdevEventHandler.cc
-@$(CREATE_LINK)
cdevHandleSet.cc : ..\cdevReactor\cdevHandleSet.cc
-@$(CREATE_LINK)
cdevReactor.cc : ..\cdevReactor\cdevReactor.cc
-@$(CREATE_LINK)
cdevSocket.cc : ..\cdevReactor\cdevSocket.cc
-@$(CREATE_LINK)
cdevSocketAcceptor.cc : ..\cdevReactor\cdevSocketAcceptor.cc
-@$(CREATE_LINK)
cdevSocketConnector.cc : ..\cdevReactor\cdevSocketConnector.cc
-@$(CREATE_LINK)
cdevSocketDatagram.cc : ..\cdevReactor\cdevSocketDatagram.cc
-@$(CREATE_LINK)
cdevSocketStream.cc : ..\cdevReactor\cdevSocketStream.cc
-@$(CREATE_LINK)
cdevStreamNode.cc : ..\cdevReactor\cdevStreamNode.cc
-@$(CREATE_LINK)
cdevStreamQueue.cc : ..\cdevReactor\cdevStreamQueue.cc
-@$(CREATE_LINK)
cdevTime.cc : ..\cdevReactor\cdevTime.cc
-@$(CREATE_LINK)
fifo.cc : ..\common\fifo.cc
-@$(CREATE_LINK)

View File

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

View File

@@ -0,0 +1,97 @@
#if !defined (_SERVER_HANDLER_H_)
#define _SERVER_HANDLER_H_
// *****************************************************************************
// * SIG_PIPE_HANDLED:
// * This definition tells the SocketWriter class not to independently
// * handle the SIGPIPE signal.
// *****************************************************************************
#define SIG_PIPE_HANDLED 1
#include "cdevEventHandler.h"
#include "cdevAddr.h"
#include "cdevSocketConnector.h"
#include "cdevReactor.h"
#include "SocketUtil.h"
#include "fifo.h"
class ServerInterface;
class ServerHandlerCallbackNode;
class SignalManager;
// *****************************************************************************
// * ServerHandlerCallback :
// * This class is used by other classes to register to be informed when the
// * ServerHandler is destroyed.
// *****************************************************************************
class GENERIC_SERVER_API ServerHandlerCallback
{
public:
ServerHandlerCallback ( void ) {}
virtual ~ServerHandlerCallback ( void ) {}
virtual void executeServerHandlerCallback (class ServerHandler * handler) = 0;
};
// *****************************************************************************
// * ServerHandler:
// * This class provides the mechanisms that will be used to service the
// * requests of a client.
// *****************************************************************************
class GENERIC_SERVER_API ServerHandler : public cdevEventHandler,
public SocketReader,
public SocketWriter
{
protected:
static SignalManager signalManager;
static int signalManagerInit;
char hostName [MAXHOSTNAMELEN + 1];
char server [256];
FifoQueue & queue;
cdevSocketConnector stream;
ServerInterface * serverface;
ServerHandlerCallbackNode * callbacks;
size_t enqueuedPackets;
size_t enqueuedBytes;
short clientID;
int contextID;
int tagChanged;
int serverQuitFlag;
public:
ServerHandler (char * Server, ServerInterface * Interface);
~ServerHandler (void);
virtual int outputError (int severity, char *name, char *formatString, ...);
virtual int open (const cdevAddr &addr);
char * getHostName (void);
char * getName (void) const;
virtual int getHandle (void) const;
virtual char * getServer (void) const;
virtual int handleClose (void);
virtual int handleInput (void);
virtual int handleOutput (void);
virtual int handleExcept (void);
virtual void registerServerCallback (ServerHandlerCallback *);
virtual void unregisterServerCallback (ServerHandlerCallback *);
void enqueue (char * buf, size_t len);
void undequeue (char * buf, size_t len) { queue.undequeue(buf, len); }
int dequeue (char **buf, size_t *len) { return queue.dequeue(buf, len); }
int empty (void) { return queue.empty(); }
static short getNextClientID ( void );
short getClientID ( void ) { return clientID; }
void setClientID ( short ClientID ) { clientID=ClientID; }
int getContextID ( void ) { return contextID; }
void setContextID ( int ContextID ) { contextID = ContextID; }
int getTagChangeFlag ( void ) { return tagChanged; }
void setTagChangeFlag ( int flag ) { tagChanged = flag; }
};
#endif /* _SERVER_HANDLER_H_ */

View File

@@ -0,0 +1,506 @@
#include "cdevClock.h"
#include "ServerInterface.h"
cdevReactor ServerInterface::Reactor;
// *****************************************************************************
// * ServerConnectionList::ServerConnectionList :
// * Constructor for the list of active connections that is being managed
// * by the ServerHandler.
// *****************************************************************************
ServerConnectionList::ServerConnectionList ( void )
{
maxItems = ALLOCATION_COUNT;
items = (ServerHandler **)malloc(maxItems*sizeof(ServerHandler *));
memset(items, 0, maxItems*sizeof(ServerHandler *));
}
// *****************************************************************************
// * ServerConnectionList::~ServerConnectionList :
// * Destructor for the list of active connections that is being managed
// * by the ServerHandler.
// *****************************************************************************
ServerConnectionList::~ServerConnectionList ( void )
{
free (items);
}
// *****************************************************************************
// * ServerConnectionList::find :
// * Locates a ServerHandler object that is associated with the specified
// * server name.
// *****************************************************************************
ServerHandler * ServerConnectionList::find ( char * server )
{
int i;
for(i=0;
i<maxItems &&
items[i]!=NULL &&
strcmp(server, items[i]->getServer());
i++);
return (i<maxItems && items[i]!=NULL)?items[i]:(ServerHandler *)NULL;
}
// *****************************************************************************
// * ServerConnectionList::insert :
// * Inserts the new ServerHandler object specified by handler into the
// * server connection list if it does not already exist there...
// *****************************************************************************
int ServerConnectionList::insert ( ServerHandler * handler )
{
int result = -1;
if(handler!=NULL)
{
int i;
char * server = handler->getServer();
for(i=0;
i<maxItems &&
items[i]!=NULL &&
items[i]!=handler &&
strcmp(server, items[i]->getServer());
i++);
if(i>=maxItems)
{
items = (ServerHandler **) realloc(items, 2*maxItems*sizeof(ServerHandler *));
memset(&items[maxItems], 0, maxItems*sizeof(ServerHandler *));
maxItems*=2;
}
if(items[i]==NULL)
{
items[i] = handler;
result = 0;
}
}
return result;
}
// *****************************************************************************
// * ServerConnectionList::remove :
// * Removes the ServerHandler object specified by handler if it exists in
// * list.
// *****************************************************************************
int ServerConnectionList::remove ( ServerHandler * handler )
{
int result = -1;
if(handler!=NULL)
{
int i;
for(i=0; i<maxItems && items[i]!=NULL && items[i]!=handler; i++);
if(i<maxItems && items[i]==handler)
{
items[i] = NULL;
if(i<maxItems-1) memmove(&items[i], &items[i+1], (maxItems-(i+1))*sizeof(ServerHandler *));
result = 0;
}
}
return result;
}
// *****************************************************************************
// * ServerConnectionList::remove :
// * locates and removes the ServerHandler specified by server and returns
// * a pointer to the handler that was removed.
// *****************************************************************************
ServerHandler * ServerConnectionList::remove ( char * server )
{
ServerHandler * handler = find(server);
if(handler!=NULL) remove(handler);
return handler;
}
// *****************************************************************************
// * ServerInterface::ServerInterface :
// * This is the constructor for the ServerInterface class. This class
// * will establish and maintain a collection of connections to cdevServers.
// *****************************************************************************
ServerInterface::ServerInterface ( void )
: connections(),
connectionQueues(),
defaultServer(NULL),
defaultServerHandler(NULL),
maxFd(32)
{
fdList = (int *)malloc( sizeof(int)*maxFd);
}
// *****************************************************************************
// * ServerInterface::~ServerInterface :
// * This is the destructor for the class. It is responsible for releasing
// * any memory that might have been previously allocated to the class.
// *****************************************************************************
ServerInterface::~ServerInterface ( void )
{
if(defaultServer) delete defaultServer;
free (fdList);
// *********************************************************************
// * Remove each of the ServerHandlers from the list and delete them.
// * This will remove them from the global reactor and will terminate
// * the connections.
// *
// * Note: When deleting a ServerHandler - it submits a FAILED_TO_SEND
// * message for each of the packets that it could not send. Because
// * destroying this class implies that the cdevService is being
// * destroyed also, this class will simply delete each of the packets
// * and will not forward any other information.
// *********************************************************************
ServerHandler * handler;
char * buf;
size_t len;
while((handler = connections[0])!=NULL)
{
while(handler->dequeue(&buf, &len)==0) delete buf;
connections.remove(handler);
delete handler;
}
// *********************************************************************
// * Iterate through the queues associated with servers and remove
// * all messages that have not been transmitted.
// *********************************************************************
StringHashIterator iter(&connectionQueues);
iter.first();
while((buf = iter.key())!=NULL)
{
FifoQueue * queue = (FifoQueue *)iter.data();
connectionQueues.remove(buf);
while(queue->dequeue(&buf, &len)==0) delete buf;
delete queue;
iter.first();
}
}
// *****************************************************************************
// * ServerInterface::getDefault :
// * This method allows the caller to obtain a pointer to the name of the
// * default server.
// *****************************************************************************
char * ServerInterface::getDefault ( void )
{
return defaultServer;
}
// *****************************************************************************
// * ServerInterface::setDefault :
// * This method allows the caller to set the name of the default server.
// *****************************************************************************
void ServerInterface::setDefault ( char * Default )
{
if(defaultServer!=NULL)
{
delete defaultServer;
defaultServer = NULL;
defaultServerHandler = NULL;
}
if(Default!=NULL && *Default)
{
defaultServer = strdup(Default);
defaultServerHandler = connect(defaultServer);
}
}
// *****************************************************************************
// * ServerInterface::connect :
// * This is a stub method that should be overridden by the developer in
// * a child class.
// *****************************************************************************
ServerHandler * ServerInterface::connect ( char *, char *, unsigned short )
{
return NULL;
}
// *****************************************************************************
// * ServerInterface::disconnect :
// * This is a stub method that should be overridden by the developer in
// * a child class.
// *****************************************************************************
ServerHandler * ServerInterface::disconnect ( char * )
{
return NULL;
}
// *****************************************************************************
// * ServerInterface::enqueue :
// * This enqueue mechanism is called by the client if they have already
// * identified the server that they wish to communicate with and have
// * obtained a pointer to its ServerHandler object.
// *
// * If the specified server handler is NULL then the message will be
// * submitted to the default server.
// *****************************************************************************
int ServerInterface::enqueue( ServerHandler * handler, char * binary, size_t binaryLen )
{
int result;
if(handler!=NULL || (handler=defaultServerHandler)!=NULL ||
(defaultServer!=NULL && (handler=(defaultServerHandler=connect(defaultServer)))!=NULL))
{
handler->enqueue(binary, binaryLen);
result = CDEV_SUCCESS;
}
else
{
outputError(CDEV_SEVERITY_ERROR,
"ServerInterface::enqueue",
"No default server has been specified");
result = CDEV_ERROR;
}
return result;
}
// *****************************************************************************
// * ServerInterface::getQueue :
// * This method allows the caller to obtain a pointer to the FifoQueue
// * associated with a specific server. This queue is then attached to
// * the ServerHandler that is connected to that server.
// *****************************************************************************
FifoQueue * ServerInterface::getQueue ( char * server )
{
FifoQueue * queue = (FifoQueue *)connectionQueues.find(server);
if(queue==NULL)
{
queue=new FifoQueue;
connectionQueues.insert(server, (void *)queue);
}
return queue;
}
// *****************************************************************************
// * ServerInterface::isPacketValid :
// * This method is called by the ServerHandler after it has been restarted.
// * If the ServerHandler inherits packets that are already in the queue, it
// * will call this method for each pcket in order to determine if they are
// * valid. If the packets are no longer valid (i.e., there is no longer
// * a cdevTransObj associated with them, they will be deleted. Otherwise,
// * they will be submitted to the server.
// *
// * Because this functionality will be handled in a derived class, this
// * method will always return 1 to indicate that the packet is valid.
// *****************************************************************************
int ServerInterface::isPacketValid ( char * binary, size_t binaryLen )
{
return (binary!=NULL && binaryLen>0)?1:0;
}
// *****************************************************************************
// * ServerInterface::getFd :
// * This mechanism is used to obtain a list of the file descriptors that
// * are used by the ServerInterface. These file descriptors may then be
// * used for polling.
// *****************************************************************************
int ServerInterface::getFd (int * &fd, int &numFd )
{
int idx = 0;
numFd = 0;
while(connections[idx]!=NULL)
{
if((numFd+1)>maxFd)
{
maxFd*=2;
fdList = (int *)realloc(fdList, maxFd*sizeof(int));
}
fdList[numFd++] = connections[idx++]->getHandle();
}
if(numFd) fd = fdList;
else fd = NULL;
return CDEV_SUCCESS;
}
// *****************************************************************************
// * ServerInterface::flush :
// * This mechanism is used to flush all outbound buffers to their respective
// * servers.
// *****************************************************************************
int ServerInterface::flush ( void )
{
// *********************************************************************
// * First - determine if there is any outbound data that needs to be
// * processed. Walk through the connectionQueue objects - which exist
// * even if the connection has been lost - and count up the number of
// * queues that are not empty.
// *********************************************************************
StringHashIterator iter(&connectionQueues);
FifoQueue * queue = NULL;
int needsFlush = 0;
// *********************************************************************
// * Invoke a brief reactor.checkHandlers in order to cause any
// * dead ServerHandlers to be removed from the Reactor. Then
// * attempt to reattach to any ServerHandlers that have
// * outbound data.
// *********************************************************************
char * server;
Reactor.checkHandlers();
for(iter.first(); (server=iter.key())!=NULL; iter++)
{
queue = (FifoQueue *)iter.data();
if(queue && !queue->empty())
{
needsFlush++;
connect(server);
}
}
// *********************************************************************
// * At this point he needsFlush variable will be non-zero if any of
// * the queues contain outbound data. The remainder of this code
// * only needs to be performed if this is the case.
// *********************************************************************
if(needsFlush)
{
// *************************************************************
// * Provide a maximum timeout value of 5 seconds. If the system
// * cannot be flushed in that amount of time - then an error or
// * a hang must exist on the other side.
// *************************************************************
cdevTimeValue t(5.0);
cdevClock timer;
timer.schedule(NULL, t);
// *************************************************************
// * While there are sockets that have outbound data AND the
// * timer has not expired - process events.
// *************************************************************
int idx = 0;
while(needsFlush && !timer.expired())
{
needsFlush = 0;
for(idx=0; connections[idx]!=NULL; idx++)
{
if(!connections[idx]->empty())
{
connections[idx]->setMask(cdevEventHandler::WRITE_MASK|cdevEventHandler::EXCEPT_MASK);
needsFlush++;
}
else connections[idx]->setMask(cdevEventHandler::READ_MASK|cdevEventHandler::EXCEPT_MASK);
}
if(needsFlush) Reactor.handleEvents(1.0, cdevReactor::UNTIL_EVENT);
}
// *********************************************************************
// * Walk through all of the ServerHandlers and restore them to
// * READ_MASK mode.
// *********************************************************************
if(needsFlush)
{
for(idx=0; connections[idx]!=NULL; idx++)
{
connections[idx]->setMask(cdevEventHandler::READ_MASK|cdevEventHandler::EXCEPT_MASK);
}
}
}
return CDEV_SUCCESS;
}
// *****************************************************************************
// * ServerInterface::flush :
// * This mechanism is used to flush all outbound buffers to their respective
// * servers.
// *****************************************************************************
int ServerInterface::flush ( int fd )
{
// *********************************************************************
// * Walk through each item and locate the handler that needs to be
// * flushed. If the connection is located, then handle events until
// * it is empty.
// *********************************************************************
int i;
for(i=0; connections[i]!=NULL && connections[i]->getHandle()!=fd; i++);
if(connections[i]!=NULL)
{
cdevTimeValue t(5.0);
cdevClock timer;
timer.schedule(NULL, t);
connections[i]->setMask(cdevEventHandler::WRITE_MASK|cdevEventHandler::EXCEPT_MASK);
while(connections[i]!=NULL && !connections[i]->empty() && !timer.expired())
{
Reactor.handleEvents(1.0, cdevReactor::UNTIL_EVENT);
}
// *************************************************************
// * If an error occurs during the write, the ServerHandler may
// * have been deleted - therefore, check to ensure that the
// * connection is valid prior to restoring its mask.
// *************************************************************
if(connections[i]!=NULL)
{
connections[i]->setMask(cdevEventHandler::READ_MASK|cdevEventHandler::EXCEPT_MASK);
}
}
return CDEV_SUCCESS;
}
// *****************************************************************************
// * ServerInterface::pend :
// * Pends for the specified period of time. The int parameter is not used
// * in this implementation. In later designs it may be used to allow the
// * interface to pend on a specific file descriptor.
// *****************************************************************************
int ServerInterface::pend ( double seconds, int )
{
// *********************************************************************
// * Test to determine if there are any ServerHandlers in operation.
// *********************************************************************
if(connections[0]!=NULL)
{
// *************************************************************
// * Flush outbound requests if necessary.
// *************************************************************
flush();
// *************************************************************
// * Handle events for the specified period.
// *************************************************************
Reactor.handleEvents(seconds);
}
return CDEV_SUCCESS;
}
// *****************************************************************************
// * ServerInterface::poll :
// * This method polls the cdevReactor to see if any events are ready to be
// * processed on any of the sockets. If events are ready, then they are
// * processed immediately - otherwise, the function returns immediately.
// *****************************************************************************
int ServerInterface::poll ( void )
{
// *********************************************************************
// * Test to determine if there are any ServerHandlers in operation.
// *********************************************************************
if(connections[0]!=NULL)
{
// *************************************************************
// * Flush outbound requests if necessary.
// *************************************************************
flush();
// *************************************************************
// * Handle events for 0 seconds - effectively polling.
// *************************************************************
Reactor.handleEvents(0.0001, cdevReactor::UNTIL_EVENT);
}
return CDEV_SUCCESS;
}

View File

@@ -0,0 +1,71 @@
#ifndef _SERVER_INTERFACE_H_
#define _SERVER_INTERFACE_H_
#include "cdevErrCode.h"
#include "ServerHandler.h"
#include "ErrorReporter.h"
#include "StringHash.h"
#include "fifo.h"
#include "cdevReactor.h"
#include "cdevEventHandler.h"
#include "cdevAddr.h"
class GENERIC_SERVER_API ServerConnectionList
{
private:
enum { ALLOCATION_COUNT = 32 };
ServerHandler ** items;
int maxItems;
public:
ServerConnectionList ( void );
virtual ~ServerConnectionList ( void );
ServerHandler * find ( char * server );
int insert ( ServerHandler * handler );
int remove ( ServerHandler * handler );
ServerHandler * remove ( char * server );
ServerHandler * operator [] ( int idx )
{ return (idx<maxItems)?items[idx]:(ServerHandler *)NULL; }
};
class GENERIC_SERVER_API ServerInterface : public ErrorReporter
{
protected:
ServerConnectionList connections;
StringHash connectionQueues;
char * defaultServer;
ServerHandler * defaultServerHandler;
int maxFd;
int * fdList;
public:
enum { FAILED_TO_SEND = -1, COMPLETED = 0};
static cdevReactor Reactor;
ServerInterface ( void );
~ServerInterface ( void );
virtual char * getDefault ( void );
virtual void setDefault ( char * Default );
virtual ServerHandler * connect ( char * server, char * host=NULL, unsigned short port=0 );
virtual ServerHandler * disconnect ( char * server );
int enqueue ( ServerHandler * handler, char * binary, size_t binaryLen );
FifoQueue * getQueue ( char * server );
virtual int enqueue ( int status, ServerHandler * handler, char * binary, size_t binaryLen ) = 0;
virtual int isPacketValid ( char * binary, size_t binaryLen );
virtual int getFd ( int * &fd, int &numFd );
virtual int flush ( void );
int flush ( int fd );
virtual int poll ( void );
virtual int pend ( double seconds, int fd = -1 );
};
#endif /* _SERVER_INTERFACE_H_ */

View File

@@ -0,0 +1,432 @@
#include <ctype.h>
#include <cdevDirectory.h>
#include <cdevClientRequestObject.h>
#include <cdevClock.h>
#include <cdevTranObj.h>
// *****************************************************************************
// * cdevClientRequestObject::cdevClientRequestObject :
// * This constructor initializes the internals of a device/message
// * pair associated with a cdevClientService based service.
// *
// * Returns nothing.
// *
// * Remember it is the responsibility of the requestObject to ensure
// * that the message is not laden with extraneous spaces.
// *****************************************************************************
cdevClientRequestObject::cdevClientRequestObject ( char * device, char * msg, cdevSystem & system)
: cdevRequestObject(device, msg, system),
syncCallback(defaultCallback, (void *)&sendStatus),
handler(NULL), contextID(-1)
{
char message[256];
char * ptr;
*server = 0;
*DDL_server = 0;
// *********************************************************************
// * Remove any extra spaces from the message.
// * Copy user supplied msg to a message buffer to allow
// * modification in this routine since the user supplied
// * msg could be a constant string
// *********************************************************************
strncpy (message, msg, sizeof (message) - 1);
message[255] = 0;
for(ptr=message; *ptr!=0; ptr++)
{
if(isspace(*ptr))
{
char * nextChar;
for(nextChar=ptr+1; isspace(*nextChar) && *nextChar!=0; nextChar++);
if(nextChar!=ptr+1) strcpy(ptr+1, nextChar);
*ptr=' ';
}
}
// *********************************************************************
// * Remove all trailing spaces from the message.
// *********************************************************************
for(ptr = message+(strlen(message)-1); ptr>=message && isspace(*ptr); ptr--)
{
*ptr=0;
}
// *********************************************************************
// * Determine the commandCode from the message string.
// *********************************************************************
if(!strncmp(message, "get ", 4)) commandCode = GET_COMMAND;
else if(!strncmp(message, "set ", 4)) commandCode = SET_COMMAND;
else if(!strncmp(message, "monitorOn ", 10)) commandCode = MONITOR_ON_COMMAND;
else if(!strncmp(message, "monitorOff ", 11)) commandCode = MONITOR_OFF_COMMAND;
else commandCode = OTHER_COMMAND;
// *********************************************************************
// * Determine the messageCode from the message string.
// *********************************************************************
if(!strcmp(message, "get servers")) messageCode = GET_SERVERS_MESSAGE;
else if(!strcmp(message, "get default")) messageCode = GET_DEFAULT_MESSAGE;
else if(!strcmp(message, "set default")) messageCode = SET_DEFAULT_MESSAGE;
else if(!strcmp(message, "disconnect")) messageCode = DISCONNECT_MESSAGE;
else if(!strcmp(message, "get ClientInfo")) messageCode = GET_CLIENTINFO_MESSAGE;
else if(!strcmp(message, "get ServerInfo")) messageCode = GET_SERVERINFO_MESSAGE;
else messageCode = OTHER_MESSAGE;
// *********************************************************************
// * Attempt to read the server name from the DDL file.
// *********************************************************************
cdevData output;
sprintf (DDL_server, "resolveServiceData %s %s", device, message);
if((system.nameServer()).send(DDL_server, NULL, &output)==CDEV_SUCCESS)
{
*DDL_server = 0;
output.get ("server", DDL_server, 256);
}
else *DDL_server = 0;
}
// *****************************************************************************
// * cdevClientRequestObject::~cdevClientRequestObject:
// * This is the destructor for the object. It will free any memory that it
// * has allocated and remove itself from its associated ServerHandler
// * callback.
// *****************************************************************************
cdevClientRequestObject::~cdevClientRequestObject ( void )
{
if(handler!=NULL) handler->unregisterServerCallback(this);
}
// *****************************************************************************
// * cdevClientRequestObject::getState :
// * Returns the connection state of the cdevClientRequestObject.
// *****************************************************************************
int cdevClientRequestObject::getState ( void )
{
ServerHandler * Handler = NULL;
return (getServerHandler(&Handler)==CDEV_SUCCESS)?CDEV_STATE_NOTCONNECTED:CDEV_STATE_CONNECTED;
}
// *****************************************************************************
// * cdevClientRequestObject::className :
// * Obtains the name of this class as a string.
// *****************************************************************************
const char * cdevClientRequestObject::className ( void ) const
{
return "cdevClientRequestObject";
}
// *****************************************************************************
// * cdevClientRequestObject::setContext :
// * This method is called to set the context of the request object. The
// * first step in this process is to determine if the caller has specified
// * a server in the context. If so, the server name should be set to that
// * value. Next call the setContext method of the underlying
// * cdevRequestObject...
// *****************************************************************************
int cdevClientRequestObject::setContext (cdevData& cxt)
{
cdevClientService * svc = (cdevClientService *)service_;
int result = CDEV_SUCCESS;
int newContextID = 0;
if((newContextID = svc->contexts.insert(cxt))!=contextID)
{
ServerHandler * Handler = NULL;
if(handler!=NULL) handler->unregisterServerCallback(this);
contextID = newContextID;
*server = 0;
handler = NULL;
cxt.get ("server", server, 256);
getServerHandler(&Handler);
result = cdevRequestObject::setContext(cxt);
}
return result;
}
// *****************************************************************************
// * cdevClientRequestObject::sendNoBlock :
// * This function allows the caller to submit an asynchronous message to the
// * server for processing.
// *****************************************************************************
int cdevClientRequestObject::sendNoBlock (cdevData & in, cdevData & out)
{ return sendNoBlock(&in, &out); }
int cdevClientRequestObject::sendNoBlock (cdevData * in, cdevData & out)
{ return sendNoBlock(in, &out); }
int cdevClientRequestObject::sendNoBlock (cdevData & in, cdevData * out)
{ return sendNoBlock(&in, out); }
int cdevClientRequestObject::sendNoBlock (cdevData * in, cdevData * out)
{
cdevClientService * svc = (cdevClientService *)service_;
cdevTranObj * xobj = new cdevTranObj(&system_, this, out, &svc->syncCallback);
ServerHandler * Handler = NULL;
int status = CDEV_SUCCESS;
xobj->disableDeleteCbk();
if((status=getServerHandler(&Handler))==CDEV_SUCCESS)
{
status = svc->enqueue(Handler, in, *xobj);
}
else delete xobj;
return status;
}
// *****************************************************************************
// * cdevClientRequestObject::sendCallback :
// * This function allows the caller to submit an asynchronous message to the
// * server for processing.
// *****************************************************************************
int cdevClientRequestObject::sendCallback (cdevData & in, cdevCallback & callback)
{ return sendCallback(&in, callback); }
int cdevClientRequestObject::sendCallback (cdevData * in, cdevCallback & callback)
{
cdevCallback * cb = new cdevCallback(callback);
cdevClientService * svc = (cdevClientService *)service_;
cdevTranObj * xobj = new cdevTranObj(&system_, this, NULL, cb);
ServerHandler * Handler = NULL;
int status = CDEV_SUCCESS;
xobj->enableDeleteCbk();
if((status=getServerHandler(&Handler))==CDEV_SUCCESS)
{
status = svc->enqueue(Handler, in, *xobj);
}
else delete xobj;
return status;
}
// *****************************************************************************
// * cdevClientRequestObject::send :
// * The send interface is used to provide synchronous I/O with the service.
// *
// * Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
// *****************************************************************************
int cdevClientRequestObject::send ( cdevData & in, cdevData & out )
{ return send(&in, &out); }
int cdevClientRequestObject::send ( cdevData * in, cdevData & out )
{ return send(in, &out); }
int cdevClientRequestObject::send ( cdevData & in, cdevData * out )
{ return send(&in, out); }
int cdevClientRequestObject::send ( cdevData * in, cdevData * out )
{
int status = CDEV_SUCCESS;
cdevClientService * svc = (cdevClientService *)service_;
cdevTranObj * xobj = new cdevTranObj(&system_, this, out, &syncCallback);
ServerHandler * Handler;
sendStatus.completionCode = 0;
sendStatus.finished = 0;
xobj->disableDeleteCbk();
if((status=getServerHandler(&Handler))==CDEV_SUCCESS)
{
if((status = svc->enqueue(Handler, in, *xobj))==CDEV_SUCCESS)
{
// *****************************************************
// * I used to wait for a response here only if the outbound
// * cdevData object was non-null. However, that provided
// * unexpected behavior to the client. Now I wait whether
// * output data is expected or not.
// *****************************************************
cdevTimeValue t(waitPeriod());
cdevClock timer;
timer.schedule(NULL,t);
// *****************************************************
// * WAITING WITH system_.pend():
// * Previously I was using system_.pend() to process
// * events while waiting for the service to respond.
// * This resulted in a lock-up when the connection
// * could not be established or if the connection
// * collapsed while in use.
// *
// * WAITING WITH system_.poll():
// * When in a heavy inbound traffic situation, the
// * calls from other services will trample all over
// * the inbound data coming from the server.
// * This results in unreliable delivery and processing
// * of messages from the server.
// *
// * WAITING WITH service_.poll():
// * So far so good.
// *****************************************************
while(!sendStatus.finished && !timer.expired()) service_->poll();
if (!sendStatus.finished)
{
svc->cancel(*xobj);
status = CDEV_ERROR;
system_.reportError(
CDEV_SEVERITY_ERROR,
"cdevRequestObject",
this,
"Server failed to respond after %.1f seconds",
(float)waitPeriod());
}
else
{
status = sendStatus.completionCode;
}
}
}
else delete xobj;
return status;
}
// *****************************************************************************
// * cdevClientRequestObject::defaultCallback :
// * This is the callback function that is used by the object to
// * receive callbacks for send operations.
// *****************************************************************************
void cdevClientRequestObject::defaultCallback (int status, void * user, cdevRequestObject &, cdevData &)
{
SendStatus * result = (SendStatus *)user;
if(result)
{
result->completionCode = status;
result->finished = 1;
}
}
// *****************************************************************************
// * cdevClientRequestObject::executeServerHandlerCallback :
// * The requestObject registers itself with the ServerHandler when it
// * attaches to it... If the Serverhandler is destroyed, it will
// * call this method on all of the registered request objects in order
// * to notify them that it is going away. This allows the request
// * object to clear the pointer to the ServerHandler.
// *****************************************************************************
void cdevClientRequestObject::executeServerHandlerCallback (ServerHandler * Handler)
{
if(Handler==handler)
{
/*
* system_.reportError(CDEV_SEVERITY_INFO, "cdevRequestObject",
* this, "Connection to %s broken for %s:%s",
* Handler->get_server(), device().name(), message());
*/
handler=NULL;
}
}
// *****************************************************************************
// * cdevClientRequestObject::getServerHandler :
// * This method is used to obtain the ServerHandler for this request
// * object...
// *
// * The following rules will be followed:
// *
// * 1) If a server has been specified in the context, then that
// * server will be used.
// *
// * - otherwise -
// *
// * 2) If a server has been specified in the service data of the
// * DDL file, then that server will be used.
// *
// * - otherwise -
// *
// * 3) The default server as specified at the cdevClientService will
// * be used.
// *****************************************************************************
int cdevClientRequestObject::getServerHandler (ServerHandler ** Handler)
{
cdevClientService * svc = (cdevClientService *)service_;
int result = CDEV_SUCCESS;
*Handler = NULL;
if (*server==0 && *DDL_server!=0) strcpy(server, DDL_server);
if (*server!=0 && handler==NULL)
{
if((*Handler = svc->connect(server))==NULL) result = CDEV_ERROR;
else
{
handler = *Handler;
handler->registerServerCallback(this);
}
}
else *Handler = handler;
return result;
}
// *****************************************************************************
// * cdevClientRequestObject::isRequestRestartable :
// * This method allows the caller to determine if the request object
// * is restartable. If a server goes down and then a new server comes
// * up in its place, this method will be called for each request object
// * that has an outstanding request that has not been serviced.
// * If the isRequestRestartable method returns 1, the request will be
// * sent to the new server - otherwise, the request will be terminated.
// *****************************************************************************
int cdevClientRequestObject::isRequestRestartable ( void )
{
int result = 0;
switch(getCommandCode())
{
case GET_COMMAND:
case MONITOR_ON_COMMAND:
result = 1;
break;
case SET_COMMAND:
case MONITOR_OFF_COMMAND:
default:
result = 0;
break;
}
return result;
}
// *****************************************************************************
// * cdevClientRequestObject::getContextID :
// * This method will retrieve the identifier of the context that is
// * currently in use by this object.
// *****************************************************************************
int cdevClientRequestObject::getContextID ( void )
{
return contextID;
}
// *****************************************************************************
// * getCommandCode :
// * This method will return the current value of the commandCode variable.
// * This variable is used to identify the VERB that is utilized by this
// * cdevClientRequestObject. The default set of verbs are "get", "set",
// * "monitorOn", and "monitorOff".
// *****************************************************************************
int cdevClientRequestObject::getCommandCode ( void ) { return commandCode; }
// *****************************************************************************
// * getMessageCode :
// * This method will return the current value of the messageCode variable.
// * This variable is used to identify the message that is utilized by this
// * cdevClientRequestObject. The default set of supported messages are
// * "get servers", "get default", "set default", and "disconnect".
// *****************************************************************************
int cdevClientRequestObject::getMessageCode ( void ) { return messageCode; }

View File

@@ -0,0 +1,223 @@
#if !defined (_CDEV_CLIENT_REQUEST_OBJECT_H_)
#define _CDEV_CLIENT_REQUEST_OBJECT_H_
#include <cdevGroup.h>
#include <cdevErrCode.h>
#include <cdevClientService.h>
// *****************************************************************************
// * cdevClientRequestObject:
// * The cdevClientRequestObject class provides the interface for sending
// * messages to a server. All device/message commands are routed
// * through a cdevClientRequestObject either directly or indirectly.
// *****************************************************************************
class GENERIC_SERVER_API cdevClientRequestObject : public cdevRequestObject, public ServerHandlerCallback
{
protected:
typedef struct
{
int completionCode;
int finished;
} SendStatus;
SendStatus sendStatus;
char server [256];
char DDL_server[256];
cdevCallback syncCallback;
ServerHandler * handler;
int contextID;
int commandCode;
int messageCode;
public:
// *********************************************************************
// * These enumerated type are used to identify the basic four commands
// * that might be represented by a cdevClientRequestObject... By using
// * these identifiers the cdevService does not have to perform a
// * string compare in order to identify the nature of the request
// * object.
// *
// * At construction the cdevClientRequestObject will set the
// * commandCode to contain the correct value, the developer may
// * override this setting in the constructor for an inherited class.
// *
// * Enumerated list extensions created by developers should begin at
// * value cdevClientRequestObject::MONITOR_OFF_COMMAND+1.
// *
// * The current setting of the commandCode may be obtained by calling
// * the getCommandCode method of the class.
// *********************************************************************
enum {OTHER_COMMAND = 0,
GET_COMMAND,
SET_COMMAND,
MONITOR_ON_COMMAND,
MONITOR_OFF_COMMAND};
// *********************************************************************
// * These enumerated type are used to identify the messages that are
// * intrinisicly supported by the cdevService... By using
// * these identifiers the cdevService does not have to perform a
// * string compare in order to identify the nature of the request
// * object.
// *
// * At construction the cdevClientRequestObject will set the
// * messageCode to contain the correct value, the developer may
// * override this setting in the constructor for an inherited class.
// *
// * Enumerated list extensions created by developers should begin at
// * value cdevClientRequestObject::SET_DEFAULT_MESSAGE+1
// *
// * The current setting of the commandCode may be obtained by calling
// * the getMessageCode method of the class.
// *********************************************************************
enum {OTHER_MESSAGE = 0,
GET_SERVERS_MESSAGE,
GET_DEFAULT_MESSAGE,
SET_DEFAULT_MESSAGE,
DISCONNECT_MESSAGE,
GET_CLIENTINFO_MESSAGE,
GET_SERVERINFO_MESSAGE};
cdevClientRequestObject ( char * device, char * message,
cdevSystem & system = cdevSystem::defaultSystem());
virtual ~cdevClientRequestObject ( void );
// *********************************************************************
// * cdevClientRequestObject::getState :
// * Returns the connection state of the cdevClientRequestObject.
// *********************************************************************
virtual int getState ( void );
// *********************************************************************
// * cdevClientRequestObject::setContext :
// * This mechanism is used to specify the default server that will
// * be used for the request.
// *********************************************************************
virtual int setContext ( cdevData & ctx);
// *********************************************************************
// * 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.
// *********************************************************************
virtual int send ( cdevData & in, cdevData & out );
virtual int send ( cdevData * in, cdevData & out );
virtual int send ( cdevData & in, cdevData * out );
virtual int send ( cdevData * in, cdevData * out );
// *********************************************************************
// * cdevClientRequestObject::sendNoBlock :
// * The sendNoBlock interface is used in conjunction with cdevGroup
// * or cdevSystem to execute a series of operations. During the
// * early implementation of this product, these functions will be
// * linked directly to the send call.
// *
// * Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
// *********************************************************************
virtual int sendNoBlock (cdevData & in, cdevData & out);
virtual int sendNoBlock (cdevData * in, cdevData & out);
virtual int sendNoBlock (cdevData & in, cdevData * out);
virtual int sendNoBlock (cdevData * in, cdevData * out);
// *********************************************************************
// * cdevClientRequestObject::sendCallback :
// * The sendCallback interface provides asynchronous communications
// * with the server. During the early implementation of this
// * product, these functions will be linked directly to the send
// * call.
// *
// * Returns CDEV_SUCCESS on success or CDEV_ERROR on error.
// *********************************************************************
virtual int sendCallback (cdevData & in, cdevCallback & callback);
virtual int sendCallback (cdevData * in, cdevCallback & callback);
virtual const char * className ( void ) const;
// *********************************************************************
// * cdevClientRequestObject::deafultCallback :
// * This is the callback function that is used by the object to
// * receive callbacks for send operations.
// *********************************************************************
static void defaultCallback (int status, void * user, cdevRequestObject &, cdevData &);
// *********************************************************************
// * 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.
// *********************************************************************
virtual void executeServerHandlerCallback (ServerHandler * Handler);
// *********************************************************************
// * 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.
// *********************************************************************
virtual int getServerHandler (ServerHandler ** Handler);
// *********************************************************************
// * 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.
// *********************************************************************
virtual int isRequestRestartable ( void );
// *********************************************************************
// * getContextID :
// * This method will retrieve the identifier of the context that
// * is currently in use by this object.
// *********************************************************************
int getContextID ( void );
// *********************************************************************
// * 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 cdevRequestObject. The default set of verbs
// * are "get", "set", "monitorOn", and "monitorOff".
// *********************************************************************
int getCommandCode ( void );
// *********************************************************************
// * 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 cdevRequestObject. The default set of
// * supported messages are "get servers", "get default",
// * "set default", and "disconnect".
// *********************************************************************
int getMessageCode ( void );
// *********************************************************************
// * waitPeriod :
// * This method returns a double that indicates the maximum amount
// * of time that the service should wait for a synchronous result to
// * be returned.
// *********************************************************************
virtual double waitPeriod ( void ) { return 10.0; }
};
#endif /* _CDEV_CLIENT_REQUEST_OBJECT_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
#if !defined (_CDEV_CLIENT_SERVICE_H_)
#define _CDEV_CLIENT_SERVICE_H_
#include <cdevService.h>
#include <cdevRequestObject.h>
#include <cdevTranObj.h>
#include <ServerInterface.h>
#include <AddressIndex.h>
#include <cdevContextMap.h>
#include <ClientInfo.h>
#include <cdevGenericServerTags.h>
#include <StringHash.h>
// *****************************************************************************
// * class NSCallbackArg :
// * This class is provided as a technique for allowing the name server
// * to differentiate when making monitorOn requests between two servers that
// * use the same service.
// *****************************************************************************
class GENERIC_SERVER_API NSCallbackArg
{
friend class cdevClientService;
private:
char * server;
cdevClientService * service;
NSCallbackArg ( char * Server, cdevClientService * Service )
: server(strdup(Server)), service(Service)
{
}
~NSCallbackArg ( void )
{
if(server) delete server;
}
};
// *****************************************************************************
// * cdevClientService:
// * This is class provides the mechanisms that the cdev system will use
// * to communicate with the model service.
// *****************************************************************************
class GENERIC_SERVER_API cdevClientService : public cdevService,
public ServerInterface,
public cdevTagTableCallback
{
friend class cdevClientRequestObject;
friend class cdevClientTransaction;
public:
enum { ServiceTagBase=511 };
static int ServerTag;
static int HostTag;
static int PortTag;
cdevClientService ( char * domain, char * name, cdevSystem & system = cdevSystem::defaultSystem());
static void defaultCallback (int, void *, cdevRequestObject &, cdevData &);
static void nameServerCallback(int, void *, cdevRequestObject &, cdevData &);
virtual int outputError (int severity, char *name, char *formatString, ...);
ServerHandler * connect ( char * server, char * host=NULL, unsigned short port = 0);
ServerHandler * disconnect ( char * server );
int flush ( void );
int pend ( double seconds, int fd = -1 );
int getFd ( int * &fd, int & numFd );
int poll ( void );
int pend ( int fd = -1 );
int getNameServer ( cdevDevice * &ns );
int getRequestObject ( char * device, char * message, cdevRequestObject * &req);
int enqueue ( char * server, cdevData * in, cdevTranObj & xobj );
int enqueue ( ServerHandler * handler, cdevData * in, cdevTranObj & xobj );
int enqueue ( ServerHandler * handler, class cdevClientTransaction &, unsigned);
int cancel ( cdevTranObj & xobj );
int enqueue ( int status, ServerHandler * handler, char * binary, size_t binaryLen );
int isPacketValid ( char * binary, size_t binaryLen );
void callback ( int newTag, char * newName );
char * getDomain ( void ) const { return domain; }
protected:
virtual ~cdevClientService ( void );
virtual void fireCallback ( int status, cdevTranObj &xobj, cdevData *resultData, int partialTransaction = 0 );
virtual int processLocal ( cdevData * in, cdevTranObj & xobj );
char * domain;
AddressIndex transactions;
cdevCallback syncCallback;
cdevContextMap contexts;
int quitFlag;
StringHash nsCallbackArgs;
static ClientInfo clientInfo;
static cdevGenericServerTagDef tags;
NSCallbackArg * getCallbackArg ( char * server );
};
class GENERIC_SERVER_API cdevClientTransaction
{
private:
// *********************************************************************
// * Free list data elements and private array constructor.
// *********************************************************************
enum {ALLOCATION_COUNT = 16 };
static cdevClientTransaction * freeList_;
cdevClientTransaction * freeListNext_;
cdevClientTransaction ( void );
public:
// *********************************************************************
// * Public free list interface.
// *********************************************************************
void * operator new ( size_t size );
void operator delete ( void * ptr );
char server[256];
cdevTranObj * xobj;
int permanent;
int statusCode;
// *********************************************************************
// * Data elements used for restartable transactions.
// *********************************************************************
int restartable;
int contextID;
cdevData * userData;
cdevClientTransaction ( cdevTranObj & XObj, ServerHandler &handler,
int Restartable=0, cdevData *data=NULL,
unsigned ContextID=0 );
virtual ~cdevClientTransaction ( void );
void reconnect (char * host=NULL, unsigned short port=0, unsigned key=0);
};
#endif /* _CDEV_CLIENT_SERVICE_H_ */