From 1c91c8a106a78f2087a3fb4312e428a0128283b4 Mon Sep 17 00:00:00 2001
From: Rider Linden <none@none>
Date: Wed, 8 Apr 2015 10:17:34 -0700
Subject: Adding weak pointer support. Event polling as a coroutine.
 (incomplete) Groundwork for canceling HttpCoroutineAdapter yields.

---
 indra/llcorehttp/httpcommon.h      |   1 +
 indra/llcorehttp/httprequest.h     |   1 +
 indra/llmessage/llcorehttputil.cpp |  81 ++---
 indra/llmessage/llcorehttputil.h   |  30 +-
 indra/newview/lleventpoll.cpp      | 688 ++++++++++++++++++++++++-------------
 indra/newview/lleventpoll.h        |  17 +-
 6 files changed, 524 insertions(+), 294 deletions(-)

diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index ada5c1bbe7..898d3d47fa 100755
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -190,6 +190,7 @@
 #include "linden_common.h"		// Modifies curl/curl.h interfaces
 #include "boost/intrusive_ptr.hpp"
 #include "boost/shared_ptr.hpp"
+#include "boost/weak_ptr.hpp"
 #include "boost/function.hpp"
 #include <string>
 
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index f7ce82d412..6688f06eb5 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -98,6 +98,7 @@ public:
 	typedef unsigned int priority_t;
 	
 	typedef boost::shared_ptr<HttpRequest> ptr_t;
+    typedef boost::weak_ptr<HttpRequest>   wptr_t;
 public:
 	/// @name PolicyMethods
 	/// @{
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index 882fef66bc..d560ec8462 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -317,15 +317,18 @@ HttpCoroutineAdapter::HttpCoroutineAdapter(const std::string &name,
     LLCore::HttpRequest::policy_t policyId, LLCore::HttpRequest::priority_t priority) :
     mAdapterName(name),
     mPolicyId(policyId),
-    mPriority(priority)
+    mPriority(priority),
+    mYieldingHandle(LLCORE_HTTP_HANDLE_INVALID),
+    mWeakRequest()
 {
 }
 
 HttpCoroutineAdapter::~HttpCoroutineAdapter()
 {
+
 }
 
-LLSD HttpCoroutineAdapter::postAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t &request,
+LLSD HttpCoroutineAdapter::postAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
     const std::string & url, const LLSD & body,
     LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
 {
@@ -353,28 +356,17 @@ LLSD HttpCoroutineAdapter::postAndYield(LLCoros::self & self, LLCore::HttpReques
 
     if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
     {
-        LLCore::HttpStatus status = request->getStatus();
-        LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
-            " message = " << status.getMessage() << LL_ENDL;
-
-        // Mimic the status results returned from an http error that we had 
-        // to wait on 
-        LLSD httpresults = LLSD::emptyMap();
-
-        httpHandler->writeStatusCodes(status, url, httpresults);
-
-        LLSD errorres = LLSD::emptyMap();
-        errorres["http_result"] = httpresults;
-
-        return errorres;
+        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url, httpHandler);
     }
 
+    mYieldingHandle = hhandle;
     LLSD results = waitForEventOn(self, replyPump);
+    mYieldingHandle = LLCORE_HTTP_HANDLE_INVALID;
     //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
     return results;
 }
 
-LLSD HttpCoroutineAdapter::putAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t & request,
+LLSD HttpCoroutineAdapter::putAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
     const std::string & url, const LLSD & body,
     LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
 {
@@ -402,28 +394,17 @@ LLSD HttpCoroutineAdapter::putAndYield(LLCoros::self & self, LLCore::HttpRequest
 
     if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
     {
-        LLCore::HttpStatus status = request->getStatus();
-        LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
-            " message = " << status.getMessage() << LL_ENDL;
-
-        // Mimic the status results returned from an http error that we had 
-        // to wait on 
-        LLSD httpresults = LLSD::emptyMap();
-
-        httpHandler->writeStatusCodes(status, url, httpresults);
-
-        LLSD errorres = LLSD::emptyMap();
-        errorres["http_result"] = httpresults;
-
-        return errorres;
+        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url, httpHandler);
     }
 
+    mYieldingHandle = hhandle;
     LLSD results = waitForEventOn(self, replyPump);
+    mYieldingHandle = LLCORE_HTTP_HANDLE_INVALID;
     //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
     return results;
 }
 
-LLSD HttpCoroutineAdapter::getAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t & request,
+LLSD HttpCoroutineAdapter::getAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
     const std::string & url,
     LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
 {
@@ -450,26 +431,34 @@ LLSD HttpCoroutineAdapter::getAndYield(LLCoros::self & self, LLCore::HttpRequest
 
     if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
     {
-        LLCore::HttpStatus status = request->getStatus();
-        LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
-            " message = " << status.getMessage() << LL_ENDL;
-
-        // Mimic the status results returned from an http error that we had 
-        // to wait on 
-        LLSD httpresults = LLSD::emptyMap();
-
-        httpHandler->writeStatusCodes(status, url, httpresults);
-
-        LLSD errorres = LLSD::emptyMap();
-        errorres["http_result"] = httpresults;
-
-        return errorres;
+        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url, httpHandler);
     }
 
+    mYieldingHandle = hhandle;
     LLSD results = waitForEventOn(self, replyPump);
+    mYieldingHandle = LLCORE_HTTP_HANDLE_INVALID;
     //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
     return results;
 }
 
+LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, 
+    const std::string &url, LLCoreHttpUtil::HttpCoroHandler::ptr_t &httpHandler) 
+{
+    LLCore::HttpStatus status = request->getStatus();
+    LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
+        " message = " << status.getMessage() << LL_ENDL;
+
+    // Mimic the status results returned from an http error that we had 
+    // to wait on 
+    LLSD httpresults = LLSD::emptyMap();
+
+    httpHandler->writeStatusCodes(status, url, httpresults);
+
+    LLSD errorres = LLSD::emptyMap();
+    errorres["http_result"] = httpresults;
+
+    return errorres;
+}
+
 } // end namespace LLCoreHttpUtil
 
diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h
index 10f46dd477..33cc389c49 100644
--- a/indra/llmessage/llcorehttputil.h
+++ b/indra/llmessage/llcorehttputil.h
@@ -210,36 +210,54 @@ private:
 class HttpCoroutineAdapter
 {
 public:
+    typedef boost::shared_ptr<HttpCoroutineAdapter> ptr_t;
+    typedef boost::weak_ptr<HttpCoroutineAdapter>   wptr_t;
+
     HttpCoroutineAdapter(const std::string &name, LLCore::HttpRequest::policy_t policyId, 
             LLCore::HttpRequest::priority_t priority = 0L);
     ~HttpCoroutineAdapter();
 
     /// Execute a Post transaction on the supplied URL and yield execution of 
-    /// the coroutine until a result is available.
-    LLSD postAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t & request,
+    /// the coroutine until a result is available. 
+    /// Note: the request's smart pointer is passed by value so that it will
+    /// not be deallocated during the yield.
+    LLSD postAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
         const std::string & url, const LLSD & body, 
-        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(), 
-        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t());
+        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false),
+        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false));
 
     /// Execute a Put transaction on the supplied URL and yield execution of 
     /// the coroutine until a result is available.
-    LLSD putAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t & request,
+    /// Note: the request's smart pointer is passed by value so that it will
+    /// not be deallocated during the yield.
+    LLSD putAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
         const std::string & url, const LLSD & body,
         LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(),
         LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t());
 
     /// Execute a Get transaction on the supplied URL and yield execution of 
     /// the coroutine until a result is available.
-    LLSD getAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t & request,
+    /// Note: the request's smart pointer is passed by value so that it will
+    /// not be deallocated during the yield.
+    LLSD getAndYield(LLCoros::self & self, LLCore::HttpRequest::ptr_t request,
         const std::string & url,
         LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(),
         LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t());
 
+    ///
+    void cancelYieldingOperation();
+
 private:
+    static LLSD buildImmediateErrorResult(const LLCore::HttpRequest::ptr_t &request, 
+            const std::string &url, LLCoreHttpUtil::HttpCoroHandler::ptr_t &httpHandler);
 
     std::string                     mAdapterName;
     LLCore::HttpRequest::priority_t mPriority;
     LLCore::HttpRequest::policy_t   mPolicyId;
+
+    LLCore::HttpHandle              mYieldingHandle;
+    LLCore::HttpRequest::wptr_t     mWeakRequest;
+
 };
 
 } // end namespace LLCoreHttpUtil
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index 4de6ad4d2f..493ee06083 100755
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -37,254 +37,460 @@
 #include "llviewerregion.h"
 #include "message.h"
 #include "lltrans.h"
+#include "llcoros.h"
+#include "lleventcoro.h"
+#include "llcorehttputil.h"
 
 namespace
 {
-	// We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
-	// This means we attempt to recover relatively quickly but back off giving more time to recover
-	// until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
-	const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
-	const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
-	const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
-
-	class LLEventPollResponder : public LLHTTPClient::Responder
-	{
-		LOG_CLASS(LLEventPollResponder);
-	public:
-		
-		static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
-		void stop();
-		
-		void makeRequest();
-
-		/* virtual */ void completedRaw(const LLChannelDescriptors& channels,
-								  const LLIOPipe::buffer_ptr_t& buffer);
-
-	private:
-		LLEventPollResponder(const std::string&	pollURL, const LLHost& sender);
-		~LLEventPollResponder();
-
-		
-		void handleMessage(const LLSD& content);
-
-		/* virtual */ void httpFailure();
-		/* virtual */ void httpSuccess();
-
-	private:
-
-		bool	mDone;
-
-		std::string			mPollURL;
-		std::string			mSender;
-		
-		LLSD	mAcknowledge;
-		
-		// these are only here for debugging so	we can see which poller	is which
-		static int sCount;
-		int	mCount;
-		S32 mErrorCount;
-	};
-
-	class LLEventPollEventTimer : public LLEventTimer
-	{
-		typedef LLPointer<LLEventPollResponder> EventPollResponderPtr;
-
-	public:
-		LLEventPollEventTimer(F32 period, EventPollResponderPtr responder)
-			: LLEventTimer(period), mResponder(responder)
-		{ }
-
-		virtual BOOL tick()
-		{
-			mResponder->makeRequest();
-			return TRUE;	// Causes this instance to be deleted.
-		}
-
-	private:
-		
-		EventPollResponderPtr mResponder;
-	};
-
-	//static
-	LLHTTPClient::ResponderPtr LLEventPollResponder::start(
-		const std::string& pollURL, const LLHost& sender)
-	{
-		LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender);
-		LL_INFOS()	<< "LLEventPollResponder::start <" << sCount << "> "
-				<< pollURL << LL_ENDL;
-		return result;
-	}
-
-	void LLEventPollResponder::stop()
-	{
-		LL_INFOS()	<< "LLEventPollResponder::stop	<" << mCount <<	"> "
-				<< mPollURL	<< LL_ENDL;
-		// there should	be a way to	stop a LLHTTPClient	request	in progress
-		mDone =	true;
-	}
-
-	int	LLEventPollResponder::sCount =	0;
-
-	LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender)
-		: mDone(false),
-		  mPollURL(pollURL),
-		  mCount(++sCount),
-		  mErrorCount(0)
-	{
-		//extract host and port of simulator to set as sender
-		LLViewerRegion *regionp = gAgent.getRegion();
-		if (!regionp)
-		{
-			LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL;
-		}
-		mSender = sender.getIPandPort();
-		LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL;
-		makeRequest();
-	}
-
-	LLEventPollResponder::~LLEventPollResponder()
-	{
-		stop();
-		LL_DEBUGS() <<	"LLEventPollResponder::~Impl <" <<	mCount << "> "
-				 <<	mPollURL <<	LL_ENDL;
-	}
-
-	// virtual 
-	void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels,
-											const LLIOPipe::buffer_ptr_t& buffer)
-	{
-		if (getStatus() == HTTP_BAD_GATEWAY)
-		{
-			// These errors are not parsable as LLSD, 
-			// which LLHTTPClient::Responder::completedRaw will try to do.
-			httpCompleted();
-		}
-		else
-		{
-			LLHTTPClient::Responder::completedRaw(channels,buffer);
-		}
-	}
-
-	void LLEventPollResponder::makeRequest()
-	{
-		LLSD request;
-		request["ack"] = mAcknowledge;
-		request["done"]	= mDone;
-		
-		LL_DEBUGS() <<	"LLEventPollResponder::makeRequest	<" << mCount <<	"> ack = "
-				 <<	LLSDXMLStreamer(mAcknowledge) << LL_ENDL;
-		LLHTTPClient::post(mPollURL, request, this);
-	}
-
-	void LLEventPollResponder::handleMessage(const	LLSD& content)
-	{
-		std::string	msg_name	= content["message"];
-		LLSD message;
-		message["sender"] = mSender;
-		message["body"] = content["body"];
-		LLMessageSystem::dispatch(msg_name, message);
-	}
-
-	//virtual
-	void LLEventPollResponder::httpFailure()
-	{
-		if (mDone) return;
-
-		// A HTTP_BAD_GATEWAY (502) error is our standard timeout response
-		// we get this when there are no events.
-		if ( getStatus() == HTTP_BAD_GATEWAY )
-		{
-			mErrorCount = 0;
-			makeRequest();
-		}
-		else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS)
-		{
-			++mErrorCount;
-			
-			// The 'tick' will return TRUE causing the timer to delete this.
-			new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS
-										+ mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
-									, this);
-
-			LL_WARNS() << dumpResponse() << LL_ENDL;
-		}
-		else
-		{
-			LL_WARNS() << dumpResponse()
-					   << " [count:" << mCount << "] "
-					   << (mDone ? " -- done" : "") << LL_ENDL;
-			stop();
-
-			// At this point we have given up and the viewer will not receive HTTP messages from the simulator.
-			// IMs, teleports, about land, selecing land, region crossing and more will all fail.
-			// They are essentially disconnected from the region even though some things may still work.
-			// Since things won't get better until they relog we force a disconnect now.
-
-			// *NOTE:Mani - The following condition check to see if this failing event poll
-			// is attached to the Agent's main region. If so we disconnect the viewer.
-			// Else... its a child region and we just leave the dead event poll stopped and 
-			// continue running.
-			if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender)
-			{
-				LL_WARNS() << "Forcing disconnect due to stalled main region event poll."  << LL_ENDL;
-				LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
-			}
-		}
-	}
-
-	//virtual
-	void LLEventPollResponder::httpSuccess()
-	{
-		LL_DEBUGS() <<	"LLEventPollResponder::result <" << mCount	<< ">"
-				 <<	(mDone ? " -- done"	: "") << LL_ENDL;
-		
-		if (mDone) return;
-
-		mErrorCount = 0;
-
-		const LLSD& content = getContent();
-		if (!content.isMap() ||
-			!content.get("events") ||
-			!content.get("id"))
-		{
-			LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL;
-			makeRequest();
-			return;
-		}
-		
-		mAcknowledge = content["id"];
-		LLSD events	= content["events"];
-
-		if(mAcknowledge.isUndefined())
-		{
-			LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL;
-		}
-		
-		// was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
-		LL_DEBUGS()  << "LLEventPollResponder::httpSuccess <" <<	mCount << "> " << events.size() << "events (id "
-					 <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL;
-		
-		LLSD::array_const_iterator i = events.beginArray();
-		LLSD::array_const_iterator end = events.endArray();
-		for	(; i !=	end; ++i)
-		{
-			if (i->has("message"))
-			{
-				handleMessage(*i);
-			}
-		}
-		
-		makeRequest();
-	}	
+    // We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
+    // This means we attempt to recover relatively quickly but back off giving more time to recover
+    // until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
+    const F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
+    const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
+    const S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
+
+#if 1
+
+    class LLEventPollImpl
+    {
+    public:
+        LLEventPollImpl(const LLHost &sender);
+
+        void start(const std::string &url);
+        void stop();
+    private:
+        void eventPollCoro(LLCoros::self& self, std::string url);
+
+        void                            handleMessage(const LLSD &content);
+
+        bool                            mDone;
+        LLCore::HttpRequest::ptr_t      mHttpRequest;
+        LLCore::HttpRequest::policy_t   mHttpPolicy;
+        std::string                     mSenderIp;
+        int                             mCounter;
+
+        static int                      sNextCounter;
+    };
+
+
+    int LLEventPollImpl::sNextCounter = 1;
+
+
+    LLEventPollImpl::LLEventPollImpl(const LLHost &sender) :
+        mDone(false),
+        mHttpRequest(),
+        mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+        mSenderIp(),
+        mCounter(sNextCounter++)
+
+    {
+        mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
+        mSenderIp = sender.getIPandPort();
+    }
+
+    void LLEventPollImpl::handleMessage(const LLSD& content)
+    {
+        std::string	msg_name = content["message"];
+        LLSD message;
+        message["sender"] = mSenderIp;
+        message["body"] = content["body"];
+        LLMessageSystem::dispatch(msg_name, message);
+    }
+
+    void LLEventPollImpl::start(const std::string &url)
+    {
+        if (!url.empty())
+        {
+            std::string coroname =
+                LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro",
+                boost::bind(&LLEventPollImpl::eventPollCoro, this, _1, url));
+            LL_DEBUGS() << coroname << " with  url '" << url << LL_ENDL;
+        }
+    }
+
+    void LLEventPollImpl::stop()
+    {
+        mDone = true;
+    }
+
+    void LLEventPollImpl::eventPollCoro(LLCoros::self& self, std::string url)
+    {
+        LLCoreHttpUtil::HttpCoroutineAdapter httpAdapter("EventPoller", mHttpPolicy);
+        LLSD acknowledge;
+        int errorCount = 0;
+        int counter = mCounter; // saved on the stack for debugging.
+
+        LL_INFOS("LLEventPollImpl::eventPollCoro") << " <" << counter << "> entering coroutine." << LL_ENDL;
+
+        while (!mDone)
+        {
+            LLSD request;
+            request["ack"] = acknowledge;
+            request["done"] = mDone;
+
+//            LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> request = "
+//                << LLSDXMLStreamer(request) << LL_ENDL;
+
+            LL_INFOS("LLEventPollImpl::eventPollCoro") << " <" << counter << "> posting and yielding." << LL_ENDL;
+            LLSD result = httpAdapter.postAndYield(self, mHttpRequest, url, request);
+
+//            LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = "
+//                << LLSDXMLStreamer(result) << LL_ENDL;
+
+            if (mDone)
+                break;
+
+            LLSD httpResults;
+            httpResults = result["http_result"];
+
+
+            if (!httpResults["success"].asBoolean())
+            {
+                LL_WARNS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
+                    << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL;
+
+                if (httpResults["status"].asInteger() == HTTP_BAD_GATEWAY)
+                {
+                    // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
+                    // we get this when there are no events.
+                    errorCount = 0;
+                    continue;
+                }
+
+                LL_WARNS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> " << LLSDXMLStreamer(result) << (mDone ? " -- done" : "") << LL_ENDL;
+
+                if (errorCount < MAX_EVENT_POLL_HTTP_ERRORS)
+                {
+                    ++errorCount;
+
+                    // The 'tick' will return TRUE causing the timer to delete this.
+                    int waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS
+                        + errorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC;
+
+                    LL_WARNS() << "Retrying in " << waitToRetry <<
+                        " seconds, error count is now " << errorCount << LL_ENDL;
+
+                    // *TODO: Wait for a timeout here
+                    //                     new LLEventPollEventTimer(
+                    //                         , this);
+                    continue;
+                }
+                else
+                {
+                    // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
+                    // IMs, teleports, about land, selecting land, region crossing and more will all fail.
+                    // They are essentially disconnected from the region even though some things may still work.
+                    // Since things won't get better until they relog we force a disconnect now.
+
+                    mDone = true;
+
+                    // *NOTE:Mani - The following condition check to see if this failing event poll
+                    // is attached to the Agent's main region. If so we disconnect the viewer.
+                    // Else... its a child region and we just leave the dead event poll stopped and 
+                    // continue running.
+                    if (gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSenderIp)
+                    {
+                        LL_WARNS("LLEventPollImpl::eventPollCoro") << "< " << counter << "> Forcing disconnect due to stalled main region event poll." << LL_ENDL;
+                        LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
+                    }
+                    break;
+                }
+            }
+
+            LL_DEBUGS("LLEventPollImpl::eventPollCoro") << " <" << counter << ">"
+                << (mDone ? " -- done" : "") << LL_ENDL;
+
+            errorCount = 0;
+
+            if (!result.isMap() ||
+                !result.get("events") ||
+                !result.get("id"))
+            {
+                LL_WARNS("LLEventPollImpl::eventPollCoro") << " <" << counter << "> received event poll with no events or id key: " << LLSDXMLStreamer(result) << LL_ENDL;
+                continue;
+            }
+
+            acknowledge = result["id"];
+            LLSD events = result["events"];
+
+            if (acknowledge.isUndefined())
+            {
+                LL_WARNS("LLEventPollImpl::eventPollCoro") << " id undefined" << LL_ENDL;
+            }
+
+            // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
+            LL_DEBUGS() << "LLEventPollResponder::httpSuccess <" << counter << "> " << events.size() << "events (id "
+                << LLSDXMLStreamer(acknowledge) << ")" << LL_ENDL;
+
+            LLSD::array_const_iterator i = events.beginArray();
+            LLSD::array_const_iterator end = events.endArray();
+            for (; i != end; ++i)
+            {
+                if (i->has("message"))
+                {
+                    handleMessage(*i);
+                }
+            }
+        }
+        LL_INFOS("LLEventPollImpl::eventPollCoro") << " <" << counter << "> Leaving coroutine." << LL_ENDL;
+
+    }
+
+#else
+    class LLEventPollResponder : public LLHTTPClient::Responder
+    {
+        LOG_CLASS(LLEventPollResponder);
+    public:
+
+        static LLHTTPClient::ResponderPtr start(const std::string& pollURL, const LLHost& sender);
+        void stop();
+
+        void makeRequest();
+
+        /* virtual */ void completedRaw(const LLChannelDescriptors& channels,
+            const LLIOPipe::buffer_ptr_t& buffer);
+
+    private:
+        LLEventPollResponder(const std::string&	pollURL, const LLHost& sender);
+        ~LLEventPollResponder();
+
+
+        void handleMessage(const LLSD& content);
+
+        /* virtual */ void httpFailure();
+        /* virtual */ void httpSuccess();
+
+    private:
+
+        bool	mDone;
+
+        std::string			mPollURL;
+        std::string			mSender;
+
+        LLSD	mAcknowledge;
+
+        // these are only here for debugging so	we can see which poller	is which
+        static int sCount;
+        int	mCount;
+        S32 mErrorCount;
+    };
+
+    class LLEventPollEventTimer : public LLEventTimer
+    {
+        typedef LLPointer<LLEventPollResponder> EventPollResponderPtr;
+
+    public:
+        LLEventPollEventTimer(F32 period, EventPollResponderPtr responder)
+            : LLEventTimer(period), mResponder(responder)
+        { }
+
+        virtual BOOL tick()
+        {
+            mResponder->makeRequest();
+            return TRUE;	// Causes this instance to be deleted.
+        }
+
+    private:
+
+        EventPollResponderPtr mResponder;
+    };
+
+    //static
+    LLHTTPClient::ResponderPtr LLEventPollResponder::start(
+        const std::string& pollURL, const LLHost& sender)
+    {
+        LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender);
+        LL_INFOS()	<< "LLEventPollResponder::start <" << sCount << "> "
+            << pollURL << LL_ENDL;
+        return result;
+    }
+
+    void LLEventPollResponder::stop()
+    {
+        LL_INFOS()	<< "LLEventPollResponder::stop	<" << mCount <<	"> "
+            << mPollURL	<< LL_ENDL;
+        // there should	be a way to	stop a LLHTTPClient	request	in progress
+        mDone =	true;
+    }
+
+    int	LLEventPollResponder::sCount =	0;
+
+    LLEventPollResponder::LLEventPollResponder(const std::string& pollURL, const LLHost& sender)
+        : mDone(false),
+        mPollURL(pollURL),
+        mCount(++sCount),
+        mErrorCount(0)
+    {
+        //extract host and port of simulator to set as sender
+        LLViewerRegion *regionp = gAgent.getRegion();
+        if (!regionp)
+        {
+            LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL;
+        }
+        mSender = sender.getIPandPort();
+        LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL;
+        makeRequest();
+    }
+
+    LLEventPollResponder::~LLEventPollResponder()
+    {
+        stop();
+        LL_DEBUGS() <<	"LLEventPollResponder::~Impl <" <<	mCount << "> "
+            <<	mPollURL <<	LL_ENDL;
+    }
+
+    // virtual 
+    void LLEventPollResponder::completedRaw(const LLChannelDescriptors& channels,
+        const LLIOPipe::buffer_ptr_t& buffer)
+    {
+        if (getStatus() == HTTP_BAD_GATEWAY)
+        {
+            // These errors are not parsable as LLSD, 
+            // which LLHTTPClient::Responder::completedRaw will try to do.
+            httpCompleted();
+        }
+        else
+        {
+            LLHTTPClient::Responder::completedRaw(channels,buffer);
+        }
+    }
+
+    void LLEventPollResponder::makeRequest()
+    {
+        LLSD request;
+        request["ack"] = mAcknowledge;
+        request["done"]	= mDone;
+
+        LL_DEBUGS() <<	"LLEventPollResponder::makeRequest	<" << mCount <<	"> ack = "
+            <<	LLSDXMLStreamer(mAcknowledge) << LL_ENDL;
+        LLHTTPClient::post(mPollURL, request, this);
+    }
+
+    void LLEventPollResponder::handleMessage(const	LLSD& content)
+    {
+        std::string	msg_name	= content["message"];
+        LLSD message;
+        message["sender"] = mSender;
+        message["body"] = content["body"];
+        LLMessageSystem::dispatch(msg_name, message);
+    }
+
+    //virtual
+    void LLEventPollResponder::httpFailure()
+    {
+        if (mDone) return;
+
+        // A HTTP_BAD_GATEWAY (502) error is our standard timeout response
+        // we get this when there are no events.
+        if ( getStatus() == HTTP_BAD_GATEWAY )
+        {
+            mErrorCount = 0;
+            makeRequest();
+        }
+        else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS)
+        {
+            ++mErrorCount;
+
+            // The 'tick' will return TRUE causing the timer to delete this.
+            new LLEventPollEventTimer(EVENT_POLL_ERROR_RETRY_SECONDS
+                + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC
+                , this);
+
+            LL_WARNS() << dumpResponse() << LL_ENDL;
+        }
+        else
+        {
+            LL_WARNS() << dumpResponse()
+                << " [count:" << mCount << "] "
+                << (mDone ? " -- done" : "") << LL_ENDL;
+            stop();
+
+            // At this point we have given up and the viewer will not receive HTTP messages from the simulator.
+            // IMs, teleports, about land, selecing land, region crossing and more will all fail.
+            // They are essentially disconnected from the region even though some things may still work.
+            // Since things won't get better until they relog we force a disconnect now.
+
+            // *NOTE:Mani - The following condition check to see if this failing event poll
+            // is attached to the Agent's main region. If so we disconnect the viewer.
+            // Else... its a child region and we just leave the dead event poll stopped and 
+            // continue running.
+            if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender)
+            {
+                LL_WARNS() << "Forcing disconnect due to stalled main region event poll."  << LL_ENDL;
+                LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
+            }
+        }
+    }
+
+    //virtual
+    void LLEventPollResponder::httpSuccess()
+    {
+        LL_DEBUGS() <<	"LLEventPollResponder::result <" << mCount	<< ">"
+            <<	(mDone ? " -- done"	: "") << LL_ENDL;
+
+        if (mDone) return;
+
+        mErrorCount = 0;
+
+        const LLSD& content = getContent();
+        if (!content.isMap() ||
+            !content.get("events") ||
+            !content.get("id"))
+        {
+            LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL;
+            makeRequest();
+            return;
+        }
+
+        mAcknowledge = content["id"];
+        LLSD events	= content["events"];
+
+        if(mAcknowledge.isUndefined())
+        {
+            LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL;
+        }
+
+        // was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
+        LL_DEBUGS()  << "LLEventPollResponder::httpSuccess <" <<	mCount << "> " << events.size() << "events (id "
+            <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL;
+
+        LLSD::array_const_iterator i = events.beginArray();
+        LLSD::array_const_iterator end = events.endArray();
+        for	(; i !=	end; ++i)
+        {
+            if (i->has("message"))
+            {
+                handleMessage(*i);
+            }
+        }
+
+        makeRequest();
+    }	
 }
 
 LLEventPoll::LLEventPoll(const std::string&	poll_url, const LLHost& sender)
-	: mImpl(LLEventPollResponder::start(poll_url, sender))
-	{ }
+    : mImpl(LLEventPollResponder::start(poll_url, sender))
+{ }
 
 LLEventPoll::~LLEventPoll()
 {
-	LLHTTPClient::Responder* responderp = mImpl.get();
-	LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp);
-	if (event_poll_responder) event_poll_responder->stop();
+    LLHTTPClient::Responder* responderp = mImpl.get();
+    LLEventPollResponder* event_poll_responder = dynamic_cast<LLEventPollResponder*>(responderp);
+    if (event_poll_responder) event_poll_responder->stop();
+}
+#endif
+}
+
+LLEventPoll::LLEventPoll(const std::string&	poll_url, const LLHost& sender):
+    mImpl()
+{ 
+    mImpl = boost::unique_ptr<LLEventPollImpl>(new LLEventPollImpl(sender));
+    mImpl->start(poll_url);
+}
+
+LLEventPoll::~LLEventPoll()
+{
+    mImpl->stop();
+
 }
diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h
index e8d98062aa..4b9944724d 100755
--- a/indra/newview/lleventpoll.h
+++ b/indra/newview/lleventpoll.h
@@ -28,9 +28,20 @@
 #define LL_LLEVENTPOLL_H
 
 #include "llhttpclient.h"
+#include "boost/move/unique_ptr.hpp"
+
+namespace boost
+{
+    using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace.
+}
 
 class LLHost;
 
+namespace
+{
+    class LLEventPollImpl;
+}
+
 
 class LLEventPoll
 	///< implements the viewer side of server-to-viewer pushed events.
@@ -40,11 +51,15 @@ public:
 		///< Start polling the URL.
 
 	virtual ~LLEventPoll();
-		///< will stop polling, cancelling any poll in progress.
+		///< will stop polling, canceling any poll in progress.
 
 
 private:
+#if 1
+    boost::unique_ptr<LLEventPollImpl>    mImpl;
+#else
 	LLHTTPClient::ResponderPtr mImpl;
+#endif
 };
 
 
-- 
cgit v1.2.3