void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success)
{
	llassert(mStatus == LLXMLRPCTransaction::StatusStarted || mStatus == LLXMLRPCTransaction::StatusDownloading);

	AICurlEasyRequestStateMachine* state_machine = mCurlEasyRequestStateMachinePtr;
	// We're done with the statemachine, one way or another.
	// Set mCurlEasyRequestStateMachinePtr to NULL so we won't call mCurlEasyRequestStateMachinePtr->running() in the destructor.
	// Note that the state machine auto-cleaning: it will be deleted by the main-thread after this function returns.
	mCurlEasyRequestStateMachinePtr = NULL;

	if (!success)
	{
		// AICurlEasyRequestStateMachine did abort.
		// This currently only happens when libcurl didn't finish before the timer expired.
		std::ostringstream msg;
		F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeOut");
		msg << "Connection to " << mURI << " timed out (" << timeout_value << " s)!";
		if (timeout_value < 40)
		{
			msg << "\nTry increasing CurlRequestTimeOut in Debug Settings.";
		}
		setStatus(LLXMLRPCTransaction::StatusOtherError, msg.str());
		return;
	}

	AICurlEasyRequest_wat curlEasyRequest_w(*state_machine->mCurlEasyRequest);
	CURLcode result;
	curlEasyRequest_w->getResult(&result, &mTransferInfo);

	if (result != CURLE_OK)
	{
		setCurlStatus(result);
		llwarns << "LLXMLRPCTransaction CURL error "
				<< mCurlCode << ": " << curlEasyRequest_w->getErrorString() << llendl;
		llwarns << "LLXMLRPCTransaction request URI: "
				<< mURI << llendl;
			
		return;
	}
	
	setStatus(LLXMLRPCTransaction::StatusComplete);

	mResponse = XMLRPC_REQUEST_FromXML(
			mResponseText.data(), mResponseText.size(), NULL);

	bool		hasError = false;
	bool		hasFault = false;
	int			faultCode = 0;
	std::string	faultString;

	LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
	if (error.isValid())
	{
		hasError = true;
		faultCode = error["faultCode"].asInt();
		faultString = error["faultString"].asString();
	}
	else if (XMLRPC_ResponseIsFault(mResponse))
	{
		hasFault = true;
		faultCode = XMLRPC_GetResponseFaultCode(mResponse);
		faultString = XMLRPC_GetResponseFaultString(mResponse);
	}

	if (hasError || hasFault)
	{
		setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
		
		llwarns << "LLXMLRPCTransaction XMLRPC "
				<< (hasError ? "error " : "fault ")
				<< faultCode << ": "
				<< faultString << llendl;
		llwarns << "LLXMLRPCTransaction request URI: "
				<< mURI << llendl;
	}
}
bool LLXMLRPCTransaction::Impl::process()
{
	if(!mCurlRequest || !mCurlRequest->isValid())
	{
		llwarns << "transaction failed." << llendl ;

		delete mCurlRequest ;
		mCurlRequest = NULL ;
		return true ; //failed, quit.
	}

	switch(mStatus)
	{
		case LLXMLRPCTransaction::StatusComplete:
		case LLXMLRPCTransaction::StatusCURLError:
		case LLXMLRPCTransaction::StatusXMLRPCError:
		case LLXMLRPCTransaction::StatusOtherError:
		{
			return true;
		}
		
		case LLXMLRPCTransaction::StatusNotStarted:
		{
			setStatus(LLXMLRPCTransaction::StatusStarted);
			break;
		}
		
		default:
		{
			// continue onward
		}
	}
		
	if(!mCurlRequest->wait())
	{
		return false ;
	}

	while(1)
	{
		CURLcode result;
		bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
		if (newmsg)
		{
			if (result != CURLE_OK)
			{
				if ((result != CURLE_SSL_PEER_CERTIFICATE) &&
					(result != CURLE_SSL_CACERT))
				{
					// if we have a curl error that's not already been handled
					// (a non cert error), then generate the error message as
					// appropriate
					setCurlStatus(result);
				
					llwarns << "LLXMLRPCTransaction CURL error "
					<< mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
					llwarns << "LLXMLRPCTransaction request URI: "
					<< mURI << llendl;
				}
					
				return true;
			}
			
			setStatus(LLXMLRPCTransaction::StatusComplete);

			mResponse = XMLRPC_REQUEST_FromXML(
					mResponseText.data(), mResponseText.size(), NULL);

			bool		hasError = false;
			bool		hasFault = false;
			int			faultCode = 0;
			std::string	faultString;

			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
			if (error.isValid())
			{
				hasError = true;
				faultCode = error["faultCode"].asInt();
				faultString = error["faultString"].asString();
			}
			else if (XMLRPC_ResponseIsFault(mResponse))
			{
				hasFault = true;
				faultCode = XMLRPC_GetResponseFaultCode(mResponse);
				faultString = XMLRPC_GetResponseFaultString(mResponse);
			}

			if (hasError || hasFault)
			{
				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
				
				llwarns << "LLXMLRPCTransaction XMLRPC "
						<< (hasError ? "error " : "fault ")
						<< faultCode << ": "
						<< faultString << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
						<< mURI << llendl;
			}
			
			return true;
		}
		else
		{
			break; // done
		}
	}
	
	return false;
}
bool LLXMLRPCTransaction::Impl::process()
{
	switch(mStatus)
	{
		case LLXMLRPCTransaction::StatusComplete:
		case LLXMLRPCTransaction::StatusCURLError:
		case LLXMLRPCTransaction::StatusXMLRPCError:
		case LLXMLRPCTransaction::StatusOtherError:
		{
			return true;
		}
		
		case LLXMLRPCTransaction::StatusNotStarted:
		{
			setStatus(LLXMLRPCTransaction::StatusStarted);
			break;
		}
		
		default:
		{
			// continue onward
		}
	}
	
	const F32 MAX_PROCESSING_TIME = 0.05f;
	LLTimer timer;
	int count;
	
	while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(mCurlMulti, &count))
	{
		if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME)
		{
			return false;
		}
	}
			 
	while(CURLMsg* curl_msg = curl_multi_info_read(mCurlMulti, &count))
	{
		if (CURLMSG_DONE == curl_msg->msg)
		{
			if (curl_msg->data.result != CURLE_OK)
			{
				setCurlStatus(curl_msg->data.result);
				llwarns << "LLXMLRPCTransaction CURL error "
					<< mCurlCode << ": " << mCurlErrorBuffer << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
					<< mURI << llendl;
					
				return true;
			}
			
			setStatus(LLXMLRPCTransaction::StatusComplete);

			mResponse = XMLRPC_REQUEST_FromXML(
				mResponseText.data(), mResponseText.size(), NULL);

			bool		hasError = false;
			bool		hasFault = false;
			int			faultCode = 0;
			std::string	faultString;

			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
			if (error.isValid())
			{
				hasError = true;
				faultCode = error["faultCode"].asInt();
				faultString = error["faultString"].asString();
			}
			else if (XMLRPC_ResponseIsFault(mResponse))
			{
				hasFault = true;
				faultCode = XMLRPC_GetResponseFaultCode(mResponse);
				faultString = XMLRPC_GetResponseFaultString(mResponse);
			}

			if (hasError || hasFault)
			{
				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
				
				llwarns << "LLXMLRPCTransaction XMLRPC "
					<< (hasError ? "error " : "fault ")
					<< faultCode << ": "
					<< faultString << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
					<< mURI << llendl;
			}
			
			return true;
		}
	}
	
	return false;
}
bool LLXMLRPCTransaction::Impl::process()
{
	switch(mStatus)
	{
		case LLXMLRPCTransaction::StatusComplete:
		case LLXMLRPCTransaction::StatusCURLError:
		case LLXMLRPCTransaction::StatusXMLRPCError:
		case LLXMLRPCTransaction::StatusOtherError:
		{
			return true;
		}
		
		case LLXMLRPCTransaction::StatusNotStarted:
		{
			setStatus(LLXMLRPCTransaction::StatusStarted);
			break;
		}
		
		default:
		{
			// continue onward
		}
	}
	
	const F32 MAX_PROCESSING_TIME = 0.05f;
	LLTimer timer;

	while (mCurlRequest->perform() > 0)
	{
		if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME)
		{
			return false;
		}
	}

	while(1)
	{
		CURLcode result;
		bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
		if (newmsg)
		{
			if (result != CURLE_OK)
			{
				setCurlStatus(result);
				llwarns << "LLXMLRPCTransaction CURL error "
						<< mCurlCode << ": " << mCurlRequest->getErrorString() << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
						<< mURI << llendl;
					
				return true;
			}
			
			setStatus(LLXMLRPCTransaction::StatusComplete);

			mResponse = XMLRPC_REQUEST_FromXML(
					mResponseText.data(), mResponseText.size(), NULL);

			bool		hasError = false;
			bool		hasFault = false;
			int			faultCode = 0;
			std::string	faultString;

			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
			if (error.isValid())
			{
				hasError = true;
				faultCode = error["faultCode"].asInt();
				faultString = error["faultString"].asString();
			}
			else if (XMLRPC_ResponseIsFault(mResponse))
			{
				hasFault = true;
				faultCode = XMLRPC_GetResponseFaultCode(mResponse);
				faultString = XMLRPC_GetResponseFaultString(mResponse);
			}

			if (hasError || hasFault)
			{
				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
				
				llwarns << "LLXMLRPCTransaction XMLRPC "
						<< (hasError ? "error " : "fault ")
						<< faultCode << ": "
						<< faultString << llendl;
				llwarns << "LLXMLRPCTransaction request URI: "
						<< mURI << llendl;
			}
			
			return true;
		}
		else
		{
			break; // done
		}
	}
	
	return false;
}