summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/lljsonrpcws.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcorehttp/lljsonrpcws.cpp')
-rw-r--r--indra/llcorehttp/lljsonrpcws.cpp75
1 files changed, 48 insertions, 27 deletions
diff --git a/indra/llcorehttp/lljsonrpcws.cpp b/indra/llcorehttp/lljsonrpcws.cpp
index 5b704e6322..f04738d805 100644
--- a/indra/llcorehttp/lljsonrpcws.cpp
+++ b/indra/llcorehttp/lljsonrpcws.cpp
@@ -31,9 +31,8 @@
#include "llsdjson.h"
#include "lldate.h"
#include "llcoros.h"
-#include "llmainthreadtask.h"
-#include "lleventtimer.h"
#include "lltimer.h"
+#include "workqueue.h"
#include <boost/json.hpp>
@@ -44,27 +43,10 @@
void LLJSONRPCConnection::onOpen()
{
LL_INFOS("JSONRPC") << "JSON-RPC connection opened" << LL_ENDL;
-
- // Start the recurring timeout sweep timer on the main thread. The timer
- // is canceled in onClose() before the connection can be destroyed, so
- // capturing `this` is safe. Keep a weak_ptr so we can safely test
- // whether the timer instance still exists at cancellation time.
- LLEventTimer* timer = LLEventTimer::run_every(TIMEOUT_SWEEP_INTERVAL,
- [this]() { sweepTimeouts(); });
- mTimeoutTimer = timer->getWeak();
}
void LLJSONRPCConnection::onClose()
{
- // Cancel the sweep timer if it is still alive. LLEventTimer's instance
- // tracker keeps a shared_ptr with a no-op deleter, so raw `delete` is
- // the documented cancellation idiom (see lleventtimer.h).
- if (auto timer = mTimeoutTimer.lock())
- {
- delete timer.get();
- }
- mTimeoutTimer.reset();
-
// Move the pending-request map out under the lock so we can invoke the
// callbacks without holding it (callbacks may themselves call into this
// connection).
@@ -132,7 +114,7 @@ void LLJSONRPCConnection::onMessage(const std::string& message)
catch (const std::exception& e)
{
LL_WARNS("JSONRPC") << "Exception processing JSON-RPC message: " << e.what() << LL_ENDL;
- sendError(LLSD(), InternalError(e.what()));
+ sendError(LLSD(), InternalError());
}
}
@@ -181,6 +163,18 @@ void LLJSONRPCConnection::processRequest(const LLSD& request)
LL_DEBUGS("JSONRPC") << "Processing " << (is_notification ? "notification" : "request")
<< " for method: " << method << LL_ENDL;
+ // Nothing for a peer that has not proven itself, and nothing said of
+ // which methods there are.
+ if (!mAuthenticated)
+ {
+ LL_DEBUGS("JSONRPC") << "Refused " << method << " from a peer not authenticated" << LL_ENDL;
+ if (!is_notification)
+ {
+ sendError(id, UnauthorizedError());
+ }
+ return;
+ }
+
// Resolve the handler under the mutex, then invoke it unlocked.
MethodHandler handler;
bool is_async = false;
@@ -219,7 +213,7 @@ void LLJSONRPCConnection::processRequest(const LLSD& request)
throw InternalError("Connection expired before method " + method
+ " could be launched");
}
- LLMainThreadTask::dispatch(
+ bool posted = LL::WorkQueue::postToMainLoop(
[handler, method, id, params, conn]()
{
LLCoros::instance().launch(
@@ -255,7 +249,9 @@ void LLJSONRPCConnection::processRequest(const LLSD& request)
{
if (conn->isConnected())
{
- conn->sendError(id, InternalError(e.what()));
+ LL_WARNS("JSONRPC") << "Exception in async method " << method
+ << ": " << e.what() << LL_ENDL;
+ conn->sendError(id, InternalError());
}
else
{
@@ -265,6 +261,11 @@ void LLJSONRPCConnection::processRequest(const LLSD& request)
}
});
});
+ if (!posted)
+ {
+ LL_WARNS("JSONRPC") << "Main loop unavailable; failing async method " << method << LL_ENDL;
+ throw InternalError("Viewer is shutting down; cannot service " + method);
+ }
return;
}
@@ -302,7 +303,9 @@ void LLJSONRPCConnection::processRequest(const LLSD& request)
{
if (!is_notification)
{
- sendError(id, InternalError(e.what()));
+ LL_WARNS("JSONRPC") << "Exception in handler for " << method
+ << ": " << e.what() << LL_ENDL;
+ sendError(id, InternalError());
}
else
{
@@ -446,8 +449,7 @@ void LLJSONRPCConnection::sweepTimeouts()
for (auto& [id, callback] : expired)
{
- LL_WARNS("JSONRPC") << "Request " << id << " timed out after "
- << REQUEST_TIMEOUT_SECONDS << " seconds" << LL_ENDL;
+ LL_WARNS("JSONRPC") << "Request " << id << " timed out" << LL_ENDL;
if (callback)
{
LLSD error;
@@ -566,7 +568,7 @@ LLSD LLJSONRPCConnection::makeEnvelope(const LLSD& id,
return env;
}
-LLSD LLJSONRPCConnection::call(const std::string& method, const LLSD& params, ResponseCallback callback)
+LLSD LLJSONRPCConnection::call(const std::string& method, const LLSD& params, ResponseCallback callback, F64 timeout)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_WEBSOCKET;
LLSD id = generateId();
@@ -579,7 +581,7 @@ LLSD LLJSONRPCConnection::call(const std::string& method, const LLSD& params, Re
{
LLMutexLock lock(&mMutex);
mPendingRequests[id_str] = std::move(callback);
- mPendingDeadlines.push({ LLTimer::getTotalSeconds() + REQUEST_TIMEOUT_SECONDS, id_str });
+ mPendingDeadlines.push({ LLTimer::getTotalSeconds() + timeout, id_str });
}
// Send the request
@@ -715,6 +717,25 @@ void LLJSONRPCServer::onConnectionClosed(const LLWebsocketMgr::WSConnection::ptr
<< getConnectionCount() << LL_ENDL;
}
+bool LLJSONRPCServer::update()
+{
+ // Main thread, once per frame; throttled to TIMEOUT_SWEEP_INTERVAL.
+ if (mSweepTimer.getElapsedTimeF32() < LLJSONRPCConnection::TIMEOUT_SWEEP_INTERVAL)
+ {
+ return true;
+ }
+ mSweepTimer.reset();
+
+ for (const auto& conn : getConnections())
+ {
+ if (auto rpc = std::dynamic_pointer_cast<LLJSONRPCConnection>(conn))
+ {
+ rpc->sweepTimeouts();
+ }
+ }
+ return true;
+}
+
void LLJSONRPCServer::setupConnectionMethods(LLJSONRPCConnection::ptr_t connection)
{
LLMutexLock lock(&mGlobalMethodsMutex);