[Libreoffice-commits] online.git: 2 commits - Makefile.am test/helpers.hpp tools/Replay.hpp tools/Stress.cpp wsd/LOOLWSD.cpp wsd/LOOLWSD.hpp wsd/TraceFile.hpp

Jan Holesovsky kendy at collabora.com
Wed Feb 8 07:41:11 UTC 2017


 Makefile.am       |    2 
 test/helpers.hpp  |    5 +
 tools/Replay.hpp  |  245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/Stress.cpp  |  198 +------------------------------------------
 wsd/LOOLWSD.cpp   |   48 ++++++++++
 wsd/LOOLWSD.hpp   |    1 
 wsd/TraceFile.hpp |    6 +
 7 files changed, 309 insertions(+), 196 deletions(-)

New commits:
commit 6dd581f63532c81375196b2e85e0dd244480d2b7
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Tue Feb 7 21:00:23 2017 +0100

    fuzzer; Added --fuzz param that takes a looltrace file as input.
    
    To perform one fuzzing iteration, use something like:
    
      ./loolwsd_fuzzer --config-file=loolwsd.xml --o:lo_template_path="/opt/libreoffice/instdir" --o:storage.filesystem[@allow]=true --fuzz=/tmp/looltrace
    
    Change-Id: I27210d55a65f75e7d51e05c2f5f999acb758c4b1

diff --git a/Makefile.am b/Makefile.am
index e4a2af1..651057b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,7 +32,7 @@ AM_LDFLAGS = -pthread -Wl,-E
 loolforkit_LDFLAGS = -pthread -Wl,-E,-rpath,/snap/loolwsd/current/usr/lib
 loolmount_LDFLAGS = -pthread -Wl,-E,-rpath,/snap/loolwsd/current/usr/lib
 
-loolwsd_fuzzer_CPPFLAGS = -DKIT_IN_PROCESS=1 $(AM_CPPFLAGS)
+loolwsd_fuzzer_CPPFLAGS = -DKIT_IN_PROCESS=1 -DFUZZER=1 -DTDOC=\"$(abs_top_srcdir)/test/data\" $(AM_CPPFLAGS)
 
 AM_ETAGSFLAGS = --c++-kinds=+p --fields=+iaS --extra=+q -R --totals=yes *
 AM_CTAGSFLAGS = $(AM_ETAGSFLAGS)
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 5d7dd4e..12f91c0 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -121,6 +121,10 @@
 #include <Kit.hpp>
 #endif
 
+#ifdef FUZZER
+#include <tools/Replay.hpp>
+#endif
+
 #include "common/SigUtil.hpp"
 
 using namespace LOOLProtocol;
@@ -152,6 +156,7 @@ using Poco::ProcessHandle;
 using Poco::StreamCopier;
 using Poco::StringTokenizer;
 using Poco::TemporaryFile;
+using Poco::Thread;
 using Poco::ThreadPool;
 using Poco::URI;
 using Poco::Util::Application;
@@ -1697,6 +1702,9 @@ std::atomic<int> LOOLWSD::ForKitWritePipe(-1);
 std::atomic<int> LOOLWSD::ForKitProcId(-1);
 bool LOOLWSD::NoCapsForKit = false;
 #endif
+#ifdef FUZZER
+std::string LOOLWSD::FuzzFileName = "";
+#endif
 std::string LOOLWSD::Cache = LOOLWSD_CACHEDIR;
 std::string LOOLWSD::SysTemplate;
 std::string LOOLWSD::LoTemplate;
@@ -2049,7 +2057,7 @@ void LOOLWSD::defineOptions(OptionSet& optionSet)
                                " must not be " + std::to_string(MasterPortNumber) + ".")
                         .required(false)
                         .repeatable(false)
-                        .argument("port number"));
+                        .argument("port_number"));
 
     optionSet.addOption(Option("disable-ssl", "", "Disable SSL security layer.")
                         .required(false)
@@ -2080,6 +2088,13 @@ void LOOLWSD::defineOptions(OptionSet& optionSet)
                         .repeatable(false)
                         .argument("seconds"));
 #endif
+
+#ifdef FUZZER
+    optionSet.addOption(Option("fuzz", "", "Read input from the specified file for fuzzing.")
+                        .required(false)
+                        .repeatable(false)
+                        .argument("trace_file_name"));
+#endif
 }
 
 void LOOLWSD::handleOption(const std::string& optionName,
@@ -2125,6 +2140,11 @@ void LOOLWSD::handleOption(const std::string& optionName,
     if (masterPort)
         MasterPortNumber = std::stoi(masterPort);
 #endif
+
+#ifdef FUZZER
+    if (optionName == "fuzz")
+        FuzzFileName = value;
+#endif
 }
 
 void LOOLWSD::displayHelp()
@@ -2282,6 +2302,10 @@ bool LOOLWSD::createForKit()
 #endif
 }
 
+#ifdef FUZZER
+std::mutex Connection::Mutex;
+#endif
+
 int LOOLWSD::main(const std::vector<std::string>& /*args*/)
 {
     SigUtil::setFatalSignals();
@@ -2432,7 +2456,27 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
             // Make sure we have sufficient reserves.
             if (prespawnChildren())
             {
-                // Nothing more to do this round.
+                // Nothing more to do this round, unless we are fuzzing
+#if FUZZER
+                if (!FuzzFileName.empty())
+                {
+                    std::unique_ptr<Replay> replay(new Replay(
+#if ENABLE_SSL
+                            "https://127.0.0.1:" + std::to_string(ClientPortNumber),
+#else
+                            "http://127.0.0.1:" + std::to_string(ClientPortNumber),
+#endif
+                            FuzzFileName));
+
+                    std::unique_ptr<Thread> replayThread(new Thread());
+                    replayThread->start(*replay);
+
+                    // block until the replay finishes
+                    replayThread->join();
+
+                    TerminationFlag = true;
+                }
+#endif
             }
             else if (!std::getenv("LOOL_NO_AUTOSAVE") &&
                      std::chrono::duration_cast<std::chrono::seconds>
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index ab0b479..7438c80 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -38,6 +38,7 @@ public:
     static bool NoCapsForKit;
     static std::atomic<int> ForKitWritePipe;
     static std::atomic<int> ForKitProcId;
+    static std::string FuzzFileName;
     static std::string Cache;
     static std::string ConfigFile;
     static std::string SysTemplate;
commit 964ae25ccf038e92454ead354ee8484d493b738a
Author: Jan Holesovsky <kendy at collabora.com>
Date:   Tue Feb 7 17:16:59 2017 +0100

    fuzzer: Factor out the replay functionality to a separate file.
    
    Change-Id: Ief946b1703ef1ca0b17de3467dce66b4c3da2601

diff --git a/test/helpers.hpp b/test/helpers.hpp
index cc8205e..5b9b498 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -7,6 +7,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#ifndef INCLUDED_TEST_HELPERS_HPP
+#define INCLUDED_TEST_HELPERS_HPP
+
 #include "config.h"
 
 #include <algorithm>
@@ -570,4 +573,6 @@ inline void sendText(std::shared_ptr<LOOLWebSocket>& socket, const std::string&
 
 }
 
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tools/Replay.hpp b/tools/Replay.hpp
new file mode 100644
index 0000000..d5ed00b
--- /dev/null
+++ b/tools/Replay.hpp
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_REPLAY_HPP
+#define INCLUDED_REPLAY_HPP
+
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
+
+#include <LOOLWebSocket.hpp>
+
+#include "TraceFile.hpp"
+#include <test/helpers.hpp>
+
+/// Connection class with WSD.
+class Connection
+{
+public:
+    static
+    std::shared_ptr<Connection> create(const std::string& serverURI, const std::string& documentURL, const std::string& sessionId)
+    {
+        Poco::URI uri(serverURI);
+
+        std::unique_lock<std::mutex> lock(Mutex);
+
+        // Load a document and get its status.
+        std::cout << "NewSession [" << sessionId << "]: " << uri.toString() << "... ";
+
+        std::string encodedUri;
+        Poco::URI::encode(documentURL, ":/?", encodedUri);
+        Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, "/lool/" + encodedUri + "/ws");
+        Poco::Net::HTTPResponse response;
+        auto ws = helpers::connectLOKit(uri, request, response, sessionId + ' ');
+        std::cout << "Connected.\n";
+        return std::shared_ptr<Connection>(new Connection(documentURL, sessionId, ws));
+    }
+
+    const std::string& getName() const { return _name; }
+    std::shared_ptr<LOOLWebSocket> getWS() const { return _ws; };
+
+    /// Send a command to the server.
+    void send(const std::string& data) const
+    {
+        helpers::sendTextFrame(_ws, data, _name);
+    }
+
+    /// Poll socket until expected prefix is fetched, or timeout.
+    std::vector<char> recv(const std::string& prefix)
+    {
+        return helpers::getResponseMessage(_ws, prefix, _name);
+    }
+
+    /// Request loading the document and wait for completion.
+    bool load()
+    {
+        send("load url=" + _documentURL);
+        return helpers::isDocumentLoaded(_ws, _name);
+    }
+
+private:
+    Connection(const std::string& documentURL, const std::string& sessionId, std::shared_ptr<LOOLWebSocket>& ws) :
+        _documentURL(documentURL),
+        _sessionId(sessionId),
+        _name(sessionId + ' '),
+        _ws(ws)
+    {
+    }
+
+private:
+    const std::string _documentURL;
+    const std::string _sessionId;
+    const std::string _name;
+    std::shared_ptr<LOOLWebSocket> _ws;
+    static std::mutex Mutex;
+};
+
+/// Main thread class to replay a trace file.
+class Replay : public Poco::Runnable
+{
+public:
+
+    Replay(const std::string& serverUri, const std::string& uri, bool ignoreTiming = true) :
+        _serverUri(serverUri),
+        _uri(uri),
+        _ignoreTiming(ignoreTiming)
+    {
+    }
+
+    void run() override
+    {
+        try
+        {
+	    replay();
+        }
+        catch (const Poco::Exception &e)
+        {
+            std::cout << "Error: " << e.name() << ' ' << e.message() << std::endl;
+        }
+        catch (const std::exception &e)
+        {
+            std::cout << "Error: " << e.what() << std::endl;
+        }
+    }
+
+protected:
+
+    void replay()
+    {
+        TraceFileReader traceFile(_uri);
+
+        auto epochFile(traceFile.getEpoch());
+        auto epochCurrent(std::chrono::steady_clock::now());
+
+        for (;;)
+        {
+            const auto rec = traceFile.getNextRecord();
+            if (rec.Dir == TraceFileRecord::Direction::Invalid)
+            {
+                // End of trace file.
+                break;
+            }
+
+            const auto deltaCurrent = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - epochCurrent).count();
+            const auto deltaFile = rec.TimestampNs - epochFile;
+            const auto delay = (_ignoreTiming ? 0 : deltaFile - deltaCurrent);
+            if (delay > 0)
+            {
+                if (delay > 1e6)
+                {
+                    std::cout << "Sleeping for " << delay / 1000 << " ms.\n";
+                }
+
+                std::this_thread::sleep_for(std::chrono::microseconds(delay));
+            }
+
+            if (rec.Dir == TraceFileRecord::Direction::Event)
+            {
+                // Meta info about about an event.
+                static const std::string NewSession("NewSession: ");
+                static const std::string EndSession("EndSession: ");
+
+                if (rec.Payload.find(NewSession) == 0)
+                {
+                    const auto uriOrig = rec.Payload.substr(NewSession.size());
+                    std::string uri;
+                    Poco::URI::decode(uriOrig, uri);
+                    auto it = _sessions.find(uri);
+                    if (it != _sessions.end())
+                    {
+                        // Add a new session.
+                        if (it->second.find(rec.SessionId) != it->second.end())
+                        {
+                            std::cout << "ERROR: session [" << rec.SessionId << "] already exists on doc [" << uri << "]\n";
+                        }
+                        else
+                        {
+                            it->second.emplace(rec.SessionId, Connection::create(_serverUri, uri, rec.SessionId));
+                        }
+                    }
+                    else
+                    {
+                        std::cout << "New Document: " << uri << "\n";
+                        _childToDoc.emplace(rec.Pid, uri);
+                        _sessions[uri].emplace(rec.SessionId, Connection::create(_serverUri, uri, rec.SessionId));
+                    }
+                }
+                else if (rec.Payload.find(EndSession) == 0)
+                {
+                    const auto uriOrig = rec.Payload.substr(EndSession.size());
+                    std::string uri;
+                    Poco::URI::decode(uriOrig, uri);
+                    auto it = _sessions.find(uri);
+                    if (it != _sessions.end())
+                    {
+                        std::cout << "EndSession [" << rec.SessionId << "]: " << uri << "\n";
+
+                        it->second.erase(rec.SessionId);
+                        if (it->second.empty())
+                        {
+                            std::cout << "End Doc [" << uri << "].\n";
+                            _sessions.erase(it);
+                            _childToDoc.erase(rec.Pid);
+                        }
+                    }
+                    else
+                    {
+                        std::cout << "ERROR: Doc [" << uri << "] does not exist.\n";
+                    }
+                }
+            }
+            else if (rec.Dir == TraceFileRecord::Direction::Incoming)
+            {
+                auto docIt = _childToDoc.find(rec.Pid);
+                if (docIt != _childToDoc.end())
+                {
+                    const auto& uri = docIt->second;
+                    auto it = _sessions.find(uri);
+                    if (it != _sessions.end())
+                    {
+                        const auto sessionIt = it->second.find(rec.SessionId);
+                        if (sessionIt != it->second.end())
+                        {
+                            // Send the command.
+                            sessionIt->second->send(rec.Payload);
+                        }
+                    }
+                    else
+                    {
+                        std::cout << "ERROR: Doc [" << uri << "] does not exist.\n";
+                    }
+                }
+                else
+                {
+                    std::cout << "ERROR: Unknown PID [" << rec.Pid << "] maps to no active document.\n";
+                }
+            }
+
+            epochCurrent = std::chrono::steady_clock::now();
+            epochFile = rec.TimestampNs;
+        }
+    }
+
+protected:
+    const std::string _serverUri;
+    const std::string _uri;
+
+    /// Should we ignore timing that is saved in the trace file?
+    bool _ignoreTiming;
+
+    /// LOK child process PID to Doc URI map.
+    std::map<unsigned, std::string> _childToDoc;
+
+    /// Doc URI to _sessions map. _sessions are maps of SessionID to Connection.
+    std::map<std::string, std::map<std::string, std::shared_ptr<Connection>>> _sessions;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/tools/Stress.cpp b/tools/Stress.cpp
index a7e90d1..33a2243 100644
--- a/tools/Stress.cpp
+++ b/tools/Stress.cpp
@@ -27,6 +27,7 @@
 #include <Poco/Util/Option.h>
 #include <Poco/Util/OptionSet.h>
 
+#include "Replay.hpp"
 #include "TraceFile.hpp"
 #include "test/helpers.hpp"
 
@@ -78,68 +79,6 @@ long percentile(std::vector<long>& v, const double percentile)
     return v[k - 1] + d * (v[k] - v[k - 1]);
 }
 
-/// Connection class with WSD.
-class Connection
-{
-public:
-    static
-    std::shared_ptr<Connection> create(const std::string& serverURI, const std::string& documentURL, const std::string& sessionId)
-    {
-        Poco::URI uri(serverURI);
-
-        std::unique_lock<std::mutex> lock(Mutex);
-
-        // Load a document and get its status.
-        std::cout << "NewSession [" << sessionId << "]: " << uri.toString() << "... ";
-
-        std::string encodedUri;
-        Poco::URI::encode(documentURL, ":/?", encodedUri);
-        Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, "/lool/" + encodedUri + "/ws");
-        Poco::Net::HTTPResponse response;
-        auto ws = helpers::connectLOKit(uri, request, response, sessionId + ' ');
-        std::cout << "Connected.\n";
-        return std::shared_ptr<Connection>(new Connection(documentURL, sessionId, ws));
-    }
-
-    const std::string& getName() const { return _name; }
-    std::shared_ptr<LOOLWebSocket> getWS() const { return _ws; };
-
-    /// Send a command to the server.
-    void send(const std::string& data) const
-    {
-        helpers::sendTextFrame(_ws, data, _name);
-    }
-
-    /// Poll socket until expected prefix is fetched, or timeout.
-    std::vector<char> recv(const std::string& prefix)
-    {
-        return helpers::getResponseMessage(_ws, prefix, _name);
-    }
-
-    /// Request loading the document and wait for completion.
-    bool load()
-    {
-        send("load url=" + _documentURL);
-        return helpers::isDocumentLoaded(_ws, _name);
-    }
-
-private:
-    Connection(const std::string& documentURL, const std::string& sessionId, std::shared_ptr<LOOLWebSocket>& ws) :
-        _documentURL(documentURL),
-        _sessionId(sessionId),
-        _name(sessionId + ' '),
-        _ws(ws)
-    {
-    }
-
-private:
-    const std::string _documentURL;
-    const std::string _sessionId;
-    const std::string _name;
-    std::shared_ptr<LOOLWebSocket> _ws;
-    static std::mutex Mutex;
-};
-
 std::mutex Connection::Mutex;
 
 //static constexpr auto FIRST_ROW_TILES = "tilecombine part=0 width=256 height=256 tileposx=0,3840,7680 tileposy=0,0,0 tilewidth=3840 tileheight=3840";
@@ -147,13 +86,11 @@ static constexpr auto FIRST_PAGE_TILES = "tilecombine part=0 width=256 height=25
 static constexpr auto FIRST_PAGE_TILE_COUNT = 16;
 
 /// Main thread class to replay a trace file.
-class Worker: public Runnable
+class Worker: public Replay
 {
 public:
 
-    Worker(Stress& app, const std::string& uri) :
-        _app(app),
-        _uri(uri)
+    Worker(const std::string& serverUri, const std::string& uri) : Replay(serverUri, uri, Stress::NoDelay)
     {
     }
 
@@ -256,7 +193,7 @@ private:
 
         static std::atomic<unsigned> SessionId;
         const auto sessionId = ++SessionId;
-        auto connection = Connection::create(_app._serverURI, _uri, std::to_string(sessionId));
+        auto connection = Connection::create(_serverUri, _uri, std::to_string(sessionId));
 
         connection->load();
 
@@ -268,132 +205,7 @@ private:
         }
     }
 
-    void replay()
-    {
-        TraceFileReader traceFile(_uri);
-
-        auto epochFile(traceFile.getEpoch());
-        auto epochCurrent(std::chrono::steady_clock::now());
-
-        for (;;)
-        {
-            const auto rec = traceFile.getNextRecord();
-            if (rec.Dir == TraceFileRecord::Direction::Invalid)
-            {
-                // End of trace file.
-                break;
-            }
-
-            const auto deltaCurrent = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - epochCurrent).count();
-            const auto deltaFile = rec.TimestampNs - epochFile;
-            const auto delay = (Stress::NoDelay ? 0 : deltaFile - deltaCurrent);
-            if (delay > 0)
-            {
-                if (delay > 1e6)
-                {
-                    std::cout << "Sleeping for " << delay / 1000 << " ms.\n";
-                }
-
-                std::this_thread::sleep_for(std::chrono::microseconds(delay));
-            }
-
-            if (rec.Dir == TraceFileRecord::Direction::Event)
-            {
-                // Meta info about about an event.
-                static const std::string NewSession("NewSession: ");
-                static const std::string EndSession("EndSession: ");
-
-                if (rec.Payload.find(NewSession) == 0)
-                {
-                    const auto uriOrig = rec.Payload.substr(NewSession.size());
-                    std::string uri;
-                    Poco::URI::decode(uriOrig, uri);
-                    auto it = _sessions.find(uri);
-                    if (it != _sessions.end())
-                    {
-                        // Add a new session.
-                        if (it->second.find(rec.SessionId) != it->second.end())
-                        {
-                            std::cout << "ERROR: session [" << rec.SessionId << "] already exists on doc [" << uri << "]\n";
-                        }
-                        else
-                        {
-                            it->second.emplace(rec.SessionId, Connection::create(_app._serverURI, uri, rec.SessionId));
-                        }
-                    }
-                    else
-                    {
-                        std::cout << "New Document: " << uri << "\n";
-                        _childToDoc.emplace(rec.Pid, uri);
-                        _sessions[uri].emplace(rec.SessionId, Connection::create(_app._serverURI, uri, rec.SessionId));
-                    }
-                }
-                else if (rec.Payload.find(EndSession) == 0)
-                {
-                    const auto uriOrig = rec.Payload.substr(EndSession.size());
-                    std::string uri;
-                    Poco::URI::decode(uriOrig, uri);
-                    auto it = _sessions.find(uri);
-                    if (it != _sessions.end())
-                    {
-                        std::cout << "EndSession [" << rec.SessionId << "]: " << uri << "\n";
-
-                        it->second.erase(rec.SessionId);
-                        if (it->second.empty())
-                        {
-                            std::cout << "End Doc [" << uri << "].\n";
-                            _sessions.erase(it);
-                            _childToDoc.erase(rec.Pid);
-                        }
-                    }
-                    else
-                    {
-                        std::cout << "ERROR: Doc [" << uri << "] does not exist.\n";
-                    }
-                }
-            }
-            else if (rec.Dir == TraceFileRecord::Direction::Incoming)
-            {
-                auto docIt = _childToDoc.find(rec.Pid);
-                if (docIt != _childToDoc.end())
-                {
-                    const auto& uri = docIt->second;
-                    auto it = _sessions.find(uri);
-                    if (it != _sessions.end())
-                    {
-                        const auto sessionIt = it->second.find(rec.SessionId);
-                        if (sessionIt != it->second.end())
-                        {
-                            // Send the command.
-                            sessionIt->second->send(rec.Payload);
-                        }
-                    }
-                    else
-                    {
-                        std::cout << "ERROR: Doc [" << uri << "] does not exist.\n";
-                    }
-                }
-                else
-                {
-                    std::cout << "ERROR: Unknown PID [" << rec.Pid << "] maps to no active document.\n";
-                }
-            }
-
-            epochCurrent = std::chrono::steady_clock::now();
-            epochFile = rec.TimestampNs;
-        }
-    }
-
 private:
-    Stress& _app;
-    const std::string _uri;
-
-    /// LOK child process PID to Doc URI map.
-    std::map<unsigned, std::string> _childToDoc;
-
-    /// Doc URI to _sessions map. _sessions are maps of SessionID to Connection.
-    std::map<std::string, std::map<std::string, std::shared_ptr<Connection>>> _sessions;
-
     std::vector<long> _latencyStats;
     std::vector<long> _renderingStats;
     std::vector<long> _cacheStats;
@@ -486,7 +298,7 @@ int Stress::main(const std::vector<std::string>& args)
         std::cout << "Arg: " << args[i] << std::endl;
         for (unsigned j = 0; j < _numClients; ++j, ++index)
         {
-            workers.emplace_back(new Worker(*this, args[i]));
+            workers.emplace_back(new Worker(_serverURI, args[i]));
             clients[index].reset(new Thread());
             clients[index]->start(*workers[workers.size() - 1]);
         }
diff --git a/wsd/TraceFile.hpp b/wsd/TraceFile.hpp
index 8f308f1..544adac 100644
--- a/wsd/TraceFile.hpp
+++ b/wsd/TraceFile.hpp
@@ -7,6 +7,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#ifndef INCLUDED_TRACEFILE_HPP
+#define INCLUDED_TRACEFILE_HPP
+
 #include <fstream>
 #include <mutex>
 #include <sstream>
@@ -17,6 +20,7 @@
 #include <Poco/DateTimeFormatter.h>
 #include <Poco/DeflatingStream.h>
 #include <Poco/InflatingStream.h>
+#include <Poco/URI.h>
 
 #include "Protocol.hpp"
 #include "Log.hpp"
@@ -463,4 +467,6 @@ private:
     unsigned _indexOut;
 };
 
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list