/*############################################################################## Copyright (C) 2011 HPCC Systems. All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . ############################################################################## */ #pragma warning (disable : 4786) #if defined(_WIN32) && defined(_DEBUG) //#include #endif //Jlib #include "jliball.hpp" //CRT / OS #ifndef _WIN32 #include #include #include #include #endif //SCM Interfaces #include "esp.hpp" // We can use "work" as the first parameter when debugging. #define ESP_SINGLE_PROCESS //ESP Core #include "espp.hpp" #include "espcfg.ipp" #include "esplog.hpp" #include "espcontext.hpp" #include "build-config.h" #ifdef _WIN32 /******************************************* _WIN32 *******************************************/ #ifdef ESP_SINGLE_PROCESS int start_init_main(int argc, char** argv, int (*init_main_func)(int,char**)) { return init_main_func(argc, argv); } #define START_WORK_MAIN(config, server, result) result = work_main((config), (server)); #define SET_ESP_SIGNAL_HANDLER(sig, handler) #define RESET_ESP_SIGNAL_HANDLER(sig, handler) #else //!ESP_SINGLE_PROCESS #define SET_ESP_SIGNAL_HANDLER(sig, handler) #define RESET_ESP_SIGNAL_HANDLER(sig, handler) int start_init_main(int argc, char** argv, int (*init_main_func)(int, char**)) { if(argc > 1 && !strcmp(argv[1], "work")) { char** newargv = new char*[argc - 1]; newargv[0] = argv[0]; for(int i = 2; i < argc; i++) { newargv[i - 1] = argv[i]; } int rtcode = init_main_func(argc - 1, newargv); delete[] newargv; return rtcode; } else { StringBuffer command; command.append(argv[0]); command.append(" work "); for(int i = 1; i < argc; i++) { command.append(argv[i]); command.append(" "); } DWORD exitcode = 0; while(true) { PROGLOG("Starting working process: %s", command.str()); PROCESS_INFORMATION process; STARTUPINFO si; GetStartupInfo(&si); if(!CreateProcess(NULL, (char*)command.str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &process)) { ERRLOG("Process failed: %d\r\n",GetLastError()); exit(-1); } WaitForSingleObject(process.hProcess,INFINITE); GetExitCodeProcess(process.hProcess, &exitcode); PROGLOG("Working process exited, exitcode=%d", exitcode); if(exitcode == TERMINATE_EXITCODE) { DBGLOG("This is telling the monitoring process to exit too. Exiting once and for all...."); exit(exitcode); } CloseHandle(process.hProcess); CloseHandle(process.hThread); Sleep(1000); } } } #define START_WORK_MAIN(config, server, result) result = work_main((config), (server)); #endif //!ESP_SINGLE_PROCESS #else /***************************************************** LINUX ****************************************************/ #define SET_ESP_SIGNAL_HANDLER(sig, handler) signal(sig, handler) #define RESET_ESP_SIGNAL_HANDLER(sig, handler) signal(sig, handler) int start_init_main(int argc, char** argv, int (*init_main_func)(int,char**)) { return init_main_func(argc, argv); } int work_main(CEspConfig& config, CEspServer& server); int do_work_main(CEspConfig& config, CEspServer& server) { int result; int numchildren = 0; pid_t childpid=0; createworker: childpid = fork(); if(childpid < 0) { ERRLOG("Unable to create new process"); result = -1; } else if(childpid == 0) { result = work_main(config, server); } else { DBGLOG("New process generated, pid=%d", childpid); numchildren++; if(numchildren < MAX_CHILDREN) goto createworker; int status; childpid = wait3(&status, 0, NULL); DBGLOG("Attention: child process exited, pid = %d", childpid); numchildren--; DBGLOG("Bringing up a new process..."); sleep(1); goto createworker; } return result; } #define START_WORK_MAIN(config, server, result) result = do_work_main(config, server) #endif void brokenpipe_handler(int sig) { //Reset the signal first RESET_ESP_SIGNAL_HANDLER(SIGPIPE, brokenpipe_handler); DBGLOG("Broken Pipe - remote side closed the socket"); } int work_main(CEspConfig& config, CEspServer& server) { server.start(); DBGLOG("ESP server started."); server.waitForExit(config); server.stop(true); config.stopping(); config.clear(); return 0; } void openEspLogFile(const char* logdir, IPropertyTree* globals) { StringBuffer logbase; StringBuffer alias; if(logdir && *logdir) { logbase.append(logdir); alias.append(logdir); } logbase.append("esp_main"); alias.append("esp.log"); queryLogMsgManager()->addMonitorOwn(getRollingFileLogMsgHandler(logbase.str(), ".log", MSGFIELD_STANDARD, false, true, NULL, alias.str()), getCategoryLogMsgFilter(MSGAUD_all, MSGCLS_all, DefaultDetail)); if (globals->getPropBool("@enableSysLog", false)) UseSysLogForOperatorMessages(); DBGLOG("Esp starting %s", BUILD_TAG); } static void usage() { puts("ESP - Enterprise Service Platform server. (C) 2001-2011, HPCC Systems."); puts("Usage:"); puts(" esp [options]"); puts("Options:"); puts(" -?/-h: show this help page"); puts(" interactive: start in interactive mode (pop up error dialog when exception occurs)"); puts(" config=: specify the config file name [default: esp.xml]"); puts(" process=: specify the process name in the config [default: the 1st process]"); exit(1); } int init_main(int argc, char* argv[]) { InitModuleObjects(); Owned inputs = createProperties(true); bool interactive = false; for (int i = 1; i < argc; i++) { if (stricmp(argv[i], "-?")==0 || stricmp(argv[i], "-h")==0 || stricmp(argv[i], "-help")==0 || stricmp(argv[i], "/?")==0 || stricmp(argv[i], "/h")==0) usage(); else if(stricmp(argv[i], "interactive") == 0) interactive = true; else if (strchr(argv[i],'=')) { inputs->loadProp(argv[i]); } else { fprintf(stderr, "Unknown option: %s", argv[i]); return 0; } } int result = -1; #ifdef _WIN32 if (!interactive) ::SetErrorMode(SEM_NOGPFAULTERRORBOX|SEM_FAILCRITICALERRORS); #endif SET_ESP_SIGNAL_HANDLER(SIGPIPE, brokenpipe_handler); bool SEHMappingEnabled = false; CEspAbortHandler abortHandler; Owned sentinelFile = createSentinelTarget(); removeSentinelFile(sentinelFile); Owned config; Owned server; try { const char* cfgfile = NULL; const char* procname = NULL; if(inputs.get()) { if(inputs->hasProp("config")) cfgfile = inputs->queryProp("config"); if(inputs->hasProp("process")) procname = inputs->queryProp("process"); } if(!cfgfile || !*cfgfile) cfgfile = "esp.xml"; Owned envpt= createPTreeFromXMLFile(cfgfile, ipt_caseInsensitive); Owned procpt = NULL; if (envpt) { envpt->addProp("@config", cfgfile); StringBuffer xpath; if (procname==NULL || strcmp(procname, ".")==0) xpath.appendf("Software/EspProcess[1]"); else xpath.appendf("Software/EspProcess[@name=\"%s\"]", procname); DBGLOG("Using ESP configuration section [%s]", xpath.str()); procpt.set(envpt->queryPropTree(xpath.str())); if (!procpt) throw MakeStringException(-1, "Config section [%s] not found", xpath.str()); } else throw MakeStringException(-1, "Failed to load config file %s", cfgfile); StringBuffer logdir; if(procpt->hasProp("@name")) { StringBuffer espNameStr; procpt->getProp("@name", espNameStr); if (!getConfigurationDirectory(envpt->queryPropTree("Software/Directories"), "log", "esp", espNameStr.str(), logdir)) { logdir.clear(); } } const char* build_ver = BUILD_TAG; setBuildVersion(build_ver); const char* build_level = BUILD_LEVEL; setBuildLevel(build_level); if(logdir.length() == 0) { if(procpt->hasProp("@logDir")) procpt->getProp("@logDir", logdir); } if(logdir.length() == 0) logdir.append("."); if(stricmp(logdir.str(), ".") != 0) { recursiveCreateDirectory(logdir.str()); } if(logdir.charAt(logdir.length() - 1) != PATHSEPCHAR) logdir.append(PATHSEPCHAR); openEspLogFile(logdir.str(), procpt.get()); StringBuffer componentfilesDir; if(procpt->hasProp("@componentfilesDir")) procpt->getProp("@componentfilesDir", componentfilesDir); if(componentfilesDir.length() > 0 && strcmp(componentfilesDir.str(), ".") != 0) { DBGLOG("componentfiles are under %s", componentfilesDir.str()); setCFD(componentfilesDir.str()); } StringBuffer sehsetting; procpt->getProp("@enableSEHMapping", sehsetting); if(!interactive && sehsetting.length() > 0 && (stricmp(sehsetting.str(), "true") == 0 || stricmp(sehsetting.str(), "1") == 0)) SEHMappingEnabled = true; if(SEHMappingEnabled) EnableSEHtoExceptionMapping(); CEspConfig* cfg = new CEspConfig(inputs.getLink(), envpt.getLink(), procpt.getLink(), false); if(cfg && cfg->isValid()) { config.setown(cfg); abortHandler.setConfig(cfg); } } catch(IException* e) { StringBuffer description; ERRLOG("ESP Unhandled IException (%d -- %s)", e->errorCode(), e->errorMessage(description).str()); e->Release(); return -1; } catch (...) { ERRLOG("ESP Unhandled General Exception."); return -1; } if (config && config->isValid()) { PROGLOG("Configuring Esp Platform..."); try { CEspServer *srv = new CEspServer(config); if(SEHMappingEnabled) srv->setSavedSEHHandler(SEHMappingEnabled); server.setown(srv); abortHandler.setServer(srv); setEspContainer(server.get()); config->loadAll(); config->bindServer(*server.get(), *server.get()); } catch(IException* e) { StringBuffer description; ERRLOG("ESP Unhandled IException (%d -- %s)", e->errorCode(), e->errorMessage(description).str()); e->Release(); return -1; } catch (...) { ERRLOG("ESP Unhandled General Exception."); return -1; } writeSentinelFile(sentinelFile); result = work_main(*config, *server.get()); } else { ERRLOG("!!! Unable to load ESP configuration."); } return result; } //command line arguments: // [pre] if "work", special init behavior, but removed before init_main // [1] process name // [2] config location - local file name or dali address // [3] config location type - "dali" or "" int main(int argc, char* argv[]) { start_init_main(argc, argv, init_main); stopPerformanceMonitor(); UseSysLogForOperatorMessages(false); releaseAtoms(); return 0; }