Introduces AIHTTPTimeoutPolicy objects which do not just specify a single "timeout" in seconds, but a plethora of timings related to the life cycle of the average HTTP transaction. This knowledge is that moved to the Responder being used instead of floating constants hardcoded in the callers of http requests. This assumes that the same timeout policy is wanted for each transaction that uses the same Responder, which can be enforced is needed. I added a AIHTTPTimeoutPolicy for EVERY responder, only to make it easier later to tune timeout values and/or to get feedback about which responder runs into HTTP errors in debug output (especially time outs), so that they can be tuned later. If we already understood exactly what we were doing then most responders could have been left alone and just return the default timeout policy: by far most timeout policies are just a copy of the default policy, currently. This commit is not finished... It's a work in progress (viewer runs fine with it though).
333 lines
13 KiB
C++
333 lines
13 KiB
C++
/**
|
|
* @file llfloaterteleport.cpp
|
|
* @brief floater code for agentd teleports.
|
|
*
|
|
* $LicenseInfo:firstyear=2008&license=viewergpl$
|
|
*
|
|
* Copyright (c) 2008, Linden Research, Inc.
|
|
*
|
|
* Second Life Viewer Source Code
|
|
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
* to you under the terms of the GNU General Public License, version 2.0
|
|
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
*
|
|
* There are special exceptions to the terms and conditions of the GPL as
|
|
* it is applied to this Source Code. View the full text of the exception
|
|
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
*
|
|
* By copying, modifying or distributing this software, you acknowledge
|
|
* that you have read and understood your obligations described above,
|
|
* and agree to abide by those obligations.
|
|
*
|
|
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
* COMPLETENESS OR PERFORMANCE.
|
|
* $/LicenseInfo$
|
|
*/
|
|
//Teleport floater used for agent domain TP. URI text floater.
|
|
//Copyright International Business Machines Corporation 2008-9
|
|
//Contributed to Linden Research, Inc. under the Second Life Viewer Contribution
|
|
//Agreement and licensed as above.
|
|
#include "llviewerprecompiledheaders.h" // must be first include
|
|
|
|
#include "llfloaterteleport.h"
|
|
|
|
#include "llagent.h" //for hack in teleport start
|
|
#include "llchat.h"
|
|
#include "llcombobox.h"
|
|
#include "llfloaterchat.h"
|
|
#include "llsdserialize.h"
|
|
#include "llsdutil.h"
|
|
#include "llsdutil_math.h"
|
|
#include "lluictrlfactory.h" // builds floaters from XML
|
|
#include "llurlhistory.h"
|
|
#include "lluserauth.h" // for saving placeavatarresponder result
|
|
#include "llviewercontrol.h" // for gSavedSettings
|
|
#include "llviewerdisplay.h" // for gTeleportDisplay
|
|
#include "llviewermessage.h" // for send_agent_movement_complete attempt
|
|
#include "llviewerregion.h"
|
|
#include "llviewerwindow.h" // for hack in teleport start
|
|
#include "llvoavatar.h"
|
|
#include "llworld.h"
|
|
#include "pipeline.h" // for gPipeline
|
|
|
|
class AIHTTPTimeoutPolicy;
|
|
extern AIHTTPTimeoutPolicy placeAvatarTeleportResponder_timeout;
|
|
|
|
// OGPX HTTP responder for PlaceAvatar cap used for Teleport
|
|
// very similar to the responder in Login, but not as many fields are returned in the TP version
|
|
// OGPX TODO: should this be combined with the Login responder for rez_avatar/place?
|
|
// OGPX TODO: mResult should not get replaced in result(), instead
|
|
// should replace individual LLSD fields in mResult.
|
|
class LLPlaceAvatarTeleportResponder :
|
|
public LLHTTPClient::Responder
|
|
{
|
|
public:
|
|
LLPlaceAvatarTeleportResponder()
|
|
{
|
|
}
|
|
|
|
~LLPlaceAvatarTeleportResponder()
|
|
{
|
|
}
|
|
|
|
void error(U32 statusNum, const std::string& reason)
|
|
{
|
|
LL_INFOS("OGPX") << "LLPlaceAvatarTeleportResponder error in TP "
|
|
<< statusNum << " " << reason << LL_ENDL;
|
|
|
|
LLSD args;
|
|
args["REASON"] = reason;
|
|
|
|
|
|
LLNotificationsUtil::add("CouldNotTeleportReason", args);
|
|
|
|
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
|
|
|
}
|
|
|
|
void result(const LLSD& content)
|
|
{
|
|
|
|
LLSD result;
|
|
result["agent_id"] = content["agent_id"]; // need this for send_complete_agent_movement
|
|
result["region_x"] = content["region_x"]; // need these for making the first region
|
|
result["region_y"] = content["region_y"];
|
|
result["login"] = "true"; // this gets checked in idle_startup()
|
|
result["session_id"] = content["session_id"];
|
|
result["secure_session_id"] = content["secure_session_id"];
|
|
result["circuit_code"] = content["circuit_code"];
|
|
result["sim_port"] = content["sim_port"];
|
|
result["sim_host"] = content["sim_host"];
|
|
result["look_at"] = content["look_at"];
|
|
// maintaining result seed_capability name for compatibility with legacy login
|
|
result["seed_capability"] = content["region_seed_capability"];
|
|
result["position"] = content["position"]; // save this for agentmovementcomplete type processing
|
|
|
|
// Even though we have the pretty print of the complete content returned, we still find it handy
|
|
// when scanning SecondLife.log to have these laid out in this way. So they are still here.
|
|
LL_DEBUGS("OGPX") << " Teleport placeAvatar responder " << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "agent_id: " << content["agent_id"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "region_x: " << content["region_x"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "session_id: " << content["session_id"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "sim_port: " << content["sim_port"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "sim_host: " << content["sim_host"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "look_at: " << content["look_at"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "position: " << content["position"] << LL_ENDL;
|
|
LL_DEBUGS("OGPX") << "seed_capability: " << content["region_seed_capability"] << LL_ENDL;
|
|
|
|
LL_INFOS("OGPX") << " All the LLSD PlaceAvatarTeleportResponder content: \n " << ll_pretty_print_sd(content) << LL_ENDL; // OGPX
|
|
|
|
|
|
// check "connect" to make sure place_avatar fully successful
|
|
if (!content["connect"].asBoolean())
|
|
{
|
|
// place_avatar failed somewhere
|
|
LL_INFOS("OGPX") << "TP failed, connect false in TP PlaceAvatarResponder " << LL_ENDL;
|
|
|
|
LLSD args;
|
|
args["REASON"] = "Place Avatar Failed";
|
|
|
|
//gViewerWindow->alertXml("CouldNotTeleportReason", args);
|
|
LLNotificationsUtil::add("CouldNotTeleportReason",args);
|
|
|
|
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
U64 region_handle;
|
|
region_handle = to_region_handle_global(content["region_x"].asInteger(), content["region_y"].asInteger());
|
|
|
|
LLHost sim_host;
|
|
U32 sim_port = strtoul(result["sim_port"].asString().c_str(), NULL, 10);
|
|
sim_host.setHostByName(result["sim_host"].asString().c_str());
|
|
sim_host.setPort(sim_port);
|
|
|
|
if (sim_host.isOk())
|
|
{
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
gMessageSystem->enableCircuit(sim_host, TRUE);
|
|
msg->newMessageFast(_PREHASH_UseCircuitCode);
|
|
msg->nextBlockFast(_PREHASH_CircuitCode);
|
|
msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
|
|
msg->sendReliable(sim_host);
|
|
}
|
|
else
|
|
{
|
|
LL_INFOS("OGPX") << "TP failed, could not resolve hostname for UDP messages." << LL_ENDL;
|
|
LLSD args;
|
|
args["REASON"] = "Failed to resolve host.";
|
|
//gViewerWindow->alertXml("CouldNotTeleportReason", args);
|
|
LLNotificationsUtil::add("CouldNotTeleportReason", args);
|
|
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Viewer trusts the simulator.
|
|
LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
|
|
regionp->setSeedCapability(content["seed_capability"].asString().c_str());
|
|
// process_agent_movement_complete needs the region to still be the old region gAgent.setRegion(regionp);
|
|
|
|
// placing these in result so they can be set properly in LLUserAuth result
|
|
// ...they are only passed in on login, and not on TP
|
|
result["session_id"] = gAgent.getSessionID();
|
|
result["agent_id"] = gAgent.getID();
|
|
result["circuit_code"].asString() = gMessageSystem->mOurCircuitCode; // this is what startup sets, is this proper to do?
|
|
|
|
// grab the skeleton and root.
|
|
result["inventory-skeleton"] = LLUserAuth::getInstance()->mResult["inventory-skeleton"];
|
|
result["inventory-root"] = LLUserAuth::getInstance()->mResult["inventory-root"];
|
|
|
|
LL_DEBUGS("OGPX") << "session_id: " << result["session_id"] << LL_ENDL;
|
|
|
|
|
|
|
|
// results need to be stored so process_agent_movement_complete() can pull them
|
|
LLUserAuth::getInstance()->mAuthResponse = LLUserAuth::E_OK;
|
|
|
|
// OGPX TODO: This just reeks of causing problems, because we are using
|
|
// ... mResult to store things that we get from other caps....So slamming a
|
|
// ... completely new result in on teleport is going to cause issues.
|
|
// ... It makes changing the things we save in mResult error prone.
|
|
// ... Question is, how should we really be storing the seemingly random things
|
|
// ... that we get back from (now) various different caps that used to all come back
|
|
// ... in the result of XMLRPC authenticate?
|
|
LLUserAuth::getInstance()->mResult = result;
|
|
|
|
|
|
|
|
// ... new sim not sending me much without sending it CompleteAgentMovement msg.
|
|
//gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); // process_agent_mv_complete looks for TELEPORT_MOVING
|
|
LLVector3 position = ll_vector3_from_sd(result["position"]);
|
|
gAgent.setHomePosRegion(region_handle, position); // taken from teleport_finish (not sure regular code path gets this)
|
|
|
|
send_complete_agent_movement(sim_host);
|
|
|
|
// Turn off progress msg (also need to do this in all the possible failure places)
|
|
// I think we leave this, as the scene is still changing during the
|
|
// processing of agentmovementcomeplete message. TELEPORT_NONE resets it anyway
|
|
// gViewerWindow->setShowProgress(FALSE);
|
|
|
|
}
|
|
|
|
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return placeAvatarTeleportResponder_timeout; }
|
|
};
|
|
|
|
// Statics
|
|
LLFloaterTeleport* LLFloaterTeleport::sInstance = NULL;
|
|
|
|
LLFloaterTeleport::LLFloaterTeleport()
|
|
: LLFloater("floater_teleport")
|
|
{
|
|
if(!sInstance)
|
|
{
|
|
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_teleport.xml");
|
|
|
|
LLComboBox* regioncombo = getChild<LLComboBox>("teleport_edit");
|
|
regioncombo->setAllowTextEntry(TRUE, 256, FALSE); // URL bar needs to allow user text input
|
|
|
|
// iterate on uri list adding to combobox (couldn't figure out how to add them all in one call)
|
|
LLSD regionuri_history = LLURLHistory::getURLHistory("regionuri");
|
|
LLSD::array_iterator iter_history = regionuri_history.beginArray();
|
|
LLSD::array_iterator iter_end = regionuri_history.endArray();
|
|
for(; iter_history != iter_end; ++iter_history)
|
|
{
|
|
regioncombo->addSimpleElement((*iter_history).asString());
|
|
}
|
|
|
|
// select which is displayed if we have a current URL.
|
|
regioncombo->setSelectedByValue(LLSD(gSavedSettings.getString("CmdLineRegionURI")),TRUE);
|
|
|
|
// TODO : decide if 'enter' when selecting something from the combox box should *not* be sent
|
|
// to the floater (p.s. and figure out how to change it)
|
|
|
|
childSetAction("teleport_btn", onClickTeleport, this);
|
|
childSetAction("cancel_btn", onClickCancel, this);
|
|
|
|
setDefaultBtn("teleport_btn");
|
|
}
|
|
else
|
|
{
|
|
sInstance->show(NULL);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void LLFloaterTeleport::show(void*)
|
|
{
|
|
if (!sInstance)
|
|
{
|
|
sInstance = new LLFloaterTeleport();
|
|
}
|
|
|
|
sInstance->open();
|
|
}
|
|
|
|
LLFloaterTeleport::~LLFloaterTeleport()
|
|
{
|
|
sInstance=NULL;
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
void LLFloaterTeleport::onClickTeleport(void* userdata)
|
|
{
|
|
std::string placeAvatarCap = LLAppViewer::instance()->getPlaceAvatarCap();
|
|
LLSD args;
|
|
|
|
LLFloaterTeleport* self = (LLFloaterTeleport*)userdata;
|
|
std::string text = self->childGetText("teleport_edit");
|
|
if (text.find("://",0) == std::string::npos)
|
|
{
|
|
// if there is no uri, prepend it with http://
|
|
text = "http://"+text;
|
|
LL_DEBUGS("OGPX") << "Teleport URI was prepended, now " << text << LL_ENDL;
|
|
}
|
|
|
|
LL_DEBUGS("OGPX") << "onClickTeleport! from using place_avatar cap "<< placeAvatarCap << " contains "<< text << LL_ENDL;
|
|
LLStringUtil::trim(text); // trim extra spacing
|
|
gAgent.setTeleportSourceURL(gSavedSettings.getString("CmdLineRegionURI")); // grab src region name
|
|
gSavedSettings.setString("CmdLineRegionURI",text); // save the dst region
|
|
args["public_region_seed_capability"] = text;
|
|
args["position"] = ll_sd_from_vector3(LLVector3(128, 128, 50)); // default to middle of region above base terrain
|
|
LL_INFOS("OGPX") << " args to placeavatar cap " << placeAvatarCap << " on teleport: " << LLSDOStreamer<LLSDXMLFormatter>(args) << LL_ENDL;
|
|
LLHTTPClient::post4(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder());
|
|
gAgent.setTeleportMessage(
|
|
LLAgent::sTeleportProgressMessages["requesting"]);
|
|
gViewerWindow->setShowProgress(TRUE);
|
|
gAgent.teleportCore();
|
|
gAgent.setTeleportState( LLAgent::TELEPORT_PLACE_AVATAR ); // teleportcore() sets tp state to legacy path, so reset. ick!
|
|
gTeleportDisplayTimer.reset();
|
|
|
|
|
|
|
|
self->setVisible(FALSE);
|
|
if ( LLURLHistory::appendToURLCollection("regionuri",text))
|
|
{
|
|
// since URL history only populated on create of sInstance, add to combo list directly
|
|
LLComboBox* regioncombo = self->getChild<LLComboBox>("teleport_edit");
|
|
// BUG : this should add the new item to the combo box, but doesn't
|
|
regioncombo->addSimpleElement(text);
|
|
}
|
|
|
|
}
|
|
|
|
void LLFloaterTeleport::onClickCancel(void *userdata)
|
|
{
|
|
LLFloaterTeleport* self = (LLFloaterTeleport*)userdata;
|
|
LL_INFOS("OGPX") << "Teleport Cancel " << self->getName() << LL_ENDL;
|
|
self->setVisible(FALSE);
|
|
}
|