Rebased ref, commits from common ancestor: commit ff1bb35b6a99155e9ea58853d7c7c3dc5acc9031 Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Wed Dec 23 09:56:46 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Wed Dec 23 09:56:46 2015 -0500
loolwsd: fixes to loolmap Change-Id: I58ce3dbbd6bbd1e3eb860ba6c3044ba4a61e281d diff --git a/loolwsd/loolmap.c b/loolwsd/loolmap.c index 08b149a2a..21792b9d8 100644 --- a/loolwsd/loolmap.c +++ b/loolwsd/loolmap.c @@ -1,6 +1,7 @@ #include <string.h> #include <ctype.h> #include <errno.h> +#include <error.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> @@ -120,15 +121,15 @@ static void total_smaps(unsigned proc_id, const char *file, const char *cmdline) error(EXIT_FAILURE, errno, "%s\n", cmdline); printf("%s\n", cmdline); - printf("Process ID :%20ld\n", proc_id); + printf("Process ID :%20d\n", proc_id); printf("--------------------------------------\n"); - printf("Shared Clean :%20ld kB\n", total_shared_clean); - printf("Shared Dirty :%20ld kB\n", total_shared_dirty); - printf("Private Clean :%20ld kB\n", total_private_clean); - printf("Private Dirty :%20ld kB\n", total_private_dirty); + printf("Shared Clean :%20lld kB\n", total_shared_clean); + printf("Shared Dirty :%20lld kB\n", total_shared_dirty); + printf("Private Clean :%20lld kB\n", total_private_clean); + printf("Private Dirty :%20lld kB\n", total_private_dirty); printf("--------------------------------------\n"); - printf("Shared :%20ld kB\n", total_shared_clean + total_shared_dirty); - printf("Private :%20ld kB\n\n", total_private_clean + total_private_dirty); + printf("Shared :%20lld kB\n", total_shared_clean + total_shared_dirty); + printf("Private :%20lld kB\n\n", total_private_clean + total_private_dirty); } int main(int argc, char **argv) @@ -145,7 +146,7 @@ int main(int argc, char **argv) getopt(argc, argv, ""); if (argc != 2) - error(EXIT_FAILURE, EINVAL); + error(EXIT_FAILURE, EINVAL, "incorrect arguments"); root_proc = opendir("/proc"); if (!root_proc) @@ -154,7 +155,7 @@ int main(int argc, char **argv) while ( ( dir_proc = readdir(root_proc) ) ) { if ( !dir_proc && !dir_proc->d_name ) - error(EXIT_FAILURE, ENOTDIR ); + error(EXIT_FAILURE, ENOTDIR, "bad dir"); if ( *dir_proc->d_name > '0' && *dir_proc->d_name <= '9' ) { @@ -165,13 +166,15 @@ int main(int argc, char **argv) !strstr(cmdline, argv[0]) ) { snprintf(path_proc, sizeof(path_proc), "/proc/%s/%s", dir_proc->d_name, "smaps"); - total_smaps(pid_proc, path_proc, cmdline); - } + total_smaps(pid_proc, path_proc, cmdline); + } } } if ( errno ) - error(EXIT_FAILURE, errno); + error(EXIT_FAILURE, errno, "fail"); return EXIT_SUCCESS; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 48b1aa328f469514319c9d41e1360c76120b7d2c Author: Henry Castro <hcas...@collabora.com> AuthorDate: Wed Dec 23 09:55:56 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Wed Dec 23 09:55:56 2015 -0500 loolwsd: merged loolmap Change-Id: I43845ce5f45c01a67db32ab136ad96b70bc31217 diff --git a/loolwsd/.gitignore b/loolwsd/.gitignore index 1461eea5d..a50e3e6a4 100644 --- a/loolwsd/.gitignore +++ b/loolwsd/.gitignore @@ -13,6 +13,7 @@ /config.log /config.status /configure +/compile /depcomp /install-sh /missing @@ -20,6 +21,7 @@ /systemplate /test-driver /jails +/loolwsd.spec *.o *.exe @@ -33,6 +35,7 @@ loadtest loolwsd loolkit loolbroker +loolmap sockettransporttest # Debug output diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index d1f76cbc2..02fe17601 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS = test -bin_PROGRAMS = loolwsd loolbroker loolkit +bin_PROGRAMS = loolwsd loolbroker loolkit loolmap dist_bin_SCRIPTS = loolwsd-systemplate-setup @@ -25,6 +25,8 @@ loolkit_SOURCES = LOOLKit.cpp $(broker_shared_sources) loolbroker_SOURCES = LOOLBroker.cpp $(broker_shared_sources) +loolmap_SOURCES = loolmap.c + 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 diff --git a/loolwsd/configure.ac b/loolwsd/configure.ac index dce87dcb7..fe58ce892 100644 --- a/loolwsd/configure.ac +++ b/loolwsd/configure.ac @@ -13,6 +13,7 @@ AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CXX +AC_PROG_CC AC_LANG_PUSH([C++]) diff --git a/loolwsd/loolmap.c b/loolwsd/loolmap.c new file mode 100644 index 000000000..08b149a2a --- /dev/null +++ b/loolwsd/loolmap.c @@ -0,0 +1,177 @@ +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <dirent.h> +#include <locale.h> + +#define MAP_SIZE 20 +#define PATH_SIZE 64 +#define BUFFER_SIZE 9600 + +static int read_buffer( char *buffer, unsigned size, + const char *file, char sep ) +{ + int file_desc; + unsigned total_bytes = 0; + + file_desc = open(file, O_RDONLY); + if(file_desc == -1) + return 0; + + for(;;) + { + ssize_t number_bytes = read( file_desc, + buffer + total_bytes, + size - total_bytes ); + if(number_bytes == -1) + { + if(errno==EINTR) + continue; + break; + } + + total_bytes += number_bytes; + if(total_bytes == size) + { + --total_bytes; + break; + } + + if(number_bytes==0) + break; // EOF + } + + close(file_desc); + + if(total_bytes) + { + int i=total_bytes; + + while(i--) + if(buffer[i]=='\n' || buffer[i]=='\0') + buffer[i]=sep; + + if(buffer[total_bytes-1]==' ') + buffer[total_bytes-1]='\0'; + } + + buffer[total_bytes] = '\0'; + return total_bytes; +} + +static void total_smaps(unsigned proc_id, const char *file, const char *cmdline) +{ + FILE *file_pointer; + char buffer[BUFFER_SIZE]; + + unsigned long long private_dirty = 0ull; + unsigned long long private_clean = 0ull; + unsigned long long shared_dirty = 0ull; + unsigned long long shared_clean = 0ull; + unsigned long long total_private_dirty = 0ull; + unsigned long long total_private_clean = 0ull; + unsigned long long total_shared_dirty = 0ull; + unsigned long long total_shared_clean = 0ull; + unsigned long long smap_value; + char smap_key[MAP_SIZE]; + + if ((file_pointer = fopen(file, "r")) == NULL) + error(EXIT_FAILURE, errno, "%s", file); + + while (fgets(buffer, sizeof(buffer), file_pointer)) + { + if (buffer[0] >= 'A' && buffer[0] <= 'Z') + { + if (sscanf(buffer, "%20[^:]: %llu", smap_key, &smap_value) == 2) + { + if (strncmp("Shared_Dirty", smap_key, 12) == 0) + { + shared_dirty = smap_value; + total_shared_dirty += smap_value; + continue; + } + if (strncmp("Shared_Clean", smap_key, 12) == 0) + { + shared_clean = smap_value; + total_shared_clean += smap_value; + continue; + } + if (strncmp("Private_Dirty", smap_key, 13) == 0) + { + private_dirty = smap_value; + total_private_dirty += smap_value; + continue; + } + if (strncmp("Private_Clean", smap_key, 13) == 0) + { + private_clean = smap_value; + total_private_clean += smap_value; + continue; + } + } + } + } + + if ( errno ) + error(EXIT_FAILURE, errno, "%s\n", cmdline); + + printf("%s\n", cmdline); + printf("Process ID :%20ld\n", proc_id); + printf("--------------------------------------\n"); + printf("Shared Clean :%20ld kB\n", total_shared_clean); + printf("Shared Dirty :%20ld kB\n", total_shared_dirty); + printf("Private Clean :%20ld kB\n", total_private_clean); + printf("Private Dirty :%20ld kB\n", total_private_dirty); + printf("--------------------------------------\n"); + printf("Shared :%20ld kB\n", total_shared_clean + total_shared_dirty); + printf("Private :%20ld kB\n\n", total_private_clean + total_private_dirty); +} + +int main(int argc, char **argv) +{ + DIR *root_proc; + struct dirent *dir_proc; + + unsigned pid_curr; + unsigned pid_proc; + char path_proc[PATH_SIZE]; + char cmdline[BUFFER_SIZE]; + + setlocale (LC_ALL, ""); + getopt(argc, argv, ""); + + if (argc != 2) + error(EXIT_FAILURE, EINVAL); + + root_proc = opendir("/proc"); + if (!root_proc) + error(EXIT_FAILURE, errno, "%s", "/proc"); + + while ( ( dir_proc = readdir(root_proc) ) ) + { + if ( !dir_proc && !dir_proc->d_name ) + error(EXIT_FAILURE, ENOTDIR ); + + if ( *dir_proc->d_name > '0' && *dir_proc->d_name <= '9' ) + { + pid_proc = strtoul(dir_proc->d_name, NULL, 10); + snprintf(path_proc, sizeof(path_proc), "/proc/%s/%s", dir_proc->d_name, "cmdline"); + if (read_buffer(cmdline, sizeof(cmdline), path_proc, ' ') && + strstr(cmdline, argv[1]) && + !strstr(cmdline, argv[0]) ) + { + snprintf(path_proc, sizeof(path_proc), "/proc/%s/%s", dir_proc->d_name, "smaps"); + total_smaps(pid_proc, path_proc, cmdline); + } + } + } + + if ( errno ) + error(EXIT_FAILURE, errno); + + return EXIT_SUCCESS; +} commit 27487e7d121bed52aed6f598e7da555c7543758e Author: Henry Castro <hcas...@collabora.com> AuthorDate: Mon Dec 21 09:54:52 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Wed Dec 23 09:50:05 2015 -0500 loolwsd: Merged improved lifecycle prototype Enabled the broker and kit processes. Change-Id: I9afedbccac35732ffe846494cae8135d306e6311 diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp index dd56da0a5..cf75086f6 100644 --- a/loolwsd/ChildProcessSession.cpp +++ b/loolwsd/ChildProcessSession.cpp @@ -211,114 +211,15 @@ extern "C" { static void myCallback(int nType, const char* pPayload, void* pData) { - ChildProcessSession *srv = reinterpret_cast<ChildProcessSession *>(pData); + /*pid_t tid = syscall(SYS_gettid); + std::cout << tid << " callbackWorker : " << priv->m_nViewId << " " << std::string(callbackTypeToString(nType)) << " " << std::string(pPayload ? pPayload : "(nil)") << std::endl;*/ - switch ((LibreOfficeKitCallbackType) nType) - { - case LOK_CALLBACK_INVALIDATE_TILES: - { - int curPart = srv->_loKitDocument->pClass->getPart(srv->_loKitDocument); - srv->sendTextFrame("curpart: part=" + std::to_string(curPart)); - if (srv->_docType == "text") - { - curPart = 0; - } - StringTokenizer tokens(std::string(pPayload), " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - if (tokens.count() == 4) - { - int x, y, width, height; - - try { - x = std::stoi(tokens[0]); - y = std::stoi(tokens[1]); - width = std::stoi(tokens[2]); - height = std::stoi(tokens[3]); - } - catch (std::out_of_range&) - { - // something went wrong, invalidate everything - Application::instance().logger().information(Util::logPrefix() + "Ignoring integer values out of range: " + pPayload); - x = 0; - y = 0; - width = INT_MAX; - height = INT_MAX; - } - - 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: " + std::string(pPayload)); - } - } - break; - case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR: - srv->sendTextFrame("invalidatecursor: " + std::string(pPayload)); - break; - case LOK_CALLBACK_TEXT_SELECTION: - srv->sendTextFrame("textselection: " + std::string(pPayload)); - break; - case LOK_CALLBACK_TEXT_SELECTION_START: - srv->sendTextFrame("textselectionstart: " + std::string(pPayload)); - break; - case LOK_CALLBACK_TEXT_SELECTION_END: - srv->sendTextFrame("textselectionend: " + std::string(pPayload)); - break; - case LOK_CALLBACK_CURSOR_VISIBLE: - srv->sendTextFrame("cursorvisible: " + std::string(pPayload)); - break; - case LOK_CALLBACK_GRAPHIC_SELECTION: - srv->sendTextFrame("graphicselection: " + std::string(pPayload)); - break; - case LOK_CALLBACK_CELL_CURSOR: - srv->sendTextFrame("cellcursor: " + std::string(pPayload)); - break; - case LOK_CALLBACK_CELL_FORMULA: - srv->sendTextFrame("cellformula: " + std::string(pPayload)); - break; - case LOK_CALLBACK_MOUSE_POINTER: - srv->sendTextFrame("mousepointer: " + std::string(pPayload)); - break; - case LOK_CALLBACK_HYPERLINK_CLICKED: - srv->sendTextFrame("hyperlinkclicked: " + std::string(pPayload)); - break; - case LOK_CALLBACK_STATE_CHANGED: - srv->sendTextFrame("statechanged: " + std::string(pPayload)); - break; - case LOK_CALLBACK_STATUS_INDICATOR_START: - srv->sendTextFrame("statusindicatorstart:"); - break; - case LOK_CALLBACK_STATUS_INDICATOR_SET_VALUE: - srv->sendTextFrame("statusindicatorsetvalue: " + std::string(pPayload)); - break; - case LOK_CALLBACK_STATUS_INDICATOR_FINISH: - srv->sendTextFrame("statusindicatorfinish:"); - break; - case LOK_CALLBACK_SEARCH_NOT_FOUND: - srv->sendTextFrame("searchnotfound: " + std::string(pPayload)); - break; - case LOK_CALLBACK_SEARCH_RESULT_SELECTION: - srv->sendTextFrame("searchresultselection: " + std::string(pPayload)); - break; - case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED: - srv->getStatus("", 0); - srv->getPartPageRectangles("", 0); - break; - case LOK_CALLBACK_SET_PART: - srv->sendTextFrame("setpart: " + std::string(pPayload)); - break; - case LOK_CALLBACK_UNO_COMMAND_RESULT: - srv->sendTextFrame("unocommandresult: " + std::string(pPayload)); - break; - } + ChildProcessSession::_callbackQueue.enqueueNotification(new CallBackNotification(nType, pPayload ? pPayload : "(nil)", pData)); + //std::string aPayLoad(pPayload ? pPayload : "(nil)"); } } + bool ChildProcessSession::loadDocument(const char *buffer, int length, StringTokenizer& tokens) { int part = -1; diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp index f20a8ddab..3c6917a9a 100644 --- a/loolwsd/LOOLKit.cpp +++ b/loolwsd/LOOLKit.cpp @@ -109,25 +109,38 @@ public: 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 ) + switch ((LibreOfficeKitCallbackType) nType) { case LOK_CALLBACK_INVALIDATE_TILES: { - //int curPart = srv->_loKitDocument->pClass->getPart(srv->_loKitDocument); - int curPart = 0; + int curPart = srv->_loKitDocument->pClass->getPart(srv->_loKitDocument); srv->sendTextFrame("curpart: part=" + std::to_string(curPart)); + if (srv->_docType == "text") + { + curPart = 0; + } 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])); + int x, y, width, height; + + try { + x = std::stoi(tokens[0]); + y = std::stoi(tokens[1]); + width = std::stoi(tokens[2]); + height = std::stoi(tokens[3]); + } + catch (std::out_of_range&) + { + // something went wrong, invalidate everything + std::cout << Util::logPrefix() << "Ignoring integer values out of range: " << rPayload << std::endl; + x = 0; + y = 0; + width = INT_MAX; + height = INT_MAX; + } + srv->sendTextFrame("invalidatetiles:" " part=" + std::to_string(curPart) + " x=" + std::to_string(x) + @@ -135,22 +148,12 @@ public: " width=" + std::to_string(width) + " height=" + std::to_string(height)); } - else { + 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; @@ -169,25 +172,49 @@ public: case LOK_CALLBACK_GRAPHIC_SELECTION: srv->sendTextFrame("graphicselection: " + rPayload); break; + case LOK_CALLBACK_CELL_CURSOR: + srv->sendTextFrame("cellcursor: " + rPayload); + break; + case LOK_CALLBACK_CELL_FORMULA: + srv->sendTextFrame("cellformula: " + rPayload); + break; + case LOK_CALLBACK_MOUSE_POINTER: + srv->sendTextFrame("mousepointer: " + 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_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_SEARCH_NOT_FOUND: srv->sendTextFrame("searchnotfound: " + rPayload); break; + case LOK_CALLBACK_SEARCH_RESULT_SELECTION: + srv->sendTextFrame("searchresultselection: " + rPayload); + break; case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED: srv->getStatus("", 0); + srv->getPartPageRectangles("", 0); break; case LOK_CALLBACK_SET_PART: srv->sendTextFrame("setpart: " + rPayload); break; + case LOK_CALLBACK_UNO_COMMAND_RESULT: + srv->sendTextFrame("unocommandresult: " + rPayload); + break; } } - void run() { while ( true ) @@ -390,6 +417,13 @@ void run_lok_main(const std::string &loSubPath, Poco::UInt64 _childId, const std std::cout << Util::logPrefix() << "Cannot set thread name :" << strerror(errno) << std::endl; #endif + if (std::getenv("SLEEPFORDEBUGGER")) + { + std::cout << "Sleeping " << std::getenv("SLEEPFORDEBUGGER") << " seconds, attach process " + << Process::id() << " in debugger now." << std::endl; + Thread::sleep(std::stoul(std::getenv("SLEEPFORDEBUGGER")) * 1000); + } + try { #ifdef __APPLE__ diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 2bb61a18b..d543c324c 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -153,91 +153,6 @@ using Poco::URI; 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) - { - Application::instance().logger().error(Util::logPrefix() + - "link(\"" + fpath + "\",\"" + newPath.toString() + "\") failed: " + - strerror(errno)); - exit(1); - } - break; - case FTW_DP: - { - struct stat st; - if (stat(fpath, &st) == -1) - { - Application::instance().logger().error(Util::logPrefix() + - "stat(\"" + fpath + "\") failed: " + - strerror(errno)); - 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) - { - Application::instance().logger().error(Util::logPrefix() + - "utime(\"" + newPath.toString() + "\", &ut) failed: " + - strerror(errno)); - return 1; - } - } - break; - case FTW_DNR: - Application::instance().logger().error(Util::logPrefix() + - "Cannot read directory '" + fpath + "'"); - return 1; - case FTW_NS: - Application::instance().logger().error(Util::logPrefix() + - "nftw: stat failed for '" + fpath + "'"); - return 1; - case FTW_SLN: - Application::instance().logger().information(Util::logPrefix() + - "nftw: symlink to nonexistent file: '" + fpath + "', ignored"); - 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) - Application::instance().logger().error(Util::logPrefix() + - "linkOrCopy: nftw() failed for '" + source + "'"); - } - void dropCapability( #ifdef __linux cap_value_t capability @@ -752,7 +667,6 @@ std::string LOOLWSD::childRoot; std::string LOOLWSD::loSubPath = "lo"; std::string LOOLWSD::jail; Poco::NamedMutex LOOLWSD::_namedMutexLOOL("loolwsd"); -Poco::SharedMemory LOOLWSD::_sharedForkChild("loolwsd", sizeof(bool), Poco::SharedMemory::AM_WRITE); int LOOLWSD::_numPreSpawnedChildren = 10; bool LOOLWSD::doTest = false; @@ -916,299 +830,6 @@ void LOOLWSD::displayHelp() helpFormatter.format(std::cout); } -// Writer, Impress or Calc -void LOOLWSD::componentMain() -{ -#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; - - setSignals(false); -#endif - - try - { - _namedMutexLOOL.lock(); - - Path jailPath = Path::forDirectory(LOOLWSD::childRoot + Path::separator() + std::to_string(_childId)); - File(jailPath).createDirectory(); - - Path jailLOInstallation(jailPath, LOOLWSD::loSubPath); - jailLOInstallation.makeDirectory(); - File(jailLOInstallation).createDirectory(); - - // Copy (link) LO installation and other necessary files into it from the template - - linkOrCopy(LOOLWSD::sysTemplate, jailPath); - linkOrCopy(LOOLWSD::loTemplate, jailLOInstallation); - - // We need this because sometimes the hostname is not resolved - std::vector<std::string> networkFiles = {"/etc/host.conf", "/etc/hosts", "/etc/nsswitch.conf", "/etc/resolv.conf"}; - for (std::vector<std::string>::iterator it = networkFiles.begin(); it != networkFiles.end(); ++it) - { - File networkFile(*it); - if (networkFile.exists()) - { - networkFile.copyTo(Path(jailPath, "/etc").toString()); - } - } -#ifdef __linux - // Create the urandom and random devices - File(Path(jailPath, "/dev")).createDirectory(); - if (mknod((jailPath.toString() + "/dev/random").c_str(), - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, - makedev(1, 8)) != 0) - { - Application::instance().logger().error(Util::logPrefix() + - "mknod(" + jailPath.toString() + "/dev/random) failed: " + - strerror(errno)); - - } - if (mknod((jailPath.toString() + "/dev/urandom").c_str(), - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, - makedev(1, 9)) != 0) - { - Application::instance().logger().error(Util::logPrefix() + - "mknod(" + jailPath.toString() + "/dev/urandom) failed: " + - strerror(errno)); - } -#endif - - Application::instance().logger().information("componentMain -> chroot(\"" + jailPath.toString() + "\")"); - if (chroot(jailPath.toString().c_str()) == -1) - { - logger().error("chroot(\"" + jailPath.toString() + "\") failed: " + strerror(errno)); - exit(Application::EXIT_UNAVAILABLE); - } - - if (chdir("/") == -1) - { - logger().error(std::string("chdir(\"/\") in jail failed: ") + strerror(errno)); - exit(Application::EXIT_UNAVAILABLE); - } - -#ifdef __linux - dropCapability(CAP_SYS_CHROOT); - dropCapability(CAP_MKNOD); - dropCapability(CAP_FOWNER); -#else - dropCapability(); -#endif - - if (std::getenv("SLEEPFORDEBUGGER")) - { - std::cout << "Sleeping " << std::getenv("SLEEPFORDEBUGGER") << " seconds, " << - "attach process " << Process::id() << " in debugger now." << std::endl; - Thread::sleep(std::stoul(std::getenv("SLEEPFORDEBUGGER")) * 1000); - } - -#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) - { - logger().fatal(Util::logPrefix() + "LibreOfficeKit initialisation failed"); - exit(Application::EXIT_UNAVAILABLE); - } - - _namedMutexLOOL.unlock(); - - // 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, LOOLWSD::CHILD_URI); - HTTPResponse response; - std::shared_ptr<WebSocket> ws(new WebSocket(cs, request, response)); - - std::shared_ptr<ChildProcessSession> session(new ChildProcessSession(ws, loKit, nullptr, std::to_string(_childId))); - - ws->setReceiveTimeout(0); - - std::string hello("child " + std::to_string(_childId) + " " + 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(); - - // Destroy lokit document - if (session->_loKitDocument) - session->_loKitDocument->pClass->destroy(session->_loKitDocument); - - // Destroy LibreOfficeKit - loKit->pClass->destroy(loKit); - - // wait to finish lo_startmain thread - pthread_exit(0); - } - catch (Exception& exc) - { - logger().log(Util::logPrefix() + "Exception: " + exc.what()); - } - catch (std::exception& exc) - { - logger().error(Util::logPrefix() + "Exception: " + exc.what()); - } - - exit(Application::EXIT_OK); -} - -int LOOLWSD::createComponent() -{ - int pid; - - _childId = Util::rng::getNext(); - - if ((pid = fork()) == -1) - { - std::cout << "Fork failed." << std::endl; - return Application::EXIT_UNAVAILABLE; - } - - if (!pid) - { - componentMain(); - } - - MasterProcessSession::_childProcesses[pid] = _childId; - - return Application::EXIT_OK; -} - -void LOOLWSD::startupComponent(int nComponents) -{ - for (int nCntr = nComponents; nCntr; nCntr--) - { - if (createComponent() < 0) - break; - } -} - -void LOOLWSD::desktopMain() -{ -#ifdef __linux - if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("loolbroker"), 0, 0, 0) != 0) - std::cout << Util::logPrefix() << "Cannot set thread name :" << strerror(errno) << std::endl; - - setSignals(false); -#endif - - startupComponent(_numPreSpawnedChildren); - - while (MasterProcessSession::_childProcesses.size() > 0) - { - int status; - pid_t pid = waitpid(-1, &status, WUNTRACED | WNOHANG); - if (pid > 0) - { - if ( MasterProcessSession::_childProcesses.find(pid) != MasterProcessSession::_childProcesses.end() ) - { - if ((WIFEXITED(status) || WIFSIGNALED(status) || WTERMSIG(status) ) ) - { - std::cout << Util::logPrefix() << "One of our known child processes died :" << std::to_string(pid) << std::endl; - // remove chroot child - File aWorkSpace(LOOLWSD::childRoot + Path::separator() + - std::to_string(MasterProcessSession::_childProcesses[pid])); - if (aWorkSpace.exists()) - aWorkSpace.remove(true); - - MasterProcessSession::_childProcesses.erase(pid); - } - - if ( WCOREDUMP(status) ) - std::cout << Util::logPrefix() << "The child process [" << pid << "] 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); - - if (!LOOLWSD::isShutDown && _sharedForkChild.begin()[0] > 0 ) - { - _namedMutexLOOL.lock(); - _sharedForkChild.begin()[0] = _sharedForkChild.begin()[0] - 1; - std::cout << Util::logPrefix() << "Create child session, fork new one" << std::endl; - _namedMutexLOOL.unlock(); - if (createComponent() < 0 ) - break; - } - - ++timeoutCounter; - if (timeoutCounter == INTERVAL_PROBES) - { - timeoutCounter = 0; - sleep(MAINTENANCE_INTERVAL); - } - } - - exit(Application::EXIT_OK); -} - - -int LOOLWSD::createDesktop() -{ - int pid; - - if ((pid = fork()) == -1) - { - std::cout << "createDesktop fork failed." << std::endl; - return Application::EXIT_UNAVAILABLE; - } - - if (!pid) - { - desktopMain(); - } - - MasterProcessSession::_childProcesses[pid] = pid; - - return Application::EXIT_OK; -} - int LOOLWSD::createBroker() { Process::Args args; diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp index 3f7cfee4e..e14b0e46f 100644 --- a/loolwsd/LOOLWSD.hpp +++ b/loolwsd/LOOLWSD.hpp @@ -42,7 +42,6 @@ public: static std::string childRoot; static std::string loSubPath; static std::string jail; - static Poco::SharedMemory _sharedForkChild; static Poco::NamedMutex _namedMutexLOOL; static Poco::UInt64 _childId; commit 80e7bcd4ea08e218e3190ef6d22e92e92e94b29a Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> AuthorDate: Sun Dec 20 12:59:26 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Mon Dec 21 11:18:43 2015 -0500 loolwsd: Nominal logger and fixes Nominal logging interface and a fix to using Poco Application from LOOLKit, which is not a Poco App, which caused core dump. Logs now include process name. Added logs to strategic places and some cleanups. Change-Id: Ib7dcc4f1033dddf7c87cd2e786a91f5b482fb312 diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp index b74138ba0..dd56da0a5 100644 --- a/loolwsd/ChildProcessSession.cpp +++ b/loolwsd/ChildProcessSession.cpp @@ -18,7 +18,6 @@ #include <Poco/String.h> #include <Poco/StringTokenizer.h> #include <Poco/URI.h> -#include <Poco/Util/Application.h> #include "ChildProcessSession.hpp" #include "LOKitHelper.hpp" @@ -38,7 +37,6 @@ using Poco::Process; using Poco::ProcessHandle; using Poco::StringTokenizer; using Poco::URI; -using Poco::Util::Application; Poco::NotificationQueue ChildProcessSession::_callbackQueue; Poco::Mutex ChildProcessSession::_mutex; @@ -67,11 +65,11 @@ ChildProcessSession::~ChildProcessSession() bool ChildProcessSession::handleInput(const char *buffer, int length) { + Log::info(_kindString + ",Input," + getAbbreviatedMessage(buffer, length)); + std::string firstLine = getFirstLine(buffer, length); StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); - Application::instance().logger().information(Util::logPrefix() + _kindString + ",Input," + getAbbreviatedMessage(buffer, length)); - if (tokens[0] == "canceltiles") { // this command makes sense only on the command queue level, nothing @@ -363,7 +361,7 @@ bool ChildProcessSession::loadDocument(const char *buffer, int length, StringTok if ((_loKitDocument = _loKit->pClass->documentLoad(_loKit, aUri.toString().c_str())) == NULL) { sendTextFrame("error: cmd=load kind=failed"); - Application::instance().logger().information(Util::logPrefix() + "Failed to load: " + aUri.toString() + ", error is: " + _loKit->pClass->getError(_loKit)); + Log::error("Failed to load: " + aUri.toString() + ", error is: " + _loKit->pClass->getError(_loKit)); return false; } @@ -435,7 +433,7 @@ bool ChildProcessSession::getStatus(const char* /*buffer*/, int /*length*/) StringTokenizer tokens(status, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); if (!getTokenString(tokens[1], "type", _docType)) { - Application::instance().logger().information(Util::logPrefix() + "failed to get document type from" + status); + Log::error("failed to get document type from" + status); } sendTextFrame(status); diff --git a/loolwsd/LOOLBroker.cpp b/loolwsd/LOOLBroker.cpp index 5a64598bc..cca628e23 100644 --- a/loolwsd/LOOLBroker.cpp +++ b/loolwsd/LOOLBroker.cpp @@ -233,7 +233,7 @@ namespace } if (setuid(LOOLWSD::uid) != 0) { - Application::instance().logger().error(std::string("setuid() failed: ") + strerror(errno)); + Log::error(std::string("setuid() failed: ") + strerror(errno)); } } #endif @@ -368,7 +368,6 @@ public: { 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) { @@ -469,6 +468,7 @@ public: } pStart = aBuffer; pEnd = aBuffer + nBytes; + std::cout << Util::logPrefix() << "Broker readFIFO [" << std::string(pStart, nBytes) << "]" << std::endl; } } @@ -565,6 +565,7 @@ static int createLibreOfficeKit(bool sharePages, std::string loSubPath, Poco::UI ProcessHandle procChild = Process::launch(executable, args); child = procChild.id(); + std::cout << Util::logPrefix() << "Launched kit process: " << child << std::endl; if ( ( nFIFOWriter = open(pipe.c_str(), O_WRONLY) ) < 0 ) { @@ -582,7 +583,9 @@ static int startupLibreOfficeKit(bool sharePages, int nLOKits, { Process::PID pId = -1; - std::cout << Util::logPrefix() << "starting " << nLOKits << " LoKit instaces." << std::endl; + std::cout << Util::logPrefix() << "starting " << nLOKits << " LoKit instaces." + << " Shared: " << sharePages << ", loSubPath: " << loSubPath + << ", child: " << child << std::endl; for (int nCntr = nLOKits; nCntr; nCntr--) { if ( (pId = createLibreOfficeKit(sharePages, loSubPath, child)) < 0) @@ -592,7 +595,7 @@ static int startupLibreOfficeKit(bool sharePages, int nLOKits, } } - return pId; + return pId; } // Broker process @@ -605,6 +608,8 @@ int main(int argc, char** argv) std::string loTemplate; int _numPreSpawnedChildren = 0; + Log::initialize("brk"); + for (int i = 0; i < argc; ++i) { char *cmd = argv[i]; @@ -635,9 +640,7 @@ int main(int argc, char** argv) } 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)); } @@ -697,8 +700,6 @@ int main(int argc, char** argv) std::cout << Util::logPrefix() << aError.what() << std::endl; } - std::cout << "In Broker!" << std::endl; - const Poco::UInt64 _childId = Util::rng::getNext(); Path jailPath = Path::forDirectory(childRoot + Path::separator() + std::to_string(_childId)); diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp index af0b5f6f2..f20a8ddab 100644 --- a/loolwsd/LOOLKit.cpp +++ b/loolwsd/LOOLKit.cpp @@ -14,11 +14,11 @@ #include <sys/prctl.h> #include <sys/poll.h> #include <sys/syscall.h> +#include <signal.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> @@ -232,15 +232,28 @@ public: { #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; + Log::error(std::string("Cannot set thread name :") + strerror(errno)); #endif - while (true) + try { - std::string input = _queue.get(); - if (input == "eof") - break; - if (!_session->handleInput(input.c_str(), input.size())) - break; + while (true) + { + std::string input = _queue.get(); + if (input == "eof") + break; + if (!_session->handleInput(input.c_str(), input.size())) + break; + } + } + catch(std::exception& ex) + { + Log::error(std::string("Exception: ") + ex.what()); + raise(SIGABRT); + } + catch(...) + { + Log::error("Unknown Exception."); + raise(SIGABRT); } } @@ -258,6 +271,7 @@ public: _childId(childId), _threadId(threadId) { + std::cout << Util::logPrefix() << "New connection in child: " << _childId << ", thread: " << _threadId << std::endl; } void start() @@ -332,7 +346,6 @@ public: queue.put("eof"); queueHandlerThread.join(); } - catch (Exception& exc) { std::cout << Util::logPrefix() + "Exception: " + exc.what() << std::endl; @@ -345,6 +358,7 @@ public: ~Connection() { + std::cout << Util::logPrefix() << "Closing connection in child: " << _childId << ", thread: " << _threadId << std::endl; //_thread.stop(); } @@ -449,7 +463,6 @@ void run_lok_main(const std::string &loSubPath, Poco::UInt64 _childId, const std 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") @@ -520,10 +533,11 @@ void run_lok_main(const std::string &loSubPath, Poco::UInt64 _childId, const std } } - // Destroy LibreOfficeKit loKit->pClass->destroy(loKit); + std::cout << Util::logPrefix() << "loolkit finished OK!" << std::endl; + pthread_exit(0); } catch (Exception& exc) @@ -534,8 +548,6 @@ void run_lok_main(const std::string &loSubPath, Poco::UInt64 _childId, const std { std::cout << Util::logPrefix() + "Exception: " + exc.what() << std::endl; } - - std::cout << Util::logPrefix() << "loolkit finished OK!" << std::endl; } #ifndef LOOLKIT_NO_MAIN @@ -547,6 +559,8 @@ int main(int argc, char** argv) Poco::UInt64 _childId = 0; std::string _pipe; + Log::initialize("kit"); + for (int i = 1; i < argc; ++i) { char *cmd = argv[i]; diff --git a/loolwsd/LOOLSession.cpp b/loolwsd/LOOLSession.cpp index db59e7680..b43908c5d 100644 --- a/loolwsd/LOOLSession.cpp +++ b/loolwsd/LOOLSession.cpp @@ -44,7 +44,6 @@ #include <Poco/ThreadLocal.h> #include <Poco/URI.h> #include <Poco/URIStreamOpener.h> -#include <Poco/Util/Application.h> #include <Poco/Exception.h> #include <Poco/Net/NetException.h> #include <Poco/Net/DialogSocket.h> @@ -77,7 +76,6 @@ using Poco::ThreadLocal; using Poco::UInt64; using Poco::URI; using Poco::URIStreamOpener; -using Poco::Util::Application; using Poco::Exception; using Poco::Net::DialogSocket; using Poco::Net::SocketAddress; @@ -107,13 +105,18 @@ LOOLSession::LOOLSession(std::shared_ptr<WebSocket> ws, Kind kind) : LOOLSession::~LOOLSession() { - std::cout << Util::logPrefix() << "LOOLSession dtor this=" << this << " " << _kind << std::endl; + std::cout << Util::logPrefix() << "loolsession dtor this=" << this << " " << _kind << std::endl; if (_ws) Util::shutdownWebSocket(*_ws); } void LOOLSession::sendTextFrame(const std::string& text) { + if (!_ws) + Log::error("No socket to send to."); + else + Log::debug(_kindString + ",Send," + getAbbreviatedMessage(text.c_str(), text.size())); + std::unique_lock<std::mutex> lock(_mutex); _ws->sendFrame(text.data(), text.size()); @@ -121,6 +124,11 @@ void LOOLSession::sendTextFrame(const std::string& text) void LOOLSession::sendBinaryFrame(const char *buffer, int length) { + if (!_ws) + Log::error("No socket to send to."); + else + Log::debug(_kindString + ",Send," + std::to_string(length) + " bytes"); + std::unique_lock<std::mutex> lock(_mutex); if (length > 1000) diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 41da9bbde..2bb61a18b 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -251,25 +251,25 @@ namespace caps = cap_get_proc(); if (caps == NULL) { - Application::instance().logger().error(Util::logPrefix() + "cap_get_proc() failed: " + strerror(errno)); + Log::error(std::string("cap_get_proc() failed: ") + strerror(errno)); 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) { - Application::instance().logger().error(Util::logPrefix() + "cap_set_flag() failed: " + strerror(errno)); + Log::error(std::string("cap_set_flag() failed: ") + strerror(errno)); exit(1); } if (cap_set_proc(caps) == -1) { - Application::instance().logger().error(std::string("cap_set_proc() failed: ") + strerror(errno)); + Log::error(std::string("cap_set_proc() failed: ") + strerror(errno)); exit(1); } char *capText = cap_to_text(caps, NULL); - Application::instance().logger().information(Util::logPrefix() + "Capabilities now: " + capText); + Log::info(std::string("Capabilities now: ") + capText); cap_free(capText); cap_free(caps); @@ -283,7 +283,7 @@ namespace // to do chroot(). if (setuid(getuid()) != 0) { - Application::instance().logger().error(std::string("setuid() failed: ") + strerror(errno)); + Log::error(std::string("setuid() failed: ") + strerror(errno)); } } #if ENABLE_DEBUG @@ -307,7 +307,7 @@ namespace } if (setuid(LOOLWSD::uid) != 0) { - Application::instance().logger().error(std::string("setuid() failed: ") + strerror(errno)); + Log::error(std::string("setuid() failed: ") + strerror(errno)); } } #endif @@ -608,7 +608,7 @@ public: } catch (WebSocketException& exc) { - Application::instance().logger().error(Util::logPrefix() + "RequestHandler::handleRequest(), WebSocketException: " + exc.message()); + Log::error("RequestHandler::handleRequest(), WebSocketException: " + exc.message()); switch (exc.code()) { case WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION: @@ -626,7 +626,7 @@ public: } catch (IOException& exc) { - Application::instance().logger().error(Util::logPrefix() + "IOException: " + exc.message()); + Log::error("IOException: " + exc.message()); } } }; @@ -651,7 +651,7 @@ public: line += " / " + it->first + ": " + it->second; } - Application::instance().logger().information(line); + Log::info(line); return new RequestHandler(); } }; @@ -688,7 +688,7 @@ public: } catch (WebSocketException& exc) { - Application::instance().logger().error(Util::logPrefix() + "TestOutput::run(), WebSocketException: " + exc.message()); + Log::error("TestOutput::run(), WebSocketException: " + exc.message()); _ws.close(); } } @@ -1223,7 +1223,7 @@ int LOOLWSD::createBroker() const auto msg = Util::logPrefix() + "Launching broker: " + executable + " " + Poco::cat(std::string(" "), args.begin(), args.end()); - Application::instance().logger().information(msg); + Log::info(msg); ProcessHandle child = Process::launch(executable, args); @@ -1255,6 +1255,8 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) setSignals(false); #endif + Log::initialize("brk"); + if (access(cache.c_str(), R_OK | W_OK | X_OK) != 0) { std::cout << Util::logPrefix() << "Unable to access " << cache << @@ -1394,14 +1396,14 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) // Terminate child processes for (auto i : MasterProcessSession::_childProcesses) { - logger().information(Util::logPrefix() + "Requesting child process " + std::to_string(i.first) + " to terminate"); + Log::info("Requesting child process " + std::to_string(i.first) + " to terminate"); Process::requestTermination(i.first); } // wait broker process finish waitpid(-1, &status, WUNTRACED); - std::cout << Util::logPrefix() << "loolwsd finished OK!" << std::endl; + Log::info("loolwsd finished OK!"); return Application::EXIT_OK; } diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp index 513e20021..2428b821e 100644 --- a/loolwsd/MasterProcessSession.cpp +++ b/loolwsd/MasterProcessSession.cpp @@ -16,7 +16,6 @@ #include <Poco/Random.h> #include <Poco/URI.h> #include <Poco/URIStreamOpener.h> -#include <Poco/Util/Application.h> #include "LOOLProtocol.hpp" #include "LOOLSession.hpp" @@ -42,7 +41,6 @@ using Poco::StringTokenizer; using Poco::Thread; using Poco::UInt64; using Poco::URI; -using Poco::Util::Application; std::map<Process::PID, UInt64> MasterProcessSession::_childProcesses; @@ -73,7 +71,7 @@ MasterProcessSession::~MasterProcessSession() bool MasterProcessSession::handleInput(const char *buffer, int length) { - Application::instance().logger().information(Util::logPrefix() + _kindString + ",Input," + getAbbreviatedMessage(buffer, length)); + Log::info(_kindString + ",Recv," + getAbbreviatedMessage(buffer, length)); std::string firstLine = getFirstLine(buffer, length); StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); @@ -609,7 +607,7 @@ void MasterProcessSession::dispatchChild() } catch (Exception& exc) { - Application::instance().logger().error( Util::logPrefix() + + Log::error( "createDirectories(\"" + aDstPath.toString() + "\") failed: " + exc.displayText() ); } @@ -620,11 +618,11 @@ void MasterProcessSession::dispatchChild() aToCleanup.remove(); #ifdef __linux - Application::instance().logger().information(Util::logPrefix() + "Linking " + aSrcFile.toString() + " to " + aDstFile.toString()); + Log::info("Linking " + aSrcFile.toString() + " to " + aDstFile.toString()); if (!File(aDstFile).exists() && link(aSrcFile.toString().c_str(), aDstFile.toString().c_str()) == -1) { // Failed - Application::instance().logger().error( Util::logPrefix() + + Log::error( "link(\"" + aSrcFile.toString() + "\",\"" + aDstFile.toString() + "\") failed: " + strerror(errno) ); } #endif @@ -634,13 +632,13 @@ void MasterProcessSession::dispatchChild() //fallback if (!File(aDstFile).exists()) { - Application::instance().logger().information(Util::logPrefix() + "Copying " + aSrcFile.toString() + " to " + aDstFile.toString()); + Log::info(Util::logPrefix() + "Copying " + aSrcFile.toString() + " to " + aDstFile.toString()); File(aSrcFile).copyTo(aDstFile.toString()); } } catch (Exception& exc) { - Application::instance().logger().error( Util::logPrefix() + + Log::error( "copyTo(\"" + aSrcFile.toString() + "\",\"" + aDstFile.toString() + "\") failed: " + exc.displayText()); } } @@ -654,10 +652,13 @@ void MasterProcessSession::dispatchChild() void MasterProcessSession::forwardToPeer(const char *buffer, int length) { - Application::instance().logger().information(Util::logPrefix() + _kindString + ",forwardToPeer," + getAbbreviatedMessage(buffer, length)); + Log::info(_kindString + ",forwardToPeer," + getAbbreviatedMessage(buffer, length)); auto peer = _peer.lock(); if (!peer) + { + Log::error("no peer to forward to"); return; + } peer->sendBinaryFrame(buffer, length); } diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp index 3bd593916..56641c116 100644 --- a/loolwsd/TileCache.cpp +++ b/loolwsd/TileCache.cpp @@ -27,7 +27,6 @@ #include <Poco/StringTokenizer.h> #include <Poco/Timestamp.h> #include <Poco/URI.h> -#include <Poco/Util/Application.h> #include "LOOLWSD.hpp" #include "LOOLProtocol.hpp" @@ -42,7 +41,6 @@ using Poco::StringTokenizer; using Poco::SyntaxException; using Poco::Timestamp; using Poco::URI; -using Poco::Util::Application; using namespace LOOLProtocol; @@ -384,7 +382,7 @@ void TileCache::setup(const std::string& timestamp) Timestamp::TimeVal lastTimeVal; std::istringstream(timestamp) >> lastTimeVal; lastModified = lastTimeVal; - Application::instance().logger().information(Util::logPrefix() + "Timestamp provided externally: " + timestamp); + Log::info("Timestamp provided externally: " + timestamp); cleanEverything = (getLastModified() < Timestamp(lastModified)); } @@ -401,7 +399,7 @@ void TileCache::setup(const std::string& timestamp) { // document changed externally, clean up everything cacheDir.remove(true); - Application::instance().logger().information(Util::logPrefix() + "Completely cleared cache: " + toplevelCacheDirName()); + Log::info("Completely cleared cache: " + toplevelCacheDirName()); } else { @@ -410,7 +408,7 @@ void TileCache::setup(const std::string& timestamp) if (editingCacheDir.exists()) { editingCacheDir.remove(true); - Application::instance().logger().information(Util::logPrefix() + "Cleared the editing cache: " + cacheDirName(true)); + Log::info("Cleared the editing cache: " + cacheDirName(true)); } } } diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp index 4ce1cd00b..87dd14a63 100644 --- a/loolwsd/Util.cpp +++ b/loolwsd/Util.cpp @@ -69,6 +69,38 @@ namespace rng } } +namespace Log +{ + static std::string binname; + + void initialize(const std::string& name) + { + binname = name; + auto& logger = Poco::Logger::get(name); + logger.information("Initializing " + name); + } + + Poco::Logger& logger() + { + return Poco::Logger::get(binname); + } + + void debug(const std::string& msg) + { + return logger().debug(Util::logPrefix() + msg); + } + + void info(const std::string& msg) + { + logger().information(Util::logPrefix() + msg); + } + + void error(const std::string& msg) + { + return logger().error(Util::logPrefix() + msg); + } +} + namespace Util { static const Poco::Int64 epochStart = Poco::Timestamp().epochMicroseconds(); @@ -86,8 +118,10 @@ namespace Util usec %= (one_s); std::ostringstream stream; - stream << Poco::Process::id() << "," << std::setw(2) << std::setfill('0') << (Poco::Thread::current() ? Poco::Thread::current()->id() : 0) << "," << - std::setw(2) << hours << ":" << std::setw(2) << minutes << ":" << std::setw(2) << seconds << "." << std::setw(6) << usec << ","; + stream << Log::binname << ',' << Poco::Process::id() << ',' << std::setw(2) << std::setfill('0') + << (Poco::Thread::current() ? Poco::Thread::current()->id() : 0) << ',' << std::setw(2) << ',' + << hours << ':' << std::setw(2) << minutes << ':' << std::setw(2) << seconds << "." << std::setw(6) << usec + << ','; return stream.str(); } diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp index 8db7df38a..8b1babfe7 100644 --- a/loolwsd/Util.hpp +++ b/loolwsd/Util.hpp @@ -13,6 +13,7 @@ #include <string> #include <Poco/Net/WebSocket.h> +#include <Poco/Logger.h> #define LOK_USE_UNSTABLE_API #include <LibreOfficeKit/LibreOfficeKitEnums.h> @@ -44,6 +45,17 @@ namespace Util ssize_t readMessage(int nPipe, char* pBuffer, ssize_t nSize); }; +//TODO: Move to own file. +namespace Log +{ + void initialize(const std::string& name); + Poco::Logger& logger(); + + void debug(const std::string& msg); + void info(const std::string& msg); + void error(const std::string& msg); +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit d99d4376ff9e1052543bf850caf5734894ef393a Author: Henry Castro <hcas...@collabora.com> AuthorDate: Sun Dec 20 12:45:19 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Mon Dec 21 11:18:43 2015 -0500 loolwsd: merged systemplate-setup Change-Id: Id066b02e405246d6a0a268aa1b29e09cd7730642 diff --git a/loolwsd/loolwsd-systemplate-setup b/loolwsd/loolwsd-systemplate-setup index 627f23040..c2f4483ae 100755 --- a/loolwsd/loolwsd-systemplate-setup +++ b/loolwsd/loolwsd-systemplate-setup @@ -6,6 +6,7 @@ test $# -eq 2 || { echo "Usage: $0 <chroot template directory for system libs to CHROOT=$1 INSTDIR=$2 +POCODIR=/usr/local/lib test -d "$INSTDIR" || { echo "No such directory: $INSTDIR"; exit 1; } @@ -45,6 +46,9 @@ cd / || exit 1 lib/*-linux-gnu/libnss* \ -type l + find lib/libnss_* lib64/libnss_* -type l + find lib/*-linux-gnu/libnss* -type l + # Go through the LO shared objects and check what system libraries # they link to. find $INSTDIR -name '*.so' -o -name '*.so.[0-9]*' | @@ -52,6 +56,14 @@ cd / || exit 1 ldd $file 2>/dev/null done | grep -v dynamic | cut -d " " -f 3 | grep -E '^(/lib|/usr)' | sort -u | sed -e 's,^/,,' + + # Go through the loolkit + find $POCODIR -name '*Poco*.so' -o -name '*.so.[0-9]*' | + while read file; do + ldd $file 2>/dev/null + done | + grep -v dynamic | cut -d " " -f 3 | grep -E '^(/lib|/usr)' | sort -u | sed -e 's,^/,,' + else find usr/lib/dyld \ usr/lib/*.dylib \ @@ -92,6 +104,67 @@ cd / || exit 1 cpio -p -d -L $CHROOT mkdir -p $CHROOT/tmp +mkdir -p $CHROOT/usr/bin/ +dummy=$CHROOT/usr/bin/dummy + +# checking for library containing Poco::Application +cat <<_ACEOF >$dummy.cpp +#include <iostream> +#include <Poco/Util/Application.h> + +using Poco::Util::Application; + +int main () +{ + std::cout << "Poco functionality OK!" << std::endl; + return Application::EXIT_OK; +} +_ACEOF + +gcc_compile='g++ -o $dummy.o -c $dummy.cpp' +(eval "$gcc_compile") 2>$dummy.err + +if ! test $? = 0; then + cat $dummy.err; + exit 1; +fi + +gcc_link='g++ -o $dummy -lcap -lpng -ldl -lPocoNet -lPocoUtil -lPocoXML -lPocoJSON -lPocoFoundation $dummy.o' +(eval "$gcc_link") 2>$dummy.err + +if ! test $? = 0; then + cat $dummy.err; + exit 1; +fi + +lib_poco=$( echo "$dummy" | + while read file; do + ldd $file 2>/dev/null + done | + grep -v dynamic | cut -d " " -f 3 | grep -E '^(/lib|/usr)') + +for lib in $lib_poco +do + cp --parent -n $lib $CHROOT + + libs=$( echo $lib | + while read file; do + ldd $file 2>/dev/null + done | + grep -v dynamic | cut -d " " -f 3 | grep -E '^(/lib|/usr)') + + for sofile in $libs + do + cp --parent -n $sofile $CHROOT + done +done + +loaders="$(find /lib/ld-* -type l) $(find /lib32/ld-* -type l) $(find /lib64/ld-* -type l)" + +for loader in $loaders +do + cp --parent -n $loader $CHROOT +done # /usr/share/fonts needs to be taken care of separately because the # directory time stamps must be preserved are for fontconfig to trust @@ -108,3 +181,6 @@ if [ `uname -s` = Linux ]; then cp -r -p /usr/share/ghostscript/fonts usr/share/ghostscript fi fi + +echo "testing if Poco libraries were installed properly" +sudo chroot $CHROOT /usr/bin/dummy commit bcad171d21e536e9952bf387b568c8ba88cb7de8 Author: Henry Castro <hcas...@collabora.com> AuthorDate: Sat Dec 19 20:09:48 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Mon Dec 21 11:18:43 2015 -0500 loolwsd: deligating to loolbroker and loolkit Change-Id: I8499540630373a1bee12a5f58fca3ed701ff6404 diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp index 95909afe3..b74138ba0 100644 --- a/loolwsd/ChildProcessSession.cpp +++ b/loolwsd/ChildProcessSession.cpp @@ -139,10 +139,16 @@ bool ChildProcessSession::handleInput(const char *buffer, int length) tokens[0] == "resetselection" || tokens[0] == "saveas"); - if (_docType != "text" && _loKitDocument->pClass->getPart(_loKitDocument) != _clientPart) { - _loKitDocument->pClass->setPart(_loKitDocument, _clientPart); + Poco::Mutex::ScopedLock lock(_mutex); + + _loKitDocument->pClass->setView(_loKitDocument, _viewId); + if (_docType != "text" && _loKitDocument->pClass->getPart(_loKitDocument) != _clientPart) + { + _loKitDocument->pClass->setPart(_loKitDocument, _clientPart); + } } + if (tokens[0] == "clientzoom") { return clientZoom(buffer, length, tokens); diff --git a/loolwsd/LOOLBroker.cpp b/loolwsd/LOOLBroker.cpp index df77fa867..5a64598bc 100644 --- a/loolwsd/LOOLBroker.cpp +++ b/loolwsd/LOOLBroker.cpp @@ -701,16 +701,16 @@ int main(int argc, char** argv) const Poco::UInt64 _childId = Util::rng::getNext(); - Path jail = Path::forDirectory(childRoot + Path::separator() + std::to_string(_childId)); - File(jail).createDirectories(); + Path jailPath = Path::forDirectory(childRoot + Path::separator() + std::to_string(_childId)); + File(jailPath).createDirectories(); - Path jailLOInstallation(jail, loSubPath); + Path jailLOInstallation(jailPath, loSubPath); jailLOInstallation.makeDirectory(); File(jailLOInstallation).createDirectory(); // Copy (link) LO installation and other necessary files into it from the template - linkOrCopy(sysTemplate, jail); + linkOrCopy(sysTemplate, jailPath); linkOrCopy(loTemplate, jailLOInstallation); // It is necessary to deploy loolkit process to chroot jail. @@ -719,34 +719,45 @@ int main(int argc, char** argv) std::cout << Util::logPrefix() << "loolkit does not exists" << std::endl; exit(-1); } - File("loolkit").copyTo(Path(jail, "/usr/bin").toString()); + File("loolkit").copyTo(Path(jailPath, "/usr/bin").toString()); + + // We need this because sometimes the hostname is not resolved + std::vector<std::string> networkFiles = {"/etc/host.conf", "/etc/hosts", "/etc/nsswitch.conf", "/etc/resolv.conf"}; + for (std::vector<std::string>::iterator it = networkFiles.begin(); it != networkFiles.end(); ++it) + { + File networkFile(*it); + if (networkFile.exists()) + { + networkFile.copyTo(Path(jailPath, "/etc").toString()); + } + } #ifdef __linux // Create the urandom and random devices - File(Path(jail, "/dev")).createDirectory(); - if (mknod((jail.toString() + "/dev/random").c_str(), + File(Path(jailPath, "/dev")).createDirectory(); + if (mknod((jailPath.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: " + + "mknod(" + jailPath.toString() + "/dev/random) failed: " + strerror(errno) << std::endl; } - if (mknod((jail.toString() + "/dev/urandom").c_str(), + if (mknod((jailPath.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: " + + "mknod(" + jailPath.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() << "loolbroker -> chroot(\"" + jailPath.toString() + "\")" << std::endl; + if (chroot(jailPath.toString().c_str()) == -1) { - std::cout << Util::logPrefix() << "chroot(\"" + jail.toString() + "\") failed: " + strerror(errno) << std::endl; + std::cout << Util::logPrefix() << "chroot(\"" + jailPath.toString() + "\") failed: " + strerror(errno) << std::endl; exit(-1); } @@ -758,6 +769,8 @@ int main(int argc, char** argv) #ifdef __linux dropCapability(CAP_SYS_CHROOT); + dropCapability(CAP_MKNOD); + dropCapability(CAP_FOWNER); #else dropCapability(); #endif diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index 229f78d50..41da9bbde 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -148,8 +148,172 @@ using Poco::Net::Socket; using Poco::ThreadLocal; using Poco::Random; using Poco::NamedMutex; +using Poco::ProcessHandle; using Poco::URI; +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) + { + Application::instance().logger().error(Util::logPrefix() + + "link(\"" + fpath + "\",\"" + newPath.toString() + "\") failed: " + + strerror(errno)); + exit(1); + } + break; + case FTW_DP: + { + struct stat st; + if (stat(fpath, &st) == -1) + { + Application::instance().logger().error(Util::logPrefix() + + "stat(\"" + fpath + "\") failed: " + + strerror(errno)); + 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) + { + Application::instance().logger().error(Util::logPrefix() + + "utime(\"" + newPath.toString() + "\", &ut) failed: " + + strerror(errno)); + return 1; + } + } + break; + case FTW_DNR: + Application::instance().logger().error(Util::logPrefix() + + "Cannot read directory '" + fpath + "'"); + return 1; + case FTW_NS: + Application::instance().logger().error(Util::logPrefix() + + "nftw: stat failed for '" + fpath + "'"); + return 1; + case FTW_SLN: + Application::instance().logger().information(Util::logPrefix() + + "nftw: symlink to nonexistent file: '" + fpath + "', ignored"); + 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) + Application::instance().logger().error(Util::logPrefix() + + "linkOrCopy: nftw() failed for '" + source + "'"); + } + + 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) + { + Application::instance().logger().error(Util::logPrefix() + "cap_get_proc() failed: " + strerror(errno)); + 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) + { + Application::instance().logger().error(Util::logPrefix() + "cap_set_flag() failed: " + strerror(errno)); + exit(1); + } + + if (cap_set_proc(caps) == -1) + { + Application::instance().logger().error(std::string("cap_set_proc() failed: ") + strerror(errno)); + exit(1); + } + + char *capText = cap_to_text(caps, NULL); + Application::instance().logger().information(Util::logPrefix() + "Capabilities now: " + capText); + 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) + { + Application::instance().logger().error(std::string("setuid() failed: ") + strerror(errno)); + } + } +#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 QueueHandler: public Runnable { public: @@ -391,7 +555,7 @@ public: do { - char buffer[200000]; + char buffer[200000]; //FIXME: Dynamic? if ((pollTimeout = ws->poll(waitTime, Socket::SELECT_READ))) { @@ -752,169 +916,6 @@ void LOOLWSD::displayHelp() helpFormatter.format(std::cout); } -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) - { - Application::instance().logger().error(Util::logPrefix() + - "link(\"" + fpath + "\",\"" + newPath.toString() + "\") failed: " + - strerror(errno)); - exit(1); - } - break; - case FTW_DP: - { - struct stat st; - if (stat(fpath, &st) == -1) - { - Application::instance().logger().error(Util::logPrefix() + - "stat(\"" + fpath + "\") failed: " + - strerror(errno)); - 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) - { - Application::instance().logger().error(Util::logPrefix() + - "utime(\"" + newPath.toString() + "\", &ut) failed: " + - strerror(errno)); - return 1; - } - } - break; - case FTW_DNR: - Application::instance().logger().error(Util::logPrefix() + - "Cannot read directory '" + fpath + "'"); - return 1; - case FTW_NS: - Application::instance().logger().error(Util::logPrefix() + - "nftw: stat failed for '" + fpath + "'"); - return 1; - case FTW_SLN: - Application::instance().logger().information(Util::logPrefix() + - "nftw: symlink to nonexistent file: '" + fpath + "', ignored"); - 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) - Application::instance().logger().error(Util::logPrefix() + - "linkOrCopy: nftw() failed for '" + source + "'"); - } - - 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) - { - Application::instance().logger().error(Util::logPrefix() + "cap_get_proc() failed: " + strerror(errno)); - 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) - { - Application::instance().logger().error(Util::logPrefix() + "cap_set_flag() failed: " + strerror(errno)); - exit(1); - } - - if (cap_set_proc(caps) == -1) - { - Application::instance().logger().error(std::string("cap_set_proc() failed: ") + strerror(errno)); - exit(1); - } - - char *capText = cap_to_text(caps, NULL); - Application::instance().logger().information(Util::logPrefix() + "Capabilities now: " + capText); - 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) - { - Application::instance().logger().error(std::string("setuid() failed: ") + strerror(errno)); - } - } -#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 - } -} - // Writer, Impress or Calc void LOOLWSD::componentMain() { @@ -1208,11 +1209,34 @@ int LOOLWSD::createDesktop() return Application::EXIT_OK; } -void LOOLWSD::startupDesktop(int nDesktops) +int LOOLWSD::createBroker() { - for (int nCntr = nDesktops; nCntr; nCntr--) + Process::Args args; + + args.push_back("--losubpath=" + LOOLWSD::loSubPath); + args.push_back("--systemplate=" + sysTemplate); + args.push_back("--lotemplate=" + loTemplate); + args.push_back("--childroot=" + childRoot); + args.push_back("--numprespawns=" + std::to_string(_numPreSpawnedChildren)); + + std::string executable = Path(Application::instance().commandPath()).parent().toString() + "loolbroker"; + + const auto msg = Util::logPrefix() + "Launching broker: " + executable + " " + + Poco::cat(std::string(" "), args.begin(), args.end()); + Application::instance().logger().information(msg); + + ProcessHandle child = Process::launch(executable, args); + + MasterProcessSession::_childProcesses[child.id()] = child.id(); + + return Application::EXIT_OK; +} + +void LOOLWSD::startupBroker(const signed nBrokers) +{ + for (signed nCntr = nBrokers; nCntr > 0; --nCntr) { - if (createDesktop() < 0) + if (createBroker() < 0) break; } } @@ -1274,7 +1298,7 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) _namedMutexLOOL.lock(); - startupDesktop(1); + startupBroker(1); #ifdef __linux dropCapability(CAP_SYS_CHROOT); @@ -1299,6 +1323,12 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) srv2.start(); + if ( (writerBroker = open(FIFO_FILE.c_str(), O_WRONLY) ) < 0 ) + { + std::cout << Util::logPrefix() << "Pipe opened for writing" << strerror(errno) << std::endl; + return Application::EXIT_UNAVAILABLE; + } + _namedMutexLOOL.unlock(); TestInput input(*this, svs, srv); @@ -1361,9 +1391,12 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/) threadPool.joinAll(); threadPool2.joinAll(); - // Clear sessions to pre-spawned child processes that have connected - // but are not yet assigned a document to work on. - MasterProcessSession::_availableChildSessions.clear(); + // Terminate child processes + for (auto i : MasterProcessSession::_childProcesses) + { + logger().information(Util::logPrefix() + "Requesting child process " + std::to_string(i.first) + " to terminate"); + Process::requestTermination(i.first); + } // wait broker process finish waitpid(-1, &status, WUNTRACED); diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp index 637c2461f..3f7cfee4e 100644 --- a/loolwsd/LOOLWSD.hpp +++ b/loolwsd/LOOLWSD.hpp @@ -75,6 +75,9 @@ private: int createComponent(); int createDesktop(); + void startupBroker(int nBroker); + int createBroker(); + #if ENABLE_DEBUG public: diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp index fb4af0beb..513e20021 100644 --- a/loolwsd/MasterProcessSession.cpp +++ b/loolwsd/MasterProcessSession.cpp @@ -46,7 +46,7 @@ using Poco::Util::Application; std::map<Process::PID, UInt64> MasterProcessSession::_childProcesses; -std::set<std::shared_ptr<MasterProcessSession>> MasterProcessSession::_availableChildSessions; +std::map<Thread::TID, std::shared_ptr<MasterProcessSession>> MasterProcessSession::_availableChildSessions; std::mutex MasterProcessSession::_availableChildSessionMutex; std::condition_variable MasterProcessSession::_availableChildSessionCV; @@ -202,17 +202,19 @@ bool MasterProcessSession::handleInput(const char *buffer, int length) sendTextFrame("error: cmd=child kind=invalid"); return false; } - if (tokens.count() != 3) + if (tokens.count() != 4) { sendTextFrame("error: cmd=child kind=syntax"); return false; } UInt64 childId = std::stoull(tokens[1]); - Process::PID pidChild = std::stoull(tokens[2]); + Thread::TID tId = std::stoull(tokens[2]); + Process::PID pidChild = std::stoull(tokens[3]); std::unique_lock<std::mutex> lock(_availableChildSessionMutex); - _availableChildSessions.insert(shared_from_this()); + _availableChildSessions.insert(std::pair<Thread::TID, std::shared_ptr<MasterProcessSession>> (tId, shared_from_this())); + std::cout << Util::logPrefix() << _kindString << ",Inserted " << this << " id=" << childId << " into _availableChildSessions, size=" << _availableChildSessions.size() << std::endl; std::cout << Util::logPrefix() << "Inserted " << this << " id=" << childId << " into _availableChildSessions, size=" << _availableChildSessions.size() << std::endl; _childId = childId; _pidChild = pidChild; @@ -543,30 +545,48 @@ void MasterProcessSession::sendTile(const char *buffer, int length, StringTokeni void MasterProcessSession::dispatchChild() { + short nRequest = 3; + bool bFound = false; + // Copy document into jail using the fixed name std::shared_ptr<MasterProcessSession> childSession; std::unique_lock<std::mutex> lock(_availableChildSessionMutex); - std::cout << Util::logPrefix() << "_availableChildSessions size=" << _availableChildSessions.size() << std::endl; + std::cout << Util::logPrefix() << "waiting for a child session permission for " << Thread::currentTid() << std::endl; + while (nRequest-- && !bFound) + { + _availableChildSessionCV.wait_for( + lock, + std::chrono::milliseconds(2000), + [&bFound] + { + return (bFound = _availableChildSessions.find(Thread::currentTid()) != _availableChildSessions.end()); + }); + + if (!bFound) + { + std::cout << Util::logPrefix() << "trying ..." << nRequest << std::endl; + // request again new URL session + std::string aMessage = "request " + std::to_string(Thread::currentTid()) + " " + _docURL + "\r\n"; + Util::writeFIFO(LOOLWSD::writerBroker, aMessage.c_str(), aMessage.length()); + } + } - if (_availableChildSessions.size() == 0) + if ( bFound ) { - std::cout << Util::logPrefix() << "waiting for a child session to become available" << std::endl; - _availableChildSessionCV.wait(lock, [] { return _availableChildSessions.size() > 0; }); - std::cout << Util::logPrefix() << "waiting done" << std::endl; + std::cout << Util::logPrefix() << "waiting child session permission, done!" << std::endl; + childSession = _availableChildSessions[Thread::currentTid()]; + _availableChildSessions.erase(Thread::currentTid()); } - childSession = *(_availableChildSessions.begin()); - _availableChildSessions.erase(childSession); lock.unlock(); - if (_availableChildSessions.size() == 0 && !LOOLWSD::doTest) + if ( !nRequest && !bFound ) { - LOOLWSD::_namedMutexLOOL.lock(); - std::cout << Util::logPrefix() << "No available child sessions, queue new child session" << std::endl; - LOOLWSD::_sharedForkChild.begin()[0] = LOOLWSD::_numPreSpawnedChildren; - LOOLWSD::_namedMutexLOOL.unlock(); + // it cannot get connected. shutdown. + Util::shutdownWebSocket(*_ws); + return; } // Assume a valid URI diff --git a/loolwsd/MasterProcessSession.hpp b/loolwsd/MasterProcessSession.hpp index ec5ff0d84..4b9329aa5 100644 --- a/loolwsd/MasterProcessSession.hpp +++ b/loolwsd/MasterProcessSession.hpp @@ -42,10 +42,6 @@ public: */ std::string getSaveAs(); - // Sessions to pre-spawned child processes that have connected but are not yet assigned a - // document to work on. - static std::set<std::shared_ptr<MasterProcessSession>> _availableChildSessions; - protected: bool invalidateTiles(const char *buffer, int length, Poco::StringTokenizer& tokens); @@ -67,6 +63,9 @@ public: // per document being edited (i.e., per child process). std::weak_ptr<MasterProcessSession> _peer; + // Sessions to pre-spawned child processes that have connected but are not yet assigned a + // document to work on. + static std::map<Poco::Thread::TID, std::shared_ptr<MasterProcessSession>> _availableChildSessions; static std::mutex _availableChildSessionMutex; static std::condition_variable _availableChildSessionCV; commit 81c346437b6c5980dabb9a70d324a2183a364f74 Author: Henry Castro <hcas...@collabora.com> AuthorDate: Sat Dec 19 17:20:04 2015 -0500 Commit: Ashod Nakashian <ashod.nakash...@collabora.co.uk> CommitDate: Mon Dec 21 11:18:43 2015 -0500 loolwsd: LOOLBroker process added Change-Id: Ia7332761766026599b8ef415652874371938d311 diff --git a/loolwsd/.gitignore b/loolwsd/.gitignore index 2054b6abd..1461eea5d 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 000000000..df77fa867 --- /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; + } ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits