1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
/*
* ACE reactor demonstration
*
* $Id: ReadHandler.cpp 85321 2009-05-12 08:31:31Z johnnyw $
* Date: 26-Jan-2006
*/
#include "common.h"
#include "ReadHandler.h"
#include <ace/streams.h>
#include <ace/Time_Value.h>
#include <ace/Log_Msg.h>
/**
* This macro is used to increase the invocation counter by one when entering
* handle_input(). It also checks wether the counter is greater than zero
* indicating, that handle_input() has been called before.
*/
#define INVOCATION_ENTER() do { if (mInvocationCounter > 0) \
ACE_ERROR((LM_ERROR, ACE_TEXT("Multiple invocations detected.\n"))); \
mInvocationCounter++; } while (0)
/**
* THis macro is the counter part to INVOCATION_ENTER(). It decreases the
* invocation counter and then returns the given value. This macro is
* here for convenience to decrease the invocation counter also when returning
* due to errors.
*/
#define INVOCATION_RETURN(retval) do { mInvocationCounter--; \
return retval; } while(0)
ReadHandler::ReadHandler() : ACE_Event_Handler(), mStream(), mDataSize(0),
mData(0), mCallCounter(0), mInvocationCounter(0) {
ACE_TRACE(ACE_TEXT("ReadHandler::ReadHandler()"));
}
ReadHandler::~ReadHandler() {
ACE_TRACE(ACE_TEXT("ReadHandler::~ReadHandler()"));
if (mStream.close() == -1)
ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to close socket. ")
ACE_TEXT ("(errno = %i: %m)\n"), ACE_ERRNO_GET));
delete[] mData;
}
ACE_SOCK_Stream &ReadHandler::getStream(void) {
ACE_TRACE(ACE_TEXT("ReadHandler::getStream(void)"));
return mStream;
}
ACE_HANDLE ReadHandler::get_handle(void) const {
ACE_TRACE(ACE_TEXT("ReadHandler::get_handle(void)"));
return mStream.get_handle();
}
int ReadHandler::handle_input(ACE_HANDLE) {
ACE_TRACE(ACE_TEXT("ReadHandler::handle_input(ACE_HANDLE)"));
INVOCATION_ENTER();
// the response sent to the client
char response = 0;
if (mCallCounter == 0) {
/*
* This is the first request from the client.
*/
// increase the call counter so the next client request goes to else-if
mCallCounter++;
// get the desired size from the client
// Note: only use the sizeof and pointer to int on compatible
// platforms (i.e. little-endian/big-endian, data type size)
if (mStream.recv_n(&mDataSize, sizeof(mDataSize),
&connTimeout) != sizeof(mDataSize)) {
ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to receive ")
ACE_TEXT ("request. (errno = %i: %m)\n"), ACE_ERRNO_GET));
INVOCATION_RETURN(-1);
}
// The verbose debug output is replaced with some unintrusive dots.
// This increases visibility of the desired effect.
// ACE_DEBUG((LM_DEBUG, ACE_TEXT("%@: Data size: %i\n"), this, mDataSize));
ACE_DEBUG((LM_DEBUG, ACE_TEXT(".")));
// check mDataSize for plausability then allocate memory
if (mDataSize > 0) {
mData = new (std::nothrow) char[mDataSize];
if (mData == 0)
ACE_DEBUG((LM_DEBUG, ACE_TEXT("%N:%l: Failed to allocate ")
ACE_TEXT ("data buffer.\n")));
else
response = 'K';
}
// send the response to the client (which is still 0, if the
// allocation did not succeed)
if (mStream.send_n(&response, sizeof(response), &connTimeout) != 1) {
ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ")
ACE_TEXT ("response. (errno = %i: %m)\n"), ACE_ERRNO_GET));
INVOCATION_RETURN(-1);
}
if (response == 'K')
INVOCATION_RETURN(0); // get another request from the same client
else
INVOCATION_RETURN(-1); // the client will not send data if response != 'K'
} else if (mCallCounter == 1) {
/*
* This is the second request from the client.
*/
// increase the call counter, this read handler should not be called
// again
mCallCounter++;
// receive the data from the client
if (mStream.recv_n(mData, mDataSize, &connTimeout) != mDataSize) {
ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to receive data.")
ACE_TEXT ("(errno = %i: %m)\n"), ACE_ERRNO_GET));
INVOCATION_RETURN(-1);
}
response = 'K';
if (mStream.send_n(&response, 1, &connTimeout) != 1) {
ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: Failed to send ")
ACE_TEXT ("confirmation. (errno = %i: %m)\n"), ACE_ERRNO_GET));
INVOCATION_RETURN(-1);
}
INVOCATION_RETURN(-1); // ask for removal, since client does not send any more data
}
// this is to find strange actions with the call counter
ACE_ERROR((LM_ERROR, ACE_TEXT("%N:%l: We should not get here.")));
INVOCATION_RETURN(-1);
}
int ReadHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
ACE_TRACE("ReadHandler::handle_close(ACE_HANDLE, ACE_Reactor_Mask)");
delete this;
return 0;
}
|