/** Add newly created worker to application */ int wr_app_wrk_insert(wr_svr_t *server, wr_wkr_t *worker,const wr_ctl_msg_t *ctl_msg) { LOG_FUNCTION wr_app_t* app = server->apps; const char* app_name = ctl_msg->msg.wkr.app_name.str; if(strcmp(app_name, WR_STATIC_FILE_SERVER_NAME) == 0){ app = server->static_app; } while(app) { LOG_DEBUG(DEBUG,"app->a_config->max_worker = %d, app->wkr_que->q_count =%d", app->conf->max_worker, WR_QUEUE_SIZE(app->wkr_que)); LOG_DEBUG(DEBUG, "Application name = %s, Application->config->name =%s", app_name, app->conf->name.str ); if(app->conf->max_worker > WR_QUEUE_SIZE(app->wkr_que) && strcmp(app_name, app->conf->name.str) == 0) { int i; for(i = 0; i < app->pending_wkr ; i++) { if(app->last_wkr_pid[i] == worker->pid) break; } if(i == app->pending_wkr) { scgi_body_add(worker->ctl->scgi, "Either worker add timeout or worker PID does not match.", strlen("Either worker add timeout or worker PID does not match.")); return -1; } for(; i < app->pending_wkr ; i++) { app->last_wkr_pid[i] = app->last_wkr_pid[i+1]; } app->last_wkr_pid[i] = 0; app->pending_wkr --; worker->id = ++worker_count; worker->app = app; if(app->pending_wkr <= 0) ev_timer_stop(app->svr->ebb_svr.loop, &app->t_add_timeout); if(!(worker->state& WR_WKR_ACTIVE)) worker->state += WR_WKR_ACTIVE; if(app->in_use == FALSE) { app->in_use = TRUE; if(app->ctl) { LOG_DEBUG(DEBUG,"Send OK status"); scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "OK", strlen("OK")); wr_ctl_resp_write(app->ctl); app->ctl = NULL; } } return 0; } app = app->next; } LOG_ERROR(SEVERE, "Either queue is full or Baseuri is not matched"); scgi_body_add(worker->ctl->scgi, "Either queue is full or Baseuri is not matched.", strlen("Either queue is full or Baseuri is not matched.")); return -1; }
int drop_privileges(wkr_t *w, scgi_t *scgi) { char *str; str = (char*) scgi_header_value_get(scgi, "USER"); if(str && strlen(str) > 0) { struct passwd *user_info=NULL; user_info = getpwnam(str); // Check for user existence if(user_info) { w->tmp->uid = user_info->pw_uid; w->tmp->gid = user_info->pw_gid; } else { scgi_body_add(w->ctl->scgi, "Application run_as_user is invalid. Application not started.", strlen("Application run_as_user is invalid. Application not started.")); LOG_ERROR(SEVERE,"Application run_as_user is invalid. Application not started."); return FALSE; } } else { scgi_body_add(w->ctl->scgi, "Application run_as_user is missing. Application not started.", strlen("Application run_as_user is missing. Application not started.")); LOG_ERROR(SEVERE,"Application run_as_user is missing. Application not started."); return FALSE; } change_log_file_owner(w->tmp->uid, w->tmp->gid); //setting read, effective, saved group and user id if(setgid(w->tmp->gid)!=0) { scgi_body_add(w->ctl->scgi, "setegid() failed", strlen("setegid() failed")); LOG_ERROR(SEVERE,"setegid() failed"); return FALSE; } if(setuid(w->tmp->uid)!=0) { scgi_body_add(w->ctl->scgi, "seteuid() failed", strlen("seteuid() failed")); LOG_ERROR(SEVERE,"seteuid() failed"); return FALSE; } 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()); #ifdef __linux__ int rv = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); LOG_DEBUG(DEBUG,"prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) = %d", rv); if (rv < 0) { LOG_ERROR(SEVERE,"error setting prctl(PR_SET_DUMPABLE, 1, 0, 0, 0), errno = %d, desc = %s", errno, strerror(errno)); } #endif return TRUE; }
/** Allication add callback */ void wr_app_add_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) { LOG_FUNCTION wr_svr_t* server = ctl->svr; wr_app_conf_t* app_conf = NULL; wr_app_t* app = server->apps, *tmp_app = NULL; while(app) { if(strcmp(ctl_msg->msg.app.app_name.str, app->conf->name.str)==0) break; tmp_app = app; app = app->next; } ctl->svr->err_msg[0] = 0; if(app) { sprintf(ctl->svr->err_msg, "Appliation '%s' is already running.", ctl_msg->msg.app.app_name.str); } if(!app && ctl && ctl->svr && ctl->svr->conf) { app_conf = wr_conf_app_read(ctl->svr->conf, ctl_msg->msg.app.app_name.str, ctl->svr->err_msg); if(app_conf!=NULL) { if(wr_app_insert(ctl->svr, app_conf, ctl) >= 0) return; } else if(ctl->svr->err_msg[0] == 0) { sprintf(ctl->svr->err_msg, "Appliation '%s' is not found.", ctl_msg->msg.app.app_name.str); } } scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR")); scgi_body_add(ctl->scgi, ctl->svr->err_msg, strlen(ctl->svr->err_msg)); wr_ctl_resp_write(ctl); }
void load_application(wkr_t* w){ LOG_FUNCTION w->ctl->scgi = scgi_new(); if(w->ctl->scgi == NULL) { LOG_ERROR(SEVERE,"Cannot create SCGI Request"); sigproc(); return; } w->http = http_new(w); if(w->http == NULL) { scgi_body_add(w->ctl->scgi, "unable to load application.", strlen("unable to load application.")); LOG_ERROR(SEVERE,"unable to load application."); }else if(worker_listen(w) < 0) { scgi_body_add(w->ctl->scgi, "Error Initializing Workers.", strlen("Error Initializing Workers.")); LOG_ERROR(WARN,"Error Initializing Workers."); }else{ worker_accept_requests(w); LOG_INFO("Worker ready for serving requests."); init_idle_watcher(w); LOG_INFO("Successfully loaded rack application=%s with environment=%s", w->tmp->path.str, w->tmp->env.str); } //loading adapter according to application type LOG_DEBUG(DEBUG,"webroar_root = %s", 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); // Send error or ok acknowledgement message if(w->ctl->scgi->body_length > 0){ // Send error response w->ctl->error = TRUE; get_worker_add_ctl_scgi(w, TRUE); ev_io_start(w->loop,&(w->ctl->w_write)); ev_timer_again(w->loop, &w->ctl->t_ack); }else{ // Send acknowledgement message get_worker_add_ctl_scgi(w, FALSE); ev_io_start(w->loop,&(w->ctl->w_write)); } wkr_tmp_free(&w->tmp); }
/** Callback function to add worker timeout */ void wr_app_wrk_add_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) { LOG_FUNCTION wr_app_t* app = (wr_app_t*) w->data; char err_msg[512]; int err_msg_len = 0; // Stop add timeout timer ev_timer_stop(loop, &app->t_add_timeout); // Decreament active worker count if(app->pending_wkr > 0) { // Kill worker int pid = wr_app_fetch_wkr_pid(app); LOG_INFO("wr_app_wrk_add_timeout_cb: killing worker, pid = %d", pid); if(pid > 0) kill(pid ,SIGKILL); LOG_DEBUG(DEBUG,"app->pending_wkr = %d", app->pending_wkr); app->pending_wkr --; if(app->pending_wkr > 0) { ev_timer_again(loop, &app->t_add_timeout); } // Update high load ratio app->high_ratio = TOTAL_WORKER_COUNT(app) * WR_MAX_REQ_RATIO; } //TODO: Check minimum no. of workers and, cretae worker if needed. // Also, do not OK if some worker were failed to connect. // For timebeing sending OK even if some worker failed to connect. if(app->in_use == FALSE && app->ctl && app->pending_wkr == 0) { LOG_DEBUG(DEBUG,"Some problem occurred while starting Application %s.", app->conf->name.str); scgi_header_add(app->ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR")); err_msg_len = sprintf(err_msg,"The application could not be started due to an error. Please refer '/var/log/webroar/%s.log' and the application log file for details.", app->conf->name.str); scgi_body_add(app->ctl->scgi, err_msg, err_msg_len); wr_ctl_resp_write(app->ctl); app->ctl = NULL; } else if(app->in_use == TRUE && TOTAL_WORKER_COUNT(app) < app->conf->min_worker) { wr_app_wkr_add(app); } }
wr_ctl_msg_t* wr_ctl_msg_validate(scgi_t* request, wr_ctl_t* ctl) { LOG_FUNCTION wr_ctl_msg_t* ctl_msg = wr_malloc(wr_ctl_msg_t); char *val; char error[STR_SIZE64]; ctl->type = WR_CTL_MSG_NONE; ctl->scgi = scgi_new(); val = (char*) scgi_header_value_get(request,"COMPONENT"); if(val == NULL) { memcpy(error,"COMPONENT missing.", strlen("COMPONENT missing.")+1); goto ctl_msg_err; } scgi_header_add(ctl->scgi, "COMPONENT", strlen("COMPONENT"), val, strlen(val)); if(strcmp(val,"APPLICATION")==0) { val = (char*) scgi_header_value_get(request,"METHOD"); if(val == NULL) { memcpy(error,"METHOD missing.", strlen("METHOD missing.")+1); goto ctl_msg_err; } scgi_header_add(ctl->scgi, "METHOD", strlen("METHOD"), val, strlen(val)); ctl_msg->msg.app.app_name.str = (char*) scgi_header_value_get(request,"APP_NAME"); if(ctl_msg->msg.app.app_name.str) ctl_msg->msg.app.app_name.len = strlen(ctl_msg->msg.app.app_name.str); if(ctl_msg->msg.app.app_name.str == NULL) { memcpy(error,"Application name is missing.", strlen("Application name is missing.")+1); goto ctl_msg_err; } // Application Add if(strcmp(val,"ADD")==0) { ctl->type = WR_CTL_MSG_APPLICATION_ADD; } else if(strcmp(val,"REMOVE")==0) { ctl->type = WR_CTL_MSG_APPLICATION_REMOVE; } else if(strcmp(val,"RELOAD")==0) { ctl->type = WR_CTL_MSG_APPLICATION_RELOAD; }else { memcpy(error, "Invalid METHOD.", strlen("Invalid METHOD.")+1); goto ctl_msg_err; } } else if(strcmp(val,"WORKER")==0) { val = (char*) scgi_header_value_get(request,"METHOD"); if(val == NULL) { memcpy(error, "METHOD missing.", strlen("METHOD missing.")+1); goto ctl_msg_err; } if(strcmp(val,"ERROR")==0) { scgi_header_add(ctl->scgi, "METHOD", strlen("METHOD"), "ACK", strlen("ACK")); }else{ scgi_header_add(ctl->scgi, "METHOD", strlen("METHOD"), val, strlen(val)); } // Worker Add if(strcmp(val,"ADD")==0) { ctl->type = WR_CTL_MSG_WORKER_ADD; ctl_msg->msg.wkr.app_name.str = (char*) scgi_header_value_get(request,"APPLICATION"); if(ctl_msg->msg.wkr.app_name.str) ctl_msg->msg.wkr.app_name.len = strlen(ctl_msg->msg.wkr.app_name.str); ctl_msg->msg.wkr.pid.str = (char*) scgi_header_value_get(request,"PID"); if(ctl_msg->msg.wkr.pid.str) ctl_msg->msg.wkr.pid.len = strlen(ctl_msg->msg.wkr.pid.str); ctl_msg->msg.wkr.port.str = (char*) scgi_header_value_get(request,"PORT"); if(ctl_msg->msg.wkr.port.str) ctl_msg->msg.wkr.port.len = strlen(ctl_msg->msg.wkr.port.str); ctl_msg->msg.wkr.sock_path.str = (char*) scgi_header_value_get(request,"SOCK_PATH"); if(ctl_msg->msg.wkr.sock_path.str) ctl_msg->msg.wkr.sock_path.len = strlen(ctl_msg->msg.wkr.sock_path.str); ctl_msg->msg.wkr.uds.str = (char*) scgi_header_value_get(request,"UDS"); if(ctl_msg->msg.wkr.uds.str) ctl_msg->msg.wkr.uds.len = strlen(ctl_msg->msg.wkr.uds.str); if(ctl_msg->msg.wkr.app_name.str == NULL || ctl_msg->msg.wkr.pid.str == NULL || ctl_msg->msg.wkr.uds.str == NULL) { memcpy(error, "Missing some headers.", strlen("Missing some headers.")+1); goto ctl_msg_err; } } else if(strcmp(val,"REMOVE")==0) { ctl->type = WR_CTL_MSG_WORKER_REMOVE; } else if(strcmp(val,"PING") == 0) { ctl->type = WR_CTL_MSG_WORKER_PING; } else if(strcmp(val,"CONF_REQ") == 0){ ctl->type = WR_CTL_MSG_WORKER_CONF_REQ; ctl_msg->msg.wkr.app_name.str = (char*) scgi_header_value_get(request,"APPLICATION"); if(ctl_msg->msg.wkr.app_name.str) ctl_msg->msg.wkr.app_name.len = strlen(ctl_msg->msg.wkr.app_name.str); } else if(strcmp(val,"ERROR") == 0) { ctl->type = WR_CTL_MSG_WORKER_ADD_ERROR; ctl_msg->msg.wkr.app_name.str = (char*) scgi_header_value_get(request,"APPLICATION"); if(ctl_msg->msg.wkr.app_name.str) ctl_msg->msg.wkr.app_name.len = strlen(ctl_msg->msg.wkr.app_name.str); ctl_msg->msg.wkr.pid.str = (char*) scgi_header_value_get(request,"PID"); if(ctl_msg->msg.wkr.pid.str) ctl_msg->msg.wkr.pid.len = strlen(ctl_msg->msg.wkr.pid.str); ctl_msg->msg.wkr.port.str = (char*) scgi_header_value_get(request,"PORT"); if(ctl_msg->msg.wkr.port.str) ctl_msg->msg.wkr.port.len = strlen(ctl_msg->msg.wkr.port.str); ctl_msg->msg.wkr.sock_path.str = (char*) scgi_header_value_get(request,"SOCK_PATH"); if(ctl_msg->msg.wkr.sock_path.str) ctl_msg->msg.wkr.sock_path.len = strlen(ctl_msg->msg.wkr.sock_path.str); ctl_msg->msg.wkr.uds.str = (char*) scgi_header_value_get(request,"UDS"); if(ctl_msg->msg.wkr.uds.str) ctl_msg->msg.wkr.uds.len = strlen(ctl_msg->msg.wkr.uds.str); if(ctl_msg->msg.wkr.app_name.str == NULL || ctl_msg->msg.wkr.pid.str == NULL || ctl_msg->msg.wkr.uds.str == NULL) { memcpy(error, "Missing some headers.", strlen("Missing some headers.")+1); goto ctl_msg_err; } }else { memcpy(error,"Invalid METHOD.", strlen("Invalid METHOD.")+1); goto ctl_msg_err; } } else { memcpy(error,"Invalid COMPONENT.", strlen("Invalid COMPONENT.")+1); goto ctl_msg_err; } return ctl_msg; ctl_msg_err: LOG_ERROR(WARN,"Error found in controller message"); ctl->type = WR_CTL_MSG_TYPE_ERROR; scgi_body_add(ctl->scgi, error, strlen(error)); scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR")); return ctl_msg; }