X7ROOT File Manager
Current Path:
/opt/cpanel/ea-ruby27/src/passenger-release-6.1.2/src/cxx_supportlib
opt
/
cpanel
/
ea-ruby27
/
src
/
passenger-release-6.1.2
/
src
/
cxx_supportlib
/
??
..
??
Algorithms
??
AppLocalConfigFileUtils.h
(4.54 KB)
??
AppTypeDetector
??
BackgroundEventLoop.cpp
(9.83 KB)
??
BackgroundEventLoop.h
(2.13 KB)
??
ConfigKit
??
Constants.h
(4.82 KB)
??
Constants.h.cxxcodebuilder
(1.96 KB)
??
DataStructures
??
Exceptions.cpp
(6.36 KB)
??
Exceptions.h
(7.52 KB)
??
FileDescriptor.h
(8.85 KB)
??
FileTools
??
Hooks.h
(4.88 KB)
??
IOTools
??
InstanceDirectory.h
(9.11 KB)
??
Integrations
??
JsonTools
??
LoggingKit
??
LveLoggingDecorator.h
(3.29 KB)
??
MemoryKit
??
ProcessManagement
??
README.md
(199 B)
??
RandomGenerator.h
(4.9 KB)
??
ResourceLocator.h
(5.75 KB)
??
SafeLibev.h
(7.83 KB)
??
SecurityKit
??
ServerKit
??
StaticString.h
(8.84 KB)
??
StrIntTools
??
SystemTools
??
Utils
??
Utils.cpp
(9.07 KB)
??
Utils.h
(4.05 KB)
??
WatchdogLauncher.cpp
(3.86 KB)
??
WatchdogLauncher.h
(16.53 KB)
??
WrapperRegistry
??
oxt
??
vendor-copy
??
vendor-modified
Editing: WatchdogLauncher.h
/* * Phusion Passenger - https://www.phusionpassenger.com/ * Copyright (c) 2010-2025 Asynchronous B.V. * * "Passenger", "Phusion Passenger" and "Union Station" are registered * trademarks of Asynchronous B.V. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef _PASSENGER_WATCHDOG_LAUNCHER_HPsg #define _PASSENGER_WATCHDOG_LAUNCHER_HPsg #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include "JsonTools/CBindings.h" #ifdef __cplusplus extern "C" { #endif typedef enum { IM_APACHE, IM_NGINX, IM_STANDALONE } PsgIntegrationMode; typedef void PsgWatchdogLauncher; typedef void (*PsgAfterForkCallback)(void *, void *); PsgWatchdogLauncher *psg_watchdog_launcher_new(PsgIntegrationMode mode, char **error_message); int psg_watchdog_launcher_start(PsgWatchdogLauncher *launcher, const char *passengerRoot, PsgJsonValue *config, const PsgAfterForkCallback afterFork, void *callbackArgument, char **errorMessage); const char *psg_watchdog_launcher_get_core_address(PsgWatchdogLauncher *launcher, unsigned int *size); const char *psg_watchdog_launcher_get_core_password(PsgWatchdogLauncher *launcher, unsigned int *size); const char *psg_watchdog_launcher_get_instance_dir(PsgWatchdogLauncher *launcher, unsigned int *size); pid_t psg_watchdog_launcher_get_pid(PsgWatchdogLauncher *launcher); void psg_watchdog_launcher_detach(PsgWatchdogLauncher *launcher); void psg_watchdog_launcher_free(PsgWatchdogLauncher *launcher); #ifdef __cplusplus } /* extern "C" */ #endif #ifdef __cplusplus #include <boost/function.hpp> #include <oxt/system_calls.hpp> #include <oxt/backtrace.hpp> #include <string> #include <vector> #include <jsoncpp/json.h> #include <Constants.h> #include <FileDescriptor.h> #include <Exceptions.h> #include <ResourceLocator.h> #include <LoggingKit/LoggingKit.h> #include <LoggingKit/Context.h> #include <ProcessManagement/Utils.h> #include <Utils.h> #include <IOTools/IOUtils.h> #include <IOTools/MessageIO.h> #include <Utils/Timer.h> #include <Utils/ScopeGuard.h> #include <Utils/ClassUtils.h> namespace Passenger { using namespace std; using namespace boost; using namespace oxt; /** * Utility class for starting various the Passenger watchdog. */ class WatchdogLauncher { /** * Whether the starter process is Apache, Nginx or * Passenger Standalone. */ P_RO_PROPERTY(private, PsgIntegrationMode, IntegrationMode); /** * The watchdog's PID. Equals 0 if the watchdog hasn't been started yet * or if `detach()` is called. */ P_RO_PROPERTY(private, pid_t, Pid); // Note: the use of `CONST_REF` in the properties below is intentional. // The C getter functions return the string pointer directly. /** * The address on which the Passenger core listens for HTTP requests, * and the corresponding password. * * Only valid when `getPid() != 0`. */ P_RO_PROPERTY_CONST_REF(private, string, CoreAddress); P_RO_PROPERTY_CONST_REF(private, string, CorePassword); /** * The path to the instance directory that the Watchdog has created. * * Only valid when `getPid() != 0`. */ P_RO_PROPERTY_CONST_REF(private, string, InstanceDir); private: /** The watchdog's feedback file descriptor. */ FileDescriptor feedbackFd; /** * Safely dup2() the given file descriptor to 3 (FEEDBACK_FD). */ void installFeedbackFd(const FileDescriptor &fd) { if (fd != FEEDBACK_FD && syscalls::dup2(fd, FEEDBACK_FD) == -1) { int e = errno; try { writeArrayMessage(fd, "system error", "dup2() failed", toString(e).c_str(), NULL); _exit(1); } catch (...) { fprintf(stderr, "Passenger WatchdogLauncher: dup2() failed: %s (%d)\n", strerror(e), e); fflush(stderr); _exit(1); } } } /** * Call this if the watchdog seems to have crashed. This function will try * to determine whether the watchdog is still running, whether it crashed * with a signal, etc. If it has detected that the watchdog is no longer running * then it will set `pid` to -1. */ void inspectWatchdogCrashReason(pid_t &pid) { boost::this_thread::disable_interruption di; boost::this_thread::disable_syscall_interruption dsi; int ret, status; /* Upon noticing that something went wrong, the watchdog * or its subprocesses might still be writing out an error * report, so we wait a while before killing the watchdog. */ ret = timedWaitPid(pid, &status, 5000); if (ret == 0) { /* Looks like the watchdog didn't crash and is still running. */ throw RuntimeException( "Unable to start the " PROGRAM_NAME " watchdog: " "it froze during startup and reported an unknown error"); } else if (ret != -1 && WIFSIGNALED(status)) { /* Looks like a crash which caused a signal. */ pid = -1; throw RuntimeException( "Unable to start the " PROGRAM_NAME " watchdog: " "it seems to have been killed with signal " + getSignalName(WTERMSIG(status)) + " during startup"); } else if (ret == -1) { /* Looks like it exited for a different reason and has no exit code. */ pid = -1; throw RuntimeException( "Unable to start the " PROGRAM_NAME " watchdog: " "it seems to have crashed during startup for an unknown reason"); } else { /* Looks like it exited for a different reason, but has an exit code. */ pid = -1; throw RuntimeException( "Unable to start the " PROGRAM_NAME " watchdog: " "it seems to have crashed during startup for an unknown reason, " "with exit code " + toString(WEXITSTATUS(status))); } } void throwEnrichedWatchdogFailReason(const ResourceLocator &locator, const string &simpleReason) { if (mIntegrationMode == IM_STANDALONE) { throw RuntimeException("Unable to start " PROGRAM_NAME ": " + simpleReason + ". This probably means that your " SHORT_PROGRAM_NAME " installation is broken or incomplete. Please try reinstalling " SHORT_PROGRAM_NAME); } else { string passengerRootConfig; string docURL; if (mIntegrationMode == IM_APACHE) { passengerRootConfig = "PassengerRoot"; docURL = "https://www.phusionpassenger.com/library/config/apache/reference/#passengerroot"; } else { passengerRootConfig = "passenger_root"; docURL = "https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_root"; } string message = "Unable to start " PROGRAM_NAME ": " + simpleReason + ". There may be different causes for this:\n\n" " - Your '" + passengerRootConfig + "' setting is set to the wrong value." " Please see " + docURL + " to learn how to fix the value.\n"; if (!locator.getBuildSystemDir().empty()) { message.append(" - The " AGENT_EXE " binary is not compiled." " Please run this command to compile it: " + locator.getBinDir() + "/passenger-config compile-agent\n"); } message.append(" - Your " SHORT_PROGRAM_NAME " installation is broken or incomplete." " Please reinstall " SHORT_PROGRAM_NAME "."); throw RuntimeException(message); } } static void killProcessGroupAndWait(pid_t *pid, unsigned long long timeout = 0) { if (*pid != -1 && (timeout == 0 || timedWaitPid(*pid, NULL, timeout) <= 0)) { boost::this_thread::disable_syscall_interruption dsi; syscalls::killpg(*pid, SIGKILL); syscalls::waitpid(*pid, NULL, 0); *pid = -1; } } /** * Behaves like `waitpid(pid, status, WNOHANG)`, but waits at most * `timeout` miliseconds for the process to exit. */ static int timedWaitPid(pid_t pid, int *status, unsigned long long timeout) { Timer<SystemTime::GRAN_10MSEC> timer; int ret; do { ret = syscalls::waitpid(pid, status, WNOHANG); if (ret > 0 || ret == -1) { return ret; } else { syscalls::usleep(10000); } } while (timer.elapsed() < timeout); return 0; // timed out } public: /** * Construct a WatchdogLauncher object. The watchdog won't be started * until you call `start()`. */ WatchdogLauncher(PsgIntegrationMode _integrationMode) : mIntegrationMode(_integrationMode), mPid(0) { } ~WatchdogLauncher() { if (mPid != 0) { boost::this_thread::disable_syscall_interruption dsi; /* Send a message down the feedback fd to tell the watchdog * that we're shutting down cleanly. Closing the fd without * sending anything indicates an unclean shutdown. */ syscalls::write(feedbackFd, "c", 1); feedbackFd.close(); syscalls::waitpid(mPid, NULL, 0); } } const char *getIntegrationModeString() const { switch (mIntegrationMode) { case IM_APACHE: return "apache"; case IM_NGINX: return "nginx"; case IM_STANDALONE: return "standalone"; default: return "unknown"; } } /** * Start the agents through the watchdog. * * @throws SystemException Something went wrong. * @throws IOException Something went wrong while communicating with one * of the agents during its initialization phase. * @throws RuntimeException Something went wrong. */ void start(const string &passengerRoot, const Json::Value &extraConfig = Json::Value(), const boost::function<void ()> &afterFork = boost::function<void ()>()) { TRACE_POINT(); boost::this_thread::disable_interruption di; boost::this_thread::disable_syscall_interruption dsi; ResourceLocator locator(passengerRoot); string agentFilename; try { agentFilename = locator.findSupportBinary(AGENT_EXE); } catch (const Passenger::RuntimeException &e) { throwEnrichedWatchdogFailReason(locator, e.what()); } SocketPair fds; int e; pid_t pid; Json::Value::const_iterator it; Json::Value config; config["web_server_control_process_pid"] = getpid(); config["integration_mode"] = getIntegrationModeString(); config["passenger_root"] = passengerRoot; config["log_level"] = (int) LoggingKit::getLevel(); for (it = extraConfig.begin(); it != extraConfig.end(); it++) { config[it.name()] = *it; } fds = createUnixSocketPair(__FILE__, __LINE__); pid = syscalls::fork(); if (pid == 0) { // Child /* Become the session leader so that Apache can't kill the * watchdog with killpg() during shutdown, so that a * Ctrl-C only affects the web server, and so that * we can kill all of our subprocesses in a single killpg(). */ setsid(); /* We don't know how the web server or the environment affect * signal handlers and the signal mask, so reset this stuff * just in case. Also, we reset the signal handlers before * closing all file descriptors, in order to prevent bugs * like this: https://github.com/phusion/passenger/pull/97 */ resetSignalHandlersAndMask(); // Make sure the feedback fd is 3 and close all file descriptors // except stdin, stdout, stderr and 3. close(fds[0]); installFeedbackFd(fds[1]); setenv("PASSENGER_USE_FEEDBACK_FD", "true", 1); if (afterFork) { afterFork(); } closeAllFileDescriptors(FEEDBACK_FD); execl(agentFilename.c_str(), AGENT_EXE, "watchdog", // Some extra space to allow the child process to change its process title. " ", (char *) 0); e = errno; try { writeArrayMessage(FEEDBACK_FD, "exec error", toString(e).c_str(), NULL); _exit(1); } catch (...) { fprintf(stderr, "Passenger WatchdogLauncher: could not execute %s: %s (%d)\n", agentFilename.c_str(), strerror(e), e); fflush(stderr); _exit(1); } } else if (pid == -1) { // Error e = errno; throw SystemException("Cannot fork a new process", e); } else { // Parent UPDATE_TRACE_POINT(); FileDescriptor feedbackFd = fds[0]; vector<string> args; bool result = false; ScopeGuard guard(boost::bind(&WatchdogLauncher::killProcessGroupAndWait, &pid, 0)); fds[1].close(); P_LOG_FILE_DESCRIPTOR_PURPOSE(feedbackFd, "WatchdogLauncher: feedback FD"); /****** Send arguments to watchdog through the feedback channel ******/ UPDATE_TRACE_POINT(); /* Here we don't care about EPIPE and ECONNRESET errors. The watchdog * could have sent an error message over the feedback fd without * reading the arguments. We'll notice that later. */ try { writeScalarMessage(feedbackFd, config.toStyledString()); } catch (const SystemException &e) { if (e.code() != EPIPE && e.code() != ECONNRESET) { inspectWatchdogCrashReason(pid); } } /****** Read agents information report ******/ boost::this_thread::restore_interruption ri(di); boost::this_thread::restore_syscall_interruption rsi(dsi); UPDATE_TRACE_POINT(); try { result = readArrayMessage(feedbackFd, args); } catch (const SystemException &ex) { if (ex.code() == ECONNRESET) { inspectWatchdogCrashReason(pid); } else { killProcessGroupAndWait(&pid, 5000); guard.clear(); throw SystemException("Unable to start the " PROGRAM_NAME " watchdog: " "unable to read its startup information report", ex.code()); } } if (!result) { UPDATE_TRACE_POINT(); inspectWatchdogCrashReason(pid); } if (args[0] == "Agents information") { UPDATE_TRACE_POINT(); if (args.size() != 1) { throw RuntimeException("Unable to start the " PROGRAM_NAME " watchdog: " "it belongs to an incompatible version of " SHORT_PROGRAM_NAME ". Please fully upgrade " SHORT_PROGRAM_NAME "."); } string jsonData; try { result = readScalarMessage(feedbackFd, jsonData); } catch (const SystemException &ex) { if (ex.code() == ECONNRESET) { inspectWatchdogCrashReason(pid); } else { killProcessGroupAndWait(&pid, 5000); guard.clear(); throw SystemException("Unable to start the " PROGRAM_NAME " watchdog: " "unable to read its startup information report", ex.code()); } } if (!result) { UPDATE_TRACE_POINT(); inspectWatchdogCrashReason(pid); } Json::Value doc; Json::Reader reader; if (!reader.parse(jsonData, doc)) { throw RuntimeException("Unable to start the " PROGRAM_NAME " watchdog: " "unable to parse its startup information report as valid JSON: " + reader.getFormattedErrorMessages() + "\n" "Raw data: \"" + cEscapeString(jsonData) + "\""); } mPid = pid; this->feedbackFd = feedbackFd; mCoreAddress = doc["core_address"].asString(); mCorePassword = doc["core_password"].asString(); mInstanceDir = doc["instance_dir"].asString(); guard.clear(); } else if (args[0] == "Watchdog startup error") { killProcessGroupAndWait(&pid, 5000); guard.clear(); throw RuntimeException("Unable to start the " PROGRAM_NAME " watchdog " "because it encountered the following error during startup: " + args[1]); } else if (args[0] == "system error") { killProcessGroupAndWait(&pid, 5000); guard.clear(); throw SystemException(args[1], atoi(args[2])); } else if (args[0] == "exec error") { e = atoi(args[1]); killProcessGroupAndWait(&pid, 5000); guard.clear(); if (e == ENOENT) { throwEnrichedWatchdogFailReason(locator, "Executable " + agentFilename + " not found."); } else { throw SystemException("Unable to start the " PROGRAM_NAME " watchdog (" + agentFilename + ")", e); } } else { UPDATE_TRACE_POINT(); killProcessGroupAndWait(&pid, 5000); guard.clear(); throw RuntimeException("The " PROGRAM_NAME " watchdog sent an unknown feedback message '" + args[0] + "'"); } } } /** * Close any file descriptors that this object has, and make it so that * the destructor doesn't try to shut down the watchdog. * * @post getPid() == 0 */ void detach() { feedbackFd.close(); mPid = 0; } }; } // namespace Passenger #endif /* __cplusplus */ #endif /* _PASSENGER_WATCHDOG_LAUNCHER_HPsg */
Upload File
Create Folder