#include "ClientHandler.h" #include "ClientAcceptor.h" #include // ***************************************************************************** // * 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; }