net/Socket.hpp | 2 wsd/Admin.cpp | 148 ++++++++++++++++++++++++++++------------------------- wsd/Admin.hpp | 71 ++++++------------------- wsd/Exceptions.hpp | 9 --- wsd/LOOLWSD.cpp | 12 +++- 5 files changed, 107 insertions(+), 135 deletions(-)
New commits: commit d19b6eb3512931bbb2dc45004ca75aef682d9709 Author: Michael Meeks <[email protected]> Date: Wed Mar 15 16:39:13 2017 +0000 Move memstats & cpustats into the main polling thread. We can calculate the timeout ourselves easily and add it to the polling loop simplifying life. Also ensure we never send messages to a non-authenticated thread. diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp index e4b616b..a3b7035 100644 --- a/wsd/Admin.cpp +++ b/wsd/Admin.cpp @@ -32,7 +32,6 @@ #include "FileServer.hpp" #include "IoUtil.hpp" #include "Protocol.hpp" -#include "LOOLWebSocket.hpp" // FIXME: remove. #include "LOOLWSD.hpp" #include "Log.hpp" #include "Storage.hpp" @@ -87,16 +86,18 @@ void AdminRequestHandler::handleMessage(bool /* fin */, WSOpCode /* code */, std } else { - sendTextFrame("InvalidAuthToken"); + sendFrame("InvalidAuthToken"); LOG_TRC("Invalid auth token"); + shutdown(); return; } } if (!_isAuthenticated) { - sendTextFrame("NotAuthenticated"); + sendFrame("NotAuthenticated"); LOG_TRC("Not authenticated"); + shutdown(); return; } else if (tokens[0] == "documents" || @@ -229,7 +230,11 @@ AdminRequestHandler::AdminRequestHandler(Admin* adminManager, void AdminRequestHandler::sendTextFrame(const std::string& message) { UnitWSD::get().onAdminQueryMessage(message); - sendFrame(message); + std::cerr << "Admin: send text frame '" << message << "'\n"; + if (_isAuthenticated) + sendFrame(message); + else + LOG_TRC("Skip sending message to non-authenticated client: '" << message << "'"); } bool AdminRequestHandler::handleInitialRequest( @@ -273,7 +278,10 @@ bool AdminRequestHandler::handleInitialRequest( Admin::Admin() : SocketPoll("admin"), _model(AdminModel()), - _forKitPid(-1) + _forKitPid(-1), + _lastTotalMemory(0), + _memStatsTaskIntervalMs(5000), + _cpuStatsTaskIntervalMs(5000) { LOG_INF("Admin ctor."); @@ -281,20 +289,54 @@ Admin::Admin() : const auto totalMem = getTotalMemoryUsage(); LOG_TRC("Total memory used: " << totalMem); _model.addMemStats(totalMem); - - _memStatsTask = new MemoryStatsTask(this); - _memStatsTimer.schedule(_memStatsTask, _memStatsTaskInterval, _memStatsTaskInterval); - - _cpuStatsTask = new CpuStats(this); - _cpuStatsTimer.schedule(_cpuStatsTask, _cpuStatsTaskInterval, _cpuStatsTaskInterval); } Admin::~Admin() { LOG_INF("~Admin dtor."); +} + +void Admin::pollingThread() +{ + std::chrono::steady_clock::time_point lastCPU, lastMem; + + lastCPU = std::chrono::steady_clock::now(); + lastMem = lastCPU; + + while (!_stop && !TerminationFlag && !ShutdownRequestFlag) + { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + int cpuWait = _cpuStatsTaskIntervalMs - + std::chrono::duration_cast<std::chrono::milliseconds>(now - lastCPU).count(); + if (cpuWait < 0) + { + // TODO: implement me ... + lastCPU = now; + cpuWait += _cpuStatsTaskIntervalMs; + } + int memWait = _memStatsTaskIntervalMs - + std::chrono::duration_cast<std::chrono::milliseconds>(now - lastCPU).count(); + if (memWait < 0) + { + std::unique_lock<std::mutex> modelLock(getLock()); + const auto totalMem = getTotalMemoryUsage(); + if (totalMem != _lastTotalMemory) + { + LOG_TRC("Total memory used: " << totalMem); + _lastTotalMemory = totalMem; + } + + _model.addMemStats(totalMem); - _memStatsTask->cancel(); - _cpuStatsTask->cancel(); + lastMem = now; + memWait += _memStatsTaskIntervalMs; + } + + // Handle websockets & other work. + int timeout = std::min(cpuWait, memWait); + LOG_TRC("Admin poll for " << timeout << "ms"); + poll(timeout); + } } void Admin::addDoc(const std::string& docKey, Poco::Process::PID pid, const std::string& filename, const std::string& sessionId) @@ -316,43 +358,18 @@ void Admin::rmDoc(const std::string& docKey) _model.removeDocument(docKey); } -void MemoryStatsTask::run() -{ - std::unique_lock<std::mutex> modelLock(_admin->getLock()); - const auto totalMem = _admin->getTotalMemoryUsage(); - - if (totalMem != _lastTotalMemory) - { - LOG_TRC("Total memory used: " << totalMem); - _lastTotalMemory = totalMem; - } - - _admin->getModel().addMemStats(totalMem); -} - -void CpuStats::run() -{ - //TODO: Implement me - //std::unique_lock<std::mutex> modelLock(_admin->getLock()); - //model.addCpuStats(totalMem); -} - void Admin::rescheduleMemTimer(unsigned interval) { - _memStatsTask->cancel(); - _memStatsTaskInterval = interval; - _memStatsTask = new MemoryStatsTask(this); - _memStatsTimer.schedule(_memStatsTask, _memStatsTaskInterval, _memStatsTaskInterval); + _memStatsTaskIntervalMs = interval; LOG_INF("Memory stats interval changed - New interval: " << interval); + wakeup(); } void Admin::rescheduleCpuTimer(unsigned interval) { - _cpuStatsTask->cancel(); - _cpuStatsTaskInterval = interval; - _cpuStatsTask = new CpuStats(this); - _cpuStatsTimer.schedule(_cpuStatsTask, _cpuStatsTaskInterval, _cpuStatsTaskInterval); + _cpuStatsTaskIntervalMs = interval; LOG_INF("CPU stats interval changed - New interval: " << interval); + wakeup(); } unsigned Admin::getTotalMemoryUsage() @@ -373,12 +390,12 @@ unsigned Admin::getTotalMemoryUsage() unsigned Admin::getMemStatsInterval() { - return _memStatsTaskInterval; + return _memStatsTaskIntervalMs; } unsigned Admin::getCpuStatsInterval() { - return _cpuStatsTaskInterval; + return _cpuStatsTaskIntervalMs; } AdminModel& Admin::getModel() diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp index 2b8d4f0..da51cdc 100644 --- a/wsd/Admin.hpp +++ b/wsd/Admin.hpp @@ -22,7 +22,6 @@ #include "AdminModel.hpp" #include "Log.hpp" -#include <LOOLWebSocket.hpp> #include "net/WebSocketHandler.hpp" @@ -76,6 +75,9 @@ public: startThread(); } + /// Custom poll thread function + void pollingThread() override; + unsigned getTotalMemoryUsage(); /// Update the Admin Model. @@ -114,58 +116,10 @@ private: AdminModel _model; std::mutex _modelMutex; int _forKitPid; - - Poco::Util::Timer _memStatsTimer; - Poco::AutoPtr<MemoryStatsTask> _memStatsTask; - unsigned _memStatsTaskInterval = 5000; - - Poco::Util::Timer _cpuStatsTimer; - Poco::Util::TimerTask::Ptr _cpuStatsTask; - unsigned _cpuStatsTaskInterval = 5000; -}; - -/// Memory statistics. -class MemoryStatsTask : public Poco::Util::TimerTask -{ -public: - MemoryStatsTask(Admin* admin) - : _admin(admin), - _lastTotalMemory(0) - { - LOG_DBG("Memory stat ctor"); - } - - ~MemoryStatsTask() - { - LOG_DBG("Memory stat dtor"); - } - - long getLastTotalMemory() { return _lastTotalMemory; } - - void run() override; - -private: - Admin* _admin; long _lastTotalMemory; -}; - -/// CPU statistics. -class CpuStats : public Poco::Util::TimerTask -{ -public: - CpuStats(Admin* /*admin*/) - { - LOG_DBG("Cpu stat ctor"); - } - ~CpuStats() - { - LOG_DBG("Cpu stat dtor"); - } - - void run() override; - -private: + std::atomic<int> _memStatsTaskIntervalMs; + std::atomic<int> _cpuStatsTaskIntervalMs; }; #endif diff --git a/wsd/Exceptions.hpp b/wsd/Exceptions.hpp index b05d98d..b97263e 100644 --- a/wsd/Exceptions.hpp +++ b/wsd/Exceptions.hpp @@ -58,15 +58,6 @@ public: using LoolException::LoolException; }; -/// An generic error-message exception meant to -/// propagate via a valid LOOLWebSocket to the client. -/// The contents of what() will be displayed on screen. -class WebSocketErrorMessageException : public LoolException -{ -public: - using LoolException::LoolException; -}; - #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 0089723f693a8d9549b9abb7236c2f5bae4d633a Author: Michael Meeks <[email protected]> Date: Wed Mar 15 16:25:29 2017 +0000 Admin: review error handling on auth. failure. diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp index d3e684b..e4b616b 100644 --- a/wsd/Admin.cpp +++ b/wsd/Admin.cpp @@ -232,10 +232,10 @@ void AdminRequestHandler::sendTextFrame(const std::string& message) sendFrame(message); } -bool AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak, - const Poco::Net::HTTPRequest& request) +bool AdminRequestHandler::handleInitialRequest( + const std::weak_ptr<StreamSocket> &socketWeak, + const Poco::Net::HTTPRequest& request) { - HTTPResponse response; auto socket = socketWeak.lock(); // Different session id pool for admin sessions (?) @@ -260,28 +260,12 @@ bool AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> return true; } -// FIXME: ... should we move ourselves to an Admin poll [!?] ... -// Probably [!] ... and use this termination thing ? ... -// Perhaps that should be the 'Admin' instance / sub-class etc. -// FIXME: have name 'admin' etc. -// []() { return TerminationFlag.load(); }); -#if 0 - catch(const Poco::Net::NotAuthenticatedException& exc) - { - LOG_INF("Admin::NotAuthenticated"); - response.set("WWW-Authenticate", "Basic realm=\"online\""); - response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED); - response.setContentLength(0); - socket->send(response); - } - catch (const std::exception& exc) - { - LOG_INF("Admin::handleRequest: Exception: " << exc.what()); - response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST); - response.setContentLength(0); - socket->send(response); - } -#endif + HTTPResponse response; + response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST); + response.setContentLength(0); + LOG_INF("Admin::handleInitialRequest bad request"); + socket->send(response); + return false; } diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp index 4332e27..2b8d4f0 100644 --- a/wsd/Admin.hpp +++ b/wsd/Admin.hpp @@ -51,7 +51,6 @@ private: private: Admin* _admin; -// std::shared_ptr<LOOLWebSocket> _adminWs; FIXME - this is us now ! int _sessionId; bool _isAuthenticated; }; commit 909b5f8ac3aa57c4bc786fa03c5d999805e6d7ca Author: Michael Meeks <[email protected]> Date: Wed Mar 15 16:13:13 2017 +0000 Admin: should be its own socket-poll goodness. diff --git a/net/Socket.hpp b/net/Socket.hpp index 1d67bb6..9460c45 100644 --- a/net/Socket.hpp +++ b/net/Socket.hpp @@ -412,7 +412,7 @@ public: wakeup(); } - void dumpState(std::ostream& os); + virtual void dumpState(std::ostream& os); /// Removes a socket from this poller. /// NB. this must be called from the socket poll that diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp index 6f9f7cb..d3e684b 100644 --- a/wsd/Admin.cpp +++ b/wsd/Admin.cpp @@ -232,7 +232,7 @@ void AdminRequestHandler::sendTextFrame(const std::string& message) sendFrame(message); } -void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak, +bool AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> &socketWeak, const Poco::Net::HTTPRequest& request) { HTTPResponse response; @@ -257,6 +257,7 @@ void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> handler->_sessionId = sessionId; model.subscribe(sessionId, handler); } + return true; } // FIXME: ... should we move ourselves to an Admin poll [!?] ... @@ -281,10 +282,12 @@ void AdminRequestHandler::handleInitialRequest(const std::weak_ptr<StreamSocket> socket->send(response); } #endif + return false; } /// An admin command processor. Admin::Admin() : + SocketPoll("admin"), _model(AdminModel()), _forKitPid(-1) { @@ -411,4 +414,10 @@ void Admin::updateMemoryDirty(const std::string& docKey, int dirty) _model.updateMemoryDirty(docKey, dirty); } +void Admin::dumpState(std::ostream& os) +{ + // FIXME: be more helpful ... + SocketPoll::dumpState(os); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp index c15cbbb..4332e27 100644 --- a/wsd/Admin.hpp +++ b/wsd/Admin.hpp @@ -36,7 +36,9 @@ public: const std::weak_ptr<StreamSocket>& socket, const Poco::Net::HTTPRequest& request); - static void handleInitialRequest(const std::weak_ptr<StreamSocket> &socket, + /// Handle the initial Admin WS upgrade request. + /// @returns true if we should give this socket to the Admin poll. + static bool handleInitialRequest(const std::weak_ptr<StreamSocket> &socket, const Poco::Net::HTTPRequest& request); private: @@ -57,7 +59,7 @@ private: class MemoryStatsTask; /// An admin command processor. -class Admin +class Admin : public SocketPoll { Admin(); public: @@ -69,6 +71,12 @@ public: return admin; } + void start() + { + // FIXME: not if admin console is not enabled ? + startThread(); + } + unsigned getTotalMemoryUsage(); /// Update the Admin Model. @@ -101,6 +109,8 @@ public: void updateLastActivityTime(const std::string& docKey); void updateMemoryDirty(const std::string& docKey, int dirty); + void dumpState(std::ostream& os) override; + private: AdminModel _model; std::mutex _modelMutex; diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index 3aee14d..81608b6 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -1808,8 +1808,12 @@ private: else if (reqPathSegs.size() >= 2 && reqPathSegs[0] == "lool" && reqPathSegs[1] == "adminws") { LOG_ERR("Admin request: " << request.getURI()); - AdminRequestHandler::handleInitialRequest(_socket, request); - + if (AdminRequestHandler::handleInitialRequest(_socket, request)) + { + // Hand the socket over to the Admin poll. + WebServerPoll.releaseSocket(socket); + Admin::instance().insertNewSocket(socket); + } } // Client post and websocket connections else if ((request.getMethod() == HTTPRequest::HTTP_GET || @@ -2336,6 +2340,7 @@ public: _acceptPoll.insertNewSocket(findServerPort(port)); _acceptPoll.startThread(); WebServerPoll.startThread(); + Admin::instance().start(); } void stop() @@ -2364,6 +2369,9 @@ public: os << "Prisoner poll:\n"; PrisonerPoll.dumpState(os); + os << "Admin poll:\n"; + Admin::instance().dumpState(os); + os << "Document Broker polls " << "[ " << DocBrokers.size() << " ]:\n"; for (auto &i : DocBrokers) _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
