From be151807222ffa5972256aa9a392e8a319eae5ee Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 2 Nov 2010 15:59:10 -0700 Subject: start of the downloader service. --- .../updater/llupdatedownloader.cpp | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 indra/viewer_components/updater/llupdatedownloader.cpp (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp new file mode 100644 index 0000000000..4adf9c42b1 --- /dev/null +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -0,0 +1,168 @@ +/** + * @file llupdatedownloader.cpp + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lldir.h" +#include "llfile.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llthread.h" +#include "llupdatedownloader.h" + + +class LLUpdateDownloader::Implementation: + public LLThread +{ +public: + Implementation(LLUpdateDownloader::Client & client); + void cancel(void); + void download(LLURI const & uri); + bool isDownloading(void); + +private: + static const char * sSecondLifeUpdateRecord; + + LLUpdateDownloader::Client & mClient; + std::string mDownloadRecordPath; + + void resumeDownloading(LLSD const & downloadData); + void run(void); + bool shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData); + void startDownloading(LLURI const & uri); +}; + + + +// LLUpdateDownloader +//----------------------------------------------------------------------------- + + +LLUpdateDownloader::LLUpdateDownloader(Client & client): + mImplementation(new LLUpdateDownloader::Implementation(client)) +{ + ; // No op. +} + + +void LLUpdateDownloader::cancel(void) +{ + mImplementation->cancel(); +} + + +void LLUpdateDownloader::download(LLURI const & uri) +{ + mImplementation->download(uri); +} + + +bool LLUpdateDownloader::isDownloading(void) +{ + return mImplementation->isDownloading(); +} + + + +// LLUpdateDownloader::Implementation +//----------------------------------------------------------------------------- + + +const char * LLUpdateDownloader::Implementation::sSecondLifeUpdateRecord = + "SecondLifeUpdateDownload.xml"; + + +LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client): + LLThread("LLUpdateDownloader"), + mClient(client), + mDownloadRecordPath(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, sSecondLifeUpdateRecord)) +{ + ; // No op. +} + + +void LLUpdateDownloader::Implementation::cancel(void) +{ +} + + +void LLUpdateDownloader::Implementation::download(LLURI const & uri) +{ + LLSD downloadData; + if(shouldResumeOngoingDownload(uri, downloadData)){ + + } else { + + } +} + + +bool LLUpdateDownloader::Implementation::isDownloading(void) +{ + return false; +} + + +void resumeDownloading(LLSD const & downloadData) +{ +} + + +bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData) +{ + if(!LLFile::isfile(mDownloadRecordPath)) return false; + + llifstream dataStream(mDownloadRecordPath); + LLSDSerialize parser; + parser.fromXMLDocument(downloadData, dataStream); + + if(downloadData["url"].asString() != uri.asString()) return false; + + std::string downloadedFilePath = downloadData["path"].asString(); + if(LLFile::isfile(downloadedFilePath)) { + llstat fileStatus; + LLFile::stat(downloadedFilePath, &fileStatus); + downloadData["bytes_downloaded"] = LLSD(LLSD::Integer(fileStatus.st_size)); + return true; + } else { + return false; + } + + return true; +} + + +void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri) +{ + LLSD downloadData; + downloadData["url"] = uri.asString(); + LLSD path = uri.pathArray(); + std::string fileName = path[path.size() - 1].asString(); + std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName); + llofstream dataStream(mDownloadRecordPath); + LLSDSerialize parser; + parser.toPrettyXML(downloadData, dataStream); + + llofstream downloadStream(filePath); +} -- cgit v1.3 From 7622ab9249506539894d0e33d4c2a8fd9fb3e3ac Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Thu, 4 Nov 2010 11:33:02 -0700 Subject: just barely working udate downloading service; missing little nicities like error checking and sill stuff like that. --- .../viewer_components/updater/llupdatechecker.cpp | 9 +- indra/viewer_components/updater/llupdatechecker.h | 7 +- .../updater/llupdatedownloader.cpp | 128 +++++++++++++++++++-- .../viewer_components/updater/llupdatedownloader.h | 12 +- .../viewer_components/updater/llupdaterservice.cpp | 24 ++-- .../updater/tests/llupdaterservice_test.cpp | 4 + 6 files changed, 159 insertions(+), 25 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') 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 +#include #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(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(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 (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(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(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 #include #include #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 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 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 -- cgit v1.3 From dfeb7abe5f690bbd3a908c84c53bbea20a5adb7c Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Thu, 4 Nov 2010 14:08:14 -0700 Subject: checker working with v1.0 update protocol. --- indra/newview/app_settings/settings.xml | 24 +++++++++- indra/newview/llappviewer.cpp | 4 +- .../viewer_components/updater/llupdatechecker.cpp | 52 ++++++++++++++-------- indra/viewer_components/updater/llupdatechecker.h | 3 +- .../updater/llupdatedownloader.cpp | 1 + .../viewer_components/updater/llupdaterservice.cpp | 28 ++++++++---- indra/viewer_components/updater/llupdaterservice.h | 6 +-- .../updater/tests/llupdaterservice_test.cpp | 11 ++--- 8 files changed, 91 insertions(+), 38 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8f5cb7c709..cc0e0a78db 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11022,7 +11022,29 @@ Type String Value - http://localhost/agni + http://update.secondlife.com + + UpdaterServicePath + + Comment + Path on the update server host. + Persist + 0 + Type + String + Value + update + + UpdaterServiceProtocolVersion + + Comment + The update protocol version to use. + Persist + 0 + Type + String + Value + v1.0 UploadBakedTexOld diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3a48bc25f1..6bb25969a6 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2337,9 +2337,11 @@ void LLAppViewer::initUpdater() std::string url = gSavedSettings.getString("UpdaterServiceURL"); std::string channel = LLVersionInfo::getChannel(); std::string version = LLVersionInfo::getVersion(); + std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion"); + std::string service_path = gSavedSettings.getString("UpdaterServicePath"); U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod"); - mUpdater->setParams(url, channel, version); + mUpdater->setParams(protocol_version, url, service_path, channel, version); mUpdater->setCheckPeriod(check_period); if(gSavedSettings.getBOOL("UpdaterServiceActive")) { diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp index 596b122a25..2c60636122 100644 --- a/indra/viewer_components/updater/llupdatechecker.cpp +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -41,7 +41,8 @@ public: Implementation(Client & client); ~Implementation(); - void check(std::string const & host, std::string channel, std::string version); + void check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); // Responder: virtual void completed(U32 status, @@ -50,7 +51,8 @@ public: virtual void error(U32 status, const std::string & reason); private: - std::string buildUrl(std::string const & host, std::string channel, std::string version); + std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); Client & mClient; LLHTTPClient mHttpClient; @@ -74,9 +76,10 @@ LLUpdateChecker::LLUpdateChecker(LLUpdateChecker::Client & client): } -void LLUpdateChecker::check(std::string const & host, std::string channel, std::string version) +void LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) { - mImplementation->check(host, channel, version); + mImplementation->check(protocolVersion, hostUrl, servicePath, channel, version); } @@ -100,13 +103,14 @@ LLUpdateChecker::Implementation::~Implementation() } -void LLUpdateChecker::Implementation::check(std::string const & host, std::string channel, std::string version) +void LLUpdateChecker::Implementation::check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) { // llassert(!mInProgress); mInProgress = true; mVersion = version; - std::string checkUrl = buildUrl(host, channel, version); + std::string checkUrl = buildUrl(protocolVersion, hostUrl, servicePath, channel, version); LL_INFOS("UpdateCheck") << "checking for updates at " << checkUrl << llendl; // The HTTP client will wrap a raw pointer in a boost::intrusive_ptr causing the @@ -125,17 +129,17 @@ void LLUpdateChecker::Implementation::completed(U32 status, 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; - 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; - LLURI uri(content["download_url"].asString()); - mClient.optionalUpdate(content["latest_version"].asString(), uri); - } else { + } else if(!content.asBoolean()) { LL_INFOS("UpdateCheck") << "up to date" << llendl; mClient.upToDate(); + } else if(content["required"].asBoolean()) { + LL_INFOS("UpdateCheck") << "version invalid" << llendl; + LLURI uri(content["url"].asString()); + mClient.requiredUpdate(content["version"].asString(), uri); + } else { + LL_INFOS("UpdateCheck") << "newer version " << content["version"].asString() << " available" << llendl; + LLURI uri(content["url"].asString()); + mClient.optionalUpdate(content["version"].asString(), uri); } } @@ -144,14 +148,26 @@ void LLUpdateChecker::Implementation::error(U32 status, const std::string & reas { mInProgress = false; LL_WARNS("UpdateCheck") << "update check failed; " << reason << llendl; + mClient.error(reason); } -std::string LLUpdateChecker::Implementation::buildUrl(std::string const & host, std::string channel, std::string version) +std::string LLUpdateChecker::Implementation::buildUrl(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) { +#ifdef LL_WINDOWS + static const char * platform = "win"; +#elif LL_DARWIN + static const char * platform = "mac"; +#else + static const char * platform = "lnx"; +#endif + LLSD path; - path.append("version"); + path.append(servicePath); + path.append(protocolVersion); path.append(channel); path.append(version); - return LLURI::buildHTTP(host, path).asString(); + path.append(platform); + return LLURI::buildHTTP(hostUrl, path).asString(); } diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h index 1f8c6d8a91..58aaee4e3d 100644 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -41,7 +41,8 @@ public: LLUpdateChecker(Client & client); // Check status of current app on the given host for the channel and version provided. - void check(std::string const & hostUrl, std::string channel, std::string version); + void check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version); private: boost::shared_ptr mImplementation; diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 21e4ce94cc..087d79f804 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -222,6 +222,7 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u 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); diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index a1b6de38e5..e865552fb3 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -48,7 +48,9 @@ class LLUpdaterServiceImpl : { static const std::string sListenerName; + std::string mProtocolVersion; std::string mUrl; + std::string mPath; std::string mChannel; std::string mVersion; @@ -74,10 +76,12 @@ public: virtual void pluginLaunchFailed(); virtual void pluginDied(); - void setParams(const std::string& url, + void setParams(const std::string& protocol_version, + const std::string& url, + const std::string& path, const std::string& channel, const std::string& version); - + void setCheckPeriod(unsigned int seconds); void startChecking(); @@ -134,7 +138,9 @@ void LLUpdaterServiceImpl::pluginDied() { }; -void LLUpdaterServiceImpl::setParams(const std::string& url, +void LLUpdaterServiceImpl::setParams(const std::string& protocol_version, + const std::string& url, + const std::string& path, const std::string& channel, const std::string& version) { @@ -144,7 +150,9 @@ void LLUpdaterServiceImpl::setParams(const std::string& url, " before setting params."); } + mProtocolVersion = protocol_version; mUrl = url; + mPath = path; mChannel = channel; mVersion = version; } @@ -165,7 +173,7 @@ void LLUpdaterServiceImpl::startChecking() } mIsChecking = true; - mUpdateChecker.check(mUrl, mChannel, mVersion); + mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion); } } @@ -218,7 +226,7 @@ bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event) { mTimer.stop(); LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName); - mUpdateChecker.check(mUrl, mChannel, mVersion); + mUpdateChecker.check(mProtocolVersion, mUrl, mPath, mChannel, mVersion); } else { // Keep on waiting... } @@ -247,11 +255,13 @@ LLUpdaterService::~LLUpdaterService() { } -void LLUpdaterService::setParams(const std::string& url, - const std::string& chan, - const std::string& vers) +void LLUpdaterService::setParams(const std::string& protocol_version, + const std::string& url, + const std::string& path, + const std::string& channel, + const std::string& version) { - mImpl->setParams(url, chan, vers); + mImpl->setParams(protocol_version, url, path, channel, version); } void LLUpdaterService::setCheckPeriod(unsigned int seconds) diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 313ae8ada3..83b09c4bdd 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -42,9 +42,9 @@ public: LLUpdaterService(); ~LLUpdaterService(); - // The base URL. - // *NOTE:Mani The grid, if any, would be embedded in the base URL. - void setParams(const std::string& url, + void setParams(const std::string& version, + const std::string& url, + const std::string& path, const std::string& channel, const std::string& version); diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 0ffc1f2c70..958526e35b 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -60,9 +60,10 @@ 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 LLUpdateChecker::check(std::string const & protocolVersion, std::string const & hostUrl, + std::string const & servicePath, std::string channel, std::string version) {} +LLUpdateDownloader::LLUpdateDownloader(Client & ) {} void LLUpdateDownloader::download(LLURI const & ){} /***************************************************************************** @@ -113,9 +114,9 @@ namespace tut bool got_usage_error = false; try { - updater.setParams(test_url, test_channel, test_version); + updater.setParams("1.0",test_url, "update" ,test_channel, test_version); updater.startChecking(); - updater.setParams("other_url", test_channel, test_version); + updater.setParams("1.0", "other_url", "update", test_channel, test_version); } catch(LLUpdaterService::UsageError) { @@ -129,7 +130,7 @@ namespace tut { DEBUG; LLUpdaterService updater; - updater.setParams(test_url, test_channel, test_version); + updater.setParams("1.0", test_url, "update", test_channel, test_version); updater.startChecking(); ensure(updater.isChecking()); updater.stopChecking(); -- cgit v1.3 From 191e164a503b72c7feae0a46ad0422740b365556 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Thu, 4 Nov 2010 15:49:19 -0700 Subject: some better error handling. --- .../viewer_components/updater/llupdatechecker.cpp | 35 ++++-- indra/viewer_components/updater/llupdatechecker.h | 11 +- .../updater/llupdatedownloader.cpp | 122 +++++++++++++-------- .../viewer_components/updater/llupdatedownloader.h | 11 +- .../viewer_components/updater/llupdaterservice.cpp | 20 +++- .../updater/tests/llupdaterservice_test.cpp | 2 +- 6 files changed, 136 insertions(+), 65 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') 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 #include #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 #include #include #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(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 #include #include #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 -- cgit v1.3 From 4d1e45f20f924f070d0f0139878c2c96e698fb07 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Thu, 4 Nov 2010 17:14:12 -0700 Subject: added hash validation of downloaded file. --- .../updater/llupdatedownloader.cpp | 41 +++++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 23772e021e..59e929d99f 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -29,6 +29,7 @@ #include #include "lldir.h" #include "llfile.h" +#include "llmd5.h" #include "llsd.h" #include "llsdserialize.h" #include "llthread.h" @@ -58,6 +59,7 @@ private: void run(void); void startDownloading(LLURI const & uri, std::string const & hash); void throwOnCurlError(CURLcode code); + bool validateDownload(void); LOG_CLASS(LLUpdateDownloader::Implementation); }; @@ -130,6 +132,7 @@ namespace { return bytes; } + size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader) { size_t bytes = blockSize * blocks; @@ -219,10 +222,18 @@ void LLUpdateDownloader::Implementation::run(void) { CURLcode code = curl_easy_perform(mCurl); if(code == CURLE_OK) { - LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; - mClient.downloadComplete(); + if(validateDownload()) { + LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; + mClient.downloadComplete(); + } else { + LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL; + std::string filePath = mDownloadData["path"].asString(); + if(filePath.size() != 0) LLFile::remove(filePath); + mClient.downloadError("failed hash check"); + } } else { - LL_WARNS("UpdateDownload") << "download failed with error " << code << LL_ENDL; + LL_WARNS("UpdateDownload") << "download failed with error '" << + curl_easy_strerror(code) << "'" << LL_ENDL; mClient.downloadError("curl error"); } } @@ -253,6 +264,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & download { } + /* bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData) { @@ -289,8 +301,9 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName); mDownloadData["path"] = filePath; - LL_INFOS("UpdateDownload") << "downloading " << filePath << "\n" - << "from " << uri.asString() << LL_ENDL; + LL_INFOS("UpdateDownload") << "downloading " << filePath + << " from " << uri.asString() << LL_ENDL; + LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL; llofstream dataStream(mDownloadRecordPath); LLSDSerialize parser; @@ -315,3 +328,21 @@ void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code) ; // No op. } } + + +bool LLUpdateDownloader::Implementation::validateDownload(void) +{ + std::string filePath = mDownloadData["path"].asString(); + llifstream fileStream(filePath); + if(!fileStream) return false; + + std::string hash = mDownloadData["hash"].asString(); + if(hash.size() != 0) { + LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL; + char digest[33]; + LLMD5(fileStream).hex_digest(digest); + return hash == digest; + } else { + return true; // No hash check provided. + } +} -- cgit v1.3 From 9d7cdc17e311ba5f1f62112e316c531b68f67046 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Fri, 5 Nov 2010 11:12:54 -0700 Subject: resume feature (untested). --- .../updater/llupdatedownloader.cpp | 104 ++++++++++++++------- .../viewer_components/updater/llupdatedownloader.h | 5 +- .../viewer_components/updater/llupdaterservice.cpp | 2 +- 3 files changed, 77 insertions(+), 34 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 59e929d99f..102f2f9eec 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -25,6 +25,7 @@ #include "linden_common.h" #include +#include #include #include #include "lldir.h" @@ -47,6 +48,8 @@ public: bool isDownloading(void); void onHeader(void * header, size_t size); void onBody(void * header, size_t size); + void resume(void); + private: LLUpdateDownloader::Client & mClient; CURL * mCurl; @@ -54,8 +57,8 @@ private: llofstream mDownloadStream; std::string mDownloadRecordPath; - void initializeCurlGet(std::string const & url); - void resumeDownloading(LLSD const & downloadData); + void initializeCurlGet(std::string const & url, bool processHeader); + void resumeDownloading(size_t startByte); void run(void); void startDownloading(LLURI const & uri, std::string const & hash); void throwOnCurlError(CURLcode code); @@ -119,6 +122,12 @@ bool LLUpdateDownloader::isDownloading(void) } +void LLUpdateDownloader::resume(void) +{ + mImplementation->resume(); +} + + // LLUpdateDownloader::Implementation //----------------------------------------------------------------------------- @@ -183,6 +192,45 @@ bool LLUpdateDownloader::Implementation::isDownloading(void) return !isStopped(); } + +void LLUpdateDownloader::Implementation::resume(void) +{ + llifstream dataStream(mDownloadRecordPath); + if(!dataStream) { + mClient.downloadError("no download marker"); + return; + } + + LLSDSerialize parser; + parser.fromXMLDocument(mDownloadData, dataStream); + + if(!mDownloadData.asBoolean()) { + mClient.downloadError("no download information in marker"); + return; + } + + std::string filePath = mDownloadData["path"].asString(); + try { + if(LLFile::isfile(filePath)) { + llstat fileStatus; + LLFile::stat(filePath, &fileStatus); + if(fileStatus.st_size != mDownloadData["size"].asInteger()) { + resumeDownloading(fileStatus.st_size); + } else if(!validateDownload()) { + LLFile::remove(filePath); + download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); + } else { + mClient.downloadComplete(mDownloadData); + } + } else { + download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); + } + } catch(DownloadError & e) { + mClient.downloadError(e.what()); + } +} + + void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) { char const * headerPtr = reinterpret_cast (buffer); @@ -221,10 +269,11 @@ void LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) void LLUpdateDownloader::Implementation::run(void) { CURLcode code = curl_easy_perform(mCurl); + LLFile::remove(mDownloadRecordPath); if(code == CURLE_OK) { if(validateDownload()) { LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; - mClient.downloadComplete(); + mClient.downloadComplete(mDownloadData); } else { LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL; std::string filePath = mDownloadData["path"].asString(); @@ -239,7 +288,7 @@ void LLUpdateDownloader::Implementation::run(void) } -void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url) +void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader) { if(mCurl == 0) { mCurl = curl_easy_init(); @@ -253,42 +302,33 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u 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)); + if(processHeader) { + 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())); } -void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & downloadData) -{ -} - - -/* -bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData) +void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte) { - if(!LLFile::isfile(mDownloadRecordPath)) return false; + initializeCurlGet(mDownloadData["url"].asString(), false); - llifstream dataStream(mDownloadRecordPath); - LLSDSerialize parser; - parser.fromXMLDocument(downloadData, dataStream); + // The header 'Range: bytes n-' will request the bytes remaining in the + // source begining with byte n and ending with the last byte. + boost::format rangeHeaderFormat("Range: bytes=%u-"); + rangeHeaderFormat % startByte; + curl_slist * headerList = 0; + headerList = curl_slist_append(headerList, rangeHeaderFormat.str().c_str()); + if(headerList == 0) throw DownloadError("cannot add Range header"); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, headerList)); + curl_slist_free_all(headerList); - if(downloadData["url"].asString() != uri.asString()) return false; - - std::string downloadedFilePath = downloadData["path"].asString(); - if(LLFile::isfile(downloadedFilePath)) { - llstat fileStatus; - LLFile::stat(downloadedFilePath, &fileStatus); - downloadData["bytes_downloaded"] = LLSD(LLSD::Integer(fileStatus.st_size)); - return true; - } else { - return false; - } - - return true; + mDownloadStream.open(mDownloadData["path"].asString(), + std::ios_base::out | std::ios_base::binary | std::ios_base::app); + start(); } - */ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash) @@ -310,7 +350,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std parser.toPrettyXML(mDownloadData, dataStream); mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary); - initializeCurlGet(uri.asString()); + initializeCurlGet(uri.asString(), true); start(); } diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index 8754ea329c..7bfb430879 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -56,6 +56,9 @@ public: // Returns true if a download is in progress. bool isDownloading(void); + // Resume a partial download. + void resume(void); + private: boost::shared_ptr mImplementation; }; @@ -68,7 +71,7 @@ class LLUpdateDownloader::Client { public: // The download has completed successfully. - virtual void downloadComplete(void) = 0; + virtual void downloadComplete(LLSD const & data) = 0; // The download failed. 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 1e0c393539..dc48606cbc 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -99,7 +99,7 @@ public: virtual void upToDate(void); // LLUpdateDownloader::Client - void downloadComplete(void) { retry(); } + void downloadComplete(LLSD const & data) { retry(); } void downloadError(std::string const & message) { retry(); } bool onMainLoop(LLSD const & event); -- cgit v1.3 From 6f7183cd4422a008554afd854dc631fe575ad8dc Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Fri, 5 Nov 2010 13:56:36 -0700 Subject: Fixed windows build error. --- indra/viewer_components/updater/llupdatedownloader.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 102f2f9eec..75f896cc76 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -201,8 +201,7 @@ void LLUpdateDownloader::Implementation::resume(void) return; } - LLSDSerialize parser; - parser.fromXMLDocument(mDownloadData, dataStream); + LLSDSerialize::fromXMLDocument(mDownloadData, dataStream); if(!mDownloadData.asBoolean()) { mClient.downloadError("no download information in marker"); @@ -248,8 +247,7 @@ void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) mDownloadData["size"] = LLSD(LLSD::Integer(size)); llofstream odataStream(mDownloadRecordPath); - LLSDSerialize parser; - parser.toPrettyXML(mDownloadData, odataStream); + LLSDSerialize::toPrettyXML(mDownloadData, odataStream); } catch (std::exception const & e) { LL_WARNS("UpdateDownload") << "unable to read content length (" << e.what() << ")" << LL_ENDL; @@ -346,8 +344,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL; llofstream dataStream(mDownloadRecordPath); - LLSDSerialize parser; - parser.toPrettyXML(mDownloadData, dataStream); + LLSDSerialize::toPrettyXML(mDownloadData, dataStream); mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary); initializeCurlGet(uri.asString(), true); -- cgit v1.3 From a13acfc9073b0e29d84e1633fc11ff08e285be8f Mon Sep 17 00:00:00 2001 From: brad kittenbrink Date: Fri, 5 Nov 2010 15:08:27 -0700 Subject: Fixed build error due to unreferenced local variable. --- indra/viewer_components/updater/llupdatedownloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 75f896cc76..efb55ab83a 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -158,7 +158,7 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & mDownloadRecordPath(LLUpdateDownloader::downloadMarkerPath()) { CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. - llassert(code = CURLE_OK); // TODO: real error handling here. + llverify(code == CURLE_OK); // TODO: real error handling here. } -- cgit v1.3 From 02c362b8ccad08f290ca99a738ca6ad1546c7df6 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Fri, 5 Nov 2010 15:56:33 -0700 Subject: implement download cancel (untested). --- .../updater/llupdatedownloader.cpp | 37 +++++++++++++++------- .../viewer_components/updater/llupdatedownloader.h | 3 +- 2 files changed, 27 insertions(+), 13 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 102f2f9eec..eaef230a8f 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -46,11 +46,12 @@ public: void cancel(void); 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); + size_t onHeader(void * header, size_t size); + size_t onBody(void * header, size_t size); void resume(void); private: + bool mCancelled; LLUpdateDownloader::Client & mClient; CURL * mCurl; LLSD mDownloadData; @@ -137,28 +138,27 @@ namespace { size_t write_function(void * data, size_t blockSize, size_t blocks, void * downloader) { size_t bytes = blockSize * blocks; - reinterpret_cast(downloader)->onBody(data, bytes); - return bytes; + return reinterpret_cast(downloader)->onBody(data, bytes); } size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader) { size_t bytes = blockSize * blocks; - reinterpret_cast(downloader)->onHeader(data, bytes); - return bytes; + return reinterpret_cast(downloader)->onHeader(data, bytes); } } LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client): LLThread("LLUpdateDownloader"), + mCancelled(false), mClient(client), mCurl(0), mDownloadRecordPath(LLUpdateDownloader::downloadMarkerPath()) { CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. - llassert(code = CURLE_OK); // TODO: real error handling here. + llassert(code == CURLE_OK); // TODO: real error handling here. } @@ -170,7 +170,7 @@ LLUpdateDownloader::Implementation::~Implementation() void LLUpdateDownloader::Implementation::cancel(void) { - llassert(!"not implemented"); + mCancelled = true; } @@ -231,12 +231,12 @@ void LLUpdateDownloader::Implementation::resume(void) } -void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) +size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) { char const * headerPtr = reinterpret_cast (buffer); std::string header(headerPtr, headerPtr + size); size_t colonPosition = header.find(':'); - if(colonPosition == std::string::npos) return; // HTML response; ignore. + if(colonPosition == std::string::npos) return size; // HTML response; ignore. if(header.substr(0, colonPosition) == "Content-Length") { try { @@ -257,20 +257,25 @@ void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) } else { ; // No op. } + + return size; } -void LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) +size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) { + if(mCancelled) return 0; // Forces a write error which will halt curl thread. + mDownloadStream.write(reinterpret_cast(buffer), size); + return size; } void LLUpdateDownloader::Implementation::run(void) { CURLcode code = curl_easy_perform(mCurl); - LLFile::remove(mDownloadRecordPath); if(code == CURLE_OK) { + LLFile::remove(mDownloadRecordPath); if(validateDownload()) { LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; mClient.downloadComplete(mDownloadData); @@ -280,9 +285,13 @@ void LLUpdateDownloader::Implementation::run(void) if(filePath.size() != 0) LLFile::remove(filePath); mClient.downloadError("failed hash check"); } + } else if(mCancelled && (code == CURLE_WRITE_ERROR)) { + LL_INFOS("UpdateDownload") << "download canceled by user" << LL_ENDL; + // Do not call back client. } else { LL_WARNS("UpdateDownload") << "download failed with error '" << curl_easy_strerror(code) << "'" << LL_ENDL; + LLFile::remove(mDownloadRecordPath); mClient.downloadError("curl error"); } } @@ -381,6 +390,10 @@ bool LLUpdateDownloader::Implementation::validateDownload(void) LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL; char digest[33]; LLMD5(fileStream).hex_digest(digest); + if(hash != digest) { + LL_WARNS("UpdateDownload") << "download hash mismatch; expeted " << hash << + " but download is " << digest << LL_ENDL; + } return hash == digest; } else { return true; // No hash check provided. diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index dc8ecc378a..491a638f9a 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -47,7 +47,8 @@ public: LLUpdateDownloader(Client & client); - // Cancel any in progress download; a no op if none is in progress. + // Cancel any in progress download; a no op if none is in progress. The + // client will not receive a complete or error callback. void cancel(void); // Start a new download. -- cgit v1.3 From 2cfcdfe2ffd97384324c940447a4197cbf85a38e Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 9 Nov 2010 09:14:50 -0800 Subject: Fix some stream bugs that were affecting windows download and validation. --- indra/viewer_components/updater/llupdatedownloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index ca1d2d25de..2794f80c47 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -272,6 +272,7 @@ size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) void LLUpdateDownloader::Implementation::run(void) { CURLcode code = curl_easy_perform(mCurl); + mDownloadStream.close(); if(code == CURLE_OK) { LLFile::remove(mDownloadRecordPath); if(validateDownload()) { @@ -379,7 +380,7 @@ void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code) bool LLUpdateDownloader::Implementation::validateDownload(void) { std::string filePath = mDownloadData["path"].asString(); - llifstream fileStream(filePath); + llifstream fileStream(filePath, std::ios_base::in | std::ios_base::binary); if(!fileStream) return false; std::string hash = mDownloadData["hash"].asString(); -- cgit v1.3 From 5da253fdde8737361333161517c1173358bd17ff Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 9 Nov 2010 11:16:28 -0800 Subject: Shut down thread if viewer closed while downloading; fix problem of download marker path failing to expand correctly because it was happening too early in start up. --- indra/viewer_components/updater/llupdatedownloader.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 2794f80c47..208cc48c12 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -154,8 +154,7 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & LLThread("LLUpdateDownloader"), mCancelled(false), mClient(client), - mCurl(0), - mDownloadRecordPath(LLUpdateDownloader::downloadMarkerPath()) + mCurl(0) { CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. llverify(code == CURLE_OK); // TODO: real error handling here. @@ -164,6 +163,12 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & LLUpdateDownloader::Implementation::~Implementation() { + if(isDownloading()) { + cancel(); + shutdown(); + } else { + ; // No op. + } if(mCurl) curl_easy_cleanup(mCurl); } @@ -177,7 +182,8 @@ void LLUpdateDownloader::Implementation::cancel(void) void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash) { if(isDownloading()) mClient.downloadError("download in progress"); - + + mDownloadRecordPath = downloadMarkerPath(); mDownloadData = LLSD(); try { startDownloading(uri, hash); @@ -195,6 +201,9 @@ bool LLUpdateDownloader::Implementation::isDownloading(void) void LLUpdateDownloader::Implementation::resume(void) { + if(isDownloading()) mClient.downloadError("download in progress"); + + mDownloadRecordPath = downloadMarkerPath(); llifstream dataStream(mDownloadRecordPath); if(!dataStream) { mClient.downloadError("no download marker"); -- cgit v1.3 From 94942671fa81ad0da3682af31b715ca49f8e3bef Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Wed, 10 Nov 2010 15:23:26 -0800 Subject: fix resume crash. --- .../viewer_components/updater/llupdatedownloader.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 208cc48c12..21555dc3ff 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -57,6 +57,7 @@ private: LLSD mDownloadData; llofstream mDownloadStream; std::string mDownloadRecordPath; + curl_slist * mHeaderList; void initializeCurlGet(std::string const & url, bool processHeader); void resumeDownloading(size_t startByte); @@ -154,7 +155,8 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & LLThread("LLUpdateDownloader"), mCancelled(false), mClient(client), - mCurl(0) + mCurl(0), + mHeaderList(0) { CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. llverify(code == CURLE_OK); // TODO: real error handling here. @@ -302,6 +304,11 @@ void LLUpdateDownloader::Implementation::run(void) LLFile::remove(mDownloadRecordPath); mClient.downloadError("curl error"); } + + if(mHeaderList) { + curl_slist_free_all(mHeaderList); + mHeaderList = 0; + } } @@ -330,17 +337,18 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte) { + LL_INFOS("UpdateDownload") << "resuming download from " << mDownloadData["url"].asString() + << " at byte " << startByte << LL_ENDL; + initializeCurlGet(mDownloadData["url"].asString(), false); // The header 'Range: bytes n-' will request the bytes remaining in the // source begining with byte n and ending with the last byte. boost::format rangeHeaderFormat("Range: bytes=%u-"); rangeHeaderFormat % startByte; - curl_slist * headerList = 0; - headerList = curl_slist_append(headerList, rangeHeaderFormat.str().c_str()); - if(headerList == 0) throw DownloadError("cannot add Range header"); - throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, headerList)); - curl_slist_free_all(headerList); + mHeaderList = curl_slist_append(mHeaderList, rangeHeaderFormat.str().c_str()); + if(mHeaderList == 0) throw DownloadError("cannot add Range header"); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaderList)); mDownloadStream.open(mDownloadData["path"].asString(), std::ios_base::out | std::ios_base::binary | std::ios_base::app); -- cgit v1.3 From 1368a94f014884588b343802eef5fd2c7888390a Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Fri, 12 Nov 2010 12:23:30 -0800 Subject: do not resume or install if current viewer version doesn't match the recorded version which started the process. --- .../updater/llupdatedownloader.cpp | 2 + .../viewer_components/updater/llupdaterservice.cpp | 71 +++++++++++++++++++--- indra/viewer_components/updater/llupdaterservice.h | 3 + 3 files changed, 67 insertions(+), 9 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 21555dc3ff..ab441aa747 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -35,6 +35,7 @@ #include "llsdserialize.h" #include "llthread.h" #include "llupdatedownloader.h" +#include "llupdaterservice.h" class LLUpdateDownloader::Implementation: @@ -360,6 +361,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std { mDownloadData["url"] = uri.asString(); mDownloadData["hash"] = hash; + mDownloadData["current_version"] = ll_get_version(); LLSD path = uri.pathArray(); if(path.size() == 0) throw DownloadError("no file path"); std::string fileName = path[path.size() - 1].asString(); diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index 43551d6cea..6cc872f2ca 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -31,6 +31,7 @@ #include "llupdaterservice.h" #include "llupdatechecker.h" #include "llupdateinstaller.h" +#include "llversionviewer.h" #include #include @@ -237,7 +238,23 @@ bool LLUpdaterServiceImpl::checkForInstall() // Get the path to the installer file. LLSD path = update_info.get("path"); - if(path.isDefined() && !path.asString().empty()) + if(update_info["current_version"].asString() != ll_get_version()) + { + // This viewer is not the same version as the one that downloaded + // the update. Do not install this update. + if(!path.asString().empty()) + { + llinfos << "ignoring update dowloaded by different client version" << llendl; + LLFile::remove(path.asString()); + } + else + { + ; // Nothing to clean up. + } + + result = false; + } + else if(path.isDefined() && !path.asString().empty()) { int result = ll_install_update(install_script_path(), update_info["path"].asString(), @@ -251,9 +268,9 @@ bool LLUpdaterServiceImpl::checkForInstall() } else { ; // No op. } + + result = true; } - - result = true; } return result; } @@ -261,14 +278,33 @@ bool LLUpdaterServiceImpl::checkForInstall() bool LLUpdaterServiceImpl::checkForResume() { bool result = false; - llstat stat_info; - if(0 == LLFile::stat(mUpdateDownloader.downloadMarkerPath(), &stat_info)) + std::string download_marker_path = mUpdateDownloader.downloadMarkerPath(); + if(LLFile::isfile(download_marker_path)) { - mIsDownloading = true; - mUpdateDownloader.resume(); - result = true; + llifstream download_marker_stream(download_marker_path, + std::ios::in | std::ios::binary); + if(download_marker_stream.is_open()) + { + LLSD download_info; + LLSDSerialize::fromXMLDocument(download_info, download_marker_stream); + download_marker_stream.close(); + if(download_info["current_version"].asString() == ll_get_version()) + { + mIsDownloading = true; + mUpdateDownloader.resume(); + result = true; + } + else + { + // The viewer that started this download is not the same as this viewer; ignore. + llinfos << "ignoring partial download from different viewer version" << llendl; + std::string path = download_info["path"].asString(); + if(!path.empty()) LLFile::remove(path); + LLFile::remove(download_marker_path); + } + } } - return false; + return result; } void LLUpdaterServiceImpl::error(std::string const & message) @@ -406,3 +442,20 @@ void LLUpdaterService::setImplAppExitCallback(LLUpdaterService::app_exit_callbac { return mImpl->setAppExitCallback(aecb); } + + +std::string const & ll_get_version(void) { + static std::string version(""); + + if (version.empty()) { + std::ostringstream stream; + stream << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; + version = stream.str(); + } + + return version; +} + diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 42ec3a2cab..ec20dc6e05 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -68,4 +68,7 @@ private: void setImplAppExitCallback(app_exit_callback_t aecb); }; +// Returns the full version as a string. +std::string const & ll_get_version(void); + #endif // LL_UPDATERSERVICE_H -- cgit v1.3 From 64876ea9459ed0e0f1673c5ec9ae67abea2280e2 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 16 Nov 2010 09:43:23 -0800 Subject: better error checking when writing downloaded file. --- indra/viewer_components/updater/llupdatedownloader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index ab441aa747..eccc25aeee 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -275,9 +275,14 @@ size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) size_t LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) { if(mCancelled) return 0; // Forces a write error which will halt curl thread. + if((size == 0) || (buffer == 0)) return 0; mDownloadStream.write(reinterpret_cast(buffer), size); - return size; + if(mDownloadStream.bad()) { + return 0; + } else { + return size; + } } -- cgit v1.3 From 74a60346b2f04157862786d31d7181885092b766 Mon Sep 17 00:00:00 2001 From: "Andrew A. de Laix" Date: Tue, 16 Nov 2010 16:22:37 -0800 Subject: remove downloaded file on error. --- indra/viewer_components/updater/llupdatedownloader.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index eccc25aeee..4820f1f452 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -308,6 +308,7 @@ void LLUpdateDownloader::Implementation::run(void) LL_WARNS("UpdateDownload") << "download failed with error '" << curl_easy_strerror(code) << "'" << LL_ENDL; LLFile::remove(mDownloadRecordPath); + if(mDownloadData.has("path")) LLFile::remove(mDownloadData["path"].asString()); mClient.downloadError("curl error"); } -- cgit v1.3 From 8c2026d6b71f133deafa6b0e19baf69632a2510a Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Thu, 18 Nov 2010 21:57:27 -0800 Subject: CHOP-135 Bug fixes. --- indra/llcommon/llfile.cpp | 5 ++ indra/newview/llappviewer.cpp | 3 +- indra/newview/llchiclet.cpp | 8 +- indra/newview/lltransientfloatermgr.cpp | 5 +- .../updater/llupdatedownloader.cpp | 6 +- .../viewer_components/updater/llupdaterservice.cpp | 85 +++++++++++++--------- indra/viewer_components/updater/llupdaterservice.h | 2 +- 7 files changed, 71 insertions(+), 43 deletions(-) (limited to 'indra/viewer_components/updater/llupdatedownloader.cpp') diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 289ce0bc2c..8f02391e75 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -318,7 +318,12 @@ void llofstream::close() if(is_open()) { if (_Filebuffer->close() == 0) + { _Myios::setstate(ios_base::failbit); /*Flawfinder: ignore*/ + } + delete _Filebuffer; + _Filebuffer = NULL; + _ShouldClose = false; } } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1fd8b02530..b6f52e3e15 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2433,7 +2433,8 @@ void LLAppViewer::initUpdater() mUpdater->setCheckPeriod(check_period); if(gSavedSettings.getBOOL("UpdaterServiceActive")) { - mUpdater->startChecking(); + bool install_if_ready = true; + mUpdater->startChecking(install_if_ready); } LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName()); diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 8f385160e9..885d553524 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -1092,9 +1092,11 @@ LLChicletPanel::LLChicletPanel(const Params&p) LLChicletPanel::~LLChicletPanel() { - LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton); - LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton); - + if(LLTransientFloaterMgr::instanceExists()) + { + LLTransientFloaterMgr::getInstance()->removeControlView(mLeftScrollButton); + LLTransientFloaterMgr::getInstance()->removeControlView(mRightScrollButton); + } } void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){ diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp index 78dd602f39..6deab96b45 100644 --- a/indra/newview/lltransientfloatermgr.cpp +++ b/indra/newview/lltransientfloatermgr.cpp @@ -36,8 +36,11 @@ LLTransientFloaterMgr::LLTransientFloaterMgr() { - gViewerWindow->getRootView()->addMouseDownCallback(boost::bind( + if(gViewerWindow) + { + gViewerWindow->getRootView()->addMouseDownCallback(boost::bind( &LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3)); + } mGroupControls.insert(std::pair >(GLOBAL, std::set())); mGroupControls.insert(std::pair >(DOCKED, std::set())); diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 4820f1f452..c17a50e242 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -204,7 +204,11 @@ bool LLUpdateDownloader::Implementation::isDownloading(void) void LLUpdateDownloader::Implementation::resume(void) { - if(isDownloading()) mClient.downloadError("download in progress"); + mCancelled = false; + + if(isDownloading()) { + mClient.downloadError("download in progress"); + } mDownloadRecordPath = downloadMarkerPath(); llifstream dataStream(mDownloadRecordPath); diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index b49f6d04b0..cc60eaead2 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -112,13 +112,13 @@ public: void setCheckPeriod(unsigned int seconds); - void startChecking(); + void startChecking(bool install_if_ready); void stopChecking(); bool isChecking(); void setAppExitCallback(LLUpdaterService::app_exit_callback_t aecb) { mAppExitCallback = aecb;} - bool checkForInstall(); // Test if a local install is ready. + bool checkForInstall(bool launchInstaller); // Test if a local install is ready. bool checkForResume(); // Test for resumeable d/l. // LLUpdateChecker::Client: @@ -139,6 +139,7 @@ public: private: void restartTimer(unsigned int seconds); + void stopTimer(); }; const std::string LLUpdaterServiceImpl::sListenerName = "LLUpdaterServiceImpl"; @@ -182,7 +183,7 @@ void LLUpdaterServiceImpl::setCheckPeriod(unsigned int seconds) mCheckPeriod = seconds; } -void LLUpdaterServiceImpl::startChecking() +void LLUpdaterServiceImpl::startChecking(bool install_if_ready) { if(mUrl.empty() || mChannel.empty() || mVersion.empty()) { @@ -193,17 +194,18 @@ void LLUpdaterServiceImpl::startChecking() mIsChecking = true; // Check to see if an install is ready. - if(!checkForInstall()) + bool has_install = checkForInstall(install_if_ready); + if(!has_install) { - checkForResume(); - } + checkForResume(); // will set mIsDownloading to true if resuming - if(!mIsDownloading) - { - // Checking can only occur during the mainloop. - // reset the timer to 0 so that the next mainloop event - // triggers a check; - restartTimer(0); + if(!mIsDownloading) + { + // Checking can only occur during the mainloop. + // reset the timer to 0 so that the next mainloop event + // triggers a check; + restartTimer(0); + } } } @@ -212,12 +214,13 @@ void LLUpdaterServiceImpl::stopChecking() if(mIsChecking) { mIsChecking = false; - mTimer.stop(); + stopTimer(); } if(mIsDownloading) { - this->mUpdateDownloader.cancel(); + mUpdateDownloader.cancel(); + mIsDownloading = false; } } @@ -226,9 +229,9 @@ bool LLUpdaterServiceImpl::isChecking() return mIsChecking; } -bool LLUpdaterServiceImpl::checkForInstall() +bool LLUpdaterServiceImpl::checkForInstall(bool launchInstaller) { - bool result = false; // return true if install is found. + bool foundInstall = false; // return true if install is found. llifstream update_marker(update_marker_path(), std::ios::in | std::ios::binary); @@ -239,7 +242,6 @@ bool LLUpdaterServiceImpl::checkForInstall() LLSD update_info; LLSDSerialize::fromXMLDocument(update_info, update_marker); update_marker.close(); - LLFile::remove(update_marker_path()); // Get the path to the installer file. LLSD path = update_info.get("path"); @@ -251,33 +253,39 @@ bool LLUpdaterServiceImpl::checkForInstall() { llinfos << "ignoring update dowloaded by different client version" << llendl; LLFile::remove(path.asString()); + LLFile::remove(update_marker_path()); } else { ; // Nothing to clean up. } - result = false; + foundInstall = false; } else if(path.isDefined() && !path.asString().empty()) { - int result = ll_install_update(install_script_path(), - update_info["path"].asString(), - install_script_mode()); - - if((result == 0) && mAppExitCallback) + if(launchInstaller) { - mAppExitCallback(); - } else if(result != 0) { - llwarns << "failed to run update install script" << LL_ENDL; - } else { - ; // No op. + LLFile::remove(update_marker_path()); + + int result = ll_install_update(install_script_path(), + update_info["path"].asString(), + install_script_mode()); + + if((result == 0) && mAppExitCallback) + { + mAppExitCallback(); + } else if(result != 0) { + llwarns << "failed to run update install script" << LL_ENDL; + } else { + ; // No op. + } } - result = true; + foundInstall = true; } } - return result; + return foundInstall; } bool LLUpdaterServiceImpl::checkForResume() @@ -324,7 +332,7 @@ void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, LLURI const & uri, std::string const & hash) { - mTimer.stop(); + stopTimer(); mIsDownloading = true; mUpdateDownloader.download(uri, hash); } @@ -333,7 +341,7 @@ void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, LLURI const & uri, std::string const & hash) { - mTimer.stop(); + stopTimer(); mIsDownloading = true; mUpdateDownloader.download(uri, hash); } @@ -394,12 +402,17 @@ void LLUpdaterServiceImpl::restartTimer(unsigned int seconds) sListenerName, boost::bind(&LLUpdaterServiceImpl::onMainLoop, this, _1)); } +void LLUpdaterServiceImpl::stopTimer() +{ + mTimer.stop(); + LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName); +} + bool LLUpdaterServiceImpl::onMainLoop(LLSD const & event) { if(mTimer.getStarted() && mTimer.hasExpired()) { - mTimer.stop(); - LLEventPumps::instance().obtain("mainloop").stopListening(sListenerName); + stopTimer(); // Check for failed install. if(LLFile::isfile(ll_install_failed_marker_path())) @@ -468,9 +481,9 @@ void LLUpdaterService::setCheckPeriod(unsigned int seconds) mImpl->setCheckPeriod(seconds); } -void LLUpdaterService::startChecking() +void LLUpdaterService::startChecking(bool install_if_ready) { - mImpl->startChecking(); + mImpl->startChecking(install_if_ready); } void LLUpdaterService::stopChecking() diff --git a/indra/viewer_components/updater/llupdaterservice.h b/indra/viewer_components/updater/llupdaterservice.h index 55824af188..752a6f834b 100644 --- a/indra/viewer_components/updater/llupdaterservice.h +++ b/indra/viewer_components/updater/llupdaterservice.h @@ -62,7 +62,7 @@ public: void setCheckPeriod(unsigned int seconds); - void startChecking(); + void startChecking(bool install_if_ready = false); void stopChecking(); bool isChecking(); -- cgit v1.3