Commits

Monty Brandenberg committed 6d8b87d

Big comment and naming cleanup. Ready for prime-time.
Add to-do list to _httpinternal.h to guide anyone who
wants to pitch in and help.

Comments (0)

Files changed (20)

indra/llcorehttp/_httpinternal.h

 // something wrong is probably happening.
 
 
+// --------------------------------------------------------------------
+// General library to-do list
+//
+// - Implement policy classes.  Structure is mostly there just didn't
+//   need it for the first consumer.
+// - Consider Removing 'priority' from the request interface.  Its use
+//   in an always active class can lead to starvation of low-priority
+//   requests.  Requires coodination of priority values across all
+//   components that share a class.  Changing priority across threads
+//   is slightly expensive (relative to gain) and hasn't been completely
+//   implemented.  And the major user of priority, texture fetches,
+//   may not really need it.
+// - Set/get for global policy and policy classes is clumsy.  Rework
+//   it heading in a direction that allows for more dynamic behavior.
+// - Move HttpOpRequest::prepareRequest() to HttpLibcurl for the
+//   pedantic.
+// - Update downloader and other long-duration services are going to
+//   need a progress notification.  Initial idea is to introduce a
+//   'repeating request' which can piggyback on another request and
+//   persist until canceled or carrier completes.  Current queue
+//   structures allow an HttpOperation object to be enqueued
+//   repeatedly, so...
+// - Investigate making c-ares' re-implementation of a resolver library
+//   more resilient or more intelligent on Mac.  Part of the DNS failure
+//   lies in here.  The mechanism also looks a little less dynamic
+//   than needed in an environments where networking is changing.
+// - Global optimizations:  'borrowing' connections from other classes,
+//   HTTP pipelining.
+// - Dynamic/control system stuff:  detect problems and self-adjust.
+//   This won't help in the face of the router problems we've looked
+//   at, however.  Detect starvation due to UDP activity and provide
+//   feedback to it.
+//
+// Integration to-do list
+// - LLTextureFetch still needs a major refactor.  The use of
+//   LLQueuedThread makes it hard to inspect workers and do the
+//   resource waiting we're now doing.  Rebuild along simpler lines
+//   some of which are suggested in new commentary at the top of
+//   the main source file.
+// - Expand areas of usage eventually leading to the removal of LLCurl.
+//   Rough order of expansion:
+//   .  Mesh fetch
+//   .  Avatar names
+//   .  Group membership lists
+//   .  Caps access in general
+//   .  'The rest'
+// - Adapt texture cache, image decode and other image consumers to
+//   the BufferArray model to reduce data copying.  Alternatively,
+//   adapt this library to something else.
+//
+// --------------------------------------------------------------------
+
+
 // If '1', internal ready queues will not order ready
 // requests by priority, instead it's first-come-first-served.
 // Reprioritization requests have the side-effect of then
 // putting the modified request at the back of the ready queue.
 
-#define	LLCORE_READY_QUEUE_IGNORES_PRIORITY		1
+#define	LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY		1
 
 
 namespace LLCore
 
 // Maxium number of policy classes that can be defined.
 // *TODO:  Currently limited to the default class, extend.
-const int POLICY_CLASS_LIMIT = 1;
+const int HTTP_POLICY_CLASS_LIMIT = 1;
 
 // Debug/informational tracing.  Used both
 // as a global option and in per-request traces.
-const int TRACE_OFF = 0;
-const int TRACE_LOW = 1;
-const int TRACE_CURL_HEADERS = 2;
-const int TRACE_CURL_BODIES = 3;
+const int HTTP_TRACE_OFF = 0;
+const int HTTP_TRACE_LOW = 1;
+const int HTTP_TRACE_CURL_HEADERS = 2;
+const int HTTP_TRACE_CURL_BODIES = 3;
 
-const int TRACE_MIN = TRACE_OFF;
-const int TRACE_MAX = TRACE_CURL_BODIES;
+const int HTTP_TRACE_MIN = HTTP_TRACE_OFF;
+const int HTTP_TRACE_MAX = HTTP_TRACE_CURL_BODIES;
 
 // Request retry limits
-const int DEFAULT_RETRY_COUNT = 5;
-const int LIMIT_RETRY_MIN = 0;
-const int LIMIT_RETRY_MAX = 100;
+const int HTTP_RETRY_COUNT_DEFAULT = 5;
+const int HTTP_RETRY_COUNT_MIN = 0;
+const int HTTP_RETRY_COUNT_MAX = 100;
 
-const int DEFAULT_HTTP_REDIRECTS = 10;
+const int HTTP_REDIRECTS_DEFAULT = 10;
 
 // Timeout value used for both connect and protocol exchange.
 // Retries and time-on-queue are not included and aren't
 // accounted for.
-const long DEFAULT_TIMEOUT = 30L;
-const long LIMIT_TIMEOUT_MIN = 0L;
-const long LIMIT_TIMEOUT_MAX = 3600L;
+const long HTTP_REQUEST_TIMEOUT_DEFAULT = 30L;
+const long HTTP_REQUEST_TIMEOUT_MIN = 0L;
+const long HTTP_REQUEST_TIMEOUT_MAX = 3600L;
 
 // Limits on connection counts
-const int DEFAULT_CONNECTIONS = 8;
-const int LIMIT_CONNECTIONS_MIN = 1;
-const int LIMIT_CONNECTIONS_MAX = 256;
+const int HTTP_CONNECTION_LIMIT_DEFAULT = 8;
+const int HTTP_CONNECTION_LIMIT_MIN = 1;
+const int HTTP_CONNECTION_LIMIT_MAX = 256;
 
 // Tuning parameters
 
 // Time worker thread sleeps after a pass through the
 // request, ready and active queues.
-const int LOOP_SLEEP_NORMAL_MS = 2;
+const int HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS = 2;
 
 // Block allocation size (a tuning parameter) is found
 // in bufferarray.h.
 
 // Compatibility controls
-const bool ENABLE_LINKSYS_WRT54G_V5_DNS_FIX = true;
+const bool HTTP_ENABLE_LINKSYS_WRT54G_V5_DNS_FIX = true;
 
 }  // end namespace LLCore
 

indra/llcorehttp/_httplibcurl.cpp

 
 void HttpLibcurl::start(int policy_count)
 {
-	llassert_always(policy_count <= POLICY_CLASS_LIMIT);
+	llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);
 	llassert_always(! mMultiHandles);					// One-time call only
 	
 	mPolicyCount = policy_count;
 }
 
 
+// Caller has provided us with a ref count on op.
 void HttpLibcurl::addOp(HttpOpRequest * op)
 {
 	llassert_always(op->mReqPolicy < mPolicyCount);
 	if (! op->prepareRequest(mService))
 	{
 		// Couldn't issue request, fail with notification
-		// *FIXME:  Need failure path
+		// *TODO:  Need failure path
 		return;
 	}
 
 	curl_multi_add_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle);
 	op->mCurlActive = true;
 	
-	if (op->mTracing > TRACE_OFF)
+	if (op->mTracing > HTTP_TRACE_OFF)
 	{
 		HttpPolicy & policy(mService->getPolicy());
 		
 
 // *NOTE:  cancelRequest logic parallels completeRequest logic.
 // Keep them synchronized as necessary.  Caller is expected to
-// remove to op from the active list and release the op *after*
+// remove the op from the active list and release the op *after*
 // calling this method.  It must be called first to deliver the
 // op to the reply queue with refcount intact.
 void HttpLibcurl::cancelRequest(HttpOpRequest * op)
 	op->mCurlHandle = NULL;
 
 	// Tracing
-	if (op->mTracing > TRACE_OFF)
+	if (op->mTracing > HTTP_TRACE_OFF)
 	{
 		LL_INFOS("CoreHttp") << "TRACE, RequestCanceled, Handle:  "
 							 << static_cast<HttpHandle>(op)
 	op->mCurlHandle = NULL;
 
 	// Tracing
-	if (op->mTracing > TRACE_OFF)
+	if (op->mTracing > HTTP_TRACE_OFF)
 	{
 		LL_INFOS("CoreHttp") << "TRACE, RequestComplete, Handle:  "
 							 << static_cast<HttpHandle>(op)

indra/llcorehttp/_httplibcurl.h

 	/// Give cycles to libcurl to run active requests.  Completed
 	/// operations (successful or failed) will be retried or handed
 	/// over to the reply queue as final responses.
+	///
+	/// @return			Indication of how long this method is
+	///					willing to wait for next service call.
 	HttpService::ELoopSpeed processTransport();
 
 	/// Add request to the active list.  Caller is expected to have
-	/// provided us with a reference count to hold the request.  (No
-	/// additional references will be added.)
+	/// provided us with a reference count on the op to hold the
+	/// request.  (No additional references will be added.)
 	void addOp(HttpOpRequest * op);
 
 	/// One-time call to set the number of policy classes to be
 	/// serviced and to create the resources for each.  Value
 	/// must agree with HttpPolicy::setPolicies() call.
 	void start(int policy_count);
-	
+
+	/// Synchronously stop libcurl operations.  All active requests
+	/// are canceled and removed from libcurl's handling.  Easy
+	/// handles are detached from their multi handles and released.
+	/// Multi handles are also released.  Canceled requests are
+	/// completed with canceled status and made available on their
+	/// respective reply queues.
+	///
+	/// Can be restarted with a start() call.
 	void shutdown();
-	
+
+	/// Return global and per-class counts of active requests.
 	int getActiveCount() const;
 	int getActiveCountInClass(int policy_class) const;
 
-	// Shadows HttpService's method
+	/// Attempt to cancel a request identified by handle.
+	///
+	/// Interface shadows HttpService's method.
+	///
+	/// @return			True if handle was found and operation canceled.
+	///
 	bool cancel(HttpHandle handle);
 
 protected:

indra/llcorehttp/_httpopcancel.cpp

 
 #include "_httpopcancel.h"
 
-#include <cstdio>
-#include <algorithm>
-
 #include "httpcommon.h"
 #include "httphandler.h"
 #include "httpresponse.h"
 
-#include "_httprequestqueue.h"
-#include "_httpreplyqueue.h"
 #include "_httpservice.h"
-#include "_httppolicy.h"
-#include "_httplibcurl.h"
 
 
 namespace LLCore

indra/llcorehttp/_httpopcancel.h

 /// be canceled, if possible.  This includes active requests
 /// that may be in the middle of an HTTP transaction.  Any
 /// completed request will not be canceled and will return
-/// its final status unchanged.
+/// its final status unchanged and *this* request will complete
+/// with an HE_HANDLE_NOT_FOUND error status.
 
 class HttpOpCancel : public HttpOperation
 {
 public:
+	/// @param	handle	Handle of previously-issued request to
+	///					be canceled.
 	HttpOpCancel(HttpHandle handle);
 
 protected:

indra/llcorehttp/_httpoperation.cpp

 	// Default implementation should never be called.  This
 	// indicates an operation making a transition that isn't
 	// defined.
-	LL_ERRS("HttpCore") << "Default stateFromRequest method may not be called."
+	LL_ERRS("HttpCore") << "Default stageFromRequest method may not be called."
 						<< LL_ENDL;
 }
 
 	// Default implementation should never be called.  This
 	// indicates an operation making a transition that isn't
 	// defined.
-	LL_ERRS("HttpCore") << "Default stateFromReady method may not be called."
+	LL_ERRS("HttpCore") << "Default stageFromReady method may not be called."
 						<< LL_ENDL;
 }
 
 	// Default implementation should never be called.  This
 	// indicates an operation making a transition that isn't
 	// defined.
-	LL_ERRS("HttpCore") << "Default stateFromActive method may not be called."
+	LL_ERRS("HttpCore") << "Default stageFromActive method may not be called."
 						<< LL_ENDL;
 }
 
 
 void HttpOperation::addAsReply()
 {
-	if (mTracing > TRACE_OFF)
+	if (mTracing > HTTP_TRACE_OFF)
 	{
 		LL_INFOS("CoreHttp") << "TRACE, ToReplyQueue, Handle:  "
 							 << static_cast<HttpHandle>(this)

indra/llcorehttp/_httpoperation.h

 class HttpOperation : public LLCoreInt::RefCounted
 {
 public:
+	/// Threading:  called by a consumer/application thread.
 	HttpOperation();
 
 protected:
+	/// Threading:  called by any thread.
 	virtual ~HttpOperation();							// Use release()
 
 private:
 	void operator=(const HttpOperation &);				// Not defined
 
 public:
+	/// Register a reply queue and a handler for completion notifications.
+	///
+	/// Invokers of operations that want to receive notification that an
+	/// operation has been completed do so by binding a reply queue and
+	/// a handler object to the request.
+	///
+	/// @param	reply_queue		Pointer to the reply queue where completion
+	///							notifications are to be queued (typically
+	///							by addAsReply()).  This will typically be
+	///							the reply queue referenced by the request
+	///							object.  This method will increment the
+	///							refcount on the queue holding the queue
+	///							until delivery is complete.  Using a reply_queue
+	///							even if the handler is NULL has some benefits
+	///							for memory deallocation by keeping it in the
+	///							originating thread.
+	///
+	/// @param	handler			Possibly NULL pointer to a non-refcounted
+	////						handler object to be invoked (onCompleted)
+	///							when the operation is finished.  Note that
+	///							the handler object is never dereferenced
+	///							by the worker thread.  This is passible data
+	///							until notification is performed.
+	///
+	/// Threading:  called by application thread.
+	///
 	void setReplyPath(HttpReplyQueue * reply_queue,
 					  HttpHandler * handler);
 
-	HttpHandler * getUserHandler() const
-		{
-			return mUserHandler;
-		}
-	
+	/// The three possible staging steps in an operation's lifecycle.
+	/// Asynchronous requests like HTTP operations move from the
+	/// request queue to the ready queue via stageFromRequest.  Then
+	/// from the ready queue to the active queue by stageFromReady.  And
+	/// when complete, to the reply queue via stageFromActive and the
+	/// addAsReply utility.
+	///
+	/// Immediate mode operations (everything else) move from the
+	/// request queue to the reply queue directly via stageFromRequest
+	/// and addAsReply with no existence on the ready or active queues.
+	///
+	/// These methods will take out a reference count on the request,
+	/// caller only needs to dispose of its reference when done with
+	/// the request. 
+	///
+	/// Threading:  called by worker thread.
+	///
 	virtual void stageFromRequest(HttpService *);
 	virtual void stageFromReady(HttpService *);
 	virtual void stageFromActive(HttpService *);
 
+	/// Delivers a notification to a handler object on completion.
+	///
+	/// Once a request is complete and it has been removed from its
+	/// reply queue, a handler notification may be delivered by a
+	/// call to HttpRequest::update().  This method does the necessary
+	/// dispatching.
+	///
+	/// Threading:  called by application thread.
+	///
 	virtual void visitNotifier(HttpRequest *);
-	
+
+	/// Cancels the operation whether queued or active.
+	/// Final status of the request becomes canceled (an error) and
+	/// that will be delivered to caller via notification scheme.
+	///
+	/// Threading:  called by worker thread.
+	///
 	virtual HttpStatus cancel();
 	
 protected:
+	/// Delivers request to reply queue on completion.  After this
+	/// call, worker thread no longer accesses the object and it
+	/// is owned by the reply queue.
+	///
+	/// Threading:  called by worker thread.
+	///
 	void addAsReply();
 	
 protected:
 	HttpReplyQueue *			mReplyQueue;			// Have refcount
-	HttpHandler *				mUserHandler;
+	HttpHandler *				mUserHandler;			// Naked pointer
 
 public:
 	// Request Data
 
 /// HttpOpSpin is a test-only request that puts the worker
 /// thread into a cpu spin.  Used for unit tests and cleanup
-/// evaluation.  You do not want to use this.
+/// evaluation.  You do not want to use this in production.
 class HttpOpSpin : public HttpOperation
 {
 public:

indra/llcorehttp/_httpoprequest.cpp

 	  mReplyHeaders(NULL),
 	  mPolicyRetries(0),
 	  mPolicyRetryAt(HttpTime(0)),
-	  mPolicyRetryLimit(DEFAULT_RETRY_COUNT)
+	  mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT)
 {
 	// *NOTE:  As members are added, retry initialization/cleanup
-	// may need to be extended in @prepareRequest().
+	// may need to be extended in @see prepareRequest().
 }
 
 
 		mCurlHeaders = NULL;
 	}
 
-	mReplyOffset = 0;
-	mReplyLength = 0;
-	mReplyFullLength = 0;
 	if (mReplyBody)
 	{
 		mReplyBody->release();
 
 void HttpOpRequest::visitNotifier(HttpRequest * request)
 {
-	static const HttpStatus partial_content(HTTP_PARTIAL_CONTENT, HE_SUCCESS);
-	
 	if (mUserHandler)
 	{
 		HttpResponse * response = new HttpResponse();
 			mProcFlags |= PF_SAVE_HEADERS;
 		}
 		mPolicyRetryLimit = options->getRetries();
-		mPolicyRetryLimit = llclamp(mPolicyRetryLimit, LIMIT_RETRY_MIN, LIMIT_RETRY_MAX);
-		mTracing = (std::max)(mTracing, llclamp(options->getTrace(), TRACE_MIN, TRACE_MAX));
+		mPolicyRetryLimit = llclamp(mPolicyRetryLimit, HTTP_RETRY_COUNT_MIN, HTTP_RETRY_COUNT_MAX);
+		mTracing = (std::max)(mTracing, llclamp(options->getTrace(), HTTP_TRACE_MIN, HTTP_TRACE_MAX));
 	}
 }
 
 	curl_easy_setopt(mCurlHandle, CURLOPT_PRIVATE, this);
 	curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
 
-	if (ENABLE_LINKSYS_WRT54G_V5_DNS_FIX)
+	if (HTTP_ENABLE_LINKSYS_WRT54G_V5_DNS_FIX)
 	{
 		// The Linksys WRT54G V5 router has an issue with frequent
 		// DNS lookups from LAN machines.  If they happen too often,
 		// about 700 or so requests and starts issuing TCP RSTs to
 		// new connections.  Reuse the DNS lookups for even a few
 		// seconds and no RSTs.
-		curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 10);
+		curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
 	}
 	else
 	{
 	}
 	curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
 	curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1);
-	curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, DEFAULT_HTTP_REDIRECTS);
+	curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
 	curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
 	curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, this);
 	curl_easy_setopt(mCurlHandle, CURLOPT_READFUNCTION, readCallback);
 	}
 	else if (policy.get(HttpRequest::GP_HTTP_PROXY, &opt_value))
 	{
-		// *TODO:  This is fine for now but get fuller socks/
+		// *TODO:  This is fine for now but get fuller socks5/
 		// authentication thing going later....
 		curl_easy_setopt(mCurlHandle, CURLOPT_PROXY, opt_value->c_str());
 		curl_easy_setopt(mCurlHandle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
 	}
 
 	// Tracing
-	if (mTracing >= TRACE_CURL_HEADERS)
+	if (mTracing >= HTTP_TRACE_CURL_HEADERS)
 	{
 		curl_easy_setopt(mCurlHandle, CURLOPT_VERBOSE, 1);
 		curl_easy_setopt(mCurlHandle, CURLOPT_DEBUGDATA, this);
 	mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:");
 
 	// Request options
-	long timeout(DEFAULT_TIMEOUT);
+	long timeout(HTTP_REQUEST_TIMEOUT_DEFAULT);
 	if (mReqOptions)
 	{
 		timeout = mReqOptions->getTimeout();
-		timeout = llclamp(timeout, LIMIT_TIMEOUT_MIN, LIMIT_TIMEOUT_MAX);
+		timeout = llclamp(timeout, HTTP_REQUEST_TIMEOUT_MIN, HTTP_REQUEST_TIMEOUT_MAX);
 	}
 	curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, timeout);
 	curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, timeout);
 	static const char con_ran_line[] = "content-range:";
 	static const size_t con_ran_line_len = sizeof(con_ran_line) - 1;
 
-	static const char con_type_line[] = "content-type:";
-	static const size_t con_type_line_len = sizeof(con_type_line) - 1;
-	
-	static const char con_enc_line[] = "content-encoding:";
-	static const size_t con_enc_line_len = sizeof(con_enc_line) - 1;
-	
 	HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
 
 	const size_t hdr_size(size * nmemb);
 	switch (info)
 	{
 	case CURLINFO_TEXT:
-		if (op->mTracing >= TRACE_CURL_HEADERS)
+		if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
 		{
 			tag = "TEXT";
 			escape_libcurl_debug_data(buffer, len, true, safe_line);
 		break;
 			
 	case CURLINFO_HEADER_IN:
-		if (op->mTracing >= TRACE_CURL_HEADERS)
+		if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
 		{
 			tag = "HEADERIN";
 			escape_libcurl_debug_data(buffer, len, true, safe_line);
 		break;
 			
 	case CURLINFO_HEADER_OUT:
-		if (op->mTracing >= TRACE_CURL_HEADERS)
+		if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
 		{
 			tag = "HEADEROUT";
 			escape_libcurl_debug_data(buffer, 2 * len, true, safe_line);		// Goes out as one line
 		break;
 			
 	case CURLINFO_DATA_IN:
-		if (op->mTracing >= TRACE_CURL_HEADERS)
+		if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
 		{
 			tag = "DATAIN";
 			logit = true;
-			if (op->mTracing >= TRACE_CURL_BODIES)
+			if (op->mTracing >= HTTP_TRACE_CURL_BODIES)
 			{
 				escape_libcurl_debug_data(buffer, len, false, safe_line);
 			}
 		break;
 			
 	case CURLINFO_DATA_OUT:
-		if (op->mTracing >= TRACE_CURL_HEADERS)
+		if (op->mTracing >= HTTP_TRACE_CURL_HEADERS)
 		{
 			tag = "DATAOUT";
 			logit = true;
-			if (op->mTracing >= TRACE_CURL_BODIES)
+			if (op->mTracing >= HTTP_TRACE_CURL_BODIES)
 			{
 				escape_libcurl_debug_data(buffer, len, false, safe_line);
 			}

indra/llcorehttp/_httpoprequest.h

 	virtual void visitNotifier(HttpRequest * request);
 			
 public:
-	// Setup Methods
+	/// Setup Methods
+	///
+	/// Basically an RPC setup for each type of HTTP method
+	/// invocation with one per method type.  These are
+	/// generally invoked right after construction.
+	///
+	/// Threading:  called by application thread
+	///
 	HttpStatus setupGet(HttpRequest::policy_t policy_id,
 						HttpRequest::priority_t priority,
 						const std::string & url,
 						BufferArray * body,
 						HttpOptions * options,
 						HttpHeaders * headers);
-	
+
+	// Internal method used to setup the libcurl options for a request.
+	// Does all the libcurl handle setup in one place.
+	//
+	// Threading:  called by worker thread
+	//
 	HttpStatus prepareRequest(HttpService * service);
 	
 	virtual HttpStatus cancel();
 
 protected:
+	// Common setup for all the request methods.
+	//
+	// Threading:  called by application thread
+	//
 	void setupCommon(HttpRequest::policy_t policy_id,
 					 HttpRequest::priority_t priority,
 					 const std::string & url,
 					 BufferArray * body,
 					 HttpOptions * options,
 					 HttpHeaders * headers);
-	
+
+	// libcurl operational callbacks
+	//
+	// Threading:  called by worker thread
+	//
 	static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata);
 	static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata);
 	static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata);

indra/llcorehttp/_httpopsetget.cpp

 
 #include "_httpopsetget.h"
 
-#include <cstdio>
-#include <algorithm>
+#include "httpcommon.h"
 
-#include "httpcommon.h"
-#include "httphandler.h"
-#include "httpresponse.h"
-
-#include "_httprequestqueue.h"
-#include "_httpreplyqueue.h"
 #include "_httpservice.h"
 #include "_httppolicy.h"
-#include "_httplibcurl.h"
 
 
 namespace LLCore

indra/llcorehttp/_httpopsetget.h

 
 /// HttpOpSetGet requests dynamic changes to policy and
 /// configuration settings.
+///
+/// *NOTE:  Expect this to change.  Don't really like it yet.
 
 class HttpOpSetGet : public HttpOperation
 {
 	void operator=(const HttpOpSetGet &);				// Not defined
 
 public:
+	/// Threading:  called by application thread
 	void setupGet(HttpRequest::EGlobalPolicy setting);
 	void setupSet(HttpRequest::EGlobalPolicy setting, const std::string & value);
 

indra/llcorehttp/_httppolicy.cpp

 {
 
 
+// Per-policy-class data for a running system.
+// Collection of queues, parameters, history, metrics, etc.
+// for a single policy class.
+//
+// Threading:  accessed only by worker thread
 struct HttpPolicy::State
 {
 public:
 	State()
-		: mConnMax(DEFAULT_CONNECTIONS),
-		  mConnAt(DEFAULT_CONNECTIONS),
+		: mConnMax(HTTP_CONNECTION_LIMIT_DEFAULT),
+		  mConnAt(HTTP_CONNECTION_LIMIT_DEFAULT),
 		  mConnMin(1),
 		  mNextSample(0),
 		  mErrorCount(0),
 	return false;
 }
 
+
 bool HttpPolicy::stageAfterCompletion(HttpOpRequest * op)
 {
 	static const HttpStatus cant_connect(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
 }
 
 
-int HttpPolicy::getReadyCount(HttpRequest::policy_t policy_class)
+int HttpPolicy::getReadyCount(HttpRequest::policy_t policy_class) const
 {
 	if (policy_class < mActiveClasses)
 	{

indra/llcorehttp/_httppolicy.h

 	/// Cancel all ready and retry requests sending them to
 	/// their notification queues.  Release state resources
 	/// making further request handling impossible.
+	///
+	/// Threading:  called by worker thread
 	void shutdown();
 
 	/// Deliver policy definitions and enable handling of
 	/// requests.  One-time call invoked before starting
 	/// the worker thread.
+	///
+	/// Threading:  called by application thread
 	void start(const HttpPolicyGlobal & global,
 			   const std::vector<HttpPolicyClass> & classes);
 
 	/// Give the policy layer some cycles to scan the ready
 	/// queue promoting higher-priority requests to active
 	/// as permited.
+	///
+	/// @return			Indication of how soon this method
+	///					should be called again.
+	///
+	/// Threading:  called by worker thread
 	HttpService::ELoopSpeed processReadyQueue();
 
 	/// Add request to a ready queue.  Caller is expected to have
 	/// provided us with a reference count to hold the request.  (No
 	/// additional references will be added.)
+	///
+	/// OpRequest is owned by the request queue after this call
+	/// and should not be modified by anyone until retrieved
+	/// from queue.
+	///
+	/// Threading:  called by any thread
 	void addOp(HttpOpRequest *);
 
 	/// Similar to addOp, used when a caller wants to retry a
 	/// handling is the same and retried operations are considered
 	/// before new ones but that doesn't guarantee completion
 	/// order.
+	///
+	/// Threading:  called by worker thread
 	void retryOp(HttpOpRequest *);
 
-	// Shadows HttpService's method
+	/// Attempt to change the priority of an earlier request.
+	/// Request that Shadows HttpService's method
+	///
+	/// Threading:  called by worker thread
 	bool changePriority(HttpHandle handle, HttpRequest::priority_t priority);
 
-	// Shadows HttpService's method as well
+	/// Attempt to cancel a previous request.
+	/// Shadows HttpService's method as well
+	///
+	/// Threading:  called by worker thread
 	bool cancel(HttpHandle handle);
 
 	/// When transport is finished with an op and takes it off the
 	/// @return			Returns true of the request is still active
 	///					or ready after staging, false if has been
 	///					sent on to the reply queue.
+	///
+	/// Threading:  called by worker thread
 	bool stageAfterCompletion(HttpOpRequest * op);
 	
 	// Get pointer to global policy options.  Caller is expected
 	// to do context checks like no setting once running.
+	///
+	/// Threading:  called by any thread *but* the object may
+	/// only be modified by the worker thread once running.
+	///
 	HttpPolicyGlobal & getGlobalOptions()
 		{
 			return mGlobalOptions;
 		}
 
-	// Get ready counts for a particular class
-	int getReadyCount(HttpRequest::policy_t policy_class);
+	/// Get ready counts for a particular policy class
+	///
+	/// Threading:  called by worker thread
+	int getReadyCount(HttpRequest::policy_t policy_class) const;
 	
 protected:
 	struct State;

indra/llcorehttp/_httppolicyclass.cpp

 
 HttpPolicyClass::HttpPolicyClass()
 	: mSetMask(0UL),
-	  mConnectionLimit(DEFAULT_CONNECTIONS),
-	  mPerHostConnectionLimit(DEFAULT_CONNECTIONS),
+	  mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
+	  mPerHostConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
 	  mPipelining(0)
 {}
 
 	switch (opt)
 	{
 	case HttpRequest::CP_CONNECTION_LIMIT:
-		mConnectionLimit = llclamp(value, long(LIMIT_CONNECTIONS_MIN), long(LIMIT_CONNECTIONS_MAX));
+		mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX));
 		break;
 
 	case HttpRequest::CP_PER_HOST_CONNECTION_LIMIT:
-		mPerHostConnectionLimit = llclamp(value, long(LIMIT_CONNECTIONS_MIN), mConnectionLimit);
+		mPerHostConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), mConnectionLimit);
 		break;
 
 	case HttpRequest::CP_ENABLE_PIPELINING:

indra/llcorehttp/_httppolicyglobal.cpp

 
 HttpPolicyGlobal::HttpPolicyGlobal()
 	: mSetMask(0UL),
-	  mConnectionLimit(DEFAULT_CONNECTIONS),
-	  mTrace(TRACE_OFF),
+	  mConnectionLimit(HTTP_CONNECTION_LIMIT_DEFAULT),
+	  mTrace(HTTP_TRACE_OFF),
 	  mUseLLProxy(0)
 {}
 
 	switch (opt)
 	{
 	case HttpRequest::GP_CONNECTION_LIMIT:
-		mConnectionLimit = llclamp(value, long(LIMIT_CONNECTIONS_MIN), long(LIMIT_CONNECTIONS_MAX));
+		mConnectionLimit = llclamp(value, long(HTTP_CONNECTION_LIMIT_MIN), long(HTTP_CONNECTION_LIMIT_MAX));
 		break;
 
 	case HttpRequest::GP_TRACE:
-		mTrace = llclamp(value, long(TRACE_MIN), long(TRACE_MAX));
+		mTrace = llclamp(value, long(HTTP_TRACE_MIN), long(HTTP_TRACE_MAX));
 		break;
 
 	case HttpRequest::GP_LLPROXY:

indra/llcorehttp/_httpreadyqueue.h

 /// important of those rules is that any iterator becomes invalid
 /// on element erasure.  So pay attention.
 ///
-/// If LLCORE_READY_QUEUE_IGNORES_PRIORITY tests true, the class
+/// If LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY tests true, the class
 /// implements a std::priority_queue interface but on std::deque
 /// behavior to eliminate sensitivity to priority.  In the future,
 /// this will likely become the only behavior or it may become
 /// Threading:  not thread-safe.  Expected to be used entirely by
 /// a single thread, typically a worker thread of some sort.
 
-#if LLCORE_READY_QUEUE_IGNORES_PRIORITY
+#if LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY
 
 typedef std::deque<HttpOpRequest *> HttpReadyQueueBase;
 
 							std::deque<HttpOpRequest *>,
 							LLCore::HttpOpRequestCompare> HttpReadyQueueBase;
 
-#endif // LLCORE_READY_QUEUE_IGNORES_PRIORITY
+#endif // LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY
 
 class HttpReadyQueue : public HttpReadyQueueBase
 {
 
 public:
 
-#if LLCORE_READY_QUEUE_IGNORES_PRIORITY
+#if LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY
 	// Types and methods needed to make a std::deque look
 	// more like a std::priority_queue, at least for our
 	// purposes.
 			push_back(v);
 		}
 	
-#endif // LLCORE_READY_QUEUE_IGNORES_PRIORITY
+#endif // LLCORE_HTTP_READY_QUEUE_IGNORES_PRIORITY
 	
 	const container_type & get_container() const
 		{

indra/llcorehttp/_httpservice.cpp

 {
 	// Create the default policy class
 	HttpPolicyClass pol_class;
-	pol_class.set(HttpRequest::CP_CONNECTION_LIMIT, DEFAULT_CONNECTIONS);
-	pol_class.set(HttpRequest::CP_PER_HOST_CONNECTION_LIMIT, DEFAULT_CONNECTIONS);
+	pol_class.set(HttpRequest::CP_CONNECTION_LIMIT, HTTP_CONNECTION_LIMIT_DEFAULT);
+	pol_class.set(HttpRequest::CP_PER_HOST_CONNECTION_LIMIT, HTTP_CONNECTION_LIMIT_DEFAULT);
 	pol_class.set(HttpRequest::CP_ENABLE_PIPELINING, 0L);
 	mPolicyClasses.push_back(pol_class);
 }
 HttpRequest::policy_t HttpService::createPolicyClass()
 {
 	const HttpRequest::policy_t policy_class(mPolicyClasses.size());
-	if (policy_class >= POLICY_CLASS_LIMIT)
+	if (policy_class >= HTTP_POLICY_CLASS_LIMIT)
 	{
 		return 0;
 	}
 }
 
 
-	/// Try to find the given request handle on any of the request
-	/// queues and cancel the operation.
-	///
-	/// @return			True if the request was canceled.
-	///
-	/// Threading:  callable by worker thread.
+/// Try to find the given request handle on any of the request
+/// queues and cancel the operation.
+///
+/// @return			True if the request was canceled.
+///
+/// Threading:  callable by worker thread.
 bool HttpService::cancel(HttpHandle handle)
 {
 	bool canceled(false);
 		// Determine whether to spin, sleep briefly or sleep for next request
 		if (REQUEST_SLEEP != loop)
 		{
-			ms_sleep(LOOP_SLEEP_NORMAL_MS);
+			ms_sleep(HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS);
 		}
 	}
 
 		if (! mExitRequested)
 		{
 			// Setup for subsequent tracing
-			long tracing(TRACE_OFF);
+			long tracing(HTTP_TRACE_OFF);
 			mPolicy->getGlobalOptions().get(HttpRequest::GP_TRACE, &tracing);
 			op->mTracing = (std::max)(op->mTracing, int(tracing));
 
-			if (op->mTracing > TRACE_OFF)
+			if (op->mTracing > HTTP_TRACE_OFF)
 			{
 				LL_INFOS("CoreHttp") << "TRACE, FromRequestQueue, Handle:  "
 									 << static_cast<HttpHandle>(op)

indra/llcorehttp/_httpservice.h

 class HttpLibcurl;
 
 
-/// The HttpService class does the work behind the request  queue.  It
+/// The HttpService class does the work behind the request queue.  It
 /// oversees the HTTP workflow carrying out a number of tasks:
 /// - Pulling requests from the global request queue
 /// - Executing 'immediate' requests directly
 /// HttpPolicy and HttpLibcurl (transport).  These always exist in a
 /// 1:1:1 relationship with HttpService managing instances of the other
 /// two.  So, these classes do not use reference counting to refer
-/// to one-another, their lifecycles are always managed together.
+/// to one another, their lifecycles are always managed together.
 
 class HttpService
 {
 	
 	// === shared data ===
 	static volatile EState				sState;
-	HttpRequestQueue *					mRequestQueue;
+	HttpRequestQueue *					mRequestQueue;	// Refcounted
 	LLAtomicU32							mExitRequested;
 	LLCoreInt::HttpThread *				mThread;
 	

indra/llcorehttp/httpcommon.h

 /// Using the library is fairly easy.  Global setup needs a few
 /// steps:
 ///
-/// - libcurl initialization with thread-safely callbacks for c-ares
-///   DNS lookups.
+/// - libcurl initialization including thread-safely callbacks for SSL:
+///   .  curl_global_init(...)
+///   .  CRYPTO_set_locking_callback(...)
+///   .  CRYPTO_set_id_callback(...)
 /// - HttpRequest::createService() called to instantiate singletons
 ///   and support objects.
 ///
 /// - Do completion processing in your onCompletion() method.
 ///
 /// Code fragments:
-/// <TBD>
+/// Rather than a poorly-maintained example in comments, look in the
+/// example subdirectory which is a minimal yet functional tool to do
+/// GET request performance testing.  With four calls:
 ///
+///   	init_curl();
+///     LLCore::HttpRequest::createService();
+///     LLCore::HttpRequest::startThread();
+///     LLCore::HttpRequest * hr = new LLCore::HttpRequest();
+///
+/// the program is basically ready to issue requests.
+///
+
 
 #include "linden_common.h"		// Modifies curl/curl.h interfaces
 

indra/llcorehttp/httpoptions.cpp

 HttpOptions::HttpOptions()
 	: RefCounted(true),
 	  mWantHeaders(false),
-	  mTracing(TRACE_OFF),
-	  mTimeout(DEFAULT_TIMEOUT),
-	  mRetries(DEFAULT_RETRY_COUNT)
+	  mTracing(HTTP_TRACE_OFF),
+	  mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
+	  mRetries(HTTP_RETRY_COUNT_DEFAULT)
 {}