[Libreoffice-commits] online.git: common/Util.hpp kit/Kit.cpp net/Socket.hpp net/SslSocket.hpp net/WebSocketHandler.hpp wsd/Admin.cpp wsd/Admin.hpp wsd/AdminModel.cpp wsd/AdminModel.hpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp

Gabriel Masei (via logerrit) logerrit at kemper.freedesktop.org
Sat Apr 25 07:11:54 UTC 2020


 common/Util.hpp          |    4 +
 kit/Kit.cpp              |   28 ++++++-----
 net/Socket.hpp           |  113 +++++++++++++++++++++++++++++++++++++++++++++--
 net/SslSocket.hpp        |    5 +-
 net/WebSocketHandler.hpp |   66 +++++++++++++++++++++------
 wsd/Admin.cpp            |    9 ++-
 wsd/Admin.hpp            |    2 
 wsd/AdminModel.cpp       |   42 ++++++++---------
 wsd/AdminModel.hpp       |   19 ++++++-
 wsd/DocumentBroker.cpp   |   11 ++--
 wsd/DocumentBroker.hpp   |    8 ++-
 wsd/LOOLWSD.cpp          |    3 -
 12 files changed, 239 insertions(+), 71 deletions(-)

New commits:
commit 6b486f229a68cf9ee1641e14c82b0de4c64b1fe2
Author:     Gabriel Masei <gabriel.masei at 1and1.ro>
AuthorDate: Thu Apr 23 13:35:42 2020 +0300
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 25 09:11:35 2020 +0200

    wsd: admin: move kit memory reporting from kit to admin module
    
    Sometimes kit process goes into a heavy processing state (or even hangs)
    and is not able to report its memory usage. Thus we can't implement cleanup
    of problematic kit processes based on memory information reported by kit.
    By moving memory reporting to admin module we avoid this problem.
    
    Change-Id: Icf274e3a3a97b33623a93f9d2dc1e640ad9b7d99
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/92752
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/common/Util.hpp b/common/Util.hpp
index 820f4e6ce..d154942f8 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -144,6 +144,10 @@ namespace Util
     /// Example: "procmemstats: pid=123 rss=12400 pss=566"
     std::string getMemoryStats(FILE* file);
 
+    /// Reads from SMaps file Pss and Private_Dirty values and
+    /// returns them as a pair in the same order
+    std::pair<size_t, size_t> getPssAndDirtyFromSMaps(FILE* file);
+
     size_t getCpuUsage(const Poco::Process::PID pid);
 
     size_t getStatFromPid(const Poco::Process::PID pid, int ind);
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index ad37d3a2e..8cd62f43b 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -796,8 +796,20 @@ public:
         assert(_loKit);
 
 #if !MOBILEAPP
-        _lastMemStatsTime = std::chrono::steady_clock::now();
-        sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
+        if (ProcSMapsFile)
+        {
+            static const std::string str = "smapsfd:";
+            if (websocketHandler->sendTextMessageWithFD(str.c_str(), str.size(), ProcSMapsFile->_fileno) > 0)
+            {
+                LOG_DBG("Successfully sent smaps fd to wsd");
+                fclose(ProcSMapsFile);
+                ProcSMapsFile = nullptr;
+            }
+            else
+            {
+                LOG_ERR("Failed to send smaps fd to wsd");
+            }
+        }
 #endif
     }
 
@@ -1935,7 +1947,7 @@ private:
     }
 
 public:
-    void drainQueue(const std::chrono::steady_clock::time_point &now)
+    void drainQueue(const std::chrono::steady_clock::time_point &/*now*/)
     {
         try
         {
@@ -2045,16 +2057,6 @@ public:
                 }
             }
 
-#if !MOBILEAPP
-            std::chrono::milliseconds::rep durationMs =
-                std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastMemStatsTime).count();
-            // Update memory stats and editor every 5 seconds.
-            if (durationMs > 5000)
-            {
-                sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
-                _lastMemStatsTime = std::chrono::steady_clock::now();
-            }
-#endif
         }
         catch (const std::exception& exc)
         {
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 5966b1047..218de2866 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -758,9 +758,16 @@ class StreamSocket : public Socket,
                      public std::enable_shared_from_this<StreamSocket>
 {
 public:
+    enum ReadType
+    {
+        NormalRead,
+        UseRecvmsgExpectFD
+    };
+
     /// Create a StreamSocket from native FD.
     StreamSocket(const int fd, bool /* isClient */,
-                 std::shared_ptr<ProtocolHandlerInterface> socketHandler) :
+                 std::shared_ptr<ProtocolHandlerInterface> socketHandler,
+                 ReadType readType = NormalRead) :
         Socket(fd),
         _socketHandler(std::move(socketHandler)),
         _bytesSent(0),
@@ -768,7 +775,9 @@ public:
         _wsState(WSState::HTTP),
         _closed(false),
         _sentHTTPContinue(false),
-        _shutdownSignalled(false)
+        _shutdownSignalled(false),
+        _incomingFD(-1),
+        _readType(readType)
     {
         LOG_DBG("StreamSocket ctor #" << fd);
 
@@ -845,6 +854,45 @@ public:
     /// Adds Date and User-Agent.
     void send(Poco::Net::HTTPResponse& response);
 
+    /// Sends data with file descriptor as control data.
+    /// Can be used only with Unix sockets.
+    void sendFD(const char* data, const uint64_t len, int fd)
+    {
+        assertCorrectThread();
+
+        // Flush existing non-ancillary data
+        // so that our non-ancillary data will
+        // match ancillary data.
+        if (getOutBuffer().size() > 0)
+        {
+            writeOutgoingData();
+        }
+
+        msghdr msg;
+        iovec iov[1];
+
+        iov[0].iov_base = const_cast<char*>(data);
+        iov[0].iov_len = len;
+
+        msg.msg_name = nullptr;
+        msg.msg_namelen = 0;
+        msg.msg_iov = &iov[0];
+        msg.msg_iovlen = 1;
+
+        char adata[CMSG_SPACE(sizeof(int))];
+        cmsghdr *cmsg = (cmsghdr*)adata;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+        *(int *)CMSG_DATA(cmsg) = fd;
+
+        msg.msg_control = const_cast<char*>(adata);
+        msg.msg_controllen = CMSG_LEN(sizeof(int));
+        msg.msg_flags = 0;
+
+        sendmsg(getFD(), &msg, 0);
+    }
+
     /// Reads data by invoking readData() and buffering.
     /// Return false iff the socket is closed.
     virtual bool readIncomingData()
@@ -908,10 +956,12 @@ public:
     /// but we can't have a shared_ptr in the ctor.
     template <typename TSocket>
     static
-    std::shared_ptr<TSocket> create(const int fd, bool isClient, std::shared_ptr<ProtocolHandlerInterface> handler)
+    std::shared_ptr<TSocket> create(const int fd, bool isClient,
+                                    std::shared_ptr<ProtocolHandlerInterface> handler,
+                                    ReadType readType = NormalRead)
     {
         ProtocolHandlerInterface* pHandler = handler.get();
-        auto socket = std::make_shared<TSocket>(fd, isClient, std::move(handler));
+        auto socket = std::make_shared<TSocket>(fd, isClient, std::move(handler), readType);
         pHandler->onConnect(socket);
         return socket;
     }
@@ -972,6 +1022,11 @@ public:
         return _outBuffer;
     }
 
+    int getIncomingFD()
+    {
+        return _incomingFD;
+    }
+
 protected:
 
     std::vector<std::pair<size_t, size_t>> findChunks(Poco::Net::HTTPRequest &request);
@@ -1099,11 +1154,59 @@ public:
     void dumpState(std::ostream& os) override;
 
 protected:
+    /// Reads data with file descriptor as control data if received.
+    /// Can be used only with Unix sockets.
+    int readFD(char* buf, int len, int& fd)
+    {
+        msghdr msg;
+        iovec iov[1];
+        /// We don't expect more than one FD
+        char ctrl[CMSG_SPACE(sizeof(int))];
+        int ctrlLen = sizeof(ctrl);
+
+        iov[0].iov_base = buf;
+        iov[0].iov_len = len;
+
+        msg.msg_name = nullptr;
+        msg.msg_namelen = 0;
+        msg.msg_iov = &iov[0];
+        msg.msg_iovlen = 1;
+        msg.msg_control = ctrl;
+        msg.msg_controllen = ctrlLen;
+        msg.msg_flags = 0;
+
+        int ret = recvmsg(getFD(), &msg, 0);
+        if (ret >= 0)
+        {
+            if (msg.msg_controllen)
+            {
+                cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+                if (cmsg && cmsg->cmsg_type == SCM_RIGHTS && cmsg->cmsg_len == CMSG_LEN(sizeof(int)))
+                {
+                    fd = *(int*)CMSG_DATA(cmsg);
+                    if (_readType == UseRecvmsgExpectFD)
+                    {
+                        _readType = NormalRead;
+                    }
+                }
+            }
+        }
+        else
+        {
+            LOG_ERR("recvmsg call ended with error: " << errno);
+        }
+
+        return ret;
+    }
+
     /// Override to handle reading of socket data differently.
     virtual int readData(char* buf, int len)
     {
         assertCorrectThread();
 #if !MOBILEAPP
+        if (_readType == UseRecvmsgExpectFD)
+            return readFD(buf, len, _incomingFD);
+
         return ::read(getFD(), buf, len);
 #else
         return fakeSocketRead(getFD(), buf, len);
@@ -1156,6 +1259,8 @@ protected:
 
     /// True when shutdown was requested via shutdown().
     bool _shutdownSignalled;
+    int _incomingFD;
+    ReadType _readType;
 };
 
 enum class WSOpCode : unsigned char {
diff --git a/net/SslSocket.hpp b/net/SslSocket.hpp
index 508cecece..e883d0029 100644
--- a/net/SslSocket.hpp
+++ b/net/SslSocket.hpp
@@ -19,8 +19,9 @@ class SslStreamSocket final : public StreamSocket
 {
 public:
     SslStreamSocket(const int fd, bool isClient,
-                    std::shared_ptr<ProtocolHandlerInterface> responseClient) :
-        StreamSocket(fd, isClient, std::move(responseClient)),
+                    std::shared_ptr<ProtocolHandlerInterface> responseClient,
+                    ReadType readType = NormalRead) :
+        StreamSocket(fd, isClient, std::move(responseClient), readType),
         _bio(nullptr),
         _ssl(nullptr),
         _sslWantsTo(SslWantsTo::Neither),
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index a329e7711..9fb8682ac 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -545,26 +545,42 @@ public:
         std::shared_ptr<StreamSocket> socket = _socket.lock();
         return sendFrame(socket, data, len, WSFrameMask::Fin | static_cast<unsigned char>(code), flush);
     }
-private:
-    /// Sends a WebSocket frame given the data, length, and flags.
-    /// Returns the number of bytes written (including frame overhead) on success,
-    /// 0 for closed/invalid socket, and -1 for other errors.
-    int sendFrame(const std::shared_ptr<StreamSocket>& socket,
-                  const char* data, const uint64_t len,
-                  unsigned char flags, const bool flush = true) const
+
+#if !MOBILEAPP
+    /// Sends a message while giving at the same time the rights
+    /// for file descriptor to the receiving process.
+    /// DO NOT USE IT unless you have no other option.
+    int sendTextMessageWithFD(const char* msg, size_t len, int fd)
     {
-        if (!socket || data == nullptr || len == 0)
+        std::shared_ptr<StreamSocket> socket = _socket.lock();
+
+        if (!socket || msg == nullptr || len == 0)
             return -1;
 
         if (socket->isClosed())
             return 0;
 
         socket->assertCorrectThread();
-        std::vector<char>& out = socket->getOutBuffer();
 
-#if !MOBILEAPP
-        const size_t oldSize = out.size();
+        std::vector<char> out;
 
+        buildFrame(msg, len, WSFrameMask::Fin | static_cast<char>(WSOpCode::Text), out);
+
+        const size_t size = out.size();
+
+        socket->sendFD(out.data(), out.size(), fd);
+
+        return size;
+    }
+#endif
+
+protected:
+
+#if !MOBILEAPP
+    /// Builds a websocket frame based on data and flags received as parameters.
+    /// The frame is output in 'out' parameter
+    void buildFrame(const char* data, const uint64_t len, unsigned char flags, std::vector<char>& out) const
+    {
         out.push_back(flags);
 
         int maskFlag = _isMasking ? 0x80 : 0;
@@ -612,6 +628,30 @@ private:
             // Copy the data.
             out.insert(out.end(), data, data + len);
         }
+    }
+#endif
+
+    /// Sends a WebSocket frame given the data, length, and flags.
+    /// Returns the number of bytes written (including frame overhead) on success,
+    /// 0 for closed/invalid socket, and -1 for other errors.
+    int sendFrame(const std::shared_ptr<StreamSocket>& socket,
+                  const char* data, const uint64_t len,
+                  unsigned char flags, const bool flush = true) const
+    {
+        if (!socket || data == nullptr || len == 0)
+            return -1;
+
+        if (socket->isClosed())
+            return 0;
+
+        socket->assertCorrectThread();
+        std::vector<char>& out = socket->getOutBuffer();
+
+#if !MOBILEAPP
+        const size_t oldSize = out.size();
+
+        buildFrame(data, len, flags, out);
+
         const size_t size = out.size() - oldSize;
 
         if (flush)
@@ -632,8 +672,6 @@ private:
         return size;
     }
 
-protected:
-
     bool isControlFrame(WSOpCode code){ return code >= WSOpCode::Close; }
 
     void readPayload(unsigned char *data, size_t dataLen, unsigned char* mask, std::vector<char>& payload)
@@ -663,7 +701,7 @@ protected:
             _msgHandler->handleMessage(data);
     }
 
-    std::weak_ptr<StreamSocket>& getSocket()
+    const std::weak_ptr<StreamSocket>& getSocket() const
     {
         return _socket;
     }
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index f5a3d80a4..0af46c8ad 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -572,10 +572,6 @@ void Admin::updateLastActivityTime(const std::string& docKey)
     addCallback([=]{ _model.updateLastActivityTime(docKey); });
 }
 
-void Admin::updateMemoryDirty(const std::string& docKey, int dirty)
-{
-    addCallback([=] { _model.updateMemoryDirty(docKey, dirty); });
-}
 
 void Admin::addBytes(const std::string& docKey, uint64_t sent, uint64_t recv)
 {
@@ -597,6 +593,11 @@ void Admin::setDocWopiUploadDuration(const std::string& docKey, const std::chron
     addCallback([=]{ _model.setDocWopiUploadDuration(docKey, uploadDuration); });
 }
 
+void Admin::setDocProcSMapsFD(const std::string& docKey, const int smapsFD)
+{
+    addCallback([=]{ _model.setDocProcSMapsFD(docKey, smapsFD); });
+}
+
 void Admin::addSegFaultCount(unsigned segFaultCount)
 {
     addCallback([=]{ _model.addSegFaultCount(segFaultCount); });
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index 32b2ebeab..9dc015596 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -108,7 +108,6 @@ public:
     void rescheduleCpuTimer(unsigned interval);
 
     void updateLastActivityTime(const std::string& docKey);
-    void updateMemoryDirty(const std::string& docKey, int dirty);
     void addBytes(const std::string& docKey, uint64_t sent, uint64_t recv);
 
     void dumpState(std::ostream& os) override;
@@ -130,6 +129,7 @@ public:
     void setViewLoadDuration(const std::string& docKey, const std::string& sessionId, std::chrono::milliseconds viewLoadDuration);
     void setDocWopiDownloadDuration(const std::string& docKey, std::chrono::milliseconds wopiDownloadDuration);
     void setDocWopiUploadDuration(const std::string& docKey, const std::chrono::milliseconds uploadDuration);
+    void setDocProcSMapsFD(const std::string& docKey, const int smapsFD);
     void addSegFaultCount(unsigned segFaultCount);
 
     void getMetrics(std::ostringstream &metrics);
diff --git a/wsd/AdminModel.cpp b/wsd/AdminModel.cpp
index 0a69e9891..e2ba77898 100644
--- a/wsd/AdminModel.cpp
+++ b/wsd/AdminModel.cpp
@@ -135,6 +135,18 @@ std::string Document::to_string() const
     return oss.str();
 }
 
+int Document::getMemoryDirty() const
+{
+    // Avoid accessing smaps too often
+    const time_t now = std::time(nullptr);
+    if (now - _lastTimeSMapsRead >= 5)
+    {
+        _memoryDirty = _procSMaps  ? Util::getPssAndDirtyFromSMaps(_procSMaps).second : 0;
+        _lastTimeSMapsRead = now;
+    }
+    return _memoryDirty;
+}
+
 bool Subscriber::notify(const std::string& message)
 {
     // If there is no socket, then return false to
@@ -736,27 +748,6 @@ void AdminModel::updateLastActivityTime(const std::string& docKey)
     }
 }
 
-bool Document::updateMemoryDirty(int dirty)
-{
-    if (_memoryDirty == dirty)
-        return false;
-    _memoryDirty = dirty;
-    return true;
-}
-
-void AdminModel::updateMemoryDirty(const std::string& docKey, int dirty)
-{
-    assertCorrectThread();
-
-    auto docIt = _documents.find(docKey);
-    if (docIt != _documents.end() &&
-        docIt->second->updateMemoryDirty(dirty))
-    {
-        notify("propchange " + std::to_string(docIt->second->getPid()) +
-               " mem " + std::to_string(dirty));
-    }
-}
-
 double AdminModel::getServerUptime()
 {
     auto currentTime = std::chrono::system_clock::now();
@@ -785,6 +776,13 @@ void AdminModel::setDocWopiUploadDuration(const std::string& docKey, const std::
         it->second->setWopiUploadDuration(wopiUploadDuration);
 }
 
+void AdminModel::setDocProcSMapsFD(const std::string& docKey, const int smapsFD)
+{
+    auto it = _documents.find(docKey);
+    if (it != _documents.end())
+        it->second->setProcSMapsFD(smapsFD);
+}
+
 void AdminModel::addSegFaultCount(unsigned segFaultCount)
 {
     _segFaultCount += segFaultCount;
@@ -971,7 +969,7 @@ void CalcKitStats(KitProcStats& stats)
 {
     std::vector<int> childProcs;
     stats.unassignedCount = AdminModel::getPidsFromProcName(std::regex("kit_spare_[0-9]*"), &childProcs);
-    stats.assignedCount = AdminModel::getPidsFromProcName(std::regex("kitbroker_[0-9]*"), &childProcs);
+    stats.assignedCount = AdminModel::getPidsFromProcName(std::regex("kit_[0-9]*"), &childProcs);
     for (int& pid : childProcs)
     {
         stats.UpdateAggregateStats(pid);
diff --git a/wsd/AdminModel.hpp b/wsd/AdminModel.hpp
index 30f00e843..15afb344a 100644
--- a/wsd/AdminModel.hpp
+++ b/wsd/AdminModel.hpp
@@ -121,10 +121,18 @@ public:
           _recvBytes(0),
           _wopiDownloadDuration(0),
           _wopiUploadDuration(0),
+          _procSMaps(nullptr),
+          _lastTimeSMapsRead(0),
           _isModified(false)
     {
     }
 
+    ~Document()
+    {
+        if (_procSMaps)
+            fclose(_procSMaps);
+    }
+
     const std::string getDocKey() const { return _docKey; }
 
     Poco::Process::PID getPid() const { return _pid; }
@@ -149,8 +157,7 @@ public:
     const std::map<std::string, View>& getViews() const { return _views; }
 
     void updateLastActivityTime() { _lastActivity = std::time(nullptr); }
-    bool updateMemoryDirty(int dirty);
-    int getMemoryDirty() const { return _memoryDirty; }
+    int getMemoryDirty() const;
 
     std::pair<std::time_t, std::string> getSnapshot() const;
     const std::string getHistory() const;
@@ -176,6 +183,7 @@ public:
     std::chrono::milliseconds getWopiDownloadDuration() const { return _wopiDownloadDuration; }
     void setWopiUploadDuration(const std::chrono::milliseconds wopiUploadDuration) { _wopiUploadDuration = wopiUploadDuration; }
     std::chrono::milliseconds getWopiUploadDuration() const { return _wopiUploadDuration; }
+    void setProcSMapsFD(const int smapsFD) { _procSMaps = fdopen(smapsFD, "r"); }
 
     std::string to_string() const;
 
@@ -189,7 +197,7 @@ private:
     /// Hosted filename
     std::string _filename;
     /// The dirty (ie. un-shared) memory of the document's Kit process.
-    int _memoryDirty;
+    mutable int _memoryDirty;
     /// Last noted Jiffy count
     unsigned _lastJiffy;
 
@@ -205,6 +213,9 @@ private:
     std::chrono::milliseconds _wopiDownloadDuration;
     std::chrono::milliseconds _wopiUploadDuration;
 
+    FILE* _procSMaps;
+    mutable std::time_t _lastTimeSMapsRead;
+
     /// Per-doc kit process settings.
     DocProcSettings _docProcSettings;
     bool _isModified;
@@ -306,7 +317,6 @@ public:
     void removeDocument(const std::string& docKey);
 
     void updateLastActivityTime(const std::string& docKey);
-    void updateMemoryDirty(const std::string& docKey, int dirty);
 
     void addBytes(const std::string& docKey, uint64_t sent, uint64_t recv);
 
@@ -321,6 +331,7 @@ public:
     void setViewLoadDuration(const std::string& docKey, const std::string& sessionId, std::chrono::milliseconds viewLoadDuration);
     void setDocWopiDownloadDuration(const std::string& docKey, std::chrono::milliseconds wopiDownloadDuration);
     void setDocWopiUploadDuration(const std::string& docKey, const std::chrono::milliseconds wopiUploadDuration);
+    void setDocProcSMapsFD(const std::string& docKey, const int smapsFD);
     void addSegFaultCount(unsigned segFaultCount);
     void setForKitPid(pid_t pid) { _forKitPid = pid; }
 
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index f79cbbbd4..cb4685544 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1593,13 +1593,14 @@ bool DocumentBroker::handleInput(const std::vector<char>& payload)
             Util::alertAllUsers(cmd, kind);
         }
 #if !MOBILEAPP
-        else if (command == "procmemstats:")
+        else if (command == "smapsfd:")
         {
-            int dirty;
-            if (message->getTokenInteger("dirty", dirty))
+            std::shared_ptr<StreamSocket> socket = std::static_pointer_cast<StreamSocket>(_childProcess->_socket);
+            if (socket)
             {
-                Admin::instance().updateMemoryDirty(
-                    _docKey, dirty + getMemorySize()/1024);
+                _childProcess->setSMapsFD(socket->getIncomingFD());
+                Admin::instance().setDocProcSMapsFD(_docKey, _childProcess->getSMapsFD());
+                LOG_DBG("Received smaps fd");
             }
         }
 #endif
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 6e265c3dc..49bed8cbf 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -73,22 +73,28 @@ public:
                  const Poco::Net::HTTPRequest &request) :
 
         WSProcess("ChildProcess", pid, socket, std::make_shared<WebSocketHandler>(socket, request)),
-        _jailId(jailId)
+        _jailId(jailId),
+        _smapsFD(-1)
     {
     }
 
 
     ChildProcess(ChildProcess&& other) = delete;
 
+    virtual ~ChildProcess(){ ::close(_smapsFD); }
+
     const ChildProcess& operator=(ChildProcess&& other) = delete;
 
     void setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker);
     std::shared_ptr<DocumentBroker> getDocumentBroker() const { return _docBroker.lock(); }
     const std::string& getJailId() const { return _jailId; }
+    void setSMapsFD(int smapsFD) { _smapsFD = smapsFD;}
+    int getSMapsFD(){ return _smapsFD; }
 
 private:
     const std::string _jailId;
     std::weak_ptr<DocumentBroker> _docBroker;
+    int _smapsFD;
 };
 
 class ClientSession;
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 7302b3c6c..29d4b31cb 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -3321,7 +3321,8 @@ class PrisonerSocketFactory final : public SocketFactory
     std::shared_ptr<Socket> create(const int fd) override
     {
         // No local delay.
-        return StreamSocket::create<StreamSocket>(fd, false, std::make_shared<PrisonerRequestDispatcher>());
+        return StreamSocket::create<StreamSocket>(fd, false, std::make_shared<PrisonerRequestDispatcher>(),
+                                                  StreamSocket::ReadType::UseRecvmsgExpectFD);
     }
 };
 


More information about the Libreoffice-commits mailing list