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