Files
2022-12-13 12:44:04 +01:00

269 lines
9.1 KiB
C++
Executable File

#include "ClientHandler.h"
#include "ClientAcceptor.h"
#include <clipMagicNumber.h>
// *****************************************************************************
// * ClientHandler:
// * Default constructor for the ClientHandler class
// *****************************************************************************
ClientHandler::ClientHandler (cdevSessionManager & s)
: server(s), queue(NULL), clientQuitFlag(0),
SocketReader(CLIP_MAGIC_NUMBER), SocketWriter(CLIP_MAGIC_NUMBER),
packetsSent(0), packetsRecv(0)
{
hostName[0] = 0;
}
// *****************************************************************************
// * ClientHandler::getHostName:
// * This function returns the name of the remote host.
// *****************************************************************************
char * ClientHandler::getHostName( void )
{
if(*hostName==0)
{
cdevInetAddr addr;
if(stream.getRemoteAddress (addr)==0)
{
const char * ptr=addr.getHostName();
if(ptr) strncpy (hostName, ptr, MAXHOSTNAMELEN+1);
}
}
return hostName;
}
// *****************************************************************************
// * open:
// * Initializes the new socket and adds this ClientHandler class to
// * the reactor
// *****************************************************************************
int ClientHandler::open (class ClientAcceptor * )
{
cdevInetAddr addr;
int result = 0;
if (stream.getRemoteAddress (addr) == -1)
{
outputError(CDEV_SEVERITY_SEVERE, (char *)getName(),
"Couldn't get local address");
result = -1;
}
else
{
if (server.Reactor.registerHandler (this, READ_MASK|WRITE_MASK|EXCEPT_MASK)!=0)
{
outputError(CDEV_SEVERITY_SEVERE, (char *)getName(),
"Cannot register handler with reactor");
result = -1;
}
else {
// *****************************************************
// * Get the socket number and use it to identify the
// * socket within the cdevSessionManager.
// *****************************************************
int handle = getHandle();
if((queue = server.findSocket(handle))!=NULL)
{
server.removeSocket(handle);
}
queue = server.addSocket(handle);
outputError(CDEV_SEVERITY_INFO, (char *)getName(),
"Establishing connection to %s on socket %i",
getHostName(), handle);
}
}
return result;
}
// *****************************************************************************
// * getHandle:
// * Returns the device descriptor for the underlying socket
// *****************************************************************************
int ClientHandler::getHandle (void) const
{
return stream.getHandle ();
}
// *****************************************************************************
// * ~ClientHandler:
// * Destructor for the ClientHandler object
// *****************************************************************************
ClientHandler::~ClientHandler (void)
{
if(stream.getHandle()>0 && clientQuitFlag==0) writeGoodbye();
if(reactor) reactor->extractHandler(this);
handleClose();
}
// *****************************************************************************
// * handleClose:
// * Removes the object from the reactor class and then deletes it.
// *****************************************************************************
int ClientHandler::handleClose (void)
{
outputError(CDEV_SEVERITY_INFO, (char *)getName(),
"Terminating connection to %s on socket %i",
getHostName(), queue?queue->getSocketID():0);
stream.close();
if(queue)
{
server.removeSocket(queue->getSocketID());
queue = NULL;
}
return 0;
}
// *****************************************************************************
// # handleInput :
// # This function is called when data is ready to be read from a connected
// # socket. This function will read the data from the socket, and will then
// # submit the buffer to the processIncomingPacket function for processing.
// *****************************************************************************
int ClientHandler::handleInput (void)
{
int retval = 0;
char * buf = NULL;
size_t len = 0;
int result = 1;
// *****************************************************************************
// * Record oriented semantics dictate that the length of the transmission
// * always preceeds the actual data. Therefore, read the length of the
// * transmission into the len variable.
// *****************************************************************************
while(result>0)
{
if(buf==NULL) result = read(&buf, (int *)&len);
else result = readNextPacket(&buf, (int *)&len);
switch(result)
{
// *************************************************************
// * A return value of SHUTDOWN_CODE indicates that a negative
// * one was provided as the packet length - indicating a
// * shutdown...
// *************************************************************
case SHUTDOWN_CODE:
outputError(CDEV_SEVERITY_INFO, (char *)getName(),
"Connection to %s terminated by client", getHostName());
retval = -1;
break;
// *************************************************************
// * A return value of -1 indicates an error occured while
// * reading from the socket. A value of -1 is returned to
// * shutdown the socket and remove it from the reactor.
// *************************************************************
case -1:
outputError(CDEV_SEVERITY_WARN, (char *)getName(),
"Error reading from connection to client %s", getHostName());
retval = -1;
break;
// *************************************************************
// * A return value of 0 means that no data was ready to be
// * retrieved from the socket.
// *************************************************************
case 0:
break;
// *************************************************************
// * Any other value returned from the socket represents the
// * number of bytes actually read into the local buffer object.
// *************************************************************
default:
server.enqueue(getHandle(), buf, len);
packetsSent++;
break;
}
}
// *****************************************************************************
// * Return the value specified by retval.
// *****************************************************************************
return retval;
}
// *****************************************************************************
// # handleOutput :
// # This function is called when data is ready to be transmitted to a
// # connected socket. This function will read the data from the queue,
// # translate it to XDR, and then transmit it to the client.
// *****************************************************************************
int ClientHandler::handleOutput (void)
{
int retval = 0;
char * buf = NULL;
size_t len = 0;
// *****************************************************************************
// * Attempt to transmit or continue transmitting the data. Note, the peek
// * method is used to attempt to writeEnqueue a data item without actually
// * removing it from the outbound queue. If the item can be writeEnqueued,
// * then the dequeue method is called to remove it from the queue...
// * This method is repeated until the output buffer is fully populated.
// *****************************************************************************
if(!writing() && queue!=NULL && queue->peek(&buf, &len)==0)
{
int full = 0;
while(!full)
{
full = writeEnqueue(buf, len);
if(!full)
{
queue->dequeue(&buf, &len);
delete buf;
buf = NULL;
len = 0;
if(queue->peek(&buf, &len)!=0) full=-1;
packetsRecv++;
}
}
if(writeContinue()<0) retval = -1;
}
else if(writing())
{
if(writeContinue()<0) retval = -1;
}
// *****************************************************************************
// * Display an error message if the transmission failed.
// *****************************************************************************
if(retval!=0)
{
outputError(CDEV_SEVERITY_WARN, (char *)getName(),
"Error transmitting to %s", getHostName());
}
// *****************************************************************************
// * If there are no further messages in the outbound queue and the
// * ACE_Event_Handler has finished servicing the current message, turn off the
// * WRITE_MASK for this ACE_Event_Handler.
// *****************************************************************************
if(retval!=0 || ((queue==NULL || queue->empty()) && !writing()))
{
setMask(READ_MASK|EXCEPT_MASK);
}
// *****************************************************************************
// * Return the value specified by retval.
// *****************************************************************************
return retval;
}
// *****************************************************************************
// * ClientHandler::handleExcept :
// * This function is called when out of band data is ready to be received
// * from the socket.
// *****************************************************************************
int ClientHandler::handleExcept(void)
{
clientQuitFlag=1;
return -1;
}