diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2018-10-04 16:35:38 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2018-10-04 16:35:38 -0400 |
commit | 05068186c349294caf4fef3c970f9d75a9f30460 (patch) | |
tree | 58374bd2e5b519ad9b7943c9fab2a4aded52240a /indra/viewer_components/login/lllogin.cpp | |
parent | b1955d4247a4d28a3a4c259036390ff632e80008 (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.cpp | 56 |
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"]; |