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,692 @@
#include "cdevServer.h"
#include "ClientAcceptor.h"
#include "ClientHandler.h"
sig_atomic_t cdevServer::Finished = 0;
SignalManager cdevServer::SigManager;
cdevGenericServerTagDef cdevServer::tags;
// *****************************************************************************
// * This function is an interrupt handler that will be executed whenever the
// * program receives a SIGINT. When called it will set the finished flag to 1
// * and trigger the termination of the program.
// *****************************************************************************
static void SIGINT_handler (int signo)
{
cdevServer::Finished = 1;
signal(signo, SIGINT_handler);
}
// *****************************************************************************
// * cdevServer::cdevServer :
// * This is the constructor for the class. It will post the listening
// * socket, establish registration with the name server and record all
// * other pertinent information.
// *****************************************************************************
cdevServer::cdevServer (char * DomainName, char * ServerName, unsigned short Port, double Rate)
: cdevSessionManager(),
serverName (NULL),
acceptor (NULL),
timer (NULL),
status (UNINITIALIZED),
serverInfo (NULL)
{
// *********************************************************************
// * Register the import method for the cdevMessage class with the
// * cdevPacket class.
// *********************************************************************
cdevPacket::registerImportMethod(cdevMessage::CDEV_PACKET_VERSION,
cdevMessage::import);
startServer(DomainName, ServerName, Port, Rate, 0);
}
// *****************************************************************************
// * cdevServer::cdevServer :
// * This is the do nothing constructor for the class.
// *****************************************************************************
cdevServer::cdevServer ( void )
: cdevSessionManager (),
serverName (NULL),
acceptor (NULL),
timer (NULL),
status (UNINITIALIZED),
serverInfo (NULL)
{
// *********************************************************************
// * Register the import method for the cdevMessage class with the
// * cdevPacket class.
// *********************************************************************
cdevPacket::registerImportMethod(cdevMessage::CDEV_PACKET_VERSION,
cdevMessage::import);
}
// *****************************************************************************
// * cdevServer::~cdevServer :
// * This is the destructor for the object. It will close all listening
// * sockets and will delete all allocated items.
// *****************************************************************************
cdevServer::~cdevServer ( void )
{
outputError ( CDEV_SEVERITY_INFO, "CDEV Server",
"Server %s is Terminating...",
serverName);
Reactor.extractHandler(this);
if(timer!=NULL) delete timer;
if(serverName!=NULL) delete serverName;
if(acceptor!=NULL) delete acceptor;
}
// *****************************************************************************
// * cdevServer::startServer :
// * This method will initialize a cdevServer within a given name, will
// * register it within the CDEV Name Server and will commence listening
// * for connections on the specified port.
// *****************************************************************************
int cdevServer::startServer (char * DomainName, char * ServerName, unsigned short Port, double Rate, int searchForPort)
{
if(acceptor!=NULL)
{
delete acceptor;
acceptor=NULL;
}
if(timer)
{
delete timer;
timer=NULL;
}
if(serverName)
{
delete serverName;
serverName = NULL;
}
if(serverInfo)
{
delete serverInfo;
serverInfo = NULL;
}
Reactor.extractHandler(this);
setTimeoutRate(Rate);
serverName = strdup(ServerName);
status = UNINITIALIZED;
acceptor = new ClientAcceptor(*this);
// *********************************************************************
// * Attempt to open the acceptor to receive new connections.
// *********************************************************************
if(searchForPort) Port = 0;
cdevInetAddr addr(Port);
int initialized=!(acceptor->open(addr));
// *********************************************************************
// * Call getLocalAddress to retrieve the actual port number that was
// * opened. This value will differ from the specified port if...
// * 1) the user specified 0 for the port number -or-
// * 2) the user set the searchForPort flag to non-zero.
// *********************************************************************
if(acceptor->getLocalAddress(addr)==0) Port = addr.getPortNum();
else Port = (unsigned short)-1;
// *********************************************************************
// * ServerInfo must be created after the port has been searched for
// * and found. Otherwise, the server will report the original port
// * number rather than the actual port number.
// *********************************************************************
serverInfo = new ServerInfo(DomainName, ServerName, Port);
if(initialized)
{
// *************************************************************
// * Register the acceptor with the Reactor.
// *************************************************************
if(Reactor.registerHandler(acceptor, READ_MASK)!=-1)
{
// *****************************************************
// * Register this event handler with the Reactor.
// *****************************************************
if(Reactor.registerHandler(this, READ_MASK)!=-1)
{
// *********************************************
// * Schedule the periodic timer if it is
// * greater than 0.
// *********************************************
if(Rate <= 0.0 ||
Reactor.registerTimer(this)!=-1)
{
// *************************************
// * Install a name server timer to
// * continuously register this server
// * with the Name Server.
// *************************************
timer = new cdevNameServerManager(Reactor, DomainName, ServerName, Port);
outputError (CDEV_SEVERITY_INFO, "CDEV Server",
"Server %s is operational and servicing requests...",
serverName);
}
else
{
outputError ( CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to register server timer with cdevReactor",
serverName);
status = CANT_REGISTER_TIMER;
}
}
else
{
outputError ( CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to register server handler with cdevReactor",
serverName);
status = CANT_REGISTER_SERVER;
}
}
else
{
outputError (CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to register listening service with cdevReactor",
serverName);
status = CANT_REGISTER_LISTENER;
}
}
else
{
outputError ( CDEV_SEVERITY_SEVERE, "CDEV Server",
"Server %s - Unable to open listening socket",
serverName);
status = CANT_OPEN_SOCKET;
}
switch (status)
{
case CANT_REGISTER_TIMER:
Reactor.extractHandler(this);
case CANT_REGISTER_SERVER:
Reactor.extractHandler(acceptor);
case CANT_REGISTER_LISTENER:
case CANT_OPEN_SOCKET:
delete acceptor;
acceptor = NULL;
break;
case SUCCESS:
default:
status = SUCCESS;
break;
}
return status;
}
// ***************************************************************************
// * cdevServer::runServer :
// * This method is called to simultaneously execute all servers that
// * reside in the system.
// ***************************************************************************
void cdevServer::runServer ( void )
{
SigManager.installDefaults();
SigManager.installHandler (SIGINT, SIGINT_handler);
while (!Finished) Reactor.handleEvents ();
}
// *****************************************************************************
// * cdevServer::registerClient :
// * This is the cdevMessage specific method that is used to send a
// * "register" message to the server.
// *****************************************************************************
void cdevServer::registerClient ( short localID )
{
cdevMessage message(localID,0,0,0,0,0,0,0,NULL,"register");
cdevPacketBinary * packet = new cdevPacketBinary;
char * binary;
size_t binaryLen;
message.streamOut (&binary, &binaryLen);
packet->attachData(binary, binaryLen);
inbound.enqueue (packet);
}
// *****************************************************************************
// * cdevServer::unregisterClient :
// * This is the cdevMessage specific method that is used to send an
// * "unregister" message to the server.
// *****************************************************************************
void cdevServer::unregisterClient ( short localID )
{
cdevMessage message(localID,0,0,0,0,0,0,0,NULL,"unregister");
cdevPacketBinary * packet = new cdevPacketBinary;
char * binary;
size_t binaryLen;
message.streamOut (&binary, &binaryLen);
packet->attachData(binary, binaryLen);
inbound.enqueue (packet);
trigger.insertEvent();
}
// *****************************************************************************
// * cdevServer::newClientSession :
// * This method allows the caller to create a new ClientSession object. The
// * ClientSession object functions primarily as a pointer to the queue that
// * holds packets destined for a specific client, however, the developer
// * can create a subclass of the ClientSession that may be used to associate
// * additional, client specific information to the structure.
// *
// * The CLIPClientSession class allows the developer to associate a context
// * with the clientID.
// *****************************************************************************
ClientSession * cdevServer::newClientSession ( int SocketID, int ClientID, int LocalID )
{
return new CLIPClientSession (SocketID, ClientID, LocalID);
}
// *****************************************************************************
// * cdevServer::newSocketSession :
// * This method allows the caller to create a new SocketSession object. The
// * SocketSession object functions primarily as a pointer to the queue that
// * holds packets destined for a specific socket, however, the developer
// * can create a subclass of the SocketSession that may be used to associate
// * additional, socket specific information to the structure.
// *
// * The CLIPSocketSession class allows the developer to associate a
// * context map and a tag table with the socket number.
// *****************************************************************************
SocketSession * cdevServer::newSocketSession ( int SocketID )
{
if(serverInfo) serverInfo->clientCnt++;
return new CLIPSocketSession (SocketID);
}
// *****************************************************************************
// * cdevServer::deleteSocketSession :
// * This method is called to delete an existing socket session.
// *****************************************************************************
void cdevServer::deleteSocketSession ( SocketSession *socket )
{
if(socket)
{
if(serverInfo)
{
if(serverInfo->clientCnt>0) serverInfo->clientCnt--;
else serverInfo->clientCnt=0;
}
sockets.remove(socket->getSocketID());
delete socket;
}
}
// *****************************************************************************
// * cdevServer::dequeue :
// * This method provides a mechanism for the cdevServer object to only
// * dequeue packets that are of the type cdevMessage.
// *****************************************************************************
int cdevServer::dequeue ( cdevMessage * &message )
{
cdevPacket * packet = NULL;
while(packet==NULL && cdevSessionManager::dequeue(packet)==0)
{
if(packet->getVersion()!=cdevMessage::CDEV_PACKET_VERSION)
{
delete packet;
packet = NULL;
}
else if(((cdevMessage *)packet)->getOperationCode()==CDEV_SERVER_OP)
{
processLocal((cdevMessage * &)packet);
delete packet;
packet = NULL;
}
}
message = (cdevMessage *)packet;
return message==NULL?-1:0;
}
// *****************************************************************************
// * cdevServer::processLocal :
// * This method is called to process requests that are being transmitted
// * directly to the cdev Generic Server Engine to set or retrieve statistics
// * about the operation of the server or its clients.
// *****************************************************************************
void cdevServer::processLocal ( cdevMessage * & message )
{
CLIPClientSession * client = NULL;
CLIPSocketSession * socket = NULL;
if((client = (CLIPClientSession *)findLocalClient(message->getClientID()))!=NULL)
{
socket = (CLIPSocketSession *)findSocket(client->getSocketID());
}
if(!strcmp(message->getMessage(), "set ClientInfo"))
{
cdevData * data = message->getData();
if(data && socket) socket->updateClientInfo(*data);
}
else if(!strcmp(message->getMessage(), "get ServerInfo"))
{
if(serverInfo)
{
message->setOperationCode(CDEV_NORMAL_OP);
message->setData(&serverInfo->getServerData(), 1);
}
else {
message->setOperationCode(CDEV_NORMAL_OP);
message->setCompletionCode(-1);
}
enqueue(message);
}
else if(!strcmp(message->getMessage(), "get ClientInfo"))
{
IntHashIterator iter(&sockets);
ClientHandler * handler = NULL;
int socketCnt = 0;
int index = 0;
cdevData result;
iter.first();
while(iter.data()!=NULL)
{
iter++;
socketCnt++;
}
if(socketCnt)
{
char ** username = new char *[socketCnt];
char ** group = new char *[socketCnt];
unsigned * uid = new unsigned [socketCnt];
unsigned * gid = new unsigned [socketCnt];
unsigned * pid = new unsigned [socketCnt];
char ** program = new char *[socketCnt];
char ** commandline = new char *[socketCnt];
unsigned * starttime = new unsigned [socketCnt];
unsigned * connecttime = new unsigned [socketCnt];
char ** host = new char *[socketCnt];
char ** os = new char *[socketCnt];
char ** osrelease = new char *[socketCnt];
char ** osversion = new char *[socketCnt];
char ** machine = new char *[socketCnt];
char ** shell = new char *[socketCnt];
unsigned * socketNum = new unsigned[socketCnt];
unsigned * sendPktCnt = new unsigned[socketCnt];
unsigned * recvPktCnt = new unsigned[socketCnt];
iter.first();
while(index<socketCnt && (socket = (CLIPSocketSession *)iter.data())!=NULL)
{
username[index] = socket->getUsername();
group[index] = socket->getGroup();
uid[index] = socket->getUid();
gid[index] = socket->getGid();
pid[index] = socket->getPid();
program[index] = socket->getProgram();
commandline[index] = socket->getCommandLine();
starttime[index] = (unsigned)socket->getStartTime();
connecttime[index] = (unsigned)socket->getConnectTime();
host[index] = socket->getHost();
os[index] = socket->getOs();
osrelease[index] = socket->getOsRelease();
osversion[index] = socket->getOsVersion();
machine[index] = socket->getMachine();
shell[index] = socket->getShell();
socketNum[index] = socket->getSocketID();
if(Reactor.getHandler(socketNum[index], (cdevEventHandler *&)handler)==0)
{
sendPktCnt[index] = handler->getPacketsSent();
recvPktCnt[index] = handler->getPacketsRecv();
}
else {
sendPktCnt[index] = 0;
recvPktCnt[index] = 0;
}
index++;
iter++;
}
result.insert("username", username, socketCnt); delete username;
result.insert("group", group, socketCnt); delete group;
result.insert("uid", uid, socketCnt); delete uid;
result.insert("gid", gid, socketCnt); delete gid;
result.insert("pid", pid, socketCnt); delete pid;
result.insert("program", program, socketCnt); delete program;
result.insert("commandline", commandline, socketCnt); delete commandline;
result.insert("starttime", starttime, socketCnt); delete starttime;
result.insert("connecttime", connecttime, socketCnt); delete connecttime;
result.insert("host", host, socketCnt); delete host;
result.insert("os", os, socketCnt); delete os;
result.insert("osrelease", osrelease, socketCnt); delete osrelease;
result.insert("osversion", osversion, socketCnt); delete osversion;
result.insert("machine", machine, socketCnt); delete machine;
result.insert("shell", shell, socketCnt); delete shell;
result.insert("socket", socketNum, socketCnt); delete socketNum;
result.insert("sendPktCnt", sendPktCnt, socketCnt); delete sendPktCnt;
result.insert("recvPktCnt", recvPktCnt, socketCnt); delete recvPktCnt;
}
message->setOperationCode(CDEV_NORMAL_OP);
message->setData(&result, 1);
enqueue(message);
}
}
// *****************************************************************************
// * cdevServer::decodePacket :
// * This method is used to perform preprocessing on a newly dequeued binary
// * packet before it is provided to the caller. This method allows the
// * developer to perform special preparations on the packet before providing
// * it to the caller.
// *****************************************************************************
cdevPacket * cdevServer::decodePacket( cdevPacketBinary * input )
{
cdevPacket * packet = NULL;
if(input!=NULL)
{
short version;
input->getVersion(version);
switch (version)
{
// *****************************************************
// * If it is a cdevMessage object, I want to call the
// * cdevMessage specific decodePacket method.
// *****************************************************
case cdevMessage::CDEV_PACKET_VERSION:
packet = decodePacket ((cdevMessage *)cdevPacket::import(*input));
break;
// *****************************************************
// * Use the cdevSessionManager::decodePacket method
// * to handle any other type of packet.
// *****************************************************
default:
packet = cdevSessionManager::decodePacket(input);
break;
}
if(serverInfo) serverInfo->recvPktCnt++;
}
return packet;
}
// *****************************************************************************
// * cdevServer::decodePacket :
// * This decodePacket method is designed specifically to preprocess the
// * data associated with a cdevMessage object.
// *****************************************************************************
cdevPacket * cdevServer::decodePacket (cdevMessage * message )
{
CLIPClientSession * client = NULL;
CLIPSocketSession * socket = NULL;
if(message!=NULL &&
(client = (CLIPClientSession *)findLocalClient(message->getClientID()))!=NULL &&
(socket = (CLIPSocketSession *)findSocket(client->getSocketID()))!=NULL)
{
// *************************************************************
// * If a tagMap has been provided... use it to update
// * the tagMap stored in the SocketSession object.
// *************************************************************
if(message->getTagMap()!=NULL)
{
socket->TagMap().updateTagMap(*message->getTagMap());
message->setTagMap(NULL);
}
// *************************************************************
// * Pass the data and context objects through the tag map to
// * convert their tags from the remote integers to the local
// * integers.
// *************************************************************
if(message->getData()!=NULL)
socket->TagMap().remoteToLocal(*message->getData());
if(message->getContext()!=NULL)
socket->TagMap().remoteToLocal(*message->getContext());
// *************************************************************
// * If a context has been provided by the client side
// * of the connection - perform the following steps...
// *
// * 1) Add the context to the cdevContextMap for this
// * socketID if it does not already exist, and
// * obtain the index that identifies the new
// * context.
// *
// * 2) Delete the context from within the message.
// *
// * 3) Set the context within the message to the
// * current context that is specified in the
// * ClientSession object.
// *
// * 4) Set the saveContext flag in the message to
// * prevent its inadvertant destruction when the
// * message is deleted.
// *************************************************************
if(message->getContext()!=NULL)
{
cdevData * lastContext = client->getContext();
if(lastContext==NULL || *lastContext!=*message->getContext())
{
int contextID = socket->ContextMap().insert(*message->getContext());
client->setContext(socket->ContextMap().find(contextID));
}
}
message->setContext(client->getContext(), 1);
// *************************************************************
// * Toggle the local and foreign data indices.
// *************************************************************
unsigned int index = message->getForeignDataIndex();
message->setForeignDataIndex(message->getLocalDataIndex());
message->setLocalDataIndex (index);
}
return message;
}
// *****************************************************************************
// * cdevSessionManager::encodePacket :
// * This method is used to perform postprocessing on a packet that has been
// * enqueued to be sent to a client. This method allows the developer to
// * perform special preparations on the packet before providing it to the
// * client.
// *****************************************************************************
cdevPacketBinary * cdevServer::encodePacket ( cdevPacket * input )
{
cdevPacketBinary * packet = NULL;
if(input!=NULL)
{
switch(input->getVersion())
{
case cdevMessage::CDEV_PACKET_VERSION:
packet = encodePacket ((cdevMessage *)input);
break;
default:
packet = cdevSessionManager::encodePacket(input);
break;
}
if(serverInfo) serverInfo->sendPktCnt++;
}
return packet;
}
// *****************************************************************************
// * cdevServer::encodePacket :
// * This encodePacket method is designed specifically to postprocess the
// * data associated with a cdevMessage object.
// *****************************************************************************
cdevPacketBinary * cdevServer::encodePacket (cdevMessage * message )
{
cdevPacketBinary * result = NULL;
CLIPClientSession * client = NULL;
CLIPSocketSession * socket = NULL;
if(message!=NULL &&
message->getClientID()>0 &&
message->getTransIndex()>0 &&
(client = (CLIPClientSession *)findLocalClient(message->getClientID()))!=NULL &&
(socket = (CLIPSocketSession *)findSocket(client->getSocketID()))!=NULL)
{
char * binary = NULL;
size_t binaryLen = 0;
static cdevMessage outBound;
// *************************************************************
// * Remap the data to its foreign design.
// *************************************************************
if(message->getData()!=NULL)
socket->TagMap().localToRemote(*message->getData());
// *************************************************************
// * Transfer the critical data items into the class. Note that
// * we are not returning the deviceList, message, context,
// * cancelTransIndex, or operationCode with the return packet.
// *
// * Also note that the cdevData object is marked as permanent
// * and is using a pointer to the same cdevData object that is
// * in the message object.
// *************************************************************
outBound.clear();
outBound.setClientID (client->getClientID()&0xFFFF);
outBound.setTransIndex (message->getTransIndex());
outBound.setLocalDataIndex (message->getForeignDataIndex());
outBound.setForeignDataIndex (message->getLocalDataIndex());
outBound.setOperationCode (message->getOperationCode());
outBound.setCompletionCode (message->getCompletionCode());
outBound.setData (message->getData(), 1);
// *************************************************************
// * Create a binary stream from the cdevMessage object and then
// * place it into the outbound queue system.
// *************************************************************
outBound.streamOut(&binary, &binaryLen);
outBound.clear ();
result = new cdevPacketBinary;
result->attachData(binary, binaryLen);
// *************************************************************
// * Remap the data to its local design.
// *************************************************************
if(message->getData()!=NULL)
socket->TagMap().remoteToLocal(*message->getData());
}
return result;
}