diff options
-rw-r--r-- | indra/newview/llstartup.cpp | 19 | ||||
-rw-r--r-- | indra/newview/llviewerregion.cpp | 223 | ||||
-rw-r--r-- | indra/newview/llviewerregion.h | 7 | ||||
-rw-r--r-- | indra/newview/llvoavatar.cpp | 5 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 2 |
5 files changed, 164 insertions, 92 deletions
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4dfcb85295..46ff3d808a 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1242,6 +1242,25 @@ bool idle_startup() //--------------------------------------------------------------------- if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + if (regionp->capabilitiesReceived()) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + else + { + U32 num_retries = regionp->getNumSeedCapRetries(); + if (num_retries > 0) + { + LLStringUtil::format_map_t args; + args["[NUMBER]"] = llformat("%d", num_retries + 1); + set_startup_status(0.4f, LLTrans::getString("LoginRetrySeedCapGrant", args), gAgent.mMOTD); + } + else + { + set_startup_status(0.4f, LLTrans::getString("LoginRequestSeedCapGrant"), gAgent.mMOTD); + } + } return FALSE; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 5b7492b66f..5be2234ec2 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -77,6 +77,13 @@ const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; +// The server only keeps our pending agent info for 60 seconds. +// We want to allow for seed cap retry, but its not useful after that 60 seconds. +// Give it 3 chances, each at 18 seconds to give ourselves a few seconds to connect anyways if we give up. +const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; +const F32 CAP_REQUEST_TIMEOUT = 18; +// Even though we gave up on login, keep trying for caps after we are logged in: +const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; typedef std::map<std::string, std::string> CapabilityMap; @@ -86,6 +93,10 @@ public: : mHost(host), mCompositionp(NULL), mEventPoll(NULL), + mSeedCapMaxAttempts(MAX_CAP_REQUEST_ATTEMPTS), + mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), + mSeedCapAttempts(0), + mHttpResponderID(0), // I'd prefer to set the LLCapabilityListener name to match the region // name -- it's disappointing that's not available at construction time. // We could instead store an LLCapabilityListener*, making @@ -100,6 +111,8 @@ public: { } + void buildCapabilityNames(LLSD& capabilityNames); + // The surfaces and other layers LLSurface* mLandp; @@ -132,6 +145,12 @@ public: LLEventPoll* mEventPoll; + S32 mSeedCapMaxAttempts; + S32 mSeedCapMaxAttemptsBeforeLogin; + S32 mSeedCapAttempts; + + S32 mHttpResponderID; + /// Post an event to this LLCapabilityListener to invoke a capability message on /// this LLViewerRegion's server /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) @@ -139,8 +158,6 @@ public: //spatial partitions for objects in this region std::vector<LLSpatialPartition*> mObjectPartition; - - LLHTTPClient::ResponderPtr mHttpResponderPtr ; }; // support for secondlife:///app/region/{REGION} SLapps @@ -186,69 +203,51 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder { LOG_CLASS(BaseCapabilitiesComplete); public: - BaseCapabilitiesComplete(LLViewerRegion* region, S32 retry = 0) - : mRegion(region), mRetry(retry) + BaseCapabilitiesComplete(U64 region_handle, S32 id) + : mRegionHandle(region_handle), mID(id) { } virtual ~BaseCapabilitiesComplete() - { - if(mRegion) - { - mRegion->setHttpResponderPtrNULL() ; - } - } - - void setRegion(LLViewerRegion* region) - { - mRegion = region ; - } + { } void error(U32 statusNum, const std::string& reason) { LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; - - const S32 MAX_RETRIES = 5; - - if (mRetry < MAX_RETRIES) - { - std::string url = mRegion->getCapability("Seed"); - - mRetry++; - - llinfos << "retry " << mRetry << " posting to seed " << url << llendl; - - mRegion->setSeedCapability(url, mRetry); - } - else + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) { - if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) - { - LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); - } + regionp->failedSeedCapability(); } } void result(const LLSD& content) { - if(!mRegion || LLHTTPClient::ResponderPtr(this) != mRegion->getHttpResponderPtr()) //region is removed or responder is not created. + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region was removed + { + LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder { + LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; return ; } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { - mRegion->setCapability(iter->first, iter->second); + regionp->setCapability(iter->first, iter->second); LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " << iter->first << LL_ENDL; /* HACK we're waiting for the ServerReleaseNotes */ - if (iter->first == "ServerReleaseNotes" && mRegion->getReleaseNotesRequested()) + if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) { - mRegion->showReleaseNotes(); + regionp->showReleaseNotes(); } } - mRegion->setCapabilitiesReceived(true); + regionp->setCapabilitiesReceived(true); if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { @@ -256,16 +255,15 @@ public: } } - static boost::intrusive_ptr<BaseCapabilitiesComplete> build( - LLViewerRegion* region, S32 retry) + static boost::intrusive_ptr<BaseCapabilitiesComplete> build( U64 region_handle, S32 id ) { - return boost::intrusive_ptr<BaseCapabilitiesComplete>( - new BaseCapabilitiesComplete(region, retry)); + return boost::intrusive_ptr<BaseCapabilitiesComplete>( + new BaseCapabilitiesComplete(region_handle, id) ); } private: - LLViewerRegion* mRegion; - S32 mRetry; + U64 mRegionHandle; + S32 mID; }; @@ -356,11 +354,6 @@ void LLViewerRegion::initStats() LLViewerRegion::~LLViewerRegion() { - if(mImpl->mHttpResponderPtr) - { - (static_cast<BaseCapabilitiesComplete*>(mImpl->mHttpResponderPtr.get()))->setRegion(NULL) ; - } - gVLManager.cleanupData(this); // Can't do this on destruction, because the neighbor pointers might be invalid. // This should be reference counted... @@ -907,14 +900,9 @@ U32 LLViewerRegion::getPacketsLost() const } } -void LLViewerRegion::setHttpResponderPtrNULL() -{ - mImpl->mHttpResponderPtr = NULL; -} - -const LLHTTPClient::ResponderPtr LLViewerRegion::getHttpResponderPtr() const +S32 LLViewerRegion::getHttpResponderID() const { - return mImpl->mHttpResponderPtr; + return mImpl->mHttpResponderID; } BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const @@ -1493,22 +1481,9 @@ void LLViewerRegion::unpackRegionHandshake() msg->sendReliable(host); } -void LLViewerRegion::setSeedCapability(const std::string& url, S32 retry) -{ - if (retry == 0 && getCapability("Seed") == url) - { - // llwarns << "Ignoring duplicate seed capability" << llendl; - return; - } - - delete mImpl->mEventPoll; - mImpl->mEventPoll = NULL; - - mImpl->mCapabilities.clear(); - setCapability("Seed", url); - - LLSD capabilityNames = LLSD::emptyArray(); +void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) +{ capabilityNames.append("AccountingParcel"); capabilityNames.append("AccountingSelection"); capabilityNames.append("AttachmentResources"); @@ -1582,46 +1557,118 @@ void LLViewerRegion::setSeedCapability(const std::string& url, S32 retry) // Please add new capabilities alphabetically to reduce // merge conflicts. +} + +void LLViewerRegion::setSeedCapability(const std::string& url) +{ + if (getCapability("Seed") == url) + { + // llwarns << "Ignoring duplicate seed capability" << llendl; + return; + } + + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + + mImpl->mCapabilities.clear(); + setCapability("Seed", url); + + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); llinfos << "posting to seed " << url << llendl; - mImpl->mHttpResponderPtr = BaseCapabilitiesComplete::build(this, retry) ; - LLHTTPClient::post(url, capabilityNames, mImpl->mHttpResponderPtr); + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); +} + +S32 LLViewerRegion::getNumSeedCapRetries() +{ + return mImpl->mSeedCapAttempts; +} + +void LLViewerRegion::failedSeedCapability() +{ + // Should we retry asking for caps? + mImpl->mSeedCapAttempts++; + std::string url = getCapability("Seed"); + if ( url.empty() ) + { + LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; + return; + } + // After a few attempts, continue login. We will keep trying once in-world: + if ( mImpl->mSeedCapAttempts >= mImpl->mSeedCapMaxAttemptsBeforeLogin && + STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState() ) + { + LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED ); + } + + if ( mImpl->mSeedCapAttempts < mImpl->mSeedCapMaxAttempts) + { + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames(capabilityNames); + + llinfos << "posting to seed " << url << " (retry " + << mImpl->mSeedCapAttempts << ")" << llendl; + + S32 id = ++mImpl->mHttpResponderID; + LLHTTPClient::post(url, capabilityNames, + BaseCapabilitiesComplete::build(getHandle(), id), + LLSD(), CAP_REQUEST_TIMEOUT); + } + else + { + // *TODO: Give a user pop-up about this error? + LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + } } class SimulatorFeaturesReceived : public LLHTTPClient::Responder { LOG_CLASS(SimulatorFeaturesReceived); public: - SimulatorFeaturesReceived(LLViewerRegion* region) - : mRegion(region) + SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) { } void error(U32 statusNum, const std::string& reason) { LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL; + retry(); } - + void result(const LLSD& content) { - if(!mRegion) //region is removed or responder is not created. + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if(!regionp) //region is removed or responder is not created. { + LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; return ; } - mRegion->setSimulatorFeatures(content); + regionp->setSimulatorFeatures(content); } - - static boost::intrusive_ptr<SimulatorFeaturesReceived> build( - LLViewerRegion* region) - { - return boost::intrusive_ptr<SimulatorFeaturesReceived>( - new SimulatorFeaturesReceived(region)); - } - + private: - LLViewerRegion* mRegion; + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; }; @@ -1640,7 +1687,7 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // kick off a request for simulator features - LLHTTPClient::get(url, new SimulatorFeaturesReceived(this)); + LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle()), LLSD(), CAP_REQUEST_TIMEOUT); } else { diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 0176969cea..b3c19ea58d 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -226,11 +226,12 @@ public: U32 getPacketsLost() const; - void setHttpResponderPtrNULL(); - const LLHTTPClient::ResponderPtr getHttpResponderPtr() const; + S32 getHttpResponderID() const; // Get/set named capability URLs for this region. - void setSeedCapability(const std::string& url, S32 retry = 0); + void setSeedCapability(const std::string& url); + void failedSeedCapability(); + S32 getNumSeedCapRetries(); void setCapability(const std::string& name, const std::string& url); // implements LLCapabilityProvider virtual std::string getCapability(const std::string& name) const; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5c977492d8..b5be3cd552 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1133,7 +1133,10 @@ void LLVOAvatar::initClass() llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl; } // parse avatar_lad.xml - llassert(!sAvatarXmlInfo); + if (sAvatarXmlInfo) + { //this can happen if a login attempt failed + deleteAndClear(sAvatarXmlInfo); + } sAvatarXmlInfo = new LLVOAvatarXmlInfo; if (!sAvatarXmlInfo->parseXmlSkeletonNode(root)) { diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 022c97f341..cb371edacf 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -43,6 +43,8 @@ <string name="LoginInitializingQuicktime">Initializing QuickTime...</string> <string name="LoginQuicktimeNotFound">QuickTime not found - unable to initialize.</string> <string name="LoginQuicktimeOK">QuickTime initialized successfully.</string> + <string name="LoginRequestSeedCapGrant">Requesting region capabilities...</string> + <string name="LoginRetrySeedCapGrant">Requesting region capabilities, attempt [NUMBER]...</string> <string name="LoginWaitingForRegionHandshake">Waiting for region handshake...</string> <string name="LoginConnectingToRegion">Connecting to region...</string> <string name="LoginDownloadingClothing">Downloading clothing...</string> |