Compare commits

..

77 Commits

Author SHA1 Message Date
Siana Gearz
761439cc8d Setting socket pair non-blocking 2012-08-05 08:20:31 +02:00
Aleric Inglewood
08d72b12ab Fix compilation on linux. Remove trailing ^M's 2012-08-02 23:03:03 +02:00
Siana Gearz
4650636e5a Use TCP socket pair instead of UDP 2012-08-02 22:33:01 +02:00
Aleric Inglewood
725cdc2d69 Linux compile fixes 2012-07-31 23:04:45 +02:00
Siana Gearz
048c57cf0c Linktime fix 2012-07-31 22:40:20 +02:00
Siana Gearz
12dcbfbc79 Merge remote-tracking branch 'aleric/breakforce' into breakforce 2012-07-31 22:39:48 +02:00
Aleric Inglewood
32be05fa6c Compile warning fixes. Type fix (SLL -> SSL) 2012-07-31 22:37:49 +02:00
Aleric Inglewood
ae62b67554 Merge branch 'curlthreading2' into breakforce 2012-07-31 22:24:57 +02:00
Siana Gearz
9c4f22d85b Attempt at fixing linker errors... 2012-07-31 21:30:05 +02:00
Siana Gearz
7f64668e55 Compile warning fix 2012-07-31 21:29:22 +02:00
Siana Gearz
0208942b84 Compile warning fix 2012-07-31 21:28:37 +02:00
Siana Gearz
783e86990c Compile fixes 2012-07-31 19:42:15 +02:00
Aleric Inglewood
c9715c5b0b Print Dout() and DoutEntering() debug output on windows.
This is a bit of a hack currently and requires a
recompile with -DDEBUG_CURLIO.
2012-07-31 04:57:13 +02:00
Aleric Inglewood
dd47123bde Add possibility to suppress function name prefix in debug output.
Adds llinfos_nf et al.
2012-07-31 04:56:03 +02:00
Aleric Inglewood
3de21156b5 Windows code improvements and debugging.
Extended the DEBUG_WINDOWS_CODE_ON_LINUX hack to include ALL code.
memset-zero sockaddr_in, and use WSASocket as per suggestion of Shyotl.
2012-07-30 02:46:48 +02:00
Aleric Inglewood
ce2c6ab49e Don't crash when libcurl wasn't compiled with support for libz 2012-07-30 02:45:39 +02:00
Aleric Inglewood
d19c5a4a4a Move apr_os_thread_current_wrapper closer to where it's used, and fix a comment. 2012-07-30 02:44:51 +02:00
Aleric Inglewood
8945fe4857 Unbreak standalone install on 64bit linux 2012-07-30 01:47:27 +02:00
Aleric Inglewood
464919072d Use LLBufferArray instead of std::stringstream for CurlResponderBuffer::mInput
Note the changed code is never used yet.  CurlResponderBuffer::curlReadCallback
is only called when Request::post is being used, which is never used.
2012-07-29 22:52:20 +02:00
Siana Gearz
f8c2087d74 Preliminary Windows support for curlthreading 2012-07-29 22:47:19 +02:00
Siana Gearz
7adc0e24ab Merge branch 'curlthreading2' of git://github.com/AlericInglewood/SingularityViewer into curlthreading 2012-07-29 21:32:24 +02:00
Aleric Inglewood
ba65f29a72 Fix draining of wake up pipe.
This is a bug fix, although not one we'd ever run into as normally
there is always just one byte to read, never an EAGAIN and certainly
never more than 256 bytes. Anyway, also those cases should work now.
2012-07-29 21:12:45 +02:00
Aleric Inglewood
76eef6fe59 Avoid crash on exit. 2012-07-29 18:38:59 +02:00
Aleric Inglewood
fe38f59bbb Bug fix 2012-07-29 01:30:10 +02:00
Siana Gearz
2bcabce1d6 Merge branch 'curlthreading2' of git://github.com/AlericInglewood/SingularityViewer into curlthreading 2012-07-28 17:28:18 +02:00
Aleric Inglewood
ed4c6b7c92 Removed dead code.
This code has been in the viewer source for a long time,
and hasn't been used for a long time (furtherest back that
I checked was Snowglobe 1.4).

Most notably, this removes LLContextURLExtractor and code
that used it because that required an API where AICurlEasyHandle
is created before an url is known, which gets in the way of
reusing connections.
2012-07-23 18:15:11 +02:00
Aleric Inglewood
785729abdf Merge branch 'master' into curlthreading2 2012-07-22 04:17:34 +02:00
Aleric Inglewood
fb38f6adea Always write curl I/O debug info for the login attempt. 2012-07-21 21:51:24 +02:00
Aleric Inglewood
3a30f1dc71 This is called when LLApp::sStatus == LLApp::APP_STATUS_STOPPED too. 2012-07-21 03:57:58 +02:00
Siana Gearz
8802d5033f Merge branch 'master' into curlthreading
Conflicts:
	indra/newview/viewer_manifest.py
2012-07-20 00:37:58 +02:00
Siana Gearz
3d39564605 Merge branch 'curlthreading2' of git://github.com/AlericInglewood/SingularityViewer into curlthreading 2012-07-20 00:35:43 +02:00
Aleric Inglewood
9e5cbf330f Bug fix for windows code found with previous commit. 2012-07-19 17:28:45 +02:00
Aleric Inglewood
2fa9334090 Debug code to test the windows code path on linux 2012-07-19 17:27:37 +02:00
Aleric Inglewood
fcdf5d377e Move PollSet out of the header file 2012-07-19 17:26:02 +02:00
Aleric Inglewood
051263117d Don't force TLS v1 unless needed and then warn about it. 2012-07-19 00:13:43 +02:00
Aleric Inglewood
f772cbee51 Don't crash upon exit if we fail to cleanup. 2012-07-18 03:13:33 +02:00
Aleric Inglewood
7f78870295 Merge remote-tracking branch 'siana/master' into curlthreading2
Conflicts:
	indra/llcommon/llstring.cpp
	indra/llmessage/llcurl.cpp
	indra/newview/llviewertexturelist.cpp
	indra/newview/viewer_manifest.py
	install.xml

Resolved:
	indra/llcommon/llstring.cpp :
		two different ways to work around compile error.
	indra/llmessage/llcurl.cpp :
		this file is no longer used.. I deleted huge
		parts to mark that I implemented that. Siana
		apparently made a few changes in those parts.
	indra/newview/llviewertexturelist.cpp :
		manually copied patch. Mine also removed trailing
		spaces, keeping that.
	indra/newview/viewer_manifest.py:
		Collision with changes from Liru, which have been
		ignored (kept siana/master).
	install.xml:
		Collision with an earlier screw up. I kept the
		fix from siana/master.
2012-07-18 02:08:31 +02:00
Aleric Inglewood
706b9c55c2 Moving stuff around a bit... 2012-07-18 01:41:36 +02:00
Shyotl
48ae0d003d Made the Visual Studio compiler a bit more happy with aicurl. 2012-07-17 18:04:48 -05:00
Aleric Inglewood
0204d09a89 If curl thread is already awake, then don't write something to the pipe. 2012-07-17 23:39:44 +02:00
Aleric Inglewood
648ed00ce2 Don't call gSavedSettings.getU32() and calc_clock_frequency() so often anymore. 2012-07-17 19:58:34 +02:00
Aleric Inglewood
87c9358813 Add back erroneously removed comments. 2012-07-17 19:33:12 +02:00
Aleric Inglewood
64b968b262 process is no longer processing 2012-07-17 19:27:14 +02:00
Aleric Inglewood
900e533b4b Remove unused call to process(). 2012-07-17 08:01:06 +02:00
Aleric Inglewood
9deb3e433c LLCurlRequest time out fixes.
Also some more cleanup on exit improvements.
2012-07-16 22:35:04 +02:00
Aleric Inglewood
a34247ebf4 Bug fix.
Don't test on something that belongs in an assert.
is_main_thread() doesn't even exist unless --type=Debug.
2012-07-15 23:08:07 +02:00
Aleric Inglewood
53e96b02c0 Bug fix. Forgot to actually make it virtual. 2012-07-15 22:59:29 +02:00
Aleric Inglewood
7c022d6061 Don't crash on exit.
When a new state machine was just created, so run() had already
been called but it never did really run yet so running() would
return false; then abort() wasn't called in flush(), causing
the subsequent mainloop call to actually try and startup the
state machine, which then crashed because Debug Settings
mechanism is already destroyed at that point (and in general,
we really don't want anything to run: it does unpredictable
things).

With this fix, also state machines that were just created are
aborted, resulting actuall in a kill without delete, and subsequently
a clean delete from the mainloop.
2012-07-15 22:51:14 +02:00
Aleric Inglewood
14e5b46687 Fixed and adjusted remainders of isValid() code.
Note that in the code, and still, has_curl_request was always false.
However, instead of deleting all code paths that are only executed
when has_curl_request would be true, I fixed the code to work as
intended with my current implementation; which also results in
LLCurlRequests to never expire. This way things won't break
unexpectedly when this ever changes.

Since on this branch isValid was only called still (the rest was
removed already) to check if the curl download expired, I took
the liberty to rename isValid to hasNotExpired.
2012-07-15 22:46:38 +02:00
Aleric Inglewood
a6bb2604f6 Use our API, which makes more sense. 2012-07-15 16:58:47 +02:00
Aleric Inglewood
b2c71c099f Fixed typo in comment 2012-07-15 16:57:47 +02:00
Aleric Inglewood
7416d2aaf1 Timer, time out, and clean up improvements. 2012-07-14 04:29:37 +02:00
Aleric Inglewood
0419f8bee9 Add an AITimer to AICurlEasyRequestStateMachine.
Fixes AIStateMachine to work thread-safe with the timer.
2012-07-10 05:09:08 +02:00
Aleric Inglewood
f012f664d2 Threading voodoo: allow multiple concurrent calls to set_state().
This patch prepares AIStateMachine for the use of AITimer together
with calls to set_state() from other threads. The extra problem
in this case is that the main-thread CAN start running the state
machine again (when the timer times out), while before it was
assumed to be idle until a thread called set_state.

This also takes into account that a thread might call set_state()
and then AGAIN call set_state() before the main thread gets the
chance to call idle() inbetween.
2012-07-09 04:19:28 +02:00
Aleric Inglewood
744563a150 Use a newer libcurl version for linux. 2012-07-07 23:22:48 +02:00
Aleric Inglewood
389074d1e9 Fail at configure time when openGL is not found 2012-07-07 23:17:22 +02:00
Aleric Inglewood
93778eccbb Compile fix for g++ 4.7 2012-07-07 18:29:55 +02:00
Aleric Inglewood
f46d8e8a10 Try to be smart about not printing garbage (binary) received from the server. 2012-07-05 23:50:03 +02:00
Siana Gearz
f5bfab139c Merge branch 'curlthreading2' of git://github.com/AlericInglewood/SingularityViewer into curlthreading 2012-07-05 06:06:04 +02:00
Aleric Inglewood
df20f918ba New libcwd channel 'curlio'.
Enable printing of libcurl 'IO' debug messages when libcwd channel
'curlio' is turned on (added to .libcwdrc). Avoiding a recompile.
2012-07-05 03:10:16 +02:00
Aleric Inglewood
b8fc1f634e Print the curl library found during configure.
Prints something like:
-- Found CURL: /usr/lib/x86_64-linux-gnu/libcurl.so (found version "7.25.0")
2012-07-05 01:41:01 +02:00
Aleric Inglewood
ae9dadb5d8 Improved layout of curl stats print out. 2012-07-04 16:56:33 +02:00
Siana Gearz
d31c062693 Fix building with libcwd 2012-07-04 12:44:05 +02:00
Siana Gearz
544928a039 Merge branch 'curlthreading2' of git://github.com/AlericInglewood/SingularityViewer into curlthreading 2012-07-04 10:45:48 +02:00
Aleric Inglewood
14276b3cf8 Bug fix 2012-07-04 08:44:22 +02:00
Aleric Inglewood
07e7eeedd1 Added some windows code.
Iterating directly over the elements of fd_set::fd_array in
windows is faster than using FD_ISSET.
2012-07-04 07:32:24 +02:00
Aleric Inglewood
125a10bb44 Code hardening, review, bug fixes, documentation, curl stats and cleanup.
Bug fixes:
AICurlEasyRequestStateMachine didn't delete itself.
curl_multi_socket_action calls were made for potentional removed sockets.
The curl thread wasn't terminated.
2012-07-04 00:10:43 +02:00
Aleric Inglewood
9b8e5c8719 Merge branch 'V2MultiWear' into curlthreading2
I picked a few non-curl related patches from curlthreading2
and applied them to V2MultiWear. Now merging back to avoid
collisions for others.
2012-07-03 14:27:12 +02:00
Aleric Inglewood
a803507d67 Use correct way to check if we logged in yet or not.
Without this fix, we trigger an assert, in debug mode, that was added
to Singularity exactly to find out if we called functions like
getExpandedFilename(LL_PATH_PER_SL_ACCOUNT ...) before logging in.
Checking if THAT function returns empty() is clearly not safe, but
very error prone.
2012-07-01 22:15:03 +02:00
Aleric Inglewood
cb5efad026 Turn llassert[_always] into a (single) statement and print line nr in decimal. 2012-06-30 21:14:18 +02:00
Aleric Inglewood
26922a1578 Merge remote-tracking branch 'lirusaito/curlthreading2' into curlthreading2 2012-06-29 05:28:58 +02:00
Aleric Inglewood
90493b6571 Add support for libopenSSL older than version 1.0.0. 2012-06-29 05:20:24 +02:00
Aleric Inglewood
2dee921cd5 Fix libcurl version check. 2012-06-29 01:33:38 +02:00
Lirusaito
433c7c3f99 Spelling fixes and stuff like that to AICurl* and llproxy.* documentations
Also removes a duplicate include from llares.cpp

Conflicts:
	indra/llmessage/aicurl.cpp
2012-06-28 04:08:25 -04:00
Lirusaito
fef461fd13 Grabbed openSSL-1.0.0d from upstream for linux, necessary for non-standalone compiles.
Also brought in linux64 version I had sitting around, collecting dust.
2012-06-28 03:46:22 -04:00
Aleric Inglewood
1f56645b69 Always set proxy settings for every HTTP curl connection.
Move applyProxySettings to CurlEasyRequest and call it from
applyDefaultOptions.

Use AIThreadSafe for LLProxy for a more robust threadsafeness.
(This forces correct locking, checks that the unshared vars
are indeed unshared and made it easy to use read/write locking,
which might be important in this case (we do a lot of read-only
accesses to it).
2012-06-28 05:56:21 +02:00
Aleric Inglewood
69ca6cd5b2 WIP: Make curl thread code robust and flexible.
Conflicts:

	indra/llmessage/llcurl.cpp
	indra/llmessage/llcurl.h
	indra/newview/app_settings/settings.xml
	indra/newview/llappviewer.cpp
	indra/newview/llmeshrepository.cpp

Resolved:

	indra/llmessage/llcurl.cpp:

	  Basically removed (not used anyway)

	indra/llmessage/llcurl.h:

	  Basically removed (just includes aiculr.h now)

	indra/newview/app_settings/settings.xml:

	  CurlUseMultipleThreads was remvoved.
	  CurlMaximumNumberOfHandles and CurlRequestTimeOut
	  are still in there, but unused at the moment.

	indra/newview/llappviewer.cpp:

	  CurlMaximumNumberOfHandles and CurlRequestTimeOut
	  are unused at the moment.

	indra/newview/llmeshrepository.cpp:

	  Lock mSignal always (is unlocked inside wait()).
	  Use mSignal lock to see if we are waiting; remove mWaiting.
	  Return false from the MeshFetch functions iff we have to retry
	  a HTTP fetch. Catch the error exception thrown by getByteRange
	  instead of using it's return value (always returns true
	  anyway).
2012-06-28 01:30:46 +02:00
4534 changed files with 49241 additions and 53001 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
* text=auto

View File

@@ -50,7 +50,7 @@
<key>OpenCircuit</key>
<map>
<key>flavor</key>
<string>llsd</string>
<string>template</string>
<key>trusted-sender</key>
<boolean>false</boolean>
</map>
@@ -370,14 +370,6 @@
</map>
<!-- Server to client -->
<key>DisplayNameUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>ParcelVoiceInfo</key>
<map>
<key>flavor</key>
@@ -427,22 +419,6 @@
<boolean>true</boolean>
</map>
<key>SetDisplayNameReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>SimConsoleResponse</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>DirLandReply</key>
<map>
<key>flavor</key>
@@ -539,24 +515,8 @@
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>NavMeshStatusUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>AgentStateUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<!-- UDPDeprecated Messages -->
<!-- UDPDeprecated Messages -->
<key>ScriptRunningReply</key>
<map>
<key>flavor</key>
@@ -609,9 +569,26 @@
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<!-- Server to client -->
<key>DisplayNameUpdate</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
<key>SetDisplayNameReply</key>
<map>
<key>flavor</key>
<string>llsd</string>
<key>trusted-sender</key>
<boolean>true</boolean>
</map>
</map>
<key>capBans</key>

View File

@@ -77,6 +77,7 @@ if (VIEWER)
add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger)
add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)
add_subdirectory(${LIBS_OPEN_PREFIX}llui)
add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml)
# viewer plugins directory
add_subdirectory(${LIBS_OPEN_PREFIX}plugins)

View File

@@ -41,9 +41,7 @@ if (WINDOWS)
"${CMAKE_C_FLAGS_RELEASE} ${LL_C_FLAGS} /O2 /Zi /MD /MP /arch:SSE2 /fp:fast"
CACHE STRING "C compiler release options" FORCE)
if(NOT CMAKE_EXE_LINKER_FLAGS_RELEASE MATCHES LARGEADDRESSAWARE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LARGEADDRESSAWARE")
endif()
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LARGEADDRESSAWARE")
set(CMAKE_CXX_STANDARD_LIBRARIES "")
set(CMAKE_C_STANDARD_LIBRARIES "")
@@ -70,7 +68,8 @@ if (WINDOWS)
"${CMAKE_CXX_FLAGS_RELEASE} -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
CACHE STRING "C++ compiler release options" FORCE)
set(CMAKE_C_FLAGS_RELEASE
"${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "C compiler release options" FORCE)
"${CMAKE_CXX_FLAGS_RELEASE} -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0"
CACHE STRING "C compiler release options" FORCE)
add_definitions(
/Zc:wchar_t-
)
@@ -191,10 +190,10 @@ if (LINUX)
endif (NOT STANDALONE)
if (${ARCH} STREQUAL "x86_64")
add_definitions(-DLINUX64=1 -pipe)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ffast-math -funroll-loops")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fomit-frame-pointer -ffast-math -funroll-loops")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -ffast-math")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ffast-math")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fomit-frame-pointer -mmmx -msse -mfpmath=sse -msse2 -ffast-math -ftree-vectorize -fweb -fexpensive-optimizations -frename-registers")
else (${ARCH} STREQUAL "x86_64")
if (NOT STANDALONE)
set(MARCH_FLAG " -march=pentium4")
@@ -328,7 +327,7 @@ else (STANDALONE)
glib-2.0
gstreamer-0.10
gtk-2.0
freetype2
llfreetype2
pango-1.0
)
endif (STANDALONE)

View File

@@ -40,11 +40,3 @@ link_directories(
${VORBISFILE_LIBRARY_DIRS}
${OGG_LIBRARY_DIRS}
)
set(LLAUDIO_VORBIS_LIBRARIES
${VORBISENC_LIBRARIES}
${VORBISFILE_LIBRARIES}
${VORBIS_LIBRARIES}
${OGG_LIBRARIES}
)

View File

@@ -7,8 +7,10 @@ set(Boost_FIND_REQUIRED ON)
if (STANDALONE)
include(FindBoost)
set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.40.0 COMPONENTS date_time filesystem program_options regex system thread wave)
set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
set(BOOST_REGEX_LIBRARY boost_regex-mt)
set(BOOST_SYSTEM_LIBRARY boost_system-mt)
else (STANDALONE)
use_prebuilt_binary(boost)
set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
@@ -16,36 +18,36 @@ else (STANDALONE)
if (WINDOWS)
set(BOOST_VERSION 1_45)
# SNOW-788
# 00-Common.cmake alreay sets MSVC_SUFFIX to be correct for the VS we are using eg VC71, VC80, VC90 etc
# The precompiled boost libs for VC71 use a different suffix to VS80 and VS90
# This code should ensure the cmake rules are valid for any VS being used in future as long as the approprate
# boost libs are avaiable - RC.
if (MSVC71)
set(BOOST_OPTIM_SUFFIX mt-s)
set(BOOST_DEBUG_SUFFIX mt-sgd)
else (MSVC71)
set(BOOST_OPTIM_SUFFIX mt)
set(BOOST_DEBUG_SUFFIX mt-gd)
endif (MSVC71)
set(Boost_PROGRAM_OPTIONS_LIBRARY
# SNOW-788
# 00-Common.cmake alreay sets MSVC_SUFFIX to be correct for the VS we are using eg VC71, VC80, VC90 etc
# The precompiled boost libs for VC71 use a different suffix to VS80 and VS90
# This code should ensure the cmake rules are valid for any VS being used in future as long as the approprate
# boost libs are avaiable - RC.
if (MSVC71)
set(BOOST_OPTIM_SUFFIX mt-s)
set(BOOST_DEBUG_SUFFIX mt-sgd)
else (MSVC71)
set(BOOST_OPTIM_SUFFIX mt)
set(BOOST_DEBUG_SUFFIX mt-gd)
endif (MSVC71)
set(BOOST_PROGRAM_OPTIONS_LIBRARY
optimized libboost_program_options-vc${MSVC_SUFFIX}-${BOOST_OPTIM_SUFFIX}-${BOOST_VERSION}
debug libboost_program_options-vc${MSVC_SUFFIX}-${BOOST_DEBUG_SUFFIX}-${BOOST_VERSION})
set(Boost_REGEX_LIBRARY
set(BOOST_REGEX_LIBRARY
optimized libboost_regex-vc${MSVC_SUFFIX}-${BOOST_OPTIM_SUFFIX}-${BOOST_VERSION}
debug libboost_regex-vc${MSVC_SUFFIX}-${BOOST_DEBUG_SUFFIX}-${BOOST_VERSION})
elseif (DARWIN)
set(Boost_FILESYSTEM_LIBRARY boost_filesystem)
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)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options)
set(BOOST_REGEX_LIBRARY boost_regex)
set(BOOST_SYSTEM_LIBRARY boost_system)
elseif (LINUX)
set(Boost_FILESYSTEM_LIBRARY boost_filesystem-mt)
set(Boost_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
set(Boost_REGEX_LIBRARY boost_regex-mt)
set(Boost_SYSTEM_LIBRARY boost_system-mt)
set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
set(BOOST_REGEX_LIBRARY boost_regex-mt)
set(BOOST_SYSTEM_LIBRARY boost_system-mt)
endif (WINDOWS)
endif (STANDALONE)

View File

@@ -1,7 +1,7 @@
# -*- cmake -*-
include(Prebuilt)
set(CURL_FIND_QUIETLY ON)
set(CURL_FIND_QUIETLY OFF)
set(CURL_FIND_REQUIRED ON)
if (STANDALONE)

View File

@@ -8,7 +8,7 @@ if(INSTALL_PROPRIETARY)
endif(INSTALL_PROPRIETARY)
find_library(FMODEX_LIBRARY
NAMES fmodex fmodexL fmodex_vc fmodexL_vc
NAMES fmodex fmodex_vc fmodexL_vc
PATHS
optimized ${ARCH_PREBUILT_DIRS_RELEASE}
debug ${ARCH_PREBUILT_DIRS_DEBUG}
@@ -26,25 +26,26 @@ if (NOT FMODEX_LIBRARY)
${FMODEX_SDK_DIR}
)
endif(FMODEX_SDK_DIR)
if(WINDOWS AND NOT FMODEX_LIBRARY)
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
find_library(FMODEX_LIBRARY
fmodex_vc fmodexL_vc
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
find_library(FMODEX_LIBRARY
fmodex_vc fmodexL_vc
PATHS
${FMODEX_PROG_DIR}/api/lib
${FMODEX_PROG_DIR}/api
${FMODEX_PROG_DIR}
${FMODEX_PROG_DIR}/api
${FMODEX_PROG_DIR}
)
if(FMODEX_LIBRARY)
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR})
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR} CACHE PATH "Path to the FMOD Ex SDK." FORCE)
endif(FMODEX_LIBRARY)
if(FMODEX_LIBRARY)
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR})
set(FMODEX_SDK_DIR ${FMODEX_PROG_DIR} CACHE PATH "Path to the FMOD Ex SDK." FORCE)
endif(FMODEX_LIBRARY)
endif(WINDOWS AND NOT FMODEX_LIBRARY)
endif (NOT FMODEX_LIBRARY)
find_path(FMODEX_INCLUDE_DIR fmod.hpp
find_path(FMODEX_INCLUDE_DIR fmod.h
${LIBS_PREBUILT_DIR}/include/fmodex
${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodex
${FMODEX_SDK_DIR}/api/inc
@@ -52,11 +53,6 @@ find_path(FMODEX_INCLUDE_DIR fmod.hpp
${FMODEX_SDK_DIR}
)
if(DARWIN)
set(FMODEX_ORIG_LIBRARY "${FMODEX_LIBRARY}")
set(FMODEX_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/libfmodex.dylib")
endif(DARWIN)
if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
set(FMODEX ON CACHE BOOL "Use closed source FMOD Ex sound library.")
else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)

View File

@@ -5,7 +5,7 @@ FIND_PATH(HUNSPELL_INCLUDE_DIR hunspell.hxx
/usr/include
)
SET(HUNSPELL_NAMES ${HUNSPELL_NAMES} hunspell hunspell-1.2 hunspell-1.3)
SET(HUNSPELL_NAMES ${HUNSPELL_NAMES} hunspell hunspell-1.2)
FIND_LIBRARY(HUNSPELL_LIBRARY
NAMES ${HUNSPELL_NAMES}
PATHS /usr/lib /usr/local/lib

View File

@@ -8,5 +8,5 @@ set(LLVFS_INCLUDE_DIRS
set(LLVFS_LIBRARIES
llvfs
${Boost_REGEX_LIBRARY}
${BOOST_REGEX_LIBRARY}
)

View File

@@ -0,0 +1,7 @@
# -*- cmake -*-
set(LLXUIXML_INCLUDE_DIRS
${LIBS_OPEN_DIR}/llxuixml
)
set(LLXUIXML_LIBRARIES llxuixml)

View File

@@ -15,5 +15,5 @@ else (STANDALONE)
else(LINUX)
set(PNG_LIBRARIES png15)
endif()
set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/)
set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libpng15)
endif (STANDALONE)

View File

@@ -34,6 +34,8 @@ if(NOT WORD_SIZE EQUAL 32)
endif(WINDOWS)
endif (NOT WORD_SIZE EQUAL 32)
add_definitions(-Dcwdebug_EXPORTS)
list(APPEND cwdebug_SOURCE_FILES ${cwdebug_HEADER_FILES})
add_library (cwdebug ${cwdebug_SOURCE_FILES})

View File

@@ -173,6 +173,8 @@ void stop_recording_backtraces(void)
channel_ct backtrace DDCN("BACKTRACE"); //!< This debug channel is used for backtraces.
channel_ct statemachine DDCN("STATEMACHINE"); //!< This debug channel is used for output related to class AIStateMachine.
channel_ct caps DDCN("CAPS"); //!< This debug channel is used for output related to Capabilities.
channel_ct curl DDCN("CURL"); //!< This debug channel is used for output related to Curl.
channel_ct curlio DDCN("CURLIO"); //!< This debug channel is used to print debug output of libcurl.
} // namespace dc
} // namespace DEBUGCHANNELS
@@ -411,4 +413,71 @@ void cwdebug_backtrace(int n)
}
#endif
#endif // CWDEBUG
#elif defined(DEBUG_CURLIO)
#include "debug.h"
namespace debug
{
libcwd_do_type const libcw_do;
CWD_TLS int Indent::S_indentation;
std::ostream& operator<<(std::ostream& os, Indent::print_nt)
{
if (Indent::S_indentation)
os << std::string(Indent::S_indentation, ' ');
return os;
}
std::ostream& operator<<(std::ostream& os, libcwd::buf2str const& b2s)
{
static char const c2s_tab[7] = { 'a', 'b', 't', 'n', 'v', 'f', 'r' };
size_t size = b2s.mSize;
for (char const* p1 = b2s.mBuf; size > 0; --size, ++p1)
{
char c =*p1;
if ((c > 31 && c != 92 && c != 127) || (unsigned char)c > 159)
os.put(c);
else
{
os.put('\\');
if (c > 6 && c < 14)
{
os.put(c2s_tab[c - 7]);
return os;
}
else if (c == 27)
{
os.put('e');
return os;
}
else if (c == '\\')
{
os.put('\\');
return os;
}
std::ostream::char_type old_fill = os.fill('0');
std::ios_base::fmtflags old_flgs = os.flags();
os.width(3);
os << std::oct << (int)((unsigned char)c);
os.setf(old_flgs);
os.fill(old_fill);
}
}
return os;
}
namespace dc
{
fake_channel const warning(1, "WARNING ");
fake_channel const curl(1, "CURL ");
fake_channel const curlio(1, "CURLIO ");
fake_channel const statemachine(1, "STATEMACHINE");
fake_channel const notice(1, "NOTICE ");
} // namespace dc
} // namespace debug
#endif

View File

@@ -27,6 +27,113 @@
#ifndef CWDEBUG
#ifdef DEBUG_CURLIO
#if LL_WINDOWS
#define CWD_DLLEXPORT __declspec(dllexport)
#define CWD_DLLIMPORT __declspec(dllimport)
#elif LL_LINUX
#define CWD_DLLEXPORT __attribute__ ((visibility("default")))
#define CWD_DLLIMPORT
#else
#define CWD_DLLEXPORT
#define CWD_DLLIMPORT
#endif // LL_WINDOWS
#if LL_COMMON_LINK_SHARED
#if defined(cwdebug_EXPORTS) || defined(llcommon_EXPORTS)
#define CWD_API CWD_DLLEXPORT
#else // cwdebug_EXPORTS
#define CWD_API CWD_DLLIMPORT
#endif // cwdebug_EXPORTS
#else // LL_COMMON_LINK_SHARED
#error LL_COMMON_LINK_SHARED not defined
#endif // LL_COMMON_LINK_SHARED
// If CWDEBUG is not defined, but DEBUG_CURLIO is, then replace
// some of the cwd macro's with something that generates viewer
// specific debug output. Note that this generates a LOT of
// output and should not normally be defined.
#include <string>
#if LL_WINDOWS
#define CWD_API_TLS __declspec(thread)
#define CWD_TLS __declspec(thread)
#else
#define CWD_API_TLS CWD_API __thread
#define CWD_TLS __thread
#endif
namespace debug {
namespace libcwd {
struct buf2str {
buf2str(char const* buf, int size) : mBuf(buf), mSize(size) { }
char const* mBuf;
int mSize;
};
} // namespace libcwd
inline void init() { }
struct libcwd_do_type {
void on() const { }
};
extern CWD_API libcwd_do_type const libcw_do;
struct Indent {
int M_indent;
static CWD_API_TLS int S_indentation;
enum CWD_API print_nt { print };
CWD_API Indent(int indent) : M_indent(indent) { S_indentation += M_indent; }
CWD_API ~Indent() { S_indentation -= M_indent; }
};
extern CWD_API std::ostream& operator<<(std::ostream& os, libcwd::buf2str const& b2s);
extern CWD_API std::ostream& operator<<(std::ostream& os, Indent::print_nt);
namespace dc {
struct fake_channel {
int mOn;
char const* mLabel;
fake_channel(int on, char const* label) : mOn(on), mLabel(label) { }
fake_channel(void) : mOn(0) { }
bool is_on() const { return !!mOn; }
bool is_off() const { return !mOn; }
void on() const { }
void off() const { }
};
extern CWD_API fake_channel const warning;
extern CWD_API fake_channel const curl;
extern CWD_API fake_channel const curlio;
extern CWD_API fake_channel const statemachine;
extern CWD_API fake_channel const notice;
} // namespace dc
} // namespace debug
#define Debug(x) do { using namespace debug; x; } while(0)
#define Dout(a, b) do { using namespace debug; if ((a).mOn) { llinfos_nf << (a).mLabel << ": " << Indent::print << b << llendl; } } while(0)
#define DoutEntering(a, b) \
int __slviewer_debug_indentation = 2; \
{ \
using namespace debug; \
if ((a).mOn) \
llinfos_nf << (a).mLabel << ": " << Indent::print << "Entering " << b << llendl; \
else \
__slviewer_debug_indentation = 0; \
} \
debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation);
#else // !DEBUG_CURLIO
#define Debug(x)
#define Dout(a, b)
#define DoutEntering(a, b)
#endif // !DEBUG_CURLIO
#ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info.
#include <iostream>
@@ -36,9 +143,6 @@
#define AllocTag2(p, desc)
#define AllocTag_dynamic_description(p, x)
#define AllocTag(p, x)
#define Debug(x)
#define Dout(a, b)
#define DoutEntering(a, b)
#define DoutFatal(a, b) LibcwDoutFatal(::std, , a, b)
#define ForAllDebugChannels(STATEMENT)
#define ForAllDebugObjects(STATEMENT)
@@ -118,6 +222,8 @@ extern CWD_API channel_ct sdl;
extern CWD_API channel_ct backtrace;
extern CWD_API channel_ct statemachine;
extern CWD_API channel_ct caps;
extern CWD_API channel_ct curl;
extern CWD_API channel_ct curlio;
#endif

View File

@@ -111,4 +111,10 @@ list(APPEND llaudio_SOURCE_FILES ${llaudio_HEADER_FILES})
add_library (llaudio ${llaudio_SOURCE_FILES})
add_dependencies(llaudio prepare)
target_link_libraries(
llaudio
${VORBISENC_LIBRARIES}
${VORBISFILE_LIBRARIES}
${VORBIS_LIBRARIES}
${OGG_LIBRARIES}
)

View File

@@ -43,11 +43,11 @@
#include "lluuid.h"
#include "llframetimer.h"
#include "llassettype.h"
#include "llextendedstatus.h"
#include "lllistener.h"
const F32 LL_WIND_UPDATE_INTERVAL = 0.1f;
const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water
const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;

View File

@@ -72,8 +72,6 @@ bool attemptDelayLoad()
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
{
mInited = false;
@@ -132,9 +130,9 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
//result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE);
//if(Check_FMOD_Error(result, "FMOD::Memory_Initialize"))
// return false;
result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE);
if(Check_FMOD_Error(result, "FMOD::Memory_Initialize"))
return false;
result = FMOD::System_Create(&mSystem);
if(Check_FMOD_Error(result, "FMOD::System_Create"))
@@ -161,13 +159,7 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
U32 fmod_flags = FMOD_INIT_NORMAL;
if(mEnableProfiler)
{
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
}
#if LL_LINUX
bool audio_ok = false;
@@ -612,9 +604,6 @@ void LLAudioChannelFMODEX::play()
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
getSource()->setPlayedOnce(true);
if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()])
mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]);
}

View File

@@ -44,7 +44,6 @@ namespace FMOD
{
class System;
class Channel;
class ChannelGroup;
class Sound;
class DSP;
}
@@ -84,9 +83,6 @@ protected:
FMOD::DSP *mWindDSP;
FMOD::System *mSystem;
bool mEnableProfiler;
public:
static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
};

View File

@@ -106,15 +106,6 @@ void LLListener_FMODEX::commitDeferredChanges()
void LLListener_FMODEX::setRolloffFactor(F32 factor)
{
//An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment.
//Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
//In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call.
if(mRolloffFactor != factor)
{
LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f);
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL);
}
mRolloffFactor = factor;
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
}

View File

@@ -172,6 +172,7 @@ void LLStreamingAudio_FMODEX::update()
if(mFMODInternetStreamChannelp)
{
//llinfos << "progress = " << progress << llendl;
if(!mMetaData)
mMetaData = new LLSD;
@@ -395,12 +396,12 @@ LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, con
{
mInternetStreamURL = url;
/*FMOD_CREATESOUNDEXINFO exinfo;
FMOD_CREATESOUNDEXINFO exinfo;
memset(&exinfo,0,sizeof(exinfo));
exinfo.cbsize = sizeof(exinfo);
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_MPEG; //Hint to speed up loading.
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream);
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, &exinfo, &mInternetStream);
if (result!= FMOD_OK)
{
@@ -483,4 +484,4 @@ void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuf
settings.cbsize=sizeof(settings);
settings.defaultDecodeBufferSize = decodebuffertime;//ms
mSystem->setAdvancedSettings(&settings);
}
}

View File

@@ -38,6 +38,7 @@
#include "llcharacter.h"
#include "llstring.h"
#include "llfasttimer.h"
#define SKEL_HEADER "Linden Skeleton 1.0"
@@ -193,14 +194,19 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
//-----------------------------------------------------------------------------
// updateMotions()
//-----------------------------------------------------------------------------
static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation");
static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
void LLCharacter::updateMotions(e_update_t update_type)
{
if (update_type == HIDDEN_UPDATE)
{
LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION);
mMotionController.updateMotionsMinimal();
}
else
{
LLFastTimer t(FTM_UPDATE_ANIMATION);
// unpause if the number of outstanding pause requests has dropped to the initial one
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
{

View File

@@ -250,9 +250,9 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
head_rot_local = nlerp(head_slerp_amt, mLastHeadRot, head_rot_local);
mLastHeadRot = head_rot_local;
// Set the head rotation.
if(mNeckState->getJoint() && mNeckState->getJoint()->getParent())
if(mNeckState->getJoint() && mNeckState->getJoint()->getParent()) //Guess this has crashed? Taken from snowglobe -Shyotl
{
// Set the head rotation.
LLQuaternion torsoRotLocal = mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
head_rot_local = head_rot_local * ~torsoRotLocal;
mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );

View File

@@ -637,9 +637,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
motionp->fadeIn();
}
//**********************
// **********************
// MOTION INACTIVE
//**********************
// **********************
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
{
// this motion has gone on too long, deactivate it
@@ -659,9 +659,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
}
}
//**********************
// **********************
// MOTION EASE OUT
//**********************
// **********************
else if (motionp->isStopped() && mAnimTime > motionp->getStopTime())
{
// is this the first iteration in the ease out phase?
@@ -684,9 +684,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
}
//**********************
// **********************
// MOTION ACTIVE
//**********************
// **********************
else if (mAnimTime > motionp->mActivationTimestamp + motionp->getEaseInDuration())
{
posep->setWeight(motionp->getFadeWeight());
@@ -707,9 +707,9 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
}
//**********************
// **********************
// MOTION EASE IN
//**********************
// **********************
else if (mAnimTime >= motionp->mActivationTimestamp)
{
if (mLastTime < motionp->mActivationTimestamp)
@@ -837,7 +837,6 @@ void LLMotionController::updateMotions(bool force_update)
}
updateLoadingMotions();
return;
}

View File

@@ -93,7 +93,6 @@ class LLVisualParam
{
public:
typedef boost::function<LLVisualParam*(S32)> visual_param_mapper;
LLVisualParam();
virtual ~LLVisualParam();

View File

@@ -15,8 +15,8 @@ include_directories(
)
set(llcommon_SOURCE_FILES
aiframetimer.cpp
imageids.cpp
aiframetimer.cpp
imageids.cpp
indra_constants.cpp
llallocator.cpp
llallocator_heap_profile.cpp
@@ -24,7 +24,7 @@ set(llcommon_SOURCE_FILES
llapr.cpp
llaprpool.cpp
llassettype.cpp
llavatarname.cpp
llavatarname.cpp
llbase32.cpp
llbase64.cpp
llcommon.cpp
@@ -53,7 +53,6 @@ set(llcommon_SOURCE_FILES
llformat.cpp
llframetimer.cpp
llheartbeat.cpp
llinitparam.cpp
llinstancetracker.cpp
llindraconfigfile.cpp
llliveappconfig.cpp
@@ -172,7 +171,6 @@ set(llcommon_HEADER_FILES
llheartbeat.h
llhttpstatuscodes.h
llindexedqueue.h
llinitparam.h
llinstancetracker.h
llindraconfigfile.h
llkeythrottle.h
@@ -214,7 +212,6 @@ set(llcommon_HEADER_FILES
llsingleton.h
llskiplist.h
llskipmap.h
llsortedvector.h
llstack.h
llstacktrace.h
llstat.h
@@ -229,7 +226,6 @@ set(llcommon_HEADER_FILES
llthreadsafequeue.h
lltimer.h
lltreeiterators.h
lltypeinfolookup.h
lluri.h
lluuid.h
lluuidhashmap.h
@@ -265,7 +261,7 @@ target_link_libraries(
${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES}
${Boost_REGEX_LIBRARY}
${BOOST_REGEX_LIBRARY}
${CWDEBUG_LIBRARIES}
${CORESERVICES_LIBRARY}
)

View File

@@ -33,11 +33,6 @@
#ifndef LL_LINDEN_COMMON_H
#define LL_LINDEN_COMMON_H
// *NOTE: Please keep includes here to a minimum!
//
// Files included here are included in every library .cpp file and
// are not precompiled.
#include "cwdebug.h"
#if defined(LL_WINDOWS) && defined(_DEBUG)
@@ -60,11 +55,34 @@
#include <ctime>
#include <iosfwd>
// Work around Microsoft compiler warnings in STL headers
#ifdef LL_WINDOWS
#pragma warning (disable : 4702) // unreachable code
#pragma warning (disable : 4244) // conversion from time_t to S32
#endif // LL_WINDOWS
// *TODO: Eliminate these, most library .cpp files don't need them.
// Add them to llviewerprecompiledheaders.h if necessary.
#include <list>
#include <map>
#include <vector>
#include <string>
#ifdef LL_WINDOWS
// Reenable warnings we disabled above
#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4
// moved msvc warnings to llpreprocessor.h *TODO - delete this comment after merge conflicts are unlikely -brad
#endif // LL_WINDOWS
// Linden only libs in alpha-order other than stdtypes.h
// *NOTE: Please keep includes here to a minimum, see above.
#include "stdtypes.h"
#include "lldefs.h"
#include "llerror.h"
#include "llextendedstatus.h"
// Don't do this, adds 15K lines of header code to every library file.
//#include "llfasttimer.h"
#include "llfile.h"
#include "llformat.h"
#endif

View File

@@ -297,6 +297,20 @@ void LLApp::startErrorThread()
}
}
void LLApp::stopErrorThread()
{
LLApp::setStopped(); // Signal error thread that we stopped.
int count = 0;
while (mThreadErrorp && !mThreadErrorp->isStopped() && ++count < 100)
{
ms_sleep(10);
}
if (mThreadErrorp && !mThreadErrorp->isStopped())
{
llwarns << "Failed to stop Error Thread." << llendl;
}
}
void LLApp::setErrorHandler(LLAppErrorHandler handler)
{
LLApp::sErrorHandler = handler;

View File

@@ -264,6 +264,10 @@ protected:
* @ brief This method is called once as soon as logging is initialized.
*/
void startErrorThread();
/**
* @brief This method is called at the end, just prior to deinitializing curl.
*/
void stopErrorThread();
private:
void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions)

View File

@@ -148,7 +148,7 @@ const char *LLAssetType::lookup(LLAssetType::EType asset_type)
}
// static
LLAssetType::EType LLAssetType::lookup(const char* name)
LLAssetType::EType LLAssetType::lookup( const char* name )
{
return lookup(ll_safe_string(name));
}
@@ -186,7 +186,7 @@ const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type)
}
// static
LLAssetType::EType LLAssetType::lookupHumanReadable(const char* name)
LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name )
{
return lookupHumanReadable(ll_safe_string(name));
}
@@ -208,9 +208,12 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_
return AT_NONE;
}
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
// static
bool LLAssetType::lookupCanLink(EType asset_type)
{
//Check that enabling all these other types as linkable doesn't break things.
const LLAssetDictionary *dict = LLAssetDictionary::getInstance();
const AssetEntry *entry = dict->lookup(asset_type);
if (entry)
@@ -218,6 +221,9 @@ bool LLAssetType::lookupCanLink(EType asset_type)
return entry->mCanLink;
}
return false;
/*return (asset_type == AT_CLOTHING || asset_type == AT_OBJECT || asset_type == AT_CATEGORY ||
asset_type == AT_BODYPART || asset_type == AT_GESTURE);*/
}
// static
@@ -262,3 +268,4 @@ bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type)
}
return false;
}

View File

@@ -963,10 +963,14 @@ namespace LLError
settings_w->shouldLogCallCounter += 1;
std::string class_name = className(site.mClassInfo);
std::string function_name = functionName(site.mFunction);
if (site.mClassInfo != typeid(NoClassInfo))
std::string function_name;
if (site.mFunction)
{
function_name = class_name + "::" + function_name;
function_name = functionName(site.mFunction);
if (site.mClassInfo != typeid(NoClassInfo))
{
function_name = class_name + "::" + function_name;
}
}
ELevel compareLevel = settings_w->defaultLevel;
@@ -976,7 +980,7 @@ namespace LLError
// So, in increasing order of importance:
// Default < Broad Tag < File < Class < Function < Narrow Tag
((site.mNarrowTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mNarrowTag, compareLevel) : false)
|| checkLevelMap(settings_w->functionLevelMap, function_name, compareLevel)
|| (site.mFunction && checkLevelMap(settings_w->functionLevelMap, function_name, compareLevel))
|| checkLevelMap(settings_w->classLevelMap, class_name, compareLevel)
|| checkLevelMap(settings_w->fileLevelMap, abbreviateFile(site.mFile), compareLevel)
|| ((site.mBroadTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mBroadTag, compareLevel) : false);
@@ -1083,8 +1087,8 @@ namespace LLError
default: prefix << "XXX"; break;
};
bool need_function = true;
if (site.mBroadTag && *site.mBroadTag != '\0')
bool need_function = site.mFunction;
if (need_function && site.mBroadTag && *site.mBroadTag != '\0')
{
prefix << "(\"" << site.mBroadTag << "\")";
#if LL_DEBUG
@@ -1112,7 +1116,7 @@ namespace LLError
#if LL_WINDOWS
// DevStudio: __FUNCTION__ already includes the full class name
#else
if (need_function && site.mClassInfo != typeid(NoClassInfo))
if (site.mClassInfo != typeid(NoClassInfo))
{
prefix << className(site.mClassInfo) << "::";
}

View File

@@ -238,10 +238,10 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
See top of file for common usage.
*/
#define lllog(level, broadTag, narrowTag, once) \
#define lllog(level, broadTag, narrowTag, once, nofunction) \
do { \
static LLError::CallSite _site( \
level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), nofunction ? NULL : __FUNCTION__, broadTag, narrowTag, once);\
if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
@@ -255,33 +255,39 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
} while(0)
// DEPRECATED: Use the new macros that allow tags and *look* like macros.
#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false)
#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false)
#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false)
#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false)
#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false, false)
#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false, false)
#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false, false)
#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false, false)
#define llcont (*_out)
// No function name
#define lldebugs_nf lllog(LLError::LEVEL_DEBUG, NULL, NULL, false, true)
#define llinfos_nf lllog(LLError::LEVEL_INFO, NULL, NULL, false, true)
#define llwarns_nf lllog(LLError::LEVEL_WARN, NULL, NULL, false, true)
#define llerrs_nf lllog(LLError::LEVEL_ERROR, NULL, NULL, false, true)
// NEW Macros for debugging, allow the passing of a string tag
// One Tag
#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false)
#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false)
#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false)
#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false)
#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false, false)
#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false, false)
#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false, false)
#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false, false)
// Two Tags
#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false)
#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false)
#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false)
#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false)
#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false, false)
#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false, false)
#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false, false)
#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false, false)
// Only print the log message once (good for warnings or infos that would otherwise
// spam the log file over and over, such as tighter loops).
#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true)
#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true)
#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true)
#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true)
#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true)
#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true)
#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true, false)
#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true, false)
#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true, false)
#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true, false)
#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true, false)
#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true, false)
#define LL_ENDL llendl
#define LL_CONT (*_out)

View File

@@ -114,7 +114,7 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
: liru_slashpos2 == std::string::npos ? std::string(__FILE__)/*Apparently, we're in / or perhaps the top of the drive, print as is*/\
: std::string(__FILE__).substr(1+liru_slashpos2))/*print foo/bar.cpp or perhaps foo\bar.cpp*/
#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs <<"\nASSERT(" #func ")\nfile:"<<liru_assert_strip<<" line:"<<__LINE__ << llendl;
#define llassert_always(func) do { if (LL_UNLIKELY(!(func))) llerrs << "\nASSERT(" #func ")\nfile:" << liru_assert_strip << " line:" << std::dec << __LINE__ << llendl; } while(0)
#ifdef SHOW_ASSERT
#define llassert(func) llassert_always(func)

View File

@@ -194,17 +194,17 @@ void LLErrorThread::run()
if (LLApp::isError())
{
// The app is in an error state, run the application's error handler.
//llinfos << "thread_error - An error has occurred, running error callback!" << llendl;
Dout(dc::notice, "thread_error - An error has occurred, running error callback!");
// Run the error handling callback
LLApp::runErrorHandler();
}
else
{
// Everything is okay, a clean exit.
//llinfos << "thread_error - Application exited cleanly" << llendl;
Dout(dc::notice, "thread_error - Application exited cleanly");
}
//llinfos << "thread_error - Exiting" << llendl;
Dout(dc::notice, "thread_error - Exiting");
LLApp::sErrorThreadRunning = FALSE;
}

View File

@@ -182,11 +182,6 @@ std::string LLFastTimer::sLogName = "";
BOOL LLFastTimer::sMetricLog = FALSE;
LLMutex* LLFastTimer::sLogLock = NULL;
std::queue<LLSD> LLFastTimer::sLogQueue;
const int LLFastTimer::NamedTimer::HISTORY_NUM = 300;
#if LL_WINDOWS
#define USE_RDTSC 1
#endif
std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL;
U64 LLFastTimer::sTimerCycles = 0;
@@ -385,9 +380,7 @@ void LLFastTimer::updateCachedPointers()
}
// See lltimer.cpp.
#if USE_RDTSC
std::string LLFastTimer::sClockType = "rdtsc";
#elif LL_LINUX || LL_DARWIN || LL_SOLARIS
#if LL_LINUX || LL_DARWIN || LL_SOLARIS
std::string LLFastTimer::sClockType = "gettimeofday";
#elif LL_WINDOWS
std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
@@ -398,9 +391,6 @@ std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
//static
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
{
#if USE_RDTSC
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
#else
static bool firstcall = true;
static U64 sCPUClockFrequency;
if (firstcall)
@@ -408,7 +398,6 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
sCPUClockFrequency = calc_clock_frequency();
firstcall = false;
}
#endif
return sCPUClockFrequency >> 8;
}
@@ -436,12 +425,16 @@ LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
mFrameStateIndex = frame_state_list.size();
getFrameStateList().push_back(FrameState(this));
mCountHistory.resize(HISTORY_NUM);
mCallHistory.resize(HISTORY_NUM);
mCountHistory = new U32[HISTORY_NUM];
memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
mCallHistory = new U32[HISTORY_NUM];
memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
}
LLFastTimer::NamedTimer::~NamedTimer()
{
delete[] mCountHistory;
delete[] mCallHistory;
}
std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
@@ -634,12 +627,10 @@ void LLFastTimer::NamedTimer::accumulateTimings()
// update timer history
int hidx = cur_frame % HISTORY_NUM;
int weight = llmin(100, cur_frame);
timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
timerp->mCountAverage = ((F64)timerp->mCountAverage * weight + (F64)timerp->mTotalTimeCounter) / (weight+1);
timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
timerp->mCallAverage = ((F64)timerp->mCallAverage * weight + (F64)timerp->getFrameState().mCalls) / (weight+1);
timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
}
}
}
@@ -775,10 +766,8 @@ void LLFastTimer::NamedTimer::reset()
timer.mCountAverage = 0;
timer.mCallAverage = 0;
timer.mCountHistory.clear();
timer.mCountHistory.resize(HISTORY_NUM);
timer.mCallHistory.clear();
timer.mCallHistory.resize(HISTORY_NUM);
memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
}
}
@@ -857,8 +846,7 @@ void LLFastTimer::nextFrame()
if (!sPauseHistory)
{
NamedTimer::processTimes();
sLastFrameIndex = sCurFrameIndex;
++sCurFrameIndex;
sLastFrameIndex = sCurFrameIndex++;
}
// get ready for next frame
@@ -949,38 +937,6 @@ LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
// Important note: These implementations must be FAST!
//
#if USE_RDTSC
U32 LLFastTimer::getCPUClockCount32()
{
U32 ret_val;
__asm
{
_emit 0x0f
_emit 0x31
shr eax,8
shl edx,24
or eax, edx
mov dword ptr [ret_val], eax
}
return ret_val;
}
// return full timer value, *not* shifted by 8 bits
U64 LLFastTimer::getCPUClockCount64()
{
U64 ret_val;
__asm
{
_emit 0x0f
_emit 0x31
mov eax,eax
mov edx,edx
mov dword ptr [ret_val+4], edx
mov dword ptr [ret_val], eax
}
return ret_val;
}
#else
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
U32 LLFastTimer::getCPUClockCount32()
@@ -992,4 +948,4 @@ U64 LLFastTimer::getCPUClockCount64()
{
return get_clock_count();
}
#endif

View File

@@ -66,7 +66,7 @@ public:
public:
~NamedTimer();
static const int HISTORY_NUM;
enum { HISTORY_NUM = 300 };
const std::string& getName() const { return mName; }
NamedTimer* getParent() const { return mParent; }
@@ -82,8 +82,8 @@ public:
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
bool getCollapsed() const { return mCollapsed; }
U32 getCountAverage() const;
U32 getCallAverage() const;
U32 getCountAverage() const; //{ return mCountAverage }
U32 getCallAverage() const; //{ return mCallAverage }
U32 getHistoricalCount(S32 history_index = 0) const;
U32 getHistoricalCalls(S32 history_index = 0) const;
@@ -122,11 +122,11 @@ public:
U32 mTotalTimeCounter;
F64 mCountAverage;
F64 mCallAverage;
U32 mCountAverage;
U32 mCallAverage;
std::vector<U32> mCountHistory;
std::vector<U32> mCallHistory;
U32* mCountHistory;
U32* mCallHistory;
// tree structure
NamedTimer* mParent; // NamedTimer of caller(parent)
@@ -258,10 +258,11 @@ public:
static CurTimerData sCurTimerData;
static std::string sClockType;
private:
public:
static U32 getCPUClockCount32();
static U64 getCPUClockCount64();
private:
static S32 sCurFrameIndex;
static S32 sLastFrameIndex;
static U64 sLastFrameTime;

View File

@@ -174,7 +174,6 @@ public:
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
return averageCount;
}
// call each time the key wants use
State noteAction(const T& id, S32 weight = 1)
{

View File

@@ -73,15 +73,6 @@ const S32 LSL_PRIM_TEXGEN = 22;
const S32 LSL_PRIM_POINT_LIGHT = 23;
const S32 LSL_PRIM_CAST_SHADOWS = 24;
const S32 LSL_PRIM_GLOW = 25;
const S32 LSL_PRIM_TEXT = 26;
const S32 LSL_PRIM_NAME = 27;
const S32 LSL_PRIM_DESC = 28;
const S32 LSL_PRIM_ROT_LOCAL = 29;
const S32 LSL_PRIM_PHYSICS_SHAPE_TYPE = 30;
const S32 LSL_PRIM_OMEGA = 32;
const S32 LSL_PRIM_POS_LOCAL = 33;
const S32 LSL_PRIM_LINK_TARGET = 34;
const S32 LSL_PRIM_SLICE = 35;
const S32 LSL_PRIM_TYPE_BOX = 0;
const S32 LSL_PRIM_TYPE_CYLINDER= 1;
@@ -141,15 +132,6 @@ const S32 LSL_PRIM_SCULPT_TYPE_MASK = 7;
const S32 LSL_PRIM_SCULPT_FLAG_INVERT = 64;
const S32 LSL_PRIM_SCULPT_FLAG_MIRROR = 128;
const S32 LSL_PRIM_PHYSICS_SHAPE_PRIM = 0;
const S32 LSL_PRIM_PHYSICS_SHAPE_NONE = 1;
const S32 LSL_PRIM_PHYSICS_SHAPE_CONVEX = 2;
const S32 LSL_DENSITY = 1;
const S32 LSL_FRICTION = 2;
const S32 LSL_RESTITUTION = 4;
const S32 LSL_GRAVITY_MULTIPLIER = 8;
const S32 LSL_ALL_SIDES = -1;
const S32 LSL_LINK_ROOT = 1;
const S32 LSL_LINK_FIRST_CHILD = 2;
@@ -207,13 +189,6 @@ const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
const S32 OBJECT_SCRIPT_MEMORY = 11;
const S32 OBJECT_SCRIPT_TIME = 12;
const S32 OBJECT_PRIM_EQUIVALENCE = 13;
const S32 OBJECT_SERVER_COST = 14;
const S32 OBJECT_STREAMING_COST = 15;
const S32 OBJECT_PHYSICS_COST = 16;
// llTextBox() magic token string - yes it's a hack.
char const* const TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!";
// changed() event flags
const U32 CHANGED_NONE = 0x0;
@@ -241,156 +216,4 @@ const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
// Start per-function errors below, starting at 2000:
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
// Memory profiling support
const S32 LSL_PROFILE_SCRIPT_NONE = 0;
const S32 LSL_PROFILE_SCRIPT_MEMORY = 1;
// HTTP responses contents type
const S32 LSL_CONTENT_TYPE_TEXT = 0;
const S32 LSL_CONTENT_TYPE_HTML = 1;
// Ray casting
const S32 LSL_RCERR_UNKNOWN = -1;
const S32 LSL_RCERR_SIM_PERF_LOW = -2;
const S32 LSL_RCERR_CAST_TIME_EXCEEDED = -3;
const S32 LSL_RC_REJECT_TYPES = 0;
const S32 LSL_RC_DETECT_PHANTOM = 1;
const S32 LSL_RC_DATA_FLAGS = 2;
const S32 LSL_RC_MAX_HITS = 3;
const S32 LSL_RC_REJECT_AGENTS = 1;
const S32 LSL_RC_REJECT_PHYSICAL = 2;
const S32 LSL_RC_REJECT_NONPHYSICAL = 4;
const S32 LSL_RC_REJECT_LAND = 8;
const S32 LSL_RC_GET_NORMAL = 1;
const S32 LSL_RC_GET_ROOT_KEY = 2;
const S32 LSL_RC_GET_LINK_NUM = 4;
// Estate management
const S32 LSL_ESTATE_ACCESS_ALLOWED_AGENT_ADD = 4;
const S32 LSL_ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 8;
const S32 LSL_ESTATE_ACCESS_ALLOWED_GROUP_ADD = 16;
const S32 LSL_ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 32;
const S32 LSL_ESTATE_ACCESS_BANNED_AGENT_ADD = 64;
const S32 LSL_ESTATE_ACCESS_BANNED_AGENT_REMOVE = 128;
// Key Frame Motion:
const S32 LSL_KFM_COMMAND = 0;
const S32 LSL_KFM_MODE = 1;
const S32 LSL_KFM_DATA = 2;
const S32 LSL_KFM_FORWARD = 0;
const S32 LSL_KFM_LOOP = 1;
const S32 LSL_KFM_PING_PONG = 2;
const S32 LSL_KFM_REVERSE = 3;
const S32 LSL_KFM_ROTATION = 1;
const S32 LSL_KFM_TRANSLATION = 2;
const S32 LSL_KFM_CMD_PLAY = 0;
const S32 LSL_KFM_CMD_STOP = 1;
const S32 LSL_KFM_CMD_PAUSE = 2;
// Second Life Server/12 12.04.30.255166 constants for llGetAgentList
const S32 AGENT_LIST_PARCEL = 1;
const S32 AGENT_LIST_PARCEL_OWNER = 2;
const S32 AGENT_LIST_REGION = 4;
// --- SL Constants ABOVE this line ---
// --- OpenSim / Aurora-Sim constants Below ---
// OpenSim Constants (\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\LSL_Constants.cs)
// Constants for cmWindlight (\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\CM_Constants.cs)
const S32 CHANGED_ANIMATION = 16384;
const S32 PARCEL_DETAILS_CLAIMDATE = 10; // used by OpenSim osSetParcelDetails
const S32 STATS_TIME_DILATION = 0;
const S32 STATS_SIM_FPS = 1;
const S32 STATS_PHYSICS_FPS = 2;
const S32 STATS_AGENT_UPDATES = 3;
const S32 STATS_ROOT_AGENTS = 4;
const S32 STATS_CHILD_AGENTS = 5;
const S32 STATS_TOTAL_PRIMS = 6;
const S32 STATS_ACTIVE_PRIMS = 7;
const S32 STATS_FRAME_MS = 8;
const S32 STATS_NET_MS = 9;
const S32 STATS_PHYSICS_MS = 10;
const S32 STATS_IMAGE_MS = 11;
const S32 STATS_OTHER_MS = 12;
const S32 STATS_IN_PACKETS_PER_SECOND = 13;
const S32 STATS_OUT_PACKETS_PER_SECOND = 14;
const S32 STATS_UNACKED_BYTES = 15;
const S32 STATS_AGENT_MS = 16;
const S32 STATS_PENDING_DOWNLOADS = 17;
const S32 STATS_PENDING_UPLOADS = 18;
const S32 STATS_ACTIVE_SCRIPTS = 19;
const S32 STATS_SCRIPT_LPS = 20;
// osNPC
const S32 OS_NPC_FLY = 0;
const S32 OS_NPC_NO_FLY = 1;
const S32 OS_NPC_LAND_AT_TARGET = 2;
const S32 OS_NPC_SIT_NOW = 0;
const U32 OS_NPC_CREATOR_OWNED = 0x1;
const U32 OS_NPC_NOT_OWNED = 0x2;
const U32 OS_NPC_SENSE_AS_AGENT = 0x4;
const U32 OS_NPC_RUNNING = 4;
// Lightshare / Windlight
const S32 WL_WATER_COLOR = 0;
const S32 WL_WATER_FOG_DENSITY_EXPONENT = 1;
const S32 WL_UNDERWATER_FOG_MODIFIER = 2;
const S32 WL_REFLECTION_WAVELET_SCALE = 3;
const S32 WL_FRESNEL_SCALE = 4;
const S32 WL_FRESNEL_OFFSET = 5;
const S32 WL_REFRACT_SCALE_ABOVE = 6;
const S32 WL_REFRACT_SCALE_BELOW = 7;
const S32 WL_BLUR_MULTIPLIER = 8;
const S32 WL_BIG_WAVE_DIRECTION = 9;
const S32 WL_LITTLE_WAVE_DIRECTION = 10;
const S32 WL_NORMAL_MAP_TEXTURE = 11;
const S32 WL_HORIZON = 12;
const S32 WL_HAZE_HORIZON = 13;
const S32 WL_BLUE_DENSITY = 14;
const S32 WL_HAZE_DENSITY = 15;
const S32 WL_DENSITY_MULTIPLIER = 16;
const S32 WL_DISTANCE_MULTIPLIER = 17;
const S32 WL_MAX_ALTITUDE = 18;
const S32 WL_SUN_MOON_COLOR = 19;
const S32 WL_AMBIENT = 20;
const S32 WL_EAST_ANGLE = 21;
const S32 WL_SUN_GLOW_FOCUS = 22;
const S32 WL_SUN_GLOW_SIZE = 23;
const S32 WL_SCENE_GAMMA = 24;
const S32 WL_STAR_BRIGHTNESS = 25;
const S32 WL_CLOUD_COLOR = 26;
const S32 WL_CLOUD_XY_DENSITY = 27;
const S32 WL_CLOUD_COVERAGE = 28;
const S32 WL_CLOUD_SCALE = 29;
const S32 WL_CLOUD_DETAIL_XY_DENSITY = 30;
const S32 WL_CLOUD_SCROLL_X = 31;
const S32 WL_CLOUD_SCROLL_Y = 32;
const S32 WL_CLOUD_SCROLL_Y_LOCK = 33;
const S32 WL_CLOUD_SCROLL_X_LOCK = 34;
const S32 WL_DRAW_CLASSIC_CLOUDS = 35;
const S32 WL_SUN_MOON_POSITION = 36;
// Aurora-Sim Constants (\Aurora\AuroraDotNetEngine\APIs\AA_Constants.cs) -->
const S32 BOT_FOLLOW_FLAG_NONE = 0;
const S32 BOT_FOLLOW_FLAG_INDEFINITELY = 1;
const S32 BOT_FOLLOW_WALK = 0;
const S32 BOT_FOLLOW_RUN = 1;
const S32 BOT_FOLLOW_FLY = 2;
const S32 BOT_FOLLOW_TELEPORT = 3;
const S32 BOT_FOLLOW_WAIT = 4;
const S32 BOT_FOLLOW_TRIGGER_HERE_EVENT = 1;
const S32 BOT_FOLLOW_FLAG_FORCEDIRECTPATH = 4;
// string constants from Aurora-Sim
char const* const ENABLE_GRAVITY = "enable_gravity";
char const* const GRAVITY_FORCE_X = "gravity_force_x";
char const* const GRAVITY_FORCE_Y = "gravity_force_y";
char const* const GRAVITY_FORCE_Z = "gravity_force_z";
char const* const ADD_GRAVITY_POINT = "add_gravity_point";
char const* const ADD_GRAVITY_FORCE = "add_gravity_force";
char const* const START_TIME_REVERSAL_SAVING = "start_time_reversal_saving";
char const* const STOP_TIME_REVERSAL_SAVING = "stop_time_reversal_saving";
char const* const START_TIME_REVERSAL = "start_time_reversal";
char const* const STOP_TIME_REVERSAL = "stop_time_reversal";
#endif

View File

@@ -376,24 +376,24 @@ private:
// uses the MSVC compiler intrinsics __cpuid() and __rdtsc().
// Delays for the specified amount of milliseconds
static void _Delay(unsigned int ms)
static void _Delay(unsigned int ms)
{
LARGE_INTEGER freq, c1, c2;
__int64 x;
LARGE_INTEGER freq, c1, c2;
__int64 x;
// Get High-Res Timer frequency
// Get High-Res Timer frequency
if (!QueryPerformanceFrequency(&freq))
return;
// Convert ms to High-Res Timer value
x = freq.QuadPart/1000*ms;
// Get first snapshot of High-Res Timer value
// Get first snapshot of High-Res Timer value
QueryPerformanceCounter(&c1);
do
{
// Get second snapshot
QueryPerformanceCounter(&c2);
// Get second snapshot
QueryPerformanceCounter(&c2);
}while(c2.QuadPart-c1.QuadPart < x);
// Loop while (second-first < x)
}

View File

@@ -52,4 +52,5 @@ private:
LLProcessorInfoImpl* mImpl;
};
#endif // LLPROCESSOR_H
#endif

View File

@@ -251,7 +251,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
// MAIN thread
bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete)
{
llassert (handle != nullHandle())
llassert (handle != nullHandle());
bool res = false;
bool waspaused = isPaused();
bool done = false;

View File

@@ -111,6 +111,8 @@ public:
return mPriority > second.mPriority;
}
virtual void deleteRequest(); // Only method to delete a request
protected:
status_t setStatus(status_t newstatus)
{
@@ -130,7 +132,6 @@ public:
virtual bool processRequest() = 0; // Return true when request has completed
virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted
virtual void deleteRequest(); // Only method to delete a request
void setPriority(U32 pri)
{

View File

@@ -60,9 +60,6 @@ static const char LEGACY_NON_HEADER[] = "<llsd>";
const std::string LLSD_BINARY_HEADER("LLSD/Binary");
const std::string LLSD_XML_HEADER("LLSD/XML");
//used to deflate a gzipped asset (currently used for navmeshes)
#define windowBits 15
#define ENABLE_ZLIB_GZIP 32
/**
* LLSDSerialize
*/
@@ -2175,80 +2172,3 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
free(result);
return true;
}
//This unzip function will only work with a gzip header and trailer - while the contents
//of the actual compressed data is the same for either format (gzip vs zlib ), the headers
//and trailers are different for the formats.
U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size )
{
U8* result = NULL;
U32 cur_size = 0;
z_stream strm;
const U32 CHUNK = 0x4000;
U8 *in = new U8[size];
is.read((char*) in, size);
U8 out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = size;
strm.next_in = in;
S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP );
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR)
{
inflateEnd(&strm);
free(result);
delete [] in;
valid = false;
}
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
free(result);
delete [] in;
valid = false;
break;
}
U32 have = CHUNK-strm.avail_out;
result = (U8*) realloc(result, cur_size + have);
memcpy(result+cur_size, out, have);
cur_size += have;
} while (ret == Z_OK);
inflateEnd(&strm);
delete [] in;
if (ret != Z_STREAM_END)
{
free(result);
valid = false;
return NULL;
}
//result now points to the decompressed LLSD block
{
outsize= cur_size;
valid = true;
}
return result;
}

View File

@@ -755,9 +755,6 @@ public:
LLPointer<LLSDXMLParser> p = new LLSDXMLParser;
return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED);
}
// Line oriented parser, 30% faster than fromXML(), but can
// only be used when you know you have the complete XML
// document available in the stream.
static S32 fromXMLDocument(LLSD& sd, std::istream& str)
{
LLPointer<LLSDXMLParser> p = new LLSDXMLParser();
@@ -794,5 +791,4 @@ public:
//dirty little zip functions -- yell at davep
LL_COMMON_API std::string zip_llsd(LLSD& data);
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size);
#endif // LL_LLSDSERIALIZE_H

View File

@@ -1,152 +0,0 @@
/**
* @file llsortedvector.h
* @author Nat Goodspeed
* @date 2012-04-08
* @brief LLSortedVector class wraps a vector that we maintain in sorted
* order so we can perform binary-search lookups.
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Copyright (c) 2012, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLSORTEDVECTOR_H)
#define LL_LLSORTEDVECTOR_H
#include <vector>
#include <algorithm>
/**
* LLSortedVector contains a std::vector<std::pair> that we keep sorted on the
* first of the pair. This makes insertion somewhat more expensive than simple
* std::vector::push_back(), but allows us to use binary search for lookups.
* It's intended for small aggregates where lookup is far more performance-
* critical than insertion; in such cases a binary search on a small, sorted
* std::vector can be more performant than a std::map lookup.
*/
template <typename KEY, typename VALUE>
class LLSortedVector
{
public:
typedef LLSortedVector<KEY, VALUE> self;
typedef KEY key_type;
typedef VALUE mapped_type;
typedef std::pair<key_type, mapped_type> value_type;
typedef std::vector<value_type> PairVector;
typedef typename PairVector::iterator iterator;
typedef typename PairVector::const_iterator const_iterator;
/// Empty
LLSortedVector() {}
/// Fixed initial size
LLSortedVector(std::size_t size):
mVector(size)
{}
/// Bulk load
template <typename ITER>
LLSortedVector(ITER begin, ITER end):
mVector(begin, end)
{
// Allow caller to dump in a bunch of (pairs convertible to)
// value_type if desired, but make sure we sort afterwards.
std::sort(mVector.begin(), mVector.end());
}
/// insert(key, value)
std::pair<iterator, bool> insert(const key_type& key, const mapped_type& value)
{
return insert(value_type(key, value));
}
/// insert(value_type)
std::pair<iterator, bool> insert(const value_type& pair)
{
typedef std::pair<iterator, bool> iterbool;
iterator found = std::lower_bound(mVector.begin(), mVector.end(), pair,
less<value_type>());
// have to check for end() before it's even valid to dereference
if (found == mVector.end())
{
std::size_t index(mVector.size());
mVector.push_back(pair);
// don't forget that push_back() invalidates 'found'
return iterbool(mVector.begin() + index, true);
}
if (found->first == pair.first)
{
return iterbool(found, false);
}
// remember that insert() invalidates 'found' -- save index
std::size_t index(found - mVector.begin());
mVector.insert(found, pair);
// okay, convert from index back to iterator
return iterbool(mVector.begin() + index, true);
}
iterator begin() { return mVector.begin(); }
iterator end() { return mVector.end(); }
const_iterator begin() const { return mVector.begin(); }
const_iterator end() const { return mVector.end(); }
bool empty() const { return mVector.empty(); }
std::size_t size() const { return mVector.size(); }
/// find
iterator find(const key_type& key)
{
iterator found = std::lower_bound(mVector.begin(), mVector.end(),
value_type(key, mapped_type()),
less<value_type>());
if (found == mVector.end() || found->first != key)
return mVector.end();
return found;
}
const_iterator find(const key_type& key) const
{
return const_cast<self*>(this)->find(key);
}
private:
// Define our own 'less' comparator so we can specialize without messing
// with std::less.
template <typename T>
struct less: public std::less<T> {};
// Specialize 'less' for an LLSortedVector::value_type involving
// std::type_info*. This is one of LLSortedVector's foremost use cases. We
// specialize 'less' rather than just defining a specific comparator
// because LLSortedVector should be usable for other key_types as well.
template <typename T>
struct less< std::pair<std::type_info*, T> >:
public std::binary_function<std::pair<std::type_info*, T>,
std::pair<std::type_info*, T>,
bool>
{
bool operator()(const std::pair<std::type_info*, T>& lhs,
const std::pair<std::type_info*, T>& rhs) const
{
return lhs.first->before(*rhs.first);
}
};
// Same as above, but with const std::type_info*.
template <typename T>
struct less< std::pair<const std::type_info*, T> >:
public std::binary_function<std::pair<const std::type_info*, T>,
std::pair<const std::type_info*, T>,
bool>
{
bool operator()(const std::pair<const std::type_info*, T>& lhs,
const std::pair<const std::type_info*, T>& rhs) const
{
return lhs.first->before(*rhs.first);
}
};
PairVector mVector;
};
#endif /* ! defined(LL_LLSORTEDVECTOR_H) */

View File

@@ -39,7 +39,7 @@
#include <vector>
#include <set>
#include <deque>
#include <typeinfo>
#include "stdtypes.h" // llcommon/stdtypes.h, needed for S32 and U32.
// Use to compare the first element only of a pair
// e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;
@@ -477,54 +477,4 @@ llbind2nd(const _Operation& __oper, const _Tp& __x)
return llbinder2nd<_Operation>(__oper, _Arg2_type(__x));
}
/**
* Compare std::type_info* pointers a la std::less. We break this out as a
* separate function for use in two different std::less specializations.
*/
inline
bool before(const std::type_info* lhs, const std::type_info* rhs)
{
#if LL_LINUX && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
// If we're building on Linux with gcc, and it's either gcc 3.x or
// 4.{0,1,2,3}, then we have to use a workaround. Note that we use gcc on
// Mac too, and some people build with gcc on Windows (cygwin or mingw).
// On Linux, different load modules may produce different type_info*
// pointers for the same type. Have to compare name strings to get good
// results.
return strcmp(lhs->name(), rhs->name()) < 0;
#else // not Linux, or gcc 4.4+
// Just use before(), as we normally would
return lhs->before(*rhs);
#endif
}
/**
* Specialize std::less<std::type_info*> to use std::type_info::before().
* See MAINT-1175. It is NEVER a good idea to directly compare std::type_info*
* because, on Linux, you might get different std::type_info* pointers for the
* same type (from different load modules)!
*/
namespace std
{
template <>
struct less<const std::type_info*>:
public std::binary_function<const std::type_info*, const std::type_info*, bool>
{
bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{
return before(lhs, rhs);
}
};
template <>
struct less<std::type_info*>:
public std::binary_function<std::type_info*, std::type_info*, bool>
{
bool operator()(std::type_info* lhs, std::type_info* rhs) const
{
return before(lhs, rhs);
}
};
} // std
#endif // LL_LLSTL_H

View File

@@ -42,10 +42,10 @@ template <class Object> class LLStrider
U8* mBytep;
};
U32 mSkip;
//U32 mTypeSize;
public:
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
LLStrider() { mObjectp = NULL; /*mTypeSize = */mSkip = sizeof(Object); }
~LLStrider() { }
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
@@ -60,6 +60,9 @@ public:
return ret;
}
//void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
//bool isStrided() const { return mTypeSize != mSkip; }
void skip(const U32 index) { mBytep += mSkip*index;}
U32 getSkip() const { return mSkip; }
Object* get() { return mObjectp; }
@@ -67,9 +70,72 @@ public:
Object& operator *() { return *mObjectp; }
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
/*void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
{
llassert_always(sizeof(Object) <= elem_size);
U8* __restrict dest = mBytep; //refer to dest instead of mBytep to benefit from __restrict hint
const U32 bytes = elem_size * elem_count; //total bytes to copy from source to dest
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
//the TRUE vbo datatype size via VertexBufferStrider::get
if(!isStrided() && mTypeSize == elem_size)
{
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
{
U8* __restrict aligned_source = LL_NEXT_ALIGNED_ADDRESS(source);
U8* __restrict aligned_dest = LL_NEXT_ALIGNED_ADDRESS(dest);
const U32 source_offset = aligned_source - source; //Offset to first aligned location in source buffer.
const U32 dest_offset = aligned_dest - dest; //Offset to first aligned location in dest buffer.
llassert_always(source_offset < 16);
llassert_always(dest_offset < 16);
if(source_offset == dest_offset) //delta to aligned location matches between source and destination! _mm_*_ps should be viable.
{
const U32 end_offset = (bytes - source_offset) % sizeof(LLVector4); //buffers may not neatly end on a 16byte alignment boundary.
const U32 aligned_bytes = bytes - source_offset - end_offset; //how many bytes to copy from aligned start to aligned end.
llassert_always(aligned_bytes > 0);
if(source_offset) //memcpy up to the aligned location if needed
memcpy(dest,source,source_offset);
LLVector4a::memcpyNonAliased16((F32*) aligned_dest, (F32*) aligned_source, aligned_bytes);
if(end_offset) //memcpy to the very end if needed.
memcpy(aligned_dest+aligned_bytes,aligned_source+aligned_bytes,end_offset);
}
else //buffers non-uniformly offset from aligned location. Using _mm_*u_ps.
{
U32 end = bytes/sizeof(LLVector4); //sizeof(LLVector4) = 16 bytes = 128 bits
llassert_always(end > 0);
__m128* dst = (__m128*) dest;
__m128* src = (__m128*) source;
for (U32 i = 0; i < end; i++) //copy 128bit chunks
{
__m128 res = _mm_loadu_ps((F32*)&src[i]);
_mm_storeu_ps((F32*)&dst[i], res);
}
end*=16;//Convert to real byte offset
if(end < bytes) //just memcopy the rest
memcpy(dest+end,source+end,bytes-end);
}
}
else //Too small. just do a simple memcpy.
memcpy(dest,source,bytes);
}
else
{
for(U32 i=0;i<elem_count;i++)
{
memcpy(dest,source,sizeof(Object));
dest+=mSkip;
source+=elem_size;
}
}
}*/
};
#endif // LL_LLSTRIDER_H

View File

@@ -34,6 +34,7 @@
#include "llstring.h"
#include "llerror.h"
#include "llfasttimer.h"
#if LL_WINDOWS
#define WIN32_LEAN_AND_MEAN
@@ -53,7 +54,7 @@ std::string ll_safe_string(const char* in)
std::string ll_safe_string(const char* in, S32 maxlen)
{
if(in && maxlen > 0) return std::string(in, maxlen);
if(in) return std::string(in, maxlen);
return std::string();
}
@@ -603,10 +604,16 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
}
const char CR = 13;
S32 i = utf8str.find(CR);
if(i == std::string::npos)
return utf8str; //Save us from a reserve call.
std::string out;
out.reserve(utf8str.length());
const S32 len = (S32)utf8str.length();
for( S32 i = 0; i < len; i++ )
if(i)
out.assign(utf8str,0,i); //Copy previous text to buffer
for( ++i; i < len; i++ )
{
if( utf8str[i] != CR )
{

View File

@@ -35,10 +35,11 @@
#include <string>
#include <cstdio>
#include <algorithm>
#include <map>
#include <locale>
#include <iomanip>
#include "llsd.h"
#include "llfasttimer.h"
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
@@ -46,7 +47,6 @@
#endif
#include <string.h>
#include <boost/scoped_ptr.hpp>
#if LL_SOLARIS
// stricmp and strnicmp do not exist on Solaris:
@@ -246,77 +246,40 @@ private:
static std::string sLocale;
public:
typedef std::basic_string<T> string_type;
typedef typename string_type::size_type size_type;
typedef typename std::basic_string<T>::size_type size_type;
public:
/////////////////////////////////////////////////////////////////////////////////////////
// Static Utility functions that operate on std::strings
static const string_type null;
static const std::basic_string<T> null;
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
/// considers any sequence of delims as a single field separator
LL_COMMON_API static void getTokens(const string_type& instr,
std::vector<string_type >& tokens,
const string_type& delims);
/// like simple scan overload, but returns scanned vector
static std::vector<string_type> getTokens(const string_type& instr,
const string_type& delims);
/// add support for keep_delims and quotes (either could be empty string)
static void getTokens(const string_type& instr,
std::vector<string_type>& tokens,
const string_type& drop_delims,
const string_type& keep_delims,
const string_type& quotes=string_type());
/// like keep_delims-and-quotes overload, but returns scanned vector
static std::vector<string_type> getTokens(const string_type& instr,
const string_type& drop_delims,
const string_type& keep_delims,
const string_type& quotes=string_type());
/// add support for escapes (could be empty string)
static void getTokens(const string_type& instr,
std::vector<string_type>& tokens,
const string_type& drop_delims,
const string_type& keep_delims,
const string_type& quotes,
const string_type& escapes);
/// like escapes overload, but returns scanned vector
static std::vector<string_type> getTokens(const string_type& instr,
const string_type& drop_delims,
const string_type& keep_delims,
const string_type& quotes,
const string_type& escapes);
LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals);
LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch);
LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions);
LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions);
LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions);
LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions);
LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
LL_COMMON_API static void setLocale (std::string inLocale);
LL_COMMON_API static std::string getLocale (void);
static bool isValidIndex(const string_type& string, size_type i)
static bool isValidIndex(const std::basic_string<T>& string, size_type i)
{
return !string.empty() && (0 <= i) && (i <= string.size());
}
static bool contains(const string_type& string, T c, size_type i=0)
{
return string.find(c, i) != string_type::npos;
}
static void trimHead(std::basic_string<T>& string);
static void trimTail(std::basic_string<T>& string);
static void trim(std::basic_string<T>& string) { trimHead(string); trimTail(string); }
static void truncate(std::basic_string<T>& string, size_type count);
static void trimHead(string_type& string);
static void trimTail(string_type& string);
static void trim(string_type& string) { trimHead(string); trimTail(string); }
static void truncate(string_type& string, size_type count);
static void toUpper(string_type& string);
static void toLower(string_type& string);
static void toUpper(std::basic_string<T>& string);
static void toLower(std::basic_string<T>& string);
// True if this is the head of s.
static BOOL isHead( const string_type& string, const T* s );
static BOOL isHead( const std::basic_string<T>& string, const T* s );
/**
* @brief Returns true if string starts with substr
@@ -324,8 +287,8 @@ public:
* If etither string or substr are empty, this method returns false.
*/
static bool startsWith(
const string_type& string,
const string_type& substr);
const std::basic_string<T>& string,
const std::basic_string<T>& substr);
/**
* @brief Returns true if string ends in substr
@@ -333,32 +296,19 @@ public:
* If etither string or substr are empty, this method returns false.
*/
static bool endsWith(
const string_type& string,
const string_type& substr);
const std::basic_string<T>& string,
const std::basic_string<T>& substr);
static void addCRLF(string_type& string);
static void removeCRLF(string_type& string);
static void addCRLF(std::basic_string<T>& string);
static void removeCRLF(std::basic_string<T>& string);
static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab );
static void replaceNonstandardASCII( string_type& string, T replacement );
static void replaceChar( string_type& string, T target, T replacement );
static void replaceString( string_type& string, string_type target, string_type replacement );
static void replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
static void replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
static void replaceChar( std::basic_string<T>& string, T target, T replacement );
static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
static BOOL containsNonprintable(const string_type& string);
static void stripNonprintable(string_type& string);
/**
* Double-quote an argument string if needed, unless it's already
* double-quoted. Decide whether it's needed based on the presence of any
* character in @a triggers (default space or double-quote). If we quote
* it, escape any embedded double-quote with the @a escape string (default
* backslash).
*
* Passing triggers="" means always quote, unless it's already double-quoted.
*/
static string_type quote(const string_type& str,
const string_type& triggers=" \"",
const string_type& escape="\\");
static BOOL containsNonprintable(const std::basic_string<T>& string);
static void stripNonprintable(std::basic_string<T>& string);
/**
* @brief Unsafe way to make ascii characters. You should probably
@@ -367,18 +317,18 @@ public:
* The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
* should work.
*/
static void _makeASCII(string_type& string);
static void _makeASCII(std::basic_string<T>& string);
// Conversion to other data types
static BOOL convertToBOOL(const string_type& string, BOOL& value);
static BOOL convertToU8(const string_type& string, U8& value);
static BOOL convertToS8(const string_type& string, S8& value);
static BOOL convertToS16(const string_type& string, S16& value);
static BOOL convertToU16(const string_type& string, U16& value);
static BOOL convertToU32(const string_type& string, U32& value);
static BOOL convertToS32(const string_type& string, S32& value);
static BOOL convertToF32(const string_type& string, F32& value);
static BOOL convertToF64(const string_type& string, F64& value);
static BOOL convertToBOOL(const std::basic_string<T>& string, BOOL& value);
static BOOL convertToU8(const std::basic_string<T>& string, U8& value);
static BOOL convertToS8(const std::basic_string<T>& string, S8& value);
static BOOL convertToS16(const std::basic_string<T>& string, S16& value);
static BOOL convertToU16(const std::basic_string<T>& string, U16& value);
static BOOL convertToU32(const std::basic_string<T>& string, U32& value);
static BOOL convertToS32(const std::basic_string<T>& string, S32& value);
static BOOL convertToF32(const std::basic_string<T>& string, F32& value);
static BOOL convertToF64(const std::basic_string<T>& string, F64& value);
/////////////////////////////////////////////////////////////////////////////////////////
// Utility functions for working with char*'s and strings
@@ -386,24 +336,24 @@ public:
// Like strcmp but also handles empty strings. Uses
// current locale.
static S32 compareStrings(const T* lhs, const T* rhs);
static S32 compareStrings(const string_type& lhs, const string_type& rhs);
static S32 compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
// case insensitive version of above. Uses current locale on
// Win32, and falls back to a non-locale aware comparison on
// Linux.
static S32 compareInsensitive(const T* lhs, const T* rhs);
static S32 compareInsensitive(const string_type& lhs, const string_type& rhs);
static S32 compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
// Case sensitive comparison with good handling of numbers. Does not use current locale.
// a.k.a. strdictcmp()
static S32 compareDict(const string_type& a, const string_type& b);
static S32 compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
// Case *in*sensitive comparison with good handling of numbers. Does not use current locale.
// a.k.a. strdictcmp()
static S32 compareDictInsensitive(const string_type& a, const string_type& b);
static S32 compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
static BOOL precedesDict( const string_type& a, const string_type& b );
static BOOL precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
// A replacement for strncpy.
// If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
@@ -411,7 +361,7 @@ public:
static void copy(T* dst, const T* src, size_type dst_size);
// Copies src into dst at a given offset.
static void copyInto(string_type& dst, const string_type& src, size_type offset);
static void copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
@@ -421,7 +371,7 @@ public:
#endif
private:
LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector<string_type >& tokens);
LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
};
template<class T> const std::basic_string<T> LLStringUtilBase<T>::null;
@@ -699,321 +649,6 @@ namespace LLStringFn
////////////////////////////////////////////////////////////
// static
template <class T>
std::vector<typename LLStringUtilBase<T>::string_type>
LLStringUtilBase<T>::getTokens(const string_type& instr, const string_type& delims)
{
std::vector<string_type> tokens;
getTokens(instr, tokens, delims);
return tokens;
}
// static
template <class T>
std::vector<typename LLStringUtilBase<T>::string_type>
LLStringUtilBase<T>::getTokens(const string_type& instr,
const string_type& drop_delims,
const string_type& keep_delims,
const string_type& quotes)
{
std::vector<string_type> tokens;
getTokens(instr, tokens, drop_delims, keep_delims, quotes);
return tokens;
}
// static
template <class T>
std::vector<typename LLStringUtilBase<T>::string_type>
LLStringUtilBase<T>::getTokens(const string_type& instr,
const string_type& drop_delims,
const string_type& keep_delims,
const string_type& quotes,
const string_type& escapes)
{
std::vector<string_type> tokens;
getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes);
return tokens;
}
namespace LLStringUtilBaseImpl
{
/**
* Input string scanner helper for getTokens(), or really any other
* character-parsing routine that may have to deal with escape characters.
* This implementation defines the concept (also an interface, should you
* choose to implement the concept by subclassing) and provides trivial
* implementations for a string @em without escape processing.
*/
template <class T>
struct InString
{
typedef std::basic_string<T> string_type;
typedef typename string_type::const_iterator const_iterator;
InString(const_iterator b, const_iterator e):
mIter(b),
mEnd(e)
{}
virtual ~InString() {}
bool done() const { return mIter == mEnd; }
/// Is the current character (*mIter) escaped? This implementation can
/// answer trivially because it doesn't support escapes.
virtual bool escaped() const { return false; }
/// Obtain the current character and advance @c mIter.
virtual T next() { return *mIter++; }
/// Does the current character match specified character?
virtual bool is(T ch) const { return (! done()) && *mIter == ch; }
/// Is the current character any one of the specified characters?
virtual bool oneof(const string_type& delims) const
{
return (! done()) && LLStringUtilBase<T>::contains(delims, *mIter);
}
/**
* Scan forward from @from until either @a delim or end. This is primarily
* useful for processing quoted substrings.
*
* If we do see @a delim, append everything from @from until (excluding)
* @a delim to @a into, advance @c mIter to skip @a delim, and return @c
* true.
*
* If we do not see @a delim, do not alter @a into or @c mIter and return
* @c false. Do not pass GO, do not collect $200.
*
* @note The @c false case described above implements normal getTokens()
* treatment of an unmatched open quote: treat the quote character as if
* escaped, that is, simply collect it as part of the current token. Other
* plausible behaviors directly affect the way getTokens() deals with an
* unmatched quote: e.g. throwing an exception to treat it as an error, or
* assuming a close quote beyond end of string (in which case return @c
* true).
*/
virtual bool collect_until(string_type& into, const_iterator from, T delim)
{
const_iterator found = std::find(from, mEnd, delim);
// If we didn't find delim, change nothing, just tell caller.
if (found == mEnd)
return false;
// Found delim! Append everything between from and found.
into.append(from, found);
// advance past delim in input
mIter = found + 1;
return true;
}
const_iterator mIter, mEnd;
};
/// InString subclass that handles escape characters
template <class T>
class InEscString: public InString<T>
{
public:
typedef InString<T> super;
typedef typename super::string_type string_type;
typedef typename super::const_iterator const_iterator;
using super::done;
using super::mIter;
using super::mEnd;
InEscString(const_iterator b, const_iterator e, const string_type& escapes):
super(b, e),
mEscapes(escapes)
{
// Even though we've already initialized 'mIter' via our base-class
// constructor, set it again to check for initial escape char.
setiter(b);
}
/// This implementation uses the answer cached by setiter().
virtual bool escaped() const { return mIsEsc; }
virtual T next()
{
// If we're looking at the escape character of an escape sequence,
// skip that character. This is the one time we can modify 'mIter'
// without using setiter: for this one case we DO NOT CARE if the
// escaped character is itself an escape.
if (mIsEsc)
++mIter;
// If we were looking at an escape character, this is the escaped
// character; otherwise it's just the next character.
T result(*mIter);
// Advance mIter, checking for escape sequence.
setiter(mIter + 1);
return result;
}
virtual bool is(T ch) const
{
// Like base-class is(), except that an escaped character matches
// nothing.
return (! done()) && (! mIsEsc) && *mIter == ch;
}
virtual bool oneof(const string_type& delims) const
{
// Like base-class oneof(), except that an escaped character matches
// nothing.
return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter);
}
virtual bool collect_until(string_type& into, const_iterator from, T delim)
{
// Deal with escapes in the characters we collect; that is, an escaped
// character must become just that character without the preceding
// escape. Collect characters in a separate string rather than
// directly appending to 'into' in case we do not find delim, in which
// case we're supposed to leave 'into' unmodified.
string_type collected;
// For scanning purposes, we're going to work directly with 'mIter'.
// Save its current value in case we fail to see delim.
const_iterator save_iter(mIter);
// Okay, set 'mIter', checking for escape.
setiter(from);
while (! done())
{
// If we see an unescaped delim, stop and report success.
if ((! mIsEsc) && *mIter == delim)
{
// Append collected chars to 'into'.
into.append(collected);
// Don't forget to advance 'mIter' past delim.
setiter(mIter + 1);
return true;
}
// We're not at end, and either we're not looking at delim or it's
// escaped. Collect this character and keep going.
collected.push_back(next());
}
// Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell
// caller.
setiter(save_iter);
return false;
}
private:
void setiter(const_iterator i)
{
mIter = i;
// Every time we change 'mIter', set 'mIsEsc' to be able to repetitively
// answer escaped() without having to rescan 'mEscapes'. mIsEsc caches
// contains(mEscapes, *mIter).
// We're looking at an escaped char if we're not already at end (that
// is, *mIter is even meaningful); if *mIter is in fact one of the
// specified escape characters; and if there's one more character
// following it. That is, if an escape character is the very last
// character of the input string, it loses its special meaning.
mIsEsc = (! done()) &&
LLStringUtilBase<T>::contains(mEscapes, *mIter) &&
(mIter+1) != mEnd;
}
const string_type mEscapes;
bool mIsEsc;
};
/// getTokens() implementation based on InString concept
template <typename INSTRING, typename string_type>
void getTokens(INSTRING& instr, std::vector<string_type>& tokens,
const string_type& drop_delims, const string_type& keep_delims,
const string_type& quotes)
{
// There are times when we want to match either drop_delims or
// keep_delims. Concatenate them up front to speed things up.
string_type all_delims(drop_delims + keep_delims);
// no tokens yet
tokens.clear();
// try for another token
while (! instr.done())
{
// scan past any drop_delims
while (instr.oneof(drop_delims))
{
// skip this drop_delim
instr.next();
// but if that was the end of the string, done
if (instr.done())
return;
}
// found the start of another token: make a slot for it
tokens.push_back(string_type());
if (instr.oneof(keep_delims))
{
// *iter is a keep_delim, a token of exactly 1 character. Append
// that character to the new token and proceed.
tokens.back().push_back(instr.next());
continue;
}
// Here we have a non-delimiter token, which might consist of a mix of
// quoted and unquoted parts. Use bash rules for quoting: you can
// embed a quoted substring in the midst of an unquoted token (e.g.
// ~/"sub dir"/myfile.txt); you can ram two quoted substrings together
// to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge
// from bash in that bash considers an unmatched quote an error. Our
// param signature doesn't allow for errors, so just pretend it's not
// a quote and embed it.
// At this level, keep scanning until we hit the next delimiter of
// either type (drop_delims or keep_delims).
while (! instr.oneof(all_delims))
{
// If we're looking at an open quote, search forward for
// a close quote, collecting characters along the way.
if (instr.oneof(quotes) &&
instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter))
{
// collect_until is cleverly designed to do exactly what we
// need here. No further action needed if it returns true.
}
else
{
// Either *iter isn't a quote, or there's no matching close
// quote: in other words, just an ordinary char. Append it to
// current token.
tokens.back().push_back(instr.next());
}
// having scanned that segment of this token, if we've reached the
// end of the string, we're done
if (instr.done())
return;
}
}
}
} // namespace LLStringUtilBaseImpl
// static
template <class T>
void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens,
const string_type& drop_delims, const string_type& keep_delims,
const string_type& quotes)
{
// Because this overload doesn't support escapes, use simple InString to
// manage input range.
LLStringUtilBaseImpl::InString<T> instring(string.begin(), string.end());
LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes);
}
// static
template <class T>
void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens,
const string_type& drop_delims, const string_type& keep_delims,
const string_type& quotes, const string_type& escapes)
{
// This overload must deal with escapes. Delegate that to InEscString
// (unless there ARE no escapes).
boost::scoped_ptr< LLStringUtilBaseImpl::InString<T> > instrp;
if (escapes.empty())
instrp.reset(new LLStringUtilBaseImpl::InString<T>(string.begin(), string.end()));
else
instrp.reset(new LLStringUtilBaseImpl::InEscString<T>(string.begin(), string.end(), escapes));
LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes);
}
// static
template<class T>
@@ -1043,7 +678,7 @@ S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
//static
template<class T>
S32 LLStringUtilBase<T>::compareStrings(const string_type& lhs, const string_type& rhs)
S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
{
return LLStringOps::collate(lhs.c_str(), rhs.c_str());
}
@@ -1069,8 +704,8 @@ S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
}
else
{
string_type lhs_string(lhs);
string_type rhs_string(rhs);
std::basic_string<T> lhs_string(lhs);
std::basic_string<T> rhs_string(rhs);
LLStringUtilBase<T>::toUpper(lhs_string);
LLStringUtilBase<T>::toUpper(rhs_string);
result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
@@ -1080,10 +715,10 @@ S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
//static
template<class T>
S32 LLStringUtilBase<T>::compareInsensitive(const string_type& lhs, const string_type& rhs)
S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
{
string_type lhs_string(lhs);
string_type rhs_string(rhs);
std::basic_string<T> lhs_string(lhs);
std::basic_string<T> rhs_string(rhs);
LLStringUtilBase<T>::toUpper(lhs_string);
LLStringUtilBase<T>::toUpper(rhs_string);
return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
@@ -1094,7 +729,7 @@ S32 LLStringUtilBase<T>::compareInsensitive(const string_type& lhs, const string
//static
template<class T>
S32 LLStringUtilBase<T>::compareDict(const string_type& astr, const string_type& bstr)
S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
{
const T* a = astr.c_str();
const T* b = bstr.c_str();
@@ -1135,7 +770,7 @@ S32 LLStringUtilBase<T>::compareDict(const string_type& astr, const string_type&
// static
template<class T>
S32 LLStringUtilBase<T>::compareDictInsensitive(const string_type& astr, const string_type& bstr)
S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
{
const T* a = astr.c_str();
const T* b = bstr.c_str();
@@ -1170,7 +805,7 @@ S32 LLStringUtilBase<T>::compareDictInsensitive(const string_type& astr, const s
// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
// static
template<class T>
BOOL LLStringUtilBase<T>::precedesDict( const string_type& a, const string_type& b )
BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
{
if( a.size() && b.size() )
{
@@ -1184,7 +819,7 @@ BOOL LLStringUtilBase<T>::precedesDict( const string_type& a, const string_type&
//static
template<class T>
void LLStringUtilBase<T>::toUpper(string_type& string)
void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)
{
if( !string.empty() )
{
@@ -1198,7 +833,7 @@ void LLStringUtilBase<T>::toUpper(string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::toLower(string_type& string)
void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
{
if( !string.empty() )
{
@@ -1212,7 +847,7 @@ void LLStringUtilBase<T>::toLower(string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::trimHead(string_type& string)
void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
{
if( !string.empty() )
{
@@ -1227,7 +862,7 @@ void LLStringUtilBase<T>::trimHead(string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::trimTail(string_type& string)
void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
{
if( string.size() )
{
@@ -1246,7 +881,7 @@ void LLStringUtilBase<T>::trimTail(string_type& string)
// Replace line feeds with carriage return-line feed pairs.
//static
template<class T>
void LLStringUtilBase<T>::addCRLF(string_type& string)
void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
{
const T LF = 10;
const T CR = 13;
@@ -1288,7 +923,7 @@ void LLStringUtilBase<T>::addCRLF(string_type& string)
// Remove all carriage returns
//static
template<class T>
void LLStringUtilBase<T>::removeCRLF(string_type& string)
void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
{
const T CR = 13;
@@ -1309,10 +944,10 @@ void LLStringUtilBase<T>::removeCRLF(string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacement )
void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
{
size_type found_pos = 0;
while( (found_pos = string.find(target, found_pos)) != string_type::npos )
while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
{
string[found_pos] = replacement;
found_pos++; // avoid infinite defeat if target == replacement
@@ -1321,10 +956,10 @@ void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacem
//static
template<class T>
void LLStringUtilBase<T>::replaceString( string_type& string, string_type target, string_type replacement )
void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
{
size_type found_pos = 0;
while( (found_pos = string.find(target, found_pos)) != string_type::npos )
while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
{
string.replace( found_pos, target.length(), replacement );
found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
@@ -1333,7 +968,7 @@ void LLStringUtilBase<T>::replaceString( string_type& string, string_type target
//static
template<class T>
void LLStringUtilBase<T>::replaceNonstandardASCII( string_type& string, T replacement )
void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
{
const char LF = 10;
const S8 MIN = 32;
@@ -1353,12 +988,12 @@ void LLStringUtilBase<T>::replaceNonstandardASCII( string_type& string, T replac
//static
template<class T>
void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spaces_per_tab )
void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
{
const T TAB = '\t';
const T SPACE = ' ';
string_type out_str;
std::basic_string<T> out_str;
// Replace tabs with spaces
for (size_type i = 0; i < str.length(); i++)
{
@@ -1377,7 +1012,7 @@ void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spa
//static
template<class T>
BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)
BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
{
const char MIN = 32;
BOOL rv = FALSE;
@@ -1394,7 +1029,7 @@ BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::stripNonprintable(string_type& string)
void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
{
const char MIN = 32;
size_type j = 0;
@@ -1425,43 +1060,8 @@ void LLStringUtilBase<T>::stripNonprintable(string_type& string)
delete []c_string;
}
template<class T>
std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,
const string_type& triggers,
const string_type& escape)
{
size_type len(str.length());
// If the string is already quoted, assume user knows what s/he's doing.
if (len >= 2 && str[0] == '"' && str[len-1] == '"')
{
return str;
}
// Not already quoted: do we need to? triggers.empty() is a special case
// meaning "always quote."
if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos)
{
// no trigger characters, don't bother quoting
return str;
}
// For whatever reason, we must quote this string.
string_type result;
result.push_back('"');
for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci)
{
if (*ci == '"')
{
result.append(escape);
}
result.push_back(*ci);
}
result.push_back('"');
return result;
}
template<class T>
void LLStringUtilBase<T>::_makeASCII(string_type& string)
void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
{
// Replace non-ASCII chars with LL_UNKNOWN_CHAR
for (size_type i = 0; i < string.length(); i++)
@@ -1491,7 +1091,7 @@ void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
// static
template<class T>
void LLStringUtilBase<T>::copyInto(string_type& dst, const string_type& src, size_type offset)
void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
{
if ( offset == dst.length() )
{
@@ -1501,7 +1101,7 @@ void LLStringUtilBase<T>::copyInto(string_type& dst, const string_type& src, siz
}
else
{
string_type tail = dst.substr(offset);
std::basic_string<T> tail = dst.substr(offset);
dst = dst.substr(0, offset);
dst += src;
@@ -1512,7 +1112,7 @@ void LLStringUtilBase<T>::copyInto(string_type& dst, const string_type& src, siz
// True if this is the head of s.
//static
template<class T>
BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s )
BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s )
{
if( string.empty() )
{
@@ -1528,8 +1128,8 @@ BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s )
// static
template<class T>
bool LLStringUtilBase<T>::startsWith(
const string_type& string,
const string_type& substr)
const std::basic_string<T>& string,
const std::basic_string<T>& substr)
{
if(string.empty() || (substr.empty())) return false;
if(0 == string.find(substr)) return true;
@@ -1539,8 +1139,8 @@ bool LLStringUtilBase<T>::startsWith(
// static
template<class T>
bool LLStringUtilBase<T>::endsWith(
const string_type& string,
const string_type& substr)
const std::basic_string<T>& string,
const std::basic_string<T>& substr)
{
if(string.empty() || (substr.empty())) return false;
std::string::size_type idx = string.rfind(substr);
@@ -1550,14 +1150,14 @@ bool LLStringUtilBase<T>::endsWith(
template<class T>
BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value)
BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
{
if( string.empty() )
{
return FALSE;
}
string_type temp( string );
std::basic_string<T> temp( string );
trim(temp);
if(
(temp == "1") ||
@@ -1587,7 +1187,7 @@ BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value)
BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1600,7 +1200,7 @@ BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value)
BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1613,7 +1213,7 @@ BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value)
BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1626,7 +1226,7 @@ BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value)
BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)
{
S32 value32 = 0;
BOOL success = convertToS32(string, value32);
@@ -1639,17 +1239,17 @@ BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value)
BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)
{
if( string.empty() )
{
return FALSE;
}
string_type temp( string );
std::basic_string<T> temp( string );
trim(temp);
U32 v;
std::basic_istringstream<T> i_stream((string_type)temp);
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
if(i_stream >> v)
{
value = v;
@@ -1659,17 +1259,17 @@ BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value)
BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)
{
if( string.empty() )
{
return FALSE;
}
string_type temp( string );
std::basic_string<T> temp( string );
trim(temp);
S32 v;
std::basic_istringstream<T> i_stream((string_type)temp);
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
if(i_stream >> v)
{
//TODO: figure out overflow and underflow reporting here
@@ -1686,7 +1286,7 @@ BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value)
BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)
{
F64 value64 = 0.0;
BOOL success = convertToF64(string, value64);
@@ -1699,17 +1299,17 @@ BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value)
}
template<class T>
BOOL LLStringUtilBase<T>::convertToF64(const string_type& string, F64& value)
BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
{
if( string.empty() )
{
return FALSE;
}
string_type temp( string );
std::basic_string<T> temp( string );
trim(temp);
F64 v;
std::basic_istringstream<T> i_stream((string_type)temp);
std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
if(i_stream >> v)
{
//TODO: figure out overflow and underflow reporting here
@@ -1726,7 +1326,7 @@ BOOL LLStringUtilBase<T>::convertToF64(const string_type& string, F64& value)
}
template<class T>
void LLStringUtilBase<T>::truncate(string_type& string, size_type count)
void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
{
size_type cur_size = string.size();
string.resize(count < cur_size ? count : cur_size);

View File

@@ -310,15 +310,27 @@ void LLThread::wakeLocked()
}
}
#ifdef SHOW_ASSERT
// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
static apr_os_thread_t main_thread_id;
LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
#endif
//static
apr_os_thread_t LLThread::sMainThreadID;
void LLThread::set_main_thread_id(void)
{
sMainThreadID = apr_os_thread_current();
}
// The thread private handle to access the LLThreadLocalData instance.
apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
LLThreadLocalData::LLThreadLocalData(char const* name) : mCurlMultiHandle(NULL), mCurlErrorBuffer(NULL), mName(name)
{
}
LLThreadLocalData::~LLThreadLocalData()
{
delete mCurlMultiHandle;
delete [] mCurlErrorBuffer;
}
//static
void LLThreadLocalData::init(void)
{
@@ -336,10 +348,8 @@ void LLThreadLocalData::init(void)
// Create the thread-local data for the main thread (this function is called by the main thread).
LLThreadLocalData::create(NULL);
#ifdef SHOW_ASSERT
// This function is called by the main thread.
main_thread_id = apr_os_thread_current();
#endif
LLThread::set_main_thread_id();
}
// This is called once for every thread when the thread is destructed.
@@ -352,7 +362,7 @@ void LLThreadLocalData::destroy(void* thread_local_data)
//static
void LLThreadLocalData::create(LLThread* threadp)
{
LLThreadLocalData* new_tld = new LLThreadLocalData;
LLThreadLocalData* new_tld = new LLThreadLocalData(threadp ? threadp->mName.c_str() : "main thread");
if (threadp)
{
threadp->mThreadLocalData = new_tld;

View File

@@ -40,13 +40,6 @@
#include "llaprpool.h"
#include "llatomic.h"
#ifdef SHOW_ASSERT
extern LL_COMMON_API bool is_main_thread(void);
#define ASSERT_SINGLE_THREAD do { static apr_os_thread_t first_thread_id = apr_os_thread_current(); llassert(apr_os_thread_equal(first_thread_id, apr_os_thread_current())); } while(0)
#else
#define ASSERT_SINGLE_THREAD do { } while(0)
#endif
class LLThread;
class LLMutex;
class LLCondition;
@@ -57,6 +50,12 @@ class LLCondition;
#define ll_thread_local __thread
#endif
class LL_COMMON_API LLThreadLocalDataMember
{
public:
virtual ~LLThreadLocalDataMember() { };
};
class LL_COMMON_API LLThreadLocalData
{
private:
@@ -66,16 +65,24 @@ public:
// Thread-local memory pool.
LLAPRRootPool mRootPool;
LLVolatileAPRPool mVolatileAPRPool;
LLThreadLocalDataMember* mCurlMultiHandle; // Initialized by AICurlMultiHandle::getInstance
char* mCurlErrorBuffer; // NULL, or pointing to a buffer used by libcurl.
std::string mName; // "main thread", or a copy of LLThread::mName.
static void init(void);
static void destroy(void* thread_local_data);
static void create(LLThread* pthread);
static LLThreadLocalData& tldata(void);
private:
LLThreadLocalData(char const* name);
~LLThreadLocalData();
};
class LL_COMMON_API LLThread
{
private:
static apr_os_thread_t sMainThreadID;
static U32 sIDIter;
static LLAtomicS32 sCount;
static LLAtomicS32 sRunning;
@@ -99,6 +106,7 @@ public:
static S32 getCount() { return sCount; }
static S32 getRunning() { return sRunning; }
static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
static bool is_main_thread(void) { return apr_os_thread_equal(LLThread::sMainThreadID, apr_os_thread_current()); }
public:
// PAUSE / RESUME functionality. See source code for important usage notes.
@@ -122,6 +130,9 @@ public:
// Return thread-local data for the current thread.
static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
// Called once, from LLThreadLocalData::init().
static void set_main_thread_id(void);
U32 getID() const { return mID; }
private:
@@ -165,6 +176,13 @@ protected:
// mRunCondition->unlock();
};
#ifdef SHOW_ASSERT
LL_COMMON_API inline bool is_main_thread(void) { return LLThread::is_main_thread(); }
#define ASSERT_SINGLE_THREAD do { static apr_os_thread_t first_thread_id = apr_os_thread_current(); llassert(apr_os_thread_equal(first_thread_id, apr_os_thread_current())); } while(0)
#else
#define ASSERT_SINGLE_THREAD do { } while(0)
#endif
//============================================================================
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
@@ -206,6 +224,11 @@ protected:
apr_thread_mutex_t* mAPRMutexp;
mutable U32 mCount;
mutable U32 mLockingThread;
private:
// Disallow copy construction and assignment.
LLMutexBase(LLMutexBase const&);
LLMutexBase& operator=(LLMutexBase const&);
};
class LL_COMMON_API LLMutex : public LLMutexBase
@@ -225,10 +248,6 @@ public:
protected:
LLAPRPool mPool;
private:
// Disable copy construction, as si teh bomb!!! -SG
LLMutex(const LLMutex&);
LLMutex& operator=(const LLMutex&);
};
#if APR_HAS_THREADS

View File

@@ -1,117 +0,0 @@
/**
* @file lltypeinfolookup.h
* @author Nat Goodspeed
* @date 2012-04-08
* @brief Template data structure like std::map<std::type_info*, T>
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Copyright (c) 2012, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLTYPEINFOLOOKUP_H)
#define LL_LLTYPEINFOLOOKUP_H
#include <boost/unordered_map.hpp>
#include <boost/functional/hash.hpp>
#include <boost/optional.hpp>
#include <functional> // std::binary_function
#include <typeinfo>
/**
* The following helper classes are based on the Boost.Unordered documentation:
* http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html
*/
/**
* Compute hash for a string passed as const char*
*/
struct const_char_star_hash: public std::unary_function<const char*, std::size_t>
{
std::size_t operator()(const char* str) const
{
std::size_t seed = 0;
for ( ; *str; ++str)
{
boost::hash_combine(seed, *str);
}
return seed;
}
};
/**
* Compute equality for strings passed as const char*
*
* I (nat) suspect that this is where the default behavior breaks for the
* const char* values returned from std::type_info::name(). If you compare the
* two const char* pointer values, as a naive, unspecialized implementation
* will surely do, they'll compare unequal.
*/
struct const_char_star_equal: public std::binary_function<const char*, const char*, bool>
{
bool operator()(const char* lhs, const char* rhs) const
{
return strcmp(lhs, rhs) == 0;
}
};
/**
* LLTypeInfoLookup is specifically designed for use cases for which you might
* consider std::map<std::type_info*, VALUE>. We have several such data
* structures in the viewer. The trouble with them is that at least on Linux,
* you can't rely on always getting the same std::type_info* for a given type:
* different load modules will produce different std::type_info*.
* LLTypeInfoLookup contains a workaround to address this issue.
*
* The API deliberately diverges from std::map in several respects:
* * It avoids iterators, not only begin()/end() but also as return values
* from insert() and find(). This bypasses transform_iterator overhead.
* * Since we literally use compile-time types as keys, the essential insert()
* and find() methods accept the key type as a @em template parameter,
* accepting and returning value_type as a normal runtime value. This is to
* permit future optimization (e.g. compile-time type hashing) without
* changing the API.
*/
template <typename VALUE>
class LLTypeInfoLookup
{
// Use this for our underlying implementation: lookup by
// std::type_info::name() string. This is one of the rare cases in which I
// dare use const char* directly, rather than std::string, because I'm
// sure that every value returned by std::type_info::name() is static.
// HOWEVER, specify our own hash + equality functors: naively comparing
// distinct const char* values won't work.
typedef boost::unordered_map<const char*, VALUE,
const_char_star_hash, const_char_star_equal> impl_map_type;
public:
typedef VALUE value_type;
LLTypeInfoLookup() {}
bool empty() const { return mMap.empty(); }
std::size_t size() const { return mMap.size(); }
template <typename KEY>
bool insert(const value_type& value)
{
// Obtain and store the std::type_info::name() string as the key.
// Return just the bool from std::map::insert()'s return pair.
return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second;
}
template <typename KEY>
boost::optional<value_type> find() const
{
// Use the std::type_info::name() string as the key.
typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name());
if (found == mMap.end())
return boost::optional<value_type>();
return found->second;
}
private:
impl_map_type mMap;
};
#endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */

View File

@@ -33,9 +33,9 @@
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
#if LL_WINDOWS
#undef WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
# undef WIN32_LEAN_AND_MEAN
# include <winsock2.h>
# include <windows.h>
#endif
#include "lldefs.h"
@@ -452,8 +452,7 @@ static void get_random_bytes(void *buf, int nbytes)
return;
}
#if LL_WINDOWS
#if LL_WINDOWS
typedef struct _ASTAT_
{
ADAPTER_STATUS adapt;
@@ -461,44 +460,58 @@ typedef struct _ASTAT_
}ASTAT, * PASTAT;
// static
S32 LLUUID::getNodeID(unsigned char *node_id)
S32 LLUUID::getNodeID(unsigned char * node_id)
{
ASTAT Adapter;
NCB Ncb;
UCHAR uRetCode;
LANA_ENUM lenum;
int i;
int retval = 0;
ASTAT Adapter;
NCB Ncb;
UCHAR uRetCode;
LANA_ENUM lenum;
int i;
int retval = 0;
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBENUM;
Ncb.ncb_buffer = (UCHAR *)&lenum;
Ncb.ncb_length = sizeof(lenum);
uRetCode = Netbios( &Ncb );
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBENUM;
Ncb.ncb_buffer = (UCHAR *)&lenum;
Ncb.ncb_length = sizeof(lenum);
uRetCode = Netbios( &Ncb );
// printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
for(i=0; i < lenum.length ;i++)
{
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lana_num = lenum.lana[i];
for(i=0; i < lenum.length ;i++)
{
memset( &Ncb, 0, sizeof(Ncb) );
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lana_num = lenum.lana[i];
uRetCode = Netbios( &Ncb );
uRetCode = Netbios( &Ncb );
// printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
// lenum.lana[i], uRetCode );
memset( &Ncb, 0, sizeof (Ncb) );
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = lenum.lana[i];
memset( &Ncb, 0, sizeof (Ncb) );
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = lenum.lana[i];
strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
Ncb.ncb_buffer = (unsigned char *)&Adapter;
Ncb.ncb_length = sizeof(Adapter);
strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
Ncb.ncb_buffer = (unsigned char *)&Adapter;
Ncb.ncb_length = sizeof(Adapter);
uRetCode = Netbios( &Ncb );
if ( uRetCode == 0 )
{
uRetCode = Netbios( &Ncb );
// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
// lenum.lana[i], uRetCode );
if ( uRetCode == 0 )
{
// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n",
// lenum.lana[i],
// Adapter.adapt.adapter_address[0],
// Adapter.adapt.adapter_address[1],
// Adapter.adapt.adapter_address[2],
// Adapter.adapt.adapter_address[3],
// Adapter.adapt.adapter_address[4],
// Adapter.adapt.adapter_address[5] );
memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
retval = 1;
}
}
}
}
return retval;
}

View File

@@ -34,6 +34,7 @@
#include <iostream>
#include <set>
#include <vector>
#include "stdtypes.h"
#include "llpreprocessor.h"
@@ -132,7 +133,6 @@ public:
U8 mData[UUID_BYTES];
};
typedef std::vector<LLUUID> uuid_vec_t;
// Construct

View File

@@ -35,7 +35,7 @@
const S32 LL_VERSION_MAJOR = 1;
const S32 LL_VERSION_MINOR = 7;
const S32 LL_VERSION_PATCH = 2;
const S32 LL_VERSION_PATCH = 0;
const S32 LL_VERSION_BUILD = ${vBUILD};
const char * const LL_CHANNEL = "${VIEWER_CHANNEL}";

View File

@@ -371,6 +371,9 @@ void LLCrashLogger::updateApplication(const std::string& message)
bool LLCrashLogger::init()
{
// Initialize curl
AICurlInterface::initCurl();
// We assume that all the logs we're looking for reside on the current drive
gDirUtilp->initAppDirs("SecondLife");

View File

@@ -35,8 +35,8 @@
#include "lluuid.h"
#include "llstring.h"
#include "llthread.h"
#include "llmemtype.h"
#include "llthread.h"
#include "aithreadsafe.h"
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2

View File

@@ -32,7 +32,7 @@
#ifndef LL_LLPNGWRAPPER_H
#define LL_LLPNGWRAPPER_H
#include "libpng15/png.h"
#include "png.h"
#include "llimage.h"
class LLPngWrapper

View File

@@ -1700,6 +1700,6 @@ LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString()));
rv->setPreferredType(
LLFolderType::lookup(
sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
return rv;
}

View File

@@ -148,7 +148,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // 46 AT_NONE
LLInventoryType::IT_NONE, // 47 AT_NONE
LLInventoryType::IT_NONE, // 48 AT_NONE
LLInventoryType::IT_MESH // 49 AT_MESH
LLInventoryType::IT_MESH // 49 AT_MESH
};
// static

View File

@@ -51,7 +51,7 @@ const S32 PARCEL_UNIT_AREA = 16;
const F32 PARCEL_HEIGHT = 50.f;
//Height above ground which parcel boundries exist for explicitly banned avatars
const F32 BAN_HEIGHT = 5000.f;
const F32 BAN_HEIGHT = 768.f;
// Maximum number of entries in an access list
const S32 PARCEL_MAX_ACCESS_LIST = 300;
@@ -260,7 +260,7 @@ public:
void setMediaURLResetTimer(F32 time);
virtual void setLocalID(S32 local_id);
// blow away all the extra stuff lurking in parcels, including urls, access lists, etc
// blow away all the extra crap lurking in parcels, including urls, access lists, etc
void clearParcel();
// This value is not persisted out to the parcel file, it is only
@@ -686,7 +686,6 @@ public:
std::map<LLUUID,LLAccessEntry> mBanList;
std::map<LLUUID,LLAccessEntry> mTempBanList;
std::map<LLUUID,LLAccessEntry> mTempAccessList;
};

View File

@@ -32,6 +32,9 @@
#ifndef LL_LLPERMISSIONSFLAGS_H
#define LL_LLPERMISSIONSFLAGS_H
// llpermissionsflags.h
// Copyright 2002, Linden Research, Inc.
//
// Flags for various permissions bits.
// Shared between viewer and simulator.

View File

@@ -38,7 +38,7 @@
#include "lltransactiontypes.h"
#include "../newview/hippogridmanager.h"
const U8 TRANSACTION_FLAGS_NONE = 0;
const U8 TRANSACTION_FLAG_SOURCE_GROUP = 1;
const U8 TRANSACTION_FLAG_DEST_GROUP = 2;

View File

@@ -74,7 +74,6 @@ const S32 TRANS_CLASSIFIED_RENEW = 2005;
// automatically end up in the list below :-(
// So make sure you check the transaction_description table
const S32 TRANS_RECURRING_GENERIC = 2100;
// Codes 3000-3999 reserved for inventory transactions
const S32 TRANS_GIVE_INVENTORY = 3000;

View File

@@ -37,6 +37,7 @@
#include "v3math.h"
#include "llvector4a.h"
#include <vector>
#include <set>
#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
#define OCT_ERRS LL_ERRS("OctreeErrors")
@@ -88,12 +89,11 @@ public:
typedef LLOctreeTraveler<T> oct_traveler;
typedef LLTreeTraveler<T> tree_traveler;
typedef LLPointer<T>* element_list;
typedef LLPointer<T>* element_iter;
typedef const LLPointer<T>* const_element_iter;
typedef typename std::set<LLPointer<T> > element_list;
typedef typename element_list::iterator element_iter;
typedef typename element_list::const_iterator const_element_iter;
typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter;
typedef LLOctreeNode<T>** child_list;
typedef LLOctreeNode<T>** child_iter;
typedef typename std::vector<LLOctreeNode<T>* > child_list;
typedef LLTreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
@@ -115,9 +115,6 @@ public:
: mParent((oct_node*)parent),
mOctant(octant)
{
mData = NULL;
mDataEnd = NULL;
mCenter = center;
mSize = size;
@@ -136,16 +133,6 @@ public:
{
BaseType::destroyListeners();
for (U32 i = 0; i < mElementCount; ++i)
{
mData[i]->setBinIndex(-1);
mData[i] = NULL;
}
free(mData);
mData = NULL;
mDataEnd = NULL;
for (U32 i = 0; i < getChildCount(); i++)
{
delete getChild(i);
@@ -242,17 +229,12 @@ public:
}
void accept(oct_traveler* visitor) { visitor->visit(this); }
virtual bool isLeaf() const { return mChildCount == 0; }
virtual bool isLeaf() const { return mChild.empty(); }
U32 getElementCount() const { return mElementCount; }
bool isEmpty() const { return mElementCount == 0; }
element_list& getData() { return mData; }
const element_list& getData() const { return mData; }
element_iter getDataBegin() { return mData; }
element_iter getDataEnd() { return mDataEnd; }
const_element_iter getDataBegin() const { return mData; }
const_element_iter getDataEnd() const { return mDataEnd; }
U32 getChildCount() const { return mChildCount; }
oct_node* getChild(U32 index) { return mChild[index]; }
const oct_node* getChild(U32 index) const { return mChild[index]; }
@@ -317,7 +299,7 @@ public:
virtual bool insert(T* data)
{
if (data == NULL || data->getBinIndex() != -1)
if (data == NULL)
{
OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
return false;
@@ -327,19 +309,22 @@ public:
//is it here?
if (isInside(data->getPositionGroup()))
{
if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) ||
if (((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius())) ||
(data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity)))
{ //it belongs here
mElementCount++;
mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
#if LL_OCTREE_PARANOIA_CHECK
//if this is a redundant insertion, error out (should never happen)
if (mData.find(data) != mData.end())
{
llwarns << "Redundant octree insertion detected. " << data << llendl;
return false;
}
#endif
//avoid unref on uninitialized memory
memset(mData+mElementCount-1, 0, sizeof(LLPointer<T>));
mData[mElementCount-1] = data;
mDataEnd = mData + mElementCount;
data->setBinIndex(mElementCount-1);
mData.insert(data);
BaseType::insert(data);
mElementCount = mData.size();
return true;
}
else
@@ -373,16 +358,10 @@ public:
if( lt == 0x7 )
{
mElementCount++;
mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
//avoid unref on uninitialized memory
memset(mData+mElementCount-1, 0, sizeof(LLPointer<T>));
mData[mElementCount-1] = data;
mDataEnd = mData + mElementCount;
data->setBinIndex(mElementCount-1);
mData.insert(data);
BaseType::insert(data);
mElementCount = mData.size();
return true;
}
@@ -431,59 +410,23 @@ public:
return false;
}
void _remove(T* data, S32 i)
{ //precondition -- mElementCount > 0, idx is in range [0, mElementCount)
mElementCount--;
data->setBinIndex(-1);
if (mElementCount > 0)
{
if (mElementCount != i)
{
mData[i] = mData[mElementCount]; //might unref data, do not access data after this point
mData[i]->setBinIndex(i);
}
mData[mElementCount] = NULL; //needed for unref
mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
mDataEnd = mData+mElementCount;
}
else
{
mData[0] = NULL; //needed for unref
free(mData);
mData = NULL;
mDataEnd = NULL;
}
this->notifyRemoval(data);
checkAlive();
}
bool remove(T* data)
{
S32 i = data->getBinIndex();
if (i >= 0 && i < (S32)mElementCount)
{
if (mData[i] == data)
{ //found it
_remove(data, i);
llassert(data->getBinIndex() == -1);
return true;
}
if (mData.find(data) != mData.end())
{ //we have data
mData.erase(data);
mElementCount = mData.size();
this->notifyRemoval(data);
checkAlive();
return true;
}
if (isInside(data))
else if (isInside(data))
{
oct_node* dest = getNodeAt(data);
if (dest != this)
{
bool ret = dest->remove(data);
llassert(data->getBinIndex() == -1);
return ret;
return dest->remove(data);
}
}
@@ -502,20 +445,19 @@ public:
//node is now root
llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
node->removeByAddress(data);
llassert(data->getBinIndex() == -1);
return true;
}
void removeByAddress(T* data)
{
for (U32 i = 0; i < mElementCount; ++i)
if (mData.find(data) != mData.end())
{
if (mData[i] == data)
{ //we have data
_remove(data, i);
llwarns << "FOUND!" << llendl;
return;
}
mData.erase(data);
mElementCount = mData.size();
this->notifyRemoval(data);
llwarns << "FOUND!" << llendl;
checkAlive();
return;
}
for (U32 i = 0; i < getChildCount(); i++)
@@ -527,8 +469,8 @@ public:
void clearChildren()
{
mChild.clear();
mChildCount = 0;
U32* foo = (U32*) mChildMap;
foo[0] = foo[1] = 0xFFFFFFFF;
}
@@ -590,7 +532,7 @@ public:
mChildMap[child->getOctant()] = mChildCount;
mChild[mChildCount] = child;
mChild.push_back(child);
++mChildCount;
child->setParent(this);
@@ -619,12 +561,9 @@ public:
mChild[index]->destroy();
delete mChild[index];
}
mChild.erase(mChild.begin() + index);
--mChildCount;
mChild[index] = mChild[mChildCount];
//rebuild child map
U32* foo = (U32*) mChildMap;
foo[0] = foo[1] = 0xFFFFFFFF;
@@ -680,12 +619,11 @@ protected:
oct_node* mParent;
U8 mOctant;
LLOctreeNode<T>* mChild[8];
child_list mChild;
U8 mChildMap[8];
U32 mChildCount;
element_list mData;
element_iter mDataEnd;
U32 mElementCount;
};

View File

@@ -324,16 +324,16 @@ public:
LLVector4a& min = node->mExtents[0];
LLVector4a& max = node->mExtents[1];
if (!branch->isEmpty())
if (!branch->getData().empty())
{ //node has data, find AABB that binds data set
const LLVolumeTriangle* tri = *(branch->getDataBegin());
const LLVolumeTriangle* tri = *(branch->getData().begin());
//initialize min/max to first available vertex
min = *(tri->mV[0]);
max = *(tri->mV[0]);
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
branch->getData().begin(); iter != branch->getData().end(); ++iter)
{ //for each triangle in node
//stretch by triangles in node
@@ -348,7 +348,7 @@ public:
max.setMax(max, *tri->mV[2]);
}
}
else if (!branch->isLeaf())
else if (!branch->getChildren().empty())
{ //no data, but child nodes exist
LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);

View File

@@ -131,7 +131,7 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
{
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter =
node->getDataBegin(); iter != node->getDataEnd(); ++iter)
node->getData().begin(); iter != node->getData().end(); ++iter)
{
const LLVolumeTriangle* tri = *iter;
@@ -236,8 +236,8 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
}
//children fit, check data
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin();
iter != branch->getDataEnd(); ++iter)
for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
iter != branch->getData().end(); ++iter)
{
const LLVolumeTriangle* tri = *iter;

View File

@@ -39,7 +39,7 @@ class LLVolumeTriangle : public LLRefCount
public:
LLVolumeTriangle()
{
mBinIndex = -1;
}
LLVolumeTriangle(const LLVolumeTriangle& rhs)
@@ -64,14 +64,9 @@ public:
U16 mIndex[3];
F32 mRadius;
mutable S32 mBinIndex;
virtual const LLVector4a& getPositionGroup() const;
virtual const F32& getBinRadius() const;
S32 getBinIndex() const { return mBinIndex; }
void setBinIndex(S32 idx) const { mBinIndex = idx; }
};
class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>

View File

@@ -40,7 +40,7 @@ const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-hav
const F32 MIN_OBJECT_Z = -256.f;
const F32 DEFAULT_MAX_PRIM_SCALE = 256.f;
const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = DEFAULT_MAX_PRIM_SCALE;
//const F32 MIN_PRIM_SCALE = 0.01f;
const F32 MIN_PRIM_SCALE = 0.01f;
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
class LLXform

View File

@@ -29,7 +29,8 @@ set(llmessage_SOURCE_FILES
llchainio.cpp
llcircuit.cpp
llclassifiedflags.cpp
llcurl.cpp
aicurl.cpp
aicurlthread.cpp
lldatapacker.cpp
lldispatcher.cpp
llfiltersd2xmlrpc.cpp
@@ -66,8 +67,6 @@ set(llmessage_SOURCE_FILES
llsdmessage.cpp
llsdmessagebuilder.cpp
llsdmessagereader.cpp
llsdrpcclient.cpp
llsdrpcserver.cpp
llservicebuilder.cpp
llservice.cpp
llstoredmessage.cpp
@@ -117,6 +116,9 @@ set(llmessage_HEADER_FILES
llcircuit.h
llclassifiedflags.h
llcurl.h
aicurl.h
aicurlprivate.h
aicurlthread.h
lldatapacker.h
lldbstrings.h
lldispatcher.h
@@ -164,8 +166,6 @@ set(llmessage_HEADER_FILES
llsdmessage.h
llsdmessagebuilder.h
llsdmessagereader.h
llsdrpcclient.h
llsdrpcserver.h
llservice.h
llservicebuilder.h
llstoredmessage.h

1386
indra/llmessage/aicurl.cpp Normal file

File diff suppressed because it is too large Load Diff

322
indra/llmessage/aicurl.h Normal file
View File

@@ -0,0 +1,322 @@
/**
* @file aicurl.h
* @brief Thread safe wrapper for libcurl.
*
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 17/03/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AICURL_H
#define AICURL_H
#include <string>
#include <vector>
#include <set>
#include <stdexcept>
#include <boost/intrusive_ptr.hpp>
#include <boost/utility.hpp>
#include <curl/curl.h> // CURL, CURLM, CURLMcode, CURLoption, curl_*_callback
// Make sure we don't use this option: it is not thread-safe.
#undef CURLOPT_DNS_USE_GLOBAL_CACHE
#include "stdtypes.h" // U32
#include "lliopipe.h" // LLIOPipe::buffer_ptr_t
#include "llatomic.h" // LLAtomicU32
#include "aithreadsafe.h"
class LLSD;
//-----------------------------------------------------------------------------
// Exceptions.
//
// A general curl exception.
//
class AICurlError : public std::runtime_error {
public:
AICurlError(std::string const& message) : std::runtime_error(message) { }
};
class AICurlNoEasyHandle : public AICurlError {
public:
AICurlNoEasyHandle(std::string const& message) : AICurlError(message) { }
};
class AICurlNoMultiHandle : public AICurlError {
public:
AICurlNoMultiHandle(std::string const& message) : AICurlError(message) { }
};
// End Exceptions.
//-----------------------------------------------------------------------------
// Things defined in this namespace are called from elsewhere in the viewer code.
namespace AICurlInterface {
// Output parameter of AICurlPrivate::CurlEasyRequest::getResult.
// Only used by LLXMLRPCTransaction::Impl.
struct TransferInfo {
TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) { }
F64 mSizeDownload;
F64 mTotalTime;
F64 mSpeedDownload;
};
//-----------------------------------------------------------------------------
// Global functions.
// Called once at start of application (from newview/llappviewer.cpp by main thread (before threads are created)),
// with main purpose to initialize curl.
void initCurl(void (*)(void) = NULL);
// Called once at start of application (from LLAppViewer::initThreads), starts AICurlThread.
void startCurlThread(void);
// Called once at end of application (from newview/llappviewer.cpp by main thread),
// with purpose to stop curl threads, free curl resources and deinitialize curl.
void cleanupCurl(void);
// Called from indra/llmessage/llurlrequest.cpp to print debug output regarding
// an error code returned by EasyRequest::getResult.
// Just returns curl_easy_strerror(errorcode).
std::string strerror(CURLcode errorcode);
// Called from indra/newview/llfloaterabout.cpp for the About floater, and
// from newview/llappviewer.cpp in behalf of debug output.
// Just returns curl_version().
std::string getVersionString(void);
// Called from newview/llappviewer.cpp (and llcrashlogger/llcrashlogger.cpp) to set
// the Certificate Authority file used to verify HTTPS certs.
void setCAFile(std::string const& file);
// Not called from anywhere.
// Can be used to set the path to the Certificate Authority file.
void setCAPath(std::string const& file);
//-----------------------------------------------------------------------------
// Global classes.
// Responder - base class for Request::get* and Request::post API.
//
// The life cycle of classes derived from this class is as follows:
// They are allocated with new on the line where get(), getByteRange() or post() is called,
// and the pointer to the allocated object is then put in a reference counting ResponderPtr.
// This ResponderPtr is passed to CurlResponderBuffer::prepRequest which stores it in its
// member mResponder. Hence, the life time of a Responder is never longer than its
// associated CurlResponderBuffer, however, if everything works correctly, then normally a
// responder is deleted in CurlResponderBuffer::removed_from_multi_handle by setting
// mReponder to NULL.
//
// Note that the lifetime of CurlResponderBuffer is (a bit) shorter than the associated
// CurlEasyRequest (because of the order of base classes of ThreadSafeBufferedCurlEasyRequest)
// and the callbacks, as set by prepRequest, only use those two.
// A callback locks the CurlEasyRequest before actually making the callback, and the
// destruction of CurlResponderBuffer also first locks the CurlEasyRequest, and then revokes
// the callbacks. This assures that a Responder is never used when the objects it uses are
// destructed. Also, if any of those are destructed then the Responder is automatically
// destructed too.
//
class Responder {
protected:
Responder(void);
virtual ~Responder();
private:
// Associated URL, used for debug output.
std::string mURL;
public:
// Called to set the URL of the current request for this Responder,
// used only when printing debug output regarding activity of the Responder.
void setURL(std::string const& url);
public:
// Called from LLHTTPClientURLAdaptor::complete():
// Derived classes can override this to get the HTML header that was received, when the message is completed.
// The default does nothing.
virtual void completedHeader(U32 status, std::string const& reason, LLSD const& content);
// Derived classes can override this to get the raw data of the body of the HTML message that was received.
// The default is to interpret the content as LLSD and call completed().
virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer);
// Called from LLHTTPClient request calls, if an error occurs even before we can call one of the above.
// It calls completed() with a fake status U32_MAX, as that is what some derived clients expect (bad design).
// This means that if a derived class overrides completedRaw() it now STILL has to override completed() to catch this error.
void fatalError(std::string const& reason);
// A derived class should return true if curl should follow redirections.
// The default is not to follow redirections.
virtual bool followRedir(void) { return false; }
protected:
// ... or, derived classes can override this to get the LLSD content when the message is completed.
// The default is to call result() (or errorWithContent() in case of a HTML status indicating an error).
virtual void completed(U32 status, std::string const& reason, LLSD const& content);
// ... or, derived classes can override this to received the content of a body upon success.
// The default does nothing.
virtual void result(LLSD const& content);
// Derived classes can override this to get informed when a bad HTML status code is received.
// The default calls error().
virtual void errorWithContent(U32 status, std::string const& reason, LLSD const& content);
// ... or, derived classes can override this to get informed when a bad HTML statis code is received.
// The default prints the error to llinfos.
virtual void error(U32 status, std::string const& reason);
public:
// Called from LLSDMessage::ResponderAdapter::listener.
// LLSDMessage::ResponderAdapter is a hack, showing among others by fact that these functions need to be public.
void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); }
void pubResult(LLSD const& content) { result(content); }
private:
// Used by ResponderPtr. Object is deleted when reference count reaches zero.
LLAtomicU32 mReferenceCount;
friend void intrusive_ptr_add_ref(Responder* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr<Responder> is made.
friend void intrusive_ptr_release(Responder* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr<Responder> is destroyed.
// This function must delete the Responder object when the reference count reaches zero.
};
// A Responder is passed around as ResponderPtr, which causes it to automatically
// destruct when there are no pointers left pointing to it.
typedef boost::intrusive_ptr<Responder> ResponderPtr;
} // namespace AICurlInterface
// Forward declaration (see aicurlprivate.h).
namespace AICurlPrivate {
class CurlEasyRequest;
} // namespace AICurlPrivate
// Define access types (_crat = Const Read Access Type, _rat = Read Access Type, _wat = Write Access Type).
// Typical usage is:
// AICurlEasyRequest h1; // Create easy handle.
// AICurlEasyRequest h2(h1); // Make lightweight copies.
// AICurlEasyRequest_wat h2_w(*h2); // Lock and obtain write access to the easy handle.
// Use *h2_w, which is a reference to the locked CurlEasyRequest instance.
// Note: As it is not allowed to use curl easy handles in any way concurrently,
// read access would at most give access to a CURL const*, which will turn out
// to be completely useless; therefore it is sufficient and efficient to use
// an AIThreadSafeSimple and it's unlikely that AICurlEasyRequest_rat will be used.
typedef AIAccessConst<AICurlPrivate::CurlEasyRequest> AICurlEasyRequest_rat;
typedef AIAccess<AICurlPrivate::CurlEasyRequest> AICurlEasyRequest_wat;
// Events generated by AICurlPrivate::CurlEasyHandle.
struct AICurlEasyHandleEvents {
// Events.
virtual void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void finished(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
virtual void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w) = 0;
// Avoid compiler warning.
virtual ~AICurlEasyHandleEvents() { }
};
#include "aicurlprivate.h"
// AICurlPrivate::CurlEasyRequestPtr, a boost::intrusive_ptr, is no more threadsafe than a
// builtin type, but wrapping it in AIThreadSafe is obviously not going to help here.
// Therefore we use the following trick: we wrap CurlEasyRequestPtr too, and only allow
// read accesses on it.
// AICurlEasyRequest: a thread safe, reference counting, auto-cleaning curl easy handle.
class AICurlEasyRequest {
public:
// Initial construction is allowed (thread-safe).
// Note: If ThreadSafeCurlEasyRequest() throws then the memory allocated is still freed.
// 'new' never returned however and neither the constructor nor destructor of mCurlEasyRequest is called in this case.
// This might throw AICurlNoEasyHandle.
AICurlEasyRequest(bool buffered) :
mCurlEasyRequest(buffered ? new AICurlPrivate::ThreadSafeBufferedCurlEasyRequest : new AICurlPrivate::ThreadSafeCurlEasyRequest) { }
AICurlEasyRequest(AICurlEasyRequest const& orig) : mCurlEasyRequest(orig.mCurlEasyRequest) { }
// For the rest, only allow read operations.
AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>& operator*(void) const { llassert(mCurlEasyRequest.get()); return *mCurlEasyRequest; }
AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>* operator->(void) const { llassert(mCurlEasyRequest.get()); return mCurlEasyRequest.get(); }
AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>* get(void) const { return mCurlEasyRequest.get(); }
// Returns true if this object points to the same CurlEasyRequest object.
bool operator==(AICurlEasyRequest const& cer) const { return mCurlEasyRequest == cer.mCurlEasyRequest; }
// Returns true if this object points to a different CurlEasyRequest object.
bool operator!=(AICurlEasyRequest const& cer) const { return mCurlEasyRequest != cer.mCurlEasyRequest; }
// Queue this request for insertion in the multi session.
void addRequest(void);
// Queue a command to remove this request from the multi session (or cancel a queued command to add it).
void removeRequest(void);
// Returns true when this AICurlEasyRequest wraps a AICurlPrivate::ThreadSafeBufferedCurlEasyRequest.
bool isBuffered(void) const { return mCurlEasyRequest->isBuffered(); }
private:
// The actual pointer to the ThreadSafeCurlEasyRequest instance.
AICurlPrivate::CurlEasyRequestPtr mCurlEasyRequest;
private:
// Assignment would not be thread-safe; we may create this object and read from it.
// Note: Destruction is implicitly assumed thread-safe, as it would be a logic error to
// destruct it while another thread still needs it, concurrent or not.
AICurlEasyRequest& operator=(AICurlEasyRequest const&) { return *this; }
public:
// The more exotic member functions of this class, to deal with passing this class
// as CURLOPT_PRIVATE pointer to a curl handle and afterwards restore it.
// For "internal use" only; don't use things from AICurlPrivate yourself.
// It's thread-safe to give read access the underlaying boost::intrusive_ptr.
// It's not OK to then call get() on that and store the AICurlPrivate::ThreadSafeCurlEasyRequest* separately.
AICurlPrivate::CurlEasyRequestPtr const& get_ptr(void) const { return mCurlEasyRequest; }
// If we have a correct (with regard to reference counting) AICurlPrivate::CurlEasyRequestPtr,
// then it's OK to construct a AICurlEasyRequest from it.
// Note that the external AICurlPrivate::CurlEasyRequestPtr needs its own locking, because
// it's not thread-safe in itself.
AICurlEasyRequest(AICurlPrivate::CurlEasyRequestPtr const& ptr) : mCurlEasyRequest(ptr) { }
// This one is obviously dangerous. It's for use only in MultiHandle::check_run_count.
// See also the long comment in CurlEasyRequest::finalizeRequest with regard to CURLOPT_PRIVATE.
explicit AICurlEasyRequest(AICurlPrivate::ThreadSafeCurlEasyRequest* ptr) : mCurlEasyRequest(ptr) { }
};
// Write Access Type for the buffer.
struct AICurlResponderBuffer_wat : public AIAccess<AICurlPrivate::CurlResponderBuffer> {
explicit AICurlResponderBuffer_wat(AICurlPrivate::ThreadSafeBufferedCurlEasyRequest& lockobj) :
AIAccess<AICurlPrivate::CurlResponderBuffer>(lockobj) { }
AICurlResponderBuffer_wat(AIThreadSafeSimple<AICurlPrivate::CurlEasyRequest>& lockobj) :
AIAccess<AICurlPrivate::CurlResponderBuffer>(static_cast<AICurlPrivate::ThreadSafeBufferedCurlEasyRequest&>(lockobj)) { }
};
#define AICurlPrivate DONTUSE_AICurlPrivate
#endif

View File

@@ -0,0 +1,415 @@
/**
* @file aicurlprivate.h
* @brief Thread safe wrapper for libcurl.
*
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 28/04/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AICURLPRIVATE_H
#define AICURLPRIVATE_H
#include <sstream>
#include "llatomic.h"
namespace AICurlPrivate {
namespace curlthread { class MultiHandle; }
struct Stats {
static LLAtomicU32 easy_calls;
static LLAtomicU32 easy_errors;
static LLAtomicU32 easy_init_calls;
static LLAtomicU32 easy_init_errors;
static LLAtomicU32 easy_cleanup_calls;
static LLAtomicU32 multi_calls;
static LLAtomicU32 multi_errors;
static void print(void);
};
void handle_multi_error(CURLMcode code);
inline CURLMcode check_multi_code(CURLMcode code) { Stats::multi_calls++; if (code != CURLM_OK) handle_multi_error(code); return code; }
bool curlThreadIsRunning(void);
void wakeUpCurlThread(void);
void stopCurlThread(void);
class ThreadSafeCurlEasyRequest;
class ThreadSafeBufferedCurlEasyRequest;
// This class wraps CURL*'s.
// It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl.
class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEvents {
public:
CurlEasyHandle(void);
~CurlEasyHandle();
private:
// Disallow assignment.
CurlEasyHandle& operator=(CurlEasyHandle const*);
public:
// Reset all options of a libcurl session handle.
void reset(void) { llassert(!mActiveMultiHandle); curl_easy_reset(mEasyHandle); }
// Set options for a curl easy handle.
template<typename BUILTIN>
CURLcode setopt(CURLoption option, BUILTIN parameter);
// Clone a libcurl session handle using all the options previously set.
//CurlEasyHandle(CurlEasyHandle const& orig);
// URL encode/decode the given string.
char* escape(char* url, int length);
char* unescape(char* url, int inlength , int* outlength);
// Extract information from a curl handle.
CURLcode getinfo(CURLINFO info, void* data);
#if _WIN64 || __x86_64__ || __ppc64__
// Overload for integer types that are too small (libcurl demands a long).
CURLcode getinfo(CURLINFO info, S32* data) { long ldata; CURLcode res = getinfo(info, &ldata); *data = static_cast<S32>(ldata); return res; }
CURLcode getinfo(CURLINFO info, U32* data) { long ldata; CURLcode res = getinfo(info, &ldata); *data = static_cast<U32>(ldata); return res; }
#endif
// Perform a file transfer (blocking).
CURLcode perform(void);
// Pause and unpause a connection.
CURLcode pause(int bitmask);
// Called when a request is queued for removal. In that case a race between the actual removal
// and revoking of the callbacks is harmless (and happens for the raw non-statemachine version).
void remove_queued(void) { mQueuedForRemoval = true; }
// In case it's added after being removed.
void add_queued(void) { mQueuedForRemoval = false; }
private:
CURL* mEasyHandle;
CURLM* mActiveMultiHandle;
char* mErrorBuffer;
bool mQueuedForRemoval; // Set if the easy handle is (probably) added to the multi handle, but is queued for removal.
#ifdef SHOW_ASSERT
public:
bool mRemovedPerCommand; // Set if mActiveMultiHandle was reset as per command from the main thread.
#endif
private:
// This should only be called from MultiHandle; add/remove an easy handle to/from a multi handle.
friend class curlthread::MultiHandle;
CURLMcode add_handle_to_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle);
CURLMcode remove_handle_from_multi(AICurlEasyRequest_wat& curl_easy_request_w, CURLM* multi_handle);
public:
// Returns true if this easy handle was added to a curl multi handle.
bool active(void) const { return mActiveMultiHandle; }
// If there was an error code as result, then this returns a human readable error string.
// Only valid when setErrorBuffer was called and the curl_easy function returned an error.
std::string getErrorString(void) const { return mErrorBuffer ? mErrorBuffer : "(null)"; }
// Returns true when it is expected that the parent will revoke callbacks before the curl
// easy handle is removed from the multi handle; that usually happens when an external
// error demands termination of the request (ie, an expiration).
bool no_warning(void) const { return mQueuedForRemoval || LLApp::isExiting(); }
// Used for debugging purposes.
bool operator==(CURL* easy_handle) const { return mEasyHandle == easy_handle; }
private:
// Call this prior to every curl_easy function whose return value is passed to check_easy_code.
void setErrorBuffer(void);
static void handle_easy_error(CURLcode code);
// Always first call setErrorBuffer()!
static inline CURLcode check_easy_code(CURLcode code)
{
Stats::easy_calls++;
if (code != CURLE_OK)
handle_easy_error(code);
return code;
}
protected:
// Return the underlying curl easy handle.
CURL* getEasyHandle(void) const { return mEasyHandle; }
private:
// Return, and possibly create, the curl (easy) error buffer used by the current thread.
static char* getTLErrorBuffer(void);
};
template<typename BUILTIN>
CURLcode CurlEasyHandle::setopt(CURLoption option, BUILTIN parameter)
{
llassert(!mActiveMultiHandle);
setErrorBuffer();
return check_easy_code(curl_easy_setopt(mEasyHandle, option, parameter));
}
// CurlEasyRequest adds a slightly more powerful interface that can be used
// to set the options on a curl easy handle.
//
// Calling sendRequest() will then connect to the given URL and perform
// the data exchange. If an error occurs related to this handle, it can
// be read by calling getErrorString().
//
// Note that the life cycle of a CurlEasyRequest is controlled by AICurlEasyRequest:
// a CurlEasyRequest is only ever created as base class of a ThreadSafeCurlEasyRequest,
// which is only created by creating a AICurlEasyRequest. When the last copy of such
// AICurlEasyRequest is deleted, then also the ThreadSafeCurlEasyRequest is deleted
// and the CurlEasyRequest destructed.
class CurlEasyRequest : public CurlEasyHandle {
public:
void setoptString(CURLoption option, std::string const& value);
void setPost(char const* postdata, S32 size);
void addHeader(char const* str);
private:
// Callback stubs.
static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata);
static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata);
curl_write_callback mHeaderCallback;
void* mHeaderCallbackUserData;
curl_write_callback mWriteCallback;
void* mWriteCallbackUserData;
curl_read_callback mReadCallback;
void* mReadCallbackUserData;
curl_ssl_ctx_callback mSSLCtxCallback;
void* mSSLCtxCallbackUserData;
public:
void setHeaderCallback(curl_write_callback callback, void* userdata);
void setWriteCallback(curl_write_callback callback, void* userdata);
void setReadCallback(curl_read_callback callback, void* userdata);
void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
// Call this if the set callbacks are about to be invalidated.
void revokeCallbacks(void);
// Reset everything to the state it was in when this object was just created.
void resetState(void);
private:
// Called from applyDefaultOptions.
void applyProxySettings(void);
public:
// Set default options that we want applied to all curl easy handles.
void applyDefaultOptions(void);
// Prepare the request for adding it to a multi session, or calling perform.
// This actually adds the headers that were collected with addHeader.
void finalizeRequest(std::string const& url);
// Store result code that is returned by getResult.
void store_result(CURLcode result) { mResult = result; }
// Called when the curl easy handle is done.
void done(AICurlEasyRequest_wat& curl_easy_request_w) { finished(curl_easy_request_w); }
// Fill info with the transfer info.
void getTransferInfo(AICurlInterface::TransferInfo* info);
// If result != CURLE_FAILED_INIT then also info was filled.
void getResult(CURLcode* result, AICurlInterface::TransferInfo* info = NULL);
private:
curl_slist* mHeaders;
bool mRequestFinalized;
AICurlEasyHandleEvents* mEventsTarget;
CURLcode mResult;
private:
// This class may only be created by constructing a ThreadSafeCurlEasyRequest.
friend class ThreadSafeCurlEasyRequest;
// Throws AICurlNoEasyHandle.
CurlEasyRequest(void) :
mHeaders(NULL), mRequestFinalized(false), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT)
{ applyDefaultOptions(); }
public:
~CurlEasyRequest();
public:
// Post-initialization, set the parent to pass the events to.
void send_events_to(AICurlEasyHandleEvents* target) { mEventsTarget = target; }
// For debugging purposes
bool is_finalized(void) const { return mRequestFinalized; }
// Return pointer to the ThreadSafe (wrapped) version of this object.
ThreadSafeCurlEasyRequest* get_lockobj(void);
protected:
// Pass events to parent.
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
};
// Buffers used by the AICurlInterface::Request API.
// Curl callbacks write into and read from these buffers.
// The interface with the rest of the code is through AICurlInterface::Responder.
//
// The lifetime of a CurlResponderBuffer is slightly shorter than its
// associated CurlEasyRequest; this class can only be created as base class
// of ThreadSafeBufferedCurlEasyRequest, and is therefore constructed after
// the construction of the associated CurlEasyRequest and destructed before it.
// Hence, it's safe to use get_lockobj() and through that access the CurlEasyRequest
// object at all times.
//
// A CurlResponderBuffer is thus created when a ThreadSafeBufferedCurlEasyRequest
// is created which only happens by creating a AICurlEasyRequest(true) instance,
// and when the last AICurlEasyRequest is deleted, then the ThreadSafeBufferedCurlEasyRequest
// is deleted and the CurlResponderBuffer destructed.
class CurlResponderBuffer : protected AICurlEasyHandleEvents {
public:
void resetState(AICurlEasyRequest_wat& curl_easy_request_w);
void prepRequest(AICurlEasyRequest_wat& buffered_curl_easy_request_w, std::vector<std::string> const& headers, AICurlInterface::ResponderPtr responder, S32 time_out = 0, bool post = false);
LLIOPipe::buffer_ptr_t& getInput(void) { return mInput; }
std::stringstream& getHeaderOutput(void) { return mHeaderOutput; }
LLIOPipe::buffer_ptr_t& getOutput(void) { return mOutput; }
// Called if libcurl doesn't deliver within CurlRequestTimeOut seconds.
void timed_out(void);
// Called after removed_from_multi_handle was called.
void processOutput(AICurlEasyRequest_wat& curl_easy_request_w);
protected:
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
private:
LLIOPipe::buffer_ptr_t mInput;
U8* mLastRead; // Pointer into mInput where we last stopped reading (or NULL to start at the beginning).
std::stringstream mHeaderOutput;
LLIOPipe::buffer_ptr_t mOutput;
AICurlInterface::ResponderPtr mResponder;
public:
static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()).
private:
// This class may only be created by constructing a ThreadSafeBufferedCurlEasyRequest.
friend class ThreadSafeBufferedCurlEasyRequest;
CurlResponderBuffer(void);
public:
~CurlResponderBuffer();
private:
static size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data);
static size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data);
static size_t curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data);
public:
// Return pointer to the ThreadSafe (wrapped) version of this object.
ThreadSafeBufferedCurlEasyRequest* get_lockobj(void);
// Return true when prepRequest was already called and the object has not been
// invalidated as a result of calling timed_out().
bool isValid(void) const { return mResponder; }
};
// This class wraps CurlEasyRequest for thread-safety and adds a reference counter so we can
// copy it around cheaply and it gets destructed automatically when the last instance is deleted.
// It guarantees that the CURL* handle is never used concurrently, which is not allowed by libcurl.
// As AIThreadSafeSimpleDC contains a mutex, it cannot be copied. Therefore we need a reference counter for this object.
class ThreadSafeCurlEasyRequest : public AIThreadSafeSimple<CurlEasyRequest> {
public:
// Throws AICurlNoEasyHandle.
ThreadSafeCurlEasyRequest(void) : mReferenceCount(0)
{ new (ptr()) CurlEasyRequest;
Dout(dc::curl, "Creating ThreadSafeCurlEasyRequest with this = " << (void*)this); }
virtual ~ThreadSafeCurlEasyRequest()
{ Dout(dc::curl, "Destructing ThreadSafeCurlEasyRequest with this = " << (void*)this); }
// Returns true if this is a base class of ThreadSafeBufferedCurlEasyRequest.
virtual bool isBuffered(void) const { return false; }
private:
LLAtomicU32 mReferenceCount;
friend void intrusive_ptr_add_ref(ThreadSafeCurlEasyRequest* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr<ThreadSafeCurlEasyRequest> is made.
friend void intrusive_ptr_release(ThreadSafeCurlEasyRequest* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr<ThreadSafeCurlEasyRequest> is destroyed.
};
// Same as the above but adds a CurlResponderBuffer. The latter has its own locking in order to
// allow casting the underlying CurlEasyRequest to ThreadSafeCurlEasyRequest, independent of
// what class it is part of: ThreadSafeCurlEasyRequest or ThreadSafeBufferedCurlEasyRequest.
// The virtual destructor of ThreadSafeCurlEasyRequest allows to treat each easy handle transparently
// as a ThreadSafeCurlEasyRequest object, or optionally dynamic_cast it to a ThreadSafeBufferedCurlEasyRequest.
// Note: the order of these base classes is important: AIThreadSafeSimple<CurlResponderBuffer> is now
// destructed before ThreadSafeCurlEasyRequest is.
class ThreadSafeBufferedCurlEasyRequest : public ThreadSafeCurlEasyRequest, public AIThreadSafeSimple<CurlResponderBuffer> {
public:
// Throws AICurlNoEasyHandle.
ThreadSafeBufferedCurlEasyRequest(void) { new (AIThreadSafeSimple<CurlResponderBuffer>::ptr()) CurlResponderBuffer; }
/*virtual*/ bool isBuffered(void) const { return true; }
};
// The curl easy request type wrapped in a reference counting pointer.
typedef boost::intrusive_ptr<AICurlPrivate::ThreadSafeCurlEasyRequest> CurlEasyRequestPtr;
// This class wraps CURLM*'s.
// It guarantees that a pointer is cleaned up when no longer needed, as required by libcurl.
class CurlMultiHandle : public boost::noncopyable {
public:
CurlMultiHandle(void);
~CurlMultiHandle();
private:
// Disallow assignment.
CurlMultiHandle& operator=(CurlMultiHandle const*);
private:
static LLAtomicU32 sTotalMultiHandles;
protected:
CURLM* mMultiHandle;
public:
// Set options for a curl multi handle.
template<typename BUILTIN>
CURLMcode setopt(CURLMoption option, BUILTIN parameter);
// Returns total number of existing CURLM* handles (excluding ones created outside this class).
static U32 getTotalMultiHandles(void) { return sTotalMultiHandles; }
};
template<typename BUILTIN>
CURLMcode CurlMultiHandle::setopt(CURLMoption option, BUILTIN parameter)
{
return check_multi_code(curl_multi_setopt(mMultiHandle, option, parameter));
}
} // namespace AICurlPrivate
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
/**
* @file aicurlthread.h
* @brief Thread safe wrapper for libcurl.
*
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 28/04/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AICURLTHREAD_H
#define AICURLTHREAD_H
#include "aicurl.h"
#include <vector>
#undef AICurlPrivate
namespace AICurlPrivate {
namespace curlthread {
class PollSet;
// For ordering a std::set with AICurlEasyRequest objects.
struct AICurlEasyRequestCompare {
bool operator()(AICurlEasyRequest const& h1, AICurlEasyRequest const& h2) { return h1.get() < h2.get(); }
};
//-----------------------------------------------------------------------------
// MultiHandle
// This class adds member functions that will only be called from the AICurlThread thread.
// This class guarantees that all added easy handles will be removed from the multi handle
// before the multi handle is cleaned up, as is required by libcurl.
class MultiHandle : public CurlMultiHandle
{
public:
MultiHandle(void);
~MultiHandle();
// Add/remove an easy handle to/from a multi session.
CURLMcode add_easy_request(AICurlEasyRequest const& easy_request);
CURLMcode remove_easy_request(AICurlEasyRequest const& easy_request, bool as_per_command = false);
// Reads/writes available data from a particular socket (non-blocking).
CURLMcode socket_action(curl_socket_t sockfd, int ev_bitmask);
// Set data to association with an internal socket.
CURLMcode assign(curl_socket_t sockfd, void* sockptr);
// Read multi stack informationals.
CURLMsg const* info_read(int* msgs_in_queue) const;
private:
typedef std::set<AICurlEasyRequest, AICurlEasyRequestCompare> addedEasyRequests_type;
addedEasyRequests_type mAddedEasyRequests;
bool mHandleAddedOrRemoved; // Set when an easy handle was added or removed, reset in check_run_count().
int mPrevRunningHandles; // The last value of mRunningHandles that check_run_count() was called with.
int mRunningHandles; // The last value returned by curl_multi_socket_action.
long mTimeOut; // The last time out in ms as set by the callback CURLMOPT_TIMERFUNCTION.
private:
static int socket_callback(CURL* easy, curl_socket_t s, int action, void* userp, void* socketp);
static int timer_callback(CURLM* multi, long timeout_ms, void* userp);
public:
// Returns the number of active easy handles as reported by the last call to curl_multi_socket_action.
int getRunningHandles(void) const { return mRunningHandles; }
// Returns how long to wait for socket action before calling socket_action(CURL_SOCKET_TIMEOUT, 0), in ms.
int getTimeOut(void) const { return mTimeOut; }
// This is called before sleeping, after calling (one or more times) socket_action.
void check_run_count(void);
public:
//-----------------------------------------------------------------------------
// Curl socket administration:
PollSet* mReadPollSet;
PollSet* mWritePollSet;
};
} // namespace curlthread
} // namespace AICurlPrivate
// Thread safe, noncopyable curl multi handle.
// This class wraps MultiHandle for thread-safety.
// AIThreadSafeSingleThreadDC cannot be copied, but that is OK as we don't need that (or want that);
// this class provides a thread-local singleton (exactly one instance per thread), and because it
// can't be copied, that guarantees that the CURLM* handle is never used concurrently, which is
// not allowed by libcurl.
class AICurlMultiHandle : public AIThreadSafeSingleThreadDC<AICurlPrivate::curlthread::MultiHandle>, public LLThreadLocalDataMember {
public:
static AICurlMultiHandle& getInstance(void);
static void destroyInstance(void);
private:
// Use getInstance().
AICurlMultiHandle(void) { }
};
typedef AISTAccessConst<AICurlPrivate::curlthread::MultiHandle> AICurlMultiHandle_rat;
typedef AISTAccess<AICurlPrivate::curlthread::MultiHandle> AICurlMultiHandle_wat;
#define AICurlPrivate DONTUSE_AICurlPrivate
#endif

View File

@@ -28,7 +28,6 @@
#include "linden_common.h"
#include "llares.h"
#include "llscopedvolatileaprpool.h"
#include <ares_dns.h>
#include <ares_version.h>
@@ -39,6 +38,7 @@
#include "llapr.h"
#include "llareslistener.h"
#include "llscopedvolatileaprpool.h"
#if defined(LL_WINDOWS)
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
@@ -468,7 +468,6 @@ bool LLAres::process(U64 timeout)
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
apr_int32_t nsds = 0;
apr_status_t status;
int nactive = 0;
int bitmask;
@@ -479,6 +478,8 @@ bool LLAres::process(U64 timeout)
return nsds > 0;
}
LLScopedVolatileAPRPool scoped_pool;
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
{
if (ARES_GETSOCK_READABLE(bitmask, i))
@@ -494,7 +495,7 @@ bool LLAres::process(U64 timeout)
apr_socket_t *aprSock = NULL;
status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], LLAPRRootPool::get()());
apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool);
if (status != APR_SUCCESS)
{
ll_apr_warn_status(status);
@@ -503,7 +504,7 @@ bool LLAres::process(U64 timeout)
aprFds[nactive].desc.s = aprSock;
aprFds[nactive].desc_type = APR_POLL_SOCKET;
aprFds[nactive].p = LLAPRRootPool::get()();
aprFds[nactive].p = scoped_pool;
aprFds[nactive].rtnevents = 0;
aprFds[nactive].client_data = &socks[i];
@@ -512,7 +513,7 @@ bool LLAres::process(U64 timeout)
if (nactive > 0)
{
status = apr_poll(aprFds, nactive, &nsds, timeout);
apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout);
if (status != APR_SUCCESS && status != APR_TIMEUP)
{

View File

@@ -401,7 +401,7 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse
if (user_data)
{
// The *user_data should not be passed without a callback to clean it up.
llassert(callback != NULL)
llassert(callback != NULL);
}
BOOL exists = mStaticVFS->getExists(uuid, type);
@@ -441,7 +441,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
if (user_data)
{
// The *user_data should not be passed without a callback to clean it up.
llassert(callback != NULL)
llassert(callback != NULL);
}
if (mShutDown)

View File

@@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llbuffer.h"
#include <iterator>
#include "llmath.h"
#include "llmemtype.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,383 +1,39 @@
/**
/**
* @file llcurl.h
* @author Zero / Donovan
* @date 2006-10-15
* @brief A wrapper around libcurl.
* @brief Drop in replacement for old llcurl.h.
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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,
* Copyright (c) 2012, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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$
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 22/06/2012
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef LL_LLCURL_H
#define LL_LLCURL_H
#include "linden_common.h"
#include "aicurl.h"
#include <sstream>
#include <string>
#include <vector>
#include <boost/intrusive_ptr.hpp>
#include <curl/curl.h> // TODO: remove dependency
#include "llbuffer.h"
#include "lliopipe.h"
#include "llsd.h"
#include "llthread.h"
class LLMutex;
// For whatever reason, this is not typedef'd in curl.h
typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
class LLCurl
{
LOG_CLASS(LLCurl);
public:
class Easy;
class Multi;
static bool sMultiThreaded;
struct TransferInfo
{
TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
F64 mSizeDownload;
F64 mTotalTime;
F64 mSpeedDownload;
};
class Responder
{
//LOG_CLASS(Responder);
public:
Responder();
virtual ~Responder();
/**
* @brief return true if the status code indicates success.
*/
static bool isGoodStatus(U32 status)
{
return((200 <= status) && (status < 300));
}
virtual void errorWithContent(
U32 status,
const std::string& reason,
const LLSD& content);
//< called by completed() on bad status
virtual void error(U32 status, const std::string& reason);
//< called by default error(status, reason, content)
virtual void result(const LLSD& content);
//< called by completed for good status codes.
virtual void completedRaw(
U32 status,
const std::string& reason,
const LLChannelDescriptors& channels,
const LLIOPipe::buffer_ptr_t& buffer);
/**< Override point for clients that may want to use this
class when the response is some other format besides LLSD
*/
virtual void completed(
U32 status,
const std::string& reason,
const LLSD& content);
/**< The default implemetnation calls
either:
* result(), or
* error()
*/
// Override to handle parsing of the header only. Note: this is the only place where the contents
// of the header can be parsed. In the ::completed call above only the body is contained in the LLSD.
virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content);
// Used internally to set the url for debugging later.
void setURL(const std::string& url);
virtual bool followRedir()
{
return false;
}
public: /* but not really -- don't touch this */
U32 mReferenceCount;
private:
std::string mURL;
};
typedef boost::intrusive_ptr<Responder> ResponderPtr;
/**
* @ brief Set certificate authority file used to verify HTTPS certs.
*/
static void setCAFile(const std::string& file);
/**
* @ brief Set certificate authority path used to verify HTTPS certs.
*/
static void setCAPath(const std::string& path);
/**
* @ brief Return human-readable string describing libcurl version.
*/
static std::string getVersionString();
/**
* @ brief Get certificate authority file used to verify HTTPS certs.
*/
static const std::string& getCAFile() { return sCAFile; }
/**
* @ brief Get certificate authority path used to verify HTTPS certs.
*/
static const std::string& getCAPath() { return sCAPath; }
/**
* @ brief Initialize LLCurl class
*/
static void initClass(bool multi_threaded = false);
/**
* @ brief Cleanup LLCurl class
*/
static void cleanupClass();
/**
* @ brief curl error code -> string
*/
static std::string strerror(CURLcode errorcode);
// For OpenSSL callbacks
static std::vector<LLMutex*> sSSLMutex;
// OpenSSL callbacks
static void ssl_locking_callback(int mode, int type, const char *file, int line);
static unsigned long ssl_thread_id(void);
private:
static std::string sCAPath;
static std::string sCAFile;
static const unsigned int MAX_REDIRECTS;
};
class LLCurl::Easy
{
LOG_CLASS(Easy);
private:
Easy();
public:
static Easy* getEasy();
~Easy();
CURL* getCurlHandle() const { return mCurlEasyHandle; }
void setErrorBuffer();
void setCA();
void setopt(CURLoption option, S32 value);
// These assume the setter does not free value!
void setopt(CURLoption option, void* value);
void setopt(CURLoption option, char* value);
// Copies the string so that it is gauranteed to stick around
void setoptString(CURLoption option, const std::string& value);
void slist_append(const char* str);
void setHeaders();
U32 report(CURLcode);
void getTransferInfo(LLCurl::TransferInfo* info);
void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false);
const char* getErrorBuffer();
std::stringstream& getInput() { return mInput; }
std::stringstream& getHeaderOutput() { return mHeaderOutput; }
LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
const LLChannelDescriptors& getChannels() { return mChannels; }
void resetState();
static CURL* allocEasyHandle();
static void releaseEasyHandle(CURL* handle);
private:
friend class LLCurl;
friend class LLCurl::Multi;
CURL* mCurlEasyHandle;
struct curl_slist* mHeaders;
std::stringstream mRequest;
LLChannelDescriptors mChannels;
LLIOPipe::buffer_ptr_t mOutput;
std::stringstream mInput;
std::stringstream mHeaderOutput;
char mErrorBuffer[CURL_ERROR_SIZE];
// Note: char*'s not strings since we pass pointers to curl
std::vector<char*> mStrings;
ResponderPtr mResponder;
static std::set<CURL*> sFreeHandles;
static std::set<CURL*> sActiveHandles;
static LLMutex* sHandleMutex;
static LLMutex* sMultiMutex;
};
class LLCurl::Multi : public LLThread
{
LOG_CLASS(Multi);
public:
typedef enum
{
PERFORM_STATE_READY=0,
PERFORM_STATE_PERFORMING=1,
PERFORM_STATE_COMPLETED=2
} ePerformState;
Multi();
~Multi();
Easy* allocEasy();
bool addEasy(Easy* easy);
void removeEasy(Easy* easy);
S32 process();
void perform();
void doPerform();
virtual void run();
CURLMsg* info_read(S32* msgs_in_queue);
S32 mQueued;
S32 mErrorCount;
S32 mPerformState;
LLCondition* mSignal;
bool mQuitting;
bool mThreaded;
private:
void easyFree(Easy*);
CURLM* mCurlMultiHandle;
typedef std::set<Easy*> easy_active_list_t;
easy_active_list_t mEasyActiveList;
typedef std::map<CURL*, Easy*> easy_active_map_t;
easy_active_map_t mEasyActiveMap;
typedef std::set<Easy*> easy_free_list_t;
easy_free_list_t mEasyFreeList;
};
// DONT UNCOMMENT BREAKS GCC47
//namespace boost
//{
void intrusive_ptr_add_ref(LLCurl::Responder* p);
void intrusive_ptr_release(LLCurl::Responder* p);
//};
class LLCurlRequest
{
public:
typedef std::vector<std::string> headers_t;
LLCurlRequest();
~LLCurlRequest();
void get(const std::string& url, LLCurl::ResponderPtr responder);
bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
S32 process();
S32 getQueued();
private:
void addMulti();
LLCurl::Easy* allocEasy();
bool addEasy(LLCurl::Easy* easy);
private:
typedef std::set<LLCurl::Multi*> curlmulti_set_t;
curlmulti_set_t mMultiSet;
LLCurl::Multi* mActiveMulti;
S32 mActiveRequestCount;
BOOL mProcessing;
U32 mThreadID; // debug
};
class LLCurlEasyRequest
{
public:
LLCurlEasyRequest();
~LLCurlEasyRequest();
void setopt(CURLoption option, S32 value);
void setoptString(CURLoption option, const std::string& value);
void setPost(char* postdata, S32 size);
void setHeaderCallback(curl_header_callback callback, void* userdata);
void setWriteCallback(curl_write_callback callback, void* userdata);
void setReadCallback(curl_read_callback callback, void* userdata);
void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
void slist_append(const char* str);
void sendRequest(const std::string& url);
void requestComplete();
void perform();
bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
std::string getErrorString();
LLCurl::Easy* getEasy() const { return mEasy; }
private:
CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info);
private:
LLCurl::Multi* mMulti;
LLCurl::Easy* mEasy;
bool mRequestSent;
bool mResultReturned;
};
// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
namespace LLCurlFF
{
void check_easy_code(CURLcode code);
void check_multi_code(CURLMcode code);
}
// Map interface to old LLCurl names so this can be used as a drop-in replacement.
namespace LLCurl = AICurlInterface;
#endif // LL_LLCURL_H

View File

@@ -29,6 +29,7 @@
#include "lldispatcher.h"
#include <algorithm>
#include <iterator>
#include "llstl.h"
#include "message.h"

View File

@@ -80,6 +80,7 @@
#include "llbuffer.h"
#include "llbufferstream.h"
#include "llfasttimer.h"
#include "llmemorystream.h"
#include "llsd.h"
#include "llsdserialize.h"

View File

@@ -25,7 +25,7 @@
*/
#include "linden_common.h"
#include <openssl/x509_vfy.h>
#include "llhttpclient.h"
#include "llassetstorage.h"
@@ -40,7 +40,9 @@
#include "message.h"
#include <curl/curl.h>
const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
////////////////////////////////////////////////////////////////////////////
@@ -156,9 +158,9 @@ namespace
if(fstream.is_open())
{
fstream.seekg(0, std::ios::end);
U32 fileSize = (U32)fstream.tellg();
U32 fileSize = fstream.tellg();
fstream.seekg(0, std::ios::beg);
std::vector<char> fileBuffer(fileSize); //Mem leak fix'd
std::vector<char> fileBuffer(fileSize);
fstream.read(&fileBuffer[0], fileSize);
ostream.write(&fileBuffer[0], fileSize);
fstream.close();
@@ -187,9 +189,11 @@ namespace
LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ);
S32 fileSize = vfile.getSize();
std::vector<U8> fileBuffer(fileSize);
vfile.read(&fileBuffer[0], fileSize);
ostream.write((char*)&fileBuffer[0], fileSize);
U8* fileBuffer;
fileBuffer = new U8 [fileSize];
vfile.read(fileBuffer, fileSize);
ostream.write((char*)fileBuffer, fileSize);
delete [] fileBuffer;
eos = true;
return STATUS_DONE;
}
@@ -198,31 +202,63 @@ namespace
LLAssetType::EType mAssetType;
};
LLPumpIO* theClientPump = NULL;
}
void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback)
{
LLHTTPClient::mCertVerifyCallback = callback;
}
static void request(
const std::string& url,
LLURLRequest::ERequestAction method,
Injector* body_injector,
LLCurl::ResponderPtr responder,
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
const LLSD& headers = LLSD())
const LLSD& headers = LLSD()
)
{
if (responder)
{
// For possible debug output from within the responder.
responder->setURL(url);
}
if (!LLHTTPClient::hasPump())
{
responder->completed(U32_MAX, "No pump", LLSD());
responder->fatalError("No pump");
return;
}
LLPumpIO::chain_t chain;
LLURLRequest* req = new LLURLRequest(method, url);
LLURLRequest* req;
try
{
req = new LLURLRequest(method, url);
}
catch(AICurlNoEasyHandle& error)
{
llwarns << "Failed to create LLURLRequest: " << error.what() << llendl;
// This is what the old LL code did: no recovery whatsoever (but also no leaks or crash).
return ;
}
req->checkRootCertificate(true);
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
<< headers << llendl;
// Insert custom headers if the caller sent any
if (headers.isMap())
{
if (headers.has("Cookie"))
{
req->allowCookies();
}
// Insert custom headers is the caller sent any
if (headers.isMap())
{
LLSD::map_const_iterator iter = headers.beginMap();
LLSD::map_const_iterator end = headers.endMap();
@@ -257,11 +293,6 @@ static void request(
}
}
if (responder)
{
responder->setURL(url);
}
req->setCallback(new LLHTTPClientURLAdaptor(responder));
if (method == LLURLRequest::HTTP_POST && gMessageSystem)
@@ -308,7 +339,7 @@ void LLHTTPClient::getByteRange(
std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
headers["Range"] = range;
}
request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
}
void LLHTTPClient::head(
@@ -347,12 +378,12 @@ class LLHTTPBuffer
public:
LLHTTPBuffer() { }
static size_t curl_write( void *ptr, size_t size, size_t nmemb, void *user_data)
static size_t curl_write(char* ptr, size_t size, size_t nmemb, void* user_data)
{
LLHTTPBuffer* self = (LLHTTPBuffer*)user_data;
size_t bytes = (size * nmemb);
self->mBuffer.append((char*)ptr,bytes);
self->mBuffer.append(ptr,bytes);
return nmemb;
}
@@ -403,99 +434,91 @@ static LLSD blocking_request(
)
{
lldebugs << "blockingRequest of " << url << llendl;
char curl_error_buffer[CURL_ERROR_SIZE] = "\0";
CURL* curlp = curl_easy_init();
LLHTTPBuffer http_buffer;
std::string body_str;
// other request method checks root cert first, we skip?
// * Set curl handle options
curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
curl_easy_setopt(curlp, CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function.
curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, LLHTTPBuffer::curl_write);
curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &http_buffer);
curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());
curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curl_error_buffer);
// * Setup headers (don't forget to free them after the call!)
curl_slist* headers_list = NULL;
if (headers.isMap())
S32 http_status = 499;
LLSD response = LLSD::emptyMap();
try
{
LLSD::map_const_iterator iter = headers.beginMap();
LLSD::map_const_iterator end = headers.endMap();
for (; iter != end; ++iter)
AICurlEasyRequest easy_request(false);
AICurlEasyRequest_wat curlEasyRequest_w(*easy_request);
LLHTTPBuffer http_buffer;
std::string body_str;
// * Set curl handle options
curlEasyRequest_w->setopt(CURLOPT_TIMEOUT, timeout); // seconds, see warning at top of function.
curlEasyRequest_w->setWriteCallback(&LLHTTPBuffer::curl_write, &http_buffer);
// * Setup headers.
if (headers.isMap())
{
std::ostringstream header;
header << iter->first << ": " << iter->second.asString() ;
lldebugs << "header = " << header.str() << llendl;
headers_list = curl_slist_append(headers_list, header.str().c_str());
LLSD::map_const_iterator iter = headers.beginMap();
LLSD::map_const_iterator end = headers.endMap();
for (; iter != end; ++iter)
{
std::ostringstream header;
header << iter->first << ": " << iter->second.asString() ;
lldebugs << "header = " << header.str() << llendl;
curlEasyRequest_w->addHeader(header.str().c_str());
}
}
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
if (method == LLURLRequest::HTTP_GET)
{
curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1);
}
else if (method == LLURLRequest::HTTP_POST)
{
curlEasyRequest_w->setopt(CURLOPT_POST, 1);
//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
std::ostringstream ostr;
LLSDSerialize::toXML(body, ostr);
body_str = ostr.str();
curlEasyRequest_w->setopt(CURLOPT_POSTFIELDS, body_str.c_str());
//copied from PHP libs, correct?
curlEasyRequest_w->addHeader("Content-Type: application/llsd+xml");
// copied from llurlrequest.cpp
// it appears that apache2.2.3 or django in etch is busted. If
// we do not clear the expect header, we get a 500. May be
// limited to django/mod_wsgi.
curlEasyRequest_w->addHeader("Expect:");
}
// * Do the action using curl, handle results
lldebugs << "HTTP body: " << body_str << llendl;
curlEasyRequest_w->addHeader("Accept: application/llsd+xml");
curlEasyRequest_w->finalizeRequest(url);
S32 curl_success = curlEasyRequest_w->perform();
curlEasyRequest_w->getinfo(CURLINFO_RESPONSE_CODE, &http_status);
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
{
// We expect 404s, don't spam for them.
llwarns << "CURL REQ URL: " << url << llendl;
llwarns << "CURL REQ METHOD TYPE: " << method << llendl;
llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl;
llwarns << "CURL REQ BODY: " << body_str << llendl;
llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
llwarns << "CURL ERROR: " << curlEasyRequest_w->getErrorString() << llendl;
llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl;
response["body"] = http_buffer.asString();
}
else
{
response["body"] = http_buffer.asLLSD();
lldebugs << "CURL response: " << http_buffer.asString() << llendl;
}
}
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
if (method == LLURLRequest::HTTP_GET)
catch(AICurlNoEasyHandle const& error)
{
curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);
}
else if (method == LLURLRequest::HTTP_POST)
{
curl_easy_setopt(curlp, CURLOPT_POST, 1);
//serialize to ostr then copy to str - need to because ostr ptr is unstable :(
std::ostringstream ostr;
LLSDSerialize::toXML(body, ostr);
body_str = ostr.str();
curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());
//copied from PHP libs, correct?
headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml");
// copied from llurlrequest.cpp
// it appears that apache2.2.3 or django in etch is busted. If
// we do not clear the expect header, we get a 500. May be
// limited to django/mod_wsgi.
headers_list = curl_slist_append(headers_list, "Expect:");
}
// * Do the action using curl, handle results
lldebugs << "HTTP body: " << body_str << llendl;
headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml");
CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);
if ( curl_result != CURLE_OK )
{
llinfos << "Curl is hosed - can't add headers" << llendl;
response["body"] = error.what();
}
LLSD response = LLSD::emptyMap();
S32 curl_success = curl_easy_perform(curlp);
S32 http_status = 499;
curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);
response["status"] = http_status;
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
{
// We expect 404s, don't spam for them.
llwarns << "CURL REQ URL: " << url << llendl;
llwarns << "CURL REQ METHOD TYPE: " << method << llendl;
llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl;
llwarns << "CURL REQ BODY: " << body_str << llendl;
llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
llwarns << "CURL ERROR: " << curl_error_buffer << llendl;
llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl;
response["body"] = http_buffer.asString();
}
else
{
response["body"] = http_buffer.asLLSD();
lldebugs << "CURL response: " << http_buffer.asString() << llendl;
}
if(headers_list)
{ // free the header list
curl_slist_free_all(headers_list);
}
// * Cleanup
curl_easy_cleanup(curlp);
return response;
}
@@ -595,7 +618,8 @@ bool LLHTTPClient::hasPump()
return theClientPump != NULL;
}
LLPumpIO &LLHTTPClient::getPump()
//static
LLPumpIO& LLHTTPClient::getPump()
{
return *theClientPump;
}

View File

@@ -34,11 +34,10 @@
#include <string>
#include <boost/intrusive_ptr.hpp>
#include "llurlrequest.h"
#include "llassettype.h"
#include "llcurl.h"
#include "lliopipe.h"
#include "llurlrequest.h"
extern const F32 HTTP_REQUEST_EXPIRY_SECS;
@@ -56,6 +55,9 @@ public:
typedef LLCurl::Responder Responder;
typedef LLCurl::ResponderPtr ResponderPtr;
// The default actually already ignores responses.
class ResponderIgnore : public Responder { };
/** @name non-blocking API */
//@{
static void head(
@@ -153,6 +155,12 @@ public:
///< for testing
static LLPumpIO &getPump();
///< Hippo special
static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
protected:
static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
};
#endif // LL_LLHTTPCLIENT_H

View File

@@ -33,6 +33,7 @@
#include "llapr.h"
#include "llbuffer.h"
#include "llbufferstream.h"
#include "llfasttimer.h"
#include "llhttpnode.h"
#include "lliopipe.h"
#include "lliosocket.h"

View File

@@ -76,7 +76,14 @@ LLIOPipe::~LLIOPipe()
}
//virtual
bool LLIOPipe::isValid()
bool LLIOPipe::hasExpiration(void) const
{
// LLIOPipe::hasNotExpired always returns true.
return false;
}
//virtual
bool LLIOPipe::hasNotExpired(void) const
{
return true ;
}

View File

@@ -149,7 +149,7 @@ public:
// The connection was lost.
STATUS_LOST_CONNECTION = -5,
// The totoal process time has exceeded the timeout.
// The total process time has exceeded the timeout.
STATUS_EXPIRED = -6,
// Keep track of the count of codes here.
@@ -231,7 +231,16 @@ public:
*/
virtual ~LLIOPipe();
virtual bool isValid() ;
/**
* @brief External expiration facility.
*
* If hasExpiration() returns true, then we need to check hasNotExpired()
* to see if the LLIOPipe is still valid. In the legacy LL code the
* latter was called isValid() and was overloaded for two purposes:
* either expiration or failure to initialize.
*/
virtual bool hasExpiration(void) const;
virtual bool hasNotExpired(void) const;
protected:
/**

View File

@@ -32,6 +32,7 @@
#include "llapr.h"
#include "llbuffer.h"
#include "llfasttimer.h"
#include "llhost.h"
#include "llmemtype.h"
#include "llpumpio.h"

View File

@@ -37,7 +37,6 @@
* OS poll indicates it will not block.
*/
#include "llaprpool.h"
#include "lliopipe.h"
#include "apr_network_io.h"
#include "llchainio.h"

View File

@@ -27,8 +27,8 @@
*/
#include "linden_common.h"
#include "llioutil.h"
#include "llfasttimer.h"
#include "llioutil.h"
/**
* LLIOFlush

View File

@@ -50,6 +50,7 @@
#include "llstring.h"
#include "lluuid.h"
#include "net.h"
#include "llaprpool.h"
//
// constants
@@ -57,7 +58,7 @@
const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
static bool gMailEnabled = true;
static apr_pool_t* gMailPool;
static LLAPRPool gMailPool;
static apr_sockaddr_t* gSockAddr;
static apr_socket_t* gMailSocket;
@@ -82,7 +83,7 @@ bool connect_smtp()
gSockAddr->sa.sin.sin_family,
SOCK_STREAM,
APR_PROTO_TCP,
gMailPool);
gMailPool());
if(ll_apr_warn_status(status)) return false;
status = apr_socket_connect(gMailSocket, gSockAddr);
if(ll_apr_warn_status(status))
@@ -139,19 +140,19 @@ BOOL LLMail::send(
}
// static
void LLMail::init(const std::string& hostname, apr_pool_t* pool)
void LLMail::init(const std::string& hostname)
{
gMailSocket = NULL;
if(hostname.empty() || !pool)
if (hostname.empty())
{
gMailPool = NULL;
gSockAddr = NULL;
gMailPool.destroy();
}
else
{
gMailPool = pool;
gMailPool.create();
// collect all the information into a socaddr sturcture. the
// Collect all the information into a sockaddr structure. the
// documentation is a bit unclear, but I either have to
// specify APR_UNSPEC or not specify any flags. I am not sure
// which option is better.
@@ -161,7 +162,7 @@ void LLMail::init(const std::string& hostname, apr_pool_t* pool)
APR_UNSPEC,
25,
APR_IPV4_ADDR_OK,
gMailPool);
gMailPool());
ll_apr_warn_status(status);
}
}

View File

@@ -27,15 +27,13 @@
#ifndef LL_LLMAIL_H
#define LL_LLMAIL_H
typedef struct apr_pool_t apr_pool_t;
#include "llsd.h"
class LLMail
{
public:
// if hostname is NULL, then the host is resolved as 'mail'
static void init(const std::string& hostname, apr_pool_t* pool);
static void init(const std::string& hostname);
// Allow all email transmission to be disabled/enabled.
static void enable(bool mail_enabled);

View File

@@ -388,7 +388,7 @@ bool LLMimeParser::Impl::parseHeaders(
// not to read past limit when we get() the newline.
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
istr.getline(mBuffer, max_get, '\r');
mScanCount += (S32)istr.gcount();
mScanCount += istr.gcount();
int c = istr.get();
if(EOF == c)
{
@@ -496,7 +496,7 @@ void LLMimeParser::Impl::scanPastSeparator(
// past limit when we get() the newline.
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
istr.getline(mBuffer, max_get, '\r');
mScanCount += (S32)istr.gcount();
mScanCount += istr.gcount();
if(istr.gcount() >= LINE_BUFFER_LENGTH - 1)
{
// that's way too long to be a separator, so ignore it.

View File

@@ -47,23 +47,22 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel
LLProxy::LLProxy():
mHTTPProxyEnabled(false),
mProxyMutex(),
mUDPProxy(),
mTCPProxy(),
mHTTPProxy(),
ProxyShared::ProxyShared(void):
mProxyType(LLPROXY_SOCKS),
mAuthMethodSelected(METHOD_NOAUTH),
mSocksUsername(),
mSocksPassword()
mAuthMethodSelected(METHOD_NOAUTH)
{
}
LLProxy::LLProxy():
mHTTPProxyEnabled(false)
{
}
LLProxy::~LLProxy()
{
stopSOCKSProxy();
disableHTTPProxy();
Shared_wat shared_w(mShared);
disableHTTPProxy(shared_w);
}
/**
@@ -78,15 +77,18 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
{
S32 result;
Unshared_rat unshared_r(mUnshared);
Shared_rat shared_r(mShared);
/* SOCKS 5 Auth request */
socks_auth_request_t socks_auth_request;
socks_auth_response_t socks_auth_response;
socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5
socks_auth_request.num_methods = 1; // Sending 1 method.
socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method.
socks_auth_request.methods = getSelectedAuthMethod(shared_r); // Send only the selected method.
result = tcp_blocking_handshake(mProxyControlChannel,
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
static_cast<char*>(static_cast<void*>(&socks_auth_request)),
sizeof(socks_auth_request),
static_cast<char*>(static_cast<void*>(&socks_auth_response)),
@@ -109,8 +111,8 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
if (socks_auth_response.method == METHOD_PASSWORD)
{
// The server has requested a username/password combination
std::string socks_username(getSocksUser());
std::string socks_password(getSocksPwd());
std::string socks_username(getSocksUser(shared_r));
std::string socks_password(getSocksPwd(shared_r));
U32 request_size = socks_username.size() + socks_password.size() + 3;
char * password_auth = new char[request_size];
password_auth[0] = 0x01;
@@ -121,7 +123,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
authmethod_password_reply_t password_reply;
result = tcp_blocking_handshake(mProxyControlChannel,
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
password_auth,
request_size,
static_cast<char*>(static_cast<void*>(&password_reply)),
@@ -157,7 +159,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,
// the client MUST use a port number and address of all zeros. RFC 1928"
result = tcp_blocking_handshake(mProxyControlChannel,
result = tcp_blocking_handshake(unshared_r->mProxyControlChannel,
static_cast<char*>(static_cast<void*>(&connect_request)),
sizeof(connect_request),
static_cast<char*>(static_cast<void*>(&connect_reply)),
@@ -176,10 +178,14 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
return SOCKS_UDP_FWD_NOT_GRANTED;
}
mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
mUDPProxy.setAddress(proxy.getAddress());
{
// Write access type and read access type are really the same, so unshared_w must be simply a reference.
Unshared_wat& unshared_w = unshared_r;
unshared_w->mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
unshared_w->mUDPProxy.setAddress(proxy.getAddress());
}
// The connection was successful. We now have the UDP port to send requests that need forwarding to.
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL;
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << unshared_r->mUDPProxy << LL_ENDL;
return SOCKS_OK;
}
@@ -197,9 +203,11 @@ S32 LLProxy::proxyHandshake(LLHost proxy)
*/
S32 LLProxy::startSOCKSProxy(LLHost host)
{
Unshared_wat unshared_w(mUnshared);
if (host.isOk())
{
mTCPProxy = host;
unshared_w->mTCPProxy = host;
}
else
{
@@ -209,13 +217,13 @@ S32 LLProxy::startSOCKSProxy(LLHost host)
// Close any running SOCKS connection.
stopSOCKSProxy();
mProxyControlChannel = tcp_open_channel(mTCPProxy);
if (!mProxyControlChannel)
unshared_w->mProxyControlChannel = tcp_open_channel(unshared_w->mTCPProxy);
if (!unshared_w->mProxyControlChannel)
{
return SOCKS_HOST_CONNECT_FAILED;
}
S32 status = proxyHandshake(mTCPProxy);
S32 status = proxyHandshake(unshared_w->mTCPProxy);
if (status != SOCKS_OK)
{
@@ -246,14 +254,16 @@ void LLProxy::stopSOCKSProxy()
// then we must shut down any HTTP proxy operations. But it is allowable if web
// proxy is being used to continue proxying HTTP.
if (LLPROXY_SOCKS == getHTTPProxyType())
Shared_rat shared_r(mShared);
if (LLPROXY_SOCKS == getHTTPProxyType(shared_r))
{
disableHTTPProxy();
Shared_wat shared_w(shared_r);
disableHTTPProxy(shared_w);
}
if (mProxyControlChannel)
Unshared_wat unshared_w(mUnshared);
if (unshared_w->mProxyControlChannel)
{
tcp_close_channel(&mProxyControlChannel);
tcp_close_channel(&unshared_w->mProxyControlChannel);
}
}
@@ -262,9 +272,7 @@ void LLProxy::stopSOCKSProxy()
*/
void LLProxy::setAuthNone()
{
LLMutexLock lock(&mProxyMutex);
mAuthMethodSelected = METHOD_NOAUTH;
Shared_wat(mShared)->mAuthMethodSelected = METHOD_NOAUTH;
}
/**
@@ -288,11 +296,10 @@ bool LLProxy::setAuthPassword(const std::string &username, const std::string &pa
return false;
}
LLMutexLock lock(&mProxyMutex);
mAuthMethodSelected = METHOD_PASSWORD;
mSocksUsername = username;
mSocksPassword = password;
Shared_wat shared_w(mShared);
shared_w->mAuthMethodSelected = METHOD_PASSWORD;
shared_w->mSocksUsername = username;
shared_w->mSocksPassword = password;
return true;
}
@@ -314,12 +321,10 @@ bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
return false;
}
LLMutexLock lock(&mProxyMutex);
mHTTPProxy = httpHost;
mProxyType = type;
Shared_wat shared_w(mShared);
mHTTPProxyEnabled = true;
shared_w->mHTTPProxy = httpHost;
shared_w->mProxyType = type;
return true;
}
@@ -335,9 +340,8 @@ bool LLProxy::enableHTTPProxy()
{
bool ok;
LLMutexLock lock(&mProxyMutex);
ok = (mHTTPProxy.isOk());
Shared_rat shared_r(mShared);
ok = (shared_r->mHTTPProxy.isOk());
if (ok)
{
mHTTPProxyEnabled = true;
@@ -346,54 +350,6 @@ bool LLProxy::enableHTTPProxy()
return ok;
}
/**
* @brief Disable the HTTP proxy.
*/
void LLProxy::disableHTTPProxy()
{
LLMutexLock lock(&mProxyMutex);
mHTTPProxyEnabled = false;
}
/**
* @brief Get the currently selected HTTP proxy type
*/
LLHttpProxyType LLProxy::getHTTPProxyType() const
{
LLMutexLock lock(&mProxyMutex);
return mProxyType;
}
/**
* @brief Get the SOCKS 5 password.
*/
std::string LLProxy::getSocksPwd() const
{
LLMutexLock lock(&mProxyMutex);
return mSocksPassword;
}
/**
* @brief Get the SOCKS 5 username.
*/
std::string LLProxy::getSocksUser() const
{
LLMutexLock lock(&mProxyMutex);
return mSocksUsername;
}
/**
* @brief Get the currently selected SOCKS 5 authentication method.
*
* @return Returns either none or password.
*/
LLSocks5AuthType LLProxy::getSelectedAuthMethod() const
{
LLMutexLock lock(&mProxyMutex);
return mAuthMethodSelected;
}
/**
* @brief Stop the LLProxy and make certain that any APR pools and classes are deleted before terminating APR.
*
@@ -406,57 +362,6 @@ void LLProxy::cleanupClass()
deleteSingleton();
}
void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
{
applyProxySettings(handle->getEasy());
}
void LLProxy::applyProxySettings(LLCurl::Easy* handle)
{
applyProxySettings(handle->getCurlHandle());
}
/**
* @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
*
* This method has been designed to be safe to call from
* any thread in the viewer. This allows requests in the
* texture fetch thread to be aware of the proxy settings.
* When the HTTP proxy is enabled, the proxy mutex will
* be locked every time this method is called.
*
* @param handle A pointer to a valid CURL request, before it has been performed.
*/
void LLProxy::applyProxySettings(CURL* handle)
{
// Do a faster unlocked check to see if we are supposed to proxy.
if (mHTTPProxyEnabled)
{
// We think we should proxy, lock the proxy mutex.
LLMutexLock lock(&mProxyMutex);
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
if (mHTTPProxyEnabled)
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
if (mProxyType == LLPROXY_SOCKS)
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
if (mAuthMethodSelected == METHOD_PASSWORD)
{
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
}
}
else
{
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
}
}
}
}
/**
* @brief Send one TCP packet and receive one in return.
*

View File

@@ -33,6 +33,7 @@
#include "llmemory.h"
#include "llsingleton.h"
#include "llthread.h"
#include "aithreadsafe.h"
#include <string>
// SOCKS error codes returned from the StartProxy method
@@ -206,41 +207,92 @@ enum LLSocks5AuthType
* The implementation of HTTP proxying is handled by libcurl. LLProxy
* is responsible for managing the HTTP proxy options and provides a
* thread-safe method to apply those options to a curl request
* (LLProxy::applyProxySettings()). This method is overloaded
* to accommodate the various abstraction libcurl layers that exist
* throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
*
* If you are working with LLCurl or LLCurlEasyRequest objects,
* the configured proxy settings will be applied in the constructors
* of those request handles. If you are working with CURL objects
* directly, you will need to pass the handle of the request to
* applyProxySettings() before issuing the request.
* (LLProxy::applyProxySettings()).
*
* To ensure thread safety, all LLProxy members that relate to the HTTP
* proxy require the LLProxyMutex to be locked before accessing.
*/
struct ProxyUnshared
{
/*###########################################################################################
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD.
###########################################################################################*/
// UDP proxy address and port
LLHost mUDPProxy;
// TCP proxy control channel address and port
LLHost mTCPProxy;
// socket handle to proxy TCP control channel
LLSocket::ptr_t mProxyControlChannel;
/*###########################################################################################
END OF UNSHARED MEMBERS
###########################################################################################*/
};
struct ProxyShared
{
ProxyShared(void);
/*###########################################################################################
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD.
###########################################################################################*/
// HTTP proxy address and port
LLHost mHTTPProxy;
// Currently selected HTTP proxy type. Can be web or SOCKS.
LLHttpProxyType mProxyType;
// SOCKS 5 selected authentication method.
LLSocks5AuthType mAuthMethodSelected;
// SOCKS 5 username
std::string mSocksUsername;
// SOCKS 5 password
std::string mSocksPassword;
/*###########################################################################################
END OF SHARED MEMBERS
###########################################################################################*/
};
class LLProxy: public LLSingleton<LLProxy>
{
LOG_CLASS(LLProxy);
public:
typedef AISTAccessConst<ProxyUnshared> Unshared_crat; // Constant Read Access Type for Unshared (cannot be converted to write access).
typedef AISTAccess<ProxyUnshared> Unshared_rat; // Read Access Type for Unshared (same as write access type, since we don't lock at all).
typedef AISTAccess<ProxyUnshared> Unshared_wat; // Write Access Type, for Unshared.
typedef AIReadAccessConst<ProxyShared> Shared_crat; // Constant Read Access Type for Shared (cannot be converted to write access).
typedef AIReadAccess<ProxyShared> Shared_rat; // Read Access Type for Shared.
typedef AIWriteAccess<ProxyShared> Shared_wat; // Write Access Type for Shared.
/*###########################################################################################
METHODS THAT DO NOT LOCK mProxyMutex!
Public methods that only access variables not shared between threads.
###########################################################################################*/
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
LLProxy();
// Static check for enabled status for UDP packets. Call from main thread only.
static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; }
// Static check for enabled status for UDP packets. Called from main thread only.
static bool isSOCKSProxyEnabled(void) { llassert(is_main_thread()); return sUDPProxyEnabled; }
// Get the UDP proxy address and port. Call from main thread only.
LLHost getUDPProxy() const { return mUDPProxy; }
// Get the UDP proxy address and port. Called from main thread only.
LLHost getUDPProxy(void) const { return Unshared_crat(mUnshared)->mUDPProxy; }
/*###########################################################################################
END OF NON-LOCKING METHODS
End of methods that only access variables not shared between threads.
###########################################################################################*/
// Return true if there is a good chance that the HTTP proxy is currently enabled.
bool HTTPProxyEnabled(void) const { return mHTTPProxyEnabled; }
/*###########################################################################################
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
Public methods that access variables shared between threads.
###########################################################################################*/
// Destructor, closes open connections. Do not call directly, use cleanupClass().
~LLProxy();
@@ -251,9 +303,7 @@ public:
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
// Safe to call from any thread.
void applyProxySettings(CURL* handle);
void applyProxySettings(LLCurl::Easy* handle);
void applyProxySettings(LLCurlEasyRequest* handle);
void applyProxySettings(AICurlEasyRequest_wat const& curlEasyRequest_w);
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
S32 startSOCKSProxy(LLHost host);
@@ -273,30 +323,37 @@ public:
bool enableHTTPProxy();
// Stop proxying HTTP packets. Call from main thread only.
void disableHTTPProxy();
// Note that this needs shared_w to be passed because we want the shared members to be locked when this is reset to false.
void disableHTTPProxy(Shared_wat const& shared_w) { mHTTPProxyEnabled = false; }
void disableHTTPProxy(void) { disableHTTPProxy(Shared_wat(mShared)); }
// Get the currently selected HTTP proxy address and port
LLHost const& getHTTPProxy(Shared_crat const& shared_r) const { return shared_r->mHTTPProxy; }
// Get the currently selected HTTP proxy type
LLHttpProxyType getHTTPProxyType(Shared_crat const& shared_r) const { return shared_r->mProxyType; }
// Get the currently selected auth method.
LLSocks5AuthType getSelectedAuthMethod(Shared_crat const& shared_r) const { return shared_r->mAuthMethodSelected; }
// SOCKS 5 username and password accessors.
std::string getSocksUser(Shared_crat const& shared_r) const { return shared_r->mSocksUsername; }
std::string getSocksPwd(Shared_crat const& shared_r) const { return shared_r->mSocksPassword; }
/*###########################################################################################
END OF LOCKING METHODS
End of methods that access variables shared between threads.
###########################################################################################*/
private:
/*###########################################################################################
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
Private methods that access variables shared between threads.
###########################################################################################*/
// Perform a SOCKS 5 authentication and UDP association with the proxy server.
S32 proxyHandshake(LLHost proxy);
// Get the currently selected auth method.
LLSocks5AuthType getSelectedAuthMethod() const;
// Get the currently selected HTTP proxy type
LLHttpProxyType getHTTPProxyType() const;
std::string getSocksPwd() const;
std::string getSocksUser() const;
/*###########################################################################################
END OF LOCKING METHODS
End of methods that access variables shared between threads.
###########################################################################################*/
private:
@@ -304,49 +361,16 @@ private:
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
mutable LLAtomic32<bool> mHTTPProxyEnabled;
// Mutex to protect shared members in non-main thread calls to applyProxySettings().
mutable LLMutex mProxyMutex;
/*###########################################################################################
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE!
###########################################################################################*/
// Is the UDP proxy enabled?
static bool sUDPProxyEnabled;
// UDP proxy address and port
LLHost mUDPProxy;
// TCP proxy control channel address and port
LLHost mTCPProxy;
AIThreadSafeSingleThreadDC<ProxyUnshared> mUnshared;
AIThreadSafeDC<ProxyShared> mShared;
// socket handle to proxy TCP control channel
LLSocket::ptr_t mProxyControlChannel;
/*###########################################################################################
END OF UNSHARED MEMBERS
###########################################################################################*/
/*###########################################################################################
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex!
###########################################################################################*/
// HTTP proxy address and port
LLHost mHTTPProxy;
// Currently selected HTTP proxy type. Can be web or socks.
LLHttpProxyType mProxyType;
// SOCKS 5 selected authentication method.
LLSocks5AuthType mAuthMethodSelected;
// SOCKS 5 username
std::string mSocksUsername;
// SOCKS 5 password
std::string mSocksPassword;
/*###########################################################################################
END OF SHARED MEMBERS
###########################################################################################*/
public:
// For thread-safe read access. Use the _crat access types with these.
AIThreadSafeSingleThreadDC<ProxyUnshared> const& unshared_lockobj(void) const { return mUnshared; }
AIThreadSafeDC<ProxyShared> const& shared_lockobj(void) const { return mShared; }
};
#endif

View File

@@ -4,31 +4,25 @@
* @date 2004-11-21
* @brief Implementation of the i/o pump and related functions.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -40,12 +34,11 @@
#include "apr_poll.h"
#include "llapr.h"
#include "llfasttimer.h"
#include "llmemtype.h"
#include "llstl.h"
#include "llstat.h"
#include "llthread.h"
#include "llfasttimer.h"
#include <iterator> //VS2010
// These should not be enabled in production, but they can be
// intensely useful during development for finding certain kinds of
@@ -191,17 +184,28 @@ LLPumpIO::LLPumpIO(void) :
LLPumpIO::~LLPumpIO()
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
cleanup();
#if LL_THREADS_APR
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
#endif
mChainsMutex = NULL;
mCallbackMutex = NULL;
if(mPollset)
{
// lldebugs << "cleaning up pollset" << llendl;
apr_pollset_destroy(mPollset);
mPollset = NULL;
}
}
bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
bool LLPumpIO::addChain(chain_t const& chain, F32 timeout)
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
if(chain.empty()) return false;
#if LL_THREADS_APR
LLScopedLock lock(mChainsMutex);
#endif
chain_t::const_iterator it = chain.begin();
chain_t::const_iterator const end = chain.end();
if (it == end) return false;
LLChainInfo info;
info.setTimeoutSeconds(timeout);
info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray);
@@ -212,14 +216,17 @@ bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
#else
lldebugs << "LLPumpIO::addChain() " << chain[0] <<llendl;
#endif
chain_t::const_iterator it = chain.begin();
chain_t::const_iterator end = chain.end();
for(; it != end; ++it)
{
info.mHasExpiration = info.mHasExpiration || (*it)->hasExpiration();
link.mPipe = (*it);
link.mChannels = info.mData->nextChannel();
info.mChainLinks.push_back(link);
}
#if LL_THREADS_APR
LLScopedLock lock(mChainsMutex);
#endif
mPendingChains.push_back(info);
return true;
}
@@ -236,11 +243,10 @@ bool LLPumpIO::addChain(
// description, we need to have that description matched to a
// particular buffer.
if(!data) return false;
if(links.empty()) return false;
links_t::const_iterator link = links.begin();
links_t::const_iterator const end = links.end();
if (link == end) return false;
#if LL_THREADS_APR
LLScopedLock lock(mChainsMutex);
#endif
#if LL_DEBUG_PIPE_TYPE_IN_PUMP
lldebugs << "LLPumpIO::addChain() " << links[0].mPipe << " '"
<< typeid(*(links[0].mPipe)).name() << "'" << llendl;
@@ -252,6 +258,17 @@ bool LLPumpIO::addChain(
info.mChainLinks = links;
info.mData = data;
info.mContext = context;
for (; link != end; ++link)
{
if (link->mPipe->hasExpiration())
{
info.mHasExpiration = true;
break;
}
}
#if LL_THREADS_APR
LLScopedLock lock(mChainsMutex);
#endif
mPendingChains.push_back(info);
return true;
}
@@ -438,6 +455,15 @@ void LLPumpIO::pump()
static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain)
{
std::for_each(
(*run_chain).mDescriptors.begin(),
(*run_chain).mDescriptors.end(),
ll_delete_apr_pollset_fd_client_data());
return mRunningChains.erase(run_chain);
}
//timeout is in microseconds
void LLPumpIO::pump(const S32& poll_timeout)
{
@@ -583,10 +609,16 @@ void LLPumpIO::pump(const S32& poll_timeout)
// << (*run_chain).mChainLinks[0].mPipe
// << " because we reached the end." << llendl;
#endif
run_chain = mRunningChains.erase(run_chain);
run_chain = removeRunningChain(run_chain);
continue;
}
}
else if(isChainExpired(*run_chain))
{
run_chain = removeRunningChain(run_chain);
continue;
}
PUMP_DEBUG;
if((*run_chain).mLock)
{
@@ -694,11 +726,7 @@ void LLPumpIO::pump(const S32& poll_timeout)
PUMP_DEBUG;
// This chain is done. Clean up any allocated memory and
// erase the chain info.
std::for_each(
(*run_chain).mDescriptors.begin(),
(*run_chain).mDescriptors.end(),
ll_delete_apr_pollset_fd_client_data());
run_chain = mRunningChains.erase(run_chain);
run_chain = removeRunningChain(run_chain);
// *NOTE: may not always need to rebuild the pollset.
mRebuildPollset = true;
@@ -833,22 +861,6 @@ void LLPumpIO::initialize(void)
apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
#endif
}
void LLPumpIO::cleanup()
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
#if LL_THREADS_APR
if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
#endif
mChainsMutex = NULL;
mCallbackMutex = NULL;
if(mPollset)
{
// lldebugs << "cleaning up pollset" << llendl;
apr_pollset_destroy(mPollset);
mPollset = NULL;
}
}
void LLPumpIO::rebuildPollset()
{
@@ -1083,10 +1095,30 @@ void LLPumpIO::processChain(LLChainInfo& chain)
PUMP_DEBUG;
}
bool LLPumpIO::isChainExpired(LLChainInfo& chain)
{
if(!chain.mHasExpiration)
{
return false ;
}
for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter)
{
if(!(*iter).mPipe->hasNotExpired())
{
return true ;
}
}
return false ;
}
bool LLPumpIO::handleChainError(
LLChainInfo& chain,
LLIOPipe::EStatus error)
{
DoutEntering(dc::notice, "LLPumpIO::handleChainError(" << (void*)&chain << ", " << LLIOPipe::lookupStatusString(error) << ")");
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
links_t::reverse_iterator rit;
if(chain.mHead == chain.mChainLinks.end())
@@ -1124,6 +1156,9 @@ bool LLPumpIO::handleChainError(
#endif
keep_going = false;
break;
case LLIOPipe::STATUS_EXPIRED:
keep_going = false;
break ;
default:
if(LLIOPipe::isSuccess(error))
{
@@ -1146,6 +1181,7 @@ LLPumpIO::LLChainInfo::LLChainInfo() :
mInit(false),
mLock(0),
mEOS(false),
mHasExpiration(false),
mDescriptorsPool(new LLAPRPool(LLThread::tldata().mRootPool))
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);

View File

@@ -4,31 +4,25 @@
* @date 2004-11-19
* @brief Declaration of pump class which manages io chains.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -351,12 +345,13 @@ protected:
// basic member data
bool mInit;
bool mEOS;
bool mHasExpiration;
S32 mLock;
LLFrameTimer mTimer;
links_t::iterator mHead;
links_t mChainLinks;
LLIOPipe::buffer_ptr_t mData;
bool mEOS;
LLIOPipe::buffer_ptr_t mData;
LLSD mContext;
// tracking inside the pump
@@ -397,8 +392,8 @@ protected:
protected:
void initialize();
void cleanup();
current_chain_t removeRunningChain(current_chain_t& chain) ;
/**
* @brief Given the internal state of the chains, rebuild the pollset
* @see setConditional()
@@ -425,6 +420,9 @@ protected:
*/
bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error);
//if the chain is expired, remove it
bool isChainExpired(LLChainInfo& chain) ;
public:
/**
* @brief Return number of running chains.

View File

@@ -88,7 +88,7 @@ bool LLSDMessage::httpListener(const LLSD& request)
request,
url, "POST", reply, error),
LLSD(), // headers
(F32)timeout);
timeout);
return false;
}
@@ -151,11 +151,11 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)
{
if (success)
{
mResponder->result(payload);
mResponder->pubResult(payload);
}
else
{
mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
mResponder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
}
/*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/

View File

@@ -317,7 +317,7 @@ void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data)
// S64 not supported in LLSD so we just truncate it
case MVT_S64:
addS32(varname, (S32)*(S64*)mvci.getData());
addS32(varname, *(S64*)mvci.getData());
break;
case MVT_F32:

View File

@@ -1,255 +0,0 @@
/**
* @file llsdrpcclient.cpp
* @author Phoenix
* @date 2005-11-05
* @brief Implementation of the llsd client classes.
*
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llsdrpcclient.h"
#include "llbufferstream.h"
#include "llfasttimer.h"
#include "llfiltersd2xmlrpc.h"
#include "llmemtype.h"
#include "llpumpio.h"
#include "llsd.h"
#include "llsdserialize.h"
#include "llurlrequest.h"
/**
* String constants
*/
static std::string LLSDRPC_RESPONSE_NAME("response");
static std::string LLSDRPC_FAULT_NAME("fault");
/**
* LLSDRPCResponse
*/
LLSDRPCResponse::LLSDRPCResponse() :
mIsError(false),
mIsFault(false)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
// virtual
LLSDRPCResponse::~LLSDRPCResponse()
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
bool LLSDRPCResponse::extractResponse(const LLSD& sd)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
bool rv = true;
if(sd.has(LLSDRPC_RESPONSE_NAME))
{
mReturnValue = sd[LLSDRPC_RESPONSE_NAME];
mIsFault = false;
}
else if(sd.has(LLSDRPC_FAULT_NAME))
{
mReturnValue = sd[LLSDRPC_FAULT_NAME];
mIsFault = true;
}
else
{
mReturnValue.clear();
mIsError = true;
rv = false;
}
return rv;
}
static LLFastTimer::DeclareTimer FTM_SDRPC_RESPONSE("SDRPC Response");
// virtual
LLIOPipe::EStatus LLSDRPCResponse::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LLFastTimer t(FTM_SDRPC_RESPONSE);
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
if(mIsError)
{
error(pump);
}
else if(mIsFault)
{
fault(pump);
}
else
{
response(pump);
}
PUMP_DEBUG;
return STATUS_DONE;
}
/**
* LLSDRPCClient
*/
LLSDRPCClient::LLSDRPCClient() :
mState(STATE_NONE),
mQueue(EPBQ_PROCESS)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
// virtual
LLSDRPCClient::~LLSDRPCClient()
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
}
bool LLSDRPCClient::call(
const std::string& uri,
const std::string& method,
const LLSD& parameter,
LLSDRPCResponse* response,
EPassBackQueue queue)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
//llinfos << "RPC: " << uri << "." << method << "(" << *parameter << ")"
// << llendl;
if(method.empty() || !response)
{
return false;
}
mState = STATE_READY;
mURI.assign(uri);
std::stringstream req;
req << LLSDRPC_REQUEST_HEADER_1 << method
<< LLSDRPC_REQUEST_HEADER_2;
LLSDSerialize::toNotation(parameter, req);
req << LLSDRPC_REQUEST_FOOTER;
mRequest = req.str();
mQueue = queue;
mResponse = response;
return true;
}
bool LLSDRPCClient::call(
const std::string& uri,
const std::string& method,
const std::string& parameter,
LLSDRPCResponse* response,
EPassBackQueue queue)
{
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
//llinfos << "RPC: " << uri << "." << method << "(" << parameter << ")"
// << llendl;
if(method.empty() || parameter.empty() || !response)
{
return false;
}
mState = STATE_READY;
mURI.assign(uri);
std::stringstream req;
req << LLSDRPC_REQUEST_HEADER_1 << method
<< LLSDRPC_REQUEST_HEADER_2 << parameter
<< LLSDRPC_REQUEST_FOOTER;
mRequest = req.str();
mQueue = queue;
mResponse = response;
return true;
}
static LLFastTimer::DeclareTimer FTM_PROCESS_SDRPC_CLIENT("SDRPC Client");
// virtual
LLIOPipe::EStatus LLSDRPCClient::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
bool& eos,
LLSD& context,
LLPumpIO* pump)
{
LLFastTimer t(FTM_PROCESS_SDRPC_CLIENT);
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
if((STATE_NONE == mState) || (!pump))
{
// You should have called the call() method already.
return STATUS_PRECONDITION_NOT_MET;
}
EStatus rv = STATUS_DONE;
switch(mState)
{
case STATE_READY:
{
PUMP_DEBUG;
// lldebugs << "LLSDRPCClient::process_impl STATE_READY" << llendl;
buffer->append(
channels.out(),
(U8*)mRequest.c_str(),
mRequest.length());
context[CONTEXT_DEST_URI_SD_LABEL] = mURI;
mState = STATE_WAITING_FOR_RESPONSE;
break;
}
case STATE_WAITING_FOR_RESPONSE:
{
PUMP_DEBUG;
// The input channel has the sd response in it.
//lldebugs << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE"
// << llendl;
LLBufferStream resp(channels, buffer.get());
LLSD sd;
LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in()));
LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get();
if (!response)
{
mState = STATE_DONE;
break;
}
response->extractResponse(sd);
if(EPBQ_PROCESS == mQueue)
{
LLPumpIO::chain_t chain;
chain.push_back(mResponse);
pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS);
}
else
{
pump->respond(mResponse.get());
}
mState = STATE_DONE;
break;
}
case STATE_DONE:
default:
PUMP_DEBUG;
llinfos << "invalid state to process" << llendl;
rv = STATUS_ERROR;
break;
}
return rv;
}

Some files were not shown because too many files have changed in this diff Show More