269 lines
9.1 KiB
C++
Executable File
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;
|
|
}
|
|
|