Allow a 'monitor' to be connected to remotely if configured.
So far monitors have the access an permissions of an authenticated admin. Change-Id: I59dfa8a646a60584a5c113ee0521e9afba4f6b76private/mmeeks/monitoring
parent
d66e8d13b7
commit
b483f477dd
|
@ -116,4 +116,8 @@
|
|||
<password desc="The password of the admin console. Deprecated on most platforms. Instead, use PAM or loolconfig to set up a secure password."></password>
|
||||
</admin_console>
|
||||
|
||||
<monitors desc="Addresses of servers we connect to on start for monitoring">
|
||||
<monitor>ws://localhost:9042/foo</monitor>
|
||||
</monitors>
|
||||
|
||||
</config>
|
||||
|
|
|
@ -118,7 +118,7 @@ public:
|
|||
}
|
||||
|
||||
/// Create socket of the given type.
|
||||
int createSocket(Type type);
|
||||
static int createSocket(Type type);
|
||||
|
||||
/// Returns the OS native socket fd.
|
||||
int getFD() const { return _fd; }
|
||||
|
|
|
@ -432,7 +432,12 @@ protected:
|
|||
const std::string res = oss.str();
|
||||
LOG_TRC("#" << socket->getFD() << ": Sending WS Upgrade response: " << res);
|
||||
socket->send(res);
|
||||
setWebSocket();
|
||||
}
|
||||
|
||||
void setWebSocket()
|
||||
{
|
||||
std::shared_ptr<StreamSocket> socket = _socket.lock();
|
||||
socket->setWebSocket();
|
||||
|
||||
// No need to ping right upon connection/upgrade,
|
||||
|
|
|
@ -28,11 +28,15 @@
|
|||
# include <SslSocket.hpp>
|
||||
#endif
|
||||
|
||||
SocketPoll DumpSocketPoll("websocket");
|
||||
|
||||
// Dumps incoming websocket messages and doesn't respond.
|
||||
class DumpSocketHandler : public WebSocketHandler
|
||||
{
|
||||
public:
|
||||
DumpSocketHandler()
|
||||
DumpSocketHandler(const std::weak_ptr<StreamSocket>& socket,
|
||||
const Poco::Net::HTTPRequest& request) :
|
||||
WebSocketHandler(socket, request)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -63,7 +67,7 @@ private:
|
|||
}
|
||||
|
||||
/// Called after successful socket reads.
|
||||
void handleIncomingMessage(SocketDisposition & /* disposition */) override
|
||||
void handleIncomingMessage(SocketDisposition &disposition) override
|
||||
{
|
||||
std::shared_ptr<StreamSocket> socket = _socket.lock();
|
||||
std::vector<char>& in = socket->_inBuffer;
|
||||
|
@ -135,7 +139,9 @@ private:
|
|||
Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
if (request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
|
||||
socket->setHandler(std::make_shared<DumpSocketHandler>());
|
||||
{
|
||||
socket->setHandler(std::make_shared<DumpSocketHandler>(_socket, request));
|
||||
}
|
||||
else
|
||||
{
|
||||
Poco::Net::HTTPResponse response;
|
||||
|
@ -143,7 +149,7 @@ private:
|
|||
response.setContentLength(0);
|
||||
LOG_INF("DumpWebSockets bad request");
|
||||
socket->send(response);
|
||||
socket->shutdown();
|
||||
disposition.setClosed();
|
||||
}
|
||||
}
|
||||
catch (const std::exception& exc)
|
||||
|
@ -187,7 +193,7 @@ class DumpSocketFactory final : public SocketFactory
|
|||
{
|
||||
std::shared_ptr<Socket> create(const int physicalFd) override
|
||||
{
|
||||
#if ENABLE_SSL
|
||||
#if 0 && ENABLE_SSL
|
||||
return StreamSocket::create<SslStreamSocket>(physicalFd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
|
||||
#else
|
||||
return StreamSocket::create<StreamSocket>(physicalFd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
|
||||
|
@ -208,12 +214,14 @@ int main (int argc, char **argv)
|
|||
int port = 9042;
|
||||
(void) argc; (void) argv;
|
||||
|
||||
Log::initialize("WebSocketDump", "trace", true, false,
|
||||
std::map<std::string, std::string>());
|
||||
|
||||
SocketPoll acceptPoll("accept");
|
||||
SocketPoll DumpSocketPoll("websocket");
|
||||
|
||||
// Setup listening socket with a factory for connected sockets.
|
||||
auto serverSocket = std::make_shared<ServerSocket>(
|
||||
Socket::Type::IPv4, DumpSocketPoll,
|
||||
Socket::Type::All, DumpSocketPoll,
|
||||
std::make_shared<DumpSocketFactory>());
|
||||
|
||||
if (!serverSocket->bind(ServerSocket::Type::Public, port))
|
||||
|
@ -233,7 +241,7 @@ int main (int argc, char **argv)
|
|||
|
||||
while (true)
|
||||
{
|
||||
DumpSocketPoll.poll(1000);
|
||||
DumpSocketPoll.poll(100 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
157
wsd/Admin.cpp
157
wsd/Admin.cpp
|
@ -34,6 +34,7 @@
|
|||
#include <Util.hpp>
|
||||
|
||||
#include <net/Socket.hpp>
|
||||
#include <net/SslSocket.hpp>
|
||||
#include <net/WebSocketHandler.hpp>
|
||||
|
||||
#include <common/SigUtil.hpp>
|
||||
|
@ -278,6 +279,14 @@ AdminSocketHandler::AdminSocketHandler(Admin* adminManager,
|
|||
{
|
||||
}
|
||||
|
||||
AdminSocketHandler::AdminSocketHandler(Admin* adminManager)
|
||||
: WebSocketHandler(),
|
||||
_admin(adminManager),
|
||||
_sessionId(0),
|
||||
_isAuthenticated(true)
|
||||
{
|
||||
}
|
||||
|
||||
void AdminSocketHandler::sendTextFrame(const std::string& message)
|
||||
{
|
||||
UnitWSD::get().onAdminQueryMessage(message);
|
||||
|
@ -613,8 +622,156 @@ void Admin::dumpState(std::ostream& os)
|
|||
SocketPoll::dumpState(os);
|
||||
}
|
||||
|
||||
class MonitorSocketHandler : public AdminSocketHandler
|
||||
{
|
||||
bool _connecting;
|
||||
public:
|
||||
|
||||
MonitorSocketHandler(Admin *admin) :
|
||||
AdminSocketHandler(admin),
|
||||
_connecting(true)
|
||||
{
|
||||
}
|
||||
int getPollEvents(std::chrono::steady_clock::time_point now,
|
||||
int &timeoutMaxMs) override
|
||||
{
|
||||
if (_connecting)
|
||||
{
|
||||
LOG_TRC("Waiting for outbound connection to complete");
|
||||
return POLLOUT;
|
||||
}
|
||||
else
|
||||
return AdminSocketHandler::getPollEvents(now, timeoutMaxMs);
|
||||
}
|
||||
|
||||
void performWrites() override
|
||||
{
|
||||
LOG_TRC("Outbound monitor - connected");
|
||||
_connecting = false;
|
||||
setWebSocket();
|
||||
return AdminSocketHandler::performWrites();
|
||||
}
|
||||
};
|
||||
|
||||
void Admin::connectToMonitor(const Poco::URI &uri)
|
||||
{
|
||||
LOG_INF("Connecting to monitor " << uri.getHost() << " : " << uri.getPort() << " : " << uri.getPath());
|
||||
|
||||
// FIXME: put this in a ClientSocket class ?
|
||||
// FIXME: store the address there - and ... (so on) ...
|
||||
struct addrinfo* ainfo = nullptr;
|
||||
struct addrinfo hints;
|
||||
std::memset(&hints, 0, sizeof(hints));
|
||||
int rc = getaddrinfo(uri.getHost().c_str(),
|
||||
std::to_string(uri.getPort()).c_str(),
|
||||
&hints, &ainfo);
|
||||
std::string canonicalName;
|
||||
bool isSSL = uri.getScheme() != "ws";
|
||||
#if !ENABLE_SSL
|
||||
if (isSSL)
|
||||
{
|
||||
LOG_ERR("Error: wss for monitor requested but SSL not compiled in.");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!rc && ainfo)
|
||||
{
|
||||
for (struct addrinfo* ai = ainfo; ai; ai = ai->ai_next)
|
||||
{
|
||||
if (ai->ai_canonname)
|
||||
canonicalName = ai->ai_canonname;
|
||||
|
||||
if (ai->ai_addrlen && ai->ai_addr)
|
||||
{
|
||||
int fd = socket(ai->ai_addr->sa_family, SOCK_STREAM | SOCK_NONBLOCK, 0);
|
||||
int res = connect(fd, ai->ai_addr, ai->ai_addrlen);
|
||||
// FIXME: SSL sockets presumably need some setup, checking etc. and ... =)
|
||||
if (fd < 0 || (res < 0 && errno != EINPROGRESS))
|
||||
{
|
||||
LOG_ERR("Failed to connect to " << uri.getHost());
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::shared_ptr<StreamSocket> socket;
|
||||
std::shared_ptr<SocketHandlerInterface> handler = std::make_shared<MonitorSocketHandler>(this);
|
||||
#if ENABLE_SSL
|
||||
if (isSSL)
|
||||
socket = StreamSocket::create<SslStreamSocket>(fd, handler);
|
||||
#endif
|
||||
if (!socket && !isSSL)
|
||||
socket = StreamSocket::create<StreamSocket>(fd, handler);
|
||||
|
||||
if (socket)
|
||||
{
|
||||
LOG_DBG("Connected to monitor " << uri.getHost() << " #" << socket->getFD());
|
||||
|
||||
// cf. WebSocketHandler::upgradeToWebSocket (?)
|
||||
// send Sec-WebSocket-Key: <hmm> ... Sec-WebSocket-Protocol: chat, Sec-WebSocket-Version: 13
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "GET " << uri.getHost() << " HTTP/1.1\r\n"
|
||||
"Connection:Upgrade\r\n"
|
||||
"Sec-WebSocket-Accept:GAcwqP21iVOY2yKefQ64c0yVN5M=\r\n"
|
||||
"Upgrade:websocket\r\n"
|
||||
"Accept-Encoding:gzip, deflate, br\r\n"
|
||||
"Accept-Language:en\r\n"
|
||||
"Cache-Control:no-cache\r\n"
|
||||
"Pragma:no-cache\r\n"
|
||||
"Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits\r\n"
|
||||
"Sec-WebSocket-Key:fxTaWTEMVhq1PkWsMoLxGw==\r\n"
|
||||
"Sec-WebSocket-Version:13\r\n"
|
||||
"User-Agent: " << WOPI_AGENT_STRING << "\r\n"
|
||||
"\r\n";
|
||||
socket->send(oss.str());
|
||||
handler->onConnect(socket);
|
||||
insertNewSocket(socket);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERR("Failed to allocate socket for monitor " << uri.getHost());
|
||||
close(fd);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ainfo);
|
||||
}
|
||||
else
|
||||
LOG_ERR("Failed to lookup monitor host '" << uri.getHost() << "' skipping");
|
||||
}
|
||||
|
||||
void Admin::start()
|
||||
{
|
||||
bool haveMonitors = false;
|
||||
const auto& config = Application::instance().config();
|
||||
|
||||
for (size_t i = 0; ; ++i)
|
||||
{
|
||||
const std::string path = "monitors.monitor[" + std::to_string(i) + "]";
|
||||
const std::string uri = config.getString(path, "");
|
||||
if (!config.has(path))
|
||||
break;
|
||||
if (!uri.empty())
|
||||
{
|
||||
Poco::URI monitor(uri);
|
||||
if (monitor.getScheme() == "wss" || monitor.getScheme() == "ws")
|
||||
{
|
||||
addCallback([=] { connectToMonitor(monitor); } );
|
||||
haveMonitors = true;
|
||||
}
|
||||
else
|
||||
LOG_ERR("Unhandled monitor URI: '" << uri << "' should be \"wss://foo:1234/baa\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveMonitors)
|
||||
LOG_TRC("No monitors configured.");
|
||||
|
||||
startThread();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ class Admin;
|
|||
class AdminSocketHandler : public WebSocketHandler
|
||||
{
|
||||
public:
|
||||
AdminSocketHandler(Admin* adminManager);
|
||||
|
||||
AdminSocketHandler(Admin* adminManager,
|
||||
const std::weak_ptr<StreamSocket>& socket,
|
||||
const Poco::Net::HTTPRequest& request);
|
||||
|
@ -130,6 +132,9 @@ private:
|
|||
return ((value + MinStatsIntervalMs - 1) / MinStatsIntervalMs) * MinStatsIntervalMs;
|
||||
}
|
||||
|
||||
/// Synchronous connection setup to remote monitoring server
|
||||
void connectToMonitor(const Poco::URI &uri);
|
||||
|
||||
private:
|
||||
/// The model is accessed only during startup & in
|
||||
/// the Admin Poll thread.
|
||||
|
|
Loading…
Reference in New Issue