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

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file lleventpoll.cpp
  3.  * @brief Implementation of the LLEventPoll class.
  4.  *
  5.  * $LicenseInfo:firstyear=2006&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2006-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "lleventpoll.h"
  34. #include "llappviewer.h"
  35. #include "llagent.h"
  36. #include "llhttpclient.h"
  37. #include "llhttpstatuscodes.h"
  38. #include "llsdserialize.h"
  39. #include "lleventtimer.h"
  40. #include "llviewerregion.h"
  41. #include "message.h"
  42. #include "lltrans.h"
  43. namespace
  44. {
  45. // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
  46. // This means we attempt to recover relatively quickly but back off giving more time to recover
  47. // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
  48. const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
  49. const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
  50. const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
  51. class LLEventPollResponder : public LLHTTPClient::Responder
  52. {
  53. public:
  54. static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
  55. void stop();
  56. void makeRequest();
  57. private:
  58. LLEventPollResponder(const std::string& pollURL, const LLHost& sender);
  59. ~LLEventPollResponder();
  60. void handleMessage(const LLSD& content);
  61. virtual void error(U32 status, const std::string& reason);
  62. virtual void result(const LLSD& content);
  63. virtual void completedRaw(U32 status,
  64. const std::string& reason,
  65. const LLChannelDescriptors& channels,
  66. const LLIOPipe::buffer_ptr_t& buffer);
  67. private:
  68. bool mDone;
  69. std::string mPollURL;
  70. std::string mSender;
  71. LLSD mAcknowledge;
  72. // these are only here for debugging so we can see which poller is which
  73. static int sCount;
  74. int mCount;
  75. S32 mErrorCount;
  76. };
  77. class LLEventPollEventTimer : public LLEventTimer
  78. {
  79. typedef boost::intrusive_ptr<LLEventPollResponder> EventPollResponderPtr;
  80. public:
  81. LLEventPollEventTimer(F32 period, EventPollResponderPtr responder)
  82. : LLEventTimer(period), mResponder(responder)
  83. { }
  84. virtual BOOL tick()
  85. {
  86. mResponder->makeRequest();
  87. return TRUE; // Causes this instance to be deleted.
  88. }
  89. private:
  90. EventPollResponderPtr mResponder;
  91. };
  92. //static
  93. LLHTTPClient::ResponderPtr LLEventPollResponder::start(
  94. const std::string& pollURL, const LLHost& sender)
  95. {
  96. LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender);
  97. llinfos << "LLEventPollResponder::start <" << sCount << "> "
  98. << pollURL << llendl;
  99. return result;
  100. }
  101. void LLEventPollResponder::stop()
  102. {
  103. llinfos << "LLEventPollResponder::stop <" << mCount << "> "
  104. << mPollURL << llendl;
  105. // there should be a way to stop a LLHTTPClient request in progress
  106. mDone = true;
  107. }
  108. int LLEventPollResponder::sCount = 0;
  109. LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender)
  110. : mDone(false),
  111.   mPollURL(pollURL),
  112.   mCount(++sCount),
  113.   mErrorCount(0)
  114. {
  115. //extract host and port of simulator to set as sender
  116. LLViewerRegion *regionp = gAgent.getRegion();
  117. if (!regionp)
  118. {
  119. llerrs << "LLEventPoll initialized before region is added." << llendl;
  120. }
  121. mSender = sender.getIPandPort();
  122. llinfos << "LLEventPoll initialized with sender " << mSender << llendl;
  123. makeRequest();
  124. }
  125. LLEventPollResponder::~LLEventPollResponder()
  126. {
  127. stop();
  128. lldebugs << "LLEventPollResponder::~Impl <" << mCount << "> "
  129.  << mPollURL << llendl;
  130. }
  131. // virtual 
  132. void LLEventPollResponder::completedRaw(U32 status,
  133. const std::string& reason,
  134. const LLChannelDescriptors& channels,
  135. const LLIOPipe::buffer_ptr_t& buffer)
  136. {
  137. if (status == HTTP_BAD_GATEWAY)
  138. {
  139. // These errors are not parsable as LLSD, 
  140. // which LLHTTPClient::Responder::completedRaw will try to do.
  141. completed(status, reason, LLSD());
  142. }
  143. else
  144. {
  145. LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer);
  146. }
  147. }
  148. void LLEventPollResponder::makeRequest()
  149. {
  150. LLSD request;
  151. request["ack"] = mAcknowledge;
  152. request["done"] = mDone;
  153. lldebugs << "LLEventPollResponder::makeRequest <" << mCount << "> ack = "
  154.  << LLSDXMLStreamer(mAcknowledge) << llendl;
  155. LLHTTPClient::post(mPollURL, request, this);
  156. }
  157. void LLEventPollResponder::handleMessage(const LLSD& content)
  158. {
  159. std::string msg_name = content["message"];
  160. LLSD message;
  161. message["sender"] = mSender;
  162. message["body"] = content["body"];
  163. LLMessageSystem::dispatch(msg_name, message);
  164. }
  165. //virtual
  166. void LLEventPollResponder::error(U32 status, const std::string& reason)
  167. {
  168. if (mDone) return;
  169. // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
  170. // we get this when there are no events.
  171. if ( status == HTTP_BAD_GATEWAY )
  172. {
  173. mErrorCount = 0;
  174. makeRequest();
  175. }
  176. else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS)
  177. {
  178. ++mErrorCount;
  179. // The 'tick' will return TRUE causing the timer to delete this.
  180. new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS
  181. + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
  182. , this);
  183. llwarns << "Unexpected HTTP error.  status: " << status << ", reason: " << reason << llendl;
  184. }
  185. else
  186. {
  187. llwarns << "LLEventPollResponder::error: <" << mCount << "> got "
  188. << status << ": " << reason
  189. << (mDone ? " -- done" : "") << llendl;
  190. stop();
  191. // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
  192. // IMs, teleports, about land, selecing land, region crossing and more will all fail.
  193. // They are essentially disconnected from the region even though some things may still work.
  194. // Since things won't get better until they relog we force a disconnect now.
  195. // *NOTE:Mani - The following condition check to see if this failing event poll
  196. // is attached to the Agent's main region. If so we disconnect the viewer.
  197. // Else... its a child region and we just leave the dead event poll stopped and 
  198. // continue running.
  199. if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender)
  200. {
  201. llwarns << "Forcing disconnect due to stalled main region event poll."  << llendl;
  202. LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
  203. }
  204. }
  205. }
  206. //virtual
  207. void LLEventPollResponder::result(const LLSD& content)
  208. {
  209. lldebugs << "LLEventPollResponder::result <" << mCount << ">"
  210.  << (mDone ? " -- done" : "") << llendl;
  211. if (mDone) return;
  212. mErrorCount = 0;
  213. if (!content.get("events") ||
  214. !content.get("id"))
  215. {
  216. llwarns << "received event poll with no events or id key" << llendl;
  217. makeRequest();
  218. return;
  219. }
  220. mAcknowledge = content["id"];
  221. LLSD events = content["events"];
  222. if(mAcknowledge.isUndefined())
  223. {
  224. llwarns << "LLEventPollResponder: id undefined" << llendl;
  225. }
  226. // was llinfos but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
  227. lldebugs  << "LLEventPollResponder::completed <" << mCount << "> " << events.size() << "events (id "
  228.  << LLSDXMLStreamer(mAcknowledge) << ")" << llendl;
  229. LLSD::array_const_iterator i = events.beginArray();
  230. LLSD::array_const_iterator end = events.endArray();
  231. for (; i != end; ++i)
  232. {
  233. if (i->has("message"))
  234. {
  235. handleMessage(*i);
  236. }
  237. }
  238. makeRequest();
  239. }
  240. }
  241. LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender)
  242. : mImpl(LLEventPollResponder::start(poll_url, sender))
  243. { }
  244. LLEventPoll::~LLEventPoll()
  245. {
  246. LLHTTPClient::Responder* responderp = mImpl.get();
  247. LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp);
  248. if (event_poll_responder) event_poll_responder->stop();
  249. }