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,49 @@
ARCH = OS
SHOBJ = YES
#include ../include/makeinclude/Makefile.$(ARCH)
include ../include/makeinclude/Makefile.linux
APPNAME = CDEV Reactor Library
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
# ******************************************************************************
# * The BINARIES definition names all of the binary files that should be deleted
# * whenever "make clean" is executed.
# ******************************************************************************
BINARIES = $(BASELIB)/libcdevReactor.$(SHARED_EXT) \
$(BASELIB)/libcdevReactor.a
# ******************************************************************************
# * The TARGETS variable is used to specify the name of the library to build.
# ******************************************************************************
ifeq ($(SHOBJ),YES)
TARGETS = $(BASELIB)/libcdevReactor.$(SHARED_EXT)
else
TARGETS = $(BASELIB)/libcdevReactor.a
endif
targets : $(TARGETS)
$(BASELIB)/libcdevReactor.a : $(OBJS)
$(LINK.a) $@ $^
@$(RANLIB) $@ > /dev/null
@mkdir -p $(CDEVLIB)
@cp $@ $(CDEVLIB)
$(BASELIB)/libcdevReactor.$(SHARED_EXT) : $(OBJS)
$(LINK.so) -o $@ $^ $(NETLIBS)
@mkdir -p $(CDEVLIB)
@cp $@ $(CDEVLIB)

View File

@@ -0,0 +1,54 @@
.SUFFIXES: .cc .obj
ARCH = WINNT-4.0
SHOBJ = YES
APPNAME = CDEV Reactor Library
include ..\include\makeinclude\Makefile.WINNT-4.0
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
CXXEXTRA = /D "_CDEV_REACTOR_EXPORTS_=1"
# ******************************************************************************
# * The BINARIES definition names all of the binary files that should be deleted
# * whenever "make clean" is executed.
# ******************************************************************************
BINARIES = $(BASELIB)\cdevReactor.dll \
$(BASELIB)\cdevReactor.lib
# ******************************************************************************
# * The TARGETS variable is used to specify the name of the library to build.
# ******************************************************************************
!IF "$(SHOBJ)" == "YES"
TARGETS = $(CDEVLIB)\cdevReactor.dll
!ELSE
TARGETS = $(CDEVLIB)\cdevReactor.lib
!ENDIF
targets : $(TARGETS)
$(CDEVLIB)\cdevReactor.lib : $(OBJS)
@echo =^> Building $(@F)
@echo =^> Objects: $(?F)
-@if exist $@ erase $@
$(LIB32) $(LINK_LIB_FLAGS) /out:$@ $(OBJS)
@echo ^<= Done...
$(CDEVLIB)\cdevReactor.dll : $(OBJS)
@echo =^> Building $(@F)
@echo =^> Objects: $(?F)
-@if exist $@ erase $@
$(LIB32) $(LINK_DLL_FLAGS) /out:$@ /implib:$(@D)\$(@B).lib $(OBJS)
@echo ^<= Done...

View File

@@ -0,0 +1,129 @@
#include <cdevReactor.h>
#include <cdevSocketAcceptor.h>
#include <cdevBufferedSocket.cc>
#include "TestNode.h"
TestNode * TestNode::freeList = NULL;
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
cdevReactor GlobalReactor;
class ServerHandler : public cdevEventHandler, public cdevNodeFactory
{
private:
cdevBufferedSocket stream;
int count;
int inboundCount;
public:
ServerHandler ( const cdevAddr &addr )
: count(0), inboundCount(0), stream(0, 1, this)
{
open(addr);
}
int open ( const cdevAddr & addr )
{
int retval = -1;
if((retval = stream.connect(addr))==0)
{
retval = GlobalReactor.registerHandler(this, WRITE_MASK);
}
return retval;
}
int getHandle ( void ) const
{
return stream.getHandle();
}
void setHandle ( int handle )
{
stream.setHandle(handle);
}
cdevStreamNode * newNode ( ssize_t size )
{
TestNode * node = new TestNode;
node->setLen(size);
return node;
}
int handleInput ( void )
{
int retval = 0;
cdevStreamNode * node = NULL;
if((retval = stream.receive())>0)
{
while((node=stream.dequeueInbound())!=NULL)
{
if(((inboundCount++)%1000)==0) fprintf(stdout, "CLIENT: I received \"%s\"\n", node->getBuf());
delete node;
}
}
if(retval<0) setMask(DONT_CALL);
else if(!stream.inboundReady()) setMask(WRITE_MASK);
return retval>=0?0:-1;
}
int handleOutput ( void )
{
int retval = 0;
if(!stream.outboundReady())
{
for(int i=0; i<1000; i++)
{
TestNode * node = new TestNode;
node->setLen(sprintf(node->getBuf(), "Client Packet %i", count++)+1);
stream.enqueueOutbound(node);
}
setMask(WRITE_MASK);
}
retval=stream.transmit();
if(retval<0) setMask(DONT_CALL);
else if(!stream.outboundReady()) setMask(READ_MASK);
return retval>=0?0:-1;
}
int handleClose ( void )
{
stream.close();
return 0;
}
};
int main ( int argc, char * argv[], char * envp [] )
{
if(argc<3)
{
fprintf(stderr, "%s [host] [port]\n", "ClientTest1");
return -1;
}
char * host = argv[1];
short port = atoi(argv[2]);
cdevInetAddr serverAddr( port, host);
printf("Connecting to %s:%i\n", serverAddr.getHostName(),serverAddr.getPortNum());
ServerHandler * client = new ServerHandler(serverAddr);
for(int i=0; i<100; i++)
{
if(i%10==0) fprintf(stdout, "====> Have reached iteration %i\n", i);
GlobalReactor.handleEvents(1.0);
}
return 0;
}

View File

@@ -0,0 +1,17 @@
SHOBJ=NO
ARCH =OS
include ../../include/makeinclude/Makefile.$(ARCH)
APPNAME = "cdevReactor Client/Server Test"
CXXEXTRA = -I../
TARGETS = ServerTest1 ClientTest1
targets : $(TARGETS)
ServerTest1 : $(OBJDIR)/ServerTest1.o
$(LINK.cc) -o $@ $^ -L$(CDEVLIB) -lcdevReactor -lm
ClientTest1 : $(OBJDIR)/ClientTest1.o
$(LINK.cc) -o $@ $^ -L$(CDEVLIB) -lcdevReactor -lm

View File

@@ -0,0 +1,32 @@
.SUFFIXES: .cc .obj
ARCH = WINNT-4.0
include ..\..\include\makeinclude\Makefile.WINNT-4.0
BASEBIN = .
OBJDIR = .exec\WINNT-4.0
CXXINCLUDES = /I ..\
TARGETS = $(BASEBIN)\ServerTest1.exe $(BASEBIN)\ClientTest1.exe
targets : $(TARGETS)
$(BASEBIN)\ServerTest1.exe : .exec\$(TARGETDIR)\ServerTest1.obj
$(LINK) \
$(CDEVLIB)\cdevReactor.lib $(LINK_EXE_FLAGS) /out:$@ \
.exec\$(TARGETDIR)\ServerTest1.obj
$(BASEBIN)\ClientTest1.exe : .exec\$(TARGETDIR)\ClientTest1.obj
$(LINK) \
$(CDEVLIB)\cdevReactor.lib $(LINK_EXE_FLAGS) /out:$@ \
.exec\$(TARGETDIR)\ClientTest1.obj
purgeworkspace :
-@del *.dsp
-@del *.plg
-@del *.dsw
-@del *.ncb
-@del *.opt

View File

@@ -0,0 +1,176 @@
#include <cdevReactor.h>
#include <cdevSocketAcceptor.h>
#include <cdevBufferedSocket.cc>
#include "TestNode.h"
TestNode * TestNode::freeList = NULL;
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
cdevReactor GlobalReactor;
class ClientHandler : public cdevEventHandler, public cdevNodeFactory
{
friend class Acceptor;
private:
cdevBufferedSocket stream;
int inboundCount;
int count;
public:
ClientHandler ( void ) : count(0), inboundCount(0), stream(0, 1, this) {}
int open ( void )
{
return GlobalReactor.registerHandler(this, READ_MASK);
}
int getHandle ( void ) const
{
return stream.getHandle();
}
void setHandle ( int handle )
{
stream.setHandle(handle);
}
cdevStreamNode * newNode ( ssize_t size )
{
TestNode * node = new TestNode;
node->setLen(size);
return node;
}
int handleInput ( void )
{
int retval = 0;
cdevStreamNode * node = NULL;
if((retval = stream.receive())>0)
{
while((node=stream.dequeueInbound())!=NULL)
{
if(((inboundCount++)%1000)==0) fprintf(stdout, "SERVER: I received \"%s\"\n", node->getBuf());
delete node;
}
}
if(!stream.inboundReady())
{
for(int i=0; i<1000; i++)
{
TestNode * node = new TestNode;
node->setLen(sprintf(node->getBuf(), "Server Packet %i", count++)+1);
stream.enqueueOutbound(node);
}
setMask(READ_MASK|WRITE_MASK);
}
if(retval<0) setMask(DONT_CALL);
return retval>=0?0:-1;
}
int handleOutput ( void )
{
int retval = 0;
retval=stream.transmit();
if(retval<0) setMask(DONT_CALL);
else if(!stream.outboundReady()) setMask(READ_MASK);
return retval>=0?0:-1;
}
int handleClose ( void )
{
fprintf(stdout, "Closing connection to host\n");
stream.close();
return 0;
}
};
class Acceptor : public cdevEventHandler
{
public:
Acceptor ( const cdevAddr &addr )
{
open(addr);
GlobalReactor.registerHandler(this, READ_MASK);
}
int open ( const cdevAddr &addr )
{
int result = -1;
if (acceptor.open (addr, TRUE) == -1)
{
fprintf(stdout, "Acceptor [ERROR]: Failed to open listening port");
}
else if (acceptor.setFlags (O_NONBLOCK) == -1)
{
fprintf(stdout, "Acceptor [ERROR]: Could not enable non-blocking I/O");
}
else result = 0;
return result;
}
int getHandle ( void ) const
{
return acceptor.getHandle();
}
void setHandle ( int handle )
{
acceptor.setHandle(handle);
}
int handleInput ( void )
{
cdevInetAddr addr;
ClientHandler * handler = new ClientHandler;
if(acceptor.accept(handler->stream, &addr)!=-1)
{
fprintf(stdout, "Received connection from host %s\n", addr.getHostName());
handler->open();
}
return 0;
}
int handleClose ( void )
{
acceptor.close();
return 0;
}
private:
cdevSocketAcceptor acceptor;
};
int main (int argc, char * argv[], char * envp[])
{
if(argc<2)
{
fprintf(stderr, "%s [port]\n", argv[0]);
return -1;
}
short port = atoi(argv[1]);
cdevInetAddr acceptAddr(port, (long)INADDR_ANY);
Acceptor * acceptor = new Acceptor(acceptAddr);
for(int i=0; i<100; i++)
{
if(i%10==0) fprintf(stdout, "====> Have reached iteration %i\n", i);
GlobalReactor.handleEvents(1.0);
}
return 0;
}

View File

@@ -0,0 +1,48 @@
#include <cdevStreamQueue.h>
class TestNode : public cdevStreamNode
{
private:
static TestNode * freeList;
TestNode * freeListNext;
char buf[75];
size_t len;
public:
TestNode ( void )
: len(0), freeListNext(NULL)
{
}
size_t getLen ( void ) const { return len; }
void setLen ( size_t size ) { len = size; }
char * getBuf ( void ) const { return (char *)buf; }
void setBuf ( char * buffer, size_t size)
{
strcpy(buf, buffer);
len = size;
}
void * operator new ( size_t )
{
TestNode * node;
if(freeList==NULL)
{
freeList = ::new TestNode[1000];
for(int i=0; i<999; i++)
{
freeList[i].freeListNext = &freeList[i+1];
}
}
node = freeList;
freeList = node->freeListNext;
return node;
}
void operator delete ( void * ptr )
{
TestNode * node = (TestNode *)ptr;
node->freeListNext = freeList;
freeList = node;
}
};

View File

@@ -0,0 +1,17 @@
SHOBJ=NO
ARCH =OS
include ../../include/makeinclude/Makefile.$(ARCH)
APPNAME = "cdevReactor Timer Test"
TARGETS = TimerTest1 TimerTest2
CXXEXTRA = -I../
targets : $(TARGETS)
TimerTest1 : $(OBJDIR)/TimerTest1.o
$(LINK.cc) -o $@ $^ -L$(CDEVLIB) -lcdevReactor -lm
TimerTest2 : $(OBJDIR)/TimerTest2.o
$(LINK.cc) -o $@ $^ -L$(CDEVLIB) -lcdevReactor -lm

View File

@@ -0,0 +1,24 @@
.SUFFIXES: .cc .obj
ARCH = WINNT-4.0
include ..\..\include\makeinclude\Makefile.WINNT-4.0
BASEBIN = .
OBJDIR = .exec\WINNT-4.0
CXXINCLUDES = /I ..\
TARGETS = $(BASEBIN)\TimerTest1.exe $(BASEBIN)\TimerTest2.exe
targets : $(TARGETS)
$(BASEBIN)\TimerTest1.exe : .exec\$(TARGETDIR)\TimerTest1.obj
$(LINK) \
$(CDEVLIB)\cdevReactor.lib $(LINK_EXE_FLAGS) /out:$@ \
.exec\$(TARGETDIR)\TimerTest1.obj
$(BASEBIN)\TimerTest2.exe : .exec\$(TARGETDIR)\TimerTest2.obj
$(LINK) \
$(CDEVLIB)\cdevReactor.lib $(LINK_EXE_FLAGS) /out:$@ \
.exec\$(TARGETDIR)\TimerTest2.obj

View File

@@ -0,0 +1,28 @@
#include <cdevReactor.h>
#include <stdio.h>
class simpleAcceptor : public cdevEventHandler
{
}
class simpleServer : public cdevEventHandler
{
public:
int handleOpen ( void )
{
}
int handleInput ( void )
{
char block[1024];
}
};
int main ()
{
cdevReactor reactor;
simpleTimer timer;
reactor.registerTimer(&timer);
for(int i=0; i<10; i++) reactor.handleEvents();
}

View File

@@ -0,0 +1,27 @@
#include <cdevReactor.h>
#include <stdio.h>
class simpleTimer : public cdevEventHandler
{
public:
simpleTimer ( void )
{
setTimeoutRate(1.0);
}
int handleTimeout ( void )
{
fprintf(stdout, ".");
fflush(stdout);
return 0;
}
};
int main ()
{
cdevReactor reactor;
simpleTimer timer;
reactor.registerTimer(&timer);
for(int i=0; i<10; i++) reactor.handleEvents();
return 0;
}

View File

@@ -0,0 +1,48 @@
#include <cdevReactor.h>
#include <stdlib.h>
#include <stdio.h>
class simpleTimer : public cdevEventHandler
{
private:
char c;
public:
simpleTimer ( char outputChar='.', double timeout=1.0 )
: c(outputChar)
{
setTimeoutRate(timeout);
}
int handleTimeout ( void )
{
fprintf(stdout, "%c", c);
fflush(stdout);
return 0;
}
};
int main (int argc, char ** argv)
{
int iterations = 100;
cdevReactor reactor;
simpleTimer timer1('.', 1.0);
simpleTimer timer2('-', 0.5);
simpleTimer timer3(',', 10.0);
simpleTimer timer4('+', 0.25);
simpleTimer timer5('-', 0.05);
if(argc>1) iterations = atoi(argv[1]);
if(iterations<=0) iterations=100;
fprintf(stdout, "Processing for %i iterations\n", iterations);
reactor.registerTimer(&timer1);
reactor.registerTimer(&timer2);
reactor.registerTimer(&timer3);
reactor.registerTimer(&timer4);
reactor.registerTimer(&timer5);
for(int i=0; i<iterations; i++) reactor.handleEvents();
return 0;
}

View File

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

View File

@@ -0,0 +1,48 @@
#ifndef _CDEV_ADDR_H_
#define _CDEV_ADDR_H_
#include "cdevPlatforms.h"
class CDEV_REACTOR_API cdevAddr
{
protected:
int addr_type;
int addr_size;
public:
cdevAddr ( void ) : addr_type(0), addr_size(0) {}
cdevAddr ( int type, int size ) : addr_type(type), addr_size(size) {}
int getSize ( void ) const { return addr_size; }
void setSize ( int size ) { addr_size = size; }
int getType ( void ) const { return addr_type; }
void setType ( int type ) { addr_type = type; }
virtual void * getAddress ( void ) const { return NULL; }
};
class CDEV_REACTOR_API cdevInetAddr : public cdevAddr
{
protected:
sockaddr_in inet_addr;
public:
cdevInetAddr (void);
cdevInetAddr (const cdevInetAddr & addr);
cdevInetAddr (const sockaddr_in *, int len);
cdevInetAddr (unsigned short portnum, char hostname[]);
cdevInetAddr (unsigned short portnum, long ip_addr=INADDR_ANY);
int set (unsigned short portnum, const char hostname[]);
int set (unsigned short portnum, long ip_addr=INADDR_ANY);
int set (const sockaddr_in *, int len);
const char * getHostName ( void ) const;
const char * getHostAddr ( void ) const;
unsigned long getInetAddr ( void ) const;
unsigned short getPortNum ( void ) const;
void * getAddress ( void ) const;
};
#endif

View File

@@ -0,0 +1,256 @@
#include "cdevBufferedSocket.h"
// *****************************************************************************
// * cdevBufferedSocket::sigPipeHandler :
// * This is a default signal pipe handler.
// *****************************************************************************
void cdevBufferedSocket::sigPipeHandler ( int )
{
}
// *****************************************************************************
// * cdevBufferedSocket::newNode :
// * This method will return a pointer to a cdevSimpleStreamNode. This
// * node will then be populated with data that is read from the socket.
// *****************************************************************************
cdevStreamNode * cdevBufferedSocket::newNode ( ssize_t size )
{
cdevSimpleStreamNode * ptr = NULL;
if(size>0) ptr = new cdevSimpleStreamNode(new char[size], size);
return ptr;
}
// *****************************************************************************
// * cdevBufferedSocket::transmit :
// * This method will attempt to transmit as many packets as immediately
// * possible from the activeOut cdevStreamQueue. The function will cease
// * transmitting when the queue is empty or when the receiver is fails
// * to accept data after a pre-specified number of retries.
// *****************************************************************************
ssize_t cdevBufferedSocket::transmit ( void )
{
int totalSent = 0;
int parm = 0;
int retval = 0;
int retries = 0;
#ifndef WIN32
void (*oldSig)(int) = signal(SIGPIPE, sigPipeHandler);
#endif
setOption(IPPROTO_TCP, TCP_NODELAY, &parm, sizeof(parm));
if(activeOut.isEmpty())
{
if(!waitingOut.isEmpty())
{
activeOut.enqueue(waitingOut);
headerXfrLen = 0;
dataXfrLen = 0;
outboundHeader[0] = htonl(magicNumber);
outboundHeader[1] = htonl(activeOut.getSize()+sizeof(size_t));
outboundHeader[2] = htonl(activeOut.getCount());
}
else return 0;
}
while(headerXfrLen<12 && retries<RETRYCNT && retval>=0)
{
retval = send(((char *)outboundHeader)+headerXfrLen, 12-headerXfrLen);
if(retval>=0)
{
retries = retval?0:retries+1;
headerXfrLen += retval;
totalSent += retval;
}
}
while(headerXfrLen>=12 && retries<RETRYCNT && retval>=0 && !activeOut.isEmpty())
{
cdevStreamNode * node = activeOut.dequeue();
while(dataXfrLen<4 && retries<RETRYCNT && retval>=0)
{
parm = htonl(node->getLen());
retval = send(((char *)&parm)+dataXfrLen, 4-dataXfrLen);
if(retval>=0)
{
retries = retval?0:retries+1;
dataXfrLen += retval;
totalSent += retval;
}
}
while(dataXfrLen>=4 && dataXfrLen<node->getLen()+4 && retries<RETRYCNT && retval>=0)
{
retval = send(node->getBuf()+(dataXfrLen-4), node->getLen()-(dataXfrLen-4));
if(retval>=0)
{
retries = retval?0:retries+1;
dataXfrLen += retval;
totalSent += retval;
}
}
if(dataXfrLen<node->getLen()+4) activeOut.poke(node);
else {
if(deleteFlag) delete node;
dataXfrLen = 0;
}
}
parm = 1;
setOption(IPPROTO_TCP, TCP_NODELAY, &parm, sizeof(parm));
#ifndef WIN32
signal(SIGPIPE, oldSig);
#endif
return retval>=0?totalSent:-1;
}
// *****************************************************************************
// * cdevBufferedSocket::receive :
// * This method will attempt to receive as many packets as immediately
// * possible from the socket into the waitingIn cdevStreamQueue. The
// * function will cease receiving when a complete transmission block
// * (multiple packets) have been received or when the sender has failed
// * to transmit data after a pre-specified number of retries.
// *****************************************************************************
ssize_t cdevBufferedSocket::receive ( void )
{
int totalRecv = 0;
int parm = 0;
int retval = 0;
int retries = 0;
size_t packetCnt = 0;
while(headerRcvLen<12 && retries<RETRYCNT && retval>=0)
{
if((retval = recv(((char *)inboundHeader)+headerRcvLen, 12-headerRcvLen))==0)
{
int errCode = GetSocketErrno();
if(errCode!=EWOULDBLOCK && errCode!=EAGAIN) retval = -1;
else retries++;
}
else if(retval>=0)
{
retries = retval?0:retries+1;
headerRcvLen += retval;
totalRecv += retval;
}
if(headerRcvLen>=12)
{
inboundHeader[0] = ntohl(inboundHeader[0]);
inboundHeader[1] = ntohl(inboundHeader[1]);
inboundHeader[2] = ntohl(inboundHeader[2]);
if(inboundHeader[0]!=magicNumber) retval=-1;
}
}
while(headerRcvLen>=12 && retries<RETRYCNT && retval>=0 &&
inboundHeader[1]>0 && inboundHeader[2]>0)
{
while(dataRcvLen<4 && retries<RETRYCNT && retval>=0)
{
if((retval = recv(((char *)&subPacketLen)+dataRcvLen, 4-dataRcvLen))==0)
{
int errCode = GetSocketErrno();
if(errCode!=EWOULDBLOCK && errCode!=EAGAIN) retval = -1;
else retries++;
}
else if(retval>0)
{
retries = 0;
dataRcvLen += retval;
totalRecv += retval;
inboundHeader[1]-=retval;
}
if(dataRcvLen>=4)
{
subPacketLen = ntohl(subPacketLen);
rcvNode = nodeFactory->newNode(subPacketLen);
memset(rcvNode->getBuf(), rcvNode->getLen(), 0);
}
}
while(dataRcvLen>=4 && dataRcvLen<rcvNode->getLen()+4 && retries<RETRYCNT && retval>=0)
{
if((retval = recv(rcvNode->getBuf()+(dataRcvLen-4), rcvNode->getLen()-(dataRcvLen-4)))==0)
{
int errCode = GetSocketErrno();
if(errCode!=EWOULDBLOCK && errCode!=EAGAIN) retval = -1;
else retries++;
}
else if(retval>=0)
{
retries = 0;
dataRcvLen += retval;
totalRecv += retval;
inboundHeader[1]-=retval;
}
if(dataRcvLen>=(rcvNode->getLen()+4))
{
waitingIn.enqueue(rcvNode);
rcvNode = NULL;
dataRcvLen = 0;
subPacketLen = 0;
inboundHeader[2]--;
}
}
if(inboundHeader[1]<=0 || inboundHeader[2]<=0)
{
if(rcvNode) // Only received a partial packet on final entry
{
delete rcvNode;
rcvNode = NULL;
retval = -1;
}
headerRcvLen = 0;
dataRcvLen = 0;
inboundHeader[0]=(inboundHeader[1]=(inboundHeader[2]=0));
}
}
return retval>=0?totalRecv:-1;
}
// *****************************************************************************
// * cdevBufferedSocket::getBlockingSemantics :
// * Identifies the cdevBufferedSocket object as a NON-BLOCKING entity.
// *****************************************************************************
int cdevBufferedSocket::getBlockingSemantics ( void ) const
{
return O_NONBLOCK;
}
// *****************************************************************************
// * cdevBufferedSocket::getRcvBufferSize :
// * This method is called during the configureHandle method to obtain the
// * size of the receive buffer that will be used by the socket. This class
// * returns the value 56000 - telling the cdevSocketStream to set the
// * receive buffer size to 56 kilobytes.
// *****************************************************************************
int cdevBufferedSocket::getRcvBufferSize ( void ) const
{
return 56000;
}
// *****************************************************************************
// * cdevBufferedSocket::getSndBufferSize :
// * This method is called during the configureHandle method to obtain the
// * size of the send buffer that will be used by the socket. This class
// * returns the value 56000 - telling the cdevSocketStream to set the
// * send buffer size to 56 kilobytes.
// *****************************************************************************
int cdevBufferedSocket::getSndBufferSize ( void ) const
{
return 56000;
}

View File

@@ -0,0 +1,114 @@
#ifndef _CDEV_BUFFERED_SOCKET_H_
#define _CDEV_BUFFERED_SOCKET_H_
#include "cdevSocketConnector.h"
#include "cdevStreamQueue.h"
class cdevBufferedSocket : public cdevSocketConnector, public cdevNodeFactory
{
private:
cdevNodeFactory * nodeFactory;
int magicNumber;
int deleteFlag;
cdevStreamQueue activeOut;
cdevStreamQueue waitingOut;
int outboundHeader[3];
size_t headerXfrLen;
size_t dataXfrLen;
cdevStreamQueue waitingIn;
cdevStreamNode * rcvNode;
int inboundHeader[3];
size_t headerRcvLen;
size_t dataRcvLen;
size_t subPacketLen;
static void sigPipeHandler (int);
public:
enum {RETRYCNT = 1000 };
inline cdevBufferedSocket ( int MagicNumber=0, int deleteNodes = 1, cdevNodeFactory * factory=NULL );
inline int outboundReady ( void );
inline int inboundReady ( void );
inline void enqueueOutbound ( cdevStreamNode * node );
inline cdevStreamNode * dequeueInbound ( void );
cdevStreamNode * newNode ( ssize_t size );
ssize_t transmit ( void );
ssize_t receive ( void );
int getBlockingSemantics ( void ) const;
int getRcvBufferSize ( void ) const;
int getSndBufferSize ( void ) const;
};
// *****************************************************************************
// * cdevBufferedSocket::cdevBufferedSocket :
// * This is the constructor for the cdevBufferedSocket, it will initialize
// * all internal variables and sub-classes.
// *****************************************************************************
inline cdevBufferedSocket::cdevBufferedSocket ( int MagicNumber, int deleteNodes, cdevNodeFactory * factory )
: nodeFactory(factory),
magicNumber(MagicNumber),
deleteFlag (deleteNodes),
activeOut(deleteNodes),
waitingOut(deleteNodes),
headerXfrLen(0),
dataXfrLen(0),
waitingIn(),
rcvNode(NULL),
headerRcvLen(0),
dataRcvLen(0),
subPacketLen(0)
{
if(nodeFactory==NULL) nodeFactory=this;
}
// *****************************************************************************
// * cdevBufferedSocket::outboundReady :
// * This method returns an integer value indicating that outbound data is
// * ready for transmission.
// *****************************************************************************
inline int cdevBufferedSocket::outboundReady ( void )
{
return !(activeOut.isEmpty() && waitingOut.isEmpty());
}
// *****************************************************************************
// * cdevBufferedSocket::inboundReady :
// * This method returns a flag indicating that inbound data is ready to be
// * dequeued and processed.
// *****************************************************************************
inline int cdevBufferedSocket::inboundReady ( void )
{
return !(waitingIn.isEmpty() && headerRcvLen==0);
}
// *****************************************************************************
// * cdevBufferedSocket::enqueueOutbound :
// * This method places the user defined cdevStreamNode pointer into the
// * waitingOut object.
// *****************************************************************************
inline void cdevBufferedSocket::enqueueOutbound ( cdevStreamNode * node )
{
waitingOut.enqueue(node);
}
// *****************************************************************************
// * cdevBufferedSocket::dequeueInbound :
// * This method dequeues the next available cdevStreamNode object from the
// * waitingIn object.
// *****************************************************************************
inline cdevStreamNode * cdevBufferedSocket::dequeueInbound ( void )
{
return waitingIn.dequeue();
}
#endif /* _CDEV_BUFFERED_SOCKET_H_ */

View File

@@ -0,0 +1,96 @@
#include "cdevReactor.h"
#include "cdevEventHandler.h"
#include <math.h>
cdevEventHandler::cdevEventHandler ( void )
: mask(0),
next(NULL),
timeoutRate(0, 0),
nextTimeout(0, 0),
reactor(NULL)
{
}
cdevEventHandler::~cdevEventHandler ( void )
{
if(reactor!=NULL) reactor->extractHandler(this);
handleClose();
}
void cdevEventHandler::setHandle ( int )
{
}
int cdevEventHandler::getHandle ( void ) const
{
return -1;
}
void cdevEventHandler::setReactor (cdevReactor * r)
{
reactor = r;
}
cdevEventHandler * cdevEventHandler::getNext (void )
{
return next;
}
void cdevEventHandler::setNext (cdevEventHandler * n)
{
next = n;
}
int cdevEventHandler::getMask ( void )
{
return mask;
}
cdevReactor * cdevEventHandler::getReactor ( void )
{
return reactor;
}
cdevTime & cdevEventHandler::getTimeoutRate ( void )
{
return timeoutRate;
}
cdevTime & cdevEventHandler::getNextTimeout ( void )
{
return nextTimeout;
}
void cdevEventHandler::setMask ( unsigned Mask )
{
mask = (Mask&(READ_MASK|WRITE_MASK|EXCEPT_MASK|DONT_CALL));
}
void cdevEventHandler::setTimeoutRate ( cdevTime time )
{
timeoutRate = time;
resetTimer();
}
void cdevEventHandler::resetTimer ( void )
{
nextTimeout.setTime();
nextTimeout = nextTimeout+getTimeoutRate();
}
int cdevEventHandler::handleInput ( void ) { return 0; }
int cdevEventHandler::handleOutput ( void ) { return 0; }
int cdevEventHandler::handleExcept ( void ) { return 0; }
int cdevEventHandler::handleTimeout ( void ) { return 0; }
int cdevEventHandler::handleSignal ( void ) { return -1; }
int cdevEventHandler::handleClose ( void ) { return 0; }

View File

@@ -0,0 +1,54 @@
#ifndef _CDEV_EVENT_HANDLER_H_
#define _CDEV_EVENT_HANDLER_H_ 1
#include "cdevTime.h"
class CDEV_REACTOR_API cdevEventHandler
{
friend class cdevReactor;
public:
enum {
READ_MASK = 0x01,
EXCEPT_MASK = 0x02,
WRITE_MASK = 0x04,
DONT_CALL = 0x100
} REACTOR_MASK;
private:
void setReactor (cdevReactor * r);
cdevEventHandler * getNext (void );
void setNext (cdevEventHandler * n);
cdevTime & getNextTimeout (void);
protected:
cdevEventHandler * next;
cdevTime nextTimeout;
cdevReactor * reactor;
cdevTime timeoutRate;
int mask;
public:
cdevEventHandler ( void );
virtual ~cdevEventHandler ( void );
virtual void setMask ( unsigned Mask );
virtual void setHandle ( int handle );
virtual int getHandle ( void ) const;
virtual int getMask ( void );
virtual cdevReactor * getReactor ( void );
virtual cdevTime & getTimeoutRate ( void );
virtual void setTimeoutRate ( cdevTime time );
virtual void resetTimer ( void );
virtual int handleInput ( void );
virtual int handleOutput ( void );
virtual int handleExcept ( void );
virtual int handleTimeout ( void );
virtual int handleSignal ( void );
virtual int handleClose ( void );
};
#endif

View File

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

View File

@@ -0,0 +1,87 @@
//-----------------------------------------------------------------------------
// 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:
// File Descriptor Mask Class (Based On ACE Handler_Set)
#ifndef _CDEV_HANDLE_SET_H_
#define _CDEV_HANDLE_SET_H_
#include <stdio.h>
#include <string.h>
#include "cdevPlatforms.h"
class CDEV_REACTOR_API cdevHandleSet
{
friend class cdevHandleSetIterator;
friend class cdevReactor;
public:
cdevHandleSet (void);
cdevHandleSet (const fd_set &mask);
void reset (void);
int is_set (int) const;
void set_bit (int);
void clr_bit (int);
int num_set (void) const;
int max_set (void) const;
int asciiDump (FILE * fp = stdout);
void sync (int max = FD_SETSIZE);
operator fd_set *( void ) { return &mask_; }
private:
int size_;
int max_handle_;
fd_set mask_;
enum {
#ifdef _WIN32
MAX_SIZE = FD_SETSIZE,
#else
MAX_SIZE = NOFILE,
WORD_SIZE = NFDBITS,
NUM_WORDS = howmany (NOFILE, NFDBITS),
#ifdef __DECCXX
MSB_MASK = ~(1U << (NFDBITS - 1))
#elif defined(CDEV_HAS_64BIT_LONGS)
MSB_MASK = ~(1UL << (NFDBITS - 1))
#else
MSB_MASK = ~(1 << (NFDBITS - 1))
#endif
#endif
};
int count_bits (unsigned long n) const;
void set_max (int max);
static const char nbits_[256];
};
class CDEV_REACTOR_API cdevHandleSetIterator
{
public:
cdevHandleSetIterator (cdevHandleSet &);
int operator ()(void);
void operator++ (void);
private:
cdevHandleSet &fds_;
int num_;
#ifdef _WIN32
unsigned int index_;
#else
int index_;
fd_mask val_;
#endif
};
#endif /* _CDEV_HANDLE_SET_H_ */

View File

@@ -0,0 +1,585 @@
#include <stdio.h>
#include <string.h>
#include "cdevReactor.h"
// *****************************************************************************
// * This is the number of times that InitializeNetwork was called to perform
// * network initialization. The InitializeNetwork and corresponding
// * TerminateNetwork methods are wrappers to provide support for WIN32
// * WSAStartup and WSACleanup methods. They perform no actiual function on
// * UNIX platforms.
// *****************************************************************************
int cdevReactor::netInitCount = 0;
// *****************************************************************************
// * cdevReactor::cdevReactor :
// * This is the constructor for the cdevReactor class. It takes no
// * arguments. It will set maxEntries to the value of the MAX_SIZE
// * variable and the size variable (the highest fd installed) will be set
// * to zero.
// *
// * The method will allocate space in the handlers array for the
// * cdevEventHandlers that will be installed during operation. The
// * read_set, write_set and except_set masks will be cleared. These masks
// * will be populated later as file descriptors are added to the
// * cdevReactor.
// *****************************************************************************
cdevReactor::cdevReactor ( void )
: maxEntries(cdevHandleSet::MAX_SIZE),
size (0),
handlers (NULL),
timers (NULL)
{
if(!netInitCount)
{
if(InitializeNetwork()==0) netInitCount++;
}
else netInitCount++;
handlers = (cdevEventHandler **)malloc((maxEntries+1)*sizeof(cdevEventHandler *));
memset(handlers, 0, sizeof(cdevEventHandler *)*(maxEntries+1));
read_set.reset();
write_set.reset();
except_set.reset();
}
// *****************************************************************************
// * cdevReactor::~cdevReactor :
// * This is the destructor for the cdevReactor class. It wil first remove
// * all of the timer cdevEventHandlers from the timer array, it will then
// * remove all of the file-descriptor based cdevEventHandlers from the
// * handlers array. It will finish by deleteing the handlers array that
// * was allocated in the constructor.
// *****************************************************************************
cdevReactor::~cdevReactor ( void )
{
if(netInitCount && (-netInitCount)==0) TerminateNetwork();
while(timers!=NULL) removeHandler(timers);
for(int i=0; i<=maxEntries; i++)
{
if(handlers[i]!=NULL) removeHandler(handlers[i]);
}
delete handlers;
}
// *****************************************************************************
// * cdevReactor::calculateMask :
// * This method will walk through the handlers array and setup the read_set,
// * write_set and except_set masks.
// *****************************************************************************
void cdevReactor::calculateMask ( void )
{
int i;
read_set.reset();
write_set.reset();
except_set.reset();
size = 0;
for(i=0; i<=maxEntries; i++)
{
unsigned mask;
if(handlers[i]!=NULL)
{
mask = handlers[i]->getMask();
if(!(mask&cdevEventHandler::DONT_CALL))
{
if(mask&cdevEventHandler::READ_MASK)
{
read_set.set_bit(i);
size = i+1;
}
if(mask&cdevEventHandler::WRITE_MASK)
{
write_set.set_bit(i);
size = i+1;
}
if(mask&cdevEventHandler::EXCEPT_MASK)
{
except_set.set_bit(i);
size = i+1;
}
}
}
}
}
// *****************************************************************************
// * cdevReactor::calculateTimeout :
// * This method will walk through the timers and determine the duration of
// * time that the cdevReactor should wait for events on the file
// * descriptors before automatically terminating.
// *****************************************************************************
int cdevReactor::calculateTimeout ( cdevTime defaultPeriod, struct timeval &timeout )
{
if(defaultPeriod==cdevTime(0,0)) timeout.tv_sec=(timeout.tv_usec=0);
else {
cdevTime now;
cdevTime target;
cdevEventHandler * timer;
if(defaultPeriod<cdevTime(0,0)) defaultPeriod.setTime(60, 0);
now.setTime();
target.setTime(now+defaultPeriod);
for(timer=timers; timer!=NULL && target>now; timer=timer->getNext())
{
cdevTime nextTimeout = timer->getNextTimeout();
if(!(timer->getMask()&cdevEventHandler::DONT_CALL) &&
(double)nextTimeout > 0.0)
{
if(nextTimeout<target) target = nextTimeout;
}
}
if(target<=now) timeout.tv_sec=(timeout.tv_usec=0);
else timeout=target-now+(cdevTime)0.01;
}
return SUCCESS;
}
// *****************************************************************************
// * cdevReactor::checkHandlers :
// * This method is used to remove any cdevEventHandlers that have dead
// * sockets from the cdevReactor prior to beginning I/O operations. The
// * method calls select with all of the file handles installed. If select
// * returns a -1, then each of the file handles is checked independently.
// * When the bad handler is identified, its cdevEventHandler object will
// * be elliminated.
// * This method returns the number of cdevEventHandlers that were deleted.
// *****************************************************************************
int cdevReactor::checkHandlers ( void )
{
int i;
int eventCnt = 0;
struct timeval t;
read_set.reset();
write_set.reset();
except_set.reset();
t.tv_sec = 0;
t.tv_usec = 0;
for(i=0; i<maxEntries; i++)
{
if(handlers[i]!=NULL)
{
read_set.set_bit(i);
size = i+1;
}
}
if(cdevSelect(size, read_set, write_set, except_set, &t)<0)
{
for(i=0; i<maxEntries; i++)
{
if(handlers[i]!=NULL)
{
read_set.set_bit(i);
if(cdevSelect(i, read_set, write_set, except_set, &t)<0)
{
if(handlers[i]->handleSignal()<0)
{
removeHandler(handlers[i]);
eventCnt++;
}
}
read_set.clr_bit(i);
}
}
}
return eventCnt;
}
// *****************************************************************************
// * cdevReactor::registerHandler :
// * This method is called to register a file-descriptor based
// * cdevEventHandler with the reactor. It will first check the validity
// * of the handler and its file descriptor. It will then determine if
// * another handler already occupies the position associated with the
// * specified handle.
// *
// * If the handler is valid, it will install it in the handlers array and
// * will add it to the read_set, write_set and except_set masks as
// * required. The size variable will be incremented if the new handler
// * has the highest file-descriptor in the array.
// *****************************************************************************
int cdevReactor::registerHandler ( cdevEventHandler * handler, unsigned mask )
{
int fd = -1;
REACTOR_RESULT result = SUCCESS;
if(handler == NULL)
{
result = INVALID_HANDLER;
}
else if(handler->getReactor()!=NULL && handler->getReactor()!=this)
{
result = UNKNOWN_HANDLER;
}
else if((fd = handler->getHandle())<=0)
{
result = INVALID_HANDLE;
}
else if(fd<maxEntries && handlers[handler->getHandle()]!=NULL)
{
result = HANDLE_EXISTS;
}
else {
if(fd>=maxEntries)
{
int oldMaxEntries = maxEntries;
maxEntries = fd+1;
handlers = (cdevEventHandler **)realloc(handlers, (maxEntries+1) * sizeof(cdevEventHandler *));
memset(&handlers[oldMaxEntries], 0, sizeof(cdevEventHandler *)*((maxEntries+1)-oldMaxEntries));
}
handler->setReactor(this);
handler->setMask (mask);
handlers[fd] = handler;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::removeHandler :
// * This method allows the caller to remove an cdevEventHandler from the
// * cdevReactor and delete it. The method will call the extractHandler
// * method to remove the cdevEventHandler from the cdevReactor after which
// * the handler will be deleted.
// *****************************************************************************
int cdevReactor::removeHandler ( cdevEventHandler * handler )
{
REACTOR_RESULT result = INVALID_HANDLER;
if(handler!=NULL)
{
extractHandler(handler);
delete handler;
result = SUCCESS;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::removeHandler :
// * This method will remove the specified handler using the file descriptor
// * provided by the caller.
// *****************************************************************************
int cdevReactor::removeHandler ( int fd )
{
REACTOR_RESULT result = SUCCESS;
if(fd>0 && fd<=maxEntries)
{
result = (REACTOR_RESULT)removeHandler(handlers[fd]);
}
else result = INVALID_HANDLE;
return (int) result;
}
// *****************************************************************************
// * cdevReactor::extractHandler :
// * This method will remove the specified cdevEventHandler from the
// * cdevReactor, however, it will not delete the cdevEventHandler when
// * finished.
// *****************************************************************************
int cdevReactor::extractHandler ( cdevEventHandler * handler )
{
int fd = -1;
REACTOR_RESULT result = UNKNOWN_HANDLER;
if(handler == NULL) result = INVALID_HANDLER;
else {
cdevEventHandler * currTimer = timers;
cdevEventHandler * prevTimer = NULL;
while(currTimer!=NULL && currTimer!=handler)
{
prevTimer = currTimer;
currTimer = prevTimer->getNext();
}
if(currTimer)
{
if(prevTimer) prevTimer->setNext(currTimer->getNext());
else timers = currTimer->getNext();
result = SUCCESS;
}
if((fd = handler->getHandle())>=0 &&
fd<=maxEntries &&
handlers[fd]==handler)
{
handlers[fd] = NULL;
result = SUCCESS;
}
else for(fd=0; fd<=maxEntries; fd++)
{
if(handlers[fd]==handler)
{
handlers[fd] = NULL;
result = SUCCESS;
}
}
if(result==SUCCESS)
{
handler->setMask(0);
handler->setReactor(NULL);
}
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::getHandler :
// * This method allows the caller to retrieve the cdevEventHandler
// * associated with a specific file descriptor.
// *****************************************************************************
int cdevReactor::getHandler ( int fd, cdevEventHandler * & handler )
{
REACTOR_RESULT result = SUCCESS;
handler = NULL;
if(fd<=0 || fd>maxEntries) result = INVALID_HANDLE;
else if((handler = handlers[fd])==NULL) result = INVALID_HANDLE;
return (int) result;
}
// *****************************************************************************
// * cdevReactor::registerTimer :
// * This method will install a timer cdevEventHandler in the timers array.
// * The handleTimeout method of this class will be called each time the
// * timer expires. The timer's handleTimeout method will be called
// * immediately, and then the timer will be set to expire at the next
// * time period.
// *****************************************************************************
int cdevReactor::registerTimer ( cdevEventHandler * timer )
{
REACTOR_RESULT result = SUCCESS;
if(timer==NULL)
{
result = INVALID_HANDLER;
}
else if(timer->getReactor()!=NULL && timer->getReactor()!=this)
{
result = UNKNOWN_HANDLER;
}
else if((double)timer->getTimeoutRate()<=0.0)
{
result = INVALID_TIMEOUT;
}
else {
timer->setReactor(this);
timer->resetTimer();
timer->setNext(timers);
timers = timer;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::cancelTimer :
// * This method will remove the timer from the array of timers that are
// * being serviced by the reactor, however, it will NOT delete the
// * cdevEventHandler. Additionally, if the handler is also being used
// * for file-descriptor based operations - it will be not be removed from
// * that array.
// *
// * The user is responsible for deleteing the cdevEventHandler if it will
// * no longer be needed.
// *****************************************************************************
int cdevReactor::cancelTimer ( cdevEventHandler * timer )
{
REACTOR_RESULT result = SUCCESS;
if(timer==NULL) result = INVALID_HANDLER;
else
{
cdevEventHandler * currTimer = timers;
cdevEventHandler * prevTimer = NULL;
while(currTimer!=NULL && currTimer!=timer)
{
prevTimer = currTimer;
currTimer = prevTimer->getNext();
}
if(currTimer)
{
if(prevTimer) prevTimer->setNext(currTimer->getNext());
else timers = currTimer->getNext();
currTimer->setNext(NULL);
}
else result = UNKNOWN_HANDLER;
}
return (int)result;
}
// *****************************************************************************
// * cdevReactor::handleFileEvent :
// * This method will process the events that have occurred on a single
// * file descriptor. The caller must provide two arguments...
// *
// * fd_set * fds : The fd_set to be checked
// * REACTOR_EVENT event : The type of event being processed...
// * INPUT, OUTPUT, EXCEPTION, or SIGNAL.
// *
// * This method will return the number of events that have been processed
// * to completion. Note that if a cdevEventHandler returns a value greater
// * than 0, it will be called again after all other ready file descriptors
// * have been called - therefore, its occurance will not be included in the
// * number of events returned by this method.
// *****************************************************************************
int cdevReactor::handleFileEvent ( cdevHandleSet * fds, REACTOR_EVENT event)
{
int result = 0;
int eventCnt = 0;
int i;
for(i=0; i<=size; i++)
{
if(fds->is_set(i))
{
if(handlers[i])
{
if(event==INPUT) result = handlers[i]->handleInput();
else if(event==OUTPUT) result = handlers[i]->handleOutput();
else if(event==EXCEPTION) result = handlers[i]->handleExcept();
else if(event==SIGNAL) result = handlers[i]->handleSignal();
if(result<=0)
{
if(result<0) removeHandler(handlers[i]);
eventCnt++;
fds->clr_bit(i);
}
}
else eventCnt++;
}
}
return eventCnt;
}
// *****************************************************************************
// * cdevReactor::handleEvents :
// * This method is called to allow the cdevReactor to wait for events to
// * occur on the cdevEventHandler objects. This method will process events
// * until the specified time period has expired - if a negative time period
// * (or no time period) has been specified, then it will process messages
// * until the next event occurs.
// *
// * The flags parameter was added to allow the caller to specify either
// * UNTIL_TIMEOUT or UNTIL_EVENT. If the caller specifies UNTIL_TIMEOUT,
// * the cdevReactor will continue to handle events until the time period
// * has expired. If the caller specifies UNTIL_EVENT, the cdevReactor will
// * return after the first SOCKET-BASED EVENT occurs or after the time
// * expires, whichever comes first.
// *
// * Note: If the cdevEventHandler may return a -1, 0, or 1. These return
// * codes will have the following effect.
// *
// * -1 : The cdevEventHandler will be removed from the cdevReactor
// * and deleted.
// * 0 : The bit associated with the cdevEventHandler will be
// * cleared and processing will continue.
// * 1 : The bit associated with the cdevEventHandler will not be
// * cleared and it will be called to process more data after
// * after all of the subsequent cdevEventHandlers have been
// * called - this allows the cdevEventHandler in a lengthy
// * process to yeild time back for processing other events.
// *****************************************************************************
int cdevReactor::handleEvents ( cdevTime period, int flags )
{
int result = 0;
int finished = 0;
cdevTime startTime, currTime;
struct timeval timeout;
startTime.setTime();
do
{
int i;
calculateMask ();
calculateTimeout(period, timeout);
result=cdevSelect(size, read_set, write_set, except_set, &timeout);
if(result<0)
{
finished = 1;
checkHandlers();
}
else {
if(result>0)
{
int cnt = 0;
while(cnt<result)
{
cnt+=handleFileEvent(&read_set, INPUT);
cnt+=handleFileEvent(&write_set, OUTPUT);
cnt+=handleFileEvent(&except_set, EXCEPTION);
}
if(flags==UNTIL_EVENT && cnt>0) finished = 1;
}
if(timers!=NULL)
{
cdevEventHandler * timer=timers;
currTime.setTime();
while(timer!=NULL)
{
cdevTime nextTimeout = timer->getNextTimeout();
if((timer->getMask()&cdevEventHandler::DONT_CALL)==0 &&
(double)nextTimeout>0.0 && nextTimeout<=currTime)
{
if(timer->handleTimeout()<0)
{
cdevEventHandler *temp = timer->getNext();
removeHandler(timer);
timer = temp;
}
else
{
timer->resetTimer();
timer = timer->getNext();
}
currTime.setTime();
}
else timer = timer->getNext();
}
}
}
currTime.setTime();
period = period-(currTime-startTime);
} while(!finished && period>cdevTime(0,0));
return result;
}

View File

@@ -0,0 +1,65 @@
#ifndef _CDEV_REACTOR_H_
#define _CDEV_REACTOR_H_ 1
#include "cdevTime.h"
#include "cdevHandleSet.h"
#include "cdevEventHandler.h"
class CDEV_REACTOR_API cdevReactor
{
public:
typedef enum {
INPUT = 0,
OUTPUT = 1,
EXCEPTION = 2,
SIGNAL = 3
} REACTOR_EVENT;
typedef enum {
REACTOR_ERROR = -1,
SUCCESS = 0,
INVALID_HANDLE = 1,
INVALID_HANDLER = 2,
HANDLE_EXISTS = 3,
UNKNOWN_HANDLER = 4,
INVALID_TIMEOUT = 5
} REACTOR_RESULT;
typedef enum {
UNTIL_TIMEOUT = 0,
UNTIL_EVENT = 1
} HANDLE_EVENT_FLAG;
protected:
static int netInitCount;
int maxEntries;
int size;
cdevHandleSet read_set;
cdevHandleSet write_set;
cdevHandleSet except_set;
cdevEventHandler ** handlers;
cdevEventHandler * timers;
private:
void calculateMask ( void );
int calculateTimeout ( cdevTime defaultPeriod, struct timeval &timeout );
int handleFileEvent ( cdevHandleSet * fds, REACTOR_EVENT event);
public:
cdevReactor ( void );
virtual ~cdevReactor ( void );
virtual int checkHandlers ( void );
virtual int registerHandler ( cdevEventHandler * handler, unsigned mask );
virtual int removeHandler ( cdevEventHandler * handler );
virtual int removeHandler ( int fd );
virtual int extractHandler ( cdevEventHandler * handler );
virtual int getHandler ( int fd, cdevEventHandler * &handler );
virtual int registerTimer ( cdevEventHandler * timer );
virtual int cancelTimer ( cdevEventHandler * timer );
virtual int handleEvents ( cdevTime period = -1.0, int flags = UNTIL_TIMEOUT );
};
#endif

View File

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

View File

@@ -0,0 +1,34 @@
#ifndef _CDEV_SOCKET_H_
#define _CDEV_SOCKET_H_
#include <stdio.h>
#include <fcntl.h>
#include "cdevAddr.h"
class CDEV_REACTOR_API cdevSocket
{
protected:
int handle;
sockaddr_in sa;
cdevSocket(void);
cdevSocket(int type, int protocol_family, int protocol=0);
public:
enum {INVALID_HANDLE=-1};
void setHandle (int fd);
int getHandle (void) const;
int open (int type, int protocol_family, int protocol);
int close (void);
int unsetFlags (int flags);
int setFlags (int flags);
int getFlags (void);
int setOption (int level, int option, void *optval, int optlen) const;
int getOption (int level, int option, void *optval, int *optlen) const;
int getLocalAddress (cdevAddr & address);
int getRemoteAddress (cdevAddr & address);
};
#endif

View File

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

View File

@@ -0,0 +1,32 @@
#ifndef _CDEV_SOCKET_ACCEPTOR_H_
#define _CDEV_SOCKET_ACCEPTOR_H_
#include "cdevSocketStream.h"
class CDEV_REACTOR_API cdevSocketAcceptor : public cdevSocket
{
public:
cdevSocketAcceptor(void);
cdevSocketAcceptor(
const cdevAddr &addr,
int reuse_addr = 0,
int protocol_family = PF_INET,
int backlog = 5,
int protocol = 0);
int open(const cdevAddr &addr,
int reuse_addr = 0,
int protocol_family = PF_INET,
int backlog = 5,
int protocol = 0,
int reopen = 1);
int accept(
cdevSocketStream &new_stream,
cdevAddr *remote_addr=0) const;
private:
int getRemoteAddress(cdevAddr &) const;
};
#endif /* _CDEV_SOCKET_ACCEPTOR_H */

View File

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

View File

@@ -0,0 +1,12 @@
#ifndef _CDEV_SOCKET_CONNECTOR_H_
#define _CDEV_SOCKET_CONNECTOR_H_
#include "cdevSocketStream.h"
class CDEV_REACTOR_API cdevSocketConnector : public cdevSocketStream
{
public:
int connect (const cdevAddr & remote_addr );
};
#endif /* _CDEV_SOCK_CONNECTOR_H */

View File

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

View File

@@ -0,0 +1,18 @@
#if !defined (_CDEV_SOCKET_DATAGRAM_H_)
#define _CDEV_SOCKET_DATAGRAM_H
#include "cdevSocket.h"
#include "cdevAddr.h"
class CDEV_REACTOR_API cdevSocketDatagram : public cdevSocket
{
public:
cdevSocketDatagram (void);
cdevSocketDatagram (const cdevAddr &addr, int protocol_family = PF_INET, int protocol = 0);
int open (const cdevAddr &addr, int protocol_family = PF_INET, int protocol = 0);
ssize_t send (const void *buf, size_t n, const cdevAddr &addr, int flags = 0) const;
ssize_t recv (void *buf, size_t n, cdevAddr &addr, int flags = 0) const;
};
#endif /* _CDEV_SOCKET_DATAGRAM_H_ */

View File

@@ -0,0 +1,177 @@
#include "cdevSocketStream.h"
// *****************************************************************************
// * cdevSocketStream::cdevSocketStream :
// * Constructor for the cdevSocketStream class. Only serves to initialize
// * the readRetryCount variable.
// *****************************************************************************
cdevSocketStream::cdevSocketStream ( void )
{
}
// *****************************************************************************
// * cdevSocketStream::send :
// * Send an n byte message to the connected socket.
// *****************************************************************************
ssize_t cdevSocketStream::send(const void *buf, size_t n, int flags) const
{
int retval;
if((retval = ::send(getHandle(), (const char *) buf, n, flags))<=0)
{
int errCode = GetSocketErrno();
if(errCode==EAGAIN || errCode==EWOULDBLOCK) retval = 0;
}
return retval;
}
// *****************************************************************************
// * cdevSocketStream::send_n :
// * This method will transmit an n byte message to a connected socket,
// * waiting until all data has been transmitted or an error occurs.
// *****************************************************************************
ssize_t cdevSocketStream::send_n(const void *buf, size_t n, int flags) const
{
ssize_t amntsent = 0;
int result = 0;
while(amntsent<(ssize_t)n && result>=0)
{
if((result = ::send(getHandle(), (const char *)buf+amntsent, n-amntsent, flags))<=0)
{
int errCode = GetSocketErrno();
if(errCode==EAGAIN || errCode==EWOULDBLOCK) result = 0;
else result = -1;
}
else amntsent+=result;
}
return (amntsent>=(ssize_t)n)?amntsent:-1;
}
// *****************************************************************************
// * cdevSocketStream::recv :
// * Recv an n byte message from the connected socket.
// *****************************************************************************
ssize_t cdevSocketStream::recv(void *buf, size_t n, int flags)
{
int retval = 0;
if((retval = ::recv(getHandle(), (char *)buf, n, flags))<=0)
{
int errCode = GetSocketErrno();
if(errCode==EAGAIN || errCode==EWOULDBLOCK) retval = 0;
}
return retval;
}
// *****************************************************************************
// * cdevSocketStream::recv_n :
// * This method will receive an n byte message from a connected socket,
// * waiting until all data has been received or an error occurs.
// *****************************************************************************
ssize_t cdevSocketStream::recv_n(void *buf, size_t n, int flags)
{
ssize_t amntrecv = 0;
int result = 0;
while(amntrecv < (ssize_t)n)
{
if((result = ::recv(getHandle(), (char *)buf+amntrecv, n-amntrecv, flags)) < 0)
{
return -1;
}
else if (result == 0)
break;
else amntrecv+=result;
}
return amntrecv;
}
// *****************************************************************************
// * cdevSocketStream::closeReader :
// * Shut down just the reading end of a cdevSocket.
// *****************************************************************************
int cdevSocketStream::closeReader(void)
{
return ::shutdown(getHandle(), 0);
}
// *****************************************************************************
// * cdevSocketStream::closeWriter :
// * Shut down just the writing end of a cdevSocket.
// *****************************************************************************
int cdevSocketStream::closeWriter(void)
{
return ::shutdown(getHandle(), 1);
}
int cdevSocketStream::getBlockingSemantics ( void ) const
{
return O_NONBLOCK;
}
int cdevSocketStream::getRcvLowWaterMark ( void ) const
{
return 0;
}
int cdevSocketStream::getRcvBufferSize ( void ) const
{
return 56000;
}
int cdevSocketStream::getSndLowWaterMark ( void ) const
{
return 16000;
}
int cdevSocketStream::getSndBufferSize ( void ) const
{
return 56000;
}
int cdevSocketStream::configureHandle ( void )
{
int retval = 0;
int parm = 1;
if(getBlockingSemantics()==O_NONBLOCK && setFlags(O_NONBLOCK)==-1)
{
retval = -1;
}
setOption(IPPROTO_TCP, TCP_NODELAY, &parm, sizeof(parm));
if((parm = getRcvBufferSize())>0)
{
setOption(SOL_SOCKET, SO_RCVBUF, &parm, sizeof(parm));
}
#ifndef __linux
if((parm = getRcvLowWaterMark())>0)
{
setOption(SOL_SOCKET, SO_RCVLOWAT, &parm, sizeof(parm));
}
#endif
if((parm = getSndBufferSize())>0)
{
setOption(SOL_SOCKET, SO_SNDBUF, &parm, sizeof(parm));
}
#ifndef __linux
if((parm = getSndLowWaterMark())>0)
{
setOption(SOL_SOCKET, SO_SNDLOWAT, &parm, sizeof(parm));
}
#endif
return retval;
}

View File

@@ -0,0 +1,29 @@
#if !defined (_CDEV_SOCKET_STREAM_H)
#define _CDEV_SOCKET_STREAM_H
#include "cdevSocket.h"
#include <signal.h>
class CDEV_REACTOR_API cdevSocketStream : public cdevSocket
{
public:
cdevSocketStream (void);
ssize_t send (const void *buf, size_t n, int flags=0) const;
ssize_t recv (void *buf, size_t n, int flags=0);
ssize_t send_n (const void *buf, size_t n, int flags=0) const;
ssize_t recv_n (void * buf, size_t n, int flags=0);
int closeReader (void);
int closeWriter (void);
virtual int getBlockingSemantics ( void ) const;
virtual int getRcvLowWaterMark ( void ) const;
virtual int getSndLowWaterMark ( void ) const;
virtual int getRcvBufferSize ( void ) const;
virtual int getSndBufferSize ( void ) const;
virtual int configureHandle ( void );
};
#endif /* _CDEV_SOCKET_STREAM_H_ */

View File

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

View File

@@ -0,0 +1,33 @@
#ifndef _CDEV_STREAM_NODE_H_
#define _CDEV_STREAM_NODE_H_
#include "cdevPlatforms.h"
// *****************************************************************************
// * class cdevStreamNode :
// * This is a virtual base class that defines the functionality that will
// * be required for data nodes that are inserted into the
// * cdevBufferedSocket.
// *****************************************************************************
class CDEV_REACTOR_API cdevStreamNode
{
friend class cdevStreamQueue;
public:
virtual ~cdevStreamNode ( void );
virtual size_t getLen(void) const = 0;
virtual void setLen(size_t size) = 0;
virtual char * getBuf(void) const = 0;
virtual void setBuf(char * buf, size_t len) = 0;
protected:
cdevStreamNode * nextStreamNode;
cdevStreamNode ( void );
cdevStreamNode * getNext( void ) const;
void setNext(cdevStreamNode * node);
};
#endif /* _CDEV_STREAM_NODE_H_ */

View File

@@ -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 )
{
}

View File

@@ -0,0 +1,126 @@
#ifndef _CDEV_STREAM_QUEUE_H_
#define _CDEV_STREAM_QUEUE_H_
#include "cdevStreamNode.h"
// *****************************************************************************
// * class cdevSimpleStreamNode :
// * This is a simple implementation class of the cdevStreamNode. It will
// * be used if the developer does not provide his own implementation class.
// *****************************************************************************
class CDEV_REACTOR_API cdevSimpleStreamNode : public cdevStreamNode
{
protected:
char * buf;
size_t len;
public:
cdevSimpleStreamNode ( char * buffer=NULL, size_t size=0);
~cdevSimpleStreamNode ( void );
size_t getLen (void) const;
void setLen (size_t size);
char * getBuf (void) const;
void setBuf (char * buffer, size_t size);
};
// *****************************************************************************
// * class cdevNodeFactory :
// * This class will generate a user defined instance of a cdevStreamNode
// * sub-class. This class is used within the cdevBufferedSocket to
// * convert incoming binary packets into a user defined structure.
// *****************************************************************************
class CDEV_REACTOR_API cdevNodeFactory
{
public:
virtual ~cdevNodeFactory ( void );
virtual cdevStreamNode * newNode ( ssize_t size ) = 0;
};
// *****************************************************************************
// * class cdevStreamQueue :
// * This is a class that will store the data items that are being enqueued
// * by the cdevBufferedSocket.
// *****************************************************************************
class CDEV_REACTOR_API cdevStreamQueue
{
private:
cdevStreamNode * head;
cdevStreamNode * tail;
int deleteFlag;
size_t nEntries;
size_t totalLen;
public:
cdevStreamQueue ( int deleteNodesFlag = 1 )
: head(NULL), tail(NULL), deleteFlag(deleteNodesFlag),
nEntries(0), totalLen(0)
{
}
~cdevStreamQueue ( void )
{
if(deleteFlag) while(!isEmpty()) delete dequeue();
}
void enqueue( cdevStreamQueue & queue )
{
head = queue.head;
tail = queue.tail;
nEntries = queue.nEntries;
totalLen = queue.totalLen;
queue.head = NULL;
queue.tail = NULL;
queue.nEntries = 0;
queue.totalLen = 0;
}
void enqueue ( cdevStreamNode * node )
{
if(node)
{
if(tail!=NULL) tail->setNext(node);
else head = node;
tail = node;
totalLen+=(node->getLen()+sizeof(node->getLen()));
nEntries++;
}
}
cdevStreamNode * dequeue ( void )
{
cdevStreamNode * node = NULL;
if(head!=NULL)
{
node = head;
head = node->getNext();
node->setNext(NULL);
if(head==NULL) tail = NULL;
totalLen-=(node->getLen()+sizeof(node->getLen()));
nEntries--;
}
return node;
}
cdevStreamNode * peek ( void )
{
return head;
}
void poke ( cdevStreamNode * node )
{
node->setNext(head);
head = node;
if(tail==NULL) tail = head;
}
int isEmpty ( void ) const { return head==NULL?1:0; }
size_t getCount ( void ) const { return nEntries; }
size_t getSize ( void ) const { return totalLen; }
};
#endif /* _CDEV_STREAM_QUEUE_H */

View File

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

View File

@@ -0,0 +1,51 @@
#ifndef _CDEV_TIME_H_
#define _CDEV_TIME_H_ 1
#include "cdevPlatforms.h"
#define ONE_SECOND 1000000
typedef struct timeval timeval;
class CDEV_REACTOR_API cdevTime
{
private:
long tv_sec;
long tv_usec;
public:
cdevTime ( long sec=0, long usec=0 );
cdevTime ( double t );
cdevTime ( timeval &t );
cdevTime ( const cdevTime &t );
void getTime ( double * t ) const;
void getTime ( long *sec, long *usec) const;
void getTime ( timeval * t ) const;
void setTime ( void );
void setTime ( double t );
void setTime ( long sec, long usec);
void setTime ( timeval &t );
void setTime ( const cdevTime &t );
void clear ( void );
int isSet ( void ) const;
int normalize ( void );
operator double ( void );
operator timeval ( void );
cdevTime & operator = (const cdevTime& t);
friend cdevTime operator + (cdevTime t1, cdevTime t2);
friend cdevTime operator - (cdevTime t1, cdevTime t2);
friend int operator < (cdevTime t1, cdevTime t2);
friend int operator > (cdevTime t1, cdevTime t2);
friend int operator <= (cdevTime t1, cdevTime t2);
friend int operator >= (cdevTime t1, cdevTime t2);
friend int operator == (cdevTime t1, cdevTime t2);
friend int operator != (cdevTime t1, cdevTime t2);
};
#endif