[Libreoffice-commits] online.git: 18 commits - common/Common.hpp common/Seccomp.cpp common/SigUtil.cpp kit/ChildSession.hpp kit/Kit.cpp loleaflet/src loolwsd.xml.in net/Socket.cpp net/Socket.hpp net/Ssl.cpp net/SslSocket.hpp net/WebSocketHandler.hpp test/countloolkits.hpp test/Makefile.am test/WhiteBoxTests.cpp tools/WebSocketDump.cpp wsd/Admin.cpp wsd/Admin.hpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp
Jan Holesovsky
kendy at collabora.com
Fri May 18 13:20:32 UTC 2018
common/Common.hpp | 8
common/Seccomp.cpp | 1
common/SigUtil.cpp | 1
kit/ChildSession.hpp | 6
kit/Kit.cpp | 287 ++++++++++++++++++----------------
loleaflet/src/layer/tile/TileLayer.js | 88 +++++-----
loolwsd.xml.in | 4
net/Socket.cpp | 102 ++++++++++++
net/Socket.hpp | 88 +++++-----
net/Ssl.cpp | 4
net/SslSocket.hpp | 16 +
net/WebSocketHandler.hpp | 177 +++++++++++++++++---
test/Makefile.am | 8
test/WhiteBoxTests.cpp | 2
test/countloolkits.hpp | 4
tools/WebSocketDump.cpp | 82 ++++++++-
wsd/Admin.cpp | 71 ++++++++
wsd/Admin.hpp | 5
wsd/DocumentBroker.cpp | 5
wsd/DocumentBroker.hpp | 66 +++----
wsd/LOOLWSD.cpp | 15 -
21 files changed, 723 insertions(+), 317 deletions(-)
New commits:
commit 432a1c7d78d027f9986b91dc9e48edd33902a046
Author: Jan Holesovsky <kendy at collabora.com>
Date: Fri May 18 13:00:16 2018 +0200
Split close(bool) into close() and terminate().
The bool flag was causing 2 complete separate code paths anyway.
Also remove stop(), calling stop() followed by close() made no
difference.
Change-Id: Ica4c887b0324390d4e006a26eb4119bd5ab08723
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index e972459af..1006dc2dc 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1588,10 +1588,7 @@ void DocumentBroker::terminateChild(const std::string& closeReason)
{
LOG_INF("Terminating child [" << getPid() << "] of doc [" << _docKey << "].");
- // First flag to stop as it might be waiting on our lock
- // to process some incoming message.
- _childProcess->stop();
- _childProcess->close(false);
+ _childProcess->close();
}
stop(closeReason);
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index b88e37af6..fc3cb095d 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -78,63 +78,57 @@ public:
~ChildProcess()
{
- if (_pid > 0)
- {
- LOG_DBG("~ChildProcess dtor [" << _pid << "].");
- close(true);
+ if (_pid <= 0)
+ return;
+
+ LOG_DBG("~ChildProcess dtor [" << _pid << "].");
+ terminate();
+
+ // No need for the socket anymore.
+ _ws.reset();
+ _socket.reset();
- // No need for the socket anymore.
- _ws.reset();
- _socket.reset();
- }
}
void setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker);
std::shared_ptr<DocumentBroker> getDocumentBroker() const { return _docBroker.lock(); }
- void stop()
+ /// Let the child close a nice way.
+ void close()
{
- // Request the child to exit.
+ if (_pid < 0)
+ return;
+
try
{
+ LOG_DBG("Closing ChildProcess [" << _pid << "].");
+
+ // Request the child to exit
if (isAlive())
{
LOG_DBG("Stopping ChildProcess [" << _pid << "]");
sendTextFrame("exit");
}
+
+ // Shutdown the socket.
+ if (_ws)
+ _ws->shutdown();
}
- catch (const std::exception&)
+ catch (const std::exception& ex)
{
- // Already logged in sendTextFrame.
+ LOG_ERR("Error while closing child process: " << ex.what());
}
+
+ _pid = -1;
}
- void close(const bool rude)
+ /// Kill or abandon the child.
+ void terminate()
{
if (_pid < 0)
return;
- try
- {
- LOG_DBG("Closing ChildProcess [" << _pid << "].");
-
- if (!rude)
- {
- // First mark to stop the thread so it knows it's intentional.
- stop();
-
- // Shutdown the socket.
- if (_ws)
- _ws->shutdown();
- }
- }
- catch (const std::exception& ex)
- {
- LOG_ERR("Error while closing child process: " << ex.what());
- }
-
- // Kill or abandon the child.
- if (rude && _pid != -1 && kill(_pid, 0) == 0)
+ if (::kill(_pid, 0) == 0)
{
LOG_INF("Killing child [" << _pid << "].");
if (!SigUtil::killChild(_pid))
@@ -179,7 +173,7 @@ public:
{
try
{
- return _pid > 1 && _ws && kill(_pid, 0) == 0;
+ return _pid > 1 && _ws && ::kill(_pid, 0) == 0;
}
catch (const std::exception&)
{
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 9e48426c8..d7cb6a473 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2885,7 +2885,7 @@ int LOOLWSD::innerMain()
LOG_INF("Requesting child processes to terminate.");
for (auto& child : NewChildren)
{
- child->close(true);
+ child->terminate();
}
#ifndef KIT_IN_PROCESS
commit 088acf5e98c32228960b81b43f447de6c384cd17
Author: Jan Holesovsky <kendy at collabora.com>
Date: Thu May 17 20:47:37 2018 +0200
Before we kill the child, check it exists, ie. kill(pid, 0) == 0.
Also warn when anything was left out.
Without this, we leave abandoned children around.
Change-Id: I293a530ffceeb7f6bdc0cc775335c782945de6e7
diff --git a/common/SigUtil.cpp b/common/SigUtil.cpp
index 856e89fd5..ae6d6b18e 100644
--- a/common/SigUtil.cpp
+++ b/common/SigUtil.cpp
@@ -284,6 +284,7 @@ namespace SigUtil
sigaction(SIGUSR1, &action, nullptr);
}
+ /// Kill the given pid with SIGTERM. Returns true when the pid does not exist any more.
bool killChild(const int pid)
{
LOG_DBG("Killing PID: " << pid);
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 443d8ab52..b88e37af6 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -134,10 +134,10 @@ public:
}
// Kill or abandon the child.
- if (_pid != -1 && rude && kill(_pid, 0) != 0 && errno != ESRCH)
+ if (rude && _pid != -1 && kill(_pid, 0) == 0)
{
LOG_INF("Killing child [" << _pid << "].");
- if (SigUtil::killChild(_pid))
+ if (!SigUtil::killChild(_pid))
{
LOG_ERR("Cannot terminate lokit [" << _pid << "]. Abandoning.");
}
commit 9c790d1796c5564875d38d6109ac883a30d3bf2a
Author: Jan Holesovsky <kendy at collabora.com>
Date: Wed Apr 25 17:38:55 2018 +0200
Paste: Prefer text/rtf mimetype when present.
Change-Id: Id4bad2d6b09b3b14e64059a942a50ce61f8f4ea4
diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index 9080acb77..1deb1425a 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -2078,48 +2078,51 @@ L.TileLayer = L.GridLayer.extend({
if (preferInternal === true) {
var pasteString = dataTransfer.getData('text/plain');
if (!pasteString) {
- pasteString = window.clipboardData.getData('Text');
+ pasteString = dataTransfer.getData('Text'); // IE 11
}
- if (pasteString === this._selectionTextHash) {
+ if (pasteString && pasteString === this._selectionTextHash) {
this._map._socket.sendMessage('uno .uno:Paste');
- return
+ return;
}
}
- // handle content
var types = dataTransfer.types;
- var hasHTML = false;
- for (var t = 0; !hasHTML && t < types.length; t++) {
- if (types[t] === 'text/html') {
- hasHTML = true;
- }
- }
- var handled = false;
- for (t = 0; !handled && t < types.length; t++) {
- var type = types[t];
- if (type === 'text/html') {
- this._map._socket.sendMessage('paste mimetype=text/html\n' + dataTransfer.getData(type));
- handled = true;
- }
- else if ((type === 'text/plain' || type ==='Text') && !hasHTML) {
- this._map._socket.sendMessage('paste mimetype=text/plain;charset=utf-8\n' + dataTransfer.getData(type));
- handled = true;
- }
- else if (type === 'Files') {
+ // first try to transfer images
+ // TODO if we have both Files and a normal mimetype, should we handle
+ // both, or prefer one or the other?
+ for (var t = 0; t < types.length; ++t) {
+ if (types[t] === 'Files') {
var files = dataTransfer.files;
- for (var i = 0; i < files.length; ++i) {
- var file = files[i];
+ for (var f = 0; f < files.length; ++f) {
+ var file = files[f];
if (file.type.match(/image.*/)) {
var reader = new FileReader();
reader.onload = this._onFileLoadFunc(file);
reader.readAsArrayBuffer(file);
- handled = true;
}
}
}
}
+
+ // now try various mime types
+ var mimeTypes = [
+ ['text/rtf', 'text/rtf'],
+ ['text/html', 'text/html'],
+ ['text/plain', 'text/plain;charset=utf-8'],
+ ['Text', 'text/plain;charset=utf-8']
+ ];
+
+ for (var i = 0; i < mimeTypes.length; ++i) {
+ for (t = 0; t < types.length; ++t) {
+ if (mimeTypes[i][0] === types[t]) {
+ var blob = new Blob(['paste mimetype=' + mimeTypes[i][1] + '\n', dataTransfer.getData(types[t])]);
+ this._map._socket.sendMessage(blob);
+ return;
+ }
+ }
+ }
},
_onFileLoadFunc: function(file) {
commit 4e4d9719d4bb3144d5385be7be104eefa3390f11
Author: Jan Holesovsky <kendy at collabora.com>
Date: Wed Apr 25 16:06:08 2018 +0200
Paste: Share the code with Drop, to allow rich content pasting.
Change-Id: I4d80421786369388b8a1a094fe7633d525fa3f08
diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index 06a04f5d8..9080acb77 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -26,16 +26,6 @@ function hex2string(inData)
}
L.Compatibility = {
- clipboardGet: function (event) {
- var text = null;
- if (event.clipboardData) { // Standard
- text = event.clipboardData.getData('text/plain');
- }
- else if (window.clipboardData) { // IE 11
- text = window.clipboardData.getData('Text');
- }
- return text;
- },
clipboardSet: function (event, text) {
if (event.clipboardData) { // Standard
event.clipboardData.setData('text/plain', text);
@@ -2052,16 +2042,12 @@ L.TileLayer = L.GridLayer.extend({
_onPaste: function (e) {
e = e.originalEvent;
e.preventDefault();
- var pasteString = L.Compatibility.clipboardGet(e);
- if (pasteString === 'false' || !pasteString || pasteString === this._selectionTextHash) {
- // If there is nothing to paste in clipboard, no harm in
- // issuing a .uno:Paste in case there is something internally copied in the document
- // or if the content of the clipboard did not change, we surely must do a rich paste
- // instead of a normal paste
- this._map._socket.sendMessage('uno .uno:Paste');
+
+ if (e.clipboardData) { // Standard
+ this._dataTransferToDocument(e.clipboardData, /* preferInternal = */ true);
}
- else {
- this._map._socket.sendMessage('paste mimetype=text/plain;charset=utf-8\n' + pasteString);
+ else if (window.clipboardData) { // IE 11
+ this._dataTransferToDocument(window.clipboardData, /* preferInternal = */ true);
}
},
@@ -2084,8 +2070,25 @@ L.TileLayer = L.GridLayer.extend({
e = e.originalEvent;
e.preventDefault();
+ this._dataTransferToDocument(e.dataTransfer, /* preferInternal = */ false);
+ },
+
+ _dataTransferToDocument: function (dataTransfer, preferInternal) {
+ // for the paste, we might prefer the internal LOK's copy/paste
+ if (preferInternal === true) {
+ var pasteString = dataTransfer.getData('text/plain');
+ if (!pasteString) {
+ pasteString = window.clipboardData.getData('Text');
+ }
+
+ if (pasteString === this._selectionTextHash) {
+ this._map._socket.sendMessage('uno .uno:Paste');
+ return
+ }
+ }
+
// handle content
- var types = e.dataTransfer.types;
+ var types = dataTransfer.types;
var hasHTML = false;
for (var t = 0; !hasHTML && t < types.length; t++) {
if (types[t] === 'text/html') {
@@ -2097,15 +2100,15 @@ L.TileLayer = L.GridLayer.extend({
for (t = 0; !handled && t < types.length; t++) {
var type = types[t];
if (type === 'text/html') {
- this._map._socket.sendMessage('paste mimetype=text/html\n' + e.dataTransfer.getData(type));
+ this._map._socket.sendMessage('paste mimetype=text/html\n' + dataTransfer.getData(type));
handled = true;
}
- else if (type === 'text/plain' && !hasHTML) {
- this._map._socket.sendMessage('paste mimetype=text/plain;charset=utf-8\n' + e.dataTransfer.getData(type));
+ else if ((type === 'text/plain' || type ==='Text') && !hasHTML) {
+ this._map._socket.sendMessage('paste mimetype=text/plain;charset=utf-8\n' + dataTransfer.getData(type));
handled = true;
}
else if (type === 'Files') {
- var files = e.dataTransfer.files;
+ var files = dataTransfer.files;
for (var i = 0; i < files.length; ++i) {
var file = files[i];
if (file.type.match(/image.*/)) {
commit fde34f6e173ceba82c7db40fa36bd38efb368638
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Mon May 14 10:35:56 2018 +0100
Better debugging of tests.
Change-Id: If3b3d2ad862526238bee3c092389c8cc266b24e6
diff --git a/test/countloolkits.hpp b/test/countloolkits.hpp
index 90b89e12a..0f7010ff0 100644
--- a/test/countloolkits.hpp
+++ b/test/countloolkits.hpp
@@ -76,9 +76,11 @@ static std::chrono::steady_clock::time_point TestStartTime;
static void testCountHowManyLoolkits()
{
+ const char testname[] = "countHowManyLoolkits ";
TestStartTime = std::chrono::steady_clock::now();
InitialLoolKitCount = countLoolKitProcesses(InitialLoolKitCount);
+ TST_LOG("Initial loolkit count is " << InitialLoolKitCount);
CPPUNIT_ASSERT(InitialLoolKitCount > 0);
TestStartTime = std::chrono::steady_clock::now();
@@ -86,7 +88,7 @@ static void testCountHowManyLoolkits()
static void testNoExtraLoolKitsLeft()
{
- const char* testname = "noExtraLoolKitsLeft ";
+ const char testname[] = "noExtraLoolKitsLeft ";
const int countNow = countLoolKitProcesses(InitialLoolKitCount);
CPPUNIT_ASSERT_EQUAL(InitialLoolKitCount, countNow);
commit 071079a6a9aba7ecb7b7da2b2c65d30b58c2f23a
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Sun May 13 12:44:39 2018 +0100
seccomp: allow socket shutdown in kit process.
Change-Id: Ie11f5eb278bcba8dcf13d6f095de2ffd6d23fcb3
diff --git a/common/Seccomp.cpp b/common/Seccomp.cpp
index 6ae0b2899..fc276a8aa 100644
--- a/common/Seccomp.cpp
+++ b/common/Seccomp.cpp
@@ -133,7 +133,6 @@ bool lockdown(Type type)
KILL_SYSCALL(getitimer),
KILL_SYSCALL(setitimer),
KILL_SYSCALL(sendfile),
- KILL_SYSCALL(shutdown),
KILL_SYSCALL(listen), // server sockets
KILL_SYSCALL(accept), // server sockets
#if 0
commit 6c31b7793c03da7d38754dbef6a9b1f32489c00c
Author: Jan Holesovsky <kendy at collabora.com>
Date: Fri May 11 19:15:16 2018 +0200
Post the message to the poll thread.
Change-Id: Ibd28090a420b5396b64fdfe676bef8cf06991116
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 59b7dec74..d7f4cc05b 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -753,6 +753,7 @@ public:
const std::string& docId,
const std::string& url,
std::shared_ptr<TileQueue> tileQueue,
+ SocketPoll& socketPoll,
const std::shared_ptr<WebSocketHandler>& websocketHandler)
: _loKit(loKit),
_jailId(jailId),
@@ -760,6 +761,7 @@ public:
_docId(docId),
_url(url),
_tileQueue(std::move(tileQueue)),
+ _socketPoll(socketPoll),
_websocketHandler(websocketHandler),
_docPassword(""),
_haveDocPassword(false),
@@ -794,6 +796,20 @@ public:
const std::string& getUrl() const { return _url; }
+ /// Post the message in the correct thread.
+ bool postMessage(const std::shared_ptr<std::vector<char>>& message, const WSOpCode code) const
+ {
+ LOG_TRC("postMessage called with: " << getAbbreviatedMessage(message->data(), message->size()));
+ if (!_websocketHandler)
+ {
+ LOG_ERR("Child Doc: Bad socket while sending [" << getAbbreviatedMessage(message->data(), message->size()) << "].");
+ return false;
+ }
+
+ _socketPoll.addCallback([=] { _websocketHandler->sendMessage(message->data(), message->size(), code); });
+ return true;
+ }
+
bool createSession(const std::string& sessionId)
{
std::unique_lock<std::mutex> lock(_mutex);
@@ -908,9 +924,8 @@ public:
LOG_INF("setDocumentPassword returned");
}
- void renderTile(const std::vector<std::string>& tokens, const std::shared_ptr<WebSocketHandler>& websocketHandler)
+ void renderTile(const std::vector<std::string>& tokens)
{
- assert(websocketHandler && "Expected a non-null websocket.");
TileDesc tile = TileDesc::parse(tokens);
size_t pixmapDataSize = 4 * tile.getWidth() * tile.getHeight();
@@ -964,12 +979,12 @@ public:
if (_docWatermark)
_docWatermark->blending(pixmap.data(), 0, 0, pixelWidth, pixelHeight, pixelWidth, pixelHeight, mode);
- std::vector<char> output;
- output.reserve(response.size() + pixmapDataSize);
- output.resize(response.size());
- std::memcpy(output.data(), response.data(), response.size());
+ std::shared_ptr<std::vector<char>> output = std::make_shared<std::vector<char>>();
+ output->reserve(response.size() + pixmapDataSize);
+ output->resize(response.size());
+ std::memcpy(output->data(), response.data(), response.size());
- if (!_pngCache.encodeBufferToPNG(pixmap.data(), tile.getWidth(), tile.getHeight(), output, mode, hash, wid, oldWireId))
+ if (!_pngCache.encodeBufferToPNG(pixmap.data(), tile.getWidth(), tile.getHeight(), *output, mode, hash, wid, oldWireId))
{
//FIXME: Return error.
//sendTextFrame("error: cmd=tile kind=failure");
@@ -978,13 +993,12 @@ public:
return;
}
- LOG_TRC("Sending render-tile response (" << output.size() << " bytes) for: " << response);
- websocketHandler->sendMessage(output.data(), output.size(), WSOpCode::Binary);
+ LOG_TRC("Sending render-tile response (" << output->size() << " bytes) for: " << response);
+ postMessage(output, WSOpCode::Binary);
}
- void renderCombinedTiles(const std::vector<std::string>& tokens, const std::shared_ptr<WebSocketHandler>& websocketHandler)
+ void renderCombinedTiles(const std::vector<std::string>& tokens)
{
- assert(websocketHandler && "Expected a non-null websocket.");
TileCombined tileCombined = TileCombined::parse(tokens);
auto& tiles = tileCombined.getTiles();
@@ -1103,12 +1117,12 @@ public:
const auto tileMsg = ADD_DEBUG_RENDERID(tileCombined.serialize("tilecombine:")) + "\n";
LOG_TRC("Sending back painted tiles for " << tileMsg);
- std::vector<char> response;
- response.resize(tileMsg.size() + output.size());
- std::copy(tileMsg.begin(), tileMsg.end(), response.begin());
- std::copy(output.begin(), output.end(), response.begin() + tileMsg.size());
+ std::shared_ptr<std::vector<char>> response = std::make_shared<std::vector<char>>();
+ response->resize(tileMsg.size() + output.size());
+ std::copy(tileMsg.begin(), tileMsg.end(), response->begin());
+ std::copy(output.begin(), output.end(), response->begin() + tileMsg.size());
- websocketHandler->sendMessage(response.data(), response.size(), WSOpCode::Binary);
+ postMessage(response, WSOpCode::Binary);
}
bool sendTextFrame(const std::string& message)
@@ -1120,14 +1134,11 @@ public:
{
try
{
- if (!_websocketHandler)
- {
- LOG_ERR("Child Doc: Bad socket while sending [" << getAbbreviatedMessage(buffer, length) << "].");
- return false;
- }
+ std::shared_ptr<std::vector<char>> message = std::make_shared<std::vector<char>>();
+ message->resize(length);
+ std::memcpy(message->data(), buffer, length);
- _websocketHandler->sendMessage(buffer, length, opCode);
- return true;
+ return postMessage(message, opCode);
}
catch (const Exception& exc)
{
@@ -1826,11 +1837,11 @@ private:
if (tokens[0] == "tile")
{
- renderTile(tokens, _websocketHandler);
+ renderTile(tokens);
}
else if (tokens[0] == "tilecombine")
{
- renderCombinedTiles(tokens, _websocketHandler);
+ renderCombinedTiles(tokens);
}
else if (LOOLProtocol::getFirstToken(tokens[0], '-') == "child")
{
@@ -1953,6 +1964,7 @@ private:
std::shared_ptr<lok::Document> _loKitDocument;
std::shared_ptr<TileQueue> _tileQueue;
+ SocketPoll& _socketPoll;
std::shared_ptr<WebSocketHandler> _websocketHandler;
PngCache _pngCache;
@@ -1995,14 +2007,16 @@ class KitWebSocketHandler final : public WebSocketHandler, public std::enable_sh
std::string _socketName;
std::shared_ptr<lok::Office> _loKit;
std::string _jailId;
+ SocketPoll& _socketPoll;
public:
- KitWebSocketHandler(const std::string& socketName, const std::shared_ptr<lok::Office>& loKit, const std::string& jailId) :
+ KitWebSocketHandler(const std::string& socketName, const std::shared_ptr<lok::Office>& loKit, const std::string& jailId, SocketPoll& socketPoll) :
WebSocketHandler(/* isClient = */ true),
_queue(std::make_shared<TileQueue>()),
_socketName(socketName),
_loKit(loKit),
- _jailId(jailId)
+ _jailId(jailId),
+ _socketPoll(socketPoll)
{
}
@@ -2038,7 +2052,7 @@ protected:
if (!document)
{
- document = std::make_shared<Document>(_loKit, _jailId, docKey, docId, url, _queue, shared_from_this());
+ document = std::make_shared<Document>(_loKit, _jailId, docKey, docId, url, _queue, _socketPoll, shared_from_this());
}
// Validate and create session.
@@ -2336,7 +2350,7 @@ void lokit_main(const std::string& childRoot,
SocketPoll mainKit("kit");
- mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId));
+ mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
LOG_INF("New kit client websocket inserted.");
while (!TerminationFlag)
commit 93cc4b4548e3abcefc282e05ddf46677f8dd2897
Author: Jan Holesovsky <kendy at collabora.com>
Date: Wed May 9 20:25:58 2018 +0200
Use std::shared_ptr consistently.
Change-Id: I6bf3ff7de47010fd78fab26a5a318bde21c1f153
diff --git a/net/Socket.hpp b/net/Socket.hpp
index cb146f62c..6cd2190d4 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -704,11 +704,11 @@ protected:
class StreamSocket : public Socket, public std::enable_shared_from_this<StreamSocket>
{
public:
- /// Create a StreamSocket from native FD and take ownership of handler instance.
+ /// Create a StreamSocket from native FD.
StreamSocket(const int fd, bool /* isClient */,
- std::shared_ptr<SocketHandlerInterface> socketHandler) :
+ const std::shared_ptr<SocketHandlerInterface> socketHandler) :
Socket(fd),
- _socketHandler(std::move(socketHandler)),
+ _socketHandler(socketHandler),
_bytesSent(0),
_bytesRecvd(0),
_wsState(WSState::HTTP),
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index 856c1721a..59814b6d5 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -130,7 +130,7 @@ public:
if (len == 0)
return false; // avoid logging.
- LOG_TRC("#" << socket->getFD() << ": Incoming WebSocket data of " << len << " bytes.");
+ LOG_TRC("#" << socket->getFD() << ": Incoming WebSocket data of " << len << " bytes: " << std::string(socket->_inBuffer.data(), socket->_inBuffer.size()));
if (len < 2) // partial read
return false;
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
index 202bff3f7..777a2c82e 100644
--- a/tools/WebSocketDump.cpp
+++ b/tools/WebSocketDump.cpp
@@ -205,9 +205,9 @@ public:
{
#if ENABLE_SSL
if (_isSSL)
- return StreamSocket::create<SslStreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+ return StreamSocket::create<SslStreamSocket>(physicalFd, false, std::make_shared<ClientRequestDispatcher>());
#endif
- return StreamSocket::create<StreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+ return StreamSocket::create<StreamSocket>(physicalFd, false, std::make_shared<ClientRequestDispatcher>());
}
};
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 7c44bab3a..9e48426c8 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2443,8 +2443,7 @@ class PlainSocketFactory final : public SocketFactory
std::shared_ptr<Socket> socket =
StreamSocket::create<StreamSocket>(
- fd, false, std::unique_ptr<SocketHandlerInterface>{
- new ClientRequestDispatcher });
+ fd, false, std::make_shared<ClientRequestDispatcher>());
return socket;
}
@@ -2461,8 +2460,7 @@ class SslSocketFactory final : public SocketFactory
fd = Delay::create(SimulatedLatencyMs, physicalFd);
return StreamSocket::create<SslStreamSocket>(
- fd, false, std::unique_ptr<SocketHandlerInterface>{
- new ClientRequestDispatcher });
+ fd, false, std::make_shared<ClientRequestDispatcher>());
}
};
#endif
@@ -2472,7 +2470,7 @@ class PrisonerSocketFactory final : public SocketFactory
std::shared_ptr<Socket> create(const int fd) override
{
// No local delay.
- return StreamSocket::create<StreamSocket>(fd, false, std::unique_ptr<SocketHandlerInterface>{ new PrisonerRequestDispatcher });
+ return StreamSocket::create<StreamSocket>(fd, false, std::make_shared<PrisonerRequestDispatcher>());
}
};
commit 6996139e5fba0310ddc9d97f2005a3383818ec7a
Author: Jan Holesovsky <kendy at collabora.com>
Date: Mon May 7 15:09:40 2018 +0200
Use correct path in the client websockets.
Change-Id: Ie0bf6646ff3f6e6cf99b505143a416c86a3a33b8
diff --git a/common/Common.hpp b/common/Common.hpp
index b73e98249..42e8dd450 100644
--- a/common/Common.hpp
+++ b/common/Common.hpp
@@ -29,10 +29,10 @@ constexpr long READ_BUFFER_SIZE = 64 * 1024;
/// or as intentionally flooding the server.
constexpr int MAX_MESSAGE_SIZE = 2 * 1024 * READ_BUFFER_SIZE;
-constexpr const char* JAILED_DOCUMENT_ROOT = "/user/docs/";
-constexpr const char* CHILD_URI = "/loolws/child?";
-constexpr const char* NEW_CHILD_URI = "/loolws/newchild?";
-constexpr const char* LO_JAIL_SUBPATH = "lo";
+constexpr const char JAILED_DOCUMENT_ROOT[] = "/user/docs/";
+constexpr const char CHILD_URI[] = "/loolws/child?";
+constexpr const char NEW_CHILD_URI[] = "/loolws/newchild";
+constexpr const char LO_JAIL_SUBPATH[] = "lo";
/// The HTTP response User-Agent.
constexpr const char* HTTP_AGENT_STRING = "LOOLWSD HTTP Agent " LOOLWSD_VERSION;
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 88a58e198..59b7dec74 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2318,25 +2318,24 @@ void lokit_main(const std::string& childRoot,
static const std::string pid = std::to_string(Process::id());
- std::string requestUrl = NEW_CHILD_URI;
- requestUrl += "pid=" + pid + "&jailid=" + jailId;
+ Poco::URI uri("ws://127.0.0.1");
+ uri.setPort(MasterPortNumber);
+ uri.setPath(NEW_CHILD_URI);
+ uri.addQueryParameter("pid", std::to_string(Process::id()));
+ uri.addQueryParameter("jailid", jailId);
+
if (queryVersion)
{
char* versionInfo = loKit->getVersionInfo();
std::string versionString(versionInfo);
if (displayVersion)
std::cout << "office version details: " << versionString << std::endl;
- std::string encodedVersionStr;
- URI::encode(versionString, "", encodedVersionStr);
- requestUrl += "&version=" + encodedVersionStr;
+ uri.addQueryParameter("version", versionString);
free(versionInfo);
}
SocketPoll mainKit("kit");
- Poco::URI uri("ws://127.0.0.1");
- uri.setPort(MasterPortNumber);
-
mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId));
LOG_INF("New kit client websocket inserted.");
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 17ac9166d..4d58ff949 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -185,7 +185,7 @@ void SocketPoll::insertNewWebSocketSync(const Poco::URI &uri, const std::shared_
// 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"
+ oss << "GET " << uri.getPathAndQuery() << " HTTP/1.1\r\n"
"Connection:Upgrade\r\n"
"User-Foo: Adminbits\r\n"
"Sec-WebSocket-Key: GAcwqP21iVOY2yKefQ64c0yVN5M=\r\n"
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 8a99428a5..7c44bab3a 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1620,14 +1620,15 @@ private:
return;
LOG_TRC("Child connection with URI [" << request.getURI() << "].");
- if (request.getURI().find(NEW_CHILD_URI) != 0)
+ Poco::URI requestURI(request.getURI());
+ if (requestURI.getPath() != NEW_CHILD_URI)
{
LOG_ERR("Invalid incoming URI.");
return;
}
// New Child is spawned.
- const Poco::URI::QueryParameters params = Poco::URI(request.getURI()).getQueryParameters();
+ const Poco::URI::QueryParameters params = requestURI.getQueryParameters();
Poco::Process::PID pid = -1;
std::string jailId;
for (const auto& param : params)
commit 98ed24257b505b10ac48b2159d12f82cb81b3559
Author: Jan Holesovsky <kendy at collabora.com>
Date: Fri May 4 18:47:33 2018 +0200
Move the functionality from connectToMonitor() to SocketPoll.
Change-Id: Iab2ac09638323f5e59f7a2ea0d880f52989ad64d
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index 093ca4e66..b1cd90133 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -70,7 +70,7 @@ public:
virtual std::shared_ptr<TileQueue>& getTileQueue() = 0;
- virtual bool sendFrame(const char* buffer, int length, int flags = Poco::Net::WebSocket::FRAME_TEXT) = 0;
+ virtual bool sendFrame(const char* buffer, int length, WSOpCode opCode = WSOpCode::Text) = 0;
};
struct RecordedEvent
@@ -161,14 +161,14 @@ public:
{
const auto msg = "client-" + getId() + ' ' + std::string(buffer, length);
const std::unique_lock<std::mutex> lock = getLock();
- return _docManager.sendFrame(msg.data(), msg.size(), Poco::Net::WebSocket::FRAME_TEXT);
+ return _docManager.sendFrame(msg.data(), msg.size(), WSOpCode::Text);
}
bool sendBinaryFrame(const char* buffer, int length) override
{
const auto msg = "client-" + getId() + ' ' + std::string(buffer, length);
const std::unique_lock<std::mutex> lock = getLock();
- return _docManager.sendFrame(msg.data(), msg.size(), Poco::Net::WebSocket::FRAME_BINARY);
+ return _docManager.sendFrame(msg.data(), msg.size(), WSOpCode::Binary);
}
using Session::sendTextFrame;
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 37c62f10c..88a58e198 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -979,7 +979,7 @@ public:
}
LOG_TRC("Sending render-tile response (" << output.size() << " bytes) for: " << response);
- websocketHandler->sendMessage(output.data(), output.size(), WebSocket::FRAME_BINARY);
+ websocketHandler->sendMessage(output.data(), output.size(), WSOpCode::Binary);
}
void renderCombinedTiles(const std::vector<std::string>& tokens, const std::shared_ptr<WebSocketHandler>& websocketHandler)
@@ -1108,7 +1108,7 @@ public:
std::copy(tileMsg.begin(), tileMsg.end(), response.begin());
std::copy(output.begin(), output.end(), response.begin() + tileMsg.size());
- websocketHandler->sendMessage(response.data(), response.size(), WebSocket::FRAME_BINARY);
+ websocketHandler->sendMessage(response.data(), response.size(), WSOpCode::Binary);
}
bool sendTextFrame(const std::string& message)
@@ -1116,7 +1116,7 @@ public:
return sendFrame(message.data(), message.size());
}
- bool sendFrame(const char* buffer, int length, int flags = Poco::Net::WebSocket::FRAME_TEXT) override
+ bool sendFrame(const char* buffer, int length, WSOpCode opCode = WSOpCode::Text) override
{
try
{
@@ -1126,7 +1126,7 @@ public:
return false;
}
- _websocketHandler->sendMessage(buffer, length, flags);
+ _websocketHandler->sendMessage(buffer, length, opCode);
return true;
}
catch (const Exception& exc)
@@ -2334,7 +2334,7 @@ void lokit_main(const std::string& childRoot,
SocketPoll mainKit("kit");
- const Poco::URI uri("ws://127.0.0.1");
+ Poco::URI uri("ws://127.0.0.1");
uri.setPort(MasterPortNumber);
mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId));
diff --git a/net/Socket.cpp b/net/Socket.cpp
index c9a2968f6..17ac9166d 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -20,10 +20,12 @@
#include <Poco/MemoryStream.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
+#include <Poco/URI.h>
#include <SigUtil.hpp>
#include "Socket.hpp"
#include "ServerSocket.hpp"
+#include "SslSocket.hpp"
#include "WebSocketHandler.hpp"
int SocketPoll::DefaultPollTimeoutMs = 5000;
@@ -126,6 +128,98 @@ void SocketPoll::wakeupWorld()
wakeup(fd);
}
+void SocketPoll::insertNewWebSocketSync(const Poco::URI &uri, const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
+{
+ LOG_INF("Connecting to " << 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 client websocket 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;
+#if ENABLE_SSL
+ if (isSSL)
+ socket = StreamSocket::create<SslStreamSocket>(fd, true, websocketHandler);
+#endif
+ if (!socket && !isSSL)
+ socket = StreamSocket::create<StreamSocket>(fd, true, websocketHandler);
+
+ if (socket)
+ {
+ LOG_DBG("Connected to client websocket " << 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"
+ "User-Foo: Adminbits\r\n"
+ "Sec-WebSocket-Key: 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());
+ websocketHandler->onConnect(socket);
+ insertNewSocket(socket);
+ }
+ else
+ {
+ LOG_ERR("Failed to allocate socket for client websocket " << uri.getHost());
+ close(fd);
+ }
+
+ break;
+ }
+ }
+ }
+
+ freeaddrinfo(ainfo);
+ }
+ else
+ LOG_ERR("Failed to lookup client websocket host '" << uri.getHost() << "' skipping");
+}
+
void ServerSocket::dumpState(std::ostream& os)
{
os << "\t" << getFD() << "\t<accept>\n";
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 373fcc79c..cb146f62c 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -46,6 +46,7 @@ namespace Poco
class HTTPRequest;
class HTTPResponse;
}
+ class URI;
}
class Socket;
@@ -307,6 +308,41 @@ private:
std::thread::id _owner;
};
+class StreamSocket;
+
+/// Interface that handles the actual incoming message.
+class SocketHandlerInterface
+{
+public:
+ virtual ~SocketHandlerInterface() {}
+ /// Called when the socket is newly created to
+ /// set the socket associated with this ResponseClient.
+ /// Will be called exactly once.
+ virtual void onConnect(const std::shared_ptr<StreamSocket>& socket) = 0;
+
+ /// Called after successful socket reads.
+ virtual void handleIncomingMessage(SocketDisposition &disposition) = 0;
+
+ /// Prepare our poll record; adjust @timeoutMaxMs downwards
+ /// for timeouts, based on current time @now.
+ /// @returns POLLIN and POLLOUT if output is expected.
+ virtual int getPollEvents(std::chrono::steady_clock::time_point now,
+ int &timeoutMaxMs) = 0;
+
+ /// Do we need to handle a timeout ?
+ virtual void checkTimeout(std::chrono::steady_clock::time_point /* now */) {}
+
+ /// Do some of the queued writing.
+ virtual void performWrites() = 0;
+
+ /// Called when the is disconnected and will be destroyed.
+ /// Will be called exactly once.
+ virtual void onDisconnect() {}
+
+ /// Append pretty printed internal state to a line
+ virtual void dumpState(std::ostream& os) { os << "\n"; }
+};
+
/// Handles non-blocking socket event polling.
/// Only polls on N-Sockets and invokes callback and
/// doesn't manage buffers or client data.
@@ -534,6 +570,10 @@ public:
}
}
+ /// Inserts a new websocket to be polled.
+ /// NOTE: The DNS lookup is synchronous.
+ void insertNewWebSocketSync(const Poco::URI &uri, const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
+
typedef std::function<void()> CallbackFn;
/// Add a callback to be invoked in the polling thread
@@ -660,41 +700,6 @@ protected:
std::thread::id _owner;
};
-class StreamSocket;
-
-/// Interface that handles the actual incoming message.
-class SocketHandlerInterface
-{
-public:
- virtual ~SocketHandlerInterface() {}
- /// Called when the socket is newly created to
- /// set the socket associated with this ResponseClient.
- /// Will be called exactly once.
- virtual void onConnect(const std::shared_ptr<StreamSocket>& socket) = 0;
-
- /// Called after successful socket reads.
- virtual void handleIncomingMessage(SocketDisposition &disposition) = 0;
-
- /// Prepare our poll record; adjust @timeoutMaxMs downwards
- /// for timeouts, based on current time @now.
- /// @returns POLLIN and POLLOUT if output is expected.
- virtual int getPollEvents(std::chrono::steady_clock::time_point now,
- int &timeoutMaxMs) = 0;
-
- /// Do we need to handle a timeout ?
- virtual void checkTimeout(std::chrono::steady_clock::time_point /* now */) {}
-
- /// Do some of the queued writing.
- virtual void performWrites() = 0;
-
- /// Called when the is disconnected and will be destroyed.
- /// Will be called exactly once.
- virtual void onDisconnect() {}
-
- /// Append pretty printed internal state to a line
- virtual void dumpState(std::ostream& os) { os << "\n"; }
-};
-
/// A plain, non-blocking, data streaming socket.
class StreamSocket : public Socket, public std::enable_shared_from_this<StreamSocket>
{
diff --git a/test/Makefile.am b/test/Makefile.am
index 5b17f54a2..7e59fa621 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -25,6 +25,10 @@ noinst_LTLIBRARIES = \
MAGIC_TO_FORCE_SHLIB_CREATION = -rpath /dummy
AM_LDFLAGS = -pthread -module $(MAGIC_TO_FORCE_SHLIB_CREATION) $(ZLIB_LIBS)
+if ENABLE_SSL
+AM_LDFLAGS += -lssl -lcrypto
+endif
+
# We work around some of the mess of using the same sources both on
# the server side and here in unit tests with conditional compilation
# based on BUILDING_TESTS
@@ -47,6 +51,10 @@ wsd_sources = \
../common/Unit.cpp \
../net/Socket.cpp
+if ENABLE_SSL
+wsd_sources += ../net/Ssl.cpp
+endif
+
test_base_source = \
TileQueueTests.cpp \
WhiteBoxTests.cpp \
diff --git a/test/WhiteBoxTests.cpp b/test/WhiteBoxTests.cpp
index f910aac3d..580df11e3 100644
--- a/test/WhiteBoxTests.cpp
+++ b/test/WhiteBoxTests.cpp
@@ -390,7 +390,7 @@ public:
return _tileQueue;
}
- bool sendFrame(const char* /*buffer*/, int /*length*/, int /*flags*/) override
+ bool sendFrame(const char* /*buffer*/, int /*length*/, WSOpCode /*opCode*/) override
{
return true;
}
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index d0e11aeb8..0350c714d 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -656,95 +656,7 @@ public:
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, true, handler);
-#endif
- if (!socket && !isSSL)
- socket = StreamSocket::create<StreamSocket>(fd, true, 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"
- "User-Foo: Adminbits\r\n"
- "Sec-WebSocket-Key: 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");
+ insertNewWebSocketSync(uri, std::make_shared<MonitorSocketHandler>(this));
}
void Admin::start()
commit 35ec3649bbf98fc79d28530a0bb8e082156ba831
Author: Jan Holesovsky <kendy at collabora.com>
Date: Fri May 4 18:32:42 2018 +0200
Change Kit to use the new client websocket code.
Change-Id: Ib4e62ea618da5bd8992b51165b0d7ee955c61637
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 1451778b3..37c62f10c 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -57,7 +57,6 @@
#include "KitHelper.hpp"
#include "Kit.hpp"
#include <Protocol.hpp>
-#include <LOOLWebSocket.hpp>
#include <Log.hpp>
#include <Png.hpp>
#include <Rectangle.hpp>
@@ -754,14 +753,14 @@ public:
const std::string& docId,
const std::string& url,
std::shared_ptr<TileQueue> tileQueue,
- const std::shared_ptr<LOOLWebSocket>& ws)
+ const std::shared_ptr<WebSocketHandler>& websocketHandler)
: _loKit(loKit),
_jailId(jailId),
_docKey(docKey),
_docId(docId),
_url(url),
_tileQueue(std::move(tileQueue)),
- _ws(ws),
+ _websocketHandler(websocketHandler),
_docPassword(""),
_haveDocPassword(false),
_isDocPasswordProtected(false),
@@ -909,9 +908,9 @@ public:
LOG_INF("setDocumentPassword returned");
}
- void renderTile(const std::vector<std::string>& tokens, const std::shared_ptr<LOOLWebSocket>& ws)
+ void renderTile(const std::vector<std::string>& tokens, const std::shared_ptr<WebSocketHandler>& websocketHandler)
{
- assert(ws && "Expected a non-null websocket.");
+ assert(websocketHandler && "Expected a non-null websocket.");
TileDesc tile = TileDesc::parse(tokens);
size_t pixmapDataSize = 4 * tile.getWidth() * tile.getHeight();
@@ -980,12 +979,12 @@ public:
}
LOG_TRC("Sending render-tile response (" << output.size() << " bytes) for: " << response);
- ws->sendFrame(output.data(), output.size(), WebSocket::FRAME_BINARY);
+ websocketHandler->sendMessage(output.data(), output.size(), WebSocket::FRAME_BINARY);
}
- void renderCombinedTiles(const std::vector<std::string>& tokens, const std::shared_ptr<LOOLWebSocket>& ws)
+ void renderCombinedTiles(const std::vector<std::string>& tokens, const std::shared_ptr<WebSocketHandler>& websocketHandler)
{
- assert(ws && "Expected a non-null websocket.");
+ assert(websocketHandler && "Expected a non-null websocket.");
TileCombined tileCombined = TileCombined::parse(tokens);
auto& tiles = tileCombined.getTiles();
@@ -1109,7 +1108,7 @@ public:
std::copy(tileMsg.begin(), tileMsg.end(), response.begin());
std::copy(output.begin(), output.end(), response.begin() + tileMsg.size());
- ws->sendFrame(response.data(), response.size(), WebSocket::FRAME_BINARY);
+ websocketHandler->sendMessage(response.data(), response.size(), WebSocket::FRAME_BINARY);
}
bool sendTextFrame(const std::string& message)
@@ -1121,13 +1120,13 @@ public:
{
try
{
- if (!_ws || _ws->poll(Poco::Timespan(0), Poco::Net::Socket::SelectMode::SELECT_ERROR))
+ if (!_websocketHandler)
{
LOG_ERR("Child Doc: Bad socket while sending [" << getAbbreviatedMessage(buffer, length) << "].");
return false;
}
- _ws->sendFrame(buffer, length, flags);
+ _websocketHandler->sendMessage(buffer, length, flags);
return true;
}
catch (const Exception& exc)
@@ -1827,11 +1826,11 @@ private:
if (tokens[0] == "tile")
{
- renderTile(tokens, _ws);
+ renderTile(tokens, _websocketHandler);
}
else if (tokens[0] == "tilecombine")
{
- renderCombinedTiles(tokens, _ws);
+ renderCombinedTiles(tokens, _websocketHandler);
}
else if (LOOLProtocol::getFirstToken(tokens[0], '-') == "child")
{
@@ -1954,7 +1953,7 @@ private:
std::shared_ptr<lok::Document> _loKitDocument;
std::shared_ptr<TileQueue> _tileQueue;
- std::shared_ptr<LOOLWebSocket> _ws;
+ std::shared_ptr<WebSocketHandler> _websocketHandler;
PngCache _pngCache;
// Document password provided
@@ -1990,6 +1989,97 @@ private:
Poco::Thread _callbackThread;
};
+class KitWebSocketHandler final : public WebSocketHandler, public std::enable_shared_from_this<KitWebSocketHandler>
+{
+ std::shared_ptr<TileQueue> _queue;
+ std::string _socketName;
+ std::shared_ptr<lok::Office> _loKit;
+ std::string _jailId;
+
+public:
+ KitWebSocketHandler(const std::string& socketName, const std::shared_ptr<lok::Office>& loKit, const std::string& jailId) :
+ WebSocketHandler(/* isClient = */ true),
+ _queue(std::make_shared<TileQueue>()),
+ _socketName(socketName),
+ _loKit(loKit),
+ _jailId(jailId)
+ {
+ }
+
+protected:
+ void handleMessage(bool /*fin*/, WSOpCode /*code*/, std::vector<char>& data) override
+ {
+ std::string message(data.data(), data.size());
+
+#if 0 // FIXME might be needed for unit tests #ifndef KIT_IN_PROCESS
+ if (UnitKit::get().filterKitMessage(ws, message))
+ {
+ return;
+ }
+#endif
+
+ LOG_DBG(_socketName << ": recv [" << LOOLProtocol::getAbbreviatedMessage(message) << "].");
+ std::vector<std::string> tokens = LOOLProtocol::tokenize(message);
+
+ // Note: Syntax or parsing errors here are unexpected and fatal.
+ if (TerminationFlag)
+ {
+ LOG_DBG("Too late, we're going down");
+ }
+ else if (tokens[0] == "session")
+ {
+ const std::string& sessionId = tokens[1];
+ const std::string& docKey = tokens[2];
+ const std::string& docId = tokens[3];
+
+ std::string url;
+ URI::decode(docKey, url);
+ LOG_INF("New session [" << sessionId << "] request on url [" << url << "].");
+
+ if (!document)
+ {
+ document = std::make_shared<Document>(_loKit, _jailId, docKey, docId, url, _queue, shared_from_this());
+ }
+
+ // Validate and create session.
+ if (!(url == document->getUrl() && document->createSession(sessionId)))
+ {
+ LOG_DBG("CreateSession failed.");
+ }
+ }
+ else if (tokens[0] == "exit")
+ {
+ LOG_TRC("Setting TerminationFlag due to 'exit' command from parent.");
+ TerminationFlag = true;
+ }
+ else if (tokens[0] == "tile" || tokens[0] == "tilecombine" || tokens[0] == "canceltiles" ||
+ tokens[0] == "paintwindow" ||
+ LOOLProtocol::getFirstToken(tokens[0], '-') == "child")
+ {
+ if (document)
+ {
+ _queue->put(message);
+ }
+ else
+ {
+ LOG_WRN("No document while processing " << tokens[0] << " request.");
+ }
+ }
+ else if (tokens.size() == 3 && tokens[0] == "setconfig")
+ {
+ // Currently onlly rlimit entries are supported.
+ if (!Rlimit::handleSetrlimitCommand(tokens))
+ {
+ LOG_ERR("Unknown setconfig command: " << message);
+ }
+ }
+ else
+ {
+ LOG_ERR("Bad or unknown token [" << tokens[0] << "]");
+ }
+ }
+};
+
void documentViewCallback(const int type, const char* payload, void* data)
{
Document::ViewCallback(type, payload, data);
@@ -2242,110 +2332,26 @@ void lokit_main(const std::string& childRoot,
free(versionInfo);
}
- // Open websocket connection between the child process and WSD.
- HTTPClientSession cs("127.0.0.1", MasterPortNumber);
- cs.setTimeout(Poco::Timespan(10, 0)); // 10 second
- LOG_DBG("Connecting to Master " << cs.getHost() << ':' << cs.getPort());
- HTTPRequest request(HTTPRequest::HTTP_GET, requestUrl);
- HTTPResponse response;
- auto ws = std::make_shared<LOOLWebSocket>(cs, request, response);
- ws->setReceiveTimeout(0);
+ SocketPoll mainKit("kit");
- auto queue = std::make_shared<TileQueue>();
+ const Poco::URI uri("ws://127.0.0.1");
+ uri.setPort(MasterPortNumber);
- if (bTraceStartup && LogLevel != "trace")
- {
- LOG_INF("Setting log-level to [" << LogLevel << "].");
- Log::logger().setLevel(LogLevel);
- }
-
- const std::string socketName = "child_ws_" + pid;
- IoUtil::SocketProcessor(ws, socketName,
- [&socketName, &ws, &loKit, &jailId, &queue](const std::vector<char>& data)
- {
- std::string message(data.data(), data.size());
-
-#ifndef KIT_IN_PROCESS
- if (UnitKit::get().filterKitMessage(ws, message))
- {
- return true;
- }
-#endif
-
- LOG_DBG(socketName << ": recv [" << LOOLProtocol::getAbbreviatedMessage(message) << "].");
- std::vector<std::string> tokens = LOOLProtocol::tokenize(message);
+ mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId));
+ LOG_INF("New kit client websocket inserted.");
- // Note: Syntax or parsing errors here are unexpected and fatal.
- if (TerminationFlag)
- {
- LOG_DBG("Too late, we're going down");
- }
- else if (tokens[0] == "session")
- {
- const std::string& sessionId = tokens[1];
- const std::string& docKey = tokens[2];
- const std::string& docId = tokens[3];
-
- std::string url;
- URI::decode(docKey, url);
- LOG_INF("New session [" << sessionId << "] request on url [" << url << "].");
-
- if (!document)
- {
- document = std::make_shared<Document>(loKit, jailId, docKey, docId, url, queue, ws);
- }
-
- // Validate and create session.
- if (!(url == document->getUrl() &&
- document->createSession(sessionId)))
- {
- LOG_DBG("CreateSession failed.");
- }
- }
- else if (tokens[0] == "exit")
- {
- LOG_TRC("Setting TerminationFlag due to 'exit' command from parent.");
- TerminationFlag = true;
- }
- else if (tokens[0] == "tile" || tokens[0] == "tilecombine" || tokens[0] == "canceltiles" ||
- tokens[0] == "paintwindow" ||
- LOOLProtocol::getFirstToken(tokens[0], '-') == "child")
- {
- if (document)
- {
- queue->put(message);
- }
- else
- {
- LOG_WRN("No document while processing " << tokens[0] << " request.");
- }
- }
- else if (tokens.size() == 3 && tokens[0] == "setconfig")
- {
- // Currently onlly rlimit entries are supported.
- if (!Rlimit::handleSetrlimitCommand(tokens))
- {
- LOG_ERR("Unknown setconfig command: " << message);
- }
- }
- else
- {
- LOG_ERR("Bad or unknown token [" << tokens[0] << "]");
- }
+ while (!TerminationFlag)
+ {
+ mainKit.poll(SocketPoll::DefaultPollTimeoutMs);
- return true;
- },
- []() {},
- []()
- {
- if (document && document->purgeSessions() == 0)
- {
- LOG_INF("Last session discarded. Terminating.");
- TerminationFlag = true;
- }
+ if (document && document->purgeSessions() == 0)
+ {
+ LOG_INF("Last session discarded. Terminating.");
+ TerminationFlag = true;
+ }
+ }
- return TerminationFlag.load();
- });
+ LOG_INF("Kit poll terminated.");
// Let forkit handle the jail cleanup.
}
commit 82f2f2711b2d2b3e1f8099c0a8e8305bc516a303
Author: Jan Holesovsky <kendy at collabora.com>
Date: Fri May 4 16:08:32 2018 +0200
websocketdump: Read the port and ssl support from the config.
Change-Id: Ifc4566d5e1f2cdba1fd4bd7d53b359d81604083b
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
index 7f13012dd..202bff3f7 100644
--- a/tools/WebSocketDump.cpp
+++ b/tools/WebSocketDump.cpp
@@ -18,6 +18,7 @@
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/StringTokenizer.h>
+#include <Poco/Util/XMLConfiguration.h>
#include <Log.hpp>
#include <Util.hpp>
@@ -194,13 +195,19 @@ private:
class DumpSocketFactory final : public SocketFactory
{
+private:
+ bool _isSSL = false;
+
+public:
+ DumpSocketFactory(bool isSSL) : _isSSL(isSSL) {}
+
std::shared_ptr<Socket> create(const int physicalFd) override
{
#if ENABLE_SSL
- return StreamSocket::create<SslStreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
-#else
- return StreamSocket::create<StreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+ if (_isSSL)
+ return StreamSocket::create<SslStreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
#endif
+ return StreamSocket::create<StreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
}
};
@@ -212,9 +219,15 @@ namespace Util
}
}
+class LoolConfig final: public Poco::Util::XMLConfiguration
+{
+public:
+ LoolConfig()
+ {}
+};
+
int main (int argc, char **argv)
{
- int port = 9042;
(void) argc; (void) argv;
if (!UnitWSD::init(UnitWSD::UnitType::Wsd, ""))
@@ -225,6 +238,20 @@ int main (int argc, char **argv)
Log::initialize("WebSocketDump", "trace", true, false,
std::map<std::string, std::string>());
+ LoolConfig config;
+ config.load("loolwsd.xml");
+
+ // read the port & ssl support
+ int port = 9042;
+ bool isSSL = false;
+ std::string monitorAddress = config.getString("monitors.monitor");
+ if (!monitorAddress.empty())
+ {
+ Poco::URI monitorURI(monitorAddress);
+ port = monitorURI.getPort();
+ isSSL = (monitorURI.getScheme() == "wss");
+ }
+
#if ENABLE_SSL
// hard coded but easy for now.
const std::string ssl_cert_file_path = "etc/cert.pem";
@@ -233,10 +260,11 @@ int main (int argc, char **argv)
const std::string ssl_cipher_list = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
// Initialize the non-blocking socket SSL.
- SslContext::initialize(ssl_cert_file_path,
- ssl_key_file_path,
- ssl_ca_file_path,
- ssl_cipher_list);
+ if (isSSL)
+ SslContext::initialize(ssl_cert_file_path,
+ ssl_key_file_path,
+ ssl_ca_file_path,
+ ssl_cipher_list);
#endif
SocketPoll acceptPoll("accept");
@@ -244,7 +272,7 @@ int main (int argc, char **argv)
// Setup listening socket with a factory for connected sockets.
auto serverSocket = std::make_shared<ServerSocket>(
Socket::Type::All, DumpSocketPoll,
- std::make_shared<DumpSocketFactory>());
+ std::make_shared<DumpSocketFactory>(isSSL));
if (!serverSocket->bind(ServerSocket::Type::Public, port))
{
commit 5a94614217b1b577dce071f6fbe797cb7f930cbc
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Thu May 3 18:03:56 2018 +0100
Enable SSL in outbound, client websockets ...
Switch SSL context creation to be generic rather than pure server.
Change-Id: I1b750b4ddc8c607381f5541a4f4412fa16e457d4
diff --git a/net/Ssl.cpp b/net/Ssl.cpp
index b56b73524..74fd75ada 100644
--- a/net/Ssl.cpp
+++ b/net/Ssl.cpp
@@ -66,9 +66,9 @@ SslContext::SslContext(const std::string& certFilePath,
// Create the Context. We only have one,
// as we don't expect/support different servers in same process.
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
- _ctx = SSL_CTX_new(TLS_server_method());
+ _ctx = SSL_CTX_new(TLS_method());
#else
- _ctx = SSL_CTX_new(SSLv23_server_method());
+ _ctx = SSL_CTX_new(SSLv23_method());
#endif
// SSL_CTX_set_default_passwd_cb(_ctx, &privateKeyPassphraseCallback);
diff --git a/net/SslSocket.hpp b/net/SslSocket.hpp
index c19fedea4..44a2fa382 100644
--- a/net/SslSocket.hpp
+++ b/net/SslSocket.hpp
@@ -46,7 +46,12 @@ public:
SSL_set_bio(_ssl, bio, bio);
if (isClient)
+ {
SSL_set_connect_state(_ssl);
+ if (SSL_connect(_ssl) == 0)
+ LOG_DBG("SslStreamSocket connect #" << getFD() << " failed ");
+ // else -1 is quite possibly SSL_ERROR_WANT_READ
+ }
else // We are a server-side socket.
SSL_set_accept_state(_ssl);
}
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
index 74faa310e..7f13012dd 100644
--- a/tools/WebSocketDump.cpp
+++ b/tools/WebSocketDump.cpp
@@ -196,7 +196,7 @@ class DumpSocketFactory final : public SocketFactory
{
std::shared_ptr<Socket> create(const int physicalFd) override
{
-#if 0 && ENABLE_SSL
+#if ENABLE_SSL
return StreamSocket::create<SslStreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
#else
return StreamSocket::create<StreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
@@ -225,6 +225,20 @@ int main (int argc, char **argv)
Log::initialize("WebSocketDump", "trace", true, false,
std::map<std::string, std::string>());
+#if ENABLE_SSL
+ // hard coded but easy for now.
+ const std::string ssl_cert_file_path = "etc/cert.pem";
+ const std::string ssl_key_file_path = "etc/key.pem";
+ const std::string ssl_ca_file_path = "etc/ca-chain.cert.pem";
+ const std::string ssl_cipher_list = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
+
+ // Initialize the non-blocking socket SSL.
+ SslContext::initialize(ssl_cert_file_path,
+ ssl_key_file_path,
+ ssl_ca_file_path,
+ ssl_cipher_list);
+#endif
+
SocketPoll acceptPoll("accept");
// Setup listening socket with a factory for connected sockets.
commit 9e7dff79f3cc9140f1a81bca2ce6cf8ddd46f8f6
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Thu May 3 17:52:35 2018 +0100
re-factor socket factories to take a client parameter.
Change-Id: I0be98eb583b4f8081dd8ad23e688e93c55220367
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 36d1a0168..373fcc79c 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -700,7 +700,8 @@ class StreamSocket : public Socket, public std::enable_shared_from_this<StreamSo
{
public:
/// Create a StreamSocket from native FD and take ownership of handler instance.
- StreamSocket(const int fd, std::shared_ptr<SocketHandlerInterface> socketHandler) :
+ StreamSocket(const int fd, bool /* isClient */,
+ std::shared_ptr<SocketHandlerInterface> socketHandler) :
Socket(fd),
_socketHandler(std::move(socketHandler)),
_bytesSent(0),
@@ -827,10 +828,10 @@ public:
/// but we can't have a shared_ptr in the ctor.
template <typename TSocket>
static
- std::shared_ptr<TSocket> create(const int fd, std::shared_ptr<SocketHandlerInterface> handler)
+ std::shared_ptr<TSocket> create(const int fd, bool isClient, std::shared_ptr<SocketHandlerInterface> handler)
{
SocketHandlerInterface* pHandler = handler.get();
- auto socket = std::make_shared<TSocket>(fd, std::move(handler));
+ auto socket = std::make_shared<TSocket>(fd, isClient, std::move(handler));
pHandler->onConnect(socket);
return socket;
}
diff --git a/net/SslSocket.hpp b/net/SslSocket.hpp
index 2f8d45cb6..c19fedea4 100644
--- a/net/SslSocket.hpp
+++ b/net/SslSocket.hpp
@@ -19,8 +19,9 @@
class SslStreamSocket final : public StreamSocket
{
public:
- SslStreamSocket(const int fd, std::shared_ptr<SocketHandlerInterface> responseClient) :
- StreamSocket(fd, std::move(responseClient)),
+ SslStreamSocket(const int fd, bool isClient,
+ std::shared_ptr<SocketHandlerInterface> responseClient) :
+ StreamSocket(fd, isClient, std::move(responseClient)),
_ssl(nullptr),
_sslWantsTo(SslWantsTo::Neither),
_doHandshake(true)
@@ -44,8 +45,10 @@ public:
SSL_set_bio(_ssl, bio, bio);
- // We are a server-side socket.
- SSL_set_accept_state(_ssl);
+ if (isClient)
+ SSL_set_connect_state(_ssl);
+ else // We are a server-side socket.
+ SSL_set_accept_state(_ssl);
}
~SslStreamSocket()
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
index bc7a04781..74faa310e 100644
--- a/tools/WebSocketDump.cpp
+++ b/tools/WebSocketDump.cpp
@@ -140,7 +140,10 @@ private:
if (request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
{
- socket->setHandler(std::make_shared<DumpSocketHandler>(_socket, request));
+ auto dumpHandler = std::make_shared<DumpSocketHandler>(_socket, request);
+ socket->setHandler(dumpHandler);
+ dumpHandler->sendMessage("version");
+ dumpHandler->sendMessage("documents");
}
else
{
@@ -194,9 +197,9 @@ class DumpSocketFactory final : public SocketFactory
std::shared_ptr<Socket> create(const int physicalFd) override
{
#if 0 && ENABLE_SSL
- return StreamSocket::create<SslStreamSocket>(physicalFd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+ return StreamSocket::create<SslStreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
#else
- return StreamSocket::create<StreamSocket>(physicalFd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+ return StreamSocket::create<StreamSocket>(physicalFd, false, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
#endif
}
};
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index 26f9243b7..d0e11aeb8 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -699,10 +699,10 @@ void Admin::connectToMonitor(const Poco::URI &uri)
std::shared_ptr<SocketHandlerInterface> handler = std::make_shared<MonitorSocketHandler>(this);
#if ENABLE_SSL
if (isSSL)
- socket = StreamSocket::create<SslStreamSocket>(fd, handler);
+ socket = StreamSocket::create<SslStreamSocket>(fd, true, handler);
#endif
if (!socket && !isSSL)
- socket = StreamSocket::create<StreamSocket>(fd, handler);
+ socket = StreamSocket::create<StreamSocket>(fd, true, handler);
if (socket)
{
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 4ffd8c9df..8a99428a5 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2442,7 +2442,7 @@ class PlainSocketFactory final : public SocketFactory
std::shared_ptr<Socket> socket =
StreamSocket::create<StreamSocket>(
- fd, std::unique_ptr<SocketHandlerInterface>{
+ fd, false, std::unique_ptr<SocketHandlerInterface>{
new ClientRequestDispatcher });
return socket;
@@ -2459,7 +2459,9 @@ class SslSocketFactory final : public SocketFactory
if (SimulatedLatencyMs > 0)
fd = Delay::create(SimulatedLatencyMs, physicalFd);
- return StreamSocket::create<SslStreamSocket>(fd, std::unique_ptr<SocketHandlerInterface>{ new ClientRequestDispatcher });
+ return StreamSocket::create<SslStreamSocket>(
+ fd, false, std::unique_ptr<SocketHandlerInterface>{
+ new ClientRequestDispatcher });
}
};
#endif
@@ -2469,7 +2471,7 @@ class PrisonerSocketFactory final : public SocketFactory
std::shared_ptr<Socket> create(const int fd) override
{
// No local delay.
- return StreamSocket::create<StreamSocket>(fd, std::unique_ptr<SocketHandlerInterface>{ new PrisonerRequestDispatcher });
+ return StreamSocket::create<StreamSocket>(fd, false, std::unique_ptr<SocketHandlerInterface>{ new PrisonerRequestDispatcher });
}
};
commit ca587f407004848937b6c8036aa21b438569b44a
Author: Jan Holesovsky <kendy at collabora.com>
Date: Thu May 3 17:32:31 2018 +0200
The WebSocketHandler::handleClientUpgrade() needs to handle a Response,
not a request.
This commit includes some fixes from Michael Meeks too.
Change-Id: I25198ded9d354a44d7718071394bcccdcabcdd94
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 4faa4f753..c9a2968f6 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -297,8 +297,16 @@ bool StreamSocket::parseHeader(const char *clientName,
return false;
}
}
+ catch (const Poco::Exception& exc)
+ {
+ LOG_DBG("parseHeader exception caught: " << exc.displayText());
+ // Probably don't have enough data just yet.
+ // TODO: timeout if we never get enough.
+ return false;
+ }
catch (const std::exception& exc)
{
+ LOG_DBG("parseHeader exception caught.");
// Probably don't have enough data just yet.
// TODO: timeout if we never get enough.
return false;
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index cea442e73..856c1721a 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -21,6 +21,7 @@
#include <Poco/MemoryStream.h>
#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/WebSocket.h>
class WebSocketHandler : public SocketHandlerInterface
@@ -494,52 +495,64 @@ protected:
{
std::shared_ptr<StreamSocket> socket = _socket.lock();
- LOG_TRC("Incoming client websocket upgrade request");
-
- Poco::MemoryInputStream message(&socket->_inBuffer[0],
- socket->_inBuffer.size());;
- Poco::Net::HTTPRequest req;
- size_t requestSize = 0;
+ LOG_TRC("Incoming client websocket upgrade response: " << std::string(&socket->_inBuffer[0], socket->_inBuffer.size()));
bool bOk = false;
- if (!socket->parseHeader("Monitor", message, req, &requestSize))
- {
-// FIXME: grim hack [!] we can't parse the response for some strange reason ...
-// we get an exception inside Poco ...
-// return;
- bOk = true;
- }
- else if (req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0)
+ size_t responseSize = 0;
+
+ try
{
- const std::string wsKey = req.get("Sec-WebSocket-Accept", "");
- const std::string wsProtocol = req.get("Sec-WebSocket-Protocol", "");
- if (Poco::icompare(wsProtocol, "chat") != 0)
- LOG_ERR("Unknown websocket protocol " << wsProtocol);
- else
+ Poco::MemoryInputStream message(&socket->_inBuffer[0], socket->_inBuffer.size());;
+ Poco::Net::HTTPResponse response;
+
+ response.read(message);
+
{
- LOG_TRC("Accepted incoming websocket request");
- // FIXME: validate Sec-WebSocket-Accept vs. Sec-WebSocket-Key etc.
- bOk = true;
+ static const std::string marker("\r\n\r\n");
+ auto itBody = std::search(socket->_inBuffer.begin(),
+ socket->_inBuffer.end(),
+ marker.begin(), marker.end());
+
+ if (itBody != socket->_inBuffer.end())
+ responseSize = itBody - socket->_inBuffer.begin() + marker.size();
}
+
+ if (response.getStatus() == Poco::Net::HTTPResponse::HTTP_SWITCHING_PROTOCOLS &&
+ response.has("Upgrade") && Poco::icompare(response.get("Upgrade"), "websocket") == 0)
+ {
+#if 0 // SAL_DEBUG ...
+ const std::string wsKey = response.get("Sec-WebSocket-Accept", "");
+ const std::string wsProtocol = response.get("Sec-WebSocket-Protocol", "");
+ if (Poco::icompare(wsProtocol, "chat") != 0)
+ LOG_ERR("Unknown websocket protocol " << wsProtocol);
+ else
+#endif
+ {
+ LOG_TRC("Accepted incoming websocket response");
+ // FIXME: validate Sec-WebSocket-Accept vs. Sec-WebSocket-Key etc.
+ bOk = true;
+ }
+ }
+ }
+ catch (const Poco::Exception& exc)
+ {
+ LOG_DBG("handleClientUpgrade exception caught: " << exc.displayText());
+ }
+ catch (const std::exception& exc)
+ {
+ LOG_DBG("handleClientUpgrade exception caught.");
}
- if (!bOk)
+ if (!bOk || responseSize == 0)
{
- LOG_ERR("Bad websocker server reply: " << req.getURI());
-
- // Bad request.
- std::ostringstream oss;
- oss << "HTTP/1.1 400\r\n"
- << "Date: " << Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n"
- << "User-Agent: " << WOPI_AGENT_STRING << "\r\n"
- << "Content-Length: 0\r\n"
- << "\r\n";
- socket->send(oss.str());
+ LOG_ERR("Bad websocker server response.");
+
socket->shutdown();
+ return;
}
setWebSocket();
- socket->eraseFirstInputBytes(requestSize);
+ socket->eraseFirstInputBytes(responseSize);
}
void setWebSocket()
commit 4cf2ee4fab2ffa86e5047c78bb99a6e408786847
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed May 2 15:40:16 2018 +0100
Get ping/pong handling sorted with more isClient conditionality.
Change-Id: I859ed5b5bcc302304e23ad3554247af920de2421
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index 7679e50ce..cea442e73 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -197,24 +197,51 @@ public:
", fin? " << fin << ", mask? " << hasMask << ", payload length: " << _wsPayload.size() <<
", residual socket data: " << socket->_inBuffer.size() << " bytes.");
+ bool doClose = false;
+
switch (code)
{
case WSOpCode::Pong:
{
- _pingTimeUs = std::chrono::duration_cast<std::chrono::microseconds>
- (std::chrono::steady_clock::now() - _lastPingSentTime).count();
- LOG_TRC("#" << socket->getFD() << ": Pong received: " << _pingTimeUs << " microseconds");
- break;
+ if (_isClient)
+ {
+ LOG_ERR("#" << socket->getFD() << ": Servers should not send pongs, only clients");
+ doClose = true;
+ break;
+ }
+ else
+ {
+ _pingTimeUs = std::chrono::duration_cast<std::chrono::microseconds>
+ (std::chrono::steady_clock::now() - _lastPingSentTime).count();
+ LOG_TRC("#" << socket->getFD() << ": Pong received: " << _pingTimeUs << " microseconds");
+ break;
+ }
}
case WSOpCode::Ping:
- LOG_ERR("#" << socket->getFD() << ": Clients should not send pings, only servers");
- // drop through
-#if defined __clang__
- [[clang::fallthrough]];
-#elif defined __GNUC__ && __GNUC__ >= 7
- [[fallthrough]];
-#endif
+ if (_isClient)
+ {
+ auto now = std::chrono::steady_clock::now();
+ _pingTimeUs = std::chrono::duration_cast<std::chrono::microseconds>
+ (now - _lastPingSentTime).count();
+ sendPong(now, &_wsPayload[0], payloadLen, socket);
+ break;
+ }
+ else
+ {
+ LOG_ERR("#" << socket->getFD() << ": Clients should not send pings, only servers");
+ doClose = true;
+ }
+ break;
case WSOpCode::Close:
+ doClose = true;
+ break;
+ default:
+ handleMessage(fin, code, _wsPayload);
+ break;
+ }
+
+ if (doClose)
+ {
if (!_shuttingDown)
{
// Peer-initiated shutdown must be echoed.
@@ -239,10 +266,6 @@ public:
// TCP Close.
socket->closeConnection();
- break;
- default:
- handleMessage(fin, code, _wsPayload);
- break;
}
_wsPayload.clear();
@@ -270,15 +293,20 @@ public:
int getPollEvents(std::chrono::steady_clock::time_point now,
int & timeoutMaxMs) override
{
- const int timeSincePingMs =
- std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastPingSentTime).count();
- timeoutMaxMs = std::min(timeoutMaxMs, PingFrequencyMs - timeSincePingMs);
+ if (!_isClient)
+ {
+ const int timeSincePingMs =
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastPingSentTime).count();
+ timeoutMaxMs = std::min(timeoutMaxMs, PingFrequencyMs - timeSincePingMs);
+ }
return POLLIN;
}
/// Send a ping message
- void sendPing(std::chrono::steady_clock::time_point now,
- const std::shared_ptr<StreamSocket>& socket)
+ void sendPingOrPong(std::chrono::steady_clock::time_point now,
+ const char* data, const size_t len,
+ const WSOpCode code,
+ const std::shared_ptr<StreamSocket>& socket)
{
assert(socket && "Expected a valid socket instance.");
@@ -290,15 +318,34 @@ public:
return;
}
- LOG_TRC("#" << socket->getFD() << ": Sending ping.");
+ LOG_TRC("#" << socket->getFD() << ": Sending " <<
+ (const char *)(code == WSOpCode::Ping ? " ping." : "pong."));
// FIXME: allow an empty payload.
- sendMessage("", 1, WSOpCode::Ping, false);
+ sendMessage(data, len, code, false);
_lastPingSentTime = now;
}
+ void sendPing(std::chrono::steady_clock::time_point now,
+ const std::shared_ptr<StreamSocket>& socket)
+ {
+ assert(!_isClient);
+ sendPingOrPong(now, "", 1, WSOpCode::Ping, socket);
+ }
+
+ void sendPong(std::chrono::steady_clock::time_point now,
+ const char* data, const size_t len,
+ const std::shared_ptr<StreamSocket>& socket)
+ {
+ assert(_isClient);
+ sendPingOrPong(now, data, len, WSOpCode::Pong, socket);
+ }
+
/// Do we need to handle a timeout ?
void checkTimeout(std::chrono::steady_clock::time_point now) override
{
+ if (_isClient)
+ return;
+
const int timeSincePingMs =
std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastPingSentTime).count();
if (timeSincePingMs >= PingFrequencyMs)
commit 80a13a1e7bddbcd52486994009afaa980838992d
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Tue May 1 17:50:13 2018 +0100
More work on client / Monitor websocket connections.
Change-Id: Ic70fe522e24f2b1863c2d9d1dd6941785510758a
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index f157720b0..7679e50ce 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -19,6 +19,7 @@
#include "common/Unit.hpp"
#include "Socket.hpp"
+#include <Poco/MemoryStream.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/WebSocket.h>
@@ -33,6 +34,7 @@ protected:
std::vector<char> _wsPayload;
std::atomic<bool> _shuttingDown;
+ bool _isClient;
struct WSFrameMask
{
@@ -44,10 +46,12 @@ protected:
static const int PingFrequencyMs;
public:
- WebSocketHandler() :
+ /// Perform upgrade ourselves, or select a client web socket.
+ WebSocketHandler(bool isClient = false) :
_lastPingSentTime(std::chrono::steady_clock::now()),
_pingTimeUs(0),
- _shuttingDown(false)
+ _shuttingDown(false),
+ _isClient(isClient)
{
}
@@ -59,7 +63,8 @@ public:
std::chrono::milliseconds(PingFrequencyMs) -
std::chrono::milliseconds(InitialPingDelayMs)),
_pingTimeUs(0),
- _shuttingDown(false)
+ _shuttingDown(false),
+ _isClient(false)
{
upgradeToWebSocket(request);
}
@@ -253,6 +258,8 @@ public:
{
LOG_ERR("No socket associated with WebSocketHandler 0x" << std::hex << this << std::dec);
}
+ else if (_isClient && !socket->isWebSocket())
+ handleClientUpgrade();
else
{
while (handleOneIncomingMessage(socket))
@@ -435,6 +442,59 @@ protected:
setWebSocket();
}
+ // Handle incoming upgrade to full socket as client WS.
+ void handleClientUpgrade()
+ {
+ std::shared_ptr<StreamSocket> socket = _socket.lock();
+
+ LOG_TRC("Incoming client websocket upgrade request");
+
+ Poco::MemoryInputStream message(&socket->_inBuffer[0],
+ socket->_inBuffer.size());;
+ Poco::Net::HTTPRequest req;
+ size_t requestSize = 0;
+
+ bool bOk = false;
+ if (!socket->parseHeader("Monitor", message, req, &requestSize))
+ {
+// FIXME: grim hack [!] we can't parse the response for some strange reason ...
+// we get an exception inside Poco ...
+// return;
+ bOk = true;
+ }
+ else if (req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0)
+ {
+ const std::string wsKey = req.get("Sec-WebSocket-Accept", "");
+ const std::string wsProtocol = req.get("Sec-WebSocket-Protocol", "");
+ if (Poco::icompare(wsProtocol, "chat") != 0)
+ LOG_ERR("Unknown websocket protocol " << wsProtocol);
+ else
+ {
+ LOG_TRC("Accepted incoming websocket request");
+ // FIXME: validate Sec-WebSocket-Accept vs. Sec-WebSocket-Key etc.
+ bOk = true;
+ }
+ }
+
+ if (!bOk)
+ {
+ LOG_ERR("Bad websocker server reply: " << req.getURI());
+
+ // Bad request.
+ std::ostringstream oss;
+ oss << "HTTP/1.1 400\r\n"
+ << "Date: " << Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n"
+ << "User-Agent: " << WOPI_AGENT_STRING << "\r\n"
+ << "Content-Length: 0\r\n"
+ << "\r\n";
+ socket->send(oss.str());
+ socket->shutdown();
+ }
+
+ setWebSocket();
+ socket->eraseFirstInputBytes(requestSize);
+ }
+
void setWebSocket()
{
std::shared_ptr<StreamSocket> socket = _socket.lock();
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
index 87c76048b..bc7a04781 100644
--- a/tools/WebSocketDump.cpp
+++ b/tools/WebSocketDump.cpp
@@ -214,6 +214,11 @@ int main (int argc, char **argv)
int port = 9042;
(void) argc; (void) argv;
+ if (!UnitWSD::init(UnitWSD::UnitType::Wsd, ""))
+ {
+ throw std::runtime_error("Failed to load wsd unit test library.");
+ }
+
Log::initialize("WebSocketDump", "trace", true, false,
std::map<std::string, std::string>());
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index a4d2baec5..26f9243b7 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -269,6 +269,7 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */,
}
}
+/// Connection from remote admin socket
AdminSocketHandler::AdminSocketHandler(Admin* adminManager,
const std::weak_ptr<StreamSocket>& socket,
const Poco::Net::HTTPRequest& request)
@@ -279,8 +280,9 @@ AdminSocketHandler::AdminSocketHandler(Admin* adminManager,
{
}
+/// Client connection to remote amdin socket
AdminSocketHandler::AdminSocketHandler(Admin* adminManager)
- : WebSocketHandler(),
+ : WebSocketHandler(true),
_admin(adminManager),
_sessionId(0),
_isAuthenticated(true)
@@ -648,7 +650,6 @@ public:
{
LOG_TRC("Outbound monitor - connected");
_connecting = false;
- setWebSocket();
return AdminSocketHandler::performWrites();
}
};
@@ -713,7 +714,8 @@ void Admin::connectToMonitor(const Poco::URI &uri)
std::ostringstream oss;
oss << "GET " << uri.getHost() << " HTTP/1.1\r\n"
"Connection:Upgrade\r\n"
- "Sec-WebSocket-Accept:GAcwqP21iVOY2yKefQ64c0yVN5M=\r\n"
+ "User-Foo: Adminbits\r\n"
+ "Sec-WebSocket-Key: GAcwqP21iVOY2yKefQ64c0yVN5M=\r\n"
"Upgrade:websocket\r\n"
"Accept-Encoding:gzip, deflate, br\r\n"
"Accept-Language:en\r\n"
commit b483f477ddfc20d936a7e202449911c4ec6b525b
Author: Michael Meeks <michael.meeks at collabora.com>
Date: Wed Apr 18 19:20:54 2018 +0100
Allow a 'monitor' to be connected to remotely if configured.
So far monitors have the access an permissions of an
authenticated admin.
Change-Id: I59dfa8a646a60584a5c113ee0521e9afba4f6b76
diff --git a/loolwsd.xml.in b/loolwsd.xml.in
index 33fd52c1b..4937055a3 100644
--- a/loolwsd.xml.in
+++ b/loolwsd.xml.in
@@ -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>
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 84632a4f2..36d1a0168 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -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; }
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index b363364fd..f157720b0 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -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,
diff --git a/tools/WebSocketDump.cpp b/tools/WebSocketDump.cpp
index a72e646c4..87c76048b 100644
--- a/tools/WebSocketDump.cpp
+++ b/tools/WebSocketDump.cpp
@@ -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);
}
}
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index f05a80281..a4d2baec5 100644
--- a/wsd/Admin.cpp
+++ b/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());
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list