[Libreoffice-commits] online.git: loolwsd/ChildProcessSession.cpp loolwsd/ChildProcessSession.hpp loolwsd/.gitignore loolwsd/LOOLKit.cpp loolwsd/LOOLWSD.cpp loolwsd/Makefile.am

Henry Castro hcastro at collabora.com
Wed Dec 23 09:11:08 PST 2015


 loolwsd/.gitignore              |    4 
 loolwsd/ChildProcessSession.cpp |    9 
 loolwsd/ChildProcessSession.hpp |   19 +
 loolwsd/LOOLKit.cpp             |  617 ++++++++++++++++++++++++++++++++++++++++
 loolwsd/LOOLWSD.cpp             |    4 
 loolwsd/Makefile.am             |   10 
 6 files changed, 657 insertions(+), 6 deletions(-)

New commits:
commit 4af013e87ec5bca1dc2f4fe9cc26970a3c2f1c7b
Author: Henry Castro <hcastro at collabora.com>
Date:   Sat Dec 19 15:55:19 2015 -0500

    loolwsd: LOOLKit process added
    
    Change-Id: I91e8a131b4959a78e43b29faede477d39150c97c
    Reviewed-on: https://gerrit.libreoffice.org/20902
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/.gitignore b/loolwsd/.gitignore
index 0f52b76..2054b6a 100644
--- a/loolwsd/.gitignore
+++ b/loolwsd/.gitignore
@@ -19,15 +19,19 @@
 /stamp-h1
 /systemplate
 /test-driver
+/jails
 
 *.o
 *.exe
 cscope*
 .*
+*.orig
+
 connect
 lokitclient
 loadtest
 loolwsd
+loolkit
 sockettransporttest
 
 # Debug output
diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp
index dfa179f..f5b0320 100644
--- a/loolwsd/ChildProcessSession.cpp
+++ b/loolwsd/ChildProcessSession.cpp
@@ -40,6 +40,9 @@ using Poco::StringTokenizer;
 using Poco::URI;
 using Poco::Util::Application;
 
+Poco::NotificationQueue ChildProcessSession::_callbackQueue;
+Poco::Mutex ChildProcessSession::_mutex;
+
 ChildProcessSession::ChildProcessSession(std::shared_ptr<WebSocket> ws,
                                          LibreOfficeKit *loKit,
                                          LibreOfficeKitDocument * loKitDocument,
@@ -528,6 +531,7 @@ bool ChildProcessSession::clientZoom(const char* /*buffer*/, int /*length*/, Str
     _loKitDocument->pClass->setClientZoom(_loKitDocument, tilePixelWidth, tilePixelHeight, tileTwipWidth, tileTwipHeight);
     return true;
 }
+
 bool ChildProcessSession::downloadAs(const char* /*buffer*/, int /*length*/, StringTokenizer& tokens)
 {
     std::string name, id, format, filterOptions;
@@ -568,8 +572,9 @@ bool ChildProcessSession::downloadAs(const char* /*buffer*/, int /*length*/, Str
             format.size() == 0 ? NULL :format.c_str(),
             filterOptions.size() == 0 ? NULL : filterOptions.c_str());
 
-    sendTextFrame("downloadas: jail=" + _childId + " dir=" + tmpDir + " name=" + name +
-            " port=" + std::to_string(LOOLWSD::portNumber) + " id=" + id);
+    //TODO: handle download portNumber.
+    //sendTextFrame("downloadas: jail=" + _childId + " dir=" + tmpDir + " name=" + name +
+    //        " port=" + std::to_string(LOOLWSD::portNumber) + " id=" + id);
     return true;
 }
 
diff --git a/loolwsd/ChildProcessSession.hpp b/loolwsd/ChildProcessSession.hpp
index 5b7baef..63a24a3 100644
--- a/loolwsd/ChildProcessSession.hpp
+++ b/loolwsd/ChildProcessSession.hpp
@@ -13,6 +13,7 @@
 #define LOK_USE_UNSTABLE_API
 #include <LibreOfficeKit/LibreOfficeKit.h>
 
+#include <Poco/NotificationQueue.h>
 #include "LOOLSession.hpp"
 
 class ChildProcessSession final : public LOOLSession
@@ -42,6 +43,8 @@ public:
     std::string _docType;
     /// View ID, returned by createView() or 0 by default.
     int _viewId;
+    static Poco::NotificationQueue _callbackQueue;
+    static Poco::Mutex _mutex;
 
  protected:
     virtual bool loadDocument(const char *buffer, int length, Poco::StringTokenizer& tokens) override;
@@ -74,6 +77,22 @@ public:
     int _clientPart;
 };
 
+class CallBackNotification: public Poco::Notification
+{
+public:
+	typedef Poco::AutoPtr<CallBackNotification> Ptr;
+
+    CallBackNotification(int nType, const std::string& rPayload, void* pSession)
+            : m_nType(nType),
+              m_aPayload(rPayload),
+              m_pSession(pSession)
+    {}
+
+    int m_nType;
+    std::string m_aPayload;
+    void* m_pSession;
+};
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
new file mode 100644
index 0000000..af0b5f6
--- /dev/null
+++ b/loolwsd/LOOLKit.cpp
@@ -0,0 +1,617 @@
+/* -*- 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/.
+ */
+
+/*
+ * NB. this file is compiled both standalone, and as part of the LOOLBroker.
+ */
+
+#include <sys/prctl.h>
+#include <sys/poll.h>
+#include <sys/syscall.h>
+
+#include <memory>
+#include <iostream>
+
+#include <Poco/Util/Application.h>
+#include <Poco/Net/WebSocket.h>
+#include <Poco/Net/HTTPClientSession.h>
+#include <Poco/Net/HTTPRequest.h>
+#include <Poco/Net/HTTPResponse.h>
+#include <Poco/Thread.h>
+#include <Poco/ThreadPool.h>
+#include <Poco/Runnable.h>
+#include <Poco/StringTokenizer.h>
+#include <Poco/Exception.h>
+#include <Poco/Process.h>
+#include <Poco/Environment.h>
+#include <Poco/NotificationQueue.h>
+#include <Poco/Notification.h>
+#include <Poco/Mutex.h>
+
+#define LOK_USE_UNSTABLE_API
+#include <LibreOfficeKit/LibreOfficeKitInit.h>
+
+#include "MessageQueue.hpp"
+#include "Util.hpp"
+#include "ChildProcessSession.hpp"
+#include "LOOLProtocol.hpp"
+
+using namespace LOOLProtocol;
+using Poco::Net::WebSocket;
+using Poco::Net::HTTPClientSession;
+using Poco::Net::HTTPRequest;
+using Poco::Net::HTTPResponse;
+using Poco::Thread;
+using Poco::Runnable;
+using Poco::StringTokenizer;
+using Poco::Exception;
+using Poco::Process;
+using Poco::Notification;
+using Poco::NotificationQueue;
+using Poco::FastMutex;
+
+const int MASTER_PORT_NUMBER = 9981;
+const std::string CHILD_URI = "/loolws/child/";
+const std::string LOKIT_BROKER = "/tmp/loolbroker.fifo";
+
+class CallBackWorker: public Runnable
+{
+public:
+    CallBackWorker(NotificationQueue& queue):
+        _queue(queue)
+    {
+    }
+
+    std::string callbackTypeToString (int nType)
+    {
+        switch (nType)
+        {
+        case LOK_CALLBACK_INVALIDATE_TILES:
+            return std::string("LOK_CALLBACK_INVALIDATE_TILES");
+        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+            return std::string("LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR");
+        case LOK_CALLBACK_TEXT_SELECTION:
+            return std::string("LOK_CALLBACK_TEXT_SELECTION");
+        case LOK_CALLBACK_TEXT_SELECTION_START:
+            return std::string("LOK_CALLBACK_TEXT_SELECTION_START");
+        case LOK_CALLBACK_TEXT_SELECTION_END:
+            return std::string("LOK_CALLBACK_TEXT_SELECTION_END");
+        case LOK_CALLBACK_CURSOR_VISIBLE:
+            return std::string("LOK_CALLBACK_CURSOR_VISIBLE");
+        case LOK_CALLBACK_GRAPHIC_SELECTION:
+            return std::string("LOK_CALLBACK_GRAPHIC_SELECTION");
+        case LOK_CALLBACK_HYPERLINK_CLICKED:
+            return std::string("LOK_CALLBACK_HYPERLINK_CLICKED");
+        case LOK_CALLBACK_STATE_CHANGED:
+            return std::string("LOK_CALLBACK_STATE_CHANGED");
+        case LOK_CALLBACK_STATUS_INDICATOR_START:
+            return std::string("LOK_CALLBACK_STATUS_INDICATOR_START");
+        case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
+            return std::string("LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE");
+        case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
+            return std::string("LOK_CALLBACK_STATUS_INDICATOR_FINISH");
+        case LOK_CALLBACK_SEARCH_NOT_FOUND:
+            return std::string("LOK_CALLBACK_SEARCH_NOT_FOUND");
+        case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
+            return std::string("LOK_CALLBACK_DOCUMENT_SIZE_CHANGED");
+        case LOK_CALLBACK_SET_PART:
+            return std::string("LOK_CALLBACK_SET_PART");
+        }
+        return std::string("");
+    }
+
+    void callback(int nType, std::string& rPayload, void* pData)
+    {
+        ChildProcessSession *srv = reinterpret_cast<ChildProcessSession *>(pData);
+        pid_t tid = syscall(SYS_gettid);
+
+        //if ( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR )
+            std::cout << tid << " callback : " << srv->_viewId << " " << callbackTypeToString(nType) << " " << rPayload << std::endl;
+
+        switch ( nType )
+        {
+        case LOK_CALLBACK_INVALIDATE_TILES:
+            {
+                //int curPart = srv->_loKitDocument->pClass->getPart(srv->_loKitDocument);
+                int curPart = 0;
+                srv->sendTextFrame("curpart: part=" + std::to_string(curPart));
+                StringTokenizer tokens(rPayload, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+                if (tokens.count() == 4)
+                {
+                    int x(std::stoi(tokens[0]));
+                    int y(std::stoi(tokens[1]));
+                    int width(std::stoi(tokens[2]));
+                    int height(std::stoi(tokens[3]));
+                    srv->sendTextFrame("invalidatetiles:"
+                                       " part=" + std::to_string(curPart) +
+                                       " x=" + std::to_string(x) +
+                                       " y=" + std::to_string(y) +
+                                       " width=" + std::to_string(width) +
+                                       " height=" + std::to_string(height));
+                }
+                else {
+                    srv->sendTextFrame("invalidatetiles: " + rPayload);
+                }
+            }
+            break;
+        case LOK_CALLBACK_STATUS_INDICATOR_START:
+            srv->sendTextFrame("statusindicatorstart:");
+            break;
+
+        case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE:
+            srv->sendTextFrame("statusindicatorsetvalue: " + rPayload);
+            break;
+
+        case LOK_CALLBACK_STATUS_INDICATOR_FINISH:
+            srv->sendTextFrame("statusindicatorfinish:");
+            break;
+        case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+            srv->sendTextFrame("invalidatecursor: " + rPayload);
+            break;
+        case LOK_CALLBACK_TEXT_SELECTION:
+            srv->sendTextFrame("textselection: " + rPayload);
+            break;
+        case LOK_CALLBACK_TEXT_SELECTION_START:
+            srv->sendTextFrame("textselectionstart: " + rPayload);
+            break;
+        case LOK_CALLBACK_TEXT_SELECTION_END:
+            srv->sendTextFrame("textselectionend: " + rPayload);
+            break;
+        case LOK_CALLBACK_CURSOR_VISIBLE:
+            srv->sendTextFrame("cursorvisible: " + rPayload);
+            break;
+        case LOK_CALLBACK_GRAPHIC_SELECTION:
+            srv->sendTextFrame("graphicselection: " + rPayload);
+            break;
+        case LOK_CALLBACK_HYPERLINK_CLICKED:
+            srv->sendTextFrame("hyperlinkclicked: " + rPayload);
+            break;
+        case LOK_CALLBACK_STATE_CHANGED:
+            srv->sendTextFrame("statechanged: " + rPayload);
+            break;
+        case LOK_CALLBACK_SEARCH_NOT_FOUND:
+            srv->sendTextFrame("searchnotfound: " + rPayload);
+            break;
+        case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
+            srv->getStatus("", 0);
+            break;
+        case LOK_CALLBACK_SET_PART:
+            srv->sendTextFrame("setpart: " + rPayload);
+            break;
+        }
+    }
+
+
+    void run()
+    {
+        while ( true )
+        {
+            Notification::Ptr aNotification(_queue.waitDequeueNotification());
+            if (aNotification)
+            {
+                CallBackNotification::Ptr aCallBackNotification = aNotification.cast<CallBackNotification>();
+                if (aCallBackNotification)
+                {
+                    {
+                        FastMutex::ScopedLock lock(_mutex);
+                        callback(aCallBackNotification->m_nType, aCallBackNotification->m_aPayload, aCallBackNotification->m_pSession);
+                    }
+                }
+            }
+            else break;
+        }
+    }
+
+private:
+    NotificationQueue& _queue;
+    static FastMutex   _mutex;
+};
+
+FastMutex CallBackWorker::_mutex;
+
+class QueueHandler: public Runnable
+{
+public:
+    QueueHandler(MessageQueue& queue):
+        _queue(queue)
+    {
+    }
+
+    void setSession(std::shared_ptr<LOOLSession> session)
+    {
+        _session = session;
+    }
+
+    void run() override
+    {
+#ifdef __linux
+      if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("queue_handler"), 0, 0, 0) != 0)
+        std::cout << Util::logPrefix() << "Cannot set thread name :" << strerror(errno) << std::endl;
+#endif
+        while (true)
+        {
+            std::string input = _queue.get();
+            if (input == "eof")
+                break;
+            if (!_session->handleInput(input.c_str(), input.size()))
+                break;
+        }
+    }
+
+private:
+    std::shared_ptr<LOOLSession> _session;
+    MessageQueue& _queue;
+};
+
+class Connection: public Runnable
+{
+public:
+    Connection(LibreOfficeKit *loKit, LibreOfficeKitDocument *loKitDocument, Poco::UInt64 childId, const std::string& threadId) :
+        _loKit(loKit),
+        _loKitDocument(loKitDocument),
+        _childId(childId),
+        _threadId(threadId)
+    {
+    }
+
+    void start()
+    {
+        _thread.start(*this);
+    }
+
+    bool isRunning()
+    {
+        return _thread.isRunning();
+    }
+
+    LibreOfficeKitDocument * getLOKitDocument()
+    {
+        return (_session ? _session->_loKitDocument : NULL);
+    };
+
+    void run() override
+    {
+#ifdef __linux
+        if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("lokit_connection"), 0, 0, 0) != 0)
+            std::cout << Util::logPrefix() << "Cannot set thread name :" << strerror(errno) << std::endl;
+#endif
+        try
+        {
+            // Open websocket connection between the child process and the
+            // parent. The parent forwards us requests that it can't handle.
+
+            HTTPClientSession cs("127.0.0.1", MASTER_PORT_NUMBER);
+            cs.setTimeout(0);
+            HTTPRequest request(HTTPRequest::HTTP_GET, CHILD_URI);
+            HTTPResponse response;
+            std::shared_ptr<WebSocket> ws(new WebSocket(cs, request, response));
+
+            _session.reset(new ChildProcessSession(ws, _loKit, _loKitDocument, std::to_string(_childId)));
+            //std::shared_ptr<ChildProcessSession> session(new ChildProcessSession(ws, _loKit, _loKitDocument));
+            ws->setReceiveTimeout(0);
+
+            // child Jail TID PID
+            std::string hello("child " + std::to_string(_childId) + " " +
+                _threadId + " " + std::to_string(Process::id()));
+            _session->sendTextFrame(hello);
+
+            TileQueue queue;
+            Thread queueHandlerThread;
+            QueueHandler handler(queue);
+
+            handler.setSession(_session);
+            queueHandlerThread.start(handler);
+
+            int flags;
+            int n;
+            do
+            {
+                char buffer[1024];
+                n = ws->receiveFrame(buffer, sizeof(buffer), flags);
+
+                if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
+                {
+                    std::string firstLine = getFirstLine(buffer, n);
+                    StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+                    // The only kind of messages a child process receives are the single-line ones (?)
+                    assert(firstLine.size() == static_cast<std::string::size_type>(n));
+
+                    queue.put(firstLine);
+                }
+            }
+            while (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
+
+            queue.clear();
+            queue.put("eof");
+            queueHandlerThread.join();
+        }
+
+        catch (Exception& exc)
+        {
+            std::cout << Util::logPrefix() + "Exception: " + exc.what() << std::endl;
+        }
+        catch (std::exception& exc)
+        {
+            std::cout << Util::logPrefix() + "Exception: " + exc.what() << std::endl;
+        }
+    }
+
+    ~Connection()
+    {
+        //_thread.stop();
+    }
+
+private:
+    LibreOfficeKit *_loKit;
+    LibreOfficeKitDocument *_loKitDocument;
+    Poco::UInt64 _childId;
+    std::string _threadId;
+    Thread _thread;
+    std::shared_ptr<ChildProcessSession> _session;
+};
+
+void run_lok_main(const std::string &loSubPath, Poco::UInt64 _childId, const std::string& pipe)
+{
+    struct pollfd aPoll;
+    ssize_t nBytes = -1;
+    char  aBuffer[1024*2];
+    char* pStart = NULL;
+    char* pEnd = NULL;
+
+    std::string aURL;
+    std::map<std::string, std::shared_ptr<Connection>> _connections;
+
+    assert (_childId != 0);
+    assert (!loSubPath.empty());
+
+#ifdef __linux
+    if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("libreofficekit"), 0, 0, 0) != 0)
+        std::cout << Util::logPrefix() << "Cannot set thread name :" << strerror(errno) << std::endl;
+#endif
+
+    try
+    {
+#ifdef __APPLE__
+        LibreOfficeKit *loKit(lok_init_2(("/" + loSubPath + "/Frameworks").c_str(), "file:///user"));
+#else
+        LibreOfficeKit *loKit(lok_init_2(("/" + loSubPath + "/program").c_str(), "file:///user"));
+#endif
+
+        if (!loKit)
+        {
+            std::cout << Util::logPrefix() + "LibreOfficeKit initialization failed" << std::endl;
+            exit(-1);
+        }
+
+        int writerBroker;
+        int readerBroker;
+
+        if ( (readerBroker = open(pipe.c_str(), O_RDONLY) ) < 0 )
+        {
+            std::cout << Util::logPrefix() << "open pipe read only: " << strerror(errno) << std::endl;
+            exit(-1);
+        }
+
+        if ( (writerBroker = open(LOKIT_BROKER.c_str(), O_WRONLY) ) < 0 )
+        {
+            std::cout << Util::logPrefix() << "open pipe write only: " << strerror(errno) << std::endl;
+            exit(-1);
+        }
+
+        CallBackWorker callbackWorker(ChildProcessSession::_callbackQueue);
+        Poco::ThreadPool::defaultPool().start(callbackWorker);
+
+        std::cout << Util::logPrefix() << "child ready!" << std::endl;
+
+        std::string aResponse;
+        std::string aMessage;
+
+        while ( true )
+        {
+            if ( pStart == pEnd )
+            {
+                aPoll.fd = readerBroker;
+                aPoll.events = POLLIN;
+                aPoll.revents = 0;
+
+                (void)poll(&aPoll, 1, -1);
+
+                if( (aPoll.revents & POLLIN) != 0 )
+                {
+                    nBytes = Util::readFIFO(readerBroker, aBuffer, sizeof(aBuffer));
+                    if (nBytes < 0)
+                    {
+                        pStart = pEnd = NULL;
+                        std::cout << Util::logPrefix() << "Error reading message :" << strerror(errno) << std::endl;
+                        continue;
+                    }
+                    pStart = aBuffer;
+                    pEnd   = aBuffer + nBytes;
+                }
+            }
+
+            if ( pStart != pEnd )
+            {
+                char aChar = *pStart++;
+                while (pStart != pEnd && aChar != '\r' && aChar != '\n')
+                {
+                    aMessage += aChar;
+                    aChar = *pStart++;
+                }
+
+                if ( aChar == '\r' && *pStart == '\n')
+                {
+                    pStart++;
+                    //std::cout << Util::logPrefix() << "child receive: " << aMessage << std::endl;
+                    StringTokenizer tokens(aMessage, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
+
+                    if (tokens[0] == "search")
+                    {
+                        if ( !_connections.empty() )
+                        {
+                            aResponse = std::to_string(Process::id()) + ( aURL == tokens[1] ? " ok \r\n" : " no \r\n");
+                            Util::writeFIFO(writerBroker, aResponse.c_str(), aResponse.length() );
+                        }
+                        else
+                        {
+                            aURL.clear();
+                            aResponse = std::to_string(Process::id()) + " empty \r\n";
+                            Util::writeFIFO(writerBroker, aResponse.c_str(), aResponse.length() );
+                        }
+                    }
+                    else if (tokens[0] == "thread")
+                    {
+                        auto aItem = _connections.find(tokens[1]);
+                        if (aItem != _connections.end())
+                        { // found item, check if still running
+                            std::cout << Util::logPrefix() << "found thread" << std::endl;
+                            if ( !aItem->second->isRunning() )
+                                std::cout << Util::logPrefix() << "found thread not running!" << std::endl;
+                        }
+                        else
+                        { // new thread id
+                            //std::cout << Util::logPrefix() << "new thread starting!" << std::endl;
+                            std::shared_ptr<Connection> thread;
+                            if ( _connections.empty() )
+                            {
+                                std::cout << Util::logPrefix() << "create main thread" << std::endl;
+                                thread = std::shared_ptr<Connection>(new Connection(loKit, NULL, _childId, tokens[1]));
+                            }
+                            else
+                            {
+                                std::cout << Util::logPrefix() << "create view thread" << std::endl;
+                                auto aConnection = _connections.begin();
+                                thread = std::shared_ptr<Connection>(new Connection(loKit, aConnection->second->getLOKitDocument(), _childId, tokens[1]));
+                            }
+
+                            auto aInserted = _connections.insert(
+                                std::pair<std::string, std::shared_ptr<Connection>>
+                                (
+                                    tokens[1],
+                                    thread
+                                ));
+
+                            if ( aInserted.second )
+                                thread->start();
+                            else
+                                std::cout << Util::logPrefix() << "Connection not created!" << std::endl;
+
+                            std::cout << Util::logPrefix() << "connections: " << Process::id() << " " << _connections.size() << std::endl;
+                        }
+                    }
+                    else if (tokens[0] == "url")
+                    {
+                        aURL = tokens[1];
+                    }
+                    else
+                    {
+                        aResponse = "bad message \r\n";
+                        Util::writeFIFO(writerBroker, aResponse.c_str(), aResponse.length() );
+                    }
+                    aMessage.clear();
+                }
+            }
+        }
+
+
+        // Destroy LibreOfficeKit
+        loKit->pClass->destroy(loKit);
+
+        pthread_exit(0);
+    }
+    catch (Exception& exc)
+    {
+        std::cout << Util::logPrefix() + "Exception: " + exc.what() << std::endl;
+    }
+    catch (std::exception& exc)
+    {
+        std::cout << Util::logPrefix() + "Exception: " + exc.what() << std::endl;
+    }
+
+    std::cout << Util::logPrefix() << "loolkit finished OK!" << std::endl;
+}
+
+#ifndef LOOLKIT_NO_MAIN
+
+/// Simple argument parsing wrapper / helper for the above.
+int main(int argc, char** argv)
+{
+    std::string loSubPath;
+    Poco::UInt64 _childId = 0;
+    std::string _pipe;
+
+    for (int i = 1; i < argc; ++i)
+    {
+        char *cmd = argv[i];
+        char *eq  = NULL;
+        if (strstr(cmd, "--losubpath=") == cmd)
+        {
+            eq = strchrnul(cmd, '=');
+            if (*eq)
+                loSubPath = std::string(++eq);
+        }
+        else if (strstr(cmd, "--child=") == cmd)
+        {
+            eq = strchrnul(cmd, '=');
+            if (*eq)
+                _childId = std::stoll(std::string(++eq));
+        }
+        else if (strstr(cmd, "--pipe=") == cmd)
+        {
+            eq = strchrnul(cmd, '=');
+            if (*eq)
+                _pipe = std::string(++eq);
+        }
+    }
+
+    if (loSubPath.empty())
+    {
+        std::cout << Util::logPrefix() << "--losubpath is empty" << std::endl;
+        exit(1);
+    }
+
+    if ( !_childId )
+    {
+        std::cout << Util::logPrefix() << "--child is 0" << std::endl;
+        exit(1);
+    }
+
+    if ( _pipe.empty() )
+    {
+        std::cout << Util::logPrefix() << "--pipe is empty" << std::endl;
+        exit(1);
+    }
+
+    try
+    {
+        Poco::Environment::get("LD_BIND_NOW");
+    }
+    catch (Poco::NotFoundException& aError)
+    {
+        std::cout << Util::logPrefix() << aError.what() << std::endl;
+    }
+
+    try
+    {
+        Poco::Environment::get("LOK_VIEW_CALLBACK");
+    }
+    catch (Poco::NotFoundException& aError)
+    {
+        std::cout << Util::logPrefix() << aError.what() << std::endl;
+    }
+
+    run_lok_main(loSubPath, _childId, _pipe);
+
+    return 0;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index f02d7e5..5588be2 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -1341,11 +1341,11 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
             }
             else
             {
-                std::cout << Util::logPrefix() << "None of our known child processes died :" << std::to_string(pid)  << std::endl;
+                std::cout << Util::logPrefix() << "None of our known child processes died :" << std::to_string(pid) << std::endl;
             }
         }
         else if (pid < 0)
-            std::cout << Util::logPrefix() << "Child error: " << strerror(errno);
+            std::cout << Util::logPrefix() << "Child error: " << strerror(errno) << std::endl;
 
         ++timeoutCounter;
         if (timeoutCounter == INTERVAL_PROBES)
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index e34292f..f5036bc 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -1,13 +1,15 @@
 SUBDIRS = test
 
-bin_PROGRAMS = loolwsd
+bin_PROGRAMS = loolwsd loolkit
 
 dist_bin_SCRIPTS = loolwsd-systemplate-setup
 
 AM_CPPFLAGS = -pthread
 AM_LDFLAGS = -pthread
 
-loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp MasterProcessSession.cpp ChildProcessSession.cpp MessageQueue.cpp TileCache.cpp Util.cpp LOOLProtocol.cpp
+shared_sources = MessageQueue.cpp Util.cpp
+
+loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp MasterProcessSession.cpp ChildProcessSession.cpp TileCache.cpp LOOLProtocol.cpp $(shared_sources)
 
 noinst_PROGRAMS = loadtest connect lokitclient
 
@@ -17,6 +19,10 @@ connect_SOURCES = Connect.cpp Util.cpp LOOLProtocol.cpp
 
 lokitclient_SOURCES = LOKitClient.cpp Util.cpp
 
+broker_shared_sources = ChildProcessSession.cpp LOOLProtocol.cpp LOOLSession.cpp $(shared_sources)
+
+loolkit_SOURCES = LOOLKit.cpp $(broker_shared_sources)
+
 noinst_HEADERS = LOKitHelper.hpp LOOLProtocol.hpp LOOLSession.hpp MasterProcessSession.hpp ChildProcessSession.hpp LOOLWSD.hpp LoadTest.hpp MessageQueue.hpp TileCache.hpp Util.hpp Png.hpp \
                  bundled/include/LibreOfficeKit/LibreOfficeKit.h bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h \
                  bundled/include/LibreOfficeKit/LibreOfficeKitInit.h bundled/include/LibreOfficeKit/LibreOfficeKitTypes.h


More information about the Libreoffice-commits mailing list