Commits

Stinson Linden  committed c505665 Merge
  • Participants
  • Parent commits 98c098e, 1298a49

Comments (0)

Files changed (115)

 93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240
 0891d7a773a31397dcad48be3fa66531d567a821 DRTVWR-242
 710785535362b3cb801b6a3dc4703be3373bd0cd 3.4.2-beta3
+2aa72e3372a83dece4df9cf72fb1e7c34f90b5e3 DRTVWR-209
+f7bedce18ad52283e6072814db23318907261487 DRTVWR-238

File autobuild.xml

             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>d98078791ce345bf6168ce9ba53ca2d7</string>
+              <string>36aa500e13cdde61607b6e93065206ec</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/222752/arch/Darwin/installer/boost-1.45.0-darwin-20110304.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/261457/arch/Darwin/installer/boost-1.48.0-darwin-20120710.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a34e7fffdb94a6a4d8a2966b1f216da3</string>
+              <string>18602d44bd435eb0d7189f436ff2cb0f</string>
               <key>url</key>
-              <string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.45.0-linux-20110310.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/261457/arch/Linux/installer/boost-1.48.0-linux-20120710.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>98be22c8833aa2bca184b9fa09fbb82b</string>
+              <string>dc8f5dc6be04c64bf3460b4932b18457</string>
               <key>url</key>
-              <string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.45.0-windows-20110124.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-boost/rev/261457/arch/CYGWIN/installer/boost-1.48.0-windows-20120710.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>

File indra/CMakeLists.txt

 add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
 add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
+add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
 add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
 add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)

File indra/cmake/00-Common.cmake

File contents unchanged.

File indra/cmake/Boost.cmake

   set(BOOST_SIGNALS_LIBRARY boost_signals-mt)
   set(BOOST_SYSTEM_LIBRARY boost_system-mt)
   set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
+  set(BOOST_THREAD_LIBRARY boost_thread-mt)
 else (STANDALONE)
   use_prebuilt_binary(boost)
   set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
 
   if (WINDOWS)
-    set(BOOST_VERSION 1_45)
+    set(BOOST_VERSION 1_48)
     if(MSVC80)
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
           optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
     else(MSVC80)
       # MSVC 10.0 config
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
-          optimized libboost_program_options-vc100-mt-${BOOST_VERSION}
-          debug libboost_program_options-vc100-mt-gd-${BOOST_VERSION})
+          optimized libboost_program_options-mt
+          debug libboost_program_options-mt-gd)
       set(BOOST_REGEX_LIBRARY
-          optimized libboost_regex-vc100-mt-${BOOST_VERSION}
-          debug libboost_regex-vc100-mt-gd-${BOOST_VERSION})
+          optimized libboost_regex-mt
+          debug libboost_regex-mt-gd)
       set(BOOST_SYSTEM_LIBRARY 
-          optimized libboost_system-vc100-mt-${BOOST_VERSION}
-          debug libboost_system-vc100-mt-gd-${BOOST_VERSION})
+          optimized libboost_system-mt
+          debug libboost_system-mt-gd)
       set(BOOST_FILESYSTEM_LIBRARY 
-          optimized libboost_filesystem-vc100-mt-${BOOST_VERSION}
-          debug libboost_filesystem-vc100-mt-gd-${BOOST_VERSION})    
+          optimized libboost_filesystem-mt
+          debug libboost_filesystem-mt-gd)
+      set(BOOST_THREAD_LIBRARY 
+          optimized libboost_thread-mt
+          debug libboost_thread-mt-gd)
     endif (MSVC80)
-  elseif (DARWIN OR LINUX)
-    set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options)
-    set(BOOST_REGEX_LIBRARY boost_regex)
-    set(BOOST_SYSTEM_LIBRARY boost_system)
-    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem)
+  elseif (LINUX)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized boost_program_options-mt
+        debug boost_program_options-mt-d)
+    set(BOOST_REGEX_LIBRARY
+        optimized boost_regex-mt
+        debug boost_regex-mt-d)
+    set(BOOST_SYSTEM_LIBRARY
+        optimized boost_system-mt
+        debug boost_system-mt-d)
+    set(BOOST_FILESYSTEM_LIBRARY
+        optimized boost_filesystem-mt
+        debug boost_filesystem-mt-d)
+    set(BOOST_THREAD_LIBRARY
+        optimized boost_thread-mt
+        debug boost_thread-mt-d)
+  elseif (DARWIN)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized boost_program_options-mt
+        debug boost_program_options-mt-d)
+    set(BOOST_PROGRAM_OPTIONS_LIBRARY
+        optimized boost_program_options-mt
+        debug boost_program_options-mt-d)
+    set(BOOST_REGEX_LIBRARY
+        optimized boost_regex-mt
+        debug boost_regex-mt-d)
+    set(BOOST_SYSTEM_LIBRARY
+        optimized boost_system-mt
+        debug boost_system-mt-d)
+    set(BOOST_FILESYSTEM_LIBRARY
+        optimized boost_filesystem-mt
+        debug boost_filesystem-mt-d)
+    set(BOOST_THREAD_LIBRARY
+        optimized boost_thread-mt
+        debug boost_thread-mt-d)
   endif (WINDOWS)
 endif (STANDALONE)

File indra/cmake/Copy3rdPartyLibs.cmake

         libapr-1.so.0
         libaprutil-1.so.0
         libatk-1.0.so
+        libboost_program_options-mt.so.1.48.0
+        libboost_regex-mt.so.1.48.0
+        libboost_thread-mt.so.1.48.0
+        libboost_filesystem-mt.so.1.48.0
+        libboost_signals-mt.so.1.48.0
+        libboost_system-mt.so.1.48.0
         libbreakpad_client.so.0
         libcollada14dom.so
         libcrypto.so.1.0.0

File indra/cmake/LLCommon.cmake

 
 add_definitions(${TCMALLOC_FLAG})
 
-set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a shared library.")
+set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")
 if(LLCOMMON_LINK_SHARED)
   add_definitions(-DLL_COMMON_LINK_SHARED=1)
 endif(LLCOMMON_LINK_SHARED)

File indra/cmake/LLCoreHttp.cmake

+# -*- cmake -*-
+
+include(CARes)
+include(CURL)
+include(OpenSSL)
+include(Boost)
+
+set(LLCOREHTTP_INCLUDE_DIRS
+    ${LIBS_OPEN_DIR}/llcorehttp
+    ${CARES_INCLUDE_DIRS}
+    ${CURL_INCLUDE_DIRS}
+    ${OPENSSL_INCLUDE_DIRS}
+    ${BOOST_INCLUDE_DIRS}
+    )
+
+set(LLCOREHTTP_LIBRARIES llcorehttp)

File indra/cmake/LLPrimitive.cmake

         optimized llprimitive
         debug libcollada14dom22-d
         optimized libcollada14dom22
-        debug libboost_filesystem-vc100-mt-gd-1_45
-        optimized libboost_filesystem-vc100-mt-1_45
-        debug libboost_system-vc100-mt-gd-1_45
-        optimized libboost_system-vc100-mt-1_45
+        debug libboost_filesystem-mt-gd
+        optimized libboost_filesystem-mt
+        debug libboost_system-mt-gd
+        optimized libboost_system-mt
         )
 else (WINDOWS)
     set(LLPRIMITIVE_LIBRARIES 

File indra/cmake/Variables.cmake

File contents unchanged.

File indra/llcharacter/lleditingmotion.cpp

 	target = target * target_dist;
 	if (!target.isFinite())
 	{
-		llerrs << "Non finite target in editing motion with target distance of " << target_dist << 
+		// Don't error out here, set a fail-safe target vector
+		llwarns << "Non finite target in editing motion with target distance of " << target_dist << 
 			" and focus point " << focus_pt << llendl;
+		target.setVec(1.f, 1.f, 1.f);
 	}
 	
 	mTarget.setPosition( target + mParentJoint.getPosition());

File indra/llcommon/linden_common.h

 #include "llerror.h"
 #include "llfile.h"
 
+// Boost 1.45 had version 2 as the default for the filesystem library,
+// 1.48 has version 3 as the default.  Keep compatibility for now.
+#define BOOST_FILESYSTEM_VERSION		2
+
 #endif

File indra/llcommon/llapr.h

 	void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
 	void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
 	Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
-	Type operator --(int) { return apr_atomic_dec32(&mData); } // Type--
+	Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
 	
 private:
 	apr_uint32_t mData;

File indra/llcommon/llsdserialize.cpp

 	}
 
 	case LLSD::TypeUUID:
+	{
 		ostr.put('u');
-		ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
+		LLSD::UUID value = data.asUUID();
+		ostr.write((const char*)(&value.mData), UUID_BYTES);
 		break;
+	}
 
 	case LLSD::TypeString:
 		ostr.put('s');

File indra/llcommon/llstring.cpp

 
 std::string ll_safe_string(const char* in, S32 maxlen)
 {
-	if(in) return std::string(in, maxlen);
+	if(in && maxlen > 0 ) return std::string(in, maxlen);
+
 	return std::string();
 }
 

File indra/llcommon/llthread.cpp

 	}
 }
 
+void LLThread::registerThreadID()
+{
+#if !LL_DARWIN
+	sThreadID = ++sIDIter;
+#endif
+}
+
 //
 // Handed to the APR thread creation function
 //

File indra/llcommon/llthread.h

 
 	U32 getID() const { return mID; }
 
+	// Called by threads *not* created via LLThread to register some
+	// internal state used by LLMutex.  You must call this once early
+	// in the running thread to prevent collisions with the main thread.
+	static void registerThreadID();
+	
 private:
 	BOOL				mPaused;
 	

File indra/llcommon/tests/bitpack_test.cpp

 		ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);
 		unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life
 		ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4);
+		ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize);
 	}
 
 	// U32 packing

File indra/llcommon/tests/reflection_test.cpp

 			const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception.
 
 			// useless op to get rid of compiler warning.
-			reflective = NULL;
+			reflective = reflective;
 		}
 		catch(...)
 		{

File indra/llcorehttp/CMakeLists.txt

+# -*- cmake -*-
+
+project(llcorehttp)
+
+include(00-Common)
+include(GoogleMock)
+include(CURL)
+include(CARes)
+include(OpenSSL)
+include(ZLIB)
+include(LLCoreHttp)
+include(LLAddBuildTest)
+include(LLMessage)
+include(LLCommon)
+include(Tut)
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR})
+
+include_directories(
+    ${LLMESSAGE_INCLUDE_DIRS}
+    ${LLCOMMON_INCLUDE_DIRS}
+    ${LLCOREHTTP_INCLUDE_DIRS}
+    )
+
+set(llcorehttp_SOURCE_FILES
+    bufferarray.cpp
+    bufferstream.cpp
+    httpcommon.cpp
+    httpheaders.cpp
+    httpoptions.cpp
+    httprequest.cpp
+    httpresponse.cpp
+    _httplibcurl.cpp
+    _httpopcancel.cpp
+    _httpoperation.cpp
+    _httpoprequest.cpp
+    _httpopsetget.cpp
+    _httpopsetpriority.cpp
+    _httppolicy.cpp
+    _httppolicyclass.cpp
+    _httppolicyglobal.cpp
+    _httpreplyqueue.cpp
+    _httprequestqueue.cpp
+    _httpservice.cpp
+    _refcounted.cpp
+    )
+
+set(llcorehttp_HEADER_FILES
+    CMakeLists.txt
+
+    bufferarray.h
+    bufferstream.h
+    httpcommon.h
+    httphandler.h
+    httpheaders.h
+    httpoptions.h
+    httprequest.h
+    httpresponse.h
+    _httpinternal.h
+    _httplibcurl.h
+    _httpopcancel.h
+    _httpoperation.h
+    _httpoprequest.h
+    _httpopsetget.h
+    _httpopsetpriority.h
+    _httppolicy.h
+    _httppolicyclass.h
+    _httppolicyglobal.h
+    _httpreadyqueue.h
+    _httpreplyqueue.h
+    _httprequestqueue.h
+    _httpservice.h
+    _mutex.h
+    _refcounted.h
+    _thread.h
+    )
+
+set_source_files_properties(${llcorehttp_HEADER_FILES}
+                            PROPERTIES HEADER_FILE_ONLY TRUE)
+if (DARWIN OR LINUX)
+  # Boost headers define unused members in condition_variable so...
+  set_source_files_properties(${llcorehttp_SOURCE_FILES}
+                              PROPERTIES COMPILE_FLAGS -Wno-unused-variable)
+endif (DARWIN OR LINUX)
+
+list(APPEND llcorehttp_SOURCE_FILES ${llcorehttp_HEADER_FILES})
+
+add_library (llcorehttp ${llcorehttp_SOURCE_FILES})
+target_link_libraries(
+  llcorehttp
+  ${CURL_LIBRARIES}
+  ${CARES_LIBRARIES}
+  ${OPENSSL_LIBRARIES}
+  ${CRYPTO_LIBRARIES}
+  ${BOOST_THREAD_LIBRARY}
+  )
+
+# tests
+if (LL_TESTS)
+  SET(llcorehttp_TEST_SOURCE_FILES
+      tests/test_allocator.cpp
+      )
+
+  set(llcorehttp_TEST_HEADER_FILS
+      tests/test_httpstatus.hpp
+      tests/test_refcounted.hpp
+      tests/test_httpoperation.hpp
+      tests/test_httprequest.hpp
+      tests/test_httprequestqueue.hpp
+      tests/test_httpheaders.hpp
+      tests/test_bufferarray.hpp
+      tests/test_bufferstream.hpp
+      )
+
+  set_source_files_properties(${llcorehttp_TEST_HEADER_FILES}
+                              PROPERTIES HEADER_FILE_ONLY TRUE)
+
+  list(APPEND llcorehttp_TEST_SOURCE_FILES ${llcorehttp_TEST_HEADER_FILES})
+
+  # LL_ADD_PROJECT_UNIT_TESTS(llcorehttp "${llcorehttp_TEST_SOURCE_FILES}")
+
+  #    set(TEST_DEBUG on)
+  set(test_libs
+      ${LLCOREHTTP_LIBRARIES}
+      ${WINDOWS_LIBRARIES}
+      ${LLMESSAGE_LIBRARIES}
+      ${LLCOMMON_LIBRARIES}
+      ${GOOGLEMOCK_LIBRARIES}
+      ${CURL_LIBRARIES}
+      ${CARES_LIBRARIES}
+      ${OPENSSL_LIBRARIES}
+      ${CRYPTO_LIBRARIES}
+      ${BOOST_THREAD_LIBRARY}
+      )
+
+  LL_ADD_INTEGRATION_TEST(llcorehttp
+                          "${llcorehttp_TEST_SOURCE_FILES}"
+                          "${test_libs}"
+                          ${PYTHON_EXECUTABLE}
+                          "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py"
+                          )
+
+  #
+  # Example Programs
+  #
+  SET(llcorehttp_EXAMPLE_SOURCE_FILES
+      examples/http_texture_load.cpp
+      )
+
+  set(example_libs
+      ${LLCOREHTTP_LIBRARIES}
+      ${WINDOWS_LIBRARIES}
+      ${LLMESSAGE_LIBRARIES}
+      ${LLCOMMON_LIBRARIES}
+      ${GOOGLEMOCK_LIBRARIES}
+      ${CURL_LIBRARIES}
+      ${CARES_LIBRARIES}
+      ${OPENSSL_LIBRARIES}
+      ${CRYPTO_LIBRARIES}
+      ${BOOST_THREAD_LIBRARY}
+      )
+
+  add_executable(http_texture_load
+                 ${llcorehttp_EXAMPLE_SOURCE_FILES}
+                 )
+  set_target_properties(http_texture_load
+                        PROPERTIES
+                        RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}"
+                        )
+
+  if (WINDOWS)
+    # The following come from LLAddBuildTest.cmake's INTEGRATION_TEST_xxxx target.
+    set_target_properties(http_texture_load
+                          PROPERTIES
+                          LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc"
+                          LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO"
+                          LINK_FLAGS_RELEASE ""
+                          )
+  endif (WINDOWS)
+
+  target_link_libraries(http_texture_load ${example_libs})
+
+endif (LL_TESTS)
+

File indra/llcorehttp/_httpinternal.h

+/**
+ * @file _httpinternal.h
+ * @brief Implementation constants and magic numbers
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#ifndef	_LLCORE_HTTP_INTERNAL_H_
+#define	_LLCORE_HTTP_INTERNAL_H_
+
+
+// If you find this included in a public interface header,
+// 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_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 HTTP_POLICY_CLASS_LIMIT = 1;
+
+// Debug/informational tracing.  Used both
+// as a global option and in per-request traces.
+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 HTTP_TRACE_MIN = HTTP_TRACE_OFF;
+const int HTTP_TRACE_MAX = HTTP_TRACE_CURL_BODIES;
+
+// Request retry limits
+const int HTTP_RETRY_COUNT_DEFAULT = 5;
+const int HTTP_RETRY_COUNT_MIN = 0;
+const int HTTP_RETRY_COUNT_MAX = 100;
+
+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 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 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 HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS = 2;
+
+// Block allocation size (a tuning parameter) is found
+// in bufferarray.h.
+
+// Compatibility controls
+const bool HTTP_ENABLE_LINKSYS_WRT54G_V5_DNS_FIX = true;
+
+}  // end namespace LLCore
+
+#endif	// _LLCORE_HTTP_INTERNAL_H_

File indra/llcorehttp/_httplibcurl.cpp

+/**
+ * @file _httplibcurl.cpp
+ * @brief Internal definitions of the Http libcurl thread
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "_httplibcurl.h"
+
+#include "httpheaders.h"
+#include "bufferarray.h"
+#include "_httpoprequest.h"
+#include "_httppolicy.h"
+
+#include "llhttpstatuscodes.h"
+
+
+namespace LLCore
+{
+
+
+HttpLibcurl::HttpLibcurl(HttpService * service)
+	: mService(service),
+	  mPolicyCount(0),
+	  mMultiHandles(NULL)
+{}
+
+
+HttpLibcurl::~HttpLibcurl()
+{
+	shutdown();
+	
+	mService = NULL;
+}
+
+
+void HttpLibcurl::shutdown()
+{
+	while (! mActiveOps.empty())
+	{
+		HttpOpRequest * op(* mActiveOps.begin());
+		mActiveOps.erase(mActiveOps.begin());
+
+		cancelRequest(op);
+		op->release();
+	}
+
+	if (mMultiHandles)
+	{
+		for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)
+		{
+			if (mMultiHandles[policy_class])
+			{
+				curl_multi_cleanup(mMultiHandles[policy_class]);
+				mMultiHandles[policy_class] = 0;
+			}
+		}
+
+		delete [] mMultiHandles;
+		mMultiHandles = NULL;
+	}
+
+	mPolicyCount = 0;
+}
+
+
+void HttpLibcurl::start(int policy_count)
+{
+	llassert_always(policy_count <= HTTP_POLICY_CLASS_LIMIT);
+	llassert_always(! mMultiHandles);					// One-time call only
+	
+	mPolicyCount = policy_count;
+	mMultiHandles = new CURLM * [mPolicyCount];
+	for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)
+	{
+		mMultiHandles[policy_class] = curl_multi_init();
+	}
+}
+
+
+// Give libcurl some cycles, invoke it's callbacks, process
+// completed requests finalizing or issuing retries as needed.
+//
+// If active list goes empty *and* we didn't queue any
+// requests for retry, we return a request for a hard
+// sleep otherwise ask for a normal polling interval.
+HttpService::ELoopSpeed HttpLibcurl::processTransport()
+{
+	HttpService::ELoopSpeed	ret(HttpService::REQUEST_SLEEP);
+
+	// Give libcurl some cycles to do I/O & callbacks
+	for (int policy_class(0); policy_class < mPolicyCount; ++policy_class)
+	{
+		if (! mMultiHandles[policy_class])
+			continue;
+		
+		int running(0);
+		CURLMcode status(CURLM_CALL_MULTI_PERFORM);
+		do
+		{
+			running = 0;
+			status = curl_multi_perform(mMultiHandles[policy_class], &running);
+		}
+		while (0 != running && CURLM_CALL_MULTI_PERFORM == status);
+
+		// Run completion on anything done
+		CURLMsg * msg(NULL);
+		int msgs_in_queue(0);
+		while ((msg = curl_multi_info_read(mMultiHandles[policy_class], &msgs_in_queue)))
+		{
+			if (CURLMSG_DONE == msg->msg)
+			{
+				CURL * handle(msg->easy_handle);
+				CURLcode result(msg->data.result);
+
+				if (completeRequest(mMultiHandles[policy_class], handle, result))
+				{
+					// Request is still active, don't get too sleepy
+					ret = HttpService::NORMAL;
+				}
+				handle = NULL;			// No longer valid on return
+			}
+			else if (CURLMSG_NONE == msg->msg)
+			{
+				// Ignore this... it shouldn't mean anything.
+				;
+			}
+			else
+			{
+				LL_WARNS_ONCE("CoreHttp") << "Unexpected message from libcurl.  Msg code:  "
+										  << msg->msg
+										  << LL_ENDL;
+			}
+			msgs_in_queue = 0;
+		}
+	}
+
+	if (! mActiveOps.empty())
+	{
+		ret = HttpService::NORMAL;
+	}
+	return ret;
+}
+
+
+// Caller has provided us with a ref count on op.
+void HttpLibcurl::addOp(HttpOpRequest * op)
+{
+	llassert_always(op->mReqPolicy < mPolicyCount);
+	llassert_always(mMultiHandles[op->mReqPolicy] != NULL);
+	
+	// Create standard handle
+	if (! op->prepareRequest(mService))
+	{
+		// Couldn't issue request, fail with notification
+		// *TODO:  Need failure path
+		return;
+	}
+
+	// Make the request live
+	curl_multi_add_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle);
+	op->mCurlActive = true;
+	
+	if (op->mTracing > HTTP_TRACE_OFF)
+	{
+		HttpPolicy & policy(mService->getPolicy());
+		
+		LL_INFOS("CoreHttp") << "TRACE, ToActiveQueue, Handle:  "
+							 << static_cast<HttpHandle>(op)
+							 << ", Actives:  " << mActiveOps.size()
+							 << ", Readies:  " << policy.getReadyCount(op->mReqPolicy)
+							 << LL_ENDL;
+	}
+	
+	// On success, make operation active
+	mActiveOps.insert(op);
+}
+
+
+// Implements the transport part of any cancel operation.
+// See if the handle is an active operation and if so,
+// use the more complicated transport-based cancelation
+// method to kill the request.
+bool HttpLibcurl::cancel(HttpHandle handle)
+{
+	HttpOpRequest * op(static_cast<HttpOpRequest *>(handle));
+	active_set_t::iterator it(mActiveOps.find(op));
+	if (mActiveOps.end() == it)
+	{
+		return false;
+	}
+
+	// Cancel request
+	cancelRequest(op);
+
+	// Drop references
+	mActiveOps.erase(it);
+	op->release();
+
+	return true;
+}
+
+
+// *NOTE:  cancelRequest logic parallels completeRequest logic.
+// Keep them synchronized as necessary.  Caller is expected to
+// 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)
+{
+	// Deactivate request
+	op->mCurlActive = false;
+
+	// Detach from multi and recycle handle
+	curl_multi_remove_handle(mMultiHandles[op->mReqPolicy], op->mCurlHandle);
+	curl_easy_cleanup(op->mCurlHandle);
+	op->mCurlHandle = NULL;
+
+	// Tracing
+	if (op->mTracing > HTTP_TRACE_OFF)
+	{
+		LL_INFOS("CoreHttp") << "TRACE, RequestCanceled, Handle:  "
+							 << static_cast<HttpHandle>(op)
+							 << ", Status:  " << op->mStatus.toHex()
+							 << LL_ENDL;
+	}
+
+	// Cancel op and deliver for notification
+	op->cancel();
+}
+
+
+// *NOTE:  cancelRequest logic parallels completeRequest logic.
+// Keep them synchronized as necessary.
+bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status)
+{
+	HttpOpRequest * op(NULL);
+	curl_easy_getinfo(handle, CURLINFO_PRIVATE, &op);
+
+	if (handle != op->mCurlHandle || ! op->mCurlActive)
+	{
+		LL_WARNS("CoreHttp") << "libcurl handle and HttpOpRequest handle in disagreement or inactive request."
+							 << "  Handle:  " << static_cast<HttpHandle>(handle)
+							 << LL_ENDL;
+		return false;
+	}
+
+	active_set_t::iterator it(mActiveOps.find(op));
+	if (mActiveOps.end() == it)
+	{
+		LL_WARNS("CoreHttp") << "libcurl completion for request not on active list.  Continuing."
+							 << "  Handle:  " << static_cast<HttpHandle>(handle)
+							 << LL_ENDL;
+		return false;
+	}
+
+	// Deactivate request
+	mActiveOps.erase(it);
+	op->mCurlActive = false;
+
+	// Set final status of request if it hasn't failed by other mechanisms yet
+	if (op->mStatus)
+	{
+		op->mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, status);
+	}
+	if (op->mStatus)
+	{
+		int http_status(HTTP_OK);
+
+		curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_status);
+		if (http_status >= 100 && http_status <= 999)
+		{
+			char * cont_type(NULL);
+			curl_easy_getinfo(handle, CURLINFO_CONTENT_TYPE, &cont_type);
+			if (cont_type)
+			{
+				op->mReplyConType = cont_type;
+			}
+			op->mStatus = HttpStatus(http_status);
+		}
+		else
+		{
+			LL_WARNS("CoreHttp") << "Invalid HTTP response code ("
+								 << http_status << ") received from server."
+								 << LL_ENDL;
+			op->mStatus = HttpStatus(HttpStatus::LLCORE, HE_INVALID_HTTP_STATUS);
+		}
+	}
+
+	// Detach from multi and recycle handle
+	curl_multi_remove_handle(multi_handle, handle);
+	curl_easy_cleanup(handle);
+	op->mCurlHandle = NULL;
+
+	// Tracing
+	if (op->mTracing > HTTP_TRACE_OFF)
+	{
+		LL_INFOS("CoreHttp") << "TRACE, RequestComplete, Handle:  "
+							 << static_cast<HttpHandle>(op)
+							 << ", Status:  " << op->mStatus.toHex()
+							 << LL_ENDL;
+	}
+
+	// Dispatch to next stage
+	HttpPolicy & policy(mService->getPolicy());
+	bool still_active(policy.stageAfterCompletion(op));
+
+	return still_active;
+}
+
+
+int HttpLibcurl::getActiveCount() const
+{
+	return mActiveOps.size();
+}
+
+
+int HttpLibcurl::getActiveCountInClass(int policy_class) const
+{
+	int count(0);
+	
+	for (active_set_t::const_iterator iter(mActiveOps.begin());
+		 mActiveOps.end() != iter;
+		 ++iter)
+	{
+		if ((*iter)->mReqPolicy == policy_class)
+		{
+			++count;
+		}
+	}
+	
+	return count;
+}
+
+
+// ---------------------------------------
+// Free functions
+// ---------------------------------------
+
+
+struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist)
+{
+	for (HttpHeaders::container_t::const_iterator it(headers->mHeaders.begin());
+
+		headers->mHeaders.end() != it;
+		 ++it)
+	{
+		slist = curl_slist_append(slist, (*it).c_str());
+	}
+	return slist;
+}
+
+
+}  // end namespace LLCore

File indra/llcorehttp/_httplibcurl.h

+/**
+ * @file _httplibcurl.h
+ * @brief Declarations for internal class providing libcurl transport.
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#ifndef	_LLCORE_HTTP_LIBCURL_H_
+#define	_LLCORE_HTTP_LIBCURL_H_
+
+#include "linden_common.h"		// Modifies curl/curl.h interfaces
+
+#include <curl/curl.h>
+#include <curl/multi.h>
+
+#include <set>
+
+#include "httprequest.h"
+#include "_httpservice.h"
+#include "_httpinternal.h"
+
+
+namespace LLCore
+{
+
+
+class HttpPolicy;
+class HttpOpRequest;
+class HttpHeaders;
+
+
+/// Implements libcurl-based transport for an HttpService instance.
+///
+/// Threading:  Single-threaded.  Other than for construction/destruction,
+/// all methods are expected to be invoked in a single thread, typically
+/// a worker thread of some sort.
+
+class HttpLibcurl
+{
+public:
+	HttpLibcurl(HttpService * service);
+	virtual ~HttpLibcurl();
+
+private:
+	HttpLibcurl(const HttpLibcurl &);			// Not defined
+	void operator=(const HttpLibcurl &);		// Not defined
+
+public:
+	/// 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 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;
+
+	/// 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:
+	/// Invoked when libcurl has indicated a request has been processed
+	/// to completion and we need to move the request to a new state.
+	bool completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status);
+
+	/// Invoked to cancel an active request, mainly during shutdown
+	/// and destroy.
+	void cancelRequest(HttpOpRequest * op);
+	
+protected:
+	typedef std::set<HttpOpRequest *> active_set_t;
+	
+protected:
+	HttpService *		mService;				// Simple reference, not owner
+	active_set_t		mActiveOps;
+	int					mPolicyCount;
+	CURLM **			mMultiHandles;
+}; // end class HttpLibcurl
+
+}  // end namespace LLCore
+
+#endif // _LLCORE_HTTP_LIBCURL_H_

File indra/llcorehttp/_httpopcancel.cpp

+/**
+ * @file _httpopcancel.cpp
+ * @brief Definitions for internal class HttpOpCancel
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "_httpopcancel.h"
+
+#include "httpcommon.h"
+#include "httphandler.h"
+#include "httpresponse.h"
+
+#include "_httpservice.h"
+
+
+namespace LLCore
+{
+
+
+// ==================================
+// HttpOpCancel
+// ==================================
+
+
+HttpOpCancel::HttpOpCancel(HttpHandle handle)
+	: HttpOperation(),
+	  mHandle(handle)
+{}
+
+
+HttpOpCancel::~HttpOpCancel()
+{}
+
+
+// Immediately search for the request on various queues
+// and cancel operations if found.  Return the status of
+// the search and cancel as the status of this request.
+// The canceled request will return a canceled status to
+// its handler.
+void HttpOpCancel::stageFromRequest(HttpService * service)
+{
+	if (! service->cancel(mHandle))
+	{
+		mStatus = HttpStatus(HttpStatus::LLCORE, HE_HANDLE_NOT_FOUND);
+	}
+	
+	addAsReply();
+}
+
+
+}   // end namespace LLCore
+
+		

File indra/llcorehttp/_httpopcancel.h

+/**
+ * @file _httpopcancel.h
+ * @brief Internal declarations for the HttpOpCancel subclass
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#ifndef	_LLCORE_HTTP_OPCANCEL_H_
+#define	_LLCORE_HTTP_OPCANCEL_H_
+
+
+#include "linden_common.h"		// Modifies curl/curl.h interfaces
+
+#include "httpcommon.h"
+
+#include <curl/curl.h>
+
+#include "_httpoperation.h"
+#include "_refcounted.h"
+
+
+namespace LLCore
+{
+
+
+/// HttpOpCancel requests that a previously issued request
+/// 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 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:
+	virtual ~HttpOpCancel();							// Use release()
+	
+private:
+	HttpOpCancel(const HttpOpCancel &);					// Not defined
+	void operator=(const HttpOpCancel &);				// Not defined
+
+public:
+	virtual void stageFromRequest(HttpService *);
+			
+public:
+	// Request data
+	HttpHandle			mHandle;
+};  // end class HttpOpCancel
+
+
+}   // end namespace LLCore
+
+#endif	// _LLCORE_HTTP_OPCANCEL_H_
+

File indra/llcorehttp/_httpoperation.cpp

+/**
+ * @file _httpoperation.cpp
+ * @brief Definitions for internal classes based on HttpOperation
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "_httpoperation.h"
+
+#include "httphandler.h"
+#include "httpresponse.h"
+#include "httprequest.h"
+
+#include "_httprequestqueue.h"
+#include "_httpreplyqueue.h"
+#include "_httpservice.h"
+#include "_httpinternal.h"
+
+#include "lltimer.h"
+
+
+namespace LLCore
+{
+
+
+// ==================================
+// HttpOperation
+// ==================================
+
+
+HttpOperation::HttpOperation()
+	: LLCoreInt::RefCounted(true),
+	  mReplyQueue(NULL),
+	  mUserHandler(NULL),
+	  mReqPolicy(HttpRequest::DEFAULT_POLICY_ID),
+	  mReqPriority(0U),
+	  mTracing(0)
+{
+	mMetricCreated = totalTime();
+}
+
+
+HttpOperation::~HttpOperation()
+{
+	setReplyPath(NULL, NULL);
+}
+
+
+void HttpOperation::setReplyPath(HttpReplyQueue * reply_queue,
+								 HttpHandler * user_handler)
+{
+	if (reply_queue != mReplyQueue)
+	{
+		if (mReplyQueue)
+		{
+			mReplyQueue->release();
+		}
+
+		if (reply_queue)
+		{
+			reply_queue->addRef();
+		}
+
+		mReplyQueue = reply_queue;
+	}
+
+	// Not refcounted
+	mUserHandler = user_handler;
+}
+
+
+
+void HttpOperation::stageFromRequest(HttpService *)
+{
+	// Default implementation should never be called.  This
+	// indicates an operation making a transition that isn't
+	// defined.
+	LL_ERRS("HttpCore") << "Default stageFromRequest method may not be called."
+						<< LL_ENDL;
+}
+
+
+void HttpOperation::stageFromReady(HttpService *)
+{
+	// Default implementation should never be called.  This
+	// indicates an operation making a transition that isn't
+	// defined.
+	LL_ERRS("HttpCore") << "Default stageFromReady method may not be called."
+						<< LL_ENDL;
+}
+
+
+void HttpOperation::stageFromActive(HttpService *)
+{
+	// Default implementation should never be called.  This
+	// indicates an operation making a transition that isn't
+	// defined.
+	LL_ERRS("HttpCore") << "Default stageFromActive method may not be called."
+						<< LL_ENDL;
+}
+
+
+void HttpOperation::visitNotifier(HttpRequest *)
+{
+	if (mUserHandler)
+	{
+		HttpResponse * response = new HttpResponse();
+
+		response->setStatus(mStatus);
+		mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
+
+		response->release();
+	}
+}
+
+
+HttpStatus HttpOperation::cancel()
+{
+	HttpStatus status;
+
+	return status;
+}
+
+
+void HttpOperation::addAsReply()
+{
+	if (mTracing > HTTP_TRACE_OFF)
+	{
+		LL_INFOS("CoreHttp") << "TRACE, ToReplyQueue, Handle:  "
+							 << static_cast<HttpHandle>(this)
+							 << LL_ENDL;
+	}
+	
+	if (mReplyQueue)
+	{
+		addRef();
+		mReplyQueue->addOp(this);
+	}
+}
+
+
+// ==================================
+// HttpOpStop
+// ==================================
+
+
+HttpOpStop::HttpOpStop()
+	: HttpOperation()
+{}
+
+
+HttpOpStop::~HttpOpStop()
+{}
+
+
+void HttpOpStop::stageFromRequest(HttpService * service)
+{
+	// Do operations
+	service->stopRequested();
+	
+	// Prepare response if needed
+	addAsReply();
+}
+
+
+// ==================================
+// HttpOpNull
+// ==================================
+
+
+HttpOpNull::HttpOpNull()
+	: HttpOperation()
+{}
+
+
+HttpOpNull::~HttpOpNull()
+{}
+
+
+void HttpOpNull::stageFromRequest(HttpService * service)
+{
+	// Perform op
+	// Nothing to perform.  This doesn't fall into the libcurl
+	// ready/active queues, it just bounces over to the reply
+	// queue directly.
+	
+	// Prepare response if needed
+	addAsReply();
+}
+
+
+// ==================================
+// HttpOpSpin
+// ==================================
+
+
+HttpOpSpin::HttpOpSpin(int mode)
+	: HttpOperation(),
+	  mMode(mode)
+{}
+
+
+HttpOpSpin::~HttpOpSpin()
+{}
+
+
+void HttpOpSpin::stageFromRequest(HttpService * service)
+{
+	if (0 == mMode)
+	{
+		// Spin forever
+		while (true)
+		{
+			ms_sleep(100);
+		}
+	}
+	else
+	{
+		ms_sleep(1);			// backoff interlock plumbing a bit
+		this->addRef();
+		if (! service->getRequestQueue().addOp(this))
+		{
+			this->release();
+		}
+	}
+}
+
+
+}   // end namespace LLCore

File indra/llcorehttp/_httpoperation.h

+/**
+ * @file _httpoperation.h
+ * @brief Internal declarations for HttpOperation and sub-classes
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#ifndef	_LLCORE_HTTP_OPERATION_H_
+#define	_LLCORE_HTTP_OPERATION_H_
+
+
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "_refcounted.h"
+
+
+namespace LLCore
+{
+
+class HttpReplyQueue;
+class HttpHandler;
+class HttpService;
+
+/// HttpOperation is the base class for all request/reply
+/// pairs.
+///
+/// Operations are expected to be of two types:  immediate
+/// and queued.  Immediate requests go to the singleton
+/// request queue and when picked up by the worker thread
+/// are executed immediately and there results placed on
+/// the supplied reply queue.  Queued requests (namely for
+/// HTTP operations), go to the request queue, are picked
+/// up and moved to a ready queue where they're ordered by
+/// priority and managed by the policy component, are
+/// then activated issuing HTTP requests and moved to an
+/// active list managed by the transport (libcurl) component
+/// and eventually finalized when a response is available
+/// and status and data return via reply queue.
+///
+/// To manage these transitions, derived classes implement
+/// three methods:  stageFromRequest, stageFromReady and
+/// stageFromActive.  Immediate requests will only override
+/// stageFromRequest which will perform the operation and
+/// return the result by invoking addAsReply() to put the
+/// request on a reply queue.  Queued requests will involve
+/// all three stage methods.
+///
+/// Threading:  not thread-safe.  Base and derived classes
+/// provide no locking.  Instances move across threads
+/// via queue-like interfaces that are thread compatible
+/// and those interfaces establish the access rules.
+
+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:
+	HttpOperation(const HttpOperation &);				// Not defined
+	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);
+
+	/// 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;			// Naked pointer
+
+public:
+	// Request Data
+	HttpRequest::policy_t		mReqPolicy;
+	HttpRequest::priority_t		mReqPriority;
+
+	// Reply Data
+	HttpStatus					mStatus;
+
+	// Tracing, debug and metrics
+	HttpTime					mMetricCreated;
+	int							mTracing;
+};  // end class HttpOperation
+
+
+/// HttpOpStop requests the servicing thread to shutdown
+/// operations, cease pulling requests from the request
+/// queue and release shared resources (particularly
+/// those shared via reference count).  The servicing
+/// thread will then exit.  The underlying thread object
+/// remains so that another thread can join on the
+/// servicing thread prior to final cleanup.  The
+/// request *does* generate a reply on the response
+/// queue, if requested.
+
+class HttpOpStop : public HttpOperation
+{
+public:
+	HttpOpStop();
+
+protected:
+	virtual ~HttpOpStop();
+
+private:
+	HttpOpStop(const HttpOpStop &);					// Not defined
+	void operator=(const HttpOpStop &);				// Not defined
+
+public:
+	virtual void stageFromRequest(HttpService *);
+
+};  // end class HttpOpStop
+
+
+/// HttpOpNull is a do-nothing operation used for testing via
+/// a basic loopback pattern.  It's executed immediately by
+/// the servicing thread which bounces a reply back to the
+/// caller without any further delay.
+
+class HttpOpNull : public HttpOperation
+{
+public:
+	HttpOpNull();
+
+protected:
+	virtual ~HttpOpNull();
+
+private:
+	HttpOpNull(const HttpOpNull &);					// Not defined
+	void operator=(const HttpOpNull &);				// Not defined
+
+public:
+	virtual void stageFromRequest(HttpService *);
+
+};  // end class HttpOpNull
+
+
+/// 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 in production.
+class HttpOpSpin : public HttpOperation
+{
+public:
+	// 0 does a hard spin in the operation
+	// 1 does a soft spin continuously requeuing itself
+	HttpOpSpin(int mode);
+
+protected:
+	virtual ~HttpOpSpin();
+
+private:
+	HttpOpSpin(const HttpOpSpin &);					// Not defined
+	void operator=(const HttpOpSpin &);				// Not defined
+
+public:
+	virtual void stageFromRequest(HttpService *);
+
+protected:
+	int			mMode;
+};  // end class HttpOpSpin
+
+
+}   // end namespace LLCore
+
+#endif	// _LLCORE_HTTP_OPERATION_H_
+

File indra/llcorehttp/_httpoprequest.cpp

+/**
+ * @file _httpoprequest.cpp
+ * @brief Definitions for internal class HttpOpRequest
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "_httpoprequest.h"
+
+#include <cstdio>
+#include <algorithm>
+
+#include "httpcommon.h"
+#include "httphandler.h"
+#include "httpresponse.h"
+#include "bufferarray.h"
+#include "httpheaders.h"
+#include "httpoptions.h"
+
+#include "_httprequestqueue.h"
+#include "_httpreplyqueue.h"
+#include "_httpservice.h"
+#include "_httppolicy.h"
+#include "_httppolicyglobal.h"