summaryrefslogtreecommitdiff
path: root/indra/viewer_components/login/lllogin.cpp
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2018-10-04 16:35:38 -0400
committerNat Goodspeed <nat@lindenlab.com>2018-10-04 16:35:38 -0400
commit05068186c349294caf4fef3c970f9d75a9f30460 (patch)
tree58374bd2e5b519ad9b7943c9fab2a4aded52240a /indra/viewer_components/login/lllogin.cpp
parentb1955d4247a4d28a3a4c259036390ff632e80008 (diff)
DRTVWR-474: Make login coroutine sync with updater process on failure.
Specifically, introduce an LLEventMailDrop("LoginSync"). When the updater detects that an update is required, it will post to that rendezvous point. When login.cgi responds with login failure, make the login coroutine wait (a few seconds) for that ping from the updater. If we receive that ping and if it contains a "reply" key, make the fail.login listener respond to the updater with an indication of whether to proceed with update. If both login.cgi and the updater concur that an update is required, produce a new confirmation message for the user and then (once user responds) tell the updater to proceed. Otherwise, produce the usual login-failure message and tell the updater never mind. Introduce LLCoro::OverrideConsuming to provide temporary save/restore of the set_consuming() / get_consuming() flag. It's a good idea to set the consuming flag when retrieving data from an LLEventMailDrop.
Diffstat (limited to 'indra/viewer_components/login/lllogin.cpp')
-rw-r--r--indra/viewer_components/login/lllogin.cpp56
1 files changed, 51 insertions, 5 deletions
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index c767d52c7b..9193d32b49 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -128,6 +128,15 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}
+namespace {
+// Instantiate this rendezvous point at namespace scope so it's already
+// present no matter how early the updater might post to it.
+// Use an LLEventMailDrop, which has future-like semantics: regardless of the
+// relative order in which post() or listen() are called, it delivers each
+// post() event to its listener(s) until one of them consumes that event.
+static LLEventMailDrop sSyncPoint("LoginSync");
+}
+
void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{
LLSD printable_params = login_params;
@@ -219,7 +228,44 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
}
else
{
- sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
+ // 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);
}
return; // Done!
}
@@ -249,10 +295,10 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
// *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;
- error_response["reason"] = mAuthResponse["status"];
- error_response["errorcode"] = mAuthResponse["errorcode"];
- error_response["message"] = mAuthResponse["error"];
+ LLSD error_response(LLSDMap
+ ("reason", mAuthResponse["status"])
+ ("errorcode", mAuthResponse["errorcode"])
+ ("message", mAuthResponse["error"]));
if(mAuthResponse.has("certificate"))
{
error_response["certificate"] = mAuthResponse["certificate"];