summaryrefslogtreecommitdiff
path: root/indra/viewer_components
diff options
context:
space:
mode:
Diffstat (limited to 'indra/viewer_components')
-rw-r--r--indra/viewer_components/login/lllogin.cpp89
-rw-r--r--indra/viewer_components/login/tests/lllogin_test.cpp74
2 files changed, 138 insertions, 25 deletions
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 7a30315b9a..b9f61ca7e1 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -70,7 +70,7 @@ public:
LLEventPump& getEventPump() { return mPump; }
private:
- void sendProgressEvent(const std::string& state, const std::string& change,
+ LLSD getProgressEventLLSD(const std::string& state, const std::string& change,
const LLSD& data = LLSD())
{
LLSD status_data;
@@ -87,7 +87,13 @@ private:
{
status_data["data"] = data;
}
+ return status_data;
+ }
+ void sendProgressEvent(const std::string& state, const std::string& change,
+ const LLSD& data = LLSD())
+ {
+ LLSD status_data = getProgressEventLLSD(state, change, data);
mPump.post(status_data);
}
@@ -127,10 +133,17 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& credentials)
void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credentials)
{
- LL_INFOS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
- << " with uri '" << uri << "', credentials " << credentials << LL_ENDL;
- // Arriving in SRVRequest state
- LLEventStream replyPump("reply", true);
+ LLSD printable_credentials = credentials;
+ if(printable_credentials.has("params")
+ && printable_credentials["params"].has("passwd"))
+ {
+ printable_credentials["params"]["passwd"] = "*******";
+ }
+ LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
+ << " with uri '" << uri << "', credentials " << printable_credentials << LL_ENDL;
+
+ // Arriving in SRVRequest state
+ LLEventStream replyPump("SRVreply", true);
// Should be an array of one or more uri strings.
LLSD rewrittenURIs;
{
@@ -138,20 +151,40 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
sendProgressEvent("offline", "srvrequest");
// Request SRV record.
- LL_INFOS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
+ LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
- // *NOTE:Mani - Completely arbitrary timeout value for SRV request.
- filter.errorAfter(5, "SRV Request timed out!");
+ // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
+ F32 seconds_to_timeout = 5.0f;
+ if(credentials.has("cfg_srv_timeout"))
+ {
+ seconds_to_timeout = credentials["cfg_srv_timeout"].asReal();
+ }
+
+ // If the SRV request times out (e.g. EXT-3934), simulate response: an
+ // array containing our original URI.
+ LLSD fakeResponse(LLSD::emptyArray());
+ fakeResponse.append(uri);
+ filter.eventAfter(seconds_to_timeout, fakeResponse);
+
+ std::string srv_pump_name = "LLAres";
+ if(credentials.has("cfg_srv_pump"))
+ {
+ srv_pump_name = credentials["cfg_srv_pump"].asString();
+ }
- // Make request
+ // Make request
LLSD request;
request["op"] = "rewriteURI";
request["uri"] = uri;
request["reply"] = replyPump.getName();
- rewrittenURIs = postAndWait(self, request, "LLAres", filter);
+ rewrittenURIs = postAndWait(self, request, srv_pump_name, filter);
} // we no longer need the filter
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);
// Loop through the rewrittenURIs, counting attempts along the way.
// Because of possible redirect responses, we may make more than one
@@ -162,7 +195,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
urit != urend; ++urit)
{
LLSD request(credentials);
- request["reply"] = replyPump.getName();
+ request["reply"] = loginReplyPump.getName();
request["uri"] = *urit;
std::string status;
@@ -174,6 +207,11 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
LLSD progress_data;
progress_data["attempt"] = attempts;
progress_data["request"] = request;
+ if(progress_data["request"].has("params")
+ && progress_data["request"]["params"].has("passwd"))
+ {
+ progress_data["request"]["params"]["passwd"] = "*******";
+ }
sendProgressEvent("offline", "authenticating", progress_data);
// We expect zero or more "Downloading" status events, followed by
@@ -182,32 +220,36 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
// possible for the reply to arrive before the post() call
// returns. Subsequent responses, of course, must be awaited
// without posting again.
- for (mAuthResponse = validateResponse(replyPump.getName(),
- postAndWait(self, request, xmlrpcPump, replyPump, "reply"));
+ for (mAuthResponse = validateResponse(loginReplyPump.getName(),
+ postAndWait(self, request, xmlrpcPump, loginReplyPump, "reply"));
mAuthResponse["status"].asString() == "Downloading";
- mAuthResponse = validateResponse(replyPump.getName(),
- waitForEventOn(self, replyPump)))
+ mAuthResponse = validateResponse(loginReplyPump.getName(),
+ waitForEventOn(self, 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"))
+ 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["next_url"];
- request["method"] = mAuthResponse["next_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 for the current rewrittenURIs
@@ -243,7 +285,14 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credential
// Here we got through all the rewrittenURIs without succeeding. Tell
// caller this didn't work out so well. Of course, the only failure data
// we can reasonably show are from the last of the rewrittenURIs.
- sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
+
+ // *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["message"] = mAuthResponse["error"];
+ sendProgressEvent("offline", "fail.login", error_response);
}
void LLLogin::Impl::disconnect()
diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp
index a8ae2883d5..51f5cd0692 100644
--- a/indra/viewer_components/login/tests/lllogin_test.cpp
+++ b/indra/viewer_components/login/tests/lllogin_test.cpp
@@ -29,6 +29,20 @@
#include "llevents.h"
#include "stringize.h"
+#if LL_WINDOWS
+#define skipwin(arg) skip(arg)
+#define skipmac(arg)
+#define skiplinux(arg)
+#elif LL_DARWIN
+#define skipwin(arg)
+#define skipmac(arg) skip(arg)
+#define skiplinux(arg)
+#elif LL_LINUX
+#define skipwin(arg)
+#define skipmac(arg)
+#define skiplinux(arg) skip(arg)
+#endif
+
/*****************************************************************************
* Helper classes
*****************************************************************************/
@@ -47,6 +61,7 @@ public:
bool call(const LLSD& event)
{
mDebug(STRINGIZE("LoginListener called!: " << event));
+
mLastEvent = event;
return false;
}
@@ -200,14 +215,14 @@ namespace tut
void llviewerlogin_object::test<1>()
{
DEBUG;
- // Testing login with immediate repsonses from Ares and XMLPRC
+ // Testing login with immediate responses from Ares and XMLPRC
// The response from both requests will come before the post request exits.
// This tests an edge case of the login state handling.
LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
bool respond_immediately = true;
- // Have 'dummy ares' repsond immediately.
+ // Have 'dummy ares' respond immediately.
LLAresListener dummyLLAres("dummy_llares", respond_immediately);
dummyLLAres.listenTo(llaresPump);
@@ -236,7 +251,7 @@ namespace tut
DEBUG;
// Tests a successful login in with delayed responses.
// Also includes 'failure' that cause the login module
- // To re-attempt connection, once from a basic failure
+ // to re-attempt connection, once from a basic failure
// and once from the 'indeterminate' response.
set_test_name("LLLogin multiple srv uris w/ success");
@@ -296,14 +311,15 @@ namespace tut
data["error"] = "dummy response";
data["transfer_rate"] = 0;
data["responses"]["login"] = "indeterminate";
- data["next_url"] = "login.indeterminate.com";
- data["next_method"] = "test_login_method";
+ data["responses"]["next_url"] = "login.indeterminate.com";
+ data["responses"]["next_method"] = "test_login_method";
dummyXMLRPC.setResponse(data);
dummyXMLRPC.sendReply();
ensure_equals("Fail back to authenticate 2", listener.lastEvent()["change"].asString(), "authenticating");
ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");
+ ensure_equals("Method 3", listener.lastEvent()["data"]["request"]["method"].asString(), "test_login_method");
// Finally let the auth succeed.
data.clear();
@@ -414,4 +430,52 @@ namespace tut
ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
}
+
+ template<> template<>
+ void llviewerlogin_object::test<5>()
+ {
+ DEBUG;
+ // Test SRV request timeout.
+ set_test_name("LLLogin SRV timeout testing");
+
+ // Testing normal login procedure.
+ LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
+
+ LLAresListener dummyLLAres("dummy_llares");
+ dummyLLAres.listenTo(llaresPump);
+
+ LLLogin login;
+ LoginListener listener("test_ear");
+ listener.listenTo(login.getEventPump());
+
+ LLSD credentials;
+ credentials["first"] = "these";
+ credentials["last"] = "don't";
+ credentials["passwd"] = "matter";
+ credentials["cfg_srv_timeout"] = 0.0f;
+
+ login.connect("login.bar.com", credentials);
+
+ ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest");
+
+ // Get the mainloop eventpump, which needs a pinging in order to drive the
+ // SRV timeout.
+ LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
+ LLSD frame_event;
+ mainloop.post(frame_event);
+
+ // In this state we have NOT sent a reply from LLAresListener -- in
+ // fact there's no such object. Nonetheless, we expect the timeout to
+ // have stepped the login module forward to try to authenticate with
+ // the original URI.
+ ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
+ ensure_equals("Attempt", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
+ ensure_equals("URI", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
+
+ // EXT-4193: if the SRV reply isn't lost but merely late, and if it
+ // arrives just at the moment we're expecting the XMLRPC reply, the
+ // original code got confused and crashed. Drive that case here. We
+ // observe that without the fix, this call DOES repro.
+ dummyLLAres.sendReply();
+ }
}