diff options
Diffstat (limited to 'indra/llplugin/llpluginmessagepipe.cpp')
-rw-r--r-- | indra/llplugin/llpluginmessagepipe.cpp | 596 |
1 files changed, 298 insertions, 298 deletions
diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 9766e1bfed..2cbc16ceec 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpluginmessagepipe.cpp * @brief Classes that implement connections from the plugin system to pipes/pumps. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -36,362 +36,362 @@ static const char MESSAGE_DELIMITER = '\0'; LLPluginMessagePipeOwner::LLPluginMessagePipeOwner() : - mMessagePipe(NULL), - mSocketError(APR_SUCCESS) + mMessagePipe(NULL), + mSocketError(APR_SUCCESS) { } -// virtual +// virtual LLPluginMessagePipeOwner::~LLPluginMessagePipeOwner() { - killMessagePipe(); + killMessagePipe(); } -// virtual +// virtual apr_status_t LLPluginMessagePipeOwner::socketError(apr_status_t error) -{ - mSocketError = error; - return error; +{ + mSocketError = error; + return error; }; -//virtual +//virtual void LLPluginMessagePipeOwner::setMessagePipe(LLPluginMessagePipe *read_pipe) { - // Save a reference to this pipe - mMessagePipe = read_pipe; + // Save a reference to this pipe + mMessagePipe = read_pipe; } bool LLPluginMessagePipeOwner::canSendMessage(void) { - return (mMessagePipe != NULL); + return (mMessagePipe != NULL); } bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message) { - bool result = true; - if(mMessagePipe != NULL) - { - result = mMessagePipe->addMessage(message); - } - else - { - LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL; - result = false; - } - - return result; + bool result = true; + if(mMessagePipe != NULL) + { + result = mMessagePipe->addMessage(message); + } + else + { + LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL; + result = false; + } + + return result; } void LLPluginMessagePipeOwner::killMessagePipe(void) { - if(mMessagePipe != NULL) - { - delete mMessagePipe; - mMessagePipe = NULL; - } + if(mMessagePipe != NULL) + { + delete mMessagePipe; + mMessagePipe = NULL; + } } LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): - mInputMutex(), - mOutputMutex(), - mOutputStartIndex(0), - mOwner(owner), - mSocket(socket) + mInputMutex(), + mOutputMutex(), + mOutputStartIndex(0), + mOwner(owner), + mSocket(socket) { - mOwner->setMessagePipe(this); + mOwner->setMessagePipe(this); } LLPluginMessagePipe::~LLPluginMessagePipe() { - if(mOwner != NULL) - { - mOwner->setMessagePipe(NULL); - } + if(mOwner != NULL) + { + mOwner->setMessagePipe(NULL); + } } bool LLPluginMessagePipe::addMessage(const std::string &message) { - // queue the message for later output - LLMutexLock lock(&mOutputMutex); - - // If we're starting to use up too much memory, clear - if (mOutputStartIndex > 1024 * 1024) - { - mOutput = mOutput.substr(mOutputStartIndex); - mOutputStartIndex = 0; - } - - mOutput += message; - mOutput += MESSAGE_DELIMITER; // message separator - - return true; + // queue the message for later output + LLMutexLock lock(&mOutputMutex); + + // If we're starting to use up too much memory, clear + if (mOutputStartIndex > 1024 * 1024) + { + mOutput = mOutput.substr(mOutputStartIndex); + mOutputStartIndex = 0; + } + + mOutput += message; + mOutput += MESSAGE_DELIMITER; // message separator + + return true; } void LLPluginMessagePipe::clearOwner(void) { - // The owner is done with this pipe. The next call to process_impl should send any remaining data and exit. - mOwner = NULL; + // The owner is done with this pipe. The next call to process_impl should send any remaining data and exit. + mOwner = NULL; } void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec) { - // We never want to sleep forever, so force negative timeouts to become non-blocking. - - // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html - // blocking/non-blocking with apr sockets is somewhat non-portable. - - if(timeout_usec <= 0) - { - // Make the socket non-blocking - apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); - apr_socket_timeout_set(mSocket->getSocket(), 0); - } - else - { - // Make the socket blocking-with-timeout - apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); - apr_socket_timeout_set(mSocket->getSocket(), timeout_usec); - } + // We never want to sleep forever, so force negative timeouts to become non-blocking. + + // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html + // blocking/non-blocking with apr sockets is somewhat non-portable. + + if(timeout_usec <= 0) + { + // Make the socket non-blocking + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), 0); + } + else + { + // Make the socket blocking-with-timeout + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), timeout_usec); + } } bool LLPluginMessagePipe::pump(F64 timeout) { - bool result = pumpOutput(); - - if(result) - { - result = pumpInput(timeout); - } - - return result; + bool result = pumpOutput(); + + if(result) + { + result = pumpInput(timeout); + } + + return result; } bool LLPluginMessagePipe::pumpOutput() { - bool result = true; - - if(mSocket) - { - apr_status_t status; - apr_size_t in_size, out_size; - - LLMutexLock lock(&mOutputMutex); - - const char * output_data = &(mOutput.data()[mOutputStartIndex]); - if(*output_data != '\0') - { - // write any outgoing messages - in_size = (apr_size_t) (mOutput.size() - mOutputStartIndex); - out_size = in_size; - - setSocketTimeout(0); - -// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; - - status = apr_socket_send(mSocket->getSocket(), - output_data, - &out_size); - -// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL; - - if((status == APR_SUCCESS) || APR_STATUS_IS_EAGAIN(status)) - { - // Success or Socket buffer is full... - - // If we've pumped the entire string, clear it - if (out_size == in_size) - { - mOutputStartIndex = 0; - mOutput.clear(); - } - else - { - llassert(in_size > out_size); - - // Remove the written part from the buffer and try again later. - mOutputStartIndex += out_size; - } - } - else if(APR_STATUS_IS_EOF(status)) - { - // This is what we normally expect when a plugin exits. - //LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL; - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - } - else - { - // some other error - // Treat this as fatal. - ll_apr_warn_status(status); - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - } - } - } - - return result; + bool result = true; + + if(mSocket) + { + apr_status_t status; + apr_size_t in_size, out_size; + + LLMutexLock lock(&mOutputMutex); + + const char * output_data = &(mOutput.data()[mOutputStartIndex]); + if(*output_data != '\0') + { + // write any outgoing messages + in_size = (apr_size_t) (mOutput.size() - mOutputStartIndex); + out_size = in_size; + + setSocketTimeout(0); + +// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; + + status = apr_socket_send(mSocket->getSocket(), + output_data, + &out_size); + +// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL; + + if((status == APR_SUCCESS) || APR_STATUS_IS_EAGAIN(status)) + { + // Success or Socket buffer is full... + + // If we've pumped the entire string, clear it + if (out_size == in_size) + { + mOutputStartIndex = 0; + mOutput.clear(); + } + else + { + llassert(in_size > out_size); + + // Remove the written part from the buffer and try again later. + mOutputStartIndex += out_size; + } + } + else if(APR_STATUS_IS_EOF(status)) + { + // This is what we normally expect when a plugin exits. + //LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL; + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + } + } + + return result; } bool LLPluginMessagePipe::pumpInput(F64 timeout) { - bool result = true; + bool result = true; - if(mSocket) - { - apr_status_t status; - apr_size_t size; + if(mSocket) + { + apr_status_t status; + apr_size_t size; - // FIXME: For some reason, the apr timeout stuff isn't working properly on windows. - // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead. + // FIXME: For some reason, the apr timeout stuff isn't working properly on windows. + // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead. #if LL_WINDOWS - if(result) - { - if(timeout != 0.0f) - { - ms_sleep((int)(timeout * 1000.0f)); - timeout = 0.0f; - } - } + if(result) + { + if(timeout != 0.0f) + { + ms_sleep((int)(timeout * 1000.0f)); + timeout = 0.0f; + } + } #endif - - // Check for incoming messages - if(result) - { - char input_buf[1024]; - apr_size_t request_size; - - if(timeout == 0.0f) - { - // If we have no timeout, start out with a full read. - request_size = sizeof(input_buf); - } - else - { - // Start out by reading one byte, so that any data received will wake us up. - request_size = 1; - } - - // and use the timeout so we'll sleep if no data is available. - setSocketTimeout((apr_interval_time_t)(timeout * 1000000)); - - while(1) - { - size = request_size; - -// LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL; - - status = apr_socket_recv( - mSocket->getSocket(), - input_buf, - &size); - -// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL; - - if(size > 0) - { - LLMutexLock lock(&mInputMutex); - mInput.append(input_buf, size); - } - - if(status == APR_SUCCESS) - { - LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL; - - if(size != request_size) - { - // This was a short read, so we're done. - break; - } - } - else if(APR_STATUS_IS_TIMEUP(status)) - { - LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL; - - // Timeout was hit. Since the initial read is 1 byte, this should never be a partial read. - break; - } - else if(APR_STATUS_IS_EAGAIN(status)) - { - LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL; - - // Non-blocking read returned immediately. - break; - } - else if(APR_STATUS_IS_EOF(status)) - { - // This is what we normally expect when a plugin exits. - //LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL; - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - break; - } - else - { - // some other error - // Treat this as fatal. - ll_apr_warn_status(status); - - if(mOwner) - { - mOwner->socketError(status); - } - result = false; - break; - } - - if(timeout != 0.0f) - { - // Second and subsequent reads should not use the timeout - setSocketTimeout(0); - // and should try to fill the input buffer - request_size = sizeof(input_buf); - } - } - - processInput(); - } - } - - return result; + + // Check for incoming messages + if(result) + { + char input_buf[1024]; + apr_size_t request_size; + + if(timeout == 0.0f) + { + // If we have no timeout, start out with a full read. + request_size = sizeof(input_buf); + } + else + { + // Start out by reading one byte, so that any data received will wake us up. + request_size = 1; + } + + // and use the timeout so we'll sleep if no data is available. + setSocketTimeout((apr_interval_time_t)(timeout * 1000000)); + + while(1) + { + size = request_size; + +// LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL; + + status = apr_socket_recv( + mSocket->getSocket(), + input_buf, + &size); + +// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL; + + if(size > 0) + { + LLMutexLock lock(&mInputMutex); + mInput.append(input_buf, size); + } + + if(status == APR_SUCCESS) + { + LL_DEBUGS("PluginSocket") << "success, read " << size << LL_ENDL; + + if(size != request_size) + { + // This was a short read, so we're done. + break; + } + } + else if(APR_STATUS_IS_TIMEUP(status)) + { + LL_DEBUGS("PluginSocket") << "TIMEUP, read " << size << LL_ENDL; + + // Timeout was hit. Since the initial read is 1 byte, this should never be a partial read. + break; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { + LL_DEBUGS("PluginSocket") << "EAGAIN, read " << size << LL_ENDL; + + // Non-blocking read returned immediately. + break; + } + else if(APR_STATUS_IS_EOF(status)) + { + // This is what we normally expect when a plugin exits. + //LL_INFOS("PluginSocket") << "Got EOF from plugin socket. " << LL_ENDL; + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + + if(timeout != 0.0f) + { + // Second and subsequent reads should not use the timeout + setSocketTimeout(0); + // and should try to fill the input buffer + request_size = sizeof(input_buf); + } + } + + processInput(); + } + } + + return result; } void LLPluginMessagePipe::processInput(void) { - // Look for input delimiter(s) in the input buffer. - int delim; - mInputMutex.lock(); - while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos) - { - // Let the owner process this message - if (mOwner) - { - // Pull the message out of the input buffer before calling receiveMessageRaw. - // It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request) - // and this guarantees that the messages will get dequeued correctly. - std::string message(mInput, 0, delim); - mInput.erase(0, delim + 1); - mInputMutex.unlock(); - mOwner->receiveMessageRaw(message); - mInputMutex.lock(); - } - else - { - LL_WARNS("Plugin") << "!mOwner" << LL_ENDL; - } - } - mInputMutex.unlock(); + // Look for input delimiter(s) in the input buffer. + int delim; + mInputMutex.lock(); + while((delim = mInput.find(MESSAGE_DELIMITER)) != std::string::npos) + { + // Let the owner process this message + if (mOwner) + { + // Pull the message out of the input buffer before calling receiveMessageRaw. + // It's now possible for this function to get called recursively (in the case where the plugin makes a blocking request) + // and this guarantees that the messages will get dequeued correctly. + std::string message(mInput, 0, delim); + mInput.erase(0, delim + 1); + mInputMutex.unlock(); + mOwner->receiveMessageRaw(message); + mInputMutex.lock(); + } + else + { + LL_WARNS("Plugin") << "!mOwner" << LL_ENDL; + } + } + mInputMutex.unlock(); } |