diff options
| author | Rider Linden <none@none> | 2015-04-08 10:17:34 -0700 | 
|---|---|---|
| committer | Rider Linden <none@none> | 2015-04-08 10:17:34 -0700 | 
| commit | 1c91c8a106a78f2087a3fb4312e428a0128283b4 (patch) | |
| tree | 1f80ff372a3a9c2670049f76cde4d6782661dfe9 /indra | |
| parent | fe34b3ef725b83af0deeffcf8bf6ef9769224e8d (diff) | |
Adding weak pointer support.
Event polling as a coroutine. (incomplete)
Groundwork for canceling HttpCoroutineAdapter yields.
Diffstat (limited to 'indra')
| -rwxr-xr-x | indra/llcorehttp/httpcommon.h | 1 | ||||
| -rwxr-xr-x | indra/llcorehttp/httprequest.h | 1 | ||||
| -rw-r--r-- | indra/llmessage/llcorehttputil.cpp | 81 | ||||
| -rw-r--r-- | indra/llmessage/llcorehttputil.h | 30 | ||||
| -rwxr-xr-x | indra/newview/lleventpoll.cpp | 688 | ||||
| -rwxr-xr-x | 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  }; | 
