diff options
Diffstat (limited to 'indra/viewer_components')
6 files changed, 159 insertions, 25 deletions
| diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp index 9cfa919b39..596b122a25 100644 --- a/indra/viewer_components/updater/llupdatechecker.cpp +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -120,17 +120,19 @@ void LLUpdateChecker::Implementation::completed(U32 status,  							  const std::string & reason,  							  const LLSD & content)  { -	mInProgress = false; +	mInProgress = false;	  	if(status != 200) {  		LL_WARNS("UpdateCheck") << "html error " << status << " (" << reason << ")" << llendl;  		mClient.error(reason);  	} else if(!content["valid"].asBoolean()) {  		LL_INFOS("UpdateCheck") << "version invalid" << llendl; -		mClient.requiredUpdate(content["latest_version"].asString()); +		LLURI uri(content["download_url"].asString()); +		mClient.requiredUpdate(content["latest_version"].asString(), uri);  	} else if(content["latest_version"].asString() != mVersion) {  		LL_INFOS("UpdateCheck") << "newer version " << content["latest_version"].asString() << " available" << llendl; -		mClient.optionalUpdate(content["latest_version"].asString()); +		LLURI uri(content["download_url"].asString()); +		mClient.optionalUpdate(content["latest_version"].asString(), uri);  	} else {  		LL_INFOS("UpdateCheck") << "up to date" << llendl;  		mClient.upToDate(); @@ -153,4 +155,3 @@ std::string LLUpdateChecker::Implementation::buildUrl(std::string const & host,  	path.append(version);  	return LLURI::buildHTTP(host, path).asString();  } - diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h index b630c4d8a6..1f8c6d8a91 100644 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -48,6 +48,9 @@ private:  }; +class LLURI; // From lluri.h + +  //  // The client interface implemented by a requestor checking for an update.  // @@ -58,10 +61,10 @@ public:  	virtual void error(std::string const & message) = 0;  	// A newer version is available, but the current version may still be used. -	virtual void optionalUpdate(std::string const & newVersion) = 0; +	virtual void optionalUpdate(std::string const & newVersion, LLURI const & uri) = 0;  	// A newer version is available, and the current version is no longer valid.  -	virtual void requiredUpdate(std::string const & newVersion) = 0; +	virtual void requiredUpdate(std::string const & newVersion, LLURI const & uri) = 0;  	// The checked version is up to date; no newer version exists.  	virtual void upToDate(void) = 0; diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 4adf9c42b1..21e4ce94cc 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -24,6 +24,8 @@   */  #include "linden_common.h" +#include <boost/lexical_cast.hpp> +#include <curl/curl.h>  #include "lldir.h"  #include "llfile.h"  #include "llsd.h" @@ -37,20 +39,27 @@ class LLUpdateDownloader::Implementation:  {  public:  	Implementation(LLUpdateDownloader::Client & client); +	~Implementation();  	void cancel(void);  	void download(LLURI const & uri);  	bool isDownloading(void); - +	void onHeader(void * header, size_t size); +	void onBody(void * header, size_t size);  private:  	static const char * sSecondLifeUpdateRecord;  	LLUpdateDownloader::Client & mClient; +	CURL * mCurl; +	llofstream mDownloadStream;  	std::string mDownloadRecordPath; +	void initializeCurlGet(std::string const & url);  	void resumeDownloading(LLSD const & downloadData);  	void run(void);  	bool shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData);  	void startDownloading(LLURI const & uri); + +	LOG_CLASS(LLUpdateDownloader::Implementation);  }; @@ -89,6 +98,23 @@ bool LLUpdateDownloader::isDownloading(void)  //----------------------------------------------------------------------------- +namespace { +	size_t write_function(void * data, size_t blockSize, size_t blocks, void * downloader) +	{ +		size_t bytes = blockSize * blocks; +		reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onBody(data, bytes); +		return bytes; +	} + +	size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader) +	{ +		size_t bytes = blockSize * blocks; +		reinterpret_cast<LLUpdateDownloader::Implementation *>(downloader)->onHeader(data, bytes); +		return bytes; +	} +} + +  const char * LLUpdateDownloader::Implementation::sSecondLifeUpdateRecord =  	"SecondLifeUpdateDownload.xml"; @@ -96,35 +122,116 @@ const char * LLUpdateDownloader::Implementation::sSecondLifeUpdateRecord =  LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):  	LLThread("LLUpdateDownloader"),  	mClient(client), +	mCurl(0),  	mDownloadRecordPath(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, sSecondLifeUpdateRecord))  { -	; // No op. +	CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. +	llassert(code = CURLE_OK); // TODO: real error handling here.   } -void LLUpdateDownloader::Implementation::cancel(void) +LLUpdateDownloader::Implementation::~Implementation()  { +	if(mCurl) curl_easy_cleanup(mCurl);  } +void LLUpdateDownloader::Implementation::cancel(void) +{ +	llassert(!"not implemented"); +} +	 +  void LLUpdateDownloader::Implementation::download(LLURI const & uri)  {  	LLSD downloadData;  	if(shouldResumeOngoingDownload(uri, downloadData)){ -		 +		startDownloading(uri); // TODO: Implement resume.  	} else { -					 +		startDownloading(uri);  	}  }  bool LLUpdateDownloader::Implementation::isDownloading(void)  { -	return false; +	return !isStopped(); +} + +void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) +{ +	char const * headerPtr = reinterpret_cast<const char *> (buffer); +	std::string header(headerPtr, headerPtr + size); +	size_t colonPosition = header.find(':'); +	if(colonPosition == std::string::npos) return; // HTML response; ignore. +	 +	if(header.substr(0, colonPosition) == "Content-Length") { +		try { +			size_t firstDigitPos = header.find_first_of("0123456789", colonPosition); +			size_t lastDigitPos = header.find_last_of("0123456789"); +			std::string contentLength = header.substr(firstDigitPos, lastDigitPos - firstDigitPos + 1); +			size_t size = boost::lexical_cast<size_t>(contentLength); +			LL_INFOS("UpdateDownload") << "download size is " << size << LL_ENDL; +			 +			LLSD downloadData; +			llifstream idataStream(mDownloadRecordPath); +			LLSDSerialize parser; +			parser.fromXMLDocument(downloadData, idataStream); +			idataStream.close(); +			downloadData["size"] = LLSD(LLSD::Integer(size)); +			llofstream odataStream(mDownloadRecordPath); +			parser.toPrettyXML(downloadData, odataStream); +		} catch (std::exception const & e) { +			LL_WARNS("UpdateDownload") << "unable to read content length ("  +				<< e.what() << ")" << LL_ENDL; +		} +	} else { +		; // No op. +	} +} + + +void LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) +{ +	mDownloadStream.write(reinterpret_cast<const char *>(buffer), size); +} + + +void LLUpdateDownloader::Implementation::run(void) +{ +	CURLcode code = curl_easy_perform(mCurl); +	if(code == CURLE_OK) { +		LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; +		mClient.downloadComplete(); +	} else { +		LL_WARNS("UpdateDownload") << "download failed with error " << code << LL_ENDL; +		mClient.downloadError("curl error"); +	} +} + + +void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url) +{ +	if(mCurl == 0) { +		mCurl = curl_easy_init(); +	} else { +		curl_easy_reset(mCurl); +	} +	 +	llassert(mCurl != 0); // TODO: real error handling here. +	 +	CURLcode code; +	code = curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true); +	code = curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function); +	code = curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this); +	code = curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function); +	code = curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this); +	code = curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true); +	code = curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str());  } -void resumeDownloading(LLSD const & downloadData) +void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & downloadData)  {  } @@ -160,9 +267,14 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri)  	LLSD path = uri.pathArray();  	std::string fileName = path[path.size() - 1].asString();  	std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName); +	LL_INFOS("UpdateDownload") << "downloading " << filePath << LL_ENDL; +	LL_INFOS("UpdateDownload") << "from " << uri.asString() << LL_ENDL; +	downloadData["path"] = filePath;  	llofstream dataStream(mDownloadRecordPath);  	LLSDSerialize parser;  	parser.toPrettyXML(downloadData, dataStream); -	llofstream downloadStream(filePath); +	mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary); +	initializeCurlGet(uri.asString()); +	start();  } diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index 9dc5d789ce..6118c4338e 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -27,6 +27,7 @@  #define LL_UPDATE_DOWNLOADER_H +#include <stdexcept>  #include <string>  #include <boost/shared_ptr.hpp>  #include "lluri.h" @@ -38,15 +39,19 @@  class LLUpdateDownloader  {  public: +	class BusyError;  	class Client;  	class Implementation;  	LLUpdateDownloader(Client & client); -	// Cancel any in progress download. +	// Cancel any in progress download; a no op if none is in progress.  	void cancel(void);  	// Start a new download. +	// +	// This method will throw a BusyException instance if a download is already +	// in progress.  	void download(LLURI const & uri);  	// Returns true if a download is in progress. @@ -61,12 +66,13 @@ private:  // An interface to be implemented by clients initiating a update download.  //  class LLUpdateDownloader::Client { +public:  	// The download has completed successfully. -	void downloadComplete(void); +	virtual void downloadComplete(void) = 0;  	// The download failed. -	void downloadError(std::string const & message); +	virtual void downloadError(std::string const & message) = 0;  }; diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index e339c69724..a1b6de38e5 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -25,6 +25,7 @@  #include "linden_common.h" +#include "llupdatedownloader.h"  #include "llevents.h"  #include "lltimer.h"  #include "llupdaterservice.h" @@ -42,7 +43,8 @@ boost::weak_ptr<LLUpdaterServiceImpl> gUpdater;  class LLUpdaterServiceImpl :   	public LLPluginProcessParentOwner, -	public LLUpdateChecker::Client +	public LLUpdateChecker::Client, +	public LLUpdateDownloader::Client  {  	static const std::string sListenerName; @@ -55,6 +57,7 @@ class LLUpdaterServiceImpl :  	boost::scoped_ptr<LLPluginProcessParent> mPlugin;  	LLUpdateChecker mUpdateChecker; +	LLUpdateDownloader mUpdateDownloader;  	LLTimer mTimer;  	void retry(void); @@ -83,10 +86,14 @@ public:  	// LLUpdateChecker::Client:  	virtual void error(std::string const & message); -	virtual void optionalUpdate(std::string const & newVersion); -	virtual void requiredUpdate(std::string const & newVersion); +	virtual void optionalUpdate(std::string const & newVersion, LLURI const & uri); +	virtual void requiredUpdate(std::string const & newVersion, LLURI const & uri);  	virtual void upToDate(void); +	// LLUpdateDownloader::Client +	void downloadComplete(void) { retry(); } +	void downloadError(std::string const & message) { retry(); }	 +  	bool onMainLoop(LLSD const & event);	  }; @@ -96,7 +103,8 @@ LLUpdaterServiceImpl::LLUpdaterServiceImpl() :  	mIsChecking(false),  	mCheckPeriod(0),  	mPlugin(0), -	mUpdateChecker(*this) +	mUpdateChecker(*this), +	mUpdateDownloader(*this)  {  	// Create the plugin parent, this is the owner.  	mPlugin.reset(new LLPluginProcessParent(this)); @@ -179,14 +187,14 @@ void LLUpdaterServiceImpl::error(std::string const & message)  	retry();  } -void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion) +void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, LLURI const & uri)  { -	retry(); +	mUpdateDownloader.download(uri);  } -void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion) +void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, LLURI const & uri)  { -	retry(); +	mUpdateDownloader.download(uri);  }  void LLUpdaterServiceImpl::upToDate(void) diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index d93a85cf7d..0ffc1f2c70 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -29,6 +29,7 @@  // associated header
  #include "../llupdaterservice.h"
  #include "../llupdatechecker.h"
 +#include "../llupdatedownloader.h"
  #include "../../../test/lltut.h"
  //#define DEBUG_ON
 @@ -60,6 +61,9 @@ LLPluginMessage::LLPluginMessage(LLPluginMessage const&) {}  LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client)
  {}
  void LLUpdateChecker::check(std::string const & host, std::string channel, std::string version){}
 +LLUpdateDownloader::LLUpdateDownloader(LLUpdateDownloader::Client & client)
 +{}
 +void LLUpdateDownloader::download(LLURI const & ){}
  /*****************************************************************************
  *   TUT
 | 
