void uwsgi_fork_server(char *socket) { // map fd 0 to /dev/null to avoid mess uwsgi_remap_fd(0, "/dev/null"); int fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); if (fd < 0) exit(1); // automatically receive credentials (TODO make something useful with them, like checking the pid is from the Emperor) if (uwsgi_socket_passcred(fd)) exit(1); // initialize the event queue int eq = event_queue_init(); if (uwsgi.has_emperor) { event_queue_add_fd_read(eq, uwsgi.emperor_fd); } event_queue_add_fd_read(eq, fd); // now start waiting for connections for(;;) { int interesting_fd = -1; int rlen = event_queue_wait(eq, -1, &interesting_fd); if (rlen <= 0) continue; if (uwsgi.has_emperor && interesting_fd == uwsgi.emperor_fd) { char byte; ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1); if (rlen > 0) { uwsgi_log_verbose("received message %d from emperor\n", byte); } exit(0); } if (interesting_fd != fd) continue; struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd < 0) { uwsgi_error("uwsgi_fork_server()/accept()"); continue; } char hbuf[4]; pid_t ppid = -1; uid_t uid = -1; gid_t gid = -1; int fds_count = 8; size_t remains = 4; // we can receive up to 8 fds (generally from 1 to 3) int fds[8]; // we only read 4 bytes header ssize_t len = uwsgi_recv_cred_and_fds(client_fd, hbuf, remains, &ppid, &uid, &gid, fds, &fds_count); uwsgi_log_verbose("[uwsgi-fork-server] connection from pid: %d uid: %d gid:%d fds:%d\n", ppid, uid, gid, fds_count); if (len <= 0 || fds_count < 1) { uwsgi_error("uwsgi_fork_server()/recvmsg()"); goto end; } remains -= len; if (uwsgi_read_nb(client_fd, hbuf + (4-remains), remains, uwsgi.socket_timeout)) { uwsgi_error("uwsgi_fork_server()/uwsgi_read_nb()"); goto end; } struct uwsgi_header *uh = (struct uwsgi_header *) hbuf; // this memory area must be freed in the right place !!! char *body_argv = uwsgi_malloc(uh->_pktsize); if (uwsgi_read_nb(client_fd, body_argv, uh->_pktsize, uwsgi.socket_timeout)) { free(body_argv); uwsgi_error("uwsgi_fork_server()/uwsgi_read_nb()"); goto end; } pid_t pid = fork(); if (pid < 0) { free(body_argv); int i; for(i=0;i<fds_count;i++) close(fds[i]); // error on fork() uwsgi_error("uwsgi_fork_server()/fork()"); goto end; } else if (pid > 0) { free(body_argv); // close inherited decriptors int i; for(i=0;i<fds_count;i++) close(fds[i]); // wait for child death... waitpid(pid, NULL, 0); goto end; } else { // close Emperor channels // we do not close others file desctiptor as lot // of funny tricks could be accomplished with them if (uwsgi.has_emperor) { close(uwsgi.emperor_fd); if (uwsgi.emperor_fd_config > -1) close(uwsgi.emperor_fd_config); } // set EMPEROR_FD and FD_CONFIG env vars char *uef = uwsgi_num2str(fds[0]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { uwsgi_error("uwsgi_fork_server()/setenv()"); exit(1); } free(uef); int pipe_config = -1; int on_demand = -1; if (uh->modifier2 & VASSAL_HAS_CONFIG && fds_count > 1) { pipe_config = fds[1]; char *uef = uwsgi_num2str(pipe_config); if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { uwsgi_error("uwsgi_fork_server()/setenv()"); exit(1); } free(uef); } if (uh->modifier2 & VASSAL_HAS_ON_DEMAND && fds_count > 1) { if (pipe_config > -1) { if (fds_count > 2) { on_demand = fds[2]; } } else { on_demand = fds[1]; } } // dup the on_demand socket to 0 and close it if (on_demand > -1) { if (dup2(on_demand, 0) < 0) { uwsgi_error("uwsgi_fork_server()/dup2()"); exit(1); } close(on_demand); } // now fork again and die pid_t new_pid = fork(); if (new_pid < 0) { uwsgi_error("uwsgi_fork_server()/fork()"); exit(1); } else if (new_pid > 0) { exit(0); } else { // send the pid to the client_fd and close it struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); // leave space for header ub->pos = 4; if (uwsgi_buffer_append_keynum(ub, "pid", 3, getpid())) exit(1); // fix uwsgi header if (uwsgi_buffer_set_uh(ub, 35, 0)) goto end; // send_pid() if (uwsgi_write_nb(client_fd, ub->buf, ub->pos, uwsgi.socket_timeout)) exit(1); close(client_fd); uwsgi_log("double fork() and reparenting successful (new pid: %d)\n", getpid()); uwsgi_buffer_destroy(ub); // now parse the uwsgi packet array and build the argv struct uwsgi_string_list *usl = NULL, *usl_argv = NULL; uwsgi_hooked_parse_array(body_argv, uh->_pktsize, parse_argv_hook, &usl_argv); free(body_argv); // build new argc/argv uwsgi.new_argc = 0; size_t procname_len = 1; uwsgi_foreach(usl, usl_argv) { uwsgi.new_argc++; procname_len += usl->len + 1; } char *new_procname = uwsgi_calloc(procname_len); uwsgi.new_argv = uwsgi_calloc(sizeof(char *) * (uwsgi.new_argc + 1)); int counter = 0; uwsgi_foreach(usl, usl_argv) { uwsgi.new_argv[counter] = usl->value; strcat(new_procname, usl->value); strcat(new_procname, " "); counter++; } // fix process name uwsgi_set_processname(new_procname); free(new_procname); // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; // this avoids the process to re-exec itself uwsgi.exit_on_reload = 1; // fixup the Emperor communication uwsgi_check_emperor(); // continue with uWSGI startup return; } }
int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) { return -1; } if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) { return -1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error; if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error; if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error; if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error; if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error; if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error; if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req); if (ub_exc_repr) { if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) { uwsgi_buffer_destroy(ub_exc_repr); goto error; } uwsgi_buffer_destroy(ub_exc_repr); } else { goto notavail3; } } else { notavail3: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req); if (ub_exc_class) { if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) { uwsgi_buffer_destroy(ub_exc_class); goto error; } uwsgi_buffer_destroy(ub_exc_class); } else { goto notavail; } } else { notavail: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub_exc_msg) { if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) { uwsgi_buffer_destroy(ub_exc_msg); goto error; } uwsgi_buffer_destroy(ub_exc_msg); } else { goto notavail2; } } else { notavail2: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) { struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req); if (ub_exc_bt) { struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096); if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) { uwsgi_buffer_destroy(ub_exc_bt); uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(ub_exc_bt); if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) { uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(parsed_bt); } else { goto notavail4; } } else { notavail4: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) { goto error; } if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) { goto error; } uwsgi_buffer_destroy(ub); return 0; error: uwsgi_buffer_destroy(ub); return -1; }