00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef _MSC_VER
00011 #include <fcntl.h>
00012 #include <unistd.h>
00013 #include <sys/stat.h>
00014 #endif
00015
00016 #ifdef _MSC_VER
00017 #include <windows.h>
00018 #include <direct.h>
00019 #endif
00020
00021
00022 #ifndef _MSC_VER
00023 #include <sys/mman.h>
00024 #include <string.h>
00025 #endif
00026
00027 #include <pion/PionConfig.hpp>
00028
00029 #ifdef PION_HAVE_SSL
00030 #include <openssl/ssl.h>
00031
00032
00033
00034 #endif
00035
00036 #ifndef SYSCONFDIR
00037 #define SYSCONFDIR "/usr/local/etc"
00038 #endif
00039
00040 #include <iostream>
00041 #include <boost/filesystem/operations.hpp>
00042 #include "PlatformConfig.hpp"
00043 #include "../../net/utils/ShutdownManager.hpp"
00044
00045 using namespace std;
00046 using namespace pion;
00047 using namespace pion::net;
00048 using namespace pion::platform;
00049 using namespace pion::server;
00050
00051
00052 void daemonize_server(void);
00053 void argument_error(void);
00054 int run(bool run_as_daemon, bool lock_memory, const std::string& platform_config_file);
00055
00056 int parse_args(int argc, char *argv[], bool& run_as_daemon, bool& lock_memory, std::string& platform_config_file)
00057 {
00058
00059 run_as_daemon = false;
00060 lock_memory = false;
00061
00062 #ifdef _MSC_VER
00063 platform_config_file = "config\\platform.xml";
00064 #else
00065 platform_config_file = "/etc/pion/platform.xml";
00066 if (! boost::filesystem::exists(platform_config_file) )
00067 platform_config_file = std::string(SYSCONFDIR) + "/pion/platform.xml";
00068 #endif
00069
00070 for (int argnum=1; argnum < argc; ++argnum) {
00071 if (argv[argnum][0] == '-') {
00072 if (argv[argnum][1] == 'D') {
00073 run_as_daemon = true;
00074 } else if (argv[argnum][1] == 'M') {
00075 lock_memory = true;
00076 } else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
00077 platform_config_file = boost::filesystem::system_complete(argv[++argnum]).normalize().file_string();
00078 } else if (strncmp(argv[argnum], "--version", 9) == 0) {
00079 std::cout << "pion version " << PION_VERSION << std::endl;
00080 return 1;
00081 } else {
00082 argument_error();
00083 return 1;
00084 }
00085 } else {
00086 argument_error();
00087 return 1;
00088 }
00089 }
00090
00091 return 0;
00092 }
00093
00095 #ifdef _MSC_VER
00096 #define SVCNAME TEXT("Pion")
00097
00099 bool g_lock_memory = false;
00100 std::string g_platform_config_file;
00101
00103 SERVICE_STATUS gSvcStatus;
00104 SERVICE_STATUS_HANDLE gSvcStatusHandle;
00105
00107 void report_service_status( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint );
00108
00110 void WINAPI service_control_handler( DWORD dwCtrl )
00111 {
00112
00113 switch(dwCtrl) {
00114 case SERVICE_CONTROL_STOP:
00115 case SERVICE_CONTROL_SHUTDOWN:
00116 report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
00117
00118 main_shutdown_manager.shutdown();
00119 return;
00120
00121 case SERVICE_CONTROL_INTERROGATE:
00122
00123 break;
00124
00125 default:
00126 break;
00127 }
00128
00129 report_service_status(gSvcStatus.dwCurrentState, NO_ERROR, 0);
00130 }
00131
00132 void report_service_status( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint )
00133 {
00134 static DWORD dwCheckPoint = 1;
00135
00136
00137 gSvcStatus.dwCurrentState = dwCurrentState;
00138 gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
00139 gSvcStatus.dwWaitHint = dwWaitHint;
00140
00141 if (dwCurrentState == SERVICE_START_PENDING)
00142 gSvcStatus.dwControlsAccepted = 0;
00143 else
00144 gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
00145
00146 if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED) )
00147 gSvcStatus.dwCheckPoint = 0;
00148 else
00149 gSvcStatus.dwCheckPoint = dwCheckPoint++;
00150
00151
00152 SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
00153 }
00154
00155 void service_report_event(LPTSTR szFunction)
00156 {
00157
00158 }
00159
00160 void WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
00161 {
00162
00163 gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, service_control_handler );
00164
00165 if( !gSvcStatusHandle ){
00166 PION_ASSERT( gSvcStatusHandle );
00167 service_report_event(TEXT("RegisterServiceCtrlHandler"));
00168 return;
00169 }
00170
00171
00172 gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
00173 gSvcStatus.dwServiceSpecificExitCode = 0;
00174
00175
00176 report_service_status( SERVICE_START_PENDING, NO_ERROR, 3000 );
00177
00178 bool run_as_daemon = false;
00179 bool lock_memory = false;
00180
00181 #ifdef _MSC_VER
00182 std::string platform_config_file("config\\platform.xml");
00183 #else
00184 std::string platform_config_file("/etc/pion/platform.xml");
00185 #endif
00186
00187 run( true, g_lock_memory, g_platform_config_file );
00188
00189 report_service_status( SERVICE_STOPPED, NO_ERROR, 0 );
00190 }
00191 #endif
00192
00194 int main (int argc, char *argv[])
00195 {
00196 bool run_as_daemon = false;
00197 bool lock_memory = false;
00198
00199 #ifdef _MSC_VER
00200 std::string platform_config_file("config\\platform.xml");
00201 #else
00202 std::string platform_config_file("/etc/pion/platform.xml");
00203 #endif
00204
00205 if(parse_args(argc, argv, run_as_daemon, lock_memory, platform_config_file) != 0)
00206 return 1;
00207
00208 #ifdef _MSC_VER
00209 if(run_as_daemon) {
00210
00211
00212 g_platform_config_file = platform_config_file;
00213 g_lock_memory = lock_memory;
00214
00215 SERVICE_TABLE_ENTRY DispatchTable[] =
00216 {
00217 { SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
00218 { NULL, NULL }
00219 };
00220
00221
00222 if (!StartServiceCtrlDispatcher( DispatchTable )) {
00223 service_report_event(("StartServiceCtrlDispatcher"));
00224 }
00225 return 0;
00226 }
00227 #endif
00228 return run(run_as_daemon, lock_memory, platform_config_file);
00229 }
00230
00231 int run (bool run_as_daemon, bool lock_memory, const std::string& platform_config_file)
00232 {
00233
00234 PionLogger pion_log(PION_GET_LOGGER("pion"));
00235
00236
00237
00238 PION_LOG_SETLEVEL_INFO(pion_log);
00239 PION_LOG_CONFIG_BASIC;
00240
00241
00242 PionLogger pion_main_log(PION_GET_LOGGER("pion.main"));
00243
00245 if (run_as_daemon)
00246 daemonize_server();
00247
00248
00249 #ifdef _MSC_VER
00250 SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
00251 #else
00252 signal(SIGPIPE, SIG_IGN);
00253 signal(SIGCHLD, SIG_IGN);
00254 signal(SIGTSTP, SIG_IGN);
00255 signal(SIGTTOU, SIG_IGN);
00256 signal(SIGTTIN, SIG_IGN);
00257 signal(SIGHUP, SIG_IGN);
00258 signal(SIGINT, handle_signal);
00259 signal(SIGTERM, handle_signal);
00260 #endif
00261
00262 #ifdef PION_HAVE_SSL
00263
00264 CRYPTO_malloc_init();
00265 SSL_library_init();
00266 #endif
00267
00268 #ifndef _MSC_VER
00269 if (lock_memory)
00270 if (mlockall(MCL_CURRENT | MCL_FUTURE))
00271 PION_LOG_FATAL(pion_main_log, "Failed to lock memory: " << strerror(errno));
00272 #endif
00273
00274
00275 try {
00276 PlatformConfig platform_cfg;
00277 try {
00278
00279 platform_cfg.setConfigFile(platform_config_file);
00280 platform_cfg.openConfigFile();
00281
00282 PION_LOG_INFO(pion_main_log, "Pion has started successfully (v" << PION_VERSION << ')');
00283 #ifdef _MSC_VER
00284 if(run_as_daemon)
00285 report_service_status( SERVICE_RUNNING, NO_ERROR, 0 );
00286 #endif
00287
00288 main_shutdown_manager.wait();
00289 } catch (std::exception& e) {
00290 PION_LOG_FATAL(pion_main_log, e.what());
00291 }
00292
00293 PION_LOG_INFO(pion_main_log, "Pion is shutting down");
00294 } catch (std::exception& e) {
00295 PION_LOG_FATAL(pion_main_log, e.what());
00296 }
00297 return 0;
00298 }
00299
00300 #ifdef _MSC_VER
00302 void daemonize_server(void)
00303 {
00304 gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, service_control_handler );
00305 if( !gSvcStatusHandle )
00306 {
00307 service_report_event(TEXT("RegisterServiceCtrlHandler"));
00308 return;
00309 }
00310
00311
00312 gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
00313 gSvcStatus.dwServiceSpecificExitCode = 0;
00314
00315
00316 report_service_status( SERVICE_START_PENDING, NO_ERROR, 20000 );
00317
00318
00319
00320 char exe_path[MAX_PATH];
00321 exe_path[0]=0;
00322 if( GetModuleFileName(NULL, exe_path, sizeof(exe_path)/sizeof(exe_path[0])) ) {
00323 char exe_dir[MAX_PATH], drive[MAX_PATH], filename[MAX_PATH];
00324 exe_dir[0]=0; drive[0] = 0; filename[0]=0;
00325 _splitpath( exe_path, drive, exe_dir, filename, NULL);
00326 SetCurrentDirectory( exe_dir );
00327 }
00328 }
00329 #else
00331 void daemonize_server(void)
00332 {
00333
00334
00335
00336
00337 if(getppid()==1) return;
00338
00339
00340 int i = fork();
00341 if (i<0) exit(1);
00342 if (i>0) exit(0);
00343
00344
00345
00346
00347 setsid();
00348
00349
00350 for (i=getdtablesize();i>=0;--i) close(i);
00351
00352
00353 i=open("/dev/null",O_RDWR); dup(i); dup(i);
00354
00355
00356 umask(027);
00357 }
00358 #endif
00359
00360
00362 void argument_error(void)
00363 {
00364 std::cerr << "usage: pion [-c PLATFORM_XML_FILE] [-D] [-M]" << std::endl;
00365 }