From f627140cf11232bab11fdfaf66c78544cf44f3e8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 19 Jun 2020 12:33:15 -0400 Subject: [PATCH 01/18] DRTVWR-476, SL-13467: Make LLTrace::BlockTimerStatHandle keys unique. There are duplicate LLTrace::BlockTimerStatHandle key strings declared in llsettingsdaycycle.cpp and llsettingswater.cpp -- the only instances of duplicate BlockTimerStatHandle keys in the viewer code base. SL-13467 tracks intentional crashes due to duplicate LLInstanceTracker subclass instances with one of those keys. The simplest experiment to try to eliminate those crashes is to ensure that every BlockTimerStatHandle in the code base is unique. --- indra/llinventory/llsettingsdaycycle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp index 457e5b7478..a687fd840d 100644 --- a/indra/llinventory/llsettingsdaycycle.cpp +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -41,8 +41,8 @@ //========================================================================= namespace { - LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment"); - LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment"); + LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment Day"); + LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment Day"); template inline T get_wrapping_distance(T begin, T end) From 80ef11de7114fcca5ceeec65e4441d88d325cb58 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 23 Jun 2020 22:06:21 -0400 Subject: [PATCH 02/18] DRTVWR-476: Update to dullahan build 544068 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 51148027b8..f21af38eb6 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - 350866eec6be17ffc265904b91dcfe6b + 027602feea00ff96168da83f51c6e1dd url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60900/572290/dullahan-1.7.0.202005311125_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-543086.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62276/587629/dullahan-1.7.0.202006231856_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-544068.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - aa4faf9ef9057362d63f8d57092506b3 + a64683f2fa3c5f678e2706780e8f9c16 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60902/572301/dullahan-1.7.0.202005311828_81.3.10_gb223419_chromium-81.0.4044.138-windows-543086.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62278/587640/dullahan-1.7.0.202006240158_81.3.10_gb223419_chromium-81.0.4044.138-windows-544068.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 6e29ea2ccdad80dcf1b5dc974932c1f6 + e6352df9db002fe8c2fbffe534ea5219 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60901/572302/dullahan-1.7.0.202005311828_81.3.10_gb223419_chromium-81.0.4044.138-windows64-543086.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62277/587642/dullahan-1.7.0.202006240158_81.3.10_gb223419_chromium-81.0.4044.138-windows64-544068.tar.bz2 name windows64 version - 1.7.0.202005311828_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202006231856_81.3.10_gb223419_chromium-81.0.4044.138 elfio From b594b05b0afe767324dee1922a19c2364c5e5bb3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 24 Jun 2020 09:16:00 -0400 Subject: [PATCH 03/18] DRTVWR-476: Update to dullahan build 544081 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index f21af38eb6..5778d3352e 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - 027602feea00ff96168da83f51c6e1dd + 45d5d040ef6dcbda1b99df37a9b10539 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62276/587629/dullahan-1.7.0.202006231856_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-544068.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62310/587969/dullahan-1.7.0.202006240610_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-544081.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - a64683f2fa3c5f678e2706780e8f9c16 + 4389a02fbe33050709fed40d5882dba3 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62278/587640/dullahan-1.7.0.202006240158_81.3.10_gb223419_chromium-81.0.4044.138-windows-544068.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62312/587967/dullahan-1.7.0.202006241309_81.3.10_gb223419_chromium-81.0.4044.138-windows-544081.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - e6352df9db002fe8c2fbffe534ea5219 + 837aa99560391a8ab43db6bebb4bc06c url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62277/587642/dullahan-1.7.0.202006240158_81.3.10_gb223419_chromium-81.0.4044.138-windows64-544068.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62311/587968/dullahan-1.7.0.202006241310_81.3.10_gb223419_chromium-81.0.4044.138-windows64-544081.tar.bz2 name windows64 version - 1.7.0.202006231856_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202006240610_81.3.10_gb223419_chromium-81.0.4044.138 elfio From e83613157b66dc7d44fe545feb92719746067c82 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 24 Jun 2020 12:03:28 -0400 Subject: [PATCH 04/18] DRTVWR-476: Update to dullahan build 544091 --- autobuild.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 5778d3352e..738c77b30b 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -580,9 +580,9 @@ archive hash - 45d5d040ef6dcbda1b99df37a9b10539 + e145f8ea99a21712434e0e868d1885dc url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62310/587969/dullahan-1.7.0.202006240610_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-544081.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62333/588183/dullahan-1.7.0.202006240858_81.3.10_gb223419_chromium-81.0.4044.138-darwin64-544091.tar.bz2 name darwin64 @@ -592,9 +592,9 @@ archive hash - 4389a02fbe33050709fed40d5882dba3 + fdbbbfc377e28cba664f2b1c54ea6086 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62312/587967/dullahan-1.7.0.202006241309_81.3.10_gb223419_chromium-81.0.4044.138-windows-544081.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62331/588162/dullahan-1.7.0.202006241556_81.3.10_gb223419_chromium-81.0.4044.138-windows-544091.tar.bz2 name windows @@ -604,16 +604,16 @@ archive hash - 837aa99560391a8ab43db6bebb4bc06c + d85a32d905b199534e8feafa34b28e39 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62311/587968/dullahan-1.7.0.202006241310_81.3.10_gb223419_chromium-81.0.4044.138-windows64-544081.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/62332/588168/dullahan-1.7.0.202006241556_81.3.10_gb223419_chromium-81.0.4044.138-windows64-544091.tar.bz2 name windows64 version - 1.7.0.202006240610_81.3.10_gb223419_chromium-81.0.4044.138 + 1.7.0.202006240858_81.3.10_gb223419_chromium-81.0.4044.138 elfio From 1231cb4585290a26e29cca221f7c81fda3e2c623 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 25 Jun 2020 20:59:04 -0400 Subject: [PATCH 05/18] DRTVWR-476, SL-13512: Make suspendUntilTimeout() notice shutdown. Specifically, the shutdown crash reported in SL-13512 was due to LLExperienceCache::idleCoro() looping on suspendUntilTimeout(), failing to notice in its slumbers that the viewer was shutting down around it. Make suspendUntilTimeout() internally call suspendUntilEventOnWithTimeout(), which already listens for "LLApp" state-change events and throws Stopping when LLApp enters its shutdown sequence. --- indra/llcommon/lleventcoro.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 11b6e5bb2f..bc02ab99de 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -116,12 +116,21 @@ void llcoro::suspend() void llcoro::suspendUntilTimeout(float seconds) { LLCoros::checkStop(); - // The fact that we accept non-integer seconds means we should probably - // use granularity finer than one second. However, given the overhead of - // the rest of our processing, it seems silly to use granularity finer - // than a millisecond. - LLCoros::TempStatus st(STRINGIZE("waiting for " << seconds << "s")); - boost::this_fiber::sleep_for(std::chrono::milliseconds(long(seconds * 1000))); + // We used to call boost::this_fiber::sleep_for(). But some coroutines + // (e.g. LLExperienceCache::idleCoro()) sit in a suspendUntilTimeout() + // loop, in which case a sleep_for() call risks sleeping through shutdown. + // So instead, listen for "LLApp" state-changing events -- which + // fortunately is handled for us by suspendUntilEventOnWithTimeout(). + // Wait for an event on a bogus LLEventPump on which nobody ever posts + // events. Don't make it static because that would force instantiation of + // the LLEventPumps LLSingleton registry at static initialization time. + LLEventStream bogus("xyzzy"); // could use an LLUUID if it matters + // Timeout is the NORMAL case for this call! + static LLSD timedout; + // Deliver, but ignore, timedout when (as usual) we did not receive any + // "LLApp" event. The point is that suspendUntilEventOnWithTimeout() will + // itself throw Stopping when "LLApp" starts broadcasting shutdown events. + suspendUntilEventOnWithTimeout(bogus, seconds, timedout); } namespace @@ -276,6 +285,10 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, { LLCoros::TempStatus st(STRINGIZE("waiting for " << replyPump.getPump().getName() << " for " << timeout << "s")); + // The fact that we accept non-integer seconds means we should probably + // use granularity finer than one second. However, given the overhead of + // the rest of our processing, it seems silly to use granularity finer + // than a millisecond. status = future.wait_for(std::chrono::milliseconds(long(timeout * 1000))); } // if the future is NOT yet ready, return timeoutResult instead From e7d3b7cc9356dcf76b5f9a1bf4c9c833d180b2f8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 26 Jun 2020 11:16:38 -0400 Subject: [PATCH 06/18] DRTVWR-476: On Windows, request 64-bit compiler to avoid TeamCity build failures due to 32-bit compiler running out of virtual memory for precompiled headers. --- indra/cmake/00-Common.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 03da30649a..865c057e33 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -60,7 +60,10 @@ if (WINDOWS) # http://www.cmake.org/pipermail/cmake/2009-September/032143.html string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + # Without PreferredToolArchitecture=x64, as of 2020-06-26 the 32-bit + # compiler on our TeamCity build hosts has started running out of virtual + # memory for the precompiled header file. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /p:PreferredToolArchitecture=x64") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" From 75b5f72e6951cae855a6abacc110a886e0ae701c Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 26 Jun 2020 14:40:07 -0400 Subject: [PATCH 07/18] DRTVWR-476, SL-13512: Fix flawed fix for former failure. Specifically, llcoro::suspendUntilTimeout() is definitely called concurrently by multiple coroutines. New code that instantiates a local LLEventStream must allow the name to be tweaked for uniqueness. --- indra/llcommon/lleventcoro.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index bc02ab99de..995356dc52 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -124,7 +124,11 @@ void llcoro::suspendUntilTimeout(float seconds) // Wait for an event on a bogus LLEventPump on which nobody ever posts // events. Don't make it static because that would force instantiation of // the LLEventPumps LLSingleton registry at static initialization time. - LLEventStream bogus("xyzzy"); // could use an LLUUID if it matters + // DO allow tweaking the name for uniqueness, this definitely gets + // re-entered on multiple coroutines! + // We could use an LLUUID if it were important to actively prohibit anyone + // from ever posting on this LLEventPump. + LLEventStream bogus("xyzzy", true); // Timeout is the NORMAL case for this call! static LLSD timedout; // Deliver, but ignore, timedout when (as usual) we did not receive any From e2dd15397c709a3a37e70942d40373f5476a434b Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 20 May 2020 15:37:21 -0700 Subject: [PATCH 08/18] SL-9756: Take the "session_id" from the offline message that was passed. --- indra/newview/llimprocessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 6da7bbe263..b534fc0b4a 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1608,7 +1608,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) message_data["to_agent_id"].asUUID(), IM_OFFLINE, (EInstantMessage)message_data["dialog"].asInteger(), - LLUUID::null, // session id, since there is none we can only use frienship/group invite caps + message_data["session_id"].asUUID(), message_data["timestamp"].asInteger(), message_data["from_agent_name"].asString(), message_data["message"].asString(), From c8b7466c1999cc834b90c9aed76d8548b66032c6 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Mon, 8 Jun 2020 11:28:05 -0700 Subject: [PATCH 09/18] SL-11430, SL-9756: Take transaction-id from offline messages. Correct LLSD names. Use offline flag rather than implicit tests of session_id and aux_id. --- indra/newview/llimprocessing.cpp | 63 ++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index b534fc0b4a..60f1de4e8c 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -857,7 +857,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) + if (offline) { // cap received offline message std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); @@ -889,9 +889,10 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, info->mIM = dialog; info->mFromID = from_id; info->mFromGroup = from_group; - info->mTransactionID = session_id; info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + info->mTransactionID = session_id.notNull() ? session_id : aux_id; + info->mFromName = name; info->mDesc = message; info->mHost = sender; @@ -1569,7 +1570,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) return; } - if (gAgent.getRegion() == NULL) + if (!gAgent.getRegion()) { LL_WARNS("Messaging") << "Region null while attempting to load messages." << LL_ENDL; return; @@ -1577,8 +1578,8 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; - std::vector data; - S32 binary_bucket_size = 0; +// std::vector data; +// S32 binary_bucket_size = 0; LLHost sender = gAgent.getRegionHost(); LLSD::array_iterator i = messages.beginArray(); @@ -1587,38 +1588,46 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) { const LLSD &message_data(*i); - LLVector3 position(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); - data = message_data["binary_bucket"].asBinary(); - binary_bucket_size = data.size(); // message_data["count"] always 0 - U32 parent_estate_id = message_data.has("parent_estate_id") ? message_data["parent_estate_id"].asInteger() : 1; // 1 - IMMainland - - // Todo: once dirtsim-369 releases, remove one of the int/str options - BOOL from_group; - if (message_data["from_group"].isInteger()) + /* RIDER: Many fields in this message are using a '_' rather than the standard '-'. This + * should be changed but would require tight coordination with the simulator. + */ + LLVector3 position; + if (message_data.has("position")) { - from_group = message_data["from_group"].asInteger(); + position.setValue(message_data["position"]); } else { - from_group = message_data["from_group"].asString() == "Y"; + position.set(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); } - LLIMProcessing::processNewMessage(message_data["from_agent_id"].asUUID(), - from_group, + std::vector bin_bucket; + if (message_data.has("binary_bucket")) + { + bin_bucket = message_data["binary_bucket"].asBinary(); + } + else + { + bin_bucket.push_back(0); + } + + LLIMProcessing::processNewMessage( + message_data["from_id"].asUUID(), + message_data["from_group"].asBoolean(), message_data["to_agent_id"].asUUID(), - IM_OFFLINE, - (EInstantMessage)message_data["dialog"].asInteger(), - message_data["session_id"].asUUID(), - message_data["timestamp"].asInteger(), - message_data["from_agent_name"].asString(), - message_data["message"].asString(), - parent_estate_id, + static_cast(message_data["offline"].asInteger()), + static_cast(message_data["dialog"].asInteger()), + message_data["transaction-id"].asUUID(), + static_cast(message_data["timestamp"].asInteger()), + message_data["from_name"].asString(), + (message_data.has("message")) ? message_data["message"].asString() : std::string(), + static_cast((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland message_data["region_id"].asUUID(), position, - &data[0], - binary_bucket_size, + bin_bucket.data(), + bin_bucket.size(), sender, - message_data["asset_id"].asUUID()); // not necessarily an asset + message_data["asset_id"].asUUID()); } } From f8e53adce7c089abe9a50c353d14f7a548ce3f95 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Thu, 18 Jun 2020 12:56:00 -0700 Subject: [PATCH 10/18] SL-9756: Get session_id/transaction id from aux if session is missing. --- indra/newview/llimprocessing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 60f1de4e8c..c274267b21 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1628,6 +1628,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) bin_bucket.size(), sender, message_data["asset_id"].asUUID()); + } } From f72759c16d74d6a996b4b63f610b50c80c3db825 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Mon, 22 Jun 2020 10:55:05 -0700 Subject: [PATCH 11/18] SL-9756: IM_TASK_INVENTORY_OFFERED bucket offline format conforms to the online format. --- indra/newview/llimprocessing.cpp | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index c274267b21..a2900c553c 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -857,33 +857,15 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (offline) + if (sizeof(S8) != binary_bucket_size) { - // cap received offline message - std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(str_bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); - // Note There is more elements in 'tokens' ... - - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } - else - { - if (sizeof(S8) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; - } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; + LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; + delete info; + break; } + info->mType = (LLAssetType::EType) binary_bucket[0]; + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; } info->mIM = dialog; From 01f2308c85dd02d199072006e6b9ff42c90a1986 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Mon, 22 Jun 2020 16:08:11 -0700 Subject: [PATCH 12/18] SL-9756: Get the LLSD names right. --- indra/newview/llimprocessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index a2900c553c..fc209c2eae 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1594,7 +1594,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) } LLIMProcessing::processNewMessage( - message_data["from_id"].asUUID(), + message_data["from_agent_id"].asUUID(), message_data["from_group"].asBoolean(), message_data["to_agent_id"].asUUID(), static_cast(message_data["offline"].asInteger()), From 4708662091760f90a7782b726a5a7d89f376ce53 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 2 Jun 2020 10:29:15 -0400 Subject: [PATCH 13/18] SL-13361: Distill redundant create_console() code to set_stream(). There are separate stanzas in llappviewerwin32.cpp's create_console() function for each of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and STD_ERROR_HANDLE. SL-13361 wants to add more code to each. Factor out new local set_stream() function and make create_console() call it three times. (cherry picked from commit 13b78a0c5a788c617866e3530c65dae616e6520f) --- indra/newview/llappviewerwin32.cpp | 59 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9a8a5f16bb..1f66177c37 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -501,11 +501,12 @@ void LLAppViewerWin32::disableWinErrorReporting() const S32 MAX_CONSOLE_LINES = 500; -static bool create_console() -{ - int h_con_handle; - intptr_t l_std_handle; +namespace { +FILE* set_stream(const char* which, DWORD handle_id, const char* mode); + +bool create_console() +{ CONSOLE_SCREEN_BUFFER_INFO coninfo; FILE *fp; @@ -518,50 +519,48 @@ static bool create_console() SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); // redirect unbuffered STDOUT to the console - l_std_handle = reinterpret_cast(GetStdHandle(STD_OUTPUT_HANDLE)); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) + FILE* fp = set_stream("stdout", STD_OUTPUT_HANDLE, "w"); + if (fp) { - LL_WARNS() << "create_console() failed to open stdout handle" << LL_ENDL; - } - else - { - fp = _fdopen( h_con_handle, "w" ); *stdout = *fp; - setvbuf( stdout, NULL, _IONBF, 0 ); } // redirect unbuffered STDIN to the console - l_std_handle = reinterpret_cast(GetStdHandle(STD_INPUT_HANDLE)); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) + fp = set_stream("stdin", STD_INPUT_HANDLE, "r"); + if (fp) { - LL_WARNS() << "create_console() failed to open stdin handle" << LL_ENDL; - } - else - { - fp = _fdopen( h_con_handle, "r" ); *stdin = *fp; - setvbuf( stdin, NULL, _IONBF, 0 ); } // redirect unbuffered STDERR to the console - l_std_handle = reinterpret_cast(GetStdHandle(STD_ERROR_HANDLE)); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); + fp = set_stream("stderr", STD_ERROR_HANDLE, "w"); + if (fp) + { + *stderr = *fp; + } + + return isConsoleAllocated; +} + +FILE* set_stream(const char* which, DWORD handle_id, const char* mode) +{ + long l_std_handle = (long)GetStdHandle(handle_id); + int h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); if (h_con_handle == -1) { - LL_WARNS() << "create_console() failed to open stderr handle" << LL_ENDL; + LL_WARNS() << "create_console() failed to open " << which << " handle" << LL_ENDL; + return nullptr; } else { - fp = _fdopen( h_con_handle, "w" ); - *stderr = *fp; - setvbuf( stderr, NULL, _IONBF, 0 ); + FILE* fp = _fdopen( h_con_handle, mode ); + setvbuf( fp, NULL, _IONBF, 0 ); + return fp; } - - return isConsoleAllocated; } +} // anonymous namespace + LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : mCmdLine(cmd_line), mIsConsoleAllocated(false) From d8649dbb8a5a20753248923a25c13f729cadd99a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 2 Jun 2020 16:44:22 -0400 Subject: [PATCH 14/18] SL-13361: Enable color processing on Windows 10 debug console. (cherry picked from commit 0b61150e698537a7e42a4cdae02496da500399d9) --- indra/llcommon/llerror.cpp | 5 ++--- indra/newview/llappviewerwin32.cpp | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 41c4ddc725..411412c883 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -40,6 +40,8 @@ # include # include # include +#else +# include #endif // !LL_WINDOWS #include #include "string.h" @@ -236,14 +238,11 @@ namespace { static bool checkANSI(void) { -#if LL_LINUX || LL_DARWIN // Check whether it's okay to use ANSI; if stderr is // a tty then we assume yes. Can be turned off with // the LL_NO_ANSI_COLOR env var. return (0 != isatty(2)) && (NULL == getenv("LL_NO_ANSI_COLOR")); -#endif // LL_LINUX - return FALSE; // works in a cygwin shell... ;) } }; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 1f66177c37..f0aa355342 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -500,6 +500,10 @@ void LLAppViewerWin32::disableWinErrorReporting() } const S32 MAX_CONSOLE_LINES = 500; +// Only defined in newer SDKs than we currently use +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 +#endif namespace { @@ -507,13 +511,11 @@ FILE* set_stream(const char* which, DWORD handle_id, const char* mode); bool create_console() { - CONSOLE_SCREEN_BUFFER_INFO coninfo; - FILE *fp; - // allocate a console for this app const bool isConsoleAllocated = AllocConsole(); // set the screen buffer to be big enough to let us scroll text + CONSOLE_SCREEN_BUFFER_INFO coninfo; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); coninfo.dwSize.Y = MAX_CONSOLE_LINES; SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); @@ -542,19 +544,24 @@ bool create_console() return isConsoleAllocated; } -FILE* set_stream(const char* which, DWORD handle_id, const char* mode) +FILE* set_stream(const char* desc, DWORD handle_id, const char* mode) { - long l_std_handle = (long)GetStdHandle(handle_id); - int h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); + auto l_std_handle = GetStdHandle(handle_id); + int h_con_handle = _open_osfhandle(reinterpret_cast(l_std_handle), _O_TEXT); if (h_con_handle == -1) { - LL_WARNS() << "create_console() failed to open " << which << " handle" << LL_ENDL; + LL_WARNS() << "create_console() failed to open " << desc << " handle" << LL_ENDL; return nullptr; } else { FILE* fp = _fdopen( h_con_handle, mode ); setvbuf( fp, NULL, _IONBF, 0 ); + // Enable color processing on Windows 10 console windows. + DWORD dwMode = 0; + GetConsoleMode(l_std_handle, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(l_std_handle, dwMode); return fp; } } From 01128f9f945f20bc3c472ed953cb0c0fae6ce407 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 1 Jul 2020 16:29:59 -0400 Subject: [PATCH 15/18] DRTVWR-476, SL-13528: Use freopen_s() instead of assigning stderr. The llappviewerwin32.cpp create_console() function called by LLAppViewerWin32::initConsole() used to assign *stderr = *(new FILE* value), and so forth for stdout and stdin. That dubious tactic no longer works with the new Windows CRT introduced with VS 2015. freopen_s() works much better. --- indra/newview/llappviewerwin32.cpp | 98 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f0aa355342..156a1c5893 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -507,63 +507,65 @@ const S32 MAX_CONSOLE_LINES = 500; namespace { -FILE* set_stream(const char* which, DWORD handle_id, const char* mode); +void set_stream(const char* desc, FILE* fp, DWORD handle_id, const char* name, const char* mode="w"); bool create_console() { - // allocate a console for this app - const bool isConsoleAllocated = AllocConsole(); + // allocate a console for this app + const bool isConsoleAllocated = AllocConsole(); - // set the screen buffer to be big enough to let us scroll text - CONSOLE_SCREEN_BUFFER_INFO coninfo; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); - coninfo.dwSize.Y = MAX_CONSOLE_LINES; - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); + if (isConsoleAllocated) + { + // set the screen buffer to be big enough to let us scroll text + CONSOLE_SCREEN_BUFFER_INFO coninfo; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); + coninfo.dwSize.Y = MAX_CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); - // redirect unbuffered STDOUT to the console - FILE* fp = set_stream("stdout", STD_OUTPUT_HANDLE, "w"); - if (fp) - { - *stdout = *fp; - } + // redirect unbuffered STDOUT to the console + set_stream("stdout", stdout, STD_OUTPUT_HANDLE, "CONOUT$"); + // redirect unbuffered STDERR to the console + set_stream("stderr", stderr, STD_ERROR_HANDLE, "CONOUT$"); + // redirect unbuffered STDIN to the console + // Don't bother: our console is solely for log output. We never read stdin. +// set_stream("stdin", stdin, STD_INPUT_HANDLE, "CONIN$", "r"); + } - // redirect unbuffered STDIN to the console - fp = set_stream("stdin", STD_INPUT_HANDLE, "r"); - if (fp) - { - *stdin = *fp; - } - - // redirect unbuffered STDERR to the console - fp = set_stream("stderr", STD_ERROR_HANDLE, "w"); - if (fp) - { - *stderr = *fp; - } - - return isConsoleAllocated; + return isConsoleAllocated; } -FILE* set_stream(const char* desc, DWORD handle_id, const char* mode) +void set_stream(const char* desc, FILE* fp, DWORD handle_id, const char* name, const char* mode) { - auto l_std_handle = GetStdHandle(handle_id); - int h_con_handle = _open_osfhandle(reinterpret_cast(l_std_handle), _O_TEXT); - if (h_con_handle == -1) - { - LL_WARNS() << "create_console() failed to open " << desc << " handle" << LL_ENDL; - return nullptr; - } - else - { - FILE* fp = _fdopen( h_con_handle, mode ); - setvbuf( fp, NULL, _IONBF, 0 ); - // Enable color processing on Windows 10 console windows. - DWORD dwMode = 0; - GetConsoleMode(l_std_handle, &dwMode); - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(l_std_handle, dwMode); - return fp; - } + // SL-13528: This code used to be based on + // http://dslweb.nwnexus.com/~ast/dload/guicon.htm + // (referenced in https://stackoverflow.com/a/191880). + // But one of the comments on that StackOverflow answer points out that + // assigning to *stdout or *stderr "probably doesn't even work with the + // Universal CRT that was introduced in 2015," suggesting freopen_s() + // instead. Code below is based on https://stackoverflow.com/a/55875595. + auto std_handle = GetStdHandle(handle_id); + if (std_handle == INVALID_HANDLE_VALUE) + { + LL_WARNS() << "create_console() failed to get " << desc << " handle" << LL_ENDL; + } + else + { + if (mode == std::string("w")) + { + // Enable color processing on Windows 10 console windows. + DWORD dwMode = 0; + GetConsoleMode(std_handle, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(std_handle, dwMode); + } + // Redirect the passed fp to the console. + FILE* ignore; + if (freopen_s(&ignore, name, mode, fp) == 0) + { + // use unbuffered I/O + setvbuf( fp, NULL, _IONBF, 0 ); + } + } } } // anonymous namespace From 766b21a0a624ffb75c06801cf8ea3573e6dc4b5d Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 1 Jul 2020 16:52:44 -0700 Subject: [PATCH 16/18] SL-13533: Use the old name for from_agent_name SL-13540: Do not fail if binary bucket is too large, attempt to extract the asset type from the old style bucket. Notification still not shown. --- indra/newview/llimprocessing.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index fc209c2eae..301b4c9214 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -857,13 +857,28 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (sizeof(S8) != binary_bucket_size) + if (sizeof(S8) == binary_bucket_size) { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; + info->mType = (LLAssetType::EType) binary_bucket[0]; + } + else + { + /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we + // still might be able to figure out the type... even though the offer is not retrievable. + std::string str_bucket(reinterpret_cast(binary_bucket)); + std::string str_type(str_bucket.substr(0, str_bucket.find('|'))); + + std::stringstream type_convert(str_type); + + S32 type; + type_convert >> type; + + // We could try AT_UNKNOWN which would be more accurate, but that causes an auto decline + info->mType = static_cast(type); + // Don't break in the case of a bad binary bucket. Go ahead and show the + // accept/decline popup even though it will not do anything. + LL_WARNS("Messaging") << "Malformed inventory offer from object, type might be " << info->mType << LL_ENDL; } - info->mType = (LLAssetType::EType) binary_bucket[0]; info->mObjectID = LLUUID::null; info->mFromObject = TRUE; } @@ -1601,8 +1616,8 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) static_cast(message_data["dialog"].asInteger()), message_data["transaction-id"].asUUID(), static_cast(message_data["timestamp"].asInteger()), - message_data["from_name"].asString(), - (message_data.has("message")) ? message_data["message"].asString() : std::string(), + message_data["from_agent_name"].asString(), + message_data["message"].asString(), static_cast((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland message_data["region_id"].asUUID(), position, From bf5585c0ec9d6c2159a203ebdbd1b639689a5c50 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 Jul 2020 13:03:57 +0300 Subject: [PATCH 17/18] SL-13540 Offline scripted inventory offers not shown on non drtsim-451 --- indra/newview/llimprocessing.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 301b4c9214..5c9d53e0b9 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -865,6 +865,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, { /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we // still might be able to figure out the type... even though the offer is not retrievable. + + // Should be safe to remove once DRTSIM-451 fully deploys std::string str_bucket(reinterpret_cast(binary_bucket)); std::string str_type(str_bucket.substr(0, str_bucket.find('|'))); @@ -1575,8 +1577,6 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; -// std::vector data; -// S32 binary_bucket_size = 0; LLHost sender = gAgent.getRegionHost(); LLSD::array_iterator i = messages.beginArray(); @@ -1608,11 +1608,22 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) bin_bucket.push_back(0); } + // Todo: once drtsim-451 releases, remove the string option + BOOL from_group; + if (message_data["from_group"].isInteger()) + { + from_group = message_data["from_group"].asInteger(); + } + else + { + from_group = message_data["from_group"].asString() == "Y"; + } + LLIMProcessing::processNewMessage( message_data["from_agent_id"].asUUID(), - message_data["from_group"].asBoolean(), + from_group, message_data["to_agent_id"].asUUID(), - static_cast(message_data["offline"].asInteger()), + message_data.has("offline") ? static_cast(message_data["offline"].asInteger()) : IM_OFFLINE, static_cast(message_data["dialog"].asInteger()), message_data["transaction-id"].asUUID(), static_cast(message_data["timestamp"].asInteger()), From 87da08b1f49a600b0e1993b31e46b1808aa8fecf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 7 Jul 2020 14:48:36 -0400 Subject: [PATCH 18/18] DRTVWR-476, SL-13555: Don't crash if user closes viewer during login. Ever since February 2010, the body of the login coroutine function has been enclosed in try/catch (...), with an llerrs message to try to crash more informatively than the runtime's unhandled-exception termination. Over the years this evolved to LL_ERRS and then to CRASH_ON_UNHANDLED_EXCEPTION. This persisted despite the August 2016 addition of generic catch clauses in the LLCoros::toplevel() function to serve the same purpose, and despite the subsequent introduction of the LLCoros::Stop family of exceptions to deliberately throw into waiting coroutines on viewer shutdown. That's exactly what was happening. When the user closed the viewer while waiting for the response from login.cgi, the waiting operation threw LLCoros::Stopping, which was caught by that CRASH_ON_UNHANDLED_EXCEPTION, which crashed the viewer with LL_ERRS rather than propagating up to the toplevel() and cleanly terminating the coroutine. Change CRASH_ON_UNHANDLED_EXCEPTION() to LOG_UNHANDLED_EXCEPTION() and re-throw so toplevel() can handle. --- indra/llcommon/llcoros.h | 5 + indra/viewer_components/login/lllogin.cpp | 291 +++++++++++----------- 2 files changed, 152 insertions(+), 144 deletions(-) diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index d49a6e939c..38c2356c99 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -232,6 +232,11 @@ public: }; /// thrown by checkStop() + // It may sound ironic that Stop is derived from LLContinueError, but the + // point is that LLContinueError is the category of exception that should + // not immediately crash the viewer. Stop and its subclasses are to notify + // coroutines that the viewer intends to shut down. The expected response + // is to terminate the coroutine, rather than abort the viewer. struct Stop: public LLContinueError { Stop(const std::string& what): LLContinueError(what) {} diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 57a7c03525..d485203fa1 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -148,167 +148,170 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params) } try { - LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName() - << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL; + LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName() + << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL; - LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); - // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used - // to share them -- but the EXT-3934 fix made it possible for an abandoned - // SRV response to arrive just as we were expecting the XMLRPC response. - LLEventStream loginReplyPump("loginreply", true); + LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); + // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used + // to share them -- but the EXT-3934 fix made it possible for an abandoned + // SRV response to arrive just as we were expecting the XMLRPC response. + LLEventStream loginReplyPump("loginreply", true); - LLSD::Integer attempts = 0; + LLSD::Integer attempts = 0; - LLSD request(login_params); - request["reply"] = loginReplyPump.getName(); - request["uri"] = uri; - std::string status; + LLSD request(login_params); + request["reply"] = loginReplyPump.getName(); + request["uri"] = uri; + std::string status; - // Loop back to here if login attempt redirects to a different - // request["uri"] - for (;;) - { - ++attempts; - LLSD progress_data; - progress_data["attempt"] = attempts; - progress_data["request"] = request; - if (progress_data["request"].has("params") - && progress_data["request"]["params"].has("passwd")) + // Loop back to here if login attempt redirects to a different + // request["uri"] + for (;;) { - progress_data["request"]["params"]["passwd"] = "*******"; - } - sendProgressEvent("offline", "authenticating", progress_data); - - // We expect zero or more "Downloading" status events, followed by - // exactly one event with some other status. Use postAndSuspend() the - // first time, because -- at least in unit-test land -- it's - // possible for the reply to arrive before the post() call - // returns. Subsequent responses, of course, must be awaited - // without posting again. - for (mAuthResponse = validateResponse(loginReplyPump.getName(), - llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply")); - mAuthResponse["status"].asString() == "Downloading"; - mAuthResponse = validateResponse(loginReplyPump.getName(), - llcoro::suspendUntilEventOn(loginReplyPump))) - { - // Still Downloading -- send progress update. - sendProgressEvent("offline", "downloading"); - } - - LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; - status = mAuthResponse["status"].asString(); - - // Okay, we've received our final status event for this - // request. Unless we got a redirect response, break the retry - // loop for the current rewrittenURIs entry. - if (!(status == "Complete" && - mAuthResponse["responses"]["login"].asString() == "indeterminate")) - { - break; - } - - sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); - - // Here the login service at the current URI is redirecting us - // to some other URI ("indeterminate" -- why not "redirect"?). - // The response should contain another uri to try, with its - // own auth method. - request["uri"] = mAuthResponse["responses"]["next_url"].asString(); - request["method"] = mAuthResponse["responses"]["next_method"].asString(); - } // loop back to try the redirected URI - - // Here we're done with redirects. - if (status == "Complete") - { - // StatusComplete does not imply auth success. Check the - // actual outcome of the request. We've already handled the - // "indeterminate" case in the loop above. - if (mAuthResponse["responses"]["login"].asString() == "true") - { - sendProgressEvent("online", "connect", mAuthResponse["responses"]); - } - else - { - // Synchronize here with the updater. We synchronize here rather - // than in the fail.login handler, which actually examines the - // response from login.cgi, because here we are definitely in a - // coroutine and can definitely use suspendUntilBlah(). Whoever's - // listening for fail.login might not be. - - // If the reason for login failure is that we must install a - // required update, we definitely want to pass control to the - // updater to manage that for us. We'll handle any other login - // failure ourselves, as usual. We figure that no matter where you - // are in the world, or what kind of network you're on, we can - // reasonably expect the Viewer Version Manager to respond more or - // less as quickly as login.cgi. This synchronization is only - // intended to smooth out minor races between the two services. - // But what if the updater crashes? Use a timeout so that - // eventually we'll tire of waiting for it and carry on as usual. - // Given the above, it can be a fairly short timeout, at least - // from a human point of view. - - // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to - // consume the posted event. - LLCoros::OverrideConsuming oc(true); - // Timeout should produce the isUndefined() object passed here. - LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL; - LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD()); - if (updater.isUndefined()) + ++attempts; + LLSD progress_data; + progress_data["attempt"] = attempts; + progress_data["request"] = request; + if (progress_data["request"].has("params") + && progress_data["request"]["params"].has("passwd")) { - LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login" - << LL_ENDL; + progress_data["request"]["params"]["passwd"] = "*******"; + } + sendProgressEvent("offline", "authenticating", progress_data); + + // We expect zero or more "Downloading" status events, followed by + // exactly one event with some other status. Use postAndSuspend() the + // first time, because -- at least in unit-test land -- it's + // possible for the reply to arrive before the post() call + // returns. Subsequent responses, of course, must be awaited + // without posting again. + for (mAuthResponse = validateResponse(loginReplyPump.getName(), + llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply")); + mAuthResponse["status"].asString() == "Downloading"; + mAuthResponse = validateResponse(loginReplyPump.getName(), + llcoro::suspendUntilEventOn(loginReplyPump))) + { + // Still Downloading -- send progress update. + sendProgressEvent("offline", "downloading"); + } + + LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL; + status = mAuthResponse["status"].asString(); + + // Okay, we've received our final status event for this + // request. Unless we got a redirect response, break the retry + // loop for the current rewrittenURIs entry. + if (!(status == "Complete" && + mAuthResponse["responses"]["login"].asString() == "indeterminate")) + { + break; + } + + sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]); + + // Here the login service at the current URI is redirecting us + // to some other URI ("indeterminate" -- why not "redirect"?). + // The response should contain another uri to try, with its + // own auth method. + request["uri"] = mAuthResponse["responses"]["next_url"].asString(); + request["method"] = mAuthResponse["responses"]["next_method"].asString(); + } // loop back to try the redirected URI + + // Here we're done with redirects. + if (status == "Complete") + { + // StatusComplete does not imply auth success. Check the + // actual outcome of the request. We've already handled the + // "indeterminate" case in the loop above. + if (mAuthResponse["responses"]["login"].asString() == "true") + { + sendProgressEvent("online", "connect", mAuthResponse["responses"]); } else { - LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL; + // Synchronize here with the updater. We synchronize here rather + // than in the fail.login handler, which actually examines the + // response from login.cgi, because here we are definitely in a + // coroutine and can definitely use suspendUntilBlah(). Whoever's + // listening for fail.login might not be. + + // If the reason for login failure is that we must install a + // required update, we definitely want to pass control to the + // updater to manage that for us. We'll handle any other login + // failure ourselves, as usual. We figure that no matter where you + // are in the world, or what kind of network you're on, we can + // reasonably expect the Viewer Version Manager to respond more or + // less as quickly as login.cgi. This synchronization is only + // intended to smooth out minor races between the two services. + // But what if the updater crashes? Use a timeout so that + // eventually we'll tire of waiting for it and carry on as usual. + // Given the above, it can be a fairly short timeout, at least + // from a human point of view. + + // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to + // consume the posted event. + LLCoros::OverrideConsuming oc(true); + // Timeout should produce the isUndefined() object passed here. + LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL; + LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD()); + if (updater.isUndefined()) + { + LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login" + << LL_ENDL; + } + else + { + LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL; + } + // Let the fail.login handler deal with empty updater response. + LLSD responses(mAuthResponse["responses"]); + responses["updater"] = updater; + sendProgressEvent("offline", "fail.login", responses); } - // Let the fail.login handler deal with empty updater response. - LLSD responses(mAuthResponse["responses"]); - responses["updater"] = updater; - sendProgressEvent("offline", "fail.login", responses); + return; // Done! } - return; // Done! - } -// /* Sometimes we end with "Started" here. Slightly slow server? -// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below. -// */ -// if( status == "Started") -// { -// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL; -// continue; -// } +/*==========================================================================*| + // Sometimes we end with "Started" here. Slightly slow server? Seems + // to be ok to just skip it. Otherwise we'd error out and crash in the + // if below. + if( status == "Started") + { + LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL; + continue; + } +|*==========================================================================*/ - // If we don't recognize status at all, trouble - if (! (status == "CURLError" - || status == "XMLRPCError" - || status == "OtherError")) - { - LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: " - << mAuthResponse << LL_ENDL; - return; - } + // If we don't recognize status at all, trouble + if (! (status == "CURLError" + || status == "XMLRPCError" + || status == "OtherError")) + { + LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: " + << mAuthResponse << LL_ENDL; + return; + } - // Here status IS one of the errors tested above. - // Tell caller this didn't work out so well. + // Here status IS one of the errors tested above. + // Tell caller this didn't work out so well. - // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an - // llsd with no "responses" node. To make the output from an incomplete login symmetrical - // to success, add a data/message and data/reason fields. - LLSD error_response(LLSDMap - ("reason", mAuthResponse["status"]) - ("errorcode", mAuthResponse["errorcode"]) - ("message", mAuthResponse["error"])); - if(mAuthResponse.has("certificate")) - { - error_response["certificate"] = mAuthResponse["certificate"]; - } - sendProgressEvent("offline", "fail.login", error_response); + // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an + // llsd with no "responses" node. To make the output from an incomplete login symmetrical + // to success, add a data/message and data/reason fields. + LLSD error_response(LLSDMap + ("reason", mAuthResponse["status"]) + ("errorcode", mAuthResponse["errorcode"]) + ("message", mAuthResponse["error"])); + if(mAuthResponse.has("certificate")) + { + error_response["certificate"] = mAuthResponse["certificate"]; + } + sendProgressEvent("offline", "fail.login", error_response); } catch (...) { - CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName() - << "('" << uri << "', " << printable_params << ")")); + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName() + << "('" << uri << "', " << printable_params << ")")); + throw; } }