From f8bf11d574722923655389e9be3961796000e0a5 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 15 Nov 2012 13:51:16 +0100 Subject: [PATCH 01/10] More clearly state the implications of the NoVerifySSLCert debug option --- indra/newview/app_settings/settings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0ccac5736..06dfc90e4 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9104,7 +9104,7 @@ Found in Advanced->Rendering->Info Displays NoVerifySSLCert Comment - Do not verify SSL peers + Do not verify SSL certificates. WARNING: Setting this to TRUE allows anyone to impersonate the server and intercept your data (man in the middle attack). Persist 1 Type From e3f30fece9c1a8ad0d0fd6f14c598d93e91b2672 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 16 Nov 2012 16:06:30 +0100 Subject: [PATCH 02/10] Fix print_diagnostics for windows. --- indra/llmessage/aicurlthread.cpp | 37 ++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 7009d5bf3..55e891137 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1971,6 +1971,10 @@ void HTTPTimeout::done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode DoutCurl("done: mStalled set to -1"); } +// Libcurl uses GetTickCount on windows, with a resolution of 10 to 16 ms. +// As a result, we can not assume that namelookup_time == 0 has a special meaning. +#define LOWRESTIMER LL_WINDOWS + void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url) { llwarns << "Request to \"" << curl_easy_request->getLowercaseHostname() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl; @@ -1981,8 +1985,15 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch curl_easy_request->getinfo(CURLINFO_APPCONNECT_TIME, &appconnect_time); curl_easy_request->getinfo(CURLINFO_PRETRANSFER_TIME, &pretransfer_time); curl_easy_request->getinfo(CURLINFO_STARTTRANSFER_TIME, &starttransfer_time); - if (namelookup_time == 0) + if (namelookup_time == 0 +#if LOWRESTIMER + && connect_time == 0 +#endif + ) { +#if LOWRESTIMER + llinfos << "Hostname seems to have been still in the DNS cache." << llendl; +#else llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but DNS lookup did not occur according to timings. Expected CURLE_COULDNT_RESOLVE_PROXY or CURLE_COULDNT_RESOLVE_HOST!" << llendl; llassert(connect_time == 0); llassert(appconnect_time == 0); @@ -1990,17 +2001,26 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch llassert(starttransfer_time == 0); // Fatal error for diagnostics. return; +#endif } // If namelookup_time is less than 500 microseconds, then it's very likely just a DNS cache lookup. else if (namelookup_time < 500e-6) { +#if LOWRESTIMER + llinfos << "Hostname was most likely still in DNS cache (or lookup occured in under ~10ms)." << llendl; +#else llinfos << "Hostname was still in DNS cache." << llendl; +#endif } else { - llwarns << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << llendl; + llinfos << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << llendl; } - if (connect_time == 0) + if (connect_time == 0 +#if LOWRESTIMER + && namelookup_time > 0 // connect_time, when set, is namelookup_time + something. +#endif + ) { llwarns << "Huh? Curl returned CURLE_OPERATION_TIMEDOUT, but connection did not occur according to timings. Expected CURLE_COULDNT_CONNECT!" << llendl; llassert(appconnect_time == 0); @@ -2010,16 +2030,21 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch return; } // If connect_time is almost equal to namelookup_time, then it was just set because it was already connected. - if (connect_time - namelookup_time <= 1e-6) + if (connect_time - namelookup_time <= 1e-5) { +#if LOWRESTIMER // Assuming 10ms resolution. + llinfos << "The socket was most likely already connected (or you connected to a proxy with a connect time of under ~10 ms)." << llendl; +#else llinfos << "The socket was already connected (to remote or proxy)." << llendl; +#endif + // I'm assuming that the SSL/TLS handshake can be measured with a low res timer. if (appconnect_time == 0) { llwarns << "The SSL/TLS handshake never occurred according to the timings!" << llendl; return; } // If appconnect_time is almost equal to connect_time, then it was just set because this is a connection re-use. - if (appconnect_time - connect_time <= 1e-6) + if (appconnect_time - connect_time <= 1e-5) { llinfos << "Connection with HTTP server was already established; this was a re-used connection." << llendl; } @@ -2043,7 +2068,7 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch llwarns << "The transfer never happened because there was too much in the pipeline (apparently)." << llendl; return; } - else if (pretransfer_time - appconnect_time >= 1e-6) + else if (pretransfer_time - appconnect_time >= 1e-5) { llinfos << "Apparently there was a delay, due to waits in line for the pipeline, of " << (pretransfer_time - appconnect_time) << " seconds before the transfer began." << llendl; } From e781870da35ab1adef68146bfbd6e37065577986 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 17 Nov 2012 04:55:34 +0100 Subject: [PATCH 03/10] Fix Ratany Residents crash --- indra/llmessage/aicurlprivate.h | 3 ++- indra/llmessage/aicurlthread.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index a1d449998..327637a3d 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -376,7 +376,8 @@ class CurlEasyRequest : public CurlEasyHandle { // This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan). LLPointer& get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj); // Accessor for mTimeout with optional creation of orphaned object (if lockobj != NULL). - LLPointer& httptimeout(ThreadSafeBufferedCurlEasyRequest* lockobj = NULL) { if (lockobj && !mTimeout) create_timeout_object(lockobj); return mTimeout; } + LLPointer& httptimeout(ThreadSafeBufferedCurlEasyRequest* lockobj = NULL) + { if (lockobj && !mTimeout) { create_timeout_object(lockobj); mTimeoutIsOrphan = true; } return mTimeout; } // Return true if no data has been received on the latest socket (if any) for too long. bool has_stalled(void) const { return mTimeout && mTimeout->has_stalled(); } diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 55e891137..0b4a6e121 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -2284,7 +2284,7 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size char const* const header_line = static_cast(data); size_t const header_len = size * nmemb; - if (self_w->httptimeout()->data_received(header_len)) // Update timeout administration. + if (self_w->httptimeout(lockobj)->data_received(header_len)) // Update timeout administration. { // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. return 0; From 5d1a138c5c78320ddaabe12133ea880cfb6df580 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 17 Nov 2012 05:16:21 +0100 Subject: [PATCH 04/10] Code clean up of code related to previous commit. --- indra/llmessage/aicurl.cpp | 10 +++++++--- indra/llmessage/aicurlprivate.h | 7 +++---- indra/llmessage/aicurlthread.cpp | 11 ++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 2353f24bd..bfd2a2243 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -1148,12 +1148,16 @@ void CurlEasyRequest::set_timeout_opts(void) setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); } -void CurlEasyRequest::create_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj) +void CurlEasyRequest::create_timeout_object(void) { + ThreadSafeBufferedCurlEasyRequest* lockobj = NULL; +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + lockobj = static_cast(this)->get_lockobj(); +#endif mTimeout = new curlthread::HTTPTimeout(mTimeoutPolicy, lockobj); } -LLPointer& CurlEasyRequest::get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj) +LLPointer& CurlEasyRequest::get_timeout_object(void) { if (mTimeoutIsOrphan) { @@ -1162,7 +1166,7 @@ LLPointer& CurlEasyRequest::get_timeout_object(ThreadSa } else { - create_timeout_object(lockobj); + create_timeout_object(); } return mTimeout; } diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index 327637a3d..abb663d4a 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -316,7 +316,7 @@ class CurlEasyRequest : public CurlEasyHandle { static CURLcode curlCtxCallback(CURL* curl, void* sslctx, void* parm); // Called from get_timeout_object and httptimeout. - void create_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj); + void create_timeout_object(void); public: // Set default options that we want applied to all curl easy handles. @@ -374,10 +374,9 @@ class CurlEasyRequest : public CurlEasyHandle { std::string const& getLowercaseHostname(void) const { return mLowercaseHostname; } // Called by CurlSocketInfo to allow access to the last (after a redirect) HTTPTimeout object related to this request. // This creates mTimeout (unless mTimeoutIsOrphan is set in which case it adopts the orphan). - LLPointer& get_timeout_object(ThreadSafeBufferedCurlEasyRequest* lockobj); + LLPointer& get_timeout_object(void); // Accessor for mTimeout with optional creation of orphaned object (if lockobj != NULL). - LLPointer& httptimeout(ThreadSafeBufferedCurlEasyRequest* lockobj = NULL) - { if (lockobj && !mTimeout) { create_timeout_object(lockobj); mTimeoutIsOrphan = true; } return mTimeout; } + LLPointer& httptimeout(void) { if (!mTimeout) { create_timeout_object(); mTimeoutIsOrphan = true; } return mTimeout; } // Return true if no data has been received on the latest socket (if any) for too long. bool has_stalled(void) const { return mTimeout && mTimeout->has_stalled(); } diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 0b4a6e121..1fbe57d3e 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -775,7 +775,7 @@ CurlSocketInfo::CurlSocketInfo(MultiHandle& multi_handle, CURL* easy, curl_socke // CurlSocketInfo objects for a request and we need upload_finished() to be called on the HTTPTimeout // object related to THIS CurlSocketInfo. AICurlEasyRequest_wat easy_request_w(*lockobj); - mTimeout = easy_request_w->get_timeout_object(lockobj); + mTimeout = easy_request_w->get_timeout_object(); } CurlSocketInfo::~CurlSocketInfo() @@ -2259,11 +2259,8 @@ size_t BufferedCurlEasyRequest::curlReadCallback(char* data, size_t size, size_t S32 bytes = size * nmemb; // The maximum amount to read. self_w->mLastRead = self_w->getInput()->readAfter(sChannels.out(), self_w->mLastRead, (U8*)data, bytes); self_w->mRequestTransferedBytes += bytes; // Accumulate data sent to the server. - // Timeout administration. Note that it can happen that we get here - // before the socket callback has been called, because the silly libcurl - // writes headers without informing us. In that case it's OK to create - // the Timeout object on the fly, so pass lockobj. - if (self_w->httptimeout(lockobj)->data_sent(bytes)) + // Timeout administration. + if (self_w->httptimeout()->data_sent(bytes)) { // Transfer timed out. Return CURL_READFUNC_ABORT which will abort with error CURLE_ABORTED_BY_CALLBACK. return CURL_READFUNC_ABORT; @@ -2284,7 +2281,7 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size char const* const header_line = static_cast(data); size_t const header_len = size * nmemb; - if (self_w->httptimeout(lockobj)->data_received(header_len)) // Update timeout administration. + if (self_w->httptimeout()->data_received(header_len)) // Update timeout administration. { // Transfer timed out. Return 0 which will abort with error CURLE_WRITE_ERROR. return 0; From 52673f52493b282c2b58af3f896605739850bfbb Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 18 Nov 2012 02:41:37 +0100 Subject: [PATCH 05/10] Slight update of README --- README | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/README b/README index 55c159679..4a048e09c 100644 --- a/README +++ b/README @@ -9,15 +9,30 @@ Sin-gu-la-ri-ty (noun) - a distinctive feature, a uniqueness; a point at which continuity breaks up; a point in history at which machine becomes smarter than humanity and/or fuses with it indivisively; or simply a cool sounding word with -my initials in it :) +the initials S.G. in it :) -Singularity Viewer is a Second Life protocol compatible client application. It -can be used to access Second LIfe service as well as a number of other such as -those based upon OpenSim plattform. It is directly based upon source code of -Ascent Viewer by Balseraph Software Group, which is in turn based upon source -code released by Linden Lab, with contributions from various sources. +Singularity Viewer is a SecondLife(tm) protocol compatible client application. +It can be used to access SecondLife services as well as a number of others such +as those based upon the OpenSim platform. + +Singulariy is maintained by a small group of volunteers who can be contacted +both, in-world (SingularityViewer group) as well on IRC (#SingularityViewer +@ FreeNode). Bug requests and features requests can be submitted through our +Issue Tracket (http://code.google.com/p/singularity-viewer/issues/list or from +the viewer menu: Help --> Bug Reporting --> Singularity Issue Tracker...) + As this Readme grows out of date, please refer to http://www.singularityviewer.org/about + +00000000011111111112222222222333333333344444444445555555555666666666677777777778 +12345678901234567890123456789012345678901234567890123456789012345678901234567890 + +History + +The Singularity viewer was started by Siana Gearz in November 2010 by forking it +of the Ascent Viewer, by Balseraph Software Group, which in turn was based upon +source code released by Linden Lab. + From 2400d146ce1037306173e9ac27c4eca07fdcc647 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 19 Nov 2012 04:01:54 +0100 Subject: [PATCH 06/10] Clear the command queue after flushing statemachines Flushing the state machines can cause remove commands to be added to the command queue, so clearing it needs to be after. --- indra/llmessage/aicurl.cpp | 1 + indra/llmessage/aicurlprivate.h | 1 + indra/llmessage/aicurlthread.cpp | 12 ++++++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index bfd2a2243..11668f5fc 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -418,6 +418,7 @@ void cleanupCurl(void) if (CurlMultiHandle::getTotalMultiHandles() != 0) llwarns << "Not all CurlMultiHandle objects were destroyed!" << llendl; AIStateMachine::flush(); + clearCommandQueue(); Stats::print(); ssl_cleanup(); diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index abb663d4a..ee28ae849 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -119,6 +119,7 @@ inline CURLMcode check_multi_code(CURLMcode code) { AICurlInterface::Stats::mult bool curlThreadIsRunning(void); void wakeUpCurlThread(void); void stopCurlThread(void); +void clearCommandQueue(void); #define DECLARE_SETOPT(param_type) \ CURLcode setopt(CURLoption option, param_type parameter) diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 1fbe57d3e..ae686c087 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1065,6 +1065,10 @@ void AICurlThread::wakeup_thread(void) DoutEntering(dc::curl, "AICurlThread::wakeup_thread"); llassert(is_main_thread()); + // If we are already exiting the viewer then return immediately. + if (!mRunning) + return; + // Try if curl thread is still awake and if so, pass the new commands directly. if (mWakeUpMutex.tryLock()) { @@ -2148,10 +2152,14 @@ void stopCurlThread(void) ms_sleep(10); } Dout(dc::curl, "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((100 - count) * 10) << "ms."); - // Clear the command queue, for a cleaner cleanup. + } +} + +void clearCommandQueue(void) +{ + // Clear the command queue now in order to avoid the global deinitialization order fiasco. command_queue_wat command_queue_w(command_queue); command_queue_w->clear(); - } } //----------------------------------------------------------------------------- From aab195a6eb3f833114a679936228122ad6d6d0bf Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 19 Nov 2012 04:42:02 +0100 Subject: [PATCH 07/10] Fix deinitialization order fiasco. --- indra/llmessage/aicurlperhost.cpp | 11 ++++++++--- indra/llmessage/aicurlperhost.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/indra/llmessage/aicurlperhost.cpp b/indra/llmessage/aicurlperhost.cpp index 724d5bccd..7f7490865 100644 --- a/indra/llmessage/aicurlperhost.cpp +++ b/indra/llmessage/aicurlperhost.cpp @@ -56,12 +56,17 @@ PerHostRequestQueuePtr PerHostRequestQueue::instance(std::string const& hostname //static void PerHostRequestQueue::release(PerHostRequestQueuePtr& instance) { - if (instance->lastone()) + if (instance->exactly_two_left()) // Being 'instance' and the one in sInstanceMap. { + // The viewer can be have left main() we can't access the global sInstanceMap anymore. + if (LLApp::isStopped()) + { + return; + } instance_map_wat instance_map_w(sInstanceMap); - // It is possible that 'lastone' is not up to date anymore. + // It is possible that 'exactly_two_left' is not up to date anymore. // Therefore, recheck the condition now that we have locked sInstanceMap. - if (!instance->lastone()) + if (!instance->exactly_two_left()) { // Some other thread added this host in the meantime. return; diff --git a/indra/llmessage/aicurlperhost.h b/indra/llmessage/aicurlperhost.h index dac9d70c0..c464d490c 100644 --- a/indra/llmessage/aicurlperhost.h +++ b/indra/llmessage/aicurlperhost.h @@ -118,7 +118,7 @@ class PerHostRequestQueue { class RefCountedThreadSafePerHostRequestQueue : public threadsafe_PerHostRequestQueue { public: RefCountedThreadSafePerHostRequestQueue(void) : mReferenceCount(0) { } - bool lastone(void) const { llassert(mReferenceCount >= 2); return mReferenceCount == 2; } + bool exactly_two_left(void) const { return mReferenceCount == 2; } private: // Used by PerHostRequestQueuePtr. Object is deleted when reference count reaches zero. From 0f54e5fe46994d6c1915fa36b2b0a1b1ffd10202 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 22 Nov 2012 03:55:10 +0100 Subject: [PATCH 08/10] Remove erroneous assertion. --- indra/llmessage/aicurl.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 11668f5fc..a0104c2a8 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -492,8 +492,6 @@ void Stats::print(void) // Even more strict, BufferedCurlEasyRequest may not be created directly either, only as // base class of ThreadSafeBufferedCurlEasyRequest. llassert(BufferedCurlEasyRequest_count == ThreadSafeBufferedCurlEasyRequest_count); - // Each AICurlEasyRequestStateMachine is responsible for exactly one easy handle. - llassert(easy_handles >= AICurlEasyRequest_count); // Each AICurlEasyRequestStateMachine has one AICurlEasyRequest member. llassert(AICurlEasyRequest_count >= AICurlEasyRequestStateMachine_count); // AIFIXME: is this really always the case? And why? From 165bebda3ec275740ba2299c17a3754f33791114 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 23 Nov 2012 03:19:39 +0100 Subject: [PATCH 09/10] Compile error and warning fixes for DEBUG_CURLIO without CWDEBUG. --- indra/llmessage/aicurlthread.cpp | 6 ++++-- indra/llmessage/debug_libcurl.cpp | 4 ++-- indra/llqtwebkit/llstyle.cpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index ae686c087..f39f38678 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -1613,7 +1613,9 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons ThreadSafeBufferedCurlEasyRequest* lockobj = iter->get_ptr().get(); #endif mAddedEasyRequests.erase(iter); +#if CWDEBUG Dout(dc::curl, "MultiHandle::remove_easy_request: Removed AICurlEasyRequest " << (void*)lockobj << "; now processing " << mAddedEasyRequests.size() << " easy handles."); +#endif // Attempt to add a queued request, if any. PerHostRequestQueue_wat(*per_host)->add_queued_to(this); @@ -2361,10 +2363,10 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size #if defined(CWDEBUG) || defined(DEBUG_CURLIO) int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr) { + BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr; + #ifdef CWDEBUG using namespace ::libcwd; - - BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr; std::ostringstream marker; marker << (void*)request->get_lockobj(); libcw_do.push_marker(); diff --git a/indra/llmessage/debug_libcurl.cpp b/indra/llmessage/debug_libcurl.cpp index 512bc696c..825cffcc9 100644 --- a/indra/llmessage/debug_libcurl.cpp +++ b/indra/llmessage/debug_libcurl.cpp @@ -624,7 +624,7 @@ void debug_curl_easy_reset(CURL* handle) CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) { - CURLcode ret; + CURLcode ret = CURLE_UNKNOWN_OPTION; // Suppress compiler warning. va_list ap; union param_type { long along; @@ -841,7 +841,7 @@ CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle) CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...) { - CURLMcode ret; + CURLMcode ret = CURLM_UNKNOWN_OPTION; // Suppress compiler warning. va_list ap; union param_type { long along; diff --git a/indra/llqtwebkit/llstyle.cpp b/indra/llqtwebkit/llstyle.cpp index ecd2b3eb8..8822d481a 100644 --- a/indra/llqtwebkit/llstyle.cpp +++ b/indra/llqtwebkit/llstyle.cpp @@ -71,7 +71,7 @@ void LLStyle::drawControl(ControlElement element, const QStyleOption *option, QP QPlastiqueStyle::drawControl(element, &localOption, painter, widget); return; } - + default: break; } From e17405d80ac3f86f163bcd690b615c112f434073 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 28 Nov 2012 17:04:24 +0100 Subject: [PATCH 10/10] Fixed snapping of rotation in the edge-on case Patch by https://codereview.secondlife.com/users/cron.stardust/ Jira: https://jira.secondlife.com/browse/STORM-1919 --- doc/contributions.txt | 1 + indra/newview/llmaniprotate.cpp | 232 +++++++++++++++++--------------- 2 files changed, 123 insertions(+), 110 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 882dca18c..9eb4520cd 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -248,6 +248,7 @@ Celierra Darling VWR-6975 Cron Stardust VWR-10579 + STORM-1919 Cypren Christenson SNOW-129 SNOW-140 diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index 304f00e4b..33baf4231 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -1381,74 +1381,28 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) BOOL hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); projected_mouse -= snap_plane_center; - S32 snap_plane = 0; - - F32 dot = cam_to_snap_plane * constraint_axis; - if (llabs(dot) < 0.01f) - { - // looking at ring edge on, project onto view plane and check if mouse is past ring - getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); - projected_mouse -= snap_plane_center; - dot = projected_mouse * constraint_axis; - if (projected_mouse * constraint_axis > 0) - { - snap_plane = 1; - } - projected_mouse -= dot * constraint_axis; - } - else if (dot > 0.f) - { - // look for mouse position outside and in front of snap circle - if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) - { - snap_plane = 1; - } - } - else - { - // look for mouse position inside or in back of snap circle - if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) - { - snap_plane = 1; - } - } - - if (snap_plane == 0) - { - // try other plane - snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f)); - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) - { - cam_to_snap_plane.setVec(1.f, 0.f, 0.f); - } - else - { - cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent(); - cam_to_snap_plane.normVec(); - } - - hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); - projected_mouse -= snap_plane_center; - - dot = cam_to_snap_plane * constraint_axis; + if (gSavedSettings.getBOOL("SnapEnabled")) { + S32 snap_plane = 0; + + F32 dot = cam_to_snap_plane * constraint_axis; if (llabs(dot) < 0.01f) { // looking at ring edge on, project onto view plane and check if mouse is past ring getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); projected_mouse -= snap_plane_center; dot = projected_mouse * constraint_axis; - if (projected_mouse * constraint_axis < 0) + if (projected_mouse * constraint_axis > 0) { - snap_plane = 2; + snap_plane = 1; } projected_mouse -= dot * constraint_axis; } - else if (dot < 0.f) + else if (dot > 0.f) { // look for mouse position outside and in front of snap circle if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) { - snap_plane = 2; + snap_plane = 1; } } else @@ -1456,78 +1410,136 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) // look for mouse position inside or in back of snap circle if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) { - snap_plane = 2; + snap_plane = 1; } } - } - - if (snap_plane > 0) - { - LLVector3 cam_at_axis; - if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) + + if (snap_plane == 0) { - cam_at_axis.setVec(1.f, 0.f, 0.f); + // try other plane + snap_plane_center = (center - (constraint_axis * mRadiusMeters * 0.5f)); + if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) + { + cam_to_snap_plane.setVec(1.f, 0.f, 0.f); + } + else + { + cam_to_snap_plane = snap_plane_center - gAgentCamera.getCameraPositionAgent(); + cam_to_snap_plane.normVec(); + } + + hit = getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, constraint_axis); + projected_mouse -= snap_plane_center; + + dot = cam_to_snap_plane * constraint_axis; + if (llabs(dot) < 0.01f) + { + // looking at ring edge on, project onto view plane and check if mouse is past ring + getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_to_snap_plane); + projected_mouse -= snap_plane_center; + dot = projected_mouse * constraint_axis; + if (projected_mouse * constraint_axis < 0) + { + snap_plane = 2; + } + projected_mouse -= dot * constraint_axis; + } + else if (dot < 0.f) + { + // look for mouse position outside and in front of snap circle + if (hit && projected_mouse.magVec() > SNAP_GUIDE_INNER_RADIUS * mRadiusMeters && projected_mouse * cam_to_snap_plane < 0.f) + { + snap_plane = 2; + } + } + else + { + // look for mouse position inside or in back of snap circle + if (projected_mouse.magVec() < SNAP_GUIDE_INNER_RADIUS * mRadiusMeters || projected_mouse * cam_to_snap_plane > 0.f || !hit) + { + snap_plane = 2; + } + } } - else - { - cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent(); - cam_at_axis.normVec(); - } - - // first, project mouse onto screen plane at point tangent to rotation radius. - getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis); - // project that point onto rotation plane - projected_mouse -= snap_plane_center; - projected_mouse -= projected_vec(projected_mouse, constraint_axis); - - F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec()); - F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; - if (llabs(mouse_lateral_dist) > 0.01f) - { - mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - - (mouse_lateral_dist * mouse_lateral_dist)); - } - LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis); - projected_mouse -= mouse_depth * projected_camera_at; - - if (!mInSnapRegime) - { - mSmoothRotate = TRUE; - } - mInSnapRegime = TRUE; - // 0 to 360 deg - F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); - F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); - //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); - - LLVector3 object_axis; - getObjectAxisClosestToMouse(object_axis); - object_axis = object_axis * first_object_node->mSavedRotation; - - // project onto constraint plane - object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); - object_axis.normVec(); - - if (relative_mouse_angle < SNAP_ANGLE_DETENTE) + if (snap_plane > 0) { - F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f)); - angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); + LLVector3 cam_at_axis; + if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) + { + cam_at_axis.setVec(1.f, 0.f, 0.f); + } + else + { + cam_at_axis = snap_plane_center - gAgentCamera.getCameraPositionAgent(); + cam_at_axis.normVec(); + } + + // first, project mouse onto screen plane at point tangent to rotation radius. + getMousePointOnPlaneAgent(projected_mouse, x, y, snap_plane_center, cam_at_axis); + // project that point onto rotation plane + projected_mouse -= snap_plane_center; + projected_mouse -= projected_vec(projected_mouse, constraint_axis); + + F32 mouse_lateral_dist = llmin(SNAP_GUIDE_INNER_RADIUS * mRadiusMeters, projected_mouse.magVec()); + F32 mouse_depth = SNAP_GUIDE_INNER_RADIUS * mRadiusMeters; + if (llabs(mouse_lateral_dist) > 0.01f) + { + mouse_depth = sqrtf((SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) * (SNAP_GUIDE_INNER_RADIUS * mRadiusMeters) - + (mouse_lateral_dist * mouse_lateral_dist)); + } + LLVector3 projected_camera_at = cam_at_axis - projected_vec(cam_at_axis, constraint_axis); + projected_mouse -= mouse_depth * projected_camera_at; + + if (!mInSnapRegime) + { + mSmoothRotate = TRUE; + } + mInSnapRegime = TRUE; + // 0 to 360 deg + F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); + + F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); + //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); + + LLVector3 object_axis; + getObjectAxisClosestToMouse(object_axis); + object_axis = object_axis * first_object_node->mSavedRotation; + + // project onto constraint plane + object_axis = object_axis - (object_axis * getConstraintAxis()) * getConstraintAxis(); + object_axis.normVec(); + + if (relative_mouse_angle < SNAP_ANGLE_DETENTE) + { + F32 quantized_mouse_angle = mouse_angle - (relative_mouse_angle - (SNAP_ANGLE_DETENTE * 0.5f)); + angle = (quantized_mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); + } + else + { + angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); + } + return LLQuaternion( -angle, constraint_axis ); } else { - angle = (mouse_angle * DEG_TO_RAD) - atan2(object_axis * axis1, object_axis * axis2); + if (mInSnapRegime) + { + mSmoothRotate = TRUE; + } + mInSnapRegime = FALSE; } - return LLQuaternion( -angle, constraint_axis ); } - else - { + else { if (mInSnapRegime) { mSmoothRotate = TRUE; } mInSnapRegime = FALSE; - + } + + if (!mInSnapRegime) + { LLVector3 up_from_axis = mCenterToCamNorm % constraint_axis; up_from_axis.normVec(); LLVector3 cur_intersection;