diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-06-07 15:11:54 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-06-07 15:11:54 -0400 |
commit | 2c00dfe53574e07b3c357d80080af04a5157f240 (patch) | |
tree | 494dff255d28263e44ae701948ad7da4a6358e53 /indra | |
parent | b0f5401adb755b305669b16d6589639f79721626 (diff) | |
parent | d317454c82e016a02c8a708a0118f3ff29aa8e82 (diff) |
Merge branch 'main' of secondlife/viewer into release/luau-scripting
Diffstat (limited to 'indra')
-rw-r--r-- | indra/cmake/Copy3rdPartyLibs.cmake | 2 | ||||
-rw-r--r-- | indra/llcommon/llleap.cpp | 205 |
2 files changed, 102 insertions, 105 deletions
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 7938d4f54b..27b20ee3b1 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -107,7 +107,7 @@ if(WINDOWS) set(MSVC_VER 140) elseif (MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1930) # Visual Studio 2019 set(MSVC_VER 140) - elseif (MSVC_VERSION GREATER_EQUAL 1930 AND MSVC_VERSION LESS 1940) # Visual Studio 2022 + elseif (MSVC_VERSION GREATER_EQUAL 1930 AND MSVC_VERSION LESS 1950) # Visual Studio 2022 set(MSVC_VER 140) else (MSVC80) MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake") diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index f7f2981638..e1ee8df24f 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -124,13 +124,9 @@ public: // Listening on stdout is stateful. In general, we're either waiting // for the length prefix or waiting for the specified length of data. - // We address that with two different listener methods -- one of which - // is blocked at any given time. + mReadPrefix = true; mStdoutConnection = childout.getPump() - .listen("prefix", [this](const LLSD& data){ return rstdout(data); }); - mStdoutDataConnection = childout.getPump() - .listen("data", [this](const LLSD& data){ return rstdoutData(data); }); - mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection)); + .listen("LLLeap", [this](const LLSD& data){ return rstdout(data); }); // Log anything sent up through stderr. When a typical program // encounters an error, it writes its error message to stderr and @@ -251,120 +247,120 @@ public: return false; } - // Initial state of stateful listening on child stdout: wait for a length - // prefix, followed by ':'. - bool rstdout(const LLSD& data) + // Stateful listening on child stdout: + // wait for a length prefix, followed by ':'. + bool rstdout(const LLSD&) { LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT)); - // It's possible we got notified of a couple digit characters without - // seeing the ':' -- unlikely, but still. Until we see ':', keep - // waiting. - if (childout.contains(':')) + while (childout.size()) { - std::istream& childstream(childout.get_istream()); - // Saw ':', read length prefix and store in mExpect. - size_t expect; - childstream >> expect; - int colon(childstream.get()); - if (colon != ':') + /*----------------- waiting for length prefix ------------------*/ + if (mReadPrefix) { - // Protocol failure. Clear out the rest of the pending data in - // childout (well, up to a max length) to log what was wrong. - LLProcess::ReadPipe::size_type - readlen((std::min)(childout.size(), LLProcess::ReadPipe::size_type(80))); - bad_protocol(STRINGIZE(expect << char(colon) << childout.read(readlen))); + // It's possible we got notified of a couple digit characters without + // seeing the ':' -- unlikely, but still. Until we see ':', keep + // waiting. + if (! childout.contains(':')) + { + if (childout.contains('\n')) + { + // Since this is the initial listening state, this is where we'd + // arrive if the child isn't following protocol at all -- say + // because the user specified 'ls' or some darn thing. + bad_protocol(childout.getline()); + } + // Either way, stop looping. + break; + } + + // Saw ':', read length prefix and store in mExpect. + std::istream& childstream(childout.get_istream()); + size_t expect; + childstream >> expect; + int colon(childstream.get()); + if (colon != ':') + { + // Protocol failure. Clear out the rest of the pending data in + // childout (well, up to a max length) to log what was wrong. + LLProcess::ReadPipe::size_type + readlen((std::min)(childout.size(), + LLProcess::ReadPipe::size_type(80))); + bad_protocol(stringize(expect, char(colon), childout.read(readlen))); + break; + } + else + { + // Saw length prefix, saw colon, life is good. Now wait for + // that length of data to arrive. + mExpect = expect; + LL_DEBUGS("LLLeap") << "got length, waiting for " + << mExpect << " bytes of data" << LL_ENDL; + // Transition to "read data" mode and loop back to check + // if we've already received all the advertised data. + mReadPrefix = false; + continue; + } } + /*----------------- saw prefix, wait for data ------------------*/ else { - // Saw length prefix, saw colon, life is good. Now wait for - // that length of data to arrive. - mExpect = expect; - LL_DEBUGS("LLLeap") << "got length, waiting for " - << mExpect << " bytes of data" << LL_ENDL; - // Block calls to this method; resetting mBlocker unblocks - // calls to the other method. - mBlocker.reset(new LLEventPump::Blocker(mStdoutConnection)); - // Go check if we've already received all the advertised data. - if (childout.size()) + // Until we've accumulated the promised length of data, keep waiting. + if (childout.size() < mExpect) { - LLSD updata(data); - updata["len"] = LLSD::Integer(childout.size()); - rstdoutData(updata); + break; } - } - } - else if (childout.contains('\n')) - { - // Since this is the initial listening state, this is where we'd - // arrive if the child isn't following protocol at all -- say - // because the user specified 'ls' or some darn thing. - bad_protocol(childout.getline()); - } - return false; - } - // State in which we listen on stdout for the specified length of data to - // arrive. - bool rstdoutData(const LLSD& data) - { - LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT)); - // Until we've accumulated the promised length of data, keep waiting. - if (childout.size() >= mExpect) - { - // Ready to rock and roll. - LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got " - << childout.size() << ", parsing LLSD" << LL_ENDL; - LLSD data; + // We have the data we were told to expect! Ready to rock and roll. + LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got " + << childout.size() << ", parsing LLSD" << LL_ENDL; + LLSD data; #if 1 - // specifically require notation LLSD from child - LLPointer<LLSDParser> parser(new LLSDNotationParser()); - S32 parse_status(parser->parse(childout.get_istream(), data, mExpect)); - if (parse_status == LLSDParser::PARSE_FAILURE) + // specifically require notation LLSD from child + LLPointer<LLSDParser> parser(new LLSDNotationParser()); + S32 parse_status(parser->parse(childout.get_istream(), data, mExpect)); + if (parse_status == LLSDParser::PARSE_FAILURE) #else - // SL-18330: accept any valid LLSD serialization format from child - // Unfortunately this runs into trouble we have not yet debugged. - bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect)); - if (! parse_status) + // SL-18330: accept any valid LLSD serialization format from child + // Unfortunately this runs into trouble we have not yet debugged. + bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect)); + if (! parse_status) #endif - { - bad_protocol("unparseable LLSD data"); - } - else if (! (data.isMap() && data["pump"].isString() && data.has("data"))) - { - // we got an LLSD object, but it lacks required keys - bad_protocol("missing 'pump' or 'data'"); - } - else - { - try { - // The LLSD object we got from our stream contains the - // keys we need. - LLEventPumps::instance().obtain(data["pump"]).post(data["data"]); + bad_protocol("unparseable LLSD data"); + break; } - catch (const std::exception& err) + else if (! (data.isMap() && data["pump"].isString() && data.has("data"))) { - // No plugin should be allowed to crash the viewer by - // driving an exception -- intentionally or not. - LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data)); - // Whether or not the plugin added a "reply" key to the - // request, send a reply. We happen to know who originated - // this request, and the reply LLEventPump of interest. - // Not our problem if the plugin ignores the reply event. - data["reply"] = mListener->getReplyPump().getName(); - sendReply(llsd::map("error", - stringize(LLError::Log::classname(err), ": ", err.what())), - data); + // we got an LLSD object, but it lacks required keys + bad_protocol("missing 'pump' or 'data'"); + break; } - // Block calls to this method; resetting mBlocker unblocks - // calls to the other method. - mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection)); - // Go check for any more pending events in the buffer. - if (childout.size()) + else { - LLSD updata(data); - data["len"] = LLSD::Integer(childout.size()); - rstdout(updata); + try + { + // The LLSD object we got from our stream contains the + // keys we need. + LLEventPumps::instance().obtain(data["pump"]).post(data["data"]); + } + catch (const std::exception& err) + { + // No plugin should be allowed to crash the viewer by + // driving an exception -- intentionally or not. + LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data)); + // Whether or not the plugin added a "reply" key to the + // request, send a reply. We happen to know who originated + // this request, and the reply LLEventPump of interest. + // Not our problem if the plugin ignores the reply event. + data["reply"] = mReplyPump.getName(); + sendReply(llsd::map("error", + stringize(LLError::Log::classname(err), ": ", err.what())), + data); + } + // Transition to "read prefix" mode and go check for any + // more pending events in the buffer. + mReadPrefix = true; + continue; } } } @@ -444,11 +440,12 @@ private: std::string mDesc; LLEventStream mDonePump; LLProcessPtr mChild; - LLTempBoundListener mStdoutConnection, mStdoutDataConnection, mStderrConnection; - std::unique_ptr<LLEventPump::Blocker> mBlocker; + LLTempBoundListener + mStdinConnection, mStdoutConnection, mStderrConnection; LLProcess::ReadPipe::size_type mExpect; LLError::RecorderPtr mRecorder; std::unique_ptr<LLLeapListener> mListener; + bool mReadPrefix; }; // These must follow the declaration of LLLeapImpl, so they may as well be last. |