diff options
| -rw-r--r-- | indra/llcommon/llprocess.cpp | 26 | ||||
| -rw-r--r-- | indra/viewer_components/updater/llupdatedownloader.cpp | 114 | 
2 files changed, 68 insertions, 72 deletions
| diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index e96b328365..760be6da9b 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -282,9 +282,13 @@ public:  	virtual std::string read(size_type len)  	{ -		// Read specified number of bytes into a buffer. Make a buffer big -		// enough. +		// Read specified number of bytes into a buffer.  		size_type readlen((std::min)(size(), len)); +		// Formally, &buffer[0] is invalid for a vector of size() 0. Exit +		// early in that situation. +		if (! readlen) +			return ""; +		// Make a buffer big enough.  		std::vector<char> buffer(readlen);  		mStream.read(&buffer[0], readlen);  		// Since we've already clamped 'readlen', we can think of no reason @@ -535,24 +539,6 @@ LLProcess::LLProcess(const LLSDOrParams& params):  	apr_procattr_t *procattr = NULL;  	chkapr(apr_procattr_create(&procattr, gAPRPoolp)); -#if ! defined(APR_HAS_PROCATTR_INHERIT_SET) -	// Our special preprocessor symbol isn't even defined -- wrong APR -	LL_WARNS("LLProcess") << "This version of APR lacks Linden apr_procattr_inherit_set() extension" << LL_ENDL; -#elif ! APR_HAS_PROCATTR_INHERIT_SET -	// Symbol is defined, but to 0: expect apr_procattr_inherit_set() to -	// return APR_ENOTIMPL. -	LL_DEBUGS("LLProcess") << "apr_procattr_inherit_set() not supported on this platform" << LL_ENDL; -#else  // APR_HAS_PROCATTR_INHERIT_SET nonzero -	// As of 2012-04-17, the original Windows implementation of -	// apr_proc_create() unconditionally passes TRUE for bInheritHandles. That -	// seems to assume that all files are opened by APR so you can -	// individually control whether each is inherited by a child process. But -	// we've been burned by having surprising open file handles inherited by -	// our child processes. Turn that OFF for us! -	LL_DEBUGS("LLProcess") << "Setting apr_procattr_inherit_set(0)" << LL_ENDL; -	ll_apr_warn_status(apr_procattr_inherit_set(procattr, 0)); -#endif -  	// For which of stdin, stdout, stderr should we create a pipe to the  	// child? In the viewer, there are only a couple viable  	// apr_procattr_io_set() alternatives: inherit the viewer's own stdxxx diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 19ac418e9e..5d48c35b4c 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -1,24 +1,24 @@ -/**  +/**   * @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$   */ @@ -40,6 +40,7 @@  #include "llthread.h"  #include "llupdaterservice.h"  #include "llcurl.h" +#include "llapr.h"  class LLUpdateDownloader::Implementation:  	public LLThread @@ -58,18 +59,18 @@ public:  	int onProgress(double downloadSize, double bytesDownloaded);  	void resume(void);  	void setBandwidthLimit(U64 bytesPerSecond); -	 +  private:  	curl_off_t mBandwidthLimit;  	bool mCancelled;  	LLUpdateDownloader::Client & mClient;  	CURL * mCurl;  	LLSD mDownloadData; -	llofstream mDownloadStream; +	apr_file_t* mDownloadStream;  	unsigned char mDownloadPercent;  	std::string mDownloadRecordPath;  	curl_slist * mHeaderList; -	 +  	void initializeCurlGet(std::string const & url, bool processHeader);  	void resumeDownloading(size_t startByte);  	void run(void); @@ -93,7 +94,7 @@ namespace {  		}  	}; -		 +  	const char * gSecondLifeUpdateRecord = "SecondLifeUpdateDownload.xml";  }; @@ -188,22 +189,23 @@ LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client &  	mCancelled(false),  	mClient(client),  	mCurl(0), +	mDownloadStream(NULL),  	mDownloadPercent(0),  	mHeaderList(0)  {  	CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case. -	llverify(code == CURLE_OK); // TODO: real error handling here.  +	llverify(code == CURLE_OK); // TODO: real error handling here.  }  LLUpdateDownloader::Implementation::~Implementation()  { -	if(isDownloading())  +	if(isDownloading())  	{  		cancel();  		shutdown(); -	}  -	else  +	} +	else  	{  		; // No op.  	} @@ -218,7 +220,7 @@ void LLUpdateDownloader::Implementation::cancel(void)  {  	mCancelled = true;  } -	 +  void LLUpdateDownloader::Implementation::download(LLURI const & uri,  												  std::string const & hash, @@ -259,24 +261,24 @@ void LLUpdateDownloader::Implementation::resume(void)  		mClient.downloadError("no download marker");  		return;  	} -	 +  	LLSDSerialize::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)) {		 +		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()),  +				download(LLURI(mDownloadData["url"].asString()),  						 mDownloadData["hash"].asString(),  						 mDownloadData["update_version"].asString(),  						 mDownloadData["required"].asBoolean()); @@ -284,7 +286,7 @@ void LLUpdateDownloader::Implementation::resume(void)  				mClient.downloadComplete(mDownloadData);  			}  		} else { -			download(LLURI(mDownloadData["url"].asString()),  +			download(LLURI(mDownloadData["url"].asString()),  					 mDownloadData["hash"].asString(),  					 mDownloadData["update_version"].asString(),  					 mDownloadData["required"].asBoolean()); @@ -301,7 +303,7 @@ void LLUpdateDownloader::Implementation::setBandwidthLimit(U64 bytesPerSecond)  		llassert(mCurl != 0);  		mBandwidthLimit = bytesPerSecond;  		CURLcode code = curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, &mBandwidthLimit); -		if(code != CURLE_OK) LL_WARNS("UpdateDownload") <<  +		if(code != CURLE_OK) LL_WARNS("UpdateDownload") <<  			"unable to change dowload bandwidth" << LL_ENDL;  	} else {  		mBandwidthLimit = bytesPerSecond; @@ -315,7 +317,7 @@ size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)  	std::string header(headerPtr, headerPtr + size);  	size_t colonPosition = header.find(':');  	if(colonPosition == std::string::npos) return size; // HTML response; ignore. -	 +  	if(header.substr(0, colonPosition) == "Content-Length") {  		try {  			size_t firstDigitPos = header.find_first_of("0123456789", colonPosition); @@ -323,18 +325,18 @@ size_t LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)  			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; -			 +  			mDownloadData["size"] = LLSD(LLSD::Integer(size));  			llofstream odataStream(mDownloadRecordPath);  			LLSDSerialize::toPrettyXML(mDownloadData, odataStream);  		} catch (std::exception const & e) { -			LL_WARNS("UpdateDownload") << "unable to read content length ("  +			LL_WARNS("UpdateDownload") << "unable to read content length ("  				<< e.what() << ")" << LL_ENDL;  		}  	} else {  		; // No op.  	} -	 +  	return size;  } @@ -342,14 +344,11 @@ 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<const char *>(buffer), size); -	if(mDownloadStream.bad()) { -		return 0; -	} else { -		return size; -	} +	if((size == 0) || (buffer == 0)) return 0; + +	apr_size_t written(size); +	ll_apr_warn_status(apr_file_write(mDownloadStream, buffer, &written)); +	return written;  } @@ -358,7 +357,7 @@ int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double b  	int downloadPercent = static_cast<int>(100. * (bytesDownloaded / downloadSize));  	if(downloadPercent > mDownloadPercent) {  		mDownloadPercent = downloadPercent; -		 +  		LLSD event;  		event["pump"] = LLUpdaterService::pumpName();  		LLSD payload; @@ -367,12 +366,12 @@ int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double b  		payload["bytes_downloaded"] = bytesDownloaded;  		event["payload"] = payload;  		LLEventPumps::instance().obtain("mainlooprepeater").post(event); -		 +  		LL_INFOS("UpdateDownload") << "progress event " << payload << LL_ENDL;  	} else {  		; // Keep events to a reasonalbe number.  	} -	 +  	return 0;  } @@ -380,7 +379,8 @@ int LLUpdateDownloader::Implementation::onProgress(double downloadSize, double b  void LLUpdateDownloader::Implementation::run(void)  {  	CURLcode code = curl_easy_perform(mCurl); -	mDownloadStream.close(); +	ll_apr_warn_status(apr_file_close(mDownloadStream)); +	mDownloadStream = NULL;  	if(code == CURLE_OK) {  		LLFile::remove(mDownloadRecordPath);  		if(validateDownload()) { @@ -396,13 +396,13 @@ void LLUpdateDownloader::Implementation::run(void)  		LL_INFOS("UpdateDownload") << "download canceled by user" << LL_ENDL;  		// Do not call back client.  	} else { -		LL_WARNS("UpdateDownload") << "download failed with error '" <<  +		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");  	} -	 +  	if(mHeaderList) {  		curl_slist_free_all(mHeaderList);  		mHeaderList = 0; @@ -412,17 +412,17 @@ void LLUpdateDownloader::Implementation::run(void)  void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader)  { -	if(mCurl == 0)  +	if(mCurl == 0)  	{  		mCurl = LLCurl::newEasyHandle(); -	}  -	else  +	} +	else  	{  		curl_easy_reset(mCurl);  	} -	 +  	if(mCurl == 0) throw DownloadError("failed to initialize curl"); -	 +  	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)); @@ -439,7 +439,7 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u  	// if it's a required update set the bandwidth limit to 0 (unlimited)  	curl_off_t limit = mDownloadData["required"].asBoolean() ? 0 : mBandwidthLimit;  	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_MAX_RECV_SPEED_LARGE, limit)); -	 +  	mDownloadPercent = 0;  } @@ -450,7 +450,7 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)  		<< " 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-"); @@ -458,9 +458,10 @@ void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)  	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); + +	ll_apr_warn_status(apr_file_open(&mDownloadStream, mDownloadData["path"].asString().c_str(), +									 APR_WRITE | APR_APPEND | APR_BINARY | APR_BUFFERED, +									 APR_OS_DEFAULT, gAPRPoolp));  	start();  } @@ -479,11 +480,20 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std  	LL_INFOS("UpdateDownload") << "downloading " << filePath  		<< " from " << uri.asString() << LL_ENDL;  	LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL; -		 +  	llofstream dataStream(mDownloadRecordPath);  	LLSDSerialize::toPrettyXML(mDownloadData, dataStream); -	 -	mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary); + +	ll_apr_warn_status(apr_file_open(&mDownloadStream, filePath.c_str(), +									 APR_WRITE | APR_TRUNCATE | APR_BINARY | APR_BUFFERED, +									 APR_OS_DEFAULT, gAPRPoolp)); +	// IQA-463: Do NOT let this open file be inherited by child processes. +	// That's why we switched from llofstream to apr_file_t. From +	// apr_file_open() doc +	// http://apr.apache.org/docs/apr/1.4/group__apr__file__io.html#gabda14cbf242fb4fe99055434213e5446 : +	// "By default, the returned file descriptor will not be inherited by +	// child processes created by apr_proc_create(). This can be changed using +	// apr_file_inherit_set()."  	initializeCurlGet(uri.asString(), true);  	start();  } | 
