Exemplo n.º 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());
		}
	}
}
Exemplo n.º 2
0
// virtual
bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
											LLAssetType::EType asset_type,
											const LLUUID& asset_id)
{
	request_list_t* requests = getRequestList(rt);
	if (deletePendingRequest(requests, asset_type, asset_id))
	{
		llinfos << "Asset " << getRequestName(rt) << " request for "
				<< asset_id << "." << LLAssetType::lookup(asset_type)
				<< " removed from pending queue." << llendl;
		return true;
	}
	return false;
}
Exemplo n.º 3
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();
}