/* WebROaR - Ruby Application Server - http://webroar.in/ * Copyright (C) 2009 WebROaR * * 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 //static wkr_t *worker = NULL; struct ev_loop *loop; // Event loop int is_alive = 1; static int drop_privileges(wkr_t *w) { change_log_file_owner(w->tmp->uid, w->tmp->gid); //setting read, effective, saved group and user id if(setgid(w->tmp->gid)!=0) { LOG_ERROR(SEVERE,"setegid() failed"); return -1; } if(setuid(w->tmp->uid)!=0) { LOG_ERROR(SEVERE,"seteuid() failed"); return -1; } LOG_DEBUG(DEBUG,"Passed userid=%d and groupid=%d", w->tmp->uid, w->tmp->gid); LOG_DEBUG(DEBUG,"effective userid=%d and groupid=%d",geteuid(),getegid()); return 0; } /** Usage */ static inline void print_usage(char *appname) { printf("usage: \n%s -a [-e ] [-u ] [-g ] ",appname); printf("[-c ] [-i ] [-t ] [-n ] "); printf("[-p ] [-r ]\n"); printf(" = path of rails application. e.g. /home/xyz/rails_projects/app1\n"); printf(" = rails environment. development/production. Default is production.\n"); printf(" = User id.\n"); printf(" = Group id.\n"); printf(" = Control port number (control sock path in case [-i 1])\n"); printf(" = Unix domain socket flag. Value should be 0 or 1.\n"); printf(" = Type of application {rails, merb}.\n"); printf(" = Name of application\n"); printf(" = Analytics flag. Value should be yes or no.\n"); printf(" = Application URL baseuri.\n"); } void sigproc() { // file_log("/tmp/too_many_worker.log","Webroar-Worker of %s getting close\n", worker->tmp->name.str); LOG_DEBUG(4,"**************Caught Interrupt Signal************"); is_alive = 0; } /** Parse command line arguments */ static inline wkr_tmp_t* parse_args(int argc, char **argv) { int option; extern char *optarg; size_t len; char *str; int invalid_arg_flag = 0, app_path_flag = 0; wkr_tmp_t *tmp = wkr_tmp_new(); if(tmp == NULL) return NULL; while ( (option=getopt(argc,argv,"a:b:e:l:f:g:u:c:i:t:n:o:p:r:k:")) != -1 ) { str = optarg; len = strlen(str); switch ( option ) { case 'a': // Application Path wr_string_new(tmp->path, str, len); app_path_flag = 1; break; case 'b': // Ruby library path wr_string_new(tmp->ruby_path, str, len); tmp->script_path.str = (char*) malloc(sizeof(char)*(tmp->ruby_path.len + 32)); tmp->script_path.len = sprintf(tmp->script_path.str, "%s%swebroar_app_loader.rb", tmp->ruby_path.str, WR_PATH_SEPARATOR); break; case 'e': // Application environment wr_string_new(tmp->env, str, len); break; case 'l': // Logging level #ifdef L_DEBUG set_log_severity(DEBUG); #else set_log_severity(atoi(optarg)); #endif break; case 'f': // Log file name wr_string_free(tmp->log_file); wr_string_new(tmp->log_file, str, len); break; case 'g': // Group id tmp->gid = atoi(optarg); break; case 'u': // User id tmp->uid = atoi(optarg); break; case 'c': // Control path wr_string_new(tmp->ctl_path, str, len); break; case 'i': // Unix domain socket flag if(strcmp(optarg, "y")==0) { tmp->is_uds = TRUE; } break; case 't': // Application type wr_string_new(tmp->type, str, len); break; case 'n': // Application name wr_string_new(tmp->name, str, len); wr_string_free(tmp->log_file); tmp->log_file.str = (char*) malloc(sizeof(char)*(strlen(optarg)+8)); tmp->log_file.len = sprintf(tmp->log_file.str,"%s.log", optarg); break; case 'o': // Server root path wr_string_new(tmp->root_path, str, len); break; case 'r': // Applicaiton base uri wr_string_new(tmp->resolver, str, len); break; case 'p': // Analytics flag if(strcmp(optarg, "y")==0) { tmp->profiler = 'y'; } break; case 'k': if(strcmp(optarg, "n")==0) { tmp->keep_alive = FALSE; } break; default: invalid_arg_flag++; } } if (invalid_arg_flag>0 || app_path_flag == 0) { print_usage(argv[0]); wkr_tmp_free(&tmp); return NULL; } return tmp; } int main(int argc, char **argv) { int port, retval = 0; wkr_t* w = NULL; if(argc==1) { print_usage(argv[0]); return -1; } wkr_tmp_t *tmp = parse_args(argc, argv); if(tmp == NULL) return -1; loop = ev_default_loop (0); w = worker_new(loop, tmp); if(w==NULL) goto err; // worker = w; // assert(w!=NULL); initialize_logger(w->tmp->log_file.str); LOG_DEBUG(DEBUG,"control path = %s, Application baseuri = %s", w->tmp->ctl_path.str, w->tmp->resolver.str); if((retval = drop_privileges(w))!=0) { goto err; } w->http = http_new(w); if(w->http == NULL) { LOG_ERROR(SEVERE,"unable to load application."); goto err; } retval = worker_connect(w); if(retval<0) { LOG_ERROR(WARN,"Error Initializing Workers."); retval = -1; goto err; } // w->http = http_new(w); // if(w->http == NULL) // { // goto err; // } //loading adapter according to application type LOG_DEBUG(DEBUG,"ruby lib = %s and webroar_root = %s", w->tmp->ruby_path.str, w->tmp->root_path.str); LOG_DEBUG(DEBUG,"path = %s, name = %s, type = %s, environment = %s, baseuri = %s, analytics = %c", w->tmp->path.str, w->tmp->name.str, w->tmp->type.str, w->tmp->env.str, w->tmp->resolver.str, w->tmp->profiler); LOG_INFO("Successfully loaded rack application=%s with environment=%s", w->tmp->path.str, w->tmp->env.str); //TODO: Windows Portability? signal(SIGHUP, SIG_IGN); /* catch hangup signal */ signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGKILL, sigproc); signal(SIGPIPE, SIG_IGN); worker_accept_requests(w); LOG_INFO("Worker ready for serving requests."); while(is_alive ==1) { ev_loop(loop,EVLOOP_ONESHOT); } err: LOG_DEBUG(DEBUG,"stoping event loop"); ev_unloop(loop,EVUNLOOP_ALL); //TODO: send worker stopping signal worker_free(&w); LOG_INFO("Worker stopped and exiting gracefully."); close_logger(); return retval; }