/* WebROaR - Ruby Application Server - http://webroar.in/ * Copyright (C) 2009 Goonj LLC * * This file is part of WebROaR. * * WebROaR is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * WebROaR 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WebROaR. If not, see . */ #include #include #include #include #include // wr_server object static wr_svr_t *server; /** Cleanup and destroy the Server */ static inline void cleanup(wr_svr_t *server) { LOG_FUNCTION // Delete 'webroar.sock' file remove(WR_TMP_SOCK_FILE); // Stop event loop ev_unloop(server->ebb_svr.loop, EVUNLOOP_ALL); // Destroy the Server structure wr_svr_free(server); // Delete 'webroar.pid' file remove(WR_PID_FILE); LOG_INFO("Shutting down network server. No more request can be served"); // Destroy logger object close_logger(); } /** Daemonize the process */ static inline void daemonize() { LOG_FUNCTION /* Our process ID and Session ID */ pid_t pid, sid; pid_t saved_pid = -1; if(saved_pid > 0) { printf("SERVER IS ALREADY RUNNING WITH PID %i",saved_pid); exit(-1); } LOG_DEBUG(4,"Calling fork"); /* Fork off the parent process */ pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) { exit(EXIT_SUCCESS); } /* Open any logs here */ /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { /* Log the failure */ exit(EXIT_FAILURE); } close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); int i=open("/dev/null",O_RDWR); /* open stdin and connect to /dev/null */ LOG_DEBUG(DEBUG,"i=%d",i); int j = dup(i); /* stdout */ LOG_DEBUG(DEBUG,"j=%d",j); j = dup(i); /* stderr */ LOG_DEBUG(DEBUG,"j=%d",j); //Log current pid char str[WR_SHORT_STR_LEN]; int pid_FD=open(WR_PID_FILE,O_RDWR|O_CREAT,0640); LOG_DEBUG(4,"FD for PID is %i",pid_FD); if (pid_FD<0) { LOG_ERROR(5,"CANNOT OPEN PID FILE:%s",strerror(errno)); exit(1); /* can not open */ } int lpk = lockf(pid_FD,F_TLOCK,0); if (lpk<0) { printf("SERVER ALREADY RUNNING..\n"); //can not lock exit(-1); } /* first instance continues */ sprintf(str,"%d\n",getpid()); write(pid_FD,str,strlen(str)); /* record pid to lockfile */ close(pid_FD); signal(SIGCHLD, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); /* Close out the standard file descriptors */ LOG_DEBUG(4,"Daemonize Server Done"); } /** Handle interrupt signal */ void sigproc() { LOG_DEBUG(4,"**************Caught Interrupt Signal************"); // clear keep alive flag. server->is_running = 0; } /** Handle segmentation fault */ void crash_handler(int sig) { void *array[WR_STACKTRACE_SIZE]; size_t size; char **bt_symbols; char bt_string[WR_STACKTRACE_SIZE * WR_LONG_STR_LEN * 2]; int i; sigset_t unblock_sig; LOG_ERROR(FATAL, "Got %d signal, trying to create core file.", sig); sigemptyset (&unblock_sig); sigaddset (&unblock_sig, SIGSEGV); sigprocmask (SIG_UNBLOCK, &unblock_sig, NULL); if(fork() == 0) { // child char cmd[64], core_file_name[48], timestamp[24]; int rv, sid; signal(SIGCHLD, SIG_DFL); sprintf(core_file_name, "/tmp/webroar-head"); if ( get_timestamp(timestamp) == 0 ) { strcat(core_file_name, "-"); strcat(core_file_name, timestamp); } #ifdef __APPLE__ sprintf(cmd, "gcore -c %s %ld", core_file_name, (long) getppid() ); #else sprintf(cmd, "gcore -o %s %ld", core_file_name, (long) getppid() ); #endif rv = system(cmd); if ( rv < 0 ) { LOG_ERROR(FATAL, "Core file creation failed, gcore might be missing... rv = %d, errno = %d, error = %s", rv, errno, strerror(errno)); } else { LOG_INFO("Core file - %s created", core_file_name); } /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { LOG_ERROR(SEVERE, "setsid() failed, errno = %d, description = %s", errno, strerror(errno)); exit(EXIT_FAILURE); } int i = 0; /* close all parent process fd except STDIN, STDOUT and STDERR */ for (i=getdtablesize(); i>=3; --i) { close(i); } sleep(5); LOG_INFO("Executing webroar restart"); rv = system("webroar restart"); if ( rv < 0 ) { LOG_ERROR(FATAL, "webroar restart failed, rv = %d, errno = %d, error = %s", rv, errno, strerror(errno)); } LOG_INFO("Return value of webroar restart is %d", rv); exit(0); } sleep(5); // get void*'s for all entries on the stack size = backtrace(array, WR_STACKTRACE_SIZE); bt_symbols = backtrace_symbols(array, size); strcpy(bt_string, "\n"); for(i = 0; i < size; i++) { strcat(bt_string, bt_symbols[i]); strcat(bt_string, "\n"); } LOG_ERROR(FATAL, "Obtained %zd stack frames.%s", size, bt_string); free(bt_symbols); //TODO: carefully dump server state(e.g. active & hang workers, number of connections, request, current request etc) server->is_running = 0; cleanup(server); exit(0); } int main(int argc, char *argv[]) { int retval = 0; wr_conf_t *conf=NULL; char *WR_ROOT = argv[1]; //Initialize logger if(initialize_logger(WR_LOG_FILE, WR_SERVER, WR_VERSION) == 0) { LOG_DEBUG(DEBUG,"Logging started in %s file",WR_LOG_FILE); } else { printf("Logger initialization failed. Please make sure you have write permission on '/var/log/webroar' directory."); } //Allocate and initialize configuration structure conf = wr_conf_read(WR_ROOT); if(conf == NULL ) { LOG_ERROR(FATAL,"Configuration reading failed."); printf("Server not started.\nProblem with reading the configuration file. Kindly refer the log files for details.\n"); return -1; } #ifdef L_DEBUG set_log_severity(DEBUG); #else set_log_severity(conf->server->log_level); #endif // Add Admin Panel wr_conf_admin_panel_add(conf); // Add staic file server wr_conf_static_server_add(conf); //TODO: Windows Portability? signal(SIGINT, sigproc); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, sigproc); /* catch hangup signal */ signal(SIGTERM, sigproc); /* catch terminate signal */ signal(SIGSEGV, crash_handler); /* set our handler for segfault */ // signal(SIGQUIT, crash_handler); // signal(SIGILL, crash_handler); // signal(SIGABRT, crash_handler); // signal(SIGFPE, crash_handler); // Initialize and start the Server to accept requests retval = wr_svr_init(&server, conf); if(retval<0) { LOG_ERROR(FATAL,"Initialization of network server failed."); printf("Server not started. Kindly refer the log files for details.\n"); return retval; } LOG_INFO("Network server successfully initialized on port %d",server->conf->server->port); // Set keep alive flag server->is_running = 1; // Initialize contol port/sock path to recive control messages retval = wr_ctl_init(server); if(retval < 0) { LOG_ERROR(FATAL,"Controller Initialization failed."); printf("Server not started. Kindly refer the log files for details.\n"); wr_svr_free(server); return retval; } LOG_INFO("Controller initialized"); // Fork processes and start 'webroar-workers's wr_app_init(server); //Daemonize the Server daemonize(); LOG_DEBUG(4,"Done daemon"); redirect_standard_io(); // Start event loop while(server->is_running) { ev_loop(server->ebb_svr.loop,EVLOOP_ONESHOT); } // Cleanup LOG_DEBUG(DEBUG,"Call cleanup"); cleanup(server); return 0; }