loolwsd/.gitignore | 1 loolwsd/LOOLBroker.cpp | 860 +++++++++++++++++++++++++++++++++++++++++++++++++ loolwsd/Makefile.am | 12 3 files changed, 869 insertions(+), 4 deletions(-)
New commits: commit 2c1e44d218bf0600a8a5563238966150f956ff77 Author: Henry Castro <hcas...@collabora.com> Date: Sat Dec 19 17:20:04 2015 -0500 loolwsd: LOOLBroker process added Change-Id: Ia7332761766026599b8ef415652874371938d311 Reviewed-on: https://gerrit.libreoffice.org/20903 Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/loolwsd/.gitignore b/loolwsd/.gitignore index 2054b6a..1461eea 100644 --- a/loolwsd/.gitignore +++ b/loolwsd/.gitignore @@ -32,6 +32,7 @@ lokitclient loadtest loolwsd loolkit +loolbroker sockettransporttest # Debug output diff --git a/loolwsd/LOOLBroker.cpp b/loolwsd/LOOLBroker.cpp new file mode 100644 index 0000000..df77fa8 --- /dev/null +++ b/loolwsd/LOOLBroker.cpp @@ -0,0 +1,860 @@ +/* -*- 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/. + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/capability.h> + +#include <utime.h> +#include <ftw.h> +#include <unistd.h> +#include <dlfcn.h> + +#include <mutex> +#include <cstring> +#include <cassert> +#include <iostream> +#include <fstream> +#include <deque> + +#include <Poco/Types.h> +#include <Poco/Random.h> +#include <Poco/Path.h> +#include <Poco/File.h> +#include <Poco/ThreadLocal.h> +#include <Poco/Process.h> +#include <Poco/Thread.h> +#include <Poco/NamedMutex.h> + +#include "Util.hpp" + +// First include the grist of the helper process - ideally +// we can avoid execve and share lots of memory here. We +// can't link to a non-PIC translation unit though, so +// include to share. +#define LOOLKIT_NO_MAIN 1 +#include "LOOLKit.cpp" + +#define INTERVAL_PROBES 10 +#define MAINTENANCE_INTERVAL 1 + +#define LIB_SOFFICEAPP "lib" "sofficeapp" ".so" +#define LIB_SCLO "lib" "sclo" ".so" +#define LIB_SWLO "lib" "swlo" ".so" +#define LIB_SDLO "lib" "sdlo" ".so" + +typedef int (LokHookPreInit) ( const char *install_path, const char *user_profile_path ); + +using Poco::Path; +using Poco::File; +using Poco::ThreadLocal; +using Poco::Process; +using Poco::Thread; +using Poco::ProcessHandle; + +const std::string FIFO_FILE = "/tmp/loolwsdfifo"; +const std::string FIFO_BROKER = "/tmp/loolbroker.fifo"; +const std::string BROKER_SUFIX = ".fifo"; +const std::string BROKER_PREFIX = "/tmp/lokit"; + +static int readerChild = -1; +static int readerBroker = -1; +static int timeoutCounter = 0; + +static unsigned int forkCounter = 0; +static unsigned int childCounter = 0; + +static std::mutex forkMutex; +static std::deque<Process::PID> _emptyURL; +static std::map<Process::PID, int> _childProcesses; +static std::map<std::string, Process::PID> _cacheURL; + +Poco::NamedMutex _namedMutexLOOL("loolwsd"); + +namespace +{ + ThreadLocal<std::string> sourceForLinkOrCopy; + ThreadLocal<Path> destinationForLinkOrCopy; + + int linkOrCopyFunction(const char *fpath, + const struct stat* /*sb*/, + int typeflag, + struct FTW* /*ftwbuf*/) + { + if (strcmp(fpath, sourceForLinkOrCopy->c_str()) == 0) + return 0; + + assert(fpath[strlen(sourceForLinkOrCopy->c_str())] == '/'); + const char *relativeOldPath = fpath + strlen(sourceForLinkOrCopy->c_str()) + 1; + +#ifdef __APPLE__ + if (strcmp(relativeOldPath, "PkgInfo") == 0) + return 0; +#endif + + Path newPath(*destinationForLinkOrCopy, Path(relativeOldPath)); + + switch (typeflag) + { + case FTW_F: + File(newPath.parent()).createDirectories(); + if (link(fpath, newPath.toString().c_str()) == -1) + { + std::cout << Util::logPrefix() + + "link(\"" + fpath + "\",\"" + newPath.toString() + "\") failed: " + + strerror(errno) << std::endl; + exit(1); + } + break; + case FTW_DP: + { + struct stat st; + if (stat(fpath, &st) == -1) + { + std::cout << Util::logPrefix() + + "stat(\"" + fpath + "\") failed: " + + strerror(errno) << std::endl; + return 1; + } + File(newPath).createDirectories(); + struct utimbuf ut; + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + if (utime(newPath.toString().c_str(), &ut) == -1) + { + std::cout << Util::logPrefix() + + "utime(\"" + newPath.toString() + "\", &ut) failed: " + + strerror(errno) << std::endl; + return 1; + } + } + break; + case FTW_DNR: + std::cout <<Util::logPrefix() + + "Cannot read directory '" + fpath + "'" << std::endl; + return 1; + case FTW_NS: + std::cout <<Util::logPrefix() + + "nftw: stat failed for '" + fpath + "'" << std::endl; + return 1; + case FTW_SLN: + std::cout <<Util::logPrefix() + + "nftw: symlink to nonexistent file: '" + fpath + "', ignored" << std::endl; + break; + default: + assert(false); + } + return 0; + } + + void linkOrCopy(const std::string& source, const Path& destination) + { + *sourceForLinkOrCopy = source; + if (sourceForLinkOrCopy->back() == '/') + sourceForLinkOrCopy->pop_back(); + *destinationForLinkOrCopy = destination; + if (nftw(source.c_str(), linkOrCopyFunction, 10, FTW_DEPTH) == -1) + std::cout << Util::logPrefix() + + "linkOrCopy: nftw() failed for '" + source + "'" << std::endl; + } + + void dropCapability( +#ifdef __linux + cap_value_t capability +#endif + ) + { +#ifdef __linux + cap_t caps; + cap_value_t cap_list[] = { capability }; + + caps = cap_get_proc(); + if (caps == NULL) + { + std::cout << Util::logPrefix() + "cap_get_proc() failed: " + strerror(errno) << std::endl; + exit(1); + } + + if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1 || + cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1) + { + std::cout << Util::logPrefix() + "cap_set_flag() failed: " + strerror(errno) << std::endl; + exit(1); + } + + if (cap_set_proc(caps) == -1) + { + std::cout << Util::logPrefix() << std::string("cap_set_proc() failed: ") + strerror(errno) << std::endl; + exit(1); + } + + char *capText = cap_to_text(caps, NULL); + std::cout << Util::logPrefix() + "Capabilities now: " + capText << std::endl; + cap_free(capText); + + cap_free(caps); +#endif + // We assume that on non-Linux we don't need to be root to be able to hardlink to files we + // don't own, so drop root. + if (geteuid() == 0 && getuid() != 0) + { + // The program is setuid root. Not normal on Linux where we use setcap, but if this + // needs to run on non-Linux Unixes, setuid root is what it will bneed to be to be able + // to do chroot(). + if (setuid(getuid()) != 0) + { + std::cout << Util::logPrefix() << std::string("setuid() failed: ") + strerror(errno) << std::endl; + } + } +#if ENABLE_DEBUG + if (geteuid() == 0 && getuid() == 0) + { +#ifdef __linux + // Argh, awful hack + if (capability == CAP_FOWNER) + return; +#endif + + // Running under sudo, probably because being debugged? Let's drop super-user rights. + LOOLWSD::runningAsRoot = true; + if (LOOLWSD::uid == 0) + { + struct passwd *nobody = getpwnam("nobody"); + if (nobody) + LOOLWSD::uid = nobody->pw_uid; + else + LOOLWSD::uid = 65534; + } + if (setuid(LOOLWSD::uid) != 0) + { + Application::instance().logger().error(std::string("setuid() failed: ") + strerror(errno)); + } + } +#endif + } +} + +class PipeRunnable: public Runnable +{ +public: + PipeRunnable() + { + _pStart = _pEnd = nullptr; + } + + ssize_t getResponseLine(int nPipeReader, std::string& aLine) + { + ssize_t nBytes = -1; + aLine.clear(); + + while (true) + { + if ( _pStart == _pEnd ) + { + nBytes = Util::readMessage(nPipeReader, _aBuffer, sizeof(_aBuffer)); + if ( nBytes < 0 ) + { + _pStart = _pEnd = NULL; + break; + } + + _pStart = _aBuffer; + _pEnd = _aBuffer + nBytes; + } + + if ( _pStart != _pEnd ) + { + char aChar = *_pStart++; + while (_pStart != _pEnd && aChar != '\r' && aChar != '\n') + { + aLine += aChar; + aChar = *_pStart++; + } + + if ( aChar == '\r' && *_pStart == '\n') + { + _pStart++; + break; + } + } + } + + return nBytes; + } + + ssize_t sendMessage(int nPipeWriter, const std::string& aMessage) + { + ssize_t nBytes = -1; + + nBytes = Util::writeFIFO(nPipeWriter, aMessage.c_str(), aMessage.length()); + if ( nBytes < 0 ) + std::cout << Util::logPrefix() << "Error writting child: " << strerror(errno) << std::endl; + + return nBytes; + } + + ssize_t createThread(Process::PID nPID, const std::string& aTID) + { + std::string aResponse; + std::string aMessage = "thread " + aTID + "\r\n"; + return sendMessage(_childProcesses[nPID], aMessage); + } + + ssize_t updateURL(Process::PID nPID, const std::string& aURL) + { + std::string aResponse; + std::string aMessage = "url " + aURL + "\r\n"; + return sendMessage(_childProcesses[nPID], aMessage); + } + + Process::PID searchURL(const std::string& aURL) + { + ssize_t nBytes = -1; + Process::PID nPID = 0; + std::string aResponse; + std::string aMessage = "search " + aURL + "\r\n"; + + auto aIterator = _childProcesses.begin(); + for ( ; aIterator!=_childProcesses.end(); ++aIterator) + { + if ( !(aIterator->first > 0 && aIterator->second > 0) ) + { + //std::cout << Util::logPrefix() << "error iterator " << aIterator->second << " " << aMessage << std::endl; + continue; + } + + nBytes = Util::writeFIFO(aIterator->second, aMessage.c_str(), aMessage.length()); + if ( nBytes < 0 ) + { + std::cout << Util::logPrefix() << "Error writting child: " << aIterator->first << " " << strerror(errno) << std::endl; + break; + } + + nBytes = getResponseLine(readerChild, aResponse); + if ( nBytes < 0 ) + { + std::cout << Util::logPrefix() << "Error reading child: " << aIterator->first << " " << strerror(errno) << std::endl; + break; + } + + //std::cout << Util::logPrefix() << "response: " << aResponse << std::endl; + StringTokenizer tokens(aResponse, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + if (tokens[1] == "ok") + { + nPID = aIterator->first; + } + else if (tokens[1] == "empty") + { + _emptyURL.push_back(aIterator->first); + } + } + + if ( aIterator != _childProcesses.end() ) + { + _cacheURL.clear(); + _emptyURL.clear(); + } + + return (nBytes > 0 ? nPID : -1); + } + + void handleInput(const std::string& aMessage) + { + Process::PID nPID; + + //std::cout << Util::logPrefix() << "Broker,Input," << aMessage << std::endl; + StringTokenizer tokens(aMessage, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); + if (tokens[0] == "request" && tokens.count() == 3) + { + std::string aTID = tokens[1]; + std::string aURL = tokens[2]; + + // check cache + auto aIterURL = _cacheURL.find(aURL); + if ( aIterURL != _cacheURL.end() ) + { + std::cout << Util::logPrefix() << "Cache Found: " << aIterURL->first << std::endl; + if (createThread(aIterURL->second, aTID) < 0) + std::cout << Util::logPrefix() << "Cache: Error creating thread: " << strerror(errno) << std::endl; + + return; + } + + // not found in cache, full search. + nPID = searchURL(aURL); + if ( nPID < 0) + return; + + if ( nPID > 0 ) + { + std::cout << Util::logPrefix() << "Search Found: " << nPID << std::endl; + if (createThread(nPID, aTID) < 0) + std::cout << Util::logPrefix() << "Search: Error creating thread: " << strerror(errno) << std::endl; + else + _cacheURL[aURL] = nPID; + + return; + } + + // not found, new URL session. + if ( _emptyURL.size() > 0 ) + { + auto aItem = _emptyURL.front(); + std::cout << Util::logPrefix() << "Not Found: " << aItem << std::endl; + if (updateURL(aItem, aURL) < 0) + { + std::cout << Util::logPrefix() << "New: Error update URL: " << strerror(errno) << std::endl; + return; + } + + if (createThread(aItem, aTID) < 0) + { + std::cout << Util::logPrefix() << "New: Error creating thread: " << strerror(errno) << std::endl; + return; + } + _emptyURL.pop_front(); + _cacheURL[aURL] = aItem; + } + + /*if (_emptyURL.size() == 0 ) + { + std::cout << Util::logPrefix() << "No available childs, fork new one" << std::endl; + forkCounter++; + }*/ + } + } + + void run() override + { + std::string aMessage; + char aBuffer[1024*2]; + char* pStart; + char* pEnd; + + struct pollfd aPoll; + ssize_t nBytes = -1; + + aPoll.fd = readerBroker; + aPoll.events = POLLIN; + aPoll.revents = 0; + + pStart = aBuffer; + pEnd = aBuffer; + +#ifdef __linux + if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("pipe_reader"), 0, 0, 0) != 0) + std::cout << Util::logPrefix() << "Cannot set thread name :" << strerror(errno) << std::endl; +#endif + + while (true) + { + if ( pStart == pEnd ) + { + (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++; + + forkMutex.lock(); + handleInput(aMessage); + aMessage.clear(); + forkMutex.unlock(); + } + } + } + } + +private: + char* _pStart; + char* _pEnd; + char _aBuffer[1024]; +}; + +/// Initializes LibreOfficeKit for cross-fork re-use. +static bool globalPreinit(const std::string &loSubPath) +{ + void *handle; + LokHookPreInit* preInit; + + std::string fname = "/" + loSubPath + "/program/" LIB_SOFFICEAPP; + handle = dlopen(fname.c_str(), RTLD_GLOBAL|RTLD_NOW); + if (!handle) + { + std::cout << Util::logPrefix() << " Failed to load library :" << LIB_SOFFICEAPP << std::endl; + return false; + } + + preInit = (LokHookPreInit *)dlsym(handle, "lok_preinit"); + if (!preInit) + { + std::cout << Util::logPrefix() << " Failed to find lok_preinit hook in library :" << LIB_SOFFICEAPP << std::endl; + return false; + } + + return preInit(("/" + loSubPath + "/program").c_str(), "file:///user") == 0; +} + +static int createLibreOfficeKit(bool sharePages, std::string loSubPath, Poco::UInt64 childID) +{ + Poco::UInt64 child; + int nFIFOWriter = -1; + + if (sharePages) + { + Poco::UInt64 pid; + + std::cout << Util::logPrefix() + "Forking LibreOfficeKit" << std::endl; + + if (!(pid = fork())) + { // child + run_lok_main(loSubPath, childID, ""); + _exit(0); + } + else + { // parent + child = pid; // (somehow - switch the hash to use real pids or ?) ... + } + } + else + { + Process::Args args; + std::string executable = "loolkit"; + std::string pipe = BROKER_PREFIX + std::to_string(childCounter++) + BROKER_SUFIX; + + if (mkfifo(pipe.c_str(), 0666) < 0) + { + std::cout << Util::logPrefix() << "mkfifo :" << strerror(errno) << std::endl; + return -1; + } + + args.push_back("--losubpath=" + loSubPath); + args.push_back("--child=" + std::to_string(childID)); + args.push_back("--pipe=" + pipe); + + std::cout << Util::logPrefix() + "Launching LibreOfficeKit: " + executable + " " + Poco::cat(std::string(" "), args.begin(), args.end()) << std::endl; + + ProcessHandle procChild = Process::launch(executable, args); + child = procChild.id(); + + if ( ( nFIFOWriter = open(pipe.c_str(), O_WRONLY) ) < 0 ) + { + std::cout << Util::logPrefix() << "open: " << strerror(errno) << std::endl; + return -1; + } + } + + _childProcesses[child] = nFIFOWriter; + return child; +} + +static int startupLibreOfficeKit(bool sharePages, int nLOKits, + std::string loSubPath, Poco::UInt64 child) +{ + Process::PID pId = -1; + + std::cout << Util::logPrefix() << "starting " << nLOKits << " LoKit instaces." << std::endl; + for (int nCntr = nLOKits; nCntr; nCntr--) + { + if ( (pId = createLibreOfficeKit(sharePages, loSubPath, child)) < 0) + { + std::cout << Util::logPrefix() << "startupLibreOfficeKit: " << strerror(errno) << std::endl; + break; + } + } + + return pId; +} + +// Broker process +int main(int argc, char** argv) +{ + // Initialization + std::string childRoot; + std::string loSubPath; + std::string sysTemplate; + std::string loTemplate; + int _numPreSpawnedChildren = 0; + + for (int i = 0; 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, "--systemplate=") == cmd) + { + eq = strchrnul(cmd, '='); + if (*eq) + sysTemplate = std::string(++eq); + } + else if (strstr(cmd, "--lotemplate=") == cmd) + { + eq = strchrnul(cmd, '='); + if (*eq) + loTemplate = std::string(++eq); + } + else if (strstr(cmd, "--childroot=") == cmd) + { + eq = strchrnul(cmd, '='); + if (*eq) + childRoot = std::string(++eq); + } + else if (strstr(cmd, "--numprespawns=") == cmd) + { + std::cout << "CMD: " << cmd << std::endl; + eq = strchrnul(cmd, '='); + std::cout << "EQ: " << std::string(eq + 1) << std::endl; + if (*eq) + _numPreSpawnedChildren = std::stoi(std::string(++eq)); + } + } + + if (loSubPath.empty()) + { + std::cout << Util::logPrefix() << "--losubpath is empty" << std::endl; + exit(-1); + } + + if (sysTemplate.empty()) + { + std::cout << Util::logPrefix() << "--systemplate is empty" << std::endl; + exit(-1); + } + + if (loTemplate.empty()) + { + std::cout << Util::logPrefix() << "--lotemplate is empty" << std::endl; + exit(-1); + } + + if (childRoot.empty()) + { + std::cout << Util::logPrefix() << "--childroot is empty" << std::endl; + exit(-1); + } + + if ( !_numPreSpawnedChildren ) + { + std::cout << Util::logPrefix() << "--numprespawns is 0" << std::endl; + exit(-1); + } + + if ( (readerBroker = open(FIFO_FILE.c_str(), O_RDONLY) ) < 0 ) + { + std::cout << Util::logPrefix() << "pipe error: " << strerror(errno) << 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; + } + + std::cout << "In Broker!" << std::endl; + + const Poco::UInt64 _childId = Util::rng::getNext(); + + Path jail = Path::forDirectory(childRoot + Path::separator() + std::to_string(_childId)); + File(jail).createDirectories(); + + Path jailLOInstallation(jail, loSubPath); + jailLOInstallation.makeDirectory(); + File(jailLOInstallation).createDirectory(); + + // Copy (link) LO installation and other necessary files into it from the template + + linkOrCopy(sysTemplate, jail); + linkOrCopy(loTemplate, jailLOInstallation); + + // It is necessary to deploy loolkit process to chroot jail. + if (!File("loolkit").exists()) + { + std::cout << Util::logPrefix() << "loolkit does not exists" << std::endl; + exit(-1); + } + File("loolkit").copyTo(Path(jail, "/usr/bin").toString()); + +#ifdef __linux + // Create the urandom and random devices + File(Path(jail, "/dev")).createDirectory(); + if (mknod((jail.toString() + "/dev/random").c_str(), + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, + makedev(1, 8)) != 0) + { + std::cout << Util::logPrefix() + + "mknod(" + jail.toString() + "/dev/random) failed: " + + strerror(errno) << std::endl; + + } + if (mknod((jail.toString() + "/dev/urandom").c_str(), + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, + makedev(1, 9)) != 0) + { + std::cout << Util::logPrefix() + + "mknod(" + jail.toString() + "/dev/urandom) failed: " + + strerror(errno) << std::endl; + } +#endif + + std::cout << Util::logPrefix() << "loolbroker -> chroot(\"" + jail.toString() + "\")" << std::endl; + if (chroot(jail.toString().c_str()) == -1) + { + std::cout << Util::logPrefix() << "chroot(\"" + jail.toString() + "\") failed: " + strerror(errno) << std::endl; + exit(-1); + } + + if (chdir("/") == -1) + { + std::cout << Util::logPrefix() << std::string("chdir(\"/\") in jail failed: ") + strerror(errno) << std::endl; + exit(-1); + } + +#ifdef __linux + dropCapability(CAP_SYS_CHROOT); +#else + dropCapability(); +#endif + + if (mkfifo(FIFO_BROKER.c_str(), 0666) == -1) + { + std::cout << Util::logPrefix() << "Fail to create pipe FIFO " << strerror(errno) << std::endl; + exit(-1); + } + + bool sharePages = globalPreinit(loSubPath); + + if ( startupLibreOfficeKit(sharePages, _numPreSpawnedChildren, loSubPath, _childId) < 0 ) + { + std::cout << Util::logPrefix() << "fail to create childs: " << strerror(errno) << std::endl; + exit(-1); + } + + if ( (readerChild = open(FIFO_BROKER.c_str(), O_RDONLY) ) < 0 ) + { + std::cout << Util::logPrefix() << "pipe opened for reading: " << strerror(errno) << std::endl; + exit(-1); + } + + PipeRunnable pipeHandler; + Poco::Thread aPipe; + + aPipe.start(pipeHandler); + + std::cout << Util::logPrefix() << "loolwsd ready!" << std::endl; + + while (_childProcesses.size() > 0) + { + int status; + pid_t pid = waitpid(-1, &status, WUNTRACED | WNOHANG); + if (pid > 0) + { + if ( _childProcesses.find(pid) != _childProcesses.end() ) + { + if ((WIFEXITED(status) || WIFSIGNALED(status) || WTERMSIG(status) ) ) + { + forkMutex.lock(); + std::cout << Util::logPrefix() << "One of our known child processes died :" << std::to_string(pid) << std::endl; + _childProcesses.erase(pid); + _cacheURL.clear(); + _emptyURL.clear(); + forkMutex.unlock(); + } + + if ( WCOREDUMP(status) ) + std::cout << Util::logPrefix() << "The child produced a core dump." << std::endl; + + if ( WIFSTOPPED(status) ) + std::cout << Util::logPrefix() << "The child process was stopped by delivery of a signal." << std::endl; + + if ( WSTOPSIG(status) ) + std::cout << Util::logPrefix() << "The child process was stopped." << std::endl; + + if ( WIFCONTINUED(status) ) + std::cout << Util::logPrefix() << "The child process was resumed." << std::endl; + } + else + { + 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::endl; + + if ( forkCounter > 0 ) + { + forkMutex.lock(); + forkCounter -= 1; + + if (createLibreOfficeKit(sharePages, loSubPath, _childId) < 0 ) + std::cout << Util::logPrefix() << "fork falied: " << strerror(errno) << std::endl; + + forkMutex.unlock(); + } + + ++timeoutCounter; + if (timeoutCounter == INTERVAL_PROBES) + { + timeoutCounter = 0; + sleep(MAINTENANCE_INTERVAL); + } + } + + // Terminate child processes + for (auto i : _childProcesses) + { + std::cout << Util::logPrefix() + "Requesting child process " + std::to_string(i.first) + " to terminate" << std::endl; + Process::requestTermination(i.first); + } + + std::cout << Util::logPrefix() << "loolbroker finished OK!" << std::endl; + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index f5036bc..d1f76cb 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -1,15 +1,15 @@ SUBDIRS = test -bin_PROGRAMS = loolwsd loolkit +bin_PROGRAMS = loolwsd loolbroker loolkit dist_bin_SCRIPTS = loolwsd-systemplate-setup AM_CPPFLAGS = -pthread AM_LDFLAGS = -pthread -shared_sources = MessageQueue.cpp Util.cpp +shared_sources = LOOLProtocol.cpp LOOLSession.cpp MessageQueue.cpp Util.cpp -loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp MasterProcessSession.cpp ChildProcessSession.cpp TileCache.cpp LOOLProtocol.cpp $(shared_sources) +loolwsd_SOURCES = LOOLWSD.cpp ChildProcessSession.cpp MasterProcessSession.cpp TileCache.cpp $(shared_sources) noinst_PROGRAMS = loadtest connect lokitclient @@ -19,10 +19,12 @@ 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) +broker_shared_sources = ChildProcessSession.cpp $(shared_sources) loolkit_SOURCES = LOOLKit.cpp $(broker_shared_sources) +loolbroker_SOURCES = LOOLBroker.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 @@ -40,8 +42,10 @@ all-local: loolwsd if test "$$BUILDING_FROM_RPMBUILD" != yes; then \ if test `uname -s` = Linux; then \ sudo @SETCAP@ cap_fowner,cap_mknod,cap_sys_chroot=ep loolwsd; \ + sudo @SETCAP@ cap_fowner,cap_mknod,cap_sys_chroot=ep loolbroker; \ else \ sudo chown root loolwsd && sudo chmod u+s loolwsd; \ + sudo chown root loolbroker && sudo chmod u+s loolbroker; \ fi; \ fi _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits