[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-4' - 14 commits - common/Common.hpp common/Log.cpp common/Log.hpp common/Png.hpp common/UnitHTTP.hpp common/Util.cpp kit/ForKit.cpp kit/Kit.cpp loleaflet/src net/ServerSocket.hpp net/Socket.cpp net/Socket.hpp wsd/DocumentBroker.cpp wsd/LOOLWSD.cpp wsd/TileCache.cpp wsd/TileDesc.hpp
Libreoffice Gerrit user
logerrit at kemper.freedesktop.org
Sat Apr 27 15:42:18 UTC 2019
common/Common.hpp | 5
common/Log.cpp | 15 +
common/Log.hpp | 26 +--
common/Png.hpp | 10 +
common/UnitHTTP.hpp | 2
common/Util.cpp | 4
kit/ForKit.cpp | 6
kit/Kit.cpp | 47 +++---
loleaflet/src/core/Socket.js | 30 ++-
loleaflet/src/layer/tile/TileLayer.js | 11 -
net/ServerSocket.hpp | 73 ++-------
net/Socket.cpp | 257 ++++++++++++++++++++++++++++++----
net/Socket.hpp | 28 ++-
wsd/DocumentBroker.cpp | 24 +--
wsd/LOOLWSD.cpp | 81 ++++------
wsd/TileCache.cpp | 2
wsd/TileDesc.hpp | 50 +++---
17 files changed, 436 insertions(+), 235 deletions(-)
New commits:
commit 9d2d523f8938f504174ee33c5a13e7c52a6209dc
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Apr 22 12:03:49 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 16:29:45 2019 +0100
wsd: reduce tile logging from debug to trace level
These are very frequent and not very useful without
the ability to trace them across the system, which
are all done at trace level. So it's highly unlikely
that these would be used at debug.
Change-Id: I479f2ead1bbd2996b9972082e00ebf984072f785
Reviewed-on: https://gerrit.libreoffice.org/71073
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 16db919a8..5d75f2637 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1417,7 +1417,7 @@ void DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined,
// Forward to child to render.
const std::string req = newTileCombined.serialize("tilecombine");
- LOG_DBG("Sending residual tilecombine: " << req);
+ LOG_TRC("Sending uncached residual tilecombine request to Kit: " << req);
_childProcess->sendTextFrame(req);
}
@@ -1566,7 +1566,7 @@ void DocumentBroker::sendRequestedTiles(const std::shared_ptr<ClientSession>& se
// Forward to child to render.
const std::string req = newTileCombined.serialize("tilecombine");
- LOG_DBG("Some of the tiles were not prerendered. Sending residual tilecombine: " << req);
+ LOG_TRC("Some of the tiles were not prerendered. Sending residual tilecombine: " << req);
_childProcess->sendTextFrame(req);
}
}
diff --git a/wsd/TileCache.cpp b/wsd/TileCache.cpp
index b46d16044..6a5a6e36f 100644
--- a/wsd/TileCache.cpp
+++ b/wsd/TileCache.cpp
@@ -371,7 +371,7 @@ void TileCache::invalidateTiles(int part, int x, int y, int width, int height)
const std::string fileName = tileIterator.path().getFileName();
if (intersectsTile(fileName, part, x, y, width, height))
{
- LOG_DBG("Removing tile: " << tileIterator.path().toString());
+ LOG_TRC("Removing tile: " << tileIterator.path().toString());
FileUtil::removeFile(tileIterator.path());
}
}
commit fee9341d078c21f49e55c855bebaf46400dea514
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Mon Apr 22 12:00:19 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:44:01 2019 +0100
leaflet: process the most common message first
The 'tile:' message is the most common and most
latency sensitive message, so give it priority.
Change-Id: Id5790369cd493423a47acab8a3d5107ce91b0d39
Reviewed-on: https://gerrit.libreoffice.org/71071
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js
index db0c1e6bf..a73c71e00 100644
--- a/loleaflet/src/core/Socket.js
+++ b/loleaflet/src/core/Socket.js
@@ -834,20 +834,22 @@ L.Socket = L.Class.extend({
this._map.fire('docloaded', {status: true});
}
- // these can arrive very early during the startup
- if (textMsg.startsWith('statusindicatorstart:')) {
- this._map.fire('statusindicator', {statusType : 'start'});
- return;
- }
- else if (textMsg.startsWith('statusindicatorsetvalue:')) {
- var value = textMsg.match(/\d+/g)[0];
- this._map.fire('statusindicator', {statusType : 'setvalue', value : value});
- return;
- }
- else if (textMsg.startsWith('statusindicatorfinish:')) {
- this._map.fire('statusindicator', {statusType : 'finish'});
- this._map._fireInitComplete('statusindicatorfinish');
- return;
+ // These can arrive very early during the startup, and never again.
+ if (textMsg.startsWith('statusindicator')) {
+ if (textMsg.startsWith('statusindicatorstart:')) {
+ this._map.fire('statusindicator', {statusType : 'start'});
+ return;
+ }
+ else if (textMsg.startsWith('statusindicatorsetvalue:')) {
+ var value = textMsg.match(/\d+/g)[0];
+ this._map.fire('statusindicator', {statusType : 'setvalue', value : value});
+ return;
+ }
+ else if (textMsg.startsWith('statusindicatorfinish:')) {
+ this._map.fire('statusindicator', {statusType : 'finish'});
+ this._map._fireInitComplete('statusindicatorfinish');
+ return;
+ }
}
if (this._map._docLayer) {
diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index ca302390e..7a7bf8a6e 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -359,7 +359,11 @@ L.TileLayer = L.GridLayer.extend({
},
_onMessage: function (textMsg, img) {
- if (textMsg.startsWith('commandvalues:')) {
+ // 'tile:' is the most common message type; keep this the first.
+ if (textMsg.startsWith('tile:')) {
+ this._onTileMsg(textMsg, img);
+ }
+ else if (textMsg.startsWith('commandvalues:')) {
this._onCommandValuesMsg(textMsg);
}
else if (textMsg.startsWith('cursorvisible:')) {
@@ -447,9 +451,6 @@ L.TileLayer = L.GridLayer.extend({
else if (textMsg.startsWith('textselectionstart:')) {
this._onTextSelectionStartMsg(textMsg);
}
- else if (textMsg.startsWith('tile:')) {
- this._onTileMsg(textMsg, img);
- }
else if (textMsg.startsWith('windowpaint:')) {
this._onDialogPaintMsg(textMsg, img);
}
@@ -812,7 +813,7 @@ L.TileLayer = L.GridLayer.extend({
//first time document open, set last cursor position
if (this.lastCursorPos.lat === 0 && this.lastCursorPos.lng === 0)
this.lastCursorPos = cursorPos;
-
+
var updateCursor = false;
if ((this.lastCursorPos.lat !== cursorPos.lat) || (this.lastCursorPos.lng !== cursorPos.lng)) {
updateCursor = true;
commit ac7db5b1c22259492004c0bd7b0d6a33938b4932
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 20 14:58:48 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:43:48 2019 +0100
wsd: tile serializer now supports adding a suffix
Moves appending tokens into the serializer and
avoids making extra copies of itself.
Change-Id: I62d374e69d9c4a55643ea20cb5f8c2b9c75c88c5
Reviewed-on: https://gerrit.libreoffice.org/71022
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 8b543204f..48bccf106 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -121,9 +121,9 @@ static std::string ObfuscatedFileId;
#endif
#if ENABLE_DEBUG
-# define ADD_DEBUG_RENDERID(s) ((s)+ " renderid=" + Util::UniqueId())
+# define ADD_DEBUG_RENDERID (" renderid=" + Util::UniqueId() + '\n')
#else
-# define ADD_DEBUG_RENDERID(s) (s)
+# define ADD_DEBUG_RENDERID ("\n")
#endif
#ifndef MOBILEAPP
@@ -1098,9 +1098,9 @@ public:
std::string tileMsg;
if (combined)
- tileMsg = ADD_DEBUG_RENDERID(tileCombined.serialize("tilecombine:")) + "\n";
+ tileMsg = tileCombined.serialize("tilecombine:", ADD_DEBUG_RENDERID);
else
- tileMsg = ADD_DEBUG_RENDERID(tiles[0].serialize("tile:")) + "\n";
+ tileMsg = tiles[0].serialize("tile:", ADD_DEBUG_RENDERID);
LOG_TRC("Sending back painted tiles for " << tileMsg << " of size " << output.size() << " bytes) for: " << tileMsg);
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 3d87e7bb9..16db919a8 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -48,6 +48,12 @@ using namespace LOOLProtocol;
using Poco::JSON::Object;
+#if ENABLE_DEBUG
+# define ADD_DEBUG_RENDERID (" renderid=cached\n")
+#else
+# define ADD_DEBUG_RENDERID ("\n")
+#endif
+
void ChildProcess::setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker)
{
assert(docBroker && "Invalid DocumentBroker instance.");
@@ -1340,11 +1346,7 @@ void DocumentBroker::handleTileRequest(TileDesc& tile,
std::unique_ptr<std::fstream> cachedTile = _tileCache->lookupTile(tile);
if (cachedTile)
{
-#if ENABLE_DEBUG
- const std::string response = tile.serialize("tile:") + " renderid=cached\n";
-#else
- const std::string response = tile.serialize("tile:") + '\n';
-#endif
+ const std::string response = tile.serialize("tile:", ADD_DEBUG_RENDERID);
std::vector<char> output;
output.reserve(static_cast<size_t>(4) * tile.getWidth() * tile.getHeight());
@@ -1391,7 +1393,7 @@ void DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined,
LOG_TRC("TileCombined request for " << tileCombined.serialize());
- // Check which newly requested tiles needs rendering.
+ // Check which newly requested tiles need rendering.
std::vector<TileDesc> tilesNeedsRendering;
for (auto& tile : tileCombined.getTiles())
{
@@ -1524,11 +1526,7 @@ void DocumentBroker::sendRequestedTiles(const std::shared_ptr<ClientSession>& se
if (cachedTile)
{
//TODO: Combine the response to reduce latency.
-#if ENABLE_DEBUG
- const std::string response = tile.serialize("tile:") + " renderid=cached\n";
-#else
- const std::string response = tile.serialize("tile:") + "\n";
-#endif
+ const std::string response = tile.serialize("tile:", ADD_DEBUG_RENDERID);
std::vector<char> output;
output.reserve(static_cast<size_t>(4) * tile.getWidth() * tile.getHeight());
diff --git a/wsd/TileDesc.hpp b/wsd/TileDesc.hpp
index e3c12938b..20f61d5c4 100644
--- a/wsd/TileDesc.hpp
+++ b/wsd/TileDesc.hpp
@@ -29,20 +29,21 @@ typedef uint64_t TileBinaryHash;
class TileDesc
{
public:
- TileDesc(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight, int ver, int imgSize, int id, bool broadcast) :
- _part(part),
- _width(width),
- _height(height),
- _tilePosX(tilePosX),
- _tilePosY(tilePosY),
- _tileWidth(tileWidth),
- _tileHeight(tileHeight),
- _ver(ver),
- _imgSize(imgSize),
- _id(id),
- _broadcast(broadcast),
- _oldWireId(0),
- _wireId(0)
+ TileDesc(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth,
+ int tileHeight, int ver, int imgSize, int id, bool broadcast)
+ : _part(part)
+ , _width(width)
+ , _height(height)
+ , _tilePosX(tilePosX)
+ , _tilePosY(tilePosY)
+ , _tileWidth(tileWidth)
+ , _tileHeight(tileHeight)
+ , _ver(ver)
+ , _imgSize(imgSize)
+ , _id(id)
+ , _broadcast(broadcast)
+ , _oldWireId(0)
+ , _wireId(0)
{
if (_part < 0 ||
_width <= 0 ||
@@ -138,7 +139,8 @@ public:
/// Serialize this instance into a string.
/// Optionally prepend a prefix.
- std::string serialize(const std::string& prefix = "") const
+ std::string serialize(const std::string& prefix = std::string(),
+ const std::string& suffix = std::string()) const
{
std::ostringstream oss;
oss << prefix
@@ -170,6 +172,7 @@ public:
oss << " broadcast=yes";
}
+ oss << suffix;
return oss.str();
}
@@ -343,7 +346,8 @@ public:
/// Serialize this instance into a string.
/// Optionally prepend a prefix.
- std::string serialize(const std::string& prefix = "") const
+ std::string serialize(const std::string& prefix = std::string(),
+ const std::string& suffix = std::string()) const
{
std::ostringstream oss;
oss << prefix
@@ -389,15 +393,19 @@ public:
oss.seekp(-1, std::ios_base::cur); // Ditto
oss << " wid=";
+
+ bool comma = false;
for (const auto& tile : _tiles)
{
- oss << tile.getWireId() << ',';
+ if (comma)
+ oss << ',';
+
+ oss << tile.getWireId();
+ comma = true;
}
- oss.seekp(-1, std::ios_base::cur); // See beow.
- // Make sure we don't return a potential trailing comma that
- // we have seeked back over but not overwritten after all.
- return oss.str().substr(0, oss.tellp());
+ oss << suffix;
+ return oss.str();
}
/// Deserialize a TileDesc from a tokenized string.
commit 0d99dc7266ae105bc8665e121146439474b58c9a
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 20 14:10:38 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:43:44 2019 +0100
wsd: set vector size when constructing
Change-Id: I68718554017b47b6df1c6bf3b997483d4c753136
Reviewed-on: https://gerrit.libreoffice.org/71021
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 6b45c8534..8b543204f 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -29,8 +29,10 @@
#include <climits>
#include <condition_variable>
#include <cstdlib>
+#include <cstring>
#include <iostream>
#include <memory>
+#include <string>
#include <sstream>
#include <thread>
@@ -1102,8 +1104,7 @@ public:
LOG_TRC("Sending back painted tiles for " << tileMsg << " of size " << output.size() << " bytes) for: " << tileMsg);
- std::shared_ptr<std::vector<char>> response = std::make_shared<std::vector<char>>();
- response->resize(tileMsg.size() + output.size());
+ std::shared_ptr<std::vector<char>> response = std::make_shared<std::vector<char>>(tileMsg.size() + output.size());
std::copy(tileMsg.begin(), tileMsg.end(), response->begin());
std::copy(output.begin(), output.end(), response->begin() + tileMsg.size());
commit 242df1594dd9283ba0501b141e176617b03cf3d9
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 20 11:39:20 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:43:10 2019 +0100
wsd: reuse ostringstream when logging
This is faster and reduces memory fragmentation.
Also, cleans up the logging macros and implementation.
Change-Id: I7fb00da041d1261c694c4b48b67a3c66ad0cbf8d
Reviewed-on: https://gerrit.libreoffice.org/71020
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/common/Log.cpp b/common/Log.cpp
index a5f101e93..3bedaa82e 100644
--- a/common/Log.cpp
+++ b/common/Log.cpp
@@ -131,6 +131,21 @@ namespace Log
return buffer;
}
+ // Reuse the same buffer to minimize memory fragmentation.
+ static thread_local std::ostringstream Oss;
+
+ std::ostringstream& begin(const char* level)
+ {
+ // Reset the oss.
+ Oss.clear();
+ Oss.seekp(0);
+
+ // Output the prefix.
+ char buffer[1024];
+ Oss << Log::prefix(buffer, sizeof(buffer) - 1, level) << std::boolalpha;
+ return Oss;
+ }
+
void signalLogPrefix()
{
char buffer[1024];
diff --git a/common/Log.hpp b/common/Log.hpp
index bf05fc7ce..9ded1425a 100644
--- a/common/Log.hpp
+++ b/common/Log.hpp
@@ -50,6 +50,9 @@ namespace Log
char* prefix(char* buffer, std::size_t len, const char* level);
+ /// Starts logging by generating the prefix and returning an oss.
+ std::ostringstream& begin(const char* level);
+
inline bool traceEnabled() { return logger().trace(); }
inline bool debugEnabled() { return logger().debug(); }
inline bool infoEnabled() { return logger().information(); }
@@ -233,20 +236,19 @@ namespace Log
#define LOG_FILE_NAME(f) (strrchr(f, '/')+1)
#endif
-#define LOG_END(LOG, FILEP) \
- do \
- { \
- if (FILEP) \
- LOG << "| " << LOG_FILE_NAME(__FILE__) << ':' << __LINE__; \
+#define LOG_END(LOG, FILEP) \
+ do \
+ { \
+ if (FILEP) \
+ LOG << "| " << LOG_FILE_NAME(__FILE__) << ':' << __LINE__; \
} while (false)
-#define LOG_BODY_(LOG, PRIO, LVL, X, FILEP) \
- Poco::Message m_(LOG.name(), "", Poco::Message::PRIO_##PRIO); \
- char b_[1024]; \
- std::ostringstream oss_(Log::prefix(b_, sizeof(b_) - 1, LVL), std::ostringstream::ate); \
- oss_ << std::boolalpha << X; \
- LOG_END(oss_, FILEP); \
- m_.setText(oss_.str()); \
+#define LOG_BODY_(LOG, PRIO, LVL, X, FILEP) \
+ Poco::Message m_(LOG.name(), "", Poco::Message::PRIO_##PRIO); \
+ std::ostringstream& oss_ = Log::begin(LVL); \
+ oss_ << X; \
+ LOG_END(oss_, FILEP); \
+ m_.setText(oss_.str()); \
LOG.log(m_);
#define LOG_TRC(X) \
commit 2ac2bf1ae1439421432ee05716c2ea3cf80ab2b2
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 20 15:23:32 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:42:57 2019 +0100
wsd: use thread_local instead of __thread
The former is the standard C++ approach
and is reportedly faster than __thread
(at least with gcc).
Change-Id: Ibdefd32172774a280637f73dd062282b7bf62025
Reviewed-on: https://gerrit.libreoffice.org/71019
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/common/Util.cpp b/common/Util.cpp
index 44a39fea8..ccde3c0d7 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -499,7 +499,7 @@ namespace Util
return replace(r, "\n", " / ");
}
- static __thread char ThreadName[32] = {0};
+ static thread_local char ThreadName[32] = {0};
void setThreadName(const std::string& s)
{
@@ -539,7 +539,7 @@ namespace Util
}
#ifdef __linux
- static __thread pid_t ThreadTid = 0;
+ static thread_local pid_t ThreadTid = 0;
pid_t getThreadId()
#else
commit b5efa32d9eb3c467be4cb92be80ac413938dba92
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Fri Apr 19 20:09:22 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:42:46 2019 +0100
wsd: use fast deflate level for png
The default deflate level of 6 is quite slow
and the benefits are hardly worth the high
latency that users experience.
Tested on a writer document with some small
images and a few pages of text:
Level 4 gives virtually identical compression
ratio to level 6, but is between 5-10% faster.
Level 3 runs almost twice as fast as level 6,
but the output is typically 2-3x larger.
Perhaps this should be exposed via config
so it would be possible to reduce latency
due to compression when CPU is scarce but
network bandwidth ample, and vice versa.
Change-Id: Iba88eea8f180d11458b33c68389e797234df1a60
Reviewed-on: https://gerrit.libreoffice.org/71018
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/common/Png.hpp b/common/Png.hpp
index f75254852..62e24357d 100644
--- a/common/Png.hpp
+++ b/common/Png.hpp
@@ -136,6 +136,12 @@ bool encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY,
#ifdef MOBILEAPP
png_set_compression_level(png_ptr, Z_BEST_SPEED);
+#else
+ // Level 4 gives virtually identical compression
+ // ratio to level 6, but is between 5-10% faster.
+ // Level 3 runs almost twice as fast, but the
+ // output is typically 2-3x larger.
+ png_set_compression_level(png_ptr, 4);
#endif
#ifdef IOS
commit 4b2f9bef15a53f76de94e5a4efa3d21f62bab818
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Fri Apr 19 20:06:27 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:42:33 2019 +0100
wsd: logging, comments, and const correctness
Change-Id: Ibfbef282e951a80fb145239df4bbcc9f3e4c8e13
Reviewed-on: https://gerrit.libreoffice.org/71017
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Signed-off-by: Michael Meeks <michael.meeks at collabora.com>
diff --git a/common/Png.hpp b/common/Png.hpp
index 0d40a37a0..f75254852 100644
--- a/common/Png.hpp
+++ b/common/Png.hpp
@@ -173,7 +173,9 @@ bool encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY,
totalDuration += duration;
nCalls += 1;
- LOG_TRC("Average PNG compression time after " << std::to_string(nCalls) << " calls: " << (totalDuration / static_cast<double>(nCalls)));
+ LOG_TRC("PNG compression took " << duration << " ms (" << output.size()
+ << " bytes). Average after " << std::to_string(nCalls)
+ << " calls: " << (totalDuration / static_cast<double>(nCalls)));
png_destroy_write_struct(&png_ptr, &info_ptr);
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index a8ab8fe2d..6b45c8534 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -430,7 +430,6 @@ private:
return _wireId;
}
} ;
-
size_t _cacheSize;
static const size_t CacheSizeSoftLimit = (1024 * 4 * 32); // 128k of cache
static const size_t CacheSizeHardLimit = CacheSizeSoftLimit * 2;
@@ -474,9 +473,9 @@ private:
for (auto it = _cache.begin(); it != _cache.end(); ++it)
avgHits += it->second.getHitCount();
- LOG_DBG("cache " << _cache.size() << " items total size " <<
- _cacheSize << " current hits " << avgHits << ", total hit rate " <<
- (_cacheHits * 100. / _cacheTests) << "% at balance start");
+ LOG_DBG("PNG cache has " << _cache.size() << " items, total size " <<
+ _cacheSize << ", current hits " << avgHits << ", total hit rate " <<
+ (_cacheHits * 100. / _cacheTests) << "% at balance start.");
avgHits /= _cache.size();
for (auto it = _cache.begin(); it != _cache.end();)
@@ -502,8 +501,8 @@ private:
}
}
- LOG_DBG("cache " << _cache.size() << " items total size " <<
- _cacheSize << " after balance");
+ LOG_DBG("PNG cache has " << _cache.size() << " items, total size " <<
+ _cacheSize << " after balance.");
}
}
commit 35a21fd0e5902ee256e624ecb0589b7c013e985f
Author: Henry Castro <hcastro at collabora.com>
AuthorDate: Tue Apr 2 10:26:02 2019 -0400
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:37:38 2019 +0100
fix build: "sockaddr_un addrunix’ has incomplete type ...
and cannot be defined"
Change-Id: I2c136fc47c800ec3efd6268b4601100033e22724
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 3ef0a4df1..f3492c37f 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -17,6 +17,7 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <zlib.h>
#include <Poco/DateTime.h>
commit 233e61f59c52875b67fcc9aeea35b6621703a99e
Author: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
AuthorDate: Mon Apr 1 14:18:23 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:26:42 2019 +0100
Fix -Werror=maybe-uninitialized
Change-Id: I076fb4b9ef80e4fbf13cdd22cff51ab1e99a2c6c
diff --git a/net/Socket.cpp b/net/Socket.cpp
index f423ecb8e..3ef0a4df1 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -43,7 +43,7 @@ std::atomic<bool> Socket::InhibitThreadChecks(false);
int Socket::createSocket(Socket::Type type)
{
#ifndef MOBILEAPP
- int domain;
+ int domain = AF_UNSPEC;
switch (type)
{
case Type::IPv4: domain = AF_INET; break;
commit aaf7bd2ff15ab9038e97d1abec17df639f3c942e
Author: Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Mon Apr 1 12:00:27 2019 +0200
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:26:07 2019 +0100
net: fix -Werror,-Winconsistent-missing-override
Change-Id: I5e7bce35cd9892a3f74d6d57e094c006bd13b991
diff --git a/net/ServerSocket.hpp b/net/ServerSocket.hpp
index f3afa0117..1b1f10fb9 100644
--- a/net/ServerSocket.hpp
+++ b/net/ServerSocket.hpp
@@ -104,7 +104,7 @@ public:
ServerSocket(Socket::Type::Unix, clientPoller, sockFactory)
{
}
- virtual bool bind(Type, int) { assert(false); return false; }
+ virtual bool bind(Type, int) override { assert(false); return false; }
virtual std::shared_ptr<Socket> accept() override;
std::string bind();
commit 6188daf581caf4a30dc62d61f5167b021d8990c0
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Apr 1 10:56:15 2019 +0100
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:25:55 2019 +0100
peercred: fixup compile issues.
Change-Id: I87d956f5754e7b353776c538b7bb9dfea7f62883
diff --git a/net/Socket.cpp b/net/Socket.cpp
index ab13b24cf..f423ecb8e 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -569,16 +569,16 @@ std::shared_ptr<Socket> LocalServerSocket::accept()
// Sanity check this incoming socket
struct ucred creds;
socklen_t credSize = sizeof(struct ucred);
- if (getsockopt(GetFD(), SOL_SOCKET, SO_PEERCRED, &creds, &credSize) < 0)
+ if (getsockopt(getFD(), SOL_SOCKET, SO_PEERCRED, &creds, &credSize) < 0)
{
- LOG_ERR("Failed to get peer creds on " << GetFD() << " " << strerror(errno));
+ LOG_ERR("Failed to get peer creds on " << getFD() << " " << strerror(errno));
::close(rc);
return std::shared_ptr<Socket>(nullptr);
}
- int uid = getuid();
- int gid = getgid();
- if (creds.uid != uid || cred.gid != gid)
+ uid_t uid = getuid();
+ uid_t gid = getgid();
+ if (creds.uid != uid || creds.gid != gid)
{
LOG_ERR("Peercred mis-match on domain socket - closing connection. uid: " <<
creds.uid << "vs." << uid << " gid: " << creds.gid << "vs." << gid);
@@ -589,7 +589,6 @@ std::shared_ptr<Socket> LocalServerSocket::accept()
addr.append(std::to_string(creds.pid));
_socket->setClientAddress(addr);
- std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
LOG_DBG("Accepted socket is UDS - address " << addr <<
" and pid/gid " << creds.pid << "/" << creds.gid);
#endif
commit 93caa4d766959e72f8a5a24b3cd4ad83f9865682
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Mar 30 21:07:58 2019 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:25:30 2019 +0100
Use peercreds to identify processes connecting rather than URL params.
Change-Id: I241e80962fb8cf2f3fff1bb4be81d9f0ee74c648
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index dd9ff3ed0..a8ab8fe2d 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2418,11 +2418,8 @@ void lokit_main(
LOG_INF("Process is ready.");
- static const std::string pid = std::to_string(Process::id());
std::string pathAndQuery(NEW_CHILD_URI);
- pathAndQuery.append("?pid=");
- pathAndQuery.append(pid);
- pathAndQuery.append("&jailid=");
+ pathAndQuery.append("?jailid=");
pathAndQuery.append(jailId);
if (queryVersion)
{
@@ -2455,7 +2452,6 @@ void lokit_main(
// Dummies
const std::string jailId = "jailid";
- const std::string pid = "101";
#endif // MOBILEAPP
@@ -2463,7 +2459,7 @@ void lokit_main(
mainKit.runOnClientThread(); // We will do the polling on this thread.
std::shared_ptr<SocketHandlerInterface> websocketHandler =
- std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit);
+ std::make_shared<KitWebSocketHandler>("child_ws", loKit, jailId, mainKit);
#ifndef MOBILEAPP
mainKit.insertNewUnixSocket(MasterLocation, pathAndQuery, websocketHandler);
#else
diff --git a/net/ServerSocket.hpp b/net/ServerSocket.hpp
index 118b93d3c..f3afa0117 100644
--- a/net/ServerSocket.hpp
+++ b/net/ServerSocket.hpp
@@ -61,58 +61,7 @@ public:
/// Accepts an incoming connection (Servers only).
/// Does not retry on error.
/// Returns a valid Socket shared_ptr on success only.
- std::shared_ptr<Socket> accept()
- {
- // Accept a connection (if any) and set it to non-blocking.
- // There still need the client's address to filter request from POST(call from REST) here.
-#ifndef MOBILEAPP
- struct sockaddr_in6 clientInfo;
- socklen_t addrlen = sizeof(clientInfo);
- const int rc = ::accept4(getFD(), (struct sockaddr *)&clientInfo, &addrlen, SOCK_NONBLOCK);
-#else
- const int rc = fakeSocketAccept4(getFD());
-#endif
- LOG_DBG("Accepted socket #" << rc << ", creating socket object.");
- try
- {
- // Create a socket object using the factory.
- if (rc != -1)
- {
-#ifndef MOBILEAPP
- char addrstr[INET6_ADDRSTRLEN];
-
- const void *inAddr;
- if (clientInfo.sin6_family == AF_INET)
- {
- auto ipv4 = (struct sockaddr_in *)&clientInfo;
- inAddr = &(ipv4->sin_addr);
- }
- else
- {
- auto ipv6 = (struct sockaddr_in6 *)&clientInfo;
- inAddr = &(ipv6->sin6_addr);
- }
-
- inet_ntop(clientInfo.sin6_family, inAddr, addrstr, sizeof(addrstr));
- std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
- _socket->setClientAddress(addrstr);
- LOG_DBG("Accepted socket has family " << clientInfo.sin6_family <<
- " address " << _socket->clientAddress());
-#else
- std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
- _socket->setClientAddress("dummy");
-#endif
- return _socket;
- }
- return std::shared_ptr<Socket>(nullptr);
- }
- catch (const std::exception& ex)
- {
- LOG_SYS("Failed to create client socket #" << rc << ". Error: " << ex.what());
- }
-
- return nullptr;
- }
+ virtual std::shared_ptr<Socket> accept();
int getPollEvents(std::chrono::steady_clock::time_point /* now */,
int & /* timeoutMaxMs */) override
@@ -143,6 +92,7 @@ public:
private:
Socket::Type _type;
SocketPoll& _clientPoller;
+protected:
std::shared_ptr<SocketFactory> _sockFactory;
};
@@ -155,6 +105,7 @@ public:
{
}
virtual bool bind(Type, int) { assert(false); return false; }
+ virtual std::shared_ptr<Socket> accept() override;
std::string bind();
private:
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 5458dde2d..ab13b24cf 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -16,6 +16,7 @@
#include <iomanip>
#include <stdio.h>
#include <unistd.h>
+#include <sys/types.h>
#include <zlib.h>
#include <Poco/DateTime.h>
@@ -398,7 +399,8 @@ void StreamSocket::dumpState(std::ostream& os)
int events = getPollEvents(std::chrono::steady_clock::now(), timeoutMaxMs);
os << "\t" << getFD() << "\t" << events << "\t"
<< _inBuffer.size() << "\t" << _outBuffer.size() << "\t"
- << " r: " << _bytesRecvd << "\t w: " << _bytesSent << "\t";
+ << " r: " << _bytesRecvd << "\t w: " << _bytesSent << "\t"
+ << clientAddress() << "\t";
_socketHandler->dumpState(os);
if (_inBuffer.size() > 0)
Util::dumpHex(os, "\t\tinBuffer:\n", "\t\t", _inBuffer);
@@ -483,6 +485,123 @@ bool ServerSocket::bind(Type type, int port)
#endif
}
+std::shared_ptr<Socket> ServerSocket::accept()
+{
+ // Accept a connection (if any) and set it to non-blocking.
+ // There still need the client's address to filter request from POST(call from REST) here.
+#if !MOBILEAPP
+ assert(_type != Socket::Type::Unix);
+
+ struct sockaddr_in6 clientInfo;
+ socklen_t addrlen = sizeof(clientInfo);
+ const int rc = ::accept4(getFD(), (struct sockaddr *)&clientInfo, &addrlen, SOCK_NONBLOCK);
+#else
+ const int rc = fakeSocketAccept4(getFD());
+#endif
+ LOG_DBG("Accepted socket #" << rc << ", creating socket object.");
+ try
+ {
+ // Create a socket object using the factory.
+ if (rc != -1)
+ {
+ std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
+
+#if !MOBILEAPP
+ char addrstr[INET6_ADDRSTRLEN];
+
+ const void *inAddr;
+ if (clientInfo.sin6_family == AF_INET)
+ {
+ auto ipv4 = (struct sockaddr_in *)&clientInfo;
+ inAddr = &(ipv4->sin_addr);
+ }
+ else
+ {
+ auto ipv6 = (struct sockaddr_in6 *)&clientInfo;
+ inAddr = &(ipv6->sin6_addr);
+ }
+
+ inet_ntop(clientInfo.sin6_family, inAddr, addrstr, sizeof(addrstr));
+ _socket->setClientAddress(addrstr);
+
+ LOG_DBG("Accepted socket has family " << clientInfo.sin6_family <<
+ " address " << _socket->clientAddress());
+#endif
+ return _socket;
+ }
+ return std::shared_ptr<Socket>(nullptr);
+ }
+ catch (const std::exception& ex)
+ {
+ LOG_SYS("Failed to create client socket #" << rc << ". Error: " << ex.what());
+ }
+
+ return nullptr;
+}
+
+int Socket::getPid() const
+{
+ struct ucred creds;
+ socklen_t credSize = sizeof(struct ucred);
+ if (getsockopt(_fd, SOL_SOCKET, SO_PEERCRED, &creds, &credSize) < 0)
+ {
+ LOG_TRC("Failed to get pid via peer creds on " << _fd << " " << strerror(errno));
+ return -1;
+ }
+ return creds.pid;
+}
+
+std::shared_ptr<Socket> LocalServerSocket::accept()
+{
+#if !MOBILEAPP
+ const int rc = ::accept4(getFD(), nullptr, nullptr, SOCK_NONBLOCK);
+#else
+ const int rc = fakeSocketAccept4(getFD());
+#endif
+ try
+ {
+ LOG_DBG("Accepted prisoner socket #" << rc << ", creating socket object.");
+ if (rc < 0)
+ return std::shared_ptr<Socket>(nullptr);
+
+ std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
+#if MOBILEAPP
+ // Sanity check this incoming socket
+ struct ucred creds;
+ socklen_t credSize = sizeof(struct ucred);
+ if (getsockopt(GetFD(), SOL_SOCKET, SO_PEERCRED, &creds, &credSize) < 0)
+ {
+ LOG_ERR("Failed to get peer creds on " << GetFD() << " " << strerror(errno));
+ ::close(rc);
+ return std::shared_ptr<Socket>(nullptr);
+ }
+
+ int uid = getuid();
+ int gid = getgid();
+ if (creds.uid != uid || cred.gid != gid)
+ {
+ LOG_ERR("Peercred mis-match on domain socket - closing connection. uid: " <<
+ creds.uid << "vs." << uid << " gid: " << creds.gid << "vs." << gid);
+ ::close(rc);
+ return std::shared_ptr<Socket>(nullptr);
+ }
+ std::string addr("uds-to-pid-");
+ addr.append(std::to_string(creds.pid));
+ _socket->setClientAddress(addr);
+
+ std::shared_ptr<Socket> _socket = _sockFactory->create(rc);
+ LOG_DBG("Accepted socket is UDS - address " << addr <<
+ " and pid/gid " << creds.pid << "/" << creds.gid);
+#endif
+ return _socket;
+ }
+ catch (const std::exception& ex)
+ {
+ LOG_SYS("Failed to create client socket #" << rc << ". Error: " << ex.what());
+ return std::shared_ptr<Socket>(nullptr);
+ }
+}
+
/// Returns true on success only.
std::string LocalServerSocket::bind()
{
diff --git a/net/Socket.hpp b/net/Socket.hpp
index f282266be..e87f0f8f7 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -173,6 +173,9 @@ public:
}
#ifndef MOBILEAPP
+ /// Uses peercreds to get prisoner PID if present or -1
+ int getPid() const;
+
/// Sets the kernel socket send buffer in size bytes.
/// Note: TCP will allocate twice this size for admin purposes,
/// so a subsequent call to getSendBufferSize will return
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 5f2b5a4c5..7a7dfed54 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1847,22 +1847,15 @@ private:
// New Child is spawned.
const Poco::URI::QueryParameters params = requestURI.getQueryParameters();
- Poco::Process::PID pid = -1;
+ int pid = socket->getPid();
std::string jailId;
for (const auto& param : params)
{
- if (param.first == "pid")
- {
- pid = std::stoi(param.second);
- }
- else if (param.first == "jailid")
- {
+ if (param.first == "jailid")
jailId = param.second;
- }
+
else if (param.first == "version")
- {
LOOLWSD::LOKitVersion = param.second;
- }
}
if (pid <= 0)
commit 46c93bce5d35af5c2684e50422ceb83ba70a792d
Author: Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Mar 30 14:06:16 2019 +0000
Commit: Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 27 15:22:27 2019 +0100
Switch local prisoner sockets to abstract UDS
Unix Domain Sockets are inaddressable remotely, and more efficient,
as well as allowing future SCM_CREDENTIALS / SCM_RIGHTS.
Change-Id: Ia2472260f75feb43e9022cdfa0fe005ccd489454
diff --git a/common/Common.hpp b/common/Common.hpp
index 013b30798..af37a77dd 100644
--- a/common/Common.hpp
+++ b/common/Common.hpp
@@ -7,12 +7,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+#include <string>
+
// Default values and other shared data between processes.
#ifndef INCLUDED_COMMON_HPP
#define INCLUDED_COMMON_HPP
constexpr int DEFAULT_CLIENT_PORT_NUMBER = 9980;
-constexpr int DEFAULT_MASTER_PORT_NUMBER = 9981;
constexpr int COMMAND_TIMEOUT_MS = 5000;
constexpr long CHILD_TIMEOUT_MS = COMMAND_TIMEOUT_MS;
@@ -46,7 +47,7 @@ constexpr const char* WOPI_AGENT_STRING = "LOOLWSD WOPI Agent " LOOLWSD_VERSION;
// The client port number, both loolwsd and the kits have this.
extern int ClientPortNumber;
-extern int MasterPortNumber;
+extern std::string MasterLocation;
#endif
diff --git a/common/UnitHTTP.hpp b/common/UnitHTTP.hpp
index 9ff24caab..640ae8b0d 100644
--- a/common/UnitHTTP.hpp
+++ b/common/UnitHTTP.hpp
@@ -74,7 +74,7 @@ public:
UnitHTTPServerRequest(UnitHTTPServerResponse& inResponse,
const std::string& uri) :
_response(inResponse),
- _serverAddress(MasterPortNumber)
+ _serverAddress(9981) // FIXME: Unix Sockets now ...
{
setURI(uri);
}
diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp
index 9b3571efb..fe5fd225a 100644
--- a/kit/ForKit.cpp
+++ b/kit/ForKit.cpp
@@ -60,7 +60,7 @@ static std::map<Process::PID, std::string> childJails;
#ifndef KIT_IN_PROCESS
int ClientPortNumber = DEFAULT_CLIENT_PORT_NUMBER;
-int MasterPortNumber = DEFAULT_MASTER_PORT_NUMBER;
+std::string MasterLocation;
#endif
/// Dispatcher class to demultiplex requests from
@@ -401,7 +401,7 @@ int main(int argc, char** argv)
ClientPortNumber = std::stoi(clientPort);
static const char* masterPort = std::getenv("LOOL_TEST_MASTER_PORT");
if (masterPort)
- MasterPortNumber = std::stoi(masterPort);
+ MasterLocation = masterPort;
#endif
for (int i = 0; i < argc; ++i)
@@ -436,7 +436,7 @@ int main(int argc, char** argv)
else if (std::strstr(cmd, "--masterport=") == cmd)
{
eq = std::strchr(cmd, '=');
- MasterPortNumber = std::stoll(std::string(eq+1));
+ MasterLocation = std::string(eq+1);
}
else if (std::strstr(cmd, "--version") == cmd)
{
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index ebb8c101f..dd9ff3ed0 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -2419,20 +2419,21 @@ void lokit_main(
LOG_INF("Process is ready.");
static const std::string pid = std::to_string(Process::id());
-
- 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);
-
+ std::string pathAndQuery(NEW_CHILD_URI);
+ pathAndQuery.append("?pid=");
+ pathAndQuery.append(pid);
+ pathAndQuery.append("&jailid=");
+ pathAndQuery.append(jailId);
if (queryVersion)
{
char* versionInfo = loKit->getVersionInfo();
std::string versionString(versionInfo);
if (displayVersion)
std::cout << "office version details: " << versionString << std::endl;
- uri.addQueryParameter("version", versionString);
+ std::string encodedVersion;
+ Poco::URI::encode(versionString, "?#/", encodedVersion);
+ pathAndQuery.append("&version=");
+ pathAndQuery.append(encodedVersion);
free(versionInfo);
}
@@ -2461,10 +2462,12 @@ void lokit_main(
SocketPoll mainKit("kit");
mainKit.runOnClientThread(); // We will do the polling on this thread.
+ std::shared_ptr<SocketHandlerInterface> websocketHandler =
+ std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit);
#ifndef MOBILEAPP
- mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
+ mainKit.insertNewUnixSocket(MasterLocation, pathAndQuery, websocketHandler);
#else
- mainKit.insertNewWebSocketSync(docBrokerSocket, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
+ mainKit.insertNewFakeSocketSync(docBrokerSocket, websocketHandler);
#endif
LOG_INF("New kit client websocket inserted.");
diff --git a/net/ServerSocket.hpp b/net/ServerSocket.hpp
index 7606e86ce..118b93d3c 100644
--- a/net/ServerSocket.hpp
+++ b/net/ServerSocket.hpp
@@ -35,12 +35,13 @@ public:
{
}
+ /// Control access to a bound TCP socket
enum Type { Local, Public };
/// Binds to a local address (Servers only).
/// Does not retry on error.
/// Returns true only on success.
- bool bind(Type type, int port);
+ virtual bool bind(Type type, int port);
/// Listen to incoming connections (Servers only).
/// Does not retry on error.
@@ -145,6 +146,21 @@ private:
std::shared_ptr<SocketFactory> _sockFactory;
};
+/// A non-blocking, streaming Unix Domain Socket for local use
+class LocalServerSocket : public ServerSocket
+{
+public:
+ LocalServerSocket(SocketPoll& clientPoller, std::shared_ptr<SocketFactory> sockFactory) :
+ ServerSocket(Socket::Type::Unix, clientPoller, sockFactory)
+ {
+ }
+ virtual bool bind(Type, int) { assert(false); return false; }
+ std::string bind();
+
+private:
+ std::string _name;
+};
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 2d35f6b02..5458dde2d 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -37,10 +37,20 @@ int SocketPoll::DefaultPollTimeoutMs = 5000;
std::atomic<bool> SocketPoll::InhibitThreadChecks(false);
std::atomic<bool> Socket::InhibitThreadChecks(false);
+#define SOCKET_ABSTRACT_UNIX_NAME "0loolwsd-"
+
int Socket::createSocket(Socket::Type type)
{
#ifndef MOBILEAPP
- int domain = type == Type::IPv4 ? AF_INET : AF_INET6;
+ int domain;
+ switch (type)
+ {
+ case Type::IPv4: domain = AF_INET; break;
+ case Type::IPv6: domain = AF_INET6; break;
+ case Type::All: domain = AF_INET6; break;
+ case Type::Unix: domain = AF_UNIX; break;
+ default: assert (false); break;
+ }
return socket(domain, SOCK_STREAM | SOCK_NONBLOCK, 0);
#else
return fakeSocketSocket();
@@ -190,14 +200,9 @@ void SocketPoll::wakeupWorld()
}
void SocketPoll::insertNewWebSocketSync(
-#ifndef MOBILEAPP
- const Poco::URI &uri,
-#else
- int peerSocket,
-#endif
- const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
+ const Poco::URI &uri,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
{
-#ifndef MOBILEAPP
LOG_INF("Connecting to " << uri.getHost() << " : " << uri.getPort() << " : " << uri.getPath());
// FIXME: put this in a ClientSocket class ?
@@ -247,24 +252,7 @@ void SocketPoll::insertNewWebSocketSync(
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.getPathAndQuery() << " HTTP/1.1\r\n"
- "Connection:Upgrade\r\n"
- "User-Foo: Adminbits\r\n"
- "Sec-WebSocket-Key:fxTaWTEMVhq1PkWsMoLxGw==\r\n"
- "Upgrade:websocket\r\n"
- "Accept-Language:en\r\n"
- "Cache-Control:no-cache\r\n"
- "Pragma:no-cache\r\n"
- "Sec-WebSocket-Version:13\r\n"
- "User-Agent: " << WOPI_AGENT_STRING << "\r\n"
- "\r\n";
- socket->send(oss.str());
- websocketHandler->onConnect(socket);
+ clientRequestWebsocketUpgrade(socket, websocketHandler, uri.getPathAndQuery());
insertNewSocket(socket);
}
else
@@ -282,7 +270,71 @@ void SocketPoll::insertNewWebSocketSync(
}
else
LOG_ERR("Failed to lookup client websocket host '" << uri.getHost() << "' skipping");
-#else
+}
+
+// should this be a static method in the WebsocketHandler(?)
+void SocketPoll::clientRequestWebsocketUpgrade(const std::shared_ptr<StreamSocket>& socket,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler,
+ const std::string &pathAndQuery)
+{
+ // cf. WebSocketHandler::upgradeToWebSocket (?)
+ // send Sec-WebSocket-Key: <hmm> ... Sec-WebSocket-Protocol: chat, Sec-WebSocket-Version: 13
+
+ LOG_TRC("Requesting upgrade of websocket at path " << pathAndQuery << " #" << socket->getFD());
+
+ std::ostringstream oss;
+ oss << "GET " << pathAndQuery << " HTTP/1.1\r\n"
+ "Connection:Upgrade\r\n"
+ "User-Foo: Adminbits\r\n"
+ "Sec-WebSocket-Key:fxTaWTEMVhq1PkWsMoLxGw==\r\n"
+ "Upgrade:websocket\r\n"
+ "Accept-Language:en\r\n"
+ "Cache-Control:no-cache\r\n"
+ "Pragma:no-cache\r\n"
+ "Sec-WebSocket-Version:13\r\n"
+ "User-Agent: " << WOPI_AGENT_STRING << "\r\n"
+ "\r\n";
+ socket->send(oss.str());
+ websocketHandler->onConnect(socket);
+}
+
+void SocketPoll::insertNewUnixSocket(
+ const std::string &location,
+ const std::string &pathAndQuery,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
+{
+ int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
+
+ struct sockaddr_un addrunix;
+ std::memset(&addrunix, 0, sizeof(addrunix));
+ addrunix.sun_family = AF_UNIX;
+ addrunix.sun_path[0] = '\0'; // abstract name
+ memcpy(&addrunix.sun_path[1], location.c_str(), location.length());
+
+ int res = connect(fd, (const struct sockaddr *)&addrunix, sizeof(addrunix));
+ if (fd < 0 || (res < 0 && errno != EINPROGRESS))
+ {
+ LOG_ERR("Failed to connect to unix socket at " << location);
+ ::close(fd);
+ }
+ else
+ {
+ std::shared_ptr<StreamSocket> socket;
+ socket = StreamSocket::create<StreamSocket>(fd, true, websocketHandler);
+ if (socket)
+ {
+ LOG_DBG("Connected to local UDS " << location << " #" << socket->getFD());
+ clientRequestWebsocketUpgrade(socket, websocketHandler, pathAndQuery);
+ insertNewSocket(socket);
+ }
+ }
+}
+
+#ifdef MOBILEAPP
+void SocketPoll::insertNewFakeSocket(
+ int peerSocket,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler)
+{
LOG_INF("Connecting to " << peerSocket);
int fd = fakeSocketSocket();
int res = fakeSocketConnect(fd, peerSocket);
@@ -307,8 +359,8 @@ void SocketPoll::insertNewWebSocketSync(
fakeSocketClose(fd);
}
}
-#endif
}
+#endif
void ServerSocket::dumpState(std::ostream& os)
{
@@ -390,6 +442,7 @@ bool ServerSocket::bind(Type type, int port)
int rc;
+ assert (_type != Socket::Type::Unix);
if (_type == Socket::Type::IPv4)
{
struct sockaddr_in addrv4;
@@ -430,6 +483,33 @@ bool ServerSocket::bind(Type type, int port)
#endif
}
+/// Returns true on success only.
+std::string LocalServerSocket::bind()
+{
+#ifndef MOBILEAPP
+ int rc;
+ struct sockaddr_un addrunix;
+ do
+ {
+ std::memset(&addrunix, 0, sizeof(addrunix));
+ addrunix.sun_family = AF_UNIX;
+ std::memcpy(addrunix.sun_path, SOCKET_ABSTRACT_UNIX_NAME, sizeof(SOCKET_ABSTRACT_UNIX_NAME));
+ addrunix.sun_path[0] = '\0'; // abstract name
+
+ std::string rand = Util::rng::getFilename(8);
+ memcpy(addrunix.sun_path + sizeof(SOCKET_ABSTRACT_UNIX_NAME) - 1, rand.c_str(), 8);
+
+ rc = ::bind(getFD(), (const sockaddr *)&addrunix, sizeof(struct sockaddr_un));
+ LOG_TRC("Bind to location " << std::string(&addrunix.sun_path[1]) <<
+ " result - " << rc << "errno: " << ((rc >= 0) ? "no error" : ::strerror(errno)));
+ } while (rc < 0 && errno == EADDRINUSE);
+
+ if (rc >= 0)
+ return std::string(&addrunix.sun_path[1]);
+#endif
+ return "";
+}
+
#ifndef MOBILEAPP
bool StreamSocket::parseHeader(const char *clientName,
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 41c15c3b9..f282266be 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -101,7 +101,7 @@ public:
static const int MaximumSendBufferSize = 128 * 1024;
static std::atomic<bool> InhibitThreadChecks;
- enum Type { IPv4, IPv6, All };
+ enum Type { IPv4, IPv6, All, Unix };
Socket(Type type) :
_fd(createSocket(type)),
@@ -643,15 +643,21 @@ public:
}
}
- /// Inserts a new websocket to be polled.
- /// NOTE: The DNS lookup is synchronous.
- void insertNewWebSocketSync(
#ifndef MOBILEAPP
- const Poco::URI &uri,
+ /// Inserts a new remote websocket to be polled.
+ /// NOTE: The DNS lookup is synchronous.
+ void insertNewWebSocketSync(const Poco::URI &uri,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
+
+ void insertNewUnixSocket(
+ const std::string &location,
+ const std::string &pathAndQuery,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
#else
- int peerSocket,
+ void insertNewFakeSocket(
+ int peerSocket,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
#endif
- const std::shared_ptr<SocketHandlerInterface>& websocketHandler);
typedef std::function<void()> CallbackFn;
@@ -719,6 +725,11 @@ protected:
}
private:
+ /// Generate the request to connect & upgrade this socket to a given path
+ void clientRequestWebsocketUpgrade(const std::shared_ptr<StreamSocket>& socket,
+ const std::shared_ptr<SocketHandlerInterface>& websocketHandler,
+ const std::string &pathAndQuery);
+
/// Initialize the poll fds array with the right events
void setupPollFds(std::chrono::steady_clock::time_point now,
int &timeoutMaxMs)
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 574b54bd1..5f2b5a4c5 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -186,8 +186,10 @@ Socket::Type ClientPortProto = Socket::Type::All;
/// INET address to listen on
ServerSocket::Type ClientListenAddr = ServerSocket::Type::Public;
-/// Port for prisoners to connect to
-int MasterPortNumber = DEFAULT_MASTER_PORT_NUMBER;
+#ifndef MOBILEAPP
+/// UDS address for kits to connect to.
+std::string MasterLocation;
+#endif
// Tracks the set of prisoners / children waiting to be used.
static std::mutex NewChildrenMutex;
@@ -1277,8 +1279,7 @@ void LOOLWSD::defineOptions(OptionSet& optionSet)
.repeatable(false));
optionSet.addOption(Option("port", "", "Port number to listen to (default: " +
- std::to_string(DEFAULT_CLIENT_PORT_NUMBER) + "),"
- " must not be " + std::to_string(MasterPortNumber) + ".")
+ std::to_string(DEFAULT_CLIENT_PORT_NUMBER) + "),")
.required(false)
.repeatable(false)
.argument("port_number"));
@@ -1364,10 +1365,6 @@ void LOOLWSD::handleOption(const std::string& optionName,
if (clientPort)
ClientPortNumber = std::stoi(clientPort);
- static const char* masterPort = std::getenv("LOOL_TEST_MASTER_PORT");
- if (masterPort)
- MasterPortNumber = std::stoi(masterPort);
-
static const char* latencyMs = std::getenv("LOOL_DELAY_SOCKET_MS");
if (latencyMs)
SimulatedLatencyMs = std::stoi(latencyMs);
@@ -1578,7 +1575,7 @@ bool LOOLWSD::createForKit()
args.push_back("--lotemplate=" + LoTemplate);
args.push_back("--childroot=" + ChildRoot);
args.push_back("--clientport=" + std::to_string(ClientPortNumber));
- args.push_back("--masterport=" + std::to_string(MasterPortNumber));
+ args.push_back("--masterport=" + MasterLocation);
const DocProcSettings& docProcSettings = Admin::instance().getDefDocProcSettings();
std::ostringstream ossRLimits;
@@ -2893,10 +2890,10 @@ public:
stop();
}
- void startPrisoners(int& port)
+ void startPrisoners()
{
PrisonerPoll.startThread();
- PrisonerPoll.insertNewSocket(findPrisonerServerPort(port));
+ PrisonerPoll.insertNewSocket(findPrisonerServerPort());
}
void stopPrisoners()
@@ -2935,7 +2932,7 @@ public:
os << "LOOLWSDServer:\n"
<< " Ports: server " << ClientPortNumber
- << " prisoner " << MasterPortNumber << "\n"
+ << " prisoner " << MasterLocation << "\n"
<< " SSL: " << (LOOLWSD::isSSLEnabled() ? "https" : "http") << "\n"
<< " SSL-Termination: " << (LOOLWSD::isSSLTermination() ? "yes" : "no") << "\n"
<< " Security " << (LOOLWSD::NoCapsForKit ? "no" : "") << " chroot, "
@@ -2997,8 +2994,7 @@ private:
const std::shared_ptr<SocketFactory>& factory)
{
auto serverSocket = std::make_shared<ServerSocket>(
- type == ServerSocket::Type::Local ? Socket::Type::IPv4 : ClientPortProto,
- clientSocket, factory);
+ ClientPortProto, clientSocket, factory);
if (!serverSocket->bind(type, port))
return nullptr;
@@ -3010,35 +3006,37 @@ private:
}
/// Create the internal only, local socket for forkit / kits prisoners to talk to.
- std::shared_ptr<ServerSocket> findPrisonerServerPort(int& port)
+ std::shared_ptr<ServerSocket> findPrisonerServerPort()
{
std::shared_ptr<SocketFactory> factory = std::make_shared<PrisonerSocketFactory>();
- std::shared_ptr<ServerSocket> socket = getServerSocket(
- ServerSocket::Type::Local, port, PrisonerPoll, factory);
+#ifndef MOBILEAPP
+ std::string location;
+ auto socket = std::make_shared<LocalServerSocket>(PrisonerPoll, factory);;
-#ifdef BUILDING_TESTS
- // If we fail, try the next 100 ports.
- for (int i = 0; i < 100 && !socket; ++i)
+ location = socket->bind();
+ if (!location.length())
{
- ++port;
- LOG_INF("Prisoner port " << (port - 1) << " is busy, trying " << port << ".");
- socket = getServerSocket(
- ServerSocket::Type::Local, port, PrisonerPoll, factory);
+ LOG_FTL("Failed to create local unix domain socket. Exiting.");
+ Log::shutdown();
+ _exit(Application::EXIT_SOFTWARE);
+ return nullptr;
}
-#endif
- if (!socket)
+ if (!socket->listen())
{
- LOG_FTL("Failed to listen on Prisoner port(s) (" <<
- MasterPortNumber << '-' << port << "). Exiting.");
+ LOG_FTL("Failed to listen on local unix domain socket at " << location << ". Exiting.");
Log::shutdown();
_exit(Application::EXIT_SOFTWARE);
}
- MasterPortNumber = port;
-#ifndef MOBILEAPP
- LOG_INF("Listening to prisoner connections on port " << port);
+ LOG_INF("Listening to prisoner connections on " << location);
+ MasterLocation = location;
#else
+ // TESTME ...
+ constexpr int DEFAULT_MASTER_PORT_NUMBER = 9981;
+ std::shared_ptr<ServerSocket> socket = getServerSocket(
+ ServerSocket::Type::Public, DEFAULT_MASTER_PORT_NUMBER, PrisonerPoll, factory);
+
LOOLWSD::prisonerServerSocketFD = socket->getFD();
LOG_INF("Listening to prisoner connections on #" << LOOLWSD::prisonerServerSocketFD);
#endif
@@ -3064,8 +3062,7 @@ private:
{
++port;
LOG_INF("Client port " << (port - 1) << " is busy, trying " << port << ".");
- socket = getServerSocket(
- ServerSocket::Type::Public, port, WebServerPoll, factory);
+ socket = getServerSocket(port, WebServerPoll, factory);
}
#endif
@@ -3156,16 +3153,13 @@ int LOOLWSD::innerMain()
FileServerRoot = Poco::Path(Application::instance().commandPath()).parent().toString();
FileServerRoot = Poco::Path(FileServerRoot).absolute().toString();
LOG_DBG("FileServerRoot: " << FileServerRoot);
-
- if (ClientPortNumber == MasterPortNumber)
- throw IncompatibleOptionsException("port");
#endif
ClientRequestDispatcher::InitStaticFileContentCache();
// Start the internal prisoner server and spawn forkit,
// which in turn forks first child.
- srv.startPrisoners(MasterPortNumber);
+ srv.startPrisoners();
// No need to "have at least one child" beforehand on mobile
#ifndef MOBILEAPP
More information about the Libreoffice-commits
mailing list