diff options
| author | Andrew A. de Laix <alain@lindenlab.com> | 2010-11-04 15:49:19 -0700 | 
|---|---|---|
| committer | Andrew A. de Laix <alain@lindenlab.com> | 2010-11-04 15:49:19 -0700 | 
| commit | 191e164a503b72c7feae0a46ad0422740b365556 (patch) | |
| tree | e4f8d565e81bbe22fde904a67d2afa95eb9189e9 /indra/viewer_components | |
| parent | 070fe9ed262da5c990a5129474489647a0369fc9 (diff) | |
some better error handling.
Diffstat (limited to 'indra/viewer_components')
6 files changed, 136 insertions, 65 deletions
| diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp index 2c60636122..d31244cc9b 100644 --- a/indra/viewer_components/updater/llupdatechecker.cpp +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -24,21 +24,35 @@   */  #include "linden_common.h" +#include <stdexcept>  #include <boost/format.hpp>  #include "llhttpclient.h"  #include "llsd.h"  #include "llupdatechecker.h"  #include "lluri.h" +  #if LL_WINDOWS  #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally  #endif + +class LLUpdateChecker::CheckError: +	public std::runtime_error +{ +public: +	CheckError(const char * message): +		std::runtime_error(message) +	{ +		; // No op. +	} +}; + +  class LLUpdateChecker::Implementation:  	public LLHTTPClient::Responder  {  public: -	  	Implementation(Client & client);  	~Implementation();  	void check(std::string const & protocolVersion, std::string const & hostUrl,  @@ -50,9 +64,8 @@ public:  						   const LLSD& content);  	virtual void error(U32 status, const std::string & reason); -private: -	std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl,  -						 std::string const & servicePath, std::string channel, std::string version); +private:	 +	static const char * sProtocolVersion;  	Client & mClient;  	LLHTTPClient mHttpClient; @@ -60,6 +73,9 @@ private:  	LLHTTPClient::ResponderPtr mMe;   	std::string mVersion; +	std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl,  +						 std::string const & servicePath, std::string channel, std::string version); +  	LOG_CLASS(LLUpdateChecker::Implementation);  }; @@ -88,6 +104,9 @@ void LLUpdateChecker::check(std::string const & protocolVersion, std::string con  //----------------------------------------------------------------------------- +const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.0"; + +  LLUpdateChecker::Implementation::Implementation(LLUpdateChecker::Client & client):  	mClient(client),  	mInProgress(false), @@ -106,7 +125,9 @@ LLUpdateChecker::Implementation::~Implementation()  void LLUpdateChecker::Implementation::check(std::string const & protocolVersion, std::string const & hostUrl,   											std::string const & servicePath, std::string channel, std::string version)  { -	// llassert(!mInProgress); +	llassert(!mInProgress); +	 +	if(protocolVersion != sProtocolVersion) throw CheckError("unsupported protocol");  	mInProgress = true;  	mVersion = version; @@ -135,11 +156,11 @@ void LLUpdateChecker::Implementation::completed(U32 status,  	} else if(content["required"].asBoolean()) {  		LL_INFOS("UpdateCheck") << "version invalid" << llendl;  		LLURI uri(content["url"].asString()); -		mClient.requiredUpdate(content["version"].asString(), uri); +		mClient.requiredUpdate(content["version"].asString(), uri, content["hash"].asString());  	} else {  		LL_INFOS("UpdateCheck") << "newer version " << content["version"].asString() << " available" << llendl;  		LLURI uri(content["url"].asString()); -		mClient.optionalUpdate(content["version"].asString(), uri); +		mClient.optionalUpdate(content["version"].asString(), uri, content["hash"].asString());  	}  } diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h index 58aaee4e3d..cea1f13647 100644 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -38,6 +38,9 @@ public:  	class Client;  	class Implementation; +	// An exception that may be raised on check errors. +	class CheckError; +	  	LLUpdateChecker(Client & client);  	// Check status of current app on the given host for the channel and version provided. @@ -62,10 +65,14 @@ 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, LLURI const & uri) = 0; +	virtual void optionalUpdate(std::string const & newVersion, +								LLURI const & uri, +								std::string const & hash) = 0;  	// A newer version is available, and the current version is no longer valid.  -	virtual void requiredUpdate(std::string const & newVersion, LLURI const & uri) = 0; +	virtual void requiredUpdate(std::string const & newVersion, +								LLURI const & uri, +								std::string const & hash) = 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 087d79f804..23772e021e 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -24,6 +24,7 @@   */  #include "linden_common.h" +#include <stdexcept>  #include <boost/lexical_cast.hpp>  #include <curl/curl.h>  #include "lldir.h" @@ -41,33 +42,56 @@ public:  	Implementation(LLUpdateDownloader::Client & client);  	~Implementation();  	void cancel(void); -	void download(LLURI const & uri); +	void download(LLURI const & uri, std::string const & hash);  	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; +	LLSD mDownloadData;  	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); +	void startDownloading(LLURI const & uri, std::string const & hash); +	void throwOnCurlError(CURLcode code);  	LOG_CLASS(LLUpdateDownloader::Implementation);  }; +namespace { +	class DownloadError: +		public std::runtime_error +	{ +	public: +		DownloadError(const char * message): +			std::runtime_error(message) +		{ +			; // No op. +		} +	}; + +		 +	const char * gSecondLifeUpdateRecord = "SecondLifeUpdateDownload.xml"; +}; + +  // LLUpdateDownloader  //----------------------------------------------------------------------------- + +std::string LLUpdateDownloader::downloadMarkerPath(void) +{ +	return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, gSecondLifeUpdateRecord); +} + +  LLUpdateDownloader::LLUpdateDownloader(Client & client):  	mImplementation(new LLUpdateDownloader::Implementation(client))  { @@ -81,9 +105,9 @@ void LLUpdateDownloader::cancel(void)  } -void LLUpdateDownloader::download(LLURI const & uri) +void LLUpdateDownloader::download(LLURI const & uri, std::string const & hash)  { -	mImplementation->download(uri); +	mImplementation->download(uri, hash);  } @@ -115,15 +139,11 @@ namespace {  } -const char * LLUpdateDownloader::Implementation::sSecondLifeUpdateRecord = -	"SecondLifeUpdateDownload.xml"; - -  LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):  	LLThread("LLUpdateDownloader"),  	mClient(client),  	mCurl(0), -	mDownloadRecordPath(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, sSecondLifeUpdateRecord)) +	mDownloadRecordPath(LLUpdateDownloader::downloadMarkerPath())  {  	CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case.  	llassert(code = CURLE_OK); // TODO: real error handling here.  @@ -142,13 +162,15 @@ void LLUpdateDownloader::Implementation::cancel(void)  } -void LLUpdateDownloader::Implementation::download(LLURI const & uri) +void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash)  { -	LLSD downloadData; -	if(shouldResumeOngoingDownload(uri, downloadData)){ -		startDownloading(uri); // TODO: Implement resume. -	} else { -		startDownloading(uri); +	if(isDownloading()) mClient.downloadError("download in progress"); +	 +	mDownloadData = LLSD(); +	try { +		startDownloading(uri, hash); +	} catch(DownloadError const & e) { +		mClient.downloadError(e.what());  	}  } @@ -173,14 +195,10 @@ void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)  			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)); +			mDownloadData["size"] = LLSD(LLSD::Integer(size));  			llofstream odataStream(mDownloadRecordPath); -			parser.toPrettyXML(downloadData, odataStream); +			LLSDSerialize parser; +			parser.toPrettyXML(mDownloadData, odataStream);  		} catch (std::exception const & e) {  			LL_WARNS("UpdateDownload") << "unable to read content length ("   				<< e.what() << ")" << LL_ENDL; @@ -218,17 +236,16 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u  		curl_easy_reset(mCurl);  	} -	llassert(mCurl != 0); // TODO: real error handling here. +	if(mCurl == 0) throw DownloadError("failed to initialize curl"); -	CURLcode code; -	code = curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true); -	code = curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, 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()); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true)); +	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str()));  } @@ -236,7 +253,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & download  {  } - +/*  bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData)  {  	if(!LLFile::isfile(mDownloadRecordPath)) return false; @@ -259,23 +276,42 @@ bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const  	return true;  } + */ -void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri) +void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash)  { -	LLSD downloadData; -	downloadData["url"] = uri.asString(); +	mDownloadData["url"] = uri.asString(); +	mDownloadData["hash"] = hash;  	LLSD path = uri.pathArray(); +	if(path.size() == 0) throw DownloadError("no file path");  	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; +	mDownloadData["path"] = filePath; + +	LL_INFOS("UpdateDownload") << "downloading " << filePath << "\n" +		<< "from " << uri.asString() << LL_ENDL; +		  	llofstream dataStream(mDownloadRecordPath);  	LLSDSerialize parser; -	parser.toPrettyXML(downloadData, dataStream); +	parser.toPrettyXML(mDownloadData, dataStream);  	mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary);  	initializeCurlGet(uri.asString());  	start();  } + + +void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code) +{ +	if(code != CURLE_OK) { +		const char * errorString = curl_easy_strerror(code); +		if(errorString != 0) { +			throw DownloadError(curl_easy_strerror(code)); +		} else { +			throw DownloadError("unknown curl error"); +		} +	} else { +		; // No op. +	} +} diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index 6118c4338e..8754ea329c 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -27,7 +27,6 @@  #define LL_UPDATE_DOWNLOADER_H -#include <stdexcept>  #include <string>  #include <boost/shared_ptr.hpp>  #include "lluri.h" @@ -39,20 +38,20 @@  class LLUpdateDownloader  {  public: -	class BusyError;  	class Client;  	class Implementation; +	// Returns the path to the download marker file containing details of the +	// latest download. +	static std::string downloadMarkerPath(void); +	  	LLUpdateDownloader(Client & client);  	// 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); +	void download(LLURI const & uri, std::string const & hash);  	// Returns true if a download is in progress.  	bool isDownloading(void); diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index e865552fb3..1e0c393539 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -90,8 +90,12 @@ public:  	// LLUpdateChecker::Client:  	virtual void error(std::string const & message); -	virtual void optionalUpdate(std::string const & newVersion, LLURI const & uri); -	virtual void requiredUpdate(std::string const & newVersion, LLURI const & uri); +	virtual void optionalUpdate(std::string const & newVersion, +								LLURI const & uri, +								std::string const & hash); +	virtual void requiredUpdate(std::string const & newVersion, +								LLURI const & uri, +								std::string const & hash);  	virtual void upToDate(void);  	// LLUpdateDownloader::Client @@ -195,14 +199,18 @@ void LLUpdaterServiceImpl::error(std::string const & message)  	retry();  } -void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, LLURI const & uri) +void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, +										  LLURI const & uri, +										  std::string const & hash)  { -	mUpdateDownloader.download(uri); +	mUpdateDownloader.download(uri, hash);  } -void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, LLURI const & uri) +void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, +										  LLURI const & uri, +										  std::string const & hash)  { -	mUpdateDownloader.download(uri); +	mUpdateDownloader.download(uri, hash);  }  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 958526e35b..20d0f8fa09 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -64,7 +64,7 @@ void LLUpdateChecker::check(std::string const & protocolVersion, std::string con  								  std::string const & servicePath, std::string channel, std::string version)
  {}
  LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
 -void LLUpdateDownloader::download(LLURI const & ){}
 +void LLUpdateDownloader::download(LLURI const & , std::string const &){}
  /*****************************************************************************
  *   TUT
 | 
