Example #1
0
void LLHTTPAssetStorage::bumpTimedOutUploads()
{
	// No point bumping currently running uploads if there are no others in line.
	if (!(mPendingUploads.size() > mRunningUploads.size())) 
	{
		return;
	}

	F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();

	// deletePendingRequest will modify the mRunningUploads list so we don't want to iterate over it.
	request_list_t temp_running = mRunningUploads;

	request_list_t::iterator it = temp_running.begin();
	request_list_t::iterator end = temp_running.end();
	for ( ; it != end; ++it)
	{
		//request_list_t::iterator curiter = iter++;
		LLAssetRequest* req = *it;

		if ( LL_ASSET_STORAGE_TIMEOUT < (mt_secs - req->mTime) )
		{
			llwarns << "Asset upload request timed out for "
					<< req->getUUID() << "."
					<< LLAssetType::lookup(req->getType()) 
					<< ", bumping to the back of the line!" << llendl;

			deletePendingRequest(RT_UPLOAD, req->getType(), req->getUUID());
		}
	}
}
Example #2
0
// virtual
bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests,
											LLAssetType::EType asset_type,
											const LLUUID& asset_id)
{
	LLAssetRequest* req = findRequest(requests, asset_type, asset_id);
	if (req)
	{
		// Remove the request from this list.
		requests->remove(req);
		S32 error = LL_ERR_TCP_TIMEOUT;
		// Run callbacks.
		if (req->mUpCallback)
		{
			req->mUpCallback(req->getUUID(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
		}
		if (req->mDownCallback)
		{
			req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
		}
		if (req->mInfoCallback)
		{
			LLAssetInfo info;
			req->mInfoCallback(&info, req->mUserData, error);
		}
		delete req;
		return true;
	}
	
	return false;
}
Example #3
0
void LLAssetStorage::_cleanupRequests(BOOL all, S32 error)
{
	F64 mt_secs = LLMessageSystem::getMessageTimeSeconds();

	request_list_t timed_out;
	S32 rt;
	for (rt = 0; rt < RT_COUNT; rt++)
	{
		request_list_t* requests = getRequestList((ERequestType)rt);
		for (request_list_t::iterator iter = requests->begin();
			 iter != requests->end(); )
		{
			request_list_t::iterator curiter = iter++;
			LLAssetRequest* tmp = *curiter;
			// if all is true, we want to clean up everything
			// otherwise just check for timed out requests
			// EXCEPT for upload timeouts
			if (all 
				|| ((RT_DOWNLOAD == rt)
					&& LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime)))
			{
				llwarns << "Asset " << getRequestName((ERequestType)rt) << " request "
						<< (all ? "aborted" : "timed out") << " for "
						<< tmp->getUUID() << "."
						<< LLAssetType::lookup(tmp->getType()) << llendl;

				timed_out.push_front(tmp);
				iter = requests->erase(curiter);
			}
		}
	}

	LLAssetInfo	info;
	for (request_list_t::iterator iter = timed_out.begin();
		 iter != timed_out.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if (tmp->mUpCallback)
		{
			tmp->mUpCallback(tmp->getUUID(), tmp->mUserData, error, LL_EXSTAT_NONE);
		}
		if (tmp->mDownCallback)
		{
			tmp->mDownCallback(mVFS, tmp->getUUID(), tmp->getType(), tmp->mUserData, error, LL_EXSTAT_NONE);
		}
		if (tmp->mInfoCallback)
		{
			tmp->mInfoCallback(&info, tmp->mUserData, error);
		}
		delete tmp;
	}

}
Example #4
0
void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
{
	// check for duplicates here, since we're about to fool the normal duplicate checker
	for (request_list_t::iterator iter = mPendingDownloads.begin();
		 iter != mPendingDownloads.end();  )
	{
		LLAssetRequest* tmp = *iter++;
		if (type == tmp->getType() && 
			uuid == tmp->getUUID() &&
			legacyGetDataCallback == tmp->mDownCallback &&
			callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback &&
			user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData)
		{
			// this is a duplicate from the same subsystem - throw it away
			llinfos << "Discarding duplicate request for UUID " << uuid << llendl;
			return;
		}
	}
	
	
	LLLegacyAssetRequest *legacy = new LLLegacyAssetRequest;

	legacy->mDownCallback = callback;
	legacy->mUserData = user_data;

	getAssetData(uuid, type, legacyGetDataCallback, (void **)legacy,
				 is_priority);
}
Example #5
0
// virtual
LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests,
										LLAssetType::EType asset_type,
										const std::string& detail_prefix) const
{
	LLSD details;
	if (requests)
	{
		request_list_t::const_iterator it = requests->begin();
		request_list_t::const_iterator end = requests->end();
		for ( ; it != end; ++it)
		{
			LLAssetRequest* req = *it;
			if (   (LLAssetType::AT_NONE == asset_type)
				|| (req->getType() == asset_type) )
			{
				LLSD row = req->getTerseDetails();

				std::ostringstream detail;
				detail	<< detail_prefix << "/" << LLAssetType::lookup(req->getType())
						<< "/" << req->getUUID();
				row["detail"] = LLURI(detail.str());

				details.append(row);
			}
		}
	}
	return details;
}
Example #6
0
void LLAssetStorage::_callUploadCallbacks(const LLUUID &uuid, LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status )
{
	// SJB: We process the callbacks in reverse order, I do not know if this is important,
	//      but I didn't want to mess with it.
	request_list_t requests;
	for (request_list_t::iterator iter = mPendingUploads.begin();
		 iter != mPendingUploads.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* req = *curiter;
		if ((req->getUUID() == uuid) && (req->getType() == asset_type))
		{
			requests.push_front(req);
			iter = mPendingUploads.erase(curiter);
		}
	}
	for (request_list_t::iterator iter = mPendingLocalUploads.begin();
		 iter != mPendingLocalUploads.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* req = *curiter;
		if ((req->getUUID() == uuid) && (req->getType() == asset_type))
		{
			requests.push_front(req);
			iter = mPendingLocalUploads.erase(curiter);
		}
	}
	for (request_list_t::iterator iter = requests.begin();
		 iter != requests.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* req = *curiter;
		if (req->mUpCallback)
		{
			req->mUpCallback(uuid, req->mUserData, (success ?  LL_ERR_NOERR :  LL_ERR_ASSET_REQUEST_FAILED ), ext_status );
		}
		delete req;
	}
}
Example #7
0
// static
LLAssetRequest* LLAssetStorage::findRequest(LLAssetStorage::request_list_t* requests,
										LLAssetType::EType asset_type,
										const LLUUID& asset_id)
{
	if (requests) 
	{
		// Search the requests list for the asset.
		request_list_t::iterator iter = requests->begin();
		request_list_t::iterator end  = requests->end();
		for (; iter != end; ++iter)
		{
			LLAssetRequest* req = *iter;
			if (asset_type == req->getType() &&
				asset_id == req->getUUID() )
			{
				return req;
			}
		}
	}
	return NULL;
}
Example #8
0
void LLAssetStorage::downloadCompleteCallback(
	S32 result,
	const LLUUID& file_id,
	LLAssetType::EType file_type,
	void* user_data, LLExtStat ext_status)
{
	lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id
		 << "," << LLAssetType::lookup(file_type) << llendl;
	LLAssetRequest* req = (LLAssetRequest*)user_data;
	if(!req)
	{
		llwarns << "LLAssetStorage::downloadCompleteCallback called without"
			"a valid request." << llendl;
		return;
	}
	if (!gAssetStorage)
	{
		llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
		return;
	}

	// Inefficient since we're doing a find through a list that may have thousands of elements.
	// This is due for refactoring; we will probably change mPendingDownloads into a set.
	request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), 
													   gAssetStorage->mPendingDownloads.end(),
													   req);
	// If the LLAssetRequest doesn't exist in the downloads queue, then it either has already been deleted
	// by _cleanupRequests, or it's a transfer.
	if (download_iter != gAssetStorage->mPendingDownloads.end())
	{
		req->setUUID(file_id);
		req->setType(file_type);
	}

	if (LL_ERR_NOERR == result)
	{
		// we might have gotten a zero-size file
		LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
		if (vfile.getSize() <= 0)
		{
			llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl;
			
			result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
			vfile.remove();
		}
	}
	
	// find and callback ALL pending requests for this UUID
	// SJB: We process the callbacks in reverse order, I do not know if this is important,
	//      but I didn't want to mess with it.
	request_list_t requests;
	for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
		 iter != gAssetStorage->mPendingDownloads.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
		{
			requests.push_front(tmp);
			iter = gAssetStorage->mPendingDownloads.erase(curiter);
		}
	}
	for (request_list_t::iterator iter = requests.begin();
		 iter != requests.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if (tmp->mDownCallback)
		{
			tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
		}
		delete tmp;
	}
}
Example #9
0
// IW - uuid is passed by value to avoid side effects, please don't re-add &    
void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL is_priority)
{
	lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;

	if (mShutDown)
	{
		return; // don't get the asset or do any callbacks, we are shutting down
	}
		
	if (uuid.isNull())
	{
		// Special case early out for NULL uuid
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
		}
		return;
	}
	/* <edit> */ 
	if(std::find(mBlackListedAsset.begin(),mBlackListedAsset.end(),uuid) != mBlackListedAsset.end())
	{
		llinfos << "Blacklisted asset " << uuid.asString() << " was trying to be accessed!!!!!!" << llendl; 
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
		}
		return;
	}
	/* </edit> */

	BOOL exists = mVFS->getExists(uuid, type);
	LLVFile file(mVFS, uuid, type);
	U32 size = exists ? file.getSize() : 0;
	
	if (size < 1)
	{
		if (exists)
		{
			llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl;
			file.remove();
		}
		
		BOOL duplicate = FALSE;
		
		// check to see if there's a pending download of this uuid already
		for (request_list_t::iterator iter = mPendingDownloads.begin();
			 iter != mPendingDownloads.end(); ++iter )
		{
			LLAssetRequest  *tmp = *iter;
			if ((type == tmp->getType()) && (uuid == tmp->getUUID()))
			{
				if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
				{
					// this is a duplicate from the same subsystem - throw it away
					llwarns << "Discarding duplicate request for asset " << uuid
							<< "." << LLAssetType::lookup(type) << llendl;
					return;
				}
				
				// this is a duplicate request
				// queue the request, but don't actually ask for it again
				duplicate = TRUE;
			}
		}
		if (duplicate)
		{
			llinfos << "Adding additional non-duplicate request for asset " << uuid 
					<< "." << LLAssetType::lookup(type) << llendl;
		}
		
		// This can be overridden by subclasses
		_queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);	
	}
	else
	{
		// we've already got the file
		// theoretically, partial files w/o a pending request shouldn't happen
		// unless there's a weird error
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
		}
	}
}
Example #10
0
// overloaded to additionally move data to/from the webserver
void LLHTTPAssetStorage::checkForTimeouts()
{
	CURLMcode mcode;
	LLAssetRequest *req;
	while ( (req = findNextRequest(mPendingDownloads, mRunningDownloads)) )
	{
		// Setup this curl download request
		// We need to generate a new request here
		// since the one in the list could go away
		char tmp_url[MAX_STRING]; /*Flawfinder: ignore*/
		char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/
		req->getUUID().toString(uuid_str);
		std::string base_url = getBaseURL(req->getUUID(), req->getType());
		snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", base_url.c_str() , uuid_str, LLAssetType::lookup(req->getType()));	/* Flawfinder: ignore */

		LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), 
										req->getType(), RT_DOWNLOAD, tmp_url, mCurlMultiHandle);
		new_req->mTmpUUID.generate();

		// Sets pending download flag internally
		new_req->setupCurlHandle();
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_FOLLOWLOCATION, TRUE);
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &curlDownCallback);
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEDATA, new_req->mCurlHandle);
	
		mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
		if (mcode > CURLM_OK)
		{
			// Failure.  Deleting the pending request will remove it from the running
			// queue, and push it to the end of the pending queue.
			new_req->cleanupCurlHandle();
			deletePendingRequest(RT_DOWNLOAD, new_req->getType(), new_req->getUUID());
			break;
		}
		else
		{
			llinfos << "Requesting " << new_req->mURLBuffer << llendl;
		}
	}

	while ( (req = findNextRequest(mPendingUploads, mRunningUploads)) )
	{
		// setup this curl upload request

		bool do_compress = req->getType() == LLAssetType::AT_OBJECT;

		char tmp_url[MAX_STRING];/*Flawfinder: ignore*/
		char uuid_str[UUID_STR_LENGTH];/*Flawfinder: ignore*/
		req->getUUID().toString(uuid_str);
		snprintf(tmp_url, sizeof(tmp_url), 					/* Flawfinder: ignore */
				do_compress ? "%s/%s.%s.gz" : "%s/%s.%s",
				mBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType())); 

		LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), 
									req->getType(), RT_UPLOAD, tmp_url, mCurlMultiHandle);
		if (do_compress)
		{
			new_req->prepareCompressedUpload();
		}

		// Sets pending upload flag internally
		new_req->setupCurlHandle();
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_UPLOAD, 1);
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);

		if (do_compress)
		{
			curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
					&LLHTTPAssetRequest::curlCompressedUploadCallback);
		}
		else
		{
			LLVFile file(mVFS, req->getUUID(), req->getType());
			curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
			curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION,
					&curlUpCallback);
		}
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
	
		mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
		if (mcode > CURLM_OK)
		{
			// Failure.  Deleting the pending request will remove it from the running
			// queue, and push it to the end of the pending queue.
			new_req->cleanupCurlHandle();
			deletePendingRequest(RT_UPLOAD, new_req->getType(), new_req->getUUID());
			break;
		}
		else
		{
			llinfos << "Requesting PUT " << new_req->mURLBuffer << llendl;
		}
		// Pending upload will have been flagged by the request
	}

	while ( (req = findNextRequest(mPendingLocalUploads, mRunningLocalUploads)) )
	{
		// setup this curl upload request
		LLVFile file(mVFS, req->getUUID(), req->getType());

		char tmp_url[MAX_STRING]; /*Flawfinder: ignore*/
		char uuid_str[UUID_STR_LENGTH]; /*Flawfinder: ignore*/
		req->getUUID().toString(uuid_str);
		
		// KLW - All temporary uploads are saved locally "http://localhost:12041/asset"
		snprintf(tmp_url, sizeof(tmp_url), "%s/%36s.%s", mLocalBaseURL.c_str(), uuid_str, LLAssetType::lookup(req->getType())); 	/* Flawfinder: ignore */

		LLHTTPAssetRequest *new_req = new LLHTTPAssetRequest(this, req->getUUID(), 
										req->getType(), RT_LOCALUPLOAD, tmp_url, mCurlMultiHandle);
		new_req->mRequestingAgentID = req->mRequestingAgentID;

		// Sets pending upload flag internally
		new_req->setupCurlHandle();
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_PUT, 1);
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_INFILESIZE, file.getSize());
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_WRITEFUNCTION, &nullOutputCallback);
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READFUNCTION, &curlUpCallback);
		curl_easy_setopt(new_req->mCurlHandle, CURLOPT_READDATA, new_req->mCurlHandle);
	
		mcode = curl_multi_add_handle(mCurlMultiHandle, new_req->mCurlHandle);
		if (mcode > CURLM_OK)
		{
			// Failure.  Deleting the pending request will remove it from the running
			// queue, and push it to the end of the pending queue.
			new_req->cleanupCurlHandle();
			deletePendingRequest(RT_LOCALUPLOAD, new_req->getType(), new_req->getUUID());
			break;
		}
		else
		{
			llinfos << "TAT: LLHTTPAssetStorage::checkForTimeouts() : pending local!"
				<< " Requesting PUT " << new_req->mURLBuffer << llendl;
		}
		// Pending upload will have been flagged by the request
	}
	S32 count = 0;
	int queue_length;
	do
	{
		mcode = curl_multi_perform(mCurlMultiHandle, &queue_length);
		count++;
	} while (mcode == CURLM_CALL_MULTI_PERFORM && (count < 5));

	CURLMsg *curl_msg;
	do
	{
		curl_msg = curl_multi_info_read(mCurlMultiHandle, &queue_length);
		if (curl_msg && curl_msg->msg == CURLMSG_DONE)
		{
			long curl_result = 0;
			S32 xfer_result = 0;

			LLHTTPAssetRequest *req = NULL;
			curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE, &req);
								
			curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_HTTP_CODE, &curl_result);
			if (RT_UPLOAD == req->mRequestType || RT_LOCALUPLOAD == req->mRequestType)
			{
				if (curl_msg->data.result == CURLE_OK && 
					(   curl_result == HTTP_OK 
					 || curl_result == HTTP_PUT_OK 
					 || curl_result == HTTP_NO_CONTENT))
				{
					llinfos << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << llendl;
					if (RT_LOCALUPLOAD == req->mRequestType)
					{
						addTempAssetData(req->getUUID(), req->mRequestingAgentID, mHostName);
					}
				}
				else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||
						curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
						curl_result == HTTP_SERVER_BAD_GATEWAY ||
						curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)
				{
					llwarns << "Re-requesting upload for " << req->getUUID() << ".  Received upload error to " << req->mURLBuffer <<
						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;
				}
				else
				{
					llwarns << "Failure uploading " << req->getUUID() << " to " << req->mURLBuffer <<
						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;

					xfer_result = LL_ERR_ASSET_REQUEST_FAILED;
				}

				if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||
						curl_msg->data.result == CURLE_OPERATION_TIMEOUTED ||
						curl_result == HTTP_SERVER_BAD_GATEWAY ||
						curl_result == HTTP_SERVER_TEMP_UNAVAILABLE))
				{
					// shared upload finished callback
					// in the base class, this is called from processUploadComplete
					_callUploadCallbacks(req->getUUID(), req->getType(), (xfer_result == 0));
					// Pending upload flag will get cleared when the request is deleted
				}
			}
			else if (RT_DOWNLOAD == req->mRequestType)
			{
				if (curl_result == HTTP_OK && curl_msg->data.result == CURLE_OK)
				{
					if (req->mVFile && req->mVFile->getSize() > 0)
					{					
						llinfos << "Success downloading " << req->mURLBuffer << ", size " << req->mVFile->getSize() << llendl;

						req->mVFile->rename(req->getUUID(), req->getType());
					}
					else
					{
						// *TODO: if this actually indicates a bad asset on the server
						// (not certain at this point), then delete it
						llwarns << "Found " << req->mURLBuffer << " to be zero size" << llendl;
						xfer_result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
					}
				}
				else
				{
					// KLW - TAT See if an avatar owns this texture, and if so request re-upload.
					llwarns << "Failure downloading " << req->mURLBuffer << 
						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << llendl;

					xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;

					if (req->mVFile)
					{
						req->mVFile->remove();
					}
				}

				// call the static callback for transfer completion
				// this will cleanup all requests for this asset, including ours
				downloadCompleteCallback(
					xfer_result,
					req->getUUID(),
					req->getType(),
					(void *)req);
				// Pending download flag will get cleared when the request is deleted
			}
			else
			{
				// nothing, just axe this request
				// currently this can only mean an asset delete
			}

			// Deleting clears the pending upload/download flag if it's set and the request is transferring
			delete req;
			req = NULL;
		}

	} while (curl_msg && queue_length > 0);
	

	// Cleanup 
	// We want to bump to the back of the line any running uploads that have timed out.
	bumpTimedOutUploads();

	LLAssetStorage::checkForTimeouts();
}
// IW - uuid is passed by value to avoid side effects, please don't re-add &    
void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority)
{
	LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL;

	LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL;

	if (user_data)
	{
		// The *user_data should not be passed without a callback to clean it up.
		llassert(callback != NULL);
	}

	if (mShutDown)
	{
		LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << LL_ENDL;

		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
		}
		return;
	}

	if (uuid.isNull())
	{
		// Special case early out for NULL uuid and for shutting down
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
		}
		return;
	}
	
	if(std::find(mBlackListedAsset.begin(),mBlackListedAsset.end(),uuid) != mBlackListedAsset.end())
	{
		LL_INFOS() << "Blacklisted asset " << uuid.asString() << " was trying to be accessed!!!!!!" << LL_ENDL; 
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
		}
		return;
	}
	
	// Try static VFS first.
	if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data))
	{
		LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL;
		return;
	}

	BOOL exists = mVFS->getExists(uuid, type);
	LLVFile file(mVFS, uuid, type);
	U32 size = exists ? file.getSize() : 0;
	
	if (size > 0)
	{
		// we've already got the file
		// theoretically, partial files w/o a pending request shouldn't happen
		// unless there's a weird error
		if (callback)
		{
			callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
		}

		LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL;
	}
	else
	{
		if (exists)
		{
			LL_WARNS() << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL;
			file.remove();
		}
		
		BOOL duplicate = FALSE;
		
		// check to see if there's a pending download of this uuid already
		for (request_list_t::iterator iter = mPendingDownloads.begin();
			 iter != mPendingDownloads.end(); ++iter )
		{
			LLAssetRequest  *tmp = *iter;
			if ((type == tmp->getType()) && (uuid == tmp->getUUID()))
			{
				if (callback == tmp->mDownCallback && user_data == tmp->mUserData)
				{
					// this is a duplicate from the same subsystem - throw it away
					LL_WARNS() << "Discarding duplicate request for asset " << uuid
							<< "." << LLAssetType::lookup(type) << LL_ENDL;
					return;
				}
				
				// this is a duplicate request
				// queue the request, but don't actually ask for it again
				duplicate = TRUE;
			}
		}
		if (duplicate)
		{
			LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid 
					<< "." << LLAssetType::lookup(type) << LL_ENDL;
		}
		
		// This can be overridden by subclasses
		_queueDataRequest(uuid, type, callback, user_data, duplicate, is_priority);	
	}

}
Example #12
0
void LLAssetStorage::downloadCompleteCallback(
	S32 result,
	const LLUUID& file_id,
	LLAssetType::EType file_type,
	void* user_data, LLExtStat ext_status)
{
	lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id
		 << "," << LLAssetType::lookup(file_type) << llendl;
	LLAssetRequest* req = (LLAssetRequest*)user_data;
	if(!req)
	{
		llwarns << "LLAssetStorage::downloadCompleteCallback called without"
			"a valid request." << llendl;
		return;
	}
	if (!gAssetStorage)
	{
		llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl;
		return;
	}

	req->setUUID(file_id);
	req->setType(file_type);
	if (LL_ERR_NOERR == result)
	{
		// we might have gotten a zero-size file
		LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType());
		if (vfile.getSize() <= 0)
		{
			llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl;
			
			result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE;
			vfile.remove();
		}
	}
	
	// find and callback ALL pending requests for this UUID
	// SJB: We process the callbacks in reverse order, I do not know if this is important,
	//      but I didn't want to mess with it.
	request_list_t requests;
	for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
		 iter != gAssetStorage->mPendingDownloads.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if ((tmp->getUUID() == req->getUUID()) && (tmp->getType()== req->getType()))
		{
			requests.push_front(tmp);
			iter = gAssetStorage->mPendingDownloads.erase(curiter);
		}
	}
	for (request_list_t::iterator iter = requests.begin();
		 iter != requests.end();  )
	{
		request_list_t::iterator curiter = iter++;
		LLAssetRequest* tmp = *curiter;
		if (tmp->mDownCallback)
		{
			tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
		}
		delete tmp;
	}
}