lllogin.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:15k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file lllogin.cpp
  3.  *
  4.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  5.  * 
  6.  * Copyright (c) 2009-2010, Linden Research, Inc.
  7.  * 
  8.  * Second Life Viewer Source Code
  9.  * The source code in this file ("Source Code") is provided by Linden Lab
  10.  * to you under the terms of the GNU General Public License, version 2.0
  11.  * ("GPL"), unless you have obtained a separate licensing agreement
  12.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  13.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15.  * 
  16.  * There are special exceptions to the terms and conditions of the GPL as
  17.  * it is applied to this Source Code. View the full text of the exception
  18.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  19.  * online at
  20.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21.  * 
  22.  * By copying, modifying or distributing this software, you acknowledge
  23.  * that you have read and understood your obligations described above,
  24.  * and agree to abide by those obligations.
  25.  * 
  26.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28.  * COMPLETENESS OR PERFORMANCE.
  29.  * $/LicenseInfo$
  30.  */
  31. #include <boost/coroutine/coroutine.hpp>
  32. #include "linden_common.h"
  33. #include "llsd.h"
  34. #include "llsdutil.h"
  35. /*==========================================================================*|
  36. #ifdef LL_WINDOWS
  37. // non-virtual destructor warning, boost::statechart does this intentionally.
  38. #pragma warning (disable : 4265) 
  39. #endif
  40. |*==========================================================================*/
  41. #include "lllogin.h"
  42. #include <boost/bind.hpp>
  43. #include "llcoros.h"
  44. #include "llevents.h"
  45. #include "lleventfilter.h"
  46. #include "lleventcoro.h"
  47. //*********************
  48. // LLLogin
  49. // *NOTE:Mani - Is this Impl needed now that the state machine runs the show?
  50. class LLLogin::Impl
  51. {
  52. public:
  53.     Impl():
  54. mPump("login", true) // Create the module's event pump with a tweaked (unique) name.
  55.     {
  56.         mValidAuthResponse["status"]        = LLSD();
  57.         mValidAuthResponse["errorcode"]     = LLSD();
  58.         mValidAuthResponse["error"]         = LLSD();
  59.         mValidAuthResponse["transfer_rate"] = LLSD();
  60.     }
  61.     void connect(const std::string& uri, const LLSD& credentials);
  62.     void disconnect();
  63. LLEventPump& getEventPump() { return mPump; }
  64. private:
  65. LLSD getProgressEventLLSD(const std::string& state, const std::string& change,
  66.    const LLSD& data = LLSD())
  67. {
  68. LLSD status_data;
  69. status_data["state"] = state;
  70. status_data["change"] = change;
  71. status_data["progress"] = 0.0f;
  72. if(mAuthResponse.has("transfer_rate"))
  73. {
  74. status_data["transfer_rate"] = mAuthResponse["transfer_rate"];
  75. }
  76. if(data.isDefined())
  77. {
  78. status_data["data"] = data;
  79. }
  80. return status_data;
  81. }
  82. void sendProgressEvent(const std::string& state, const std::string& change,
  83.    const LLSD& data = LLSD())
  84. {
  85. LLSD status_data = getProgressEventLLSD(state, change, data);
  86. mPump.post(status_data);
  87. }
  88.     LLSD validateResponse(const std::string& pumpName, const LLSD& response)
  89.     {
  90.         // Validate the response. If we don't recognize it, things
  91.         // could get ugly.
  92.         std::string mismatch(llsd_matches(mValidAuthResponse, response));
  93.         if (! mismatch.empty())
  94.         {
  95.             LL_ERRS("LLLogin") << "Received unrecognized event (" << mismatch << ") on "
  96.                                << pumpName << "pump: " << response
  97.                                << LL_ENDL;
  98.             return LLSD();
  99.         }
  100.         return response;
  101.     }
  102.     // In a coroutine's top-level function args, do NOT NOT NOT accept
  103.     // references (const or otherwise) to anything but the self argument! Pass
  104.     // by value only!
  105.     void login_(LLCoros::self& self, std::string uri, LLSD credentials);
  106.     LLEventStream mPump;
  107. LLSD mAuthResponse, mValidAuthResponse;
  108. };
  109. void LLLogin::Impl::connect(const std::string& uri, const LLSD& credentials)
  110. {
  111.     // Launch a coroutine with our login_() method. Run the coroutine until
  112.     // its first wait; at that point, return here.
  113.     std::string coroname = 
  114.         LLCoros::instance().launch("LLLogin::Impl::login_",
  115.                                    boost::bind(&Impl::login_, this, _1, uri, credentials));
  116. }
  117. void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD credentials)
  118. {
  119. LLSD printable_credentials = credentials;
  120. if(printable_credentials.has("params") 
  121. && printable_credentials["params"].has("passwd")) 
  122. {
  123. printable_credentials["params"]["passwd"] = "*******";
  124. }
  125.     LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
  126.                         << " with uri '" << uri << "', credentials " << printable_credentials << LL_ENDL;
  127. // Arriving in SRVRequest state
  128.     LLEventStream replyPump("SRVreply", true);
  129.     // Should be an array of one or more uri strings.
  130.     LLSD rewrittenURIs;
  131.     {
  132.         LLEventTimeout filter(replyPump);
  133.         sendProgressEvent("offline", "srvrequest");
  134.         // Request SRV record.
  135.         LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
  136.         // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
  137. F32 seconds_to_timeout = 5.0f;
  138. if(credentials.has("cfg_srv_timeout"))
  139. {
  140. seconds_to_timeout = credentials["cfg_srv_timeout"].asReal();
  141. }
  142.         // If the SRV request times out (e.g. EXT-3934), simulate response: an
  143.         // array containing our original URI.
  144.         LLSD fakeResponse(LLSD::emptyArray());
  145.         fakeResponse.append(uri);
  146. filter.eventAfter(seconds_to_timeout, fakeResponse);
  147. std::string srv_pump_name = "LLAres";
  148. if(credentials.has("cfg_srv_pump"))
  149. {
  150. srv_pump_name = credentials["cfg_srv_pump"].asString();
  151. }
  152. // Make request
  153.         LLSD request;
  154.         request["op"] = "rewriteURI";
  155.         request["uri"] = uri;
  156.         request["reply"] = replyPump.getName();
  157.         rewrittenURIs = postAndWait(self, request, srv_pump_name, filter);
  158.     } // we no longer need the filter
  159.     LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
  160.     // EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used
  161.     // to share them -- but the EXT-3934 fix made it possible for an abandoned
  162.     // SRV response to arrive just as we were expecting the XMLRPC response.
  163.     LLEventStream loginReplyPump("loginreply", true);
  164.     // Loop through the rewrittenURIs, counting attempts along the way.
  165.     // Because of possible redirect responses, we may make more than one
  166.     // attempt per rewrittenURIs entry.
  167.     LLSD::Integer attempts = 0;
  168.     for (LLSD::array_const_iterator urit(rewrittenURIs.beginArray()),
  169.              urend(rewrittenURIs.endArray());
  170.          urit != urend; ++urit)
  171.     {
  172.         LLSD request(credentials);
  173.         request["reply"] = loginReplyPump.getName();
  174.         request["uri"] = *urit;
  175.         std::string status;
  176.         // Loop back to here if login attempt redirects to a different
  177.         // request["uri"]
  178.         for (;;)
  179.         {
  180.             ++attempts;
  181.             LLSD progress_data;
  182.             progress_data["attempt"] = attempts;
  183.             progress_data["request"] = request;
  184. if(progress_data["request"].has("params")
  185. && progress_data["request"]["params"].has("passwd"))
  186. {
  187. progress_data["request"]["params"]["passwd"] = "*******";
  188. }
  189.             sendProgressEvent("offline", "authenticating", progress_data);
  190.             // We expect zero or more "Downloading" status events, followed by
  191.             // exactly one event with some other status. Use postAndWait() the
  192.             // first time, because -- at least in unit-test land -- it's
  193.             // possible for the reply to arrive before the post() call
  194.             // returns. Subsequent responses, of course, must be awaited
  195.             // without posting again.
  196.             for (mAuthResponse = validateResponse(loginReplyPump.getName(),
  197.                                  postAndWait(self, request, xmlrpcPump, loginReplyPump, "reply"));
  198.                  mAuthResponse["status"].asString() == "Downloading";
  199.                  mAuthResponse = validateResponse(loginReplyPump.getName(),
  200.                                      waitForEventOn(self, loginReplyPump)))
  201.             {
  202.                 // Still Downloading -- send progress update.
  203.                 sendProgressEvent("offline", "downloading");
  204.             }
  205.  
  206. LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
  207.             status = mAuthResponse["status"].asString();
  208.             // Okay, we've received our final status event for this
  209.             // request. Unless we got a redirect response, break the retry
  210.             // loop for the current rewrittenURIs entry.
  211.             if (!(status == "Complete" &&
  212.                   mAuthResponse["responses"]["login"].asString() == "indeterminate"))
  213.             {
  214.                 break;
  215.             }
  216. sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
  217.             // Here the login service at the current URI is redirecting us
  218.             // to some other URI ("indeterminate" -- why not "redirect"?).
  219.             // The response should contain another uri to try, with its
  220.             // own auth method.
  221.             request["uri"] = mAuthResponse["responses"]["next_url"].asString();
  222.             request["method"] = mAuthResponse["responses"]["next_method"].asString();
  223.         } // loop back to try the redirected URI
  224.         // Here we're done with redirects for the current rewrittenURIs
  225.         // entry.
  226.         if (status == "Complete")
  227.         {
  228.             // StatusComplete does not imply auth success. Check the
  229.             // actual outcome of the request. We've already handled the
  230.             // "indeterminate" case in the loop above.
  231.             if (mAuthResponse["responses"]["login"].asString() == "true")
  232.             {
  233.                 sendProgressEvent("online", "connect", mAuthResponse["responses"]);
  234.             }
  235.             else
  236.             {
  237.                 sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
  238.             }
  239.             return;             // Done!
  240.         }
  241.         // If we don't recognize status at all, trouble
  242.         if (! (status == "CURLError"
  243.                || status == "XMLRPCError"
  244.                || status == "OtherError"))
  245.         {
  246.             LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
  247.                                << mAuthResponse << LL_ENDL;
  248.             return;
  249.         }
  250.         // Here status IS one of the errors tested above.
  251.     } // Retry if there are any more rewrittenURIs.
  252.     // Here we got through all the rewrittenURIs without succeeding. Tell
  253.     // caller this didn't work out so well. Of course, the only failure data
  254.     // we can reasonably show are from the last of the rewrittenURIs.
  255. // *NOTE: The response from LLXMLRPCListener's Poller::poll method returns an
  256. // llsd with no "responses" node. To make the output from an incomplete login symmetrical 
  257. // to success, add a data/message and data/reason fields.
  258. LLSD error_response;
  259. error_response["reason"] = mAuthResponse["status"];
  260. error_response["message"] = mAuthResponse["error"];
  261. sendProgressEvent("offline", "fail.login", error_response);
  262. }
  263. void LLLogin::Impl::disconnect()
  264. {
  265.     sendProgressEvent("offline", "disconnect");
  266. }
  267. //*********************
  268. // LLLogin
  269. LLLogin::LLLogin() :
  270. mImpl(new LLLogin::Impl())
  271. {
  272. }
  273. LLLogin::~LLLogin()
  274. {
  275. }
  276. void LLLogin::connect(const std::string& uri, const LLSD& credentials)
  277. {
  278. mImpl->connect(uri, credentials);
  279. }
  280. void LLLogin::disconnect()
  281. {
  282. mImpl->disconnect();
  283. }
  284. LLEventPump& LLLogin::getEventPump()
  285. {
  286. return mImpl->getEventPump();
  287. }
  288. // The following is the list of important functions that happen in the 
  289. // current login process that we want to move to this login module.
  290. // The list associates to event with the original idle_startup() 'STATE'.
  291. // Rewrite URIs
  292.  // State_LOGIN_AUTH_INIT
  293. // Given a vector of login uris (usually just one), perform a dns lookup for the 
  294. // SRV record from each URI. I think this is used to distribute login requests to 
  295. // a single URI to multiple hosts.
  296. // This is currently a synchronous action. (See LLSRV::rewriteURI() implementation)
  297. // On dns lookup error the output uris == the input uris.
  298. //
  299. // Input: A vector of login uris
  300. // Output: A vector of login uris
  301. //
  302. // Code:
  303. // std::vector<std::string> uris;
  304. // LLViewerLogin::getInstance()->getLoginURIs(uris);
  305. // std::vector<std::string>::const_iterator iter, end;
  306. // for (iter = uris.begin(), end = uris.end(); iter != end; ++iter)
  307. // {
  308. // std::vector<std::string> rewritten;
  309. // rewritten = LLSRV::rewriteURI(*iter);
  310. // sAuthUris.insert(sAuthUris.end(),
  311. //  rewritten.begin(), rewritten.end());
  312. // }
  313. // sAuthUriNum = 0;
  314. // Authenticate 
  315. // STATE_LOGIN_AUTHENTICATE
  316. // Connect to the login server, presumably login.cgi, requesting the login 
  317. // and a slew of related initial connection information.
  318. // This is an asynch action. The final response, whether success or error
  319. // is handled by STATE_LOGIN_PROCESS_REPONSE.
  320. // There is no immediate error or output from this call.
  321. // 
  322. // Input: 
  323. //  URI
  324. //  Credentials (first, last, password)
  325. //  Start location
  326. //  Bool Flags:
  327. //    skip optional update
  328. //    accept terms of service
  329. //    accept critical message
  330. //  Last exec event. (crash state of previous session)
  331. //  requested optional data (inventory skel, initial outfit, etc.)
  332. //  local mac address
  333. //  viewer serial no. (md5 checksum?)
  334. //sAuthUriNum = llclamp(sAuthUriNum, 0, (S32)sAuthUris.size()-1);
  335. //LLUserAuth::getInstance()->authenticate(
  336. // sAuthUris[sAuthUriNum],
  337. // auth_method,
  338. // firstname,
  339. // lastname,
  340. // password, // web_login_key,
  341. // start.str(),
  342. // gSkipOptionalUpdate,
  343. // gAcceptTOS,
  344. // gAcceptCriticalMessage,
  345. // gLastExecEvent,
  346. // requested_options,
  347. // hashed_mac_string,
  348. // LLAppViewer::instance()->getSerialNumber());
  349. //
  350. // Download the Response
  351. // STATE_LOGIN_NO_REPONSE_YET and STATE_LOGIN_DOWNLOADING
  352. // I had assumed that this was default behavior of the message system. However...
  353. // During login, the message system is checked only by these two states in idle_startup().
  354. // I guess this avoids the overhead of checking network messages for those login states
  355. // that don't need to do so, but geez!
  356. // There are two states to do this one function just to update the login
  357. // status text from 'Logging In...' to 'Downloading...'
  358. // 
  359. //
  360. // Handle Login Response
  361. // STATE_LOGIN_PROCESS_RESPONSE
  362. // 
  363. // This state handle the result of the request to login. There is a metric ton of
  364. // code in this case. This state will transition to:
  365. // STATE_WORLD_INIT, on success.
  366. // STATE_AUTHENTICATE, on failure.
  367. // STATE_UPDATE_CHECK, to handle user during login interaction like TOS display.
  368. //
  369. // Much of the code in this case belongs on the viewer side of the fence and not in login. 
  370. // Login should probably return with a couple of events, success and failure.
  371. // Failure conditions can be specified in the events data pacet to allow the viewer 
  372. // to re-engauge login as is appropriate. (Or should there be multiple failure messages?)
  373. // Success is returned with the data requested from the login. According to OGP specs 
  374. // there may be intermediate steps before reaching this result in future login 
  375. // implementations.