diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 8e80e321cf9c4070014a68b7370aeecc65cd53ae..cd3734b8e9aff702b331b37db8c997aae8ef7fbd 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -71,6 +71,8 @@ static unsigned long bytestream_id; DEFINE_LOGGER(logger, "NetworkPluginServer"); +static NetworkPluginServer *_server; + class NetworkConversation : public Conversation { public: NetworkConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) { @@ -128,7 +130,7 @@ class NetworkFactory : public Factory { wrap.SerializeToString(&MESSAGE); // Executes new backend -static unsigned long exec_(const std::string& exePath, const char *host, const char *port, const char *cmdlineArgs) { +static unsigned long exec_(const std::string& exePath, const char *host, const char *port, const char *log_id, const char *cmdlineArgs) { // BACKEND_ID is replaced with unique ID. The ID is increasing for every backend. std::string finalExePath = boost::replace_all_copy(exePath, "BACKEND_ID", boost::lexical_cast(backend_id++)); @@ -171,7 +173,7 @@ static unsigned long exec_(const std::string& exePath, const char *host, const c return 0; #else // Add host and port. - finalExePath += std::string(" --host ") + host + " --port " + port + " " + cmdlineArgs; + finalExePath += std::string(" --host ") + host + " --port " + port + " --service.backend_id=" + log_id + " " + cmdlineArgs; LOG4CXX_INFO(logger, "Starting new backend " << finalExePath); // Create array of char * from string using -lpopt library @@ -214,6 +216,7 @@ static void SigCatcher(int n) { // WARNING: Do not put LOG4CXX_ here, because it can lead to deadlock while ((result = waitpid(-1, &status, WNOHANG)) > 0) { if (result != 0) { + _server->handlePIDTerminated((unsigned long)result); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { // LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status)); @@ -251,6 +254,7 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa } NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager, DiscoItemsResponder *discoItemsResponder) { + _server = this; m_ftManager = ftManager; m_userManager = userManager; m_config = config; @@ -324,7 +328,7 @@ void NetworkPluginServer::start() { LOG4CXX_INFO(logger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); while (true) { - unsigned long pid = exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getCommandLineArgs().c_str()); + unsigned long pid = exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), "1", m_config->getCommandLineArgs().c_str()); LOG4CXX_INFO(logger, "Tried to spawn first backend with pid " << pid); LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); @@ -353,6 +357,8 @@ void NetworkPluginServer::start() { } } + m_pids.push_back(pid); + signal(SIGCHLD, SigCatcher); #endif // quit the while loop @@ -1660,6 +1666,57 @@ void NetworkPluginServer::sendPing(Backend *c) { // LOG4CXX_INFO(logger, "PING to " << c); } +void NetworkPluginServer::handlePIDTerminated(unsigned long pid) { + std::vector::iterator log_id_it; + log_id_it = std::find(m_pids.begin(), m_pids.end(), pid); + if (log_id_it != m_pids.end()) { + *log_id_it = 0; + } +} + +#ifndef _WIN32 + +static int sig_block_count = 0; +static sigset_t block_mask; + +static void __block_signals ( void ) +{ + static int init_done = 0; + + if ( (sig_block_count++) != 1 ) return; + + if ( init_done == 0 ) { + sigemptyset ( &block_mask ); + sigaddset ( &block_mask, SIGPIPE ); + sigaddset ( &block_mask, SIGHUP ); + sigaddset ( &block_mask, SIGINT ); + sigaddset ( &block_mask, SIGQUIT ); + sigaddset ( &block_mask, SIGTERM ); + sigaddset ( &block_mask, SIGABRT ); + sigaddset ( &block_mask, SIGCHLD ); + init_done = 1; + } + + sigprocmask ( SIG_BLOCK, &block_mask, NULL ); + return; +} + +static void __unblock_signals ( void ) +{ + sigset_t sigset; + + if ( (sig_block_count--) != 0 ) return; + sigprocmask ( SIG_UNBLOCK, &block_mask, NULL ); + + if ( sigpending ( &sigset ) == 0 ) { + if ( sigismember ( &sigset, SIGCHLD ) ) { + raise ( SIGCHLD ); + } + } +} + +#endif + NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUsers, bool longRun, bool check) { NetworkPluginServer::Backend *c = NULL; @@ -1692,7 +1749,29 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUser if (c == NULL && !m_startingBackend) { m_isNextLongRun = longRun; m_startingBackend = true; - exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getCommandLineArgs().c_str()); + +#ifndef _WIN32 + __block_signals(); +#endif + std::vector::iterator log_id_it; + log_id_it = std::find(m_pids.begin(), m_pids.end(), 0); + std::string log_id = ""; + if (log_id_it == m_pids.end()) { + log_id = boost::lexical_cast(m_pids.size() + 1); + } + else { + log_id = boost::lexical_cast(log_id_it - m_pids.begin() + 1); + } + unsigned long pid = exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), log_id.c_str(), m_config->getCommandLineArgs().c_str()); + if (log_id_it == m_pids.end()) { + m_pids.push_back(pid); + } + else { + *log_id_it = pid; + } +#ifndef _WIN32 + __unblock_signals(); +#endif } return c;