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.nakash...@collabora.co.uk>
AuthorDate: Mon Apr 22 12:03:49 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@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.nakash...@collabora.co.uk>
AuthorDate: Mon Apr 22 12:00:19 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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.nakash...@collabora.co.uk>
AuthorDate: Sat Apr 20 14:58:48 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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.nakash...@collabora.co.uk>
AuthorDate: Sat Apr 20 14:10:38 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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.nakash...@collabora.co.uk>
AuthorDate: Sat Apr 20 11:39:20 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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.nakash...@collabora.co.uk>
AuthorDate: Sat Apr 20 15:23:32 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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.nakash...@collabora.co.uk>
AuthorDate: Fri Apr 19 20:09:22 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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.nakash...@collabora.co.uk>
AuthorDate: Fri Apr 19 20:06:27 2019 -0400
Commit:     Michael Meeks <michael.me...@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 <ashnak...@gmail.com>
    Tested-by: Ashod Nakashian <ashnak...@gmail.com>
    Signed-off-by: Michael Meeks <michael.me...@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 <hcas...@collabora.com>
AuthorDate: Tue Apr 2 10:26:02 2019 -0400
Commit:     Michael Meeks <michael.me...@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.mehrbr...@cib.de>
AuthorDate: Mon Apr 1 14:18:23 2019 +0200
Commit:     Michael Meeks <michael.me...@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 <vmik...@collabora.com>
AuthorDate: Mon Apr 1 12:00:27 2019 +0200
Commit:     Michael Meeks <michael.me...@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.me...@collabora.com>
AuthorDate: Mon Apr 1 10:56:15 2019 +0100
Commit:     Michael Meeks <michael.me...@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.me...@collabora.com>
AuthorDate: Sat Mar 30 21:07:58 2019 +0000
Commit:     Michael Meeks <michael.me...@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.me...@collabora.com>
AuthorDate: Sat Mar 30 14:06:16 2019 +0000
Commit:     Michael Meeks <michael.me...@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
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to