aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lleventpoll.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/lleventpoll.cpp')
-rw-r--r--linden/indra/newview/lleventpoll.cpp99
1 files changed, 91 insertions, 8 deletions
diff --git a/linden/indra/newview/lleventpoll.cpp b/linden/indra/newview/lleventpoll.cpp
index f00c05b..083c46c 100644
--- a/linden/indra/newview/lleventpoll.cpp
+++ b/linden/indra/newview/lleventpoll.cpp
@@ -31,16 +31,26 @@
31 31
32#include "llviewerprecompiledheaders.h" 32#include "llviewerprecompiledheaders.h"
33 33
34#include "llappviewer.h"
34#include "llagent.h" 35#include "llagent.h"
35#include "lleventpoll.h" 36#include "lleventpoll.h"
36 37
37#include "llhttpclient.h" 38#include "llhttpclient.h"
39#include "llhttpstatuscodes.h"
38#include "llsdserialize.h" 40#include "llsdserialize.h"
41#include "lltimer.h"
39#include "llviewerregion.h" 42#include "llviewerregion.h"
40#include "message.h" 43#include "message.h"
41 44
42namespace 45namespace
43{ 46{
47 // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
48 // This means we attempt to recover relatively quickly but back off giving more time to recover
49 // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
50 const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
51 const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
52 const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
53
44 class LLEventPollResponder : public LLHTTPClient::Responder 54 class LLEventPollResponder : public LLHTTPClient::Responder
45 { 55 {
46 public: 56 public:
@@ -48,15 +58,21 @@ namespace
48 static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender); 58 static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
49 void stop(); 59 void stop();
50 60
61 void makeRequest();
62
51 private: 63 private:
52 LLEventPollResponder(const std::string& pollURL, const LLHost& sender); 64 LLEventPollResponder(const std::string& pollURL, const LLHost& sender);
53 ~LLEventPollResponder(); 65 ~LLEventPollResponder();
54 66
55 void makeRequest(); 67
56 void handleMessage(const LLSD& content); 68 void handleMessage(const LLSD& content);
57 virtual void error(U32 status, const std::string& reason); 69 virtual void error(U32 status, const std::string& reason);
58 virtual void result(const LLSD& content); 70 virtual void result(const LLSD& content);
59 71
72 virtual void completedRaw(U32 status,
73 const std::string& reason,
74 const LLChannelDescriptors& channels,
75 const LLIOPipe::buffer_ptr_t& buffer);
60 private: 76 private:
61 77
62 bool mDone; 78 bool mDone;
@@ -69,6 +85,27 @@ namespace
69 // these are only here for debugging so we can see which poller is which 85 // these are only here for debugging so we can see which poller is which
70 static int sCount; 86 static int sCount;
71 int mCount; 87 int mCount;
88 S32 mErrorCount;
89 };
90
91 class LLEventPollEventTimer : public LLEventTimer
92 {
93 typedef boost::intrusive_ptr<LLEventPollResponder> EventPollResponderPtr;
94
95 public:
96 LLEventPollEventTimer(F32 period, EventPollResponderPtr responder)
97 : LLEventTimer(period), mResponder(responder)
98 { }
99
100 virtual BOOL tick()
101 {
102 mResponder->makeRequest();
103 return TRUE; // Causes this instance to be deleted.
104 }
105
106 private:
107
108 EventPollResponderPtr mResponder;
72 }; 109 };
73 110
74 //static 111 //static
@@ -94,7 +131,8 @@ namespace
94 LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender) 131 LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender)
95 : mDone(false), 132 : mDone(false),
96 mPollURL(pollURL), 133 mPollURL(pollURL),
97 mCount(++sCount) 134 mCount(++sCount),
135 mErrorCount(0)
98 { 136 {
99 //extract host and port of simulator to set as sender 137 //extract host and port of simulator to set as sender
100 LLViewerRegion *regionp = gAgent.getRegion(); 138 LLViewerRegion *regionp = gAgent.getRegion();
@@ -114,6 +152,24 @@ namespace
114 << mPollURL << llendl; 152 << mPollURL << llendl;
115 } 153 }
116 154
155 // virtual
156 void LLEventPollResponder::completedRaw(U32 status,
157 const std::string& reason,
158 const LLChannelDescriptors& channels,
159 const LLIOPipe::buffer_ptr_t& buffer)
160 {
161 if (status == HTTP_BAD_GATEWAY)
162 {
163 // These errors are not parsable as LLSD,
164 // which LLHTTPClient::Responder::completedRaw will try to do.
165 completed(status, reason, LLSD());
166 }
167 else
168 {
169 LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer);
170 }
171 }
172
117 void LLEventPollResponder::makeRequest() 173 void LLEventPollResponder::makeRequest()
118 { 174 {
119 LLSD request; 175 LLSD request;
@@ -139,16 +195,37 @@ namespace
139 { 195 {
140 if (mDone) return; 196 if (mDone) return;
141 197
142 if(status != 499) 198 // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
199 // we get this when there are no events.
200 if ( status == HTTP_BAD_GATEWAY )
201 {
202 mErrorCount = 0;
203 makeRequest();
204 }
205 else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS)
206 {
207 ++mErrorCount;
208
209 // The 'tick' will return TRUE causing the timer to delete this.
210 new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS
211 + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
212 , this);
213
214 llwarns << "Unexpected HTTP error. status: " << status << ", reason: " << reason << llendl;
215 }
216 else
143 { 217 {
144 llwarns << "LLEventPollResponder::error: <" << mCount << "> got " 218 llwarns << "LLEventPollResponder::error: <" << mCount << "> got "
145 << status << ": " << reason 219 << status << ": " << reason
146 << (mDone ? " -- done" : "") << llendl; 220 << (mDone ? " -- done" : "") << llendl;
147 stop(); 221 stop();
148 return;
149 }
150 222
151 makeRequest(); 223 // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
224 // IMs, teleports, about land, selecing land, region crossing and more will all fail.
225 // They are essentially disconnected from the region even though some things may still work.
226 // Since things won't get better until they relog we force a disconnect now.
227 LLAppViewer::instance()->forceDisconnect("You have been disconnected from the region you were in.");
228 }
152 } 229 }
153 230
154 //virtual 231 //virtual
@@ -159,10 +236,13 @@ namespace
159 236
160 if (mDone) return; 237 if (mDone) return;
161 238
239 mErrorCount = 0;
240
162 if (!content.get("events") || 241 if (!content.get("events") ||
163 !content.get("id")) 242 !content.get("id"))
164 { 243 {
165 llwarns << "received event poll with no events or id key" << llendl; 244 llwarns << "received event poll with no events or id key" << llendl;
245 makeRequest();
166 return; 246 return;
167 } 247 }
168 248
@@ -192,10 +272,13 @@ namespace
192 } 272 }
193} 273}
194 274
195LLEventPoll::LLEventPoll(const std::string& pollURL, const LLHost& sender) 275LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender)
196 : mImpl(LLEventPollResponder::start(pollURL, sender)) 276 : mImpl(LLEventPollResponder::start(poll_url, sender))
197 { } 277 { }
198 278
199LLEventPoll::~LLEventPoll() 279LLEventPoll::~LLEventPoll()
200{ 280{
281 LLHTTPClient::Responder* responderp = mImpl.get();
282 LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp);
283 if (event_poll_responder) event_poll_responder->stop();
201} 284}