mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-08-28 09:27:03 +00:00
2657 lines
79 KiB
C
2657 lines
79 KiB
C
/*
|
|
|
|
*** uWSGI ***
|
|
|
|
Copyright 2009 Unbit S.a.s. <info@unbit.it>
|
|
|
|
This program 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 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program 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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
********* Note for Linux users *********
|
|
uWSGI supports UNIX socket on abstract namespace.
|
|
Use them if you have filesystem permission problems.
|
|
|
|
********* Note for Unbit users *********
|
|
Try to keep the same configuration on your unbit account (threading mode
|
|
in particular)
|
|
|
|
*/
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
#ifdef __linux__
|
|
#include <sys/sendfile.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef UNBIT
|
|
|
|
#ifndef ROCK_SOLID
|
|
#include <libxml/parser.h>
|
|
#include <libxml/tree.h>
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
#include "uwsgi.h"
|
|
|
|
#if PY_MINOR_VERSION < 5
|
|
#define Py_ssize_t int
|
|
#endif
|
|
|
|
struct uwsgi_server uwsgi;
|
|
|
|
static char *nl = "\r\n";
|
|
static char *h_sep = ": " ;
|
|
static const char *http_protocol = "HTTP/1.1" ;
|
|
static const char *app_slash = "/" ;
|
|
|
|
int find_worker_id(pid_t pid) {
|
|
int i ;
|
|
for(i = 1 ; i<= uwsgi.numproc ; i++) {
|
|
/* fprintf(stderr,"%d of %d\n", pid, uwsgi.workers[i].pid); */
|
|
if (uwsgi.workers[i].pid == pid)
|
|
return i ;
|
|
}
|
|
|
|
return -1 ;
|
|
}
|
|
|
|
struct wsgi_request wsgi_req;
|
|
|
|
PyMethodDef null_methods[] = {
|
|
{NULL, NULL},
|
|
};
|
|
|
|
#ifdef UNBIT
|
|
int save_to_disk = -1 ;
|
|
int tmp_dir_fd = -1 ;
|
|
char *tmp_filename ;
|
|
int uri_to_hex(void);
|
|
int check_for_memory_errors = 0 ;
|
|
#endif
|
|
|
|
PyObject *wsgi_writeout ;
|
|
|
|
// iovec
|
|
struct iovec *hvec ;
|
|
|
|
#ifdef ROCK_SOLID
|
|
struct uwsgi_app *wi;
|
|
#endif
|
|
|
|
void gracefully_kill() {
|
|
fprintf(stderr, "Gracefully killing worker %d...\n", uwsgi.mypid);
|
|
if (uwsgi.in_request) {
|
|
uwsgi.manage_next_request = 0 ;
|
|
}
|
|
else {
|
|
reload_me();
|
|
}
|
|
}
|
|
|
|
void reload_me() {
|
|
exit(UWSGI_RELOAD_CODE);
|
|
}
|
|
|
|
void end_me() {
|
|
exit(UWSGI_END_CODE);
|
|
}
|
|
|
|
void goodbye_cruel_world() {
|
|
fprintf(stderr, "...The work of process %d is done. Seeya!\n", getpid());
|
|
exit(0);
|
|
}
|
|
|
|
void kill_them_all() {
|
|
int i ;
|
|
fprintf(stderr,"SIGINT/SIGQUIT received...killing workers...\n");
|
|
for(i=1;i<=uwsgi.numproc;i++) {
|
|
kill(uwsgi.workers[i].pid, SIGINT);
|
|
}
|
|
}
|
|
|
|
void grace_them_all() {
|
|
int i ;
|
|
fprintf(stderr,"...gracefully killing workers...\n");
|
|
for(i=1;i<=uwsgi.numproc;i++) {
|
|
kill(uwsgi.workers[i].pid, SIGHUP);
|
|
}
|
|
}
|
|
|
|
void reap_them_all() {
|
|
int i ;
|
|
fprintf(stderr,"...brutally killing workers...\n");
|
|
for(i=1;i<=uwsgi.numproc;i++) {
|
|
kill(uwsgi.workers[i].pid, SIGTERM);
|
|
}
|
|
}
|
|
|
|
void harakiri() {
|
|
|
|
PyThreadState *_myself;
|
|
#ifndef ROCK_SOLID
|
|
struct uwsgi_app *wi = NULL ;
|
|
if (wsgi_req.app_id >= 0) {
|
|
wi = &uwsgi.wsgi_apps[wsgi_req.app_id] ;
|
|
}
|
|
#endif
|
|
PyGILState_Ensure();
|
|
_myself = PyThreadState_Get();
|
|
if (wi) {
|
|
#ifdef ROCK_SOLID
|
|
fprintf(stderr,"\nF*CK !!! i must kill myself (pid: %d) wi: %p wi->wsgi_harakiri: %p thread_state: %p frame: %p...\n", uwsgi.mypid, wi, wi->wsgi_harakiri, _myself, _myself->frame );
|
|
#else
|
|
fprintf(stderr,"\nF*CK !!! i must kill myself (pid: %d app_id: %d) wi: %p wi->wsgi_harakiri: %p thread_state: %p frame: %p...\n", uwsgi.mypid, wsgi_req.app_id, wi, wi->wsgi_harakiri, _myself, _myself->frame );
|
|
#endif
|
|
|
|
if (wi->wsgi_harakiri) {
|
|
PyEval_CallObject(wi->wsgi_harakiri, wi->wsgi_args);
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
}
|
|
}
|
|
Py_FatalError("HARAKIRI !\n");
|
|
}
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
void stats() {
|
|
struct uwsgi_app *ua = NULL;
|
|
int i;
|
|
|
|
fprintf(stderr, "*** pid %d stats ***\n", getpid());
|
|
fprintf(stderr, "\ttotal requests: %llu\n", uwsgi.workers[0].requests);
|
|
for(i=0;i<uwsgi.wsgi_cnt;i++) {
|
|
ua = &uwsgi.wsgi_apps[i];
|
|
if (ua) {
|
|
fprintf(stderr, "\tapp %d requests: %d\n", i, ua->requests);
|
|
}
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void internal_server_error(int fd, char *message) {
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.cgi_mode == 0) {
|
|
#endif
|
|
#endif
|
|
wsgi_req.headers_size = write(fd, "HTTP/1.1 500 Internal Server Error\r\nContent-type: text/html\r\n\r\n", 63);
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
else {
|
|
wsgi_req.headers_size = write(fd, "Status: 500 Internal Server Error\r\nContent-type: text/html\r\n\r\n", 62);
|
|
}
|
|
#endif
|
|
wsgi_req.header_cnt = 2 ;
|
|
#endif
|
|
wsgi_req.response_size = write(fd, "<h1>uWSGI Error</h1>", 20);
|
|
wsgi_req.response_size += write(fd, message, strlen(message));
|
|
}
|
|
|
|
#ifndef ROCK_SOLID
|
|
PyObject *py_uwsgi_sendfile(PyObject *self, PyObject *args) {
|
|
|
|
//PyObject *zero ;
|
|
|
|
uwsgi.py_sendfile = PyTuple_GetItem(args, 0);
|
|
|
|
#ifdef PYTHREE
|
|
if ((wsgi_req.sendfile_fd = PyObject_AsFileDescriptor(uwsgi.py_sendfile)) >= 0) {
|
|
Py_INCREF(uwsgi.py_sendfile);
|
|
}
|
|
#else
|
|
if (PyFile_Check(uwsgi.py_sendfile)) {
|
|
//zero = PyFile_Name(uwsgi.py_sendfile) ;
|
|
//fprintf(stderr,"->serving %s as static file...", PyString_AsString(zero));
|
|
wsgi_req.sendfile_fd = PyObject_AsFileDescriptor(uwsgi.py_sendfile);
|
|
Py_INCREF(uwsgi.py_sendfile);
|
|
}
|
|
#endif
|
|
|
|
|
|
return PyTuple_New(0);
|
|
}
|
|
#endif
|
|
|
|
PyObject *py_uwsgi_write(PyObject *self, PyObject *args) {
|
|
PyObject *data;
|
|
char *content ;
|
|
int len;
|
|
data = PyTuple_GetItem(args, 0);
|
|
if (PyString_Check(data)) {
|
|
content = PyString_AsString(data) ;
|
|
len = PyString_Size(data);
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.has_threads) {
|
|
Py_BEGIN_ALLOW_THREADS
|
|
wsgi_req.response_size = write(uwsgi.poll.fd, content, len);
|
|
Py_END_ALLOW_THREADS
|
|
}
|
|
else {
|
|
#endif
|
|
wsgi_req.response_size = write(uwsgi.poll.fd, content, len);
|
|
#ifdef UNBIT
|
|
if (save_to_disk >= 0) {
|
|
if (write(save_to_disk, content, len) != len) {
|
|
perror("write()");
|
|
close(save_to_disk);
|
|
save_to_disk = -1 ;
|
|
}
|
|
}
|
|
#endif
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef UNBIT
|
|
if (save_to_disk >= 0) {
|
|
close(save_to_disk);
|
|
save_to_disk = -1 ;
|
|
fprintf(stderr,"[uWSGI cacher] output of request %d (%.*s) on pid %d written to cache file %s\n",uwsgi.workers[0].requests, wsgi_req.uri_len, wsgi_req.uri, uwsgi.mypid,tmp_filename);
|
|
}
|
|
#endif
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
|
|
PyObject *wsgi_spitout;
|
|
|
|
PyObject *py_uwsgi_spit(PyObject *self, PyObject *args) {
|
|
PyObject *headers, *head ;
|
|
PyObject *h_key, *h_value;
|
|
int i,j ;
|
|
#ifndef UNBIT
|
|
#ifdef ROCK_SOLID
|
|
int base = 4 ;
|
|
#else
|
|
int base = 0 ;
|
|
#endif
|
|
#else
|
|
int base = 4 ;
|
|
#endif
|
|
|
|
// use writev()
|
|
|
|
head = PyTuple_GetItem(args,0) ;
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.cgi_mode == 0) {
|
|
base = 4 ;
|
|
#endif
|
|
#endif
|
|
|
|
if (wsgi_req.protocol_len == 0) {
|
|
hvec[0].iov_base = (char * )http_protocol ;
|
|
wsgi_req.protocol_len = 8 ;
|
|
}
|
|
else {
|
|
hvec[0].iov_base = wsgi_req.protocol ;
|
|
}
|
|
hvec[0].iov_len = wsgi_req.protocol_len ;
|
|
hvec[1].iov_base = " " ;
|
|
hvec[1].iov_len = 1 ;
|
|
#ifdef PYTHREE
|
|
hvec[2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head)) ;
|
|
hvec[2].iov_len = strlen(hvec[2].iov_base);
|
|
#else
|
|
hvec[2].iov_base = PyString_AsString(head) ;
|
|
hvec[2].iov_len = PyString_Size(head) ;
|
|
#endif
|
|
wsgi_req.status = atoi(hvec[2].iov_base) ;
|
|
hvec[3].iov_base = nl ;
|
|
hvec[3].iov_len = NL_SIZE ;
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
else {
|
|
// drop http status on cgi mode
|
|
base = 3 ;
|
|
hvec[0].iov_base = "Status: " ;
|
|
hvec[0].iov_len = 8 ;
|
|
#ifdef PYTHREE
|
|
hvec[1].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(head)) ;
|
|
hvec[1].iov_len = strlen(hvec[1].iov_base);
|
|
#else
|
|
hvec[1].iov_base = PyString_AsString(head) ;
|
|
hvec[1].iov_len = PyString_Size(head) ;
|
|
#endif
|
|
wsgi_req.status = atoi(hvec[1].iov_base) ;
|
|
hvec[2].iov_base = nl ;
|
|
hvec[2].iov_len = NL_SIZE ;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef UNBIT
|
|
if (wsgi_req.unbit_flags & (unsigned long long) 1) {
|
|
if (tmp_dir_fd >= 0 && tmp_filename[0] != 0 && wsgi_req.status == 200 && wsgi_req.method_len == 3 && wsgi_req.method[0] == 'G' && wsgi_req.method[1] == 'E' && wsgi_req.method[2] == 'T') {
|
|
save_to_disk = openat(tmp_dir_fd, tmp_filename,O_CREAT | O_TRUNC | O_WRONLY , S_IRUSR |S_IWUSR |S_IRGRP);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
headers = PyTuple_GetItem(args,1) ;
|
|
wsgi_req.header_cnt = PyList_Size(headers) ;
|
|
|
|
|
|
|
|
if (wsgi_req.header_cnt > uwsgi.max_vars) {
|
|
wsgi_req.header_cnt = uwsgi.max_vars ;
|
|
}
|
|
for(i=0;i<wsgi_req.header_cnt;i++) {
|
|
j = (i*4)+base ;
|
|
head = PyList_GetItem(headers, i);
|
|
h_key = PyTuple_GetItem(head,0) ;
|
|
h_value = PyTuple_GetItem(head,1) ;
|
|
#ifdef PYTHREE
|
|
hvec[j].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_key)) ;
|
|
hvec[j].iov_len = strlen(hvec[j].iov_base);
|
|
#else
|
|
hvec[j].iov_base = PyString_AsString(h_key) ;
|
|
hvec[j].iov_len = PyString_Size(h_key) ;
|
|
#endif
|
|
hvec[j+1].iov_base = h_sep;
|
|
hvec[j+1].iov_len = H_SEP_SIZE;
|
|
#ifdef PYTHREE
|
|
hvec[j+2].iov_base = PyBytes_AsString(PyUnicode_AsASCIIString(h_value)) ;
|
|
hvec[j+2].iov_len = strlen(hvec[j+2].iov_base);
|
|
#else
|
|
hvec[j+2].iov_base = PyString_AsString(h_value) ;
|
|
hvec[j+2].iov_len = PyString_Size(h_value) ;
|
|
#endif
|
|
hvec[j+3].iov_base = nl;
|
|
hvec[j+3].iov_len = NL_SIZE;
|
|
//fprintf(stderr, "%.*s: %.*s\n", hvec[j].iov_len, (char *)hvec[j].iov_base, hvec[j+2].iov_len, (char *) hvec[j+2].iov_base);
|
|
}
|
|
|
|
#ifdef UNBIT
|
|
if (save_to_disk >= 0) {
|
|
for(j=0;j<i;j+=4) {
|
|
if (!strncasecmp(hvec[j].iov_base,"Set-Cookie",hvec[j].iov_len)) {
|
|
close(save_to_disk);
|
|
save_to_disk = -1 ;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// \r\n
|
|
j = (i*4)+base ;
|
|
hvec[j].iov_base = nl;
|
|
hvec[j].iov_len = NL_SIZE;
|
|
|
|
wsgi_req.headers_size = writev(uwsgi.poll.fd, hvec,j+1);
|
|
if (wsgi_req.headers_size < 0) {
|
|
perror("writev()");
|
|
}
|
|
Py_INCREF(wsgi_writeout);
|
|
|
|
return wsgi_writeout ;
|
|
}
|
|
|
|
|
|
PyMethodDef uwsgi_spit_method[] = {{"uwsgi_spit", py_uwsgi_spit, METH_VARARGS, ""}} ;
|
|
PyMethodDef uwsgi_write_method[] = {{"uwsgi_write", py_uwsgi_write, METH_VARARGS, ""}} ;
|
|
|
|
#ifndef ROCK_SOLID
|
|
PyMethodDef uwsgi_sendfile_method[] = {{"uwsgi_sendfile", py_uwsgi_sendfile, METH_VARARGS, ""}} ;
|
|
#endif
|
|
|
|
|
|
// process manager is now (20090725) available on Unbit
|
|
pid_t masterpid;
|
|
pid_t diedpid;
|
|
int waitpid_status;
|
|
int process_reaper = 0 ;
|
|
int max_requests = 0;
|
|
struct timeval last_respawn;
|
|
time_t respawn_delta;
|
|
#ifdef UNBIT
|
|
int single_app_mode = 0;
|
|
#endif
|
|
|
|
char *spool_dir = NULL ;
|
|
|
|
int main(int argc, char *argv[], char *envp[]) {
|
|
|
|
struct timeval check_interval = {.tv_sec = 1, .tv_usec = 0 };
|
|
|
|
#ifndef PYTHREE
|
|
PyObject *uwsgi_module;
|
|
#endif
|
|
PyObject *wsgi_result, *wsgi_chunks, *wchunk;
|
|
PyObject *zero, *wsgi_socket;
|
|
#ifndef ROCK_SOLID
|
|
PyThreadState *_save = NULL;
|
|
#endif
|
|
|
|
FILE *wsgi_file;
|
|
struct sockaddr_un c_addr ;
|
|
int c_len = sizeof(struct sockaddr_un);
|
|
int rlen,i ;
|
|
pid_t pid ;
|
|
|
|
int serverfd = 0 ;
|
|
#ifndef UNBIT
|
|
char *socket_name = NULL ;
|
|
#endif
|
|
|
|
#ifndef ROCK_SOLID
|
|
char spool_filename[1024];
|
|
pid_t spooler_pid = 0 ;
|
|
#endif
|
|
|
|
char *cwd ;
|
|
char *binary_path ;
|
|
int ready_to_reload = 0;
|
|
int ready_to_die = 0;
|
|
|
|
int is_a_reload = 0 ;
|
|
|
|
PyObject *pydictkey, *pydictvalue;
|
|
|
|
char *buffer ;
|
|
char *ptrbuf ;
|
|
char *bufferend ;
|
|
|
|
unsigned short strsize = 0;
|
|
struct uwsgi_app *wi;
|
|
|
|
#ifdef __linux__
|
|
struct rlimit rl ;
|
|
#endif
|
|
|
|
#ifdef UNBIT
|
|
struct uidsec_struct us;
|
|
#endif
|
|
|
|
int socket_type;
|
|
socklen_t socket_type_len ;
|
|
char *path_info;
|
|
|
|
/* anti signal bombing */
|
|
signal(SIGHUP, SIG_IGN);
|
|
signal(SIGTERM, SIG_IGN);
|
|
|
|
memset(&uwsgi, 0, sizeof(struct uwsgi_server));
|
|
|
|
#ifndef ROCK_SOLID
|
|
uwsgi.wsgi_cnt = 1;
|
|
uwsgi.default_app = -1;
|
|
#endif
|
|
uwsgi.manage_next_request = 1;
|
|
uwsgi.buffer_size = 4096;
|
|
uwsgi.numproc = 1;
|
|
#ifndef UNBIT
|
|
uwsgi.listen_queue = 64;
|
|
#endif
|
|
uwsgi.socket_timeout = 4 ;
|
|
|
|
uwsgi.max_vars = MAX_VARS ;
|
|
uwsgi.vec_size = 4+1+(4*MAX_VARS) ;
|
|
|
|
uwsgi.request_logging = 1;
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
int option_index = 0;
|
|
struct option long_options[] = {
|
|
{"socket", required_argument, 0, 's'},
|
|
{"processes", required_argument, 0, 'p'},
|
|
{"harakiri", required_argument, 0, 't'},
|
|
{"xmlconfig", required_argument, 0, 'x'},
|
|
{"daemonize", required_argument, 0, 'd'},
|
|
{"listen", required_argument, 0, 'l'},
|
|
{"optimize", required_argument, 0, 'O'},
|
|
{"max-vars", required_argument, 0, 'v'},
|
|
{"buffer-size", required_argument, 0, 'b'},
|
|
{"memory-report", no_argument, 0, 'm'},
|
|
{"cgi-mode", no_argument, 0, 'c'},
|
|
{"abstract-socket", no_argument, 0, 'a'},
|
|
{"chmod-socket", no_argument, 0, 'C'},
|
|
{"enable-threads", no_argument, 0, 'T'},
|
|
{"profiler", no_argument, 0, 'P'},
|
|
{"single-interpreter", no_argument, 0, 'i'},
|
|
{"master", no_argument, 0, 'M'},
|
|
{"help", no_argument, 0, 'h'},
|
|
{"reaper", no_argument, 0, 'r'},
|
|
{"max-requests", required_argument, 0, 'R'},
|
|
{"socket-timeout", required_argument, 0, 'z'},
|
|
{"module", required_argument, 0, 'w'},
|
|
{"test", required_argument, 0, 'j'},
|
|
{"home", required_argument, 0, 'H'},
|
|
{"sharedarea", required_argument, 0, 'A'},
|
|
{"spooler", required_argument, 0, 'Q'},
|
|
{"disable-logging", no_argument, 0, 'L'},
|
|
|
|
{"pidfile", required_argument, 0, 10001},
|
|
{0, 0, 0, 0}
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
|
|
gettimeofday(&uwsgi.start_tv, NULL) ;
|
|
|
|
setlinebuf(stdout);
|
|
|
|
|
|
cwd = uwsgi_get_cwd();
|
|
binary_path = malloc(strlen(argv[0])+1) ;
|
|
if (binary_path == NULL) {
|
|
perror("malloc()");
|
|
exit(1);
|
|
}
|
|
strcpy(binary_path, argv[0]);
|
|
|
|
socket_type_len = sizeof(int);
|
|
if (!getsockopt(3, SOL_SOCKET, SO_TYPE, &socket_type, &socket_type_len)) {
|
|
fprintf(stderr, "...fd 3 is a socket, i suppose this is a graceful reload of uWSGI, i will try to do my best...\n");
|
|
is_a_reload = 1 ;
|
|
#ifdef UNBIT
|
|
/* discard the 3'th fd as we will use the fd 0 */
|
|
close(3);
|
|
#else
|
|
serverfd = 3;
|
|
#endif
|
|
}
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
while ((i = getopt_long(argc, argv, "s:p:t:x:d:l:O:v:b:mcaCTPiMhrR:z:w:j:H:A:Q:L", long_options, &option_index)) != -1) {
|
|
#else
|
|
while ((i = getopt (argc, argv, "s:p:t:d:l:v:b:aCMhrR:z:j:H:A:L")) != -1) {
|
|
#endif
|
|
#else
|
|
while ((i = getopt (argc, argv, "p:t:mTPiv:b:rMR:Sz:w:C:j:H:A:EQ:L")) != -1) {
|
|
#endif
|
|
switch(i) {
|
|
case 10001:
|
|
uwsgi.pidfile = optarg;
|
|
break;
|
|
case 'j':
|
|
uwsgi.test_module = optarg;
|
|
break;
|
|
case 'H':
|
|
uwsgi.pyhome = optarg;
|
|
break;
|
|
case 'A':
|
|
uwsgi.sharedareasize = atoi(optarg);
|
|
break;
|
|
case 'L':
|
|
uwsgi.request_logging = 0 ;
|
|
break;
|
|
#ifndef ROCK_SOLID
|
|
case 'Q':
|
|
spool_dir = optarg;
|
|
if (access(spool_dir, R_OK|W_OK|X_OK)) {
|
|
perror("access()");
|
|
exit(1);
|
|
}
|
|
uwsgi.master_process = 1;
|
|
break;
|
|
#endif
|
|
#ifdef UNBIT
|
|
case 'E':
|
|
check_for_memory_errors = 1 ;
|
|
break;
|
|
case 'S':
|
|
uwsgi.single_interpreter = 1;
|
|
single_app_mode = 1;
|
|
uwsgi.default_app = 0;
|
|
break;
|
|
case 'C':
|
|
tmp_dir_fd = open(optarg, O_DIRECTORY);
|
|
if (tmp_dir_fd <0) {
|
|
perror("open()");
|
|
exit(1);
|
|
}
|
|
tmp_filename = malloc(8192);
|
|
if (!tmp_filename) {
|
|
fprintf(stderr,"unable to allocate space (8k) for tmp_filename\n");
|
|
exit(1);
|
|
}
|
|
memset(tmp_filename, 0 ,8192);
|
|
break;
|
|
#endif
|
|
#ifndef UNBIT
|
|
case 'd':
|
|
if (!is_a_reload) {
|
|
daemonize(optarg);
|
|
}
|
|
break;
|
|
case 's':
|
|
socket_name = optarg;
|
|
break;
|
|
#ifndef ROCK_SOLID
|
|
case 'x':
|
|
uwsgi.xml_config = optarg;
|
|
break;
|
|
#endif
|
|
case 'l':
|
|
uwsgi.listen_queue = atoi(optarg);
|
|
break;
|
|
#endif
|
|
case 'v':
|
|
uwsgi.max_vars = atoi(optarg);
|
|
uwsgi.vec_size = 4+1+(4*uwsgi.max_vars) ;
|
|
break;
|
|
case 'p':
|
|
uwsgi.numproc = atoi(optarg);
|
|
break;
|
|
case 'r':
|
|
process_reaper = 1;
|
|
break;
|
|
#ifndef ROCK_SOLID
|
|
case 'w':
|
|
uwsgi.single_interpreter = 1;
|
|
uwsgi.wsgi_config = optarg;
|
|
break;
|
|
case 'm':
|
|
uwsgi.memory_debug = 1 ;
|
|
break;
|
|
case 'O':
|
|
uwsgi.py_optimize = atoi(optarg) ;
|
|
break;
|
|
#endif
|
|
case 't':
|
|
uwsgi.harakiri_timeout = atoi(optarg);
|
|
break;
|
|
case 'b':
|
|
uwsgi.buffer_size = atoi(optarg);
|
|
break;
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
case 'c':
|
|
uwsgi.cgi_mode = 1;
|
|
break;
|
|
#endif
|
|
case 'a':
|
|
uwsgi.abstract_socket = 1;
|
|
break;
|
|
case 'C':
|
|
uwsgi.chmod_socket = 1;
|
|
break;
|
|
#endif
|
|
case 'M':
|
|
uwsgi.master_process = 1;
|
|
break;
|
|
case 'R':
|
|
max_requests = atoi(optarg);
|
|
break;
|
|
case 'z':
|
|
if (atoi(optarg) > 0) {
|
|
uwsgi.socket_timeout = atoi(optarg) ;
|
|
}
|
|
break;
|
|
#ifndef ROCK_SOLID
|
|
case 'T':
|
|
uwsgi.has_threads = 1;
|
|
break;
|
|
case 'P':
|
|
uwsgi.enable_profiler = 1;
|
|
break;
|
|
case 'i':
|
|
uwsgi.single_interpreter = 1;
|
|
break;
|
|
#endif
|
|
#ifndef UNBIT
|
|
case 'h':
|
|
fprintf(stderr, "Usage: %s [options...]\n\
|
|
\t-s|--server <name>\t\tpath (or name) of UNIX/TCP socket to bind to\n\
|
|
\t-l|--listen <num>\t\tset socket listen queue to <n> (default 64, maximum is system dependent)\n\
|
|
\t-z|--socket-timeout <sec>\tset socket timeout to <sec> seconds (default 4 seconds)\n\
|
|
\t-b|--buffer-size <n>\t\tset buffer size to <n> bytes\n\
|
|
\t-L|--disable-logging\t\tdisable request logging (only errors or server messages will be logged)\n\
|
|
\t-x|--xmlconfig <path>\t\tpath of xml config file (no ROCK_SOLID)\n\
|
|
\t-w|--module <module>\t\tname of python config module (no ROCK_SOLID)\n\
|
|
\t-t|--harakiri <sec>\t\tset harakiri timeout to <sec> seconds\n\
|
|
\t-p|--processes <n>\t\tspawn <n> uwsgi worker processes\n\
|
|
\t-O|--optimize <n>\t\tset python optimization level to <n> (no ROCK_SOLID)\n\
|
|
\t-v|--max-vars <n>\t\tset maximum number of vars/headers to <n>\n\
|
|
\t-A|--sharedarea <n>\t\tcreate a shared memory area of <n> pages\n\
|
|
\t-c|--cgi-mode\t\t\tset cgi mode (no ROCK_SOLID) \n\
|
|
\t-C|--chmod-socket\t\tchmod socket to 666\n\
|
|
\t-P|--profiler\t\t\tenable profiler (no ROCK_SOLID)\n\
|
|
\t-m|--memory-report\t\tenable memory usage report (Linux/OSX only, no ROCK_SOLID)\n\
|
|
\t-i|--single-interpreter\t\tsingle interpreter mode (no ROCK_SOLID)\n\
|
|
\t-a|--abstract-socket\t\tset socket in the abstract namespace (Linux only)\n\
|
|
\t-T|--enable-threads\t\tenable threads support (no ROCK_SOLID)\n\
|
|
\t-M|--master\t\t\tenable master process manager\n\
|
|
\t-H|--home <path>\t\tset python home/virtualenv\n\
|
|
\t-h|--help\t\t\tthis help\n\
|
|
\t-d|--daemonize <logfile>\tdaemonize and log into <logfile>\n", argv[0]);
|
|
exit(1);
|
|
default:
|
|
exit(1);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.cgi_mode == 0) {
|
|
#endif
|
|
#endif
|
|
if (uwsgi.test_module == NULL) {
|
|
fprintf(stderr,"*** Starting uWSGI on [%.*s] ***\n", 24, ctime( (const time_t *) &uwsgi.start_tv.tv_sec));
|
|
}
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
else {
|
|
fprintf(stderr,"*** Starting uWSGI (CGI mode) on [%.*s] ***\n", 24, ctime( (const time_t *) &uwsgi.start_tv.tv_sec));
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __linux__
|
|
if (!getrlimit(RLIMIT_AS, &rl)) {
|
|
fprintf(stderr,"your process address space limit is %lld bytes (%lld MB)\n", (long long) rl.rlim_max, (long long) rl.rlim_max/1024/1024);
|
|
}
|
|
#endif
|
|
|
|
if (uwsgi.pyhome != NULL) {
|
|
fprintf(stderr,"Setting PythonHome to %s...\n", uwsgi.pyhome);
|
|
#ifdef PYTHREE
|
|
wchar_t *wpyhome ;
|
|
wpyhome = malloc((sizeof(wchar_t)*strlen(uwsgi.pyhome))+2) ;
|
|
if (!wpyhome) {
|
|
perror("malloc()");
|
|
exit(1);
|
|
}
|
|
mbstowcs(wpyhome, uwsgi.pyhome, strlen(uwsgi.pyhome));
|
|
Py_SetPythonHome(wpyhome);
|
|
free(wpyhome);
|
|
#else
|
|
Py_SetPythonHome(uwsgi.pyhome);
|
|
#endif
|
|
}
|
|
|
|
#ifdef PYTHREE
|
|
wchar_t pname[6] ;
|
|
mbstowcs(pname, "uWSGI", 6);
|
|
Py_SetProgramName(pname);
|
|
#else
|
|
Py_SetProgramName("uWSGI");
|
|
#endif
|
|
|
|
Py_Initialize() ;
|
|
|
|
#ifndef ROCK_SOLID
|
|
uwsgi.py_apps = PyDict_New();
|
|
if (!uwsgi.py_apps) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
wsgi_spitout = PyCFunction_New(uwsgi_spit_method,NULL) ;
|
|
wsgi_writeout = PyCFunction_New(uwsgi_write_method,NULL) ;
|
|
|
|
#ifndef PYTHREE
|
|
uwsgi_module = Py_InitModule("uwsgi", null_methods);
|
|
if (uwsgi_module == NULL) {
|
|
fprintf(stderr,"could not initialize the uwsgi python module\n");
|
|
exit(1);
|
|
}
|
|
if (uwsgi.sharedareasize > 0) {
|
|
#ifndef __OpenBSD__
|
|
uwsgi.sharedareamutex = mmap(NULL, sizeof(pthread_mutexattr_t) + sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE , MAP_SHARED|MAP_ANON , -1, 0);
|
|
if (!uwsgi.sharedareamutex) {
|
|
perror("mmap()");
|
|
exit(1);
|
|
}
|
|
#else
|
|
fprintf(stderr,"***WARNING*** the sharedarea on OpenBSD is not SMP-safe. Beware of race conditions !!!\n");
|
|
#endif
|
|
uwsgi.sharedarea = mmap(NULL, getpagesize() * uwsgi.sharedareasize, PROT_READ|PROT_WRITE , MAP_SHARED|MAP_ANON , -1, 0);
|
|
if (uwsgi.sharedarea) {
|
|
fprintf(stderr,"shared area mapped at %p, you can access it with uwsgi.sharedarea* functions.\n", uwsgi.sharedarea);
|
|
|
|
#ifdef __APPLE__
|
|
memset(uwsgi.sharedareamutex,0, sizeof(OSSpinLock));
|
|
#else
|
|
#ifndef __OpenBSD__
|
|
if (pthread_mutexattr_init((pthread_mutexattr_t *)uwsgi.sharedareamutex)) {
|
|
fprintf(stderr,"unable to allocate mutexattr structure\n");
|
|
exit(1);
|
|
}
|
|
if (pthread_mutexattr_setpshared((pthread_mutexattr_t *)uwsgi.sharedareamutex, PTHREAD_PROCESS_SHARED)) {
|
|
fprintf(stderr,"unable to share mutex\n");
|
|
exit(1);
|
|
}
|
|
if (pthread_mutex_init((pthread_mutex_t *) uwsgi.sharedareamutex + sizeof(pthread_mutexattr_t), (pthread_mutexattr_t *)uwsgi.sharedareamutex)) {
|
|
fprintf(stderr,"unable to initialize mutex\n");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
else {
|
|
perror("mmap()");
|
|
exit(1);
|
|
}
|
|
|
|
}
|
|
|
|
init_uwsgi_embedded_module();
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ROCK_SOLID
|
|
|
|
|
|
wi = malloc(sizeof(struct uwsgi_app));
|
|
if (wi == NULL) {
|
|
perror("malloc()");
|
|
exit(1);
|
|
}
|
|
memset(wi, 0, sizeof(struct uwsgi_app));
|
|
|
|
// load wsgi module/script
|
|
for (i = optind; i < argc; i++) {
|
|
init_uwsgi_vars();
|
|
wi->wsgi_module = PyImport_ImportModule(argv[i]);
|
|
if (!wi->wsgi_module) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
wi->wsgi_dict = PyModule_GetDict(wi->wsgi_module);
|
|
if (!wi->wsgi_dict) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
wi->wsgi_callable = PyDict_GetItemString(wi->wsgi_dict, "application");
|
|
if (!wi->wsgi_callable) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
wi->wsgi_environ = PyDict_New();
|
|
if (!wi->wsgi_environ) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
wi->wsgi_harakiri = PyDict_GetItemString(wi->wsgi_dict, "harakiri");
|
|
|
|
wi->wsgi_args = PyTuple_New(2) ;
|
|
if (!wi->wsgi_args) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyTuple_SetItem(wi->wsgi_args,0, wi->wsgi_environ)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyTuple_SetItem(wi->wsgi_args,1, wsgi_spitout)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!wi->wsgi_module) {
|
|
fprintf(stderr,"unable to find the wsgi script. Have you specified it ?\n");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
#ifndef ROCK_SOLID
|
|
Py_OptimizeFlag = uwsgi.py_optimize;
|
|
|
|
uwsgi.main_thread = PyThreadState_Get();
|
|
|
|
|
|
if (uwsgi.has_threads) {
|
|
PyEval_InitThreads() ;
|
|
fprintf(stderr, "threads support enabled\n");
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef UNBIT
|
|
if (socket_name != NULL && !is_a_reload) {
|
|
char *tcp_port = strchr(socket_name, ':');
|
|
if (tcp_port == NULL) {
|
|
serverfd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
|
|
}
|
|
else {
|
|
serverfd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port);
|
|
}
|
|
|
|
if (serverfd < 0) {
|
|
fprintf(stderr,"unable to create the server socket.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
socket_type_len = sizeof(int);
|
|
if (getsockopt(serverfd, SOL_SOCKET, SO_TYPE, &socket_type, &socket_type_len)) {
|
|
perror("getsockopt()");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.single_interpreter == 1) {
|
|
init_uwsgi_vars();
|
|
}
|
|
|
|
memset(uwsgi.wsgi_apps, 0, sizeof(uwsgi.wsgi_apps));
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uwsgi.poll.events = POLLIN ;
|
|
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.wsgi_config != NULL) {
|
|
uwsgi_wsgi_config();
|
|
}
|
|
#endif
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
else if (uwsgi.xml_config != NULL) {
|
|
uwsgi_xml_config();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if (uwsgi.test_module != NULL) {
|
|
if (PyImport_ImportModule(uwsgi.test_module)) {
|
|
exit(0);
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
|
|
uwsgi.mypid = getpid();
|
|
masterpid = uwsgi.mypid ;
|
|
|
|
if (uwsgi.buffer_size > 65536) {
|
|
fprintf(stderr,"invalid buffer size.\n");
|
|
exit(1);
|
|
}
|
|
buffer = malloc(uwsgi.buffer_size);
|
|
if (buffer == NULL) {
|
|
fprintf(stderr,"unable to allocate memory for buffer.\n");
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(stderr,"request/response buffer (%d bytes) allocated.\n", uwsgi.buffer_size);
|
|
|
|
|
|
|
|
/* shared area for workers */
|
|
uwsgi.workers = (struct uwsgi_worker *) mmap(NULL, sizeof(struct uwsgi_worker)*uwsgi.numproc+1, PROT_READ|PROT_WRITE , MAP_SHARED|MAP_ANON , -1, 0);
|
|
if (!uwsgi.workers) {
|
|
perror("mmap()");
|
|
exit(1);
|
|
}
|
|
memset(uwsgi.workers, 0, sizeof(struct uwsgi_worker)*uwsgi.numproc+1);
|
|
|
|
/* preforking() */
|
|
if (uwsgi.master_process) {
|
|
if (is_a_reload) {
|
|
fprintf(stderr, "gracefully (RE)spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
|
|
}
|
|
else {
|
|
fprintf(stderr, "spawned uWSGI master process (pid: %d)\n", uwsgi.mypid);
|
|
}
|
|
}
|
|
|
|
#ifdef UNBIT
|
|
if (single_app_mode == 1) {
|
|
wsgi_req.wsgi_script = getenv("UWSGI_SCRIPT");
|
|
if (wsgi_req.wsgi_script) {
|
|
wsgi_req.wsgi_script_len = strlen(wsgi_req.wsgi_script);
|
|
}
|
|
else {
|
|
fprintf(stderr, "UWSGI_SCRIPT env var not set !\n");
|
|
exit(1);
|
|
}
|
|
|
|
init_uwsgi_app(NULL, NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifndef ROCK_SOLID
|
|
if (spool_dir != NULL) {
|
|
spooler_pid = spooler_start(serverfd, uwsgi_module);
|
|
}
|
|
#endif
|
|
|
|
/* save the masterpid */
|
|
uwsgi.workers[0].pid = masterpid ;
|
|
for(i=1;i<uwsgi.numproc+1;i++) {
|
|
/* let the worker know his worker_id (wid) */
|
|
pid = fork();
|
|
if (pid == 0 ) {
|
|
uwsgi.mypid = getpid();
|
|
uwsgi.mywid = i;
|
|
if (serverfd != 0 && uwsgi.master_process == 1) {
|
|
/* close STDIN for workers */
|
|
close(0);
|
|
}
|
|
break;
|
|
}
|
|
else if (pid < 1) {
|
|
perror("fork()");
|
|
exit(1);
|
|
}
|
|
else {
|
|
fprintf(stderr, "spawned uWSGI worker %d (pid: %d)\n", i, pid);
|
|
uwsgi.workers[i].pid = pid ;
|
|
uwsgi.workers[i].id = i ;
|
|
gettimeofday(&last_respawn, NULL) ;
|
|
respawn_delta = last_respawn.tv_sec;
|
|
}
|
|
}
|
|
|
|
|
|
if (getpid() == masterpid && uwsgi.master_process == 1) {
|
|
/* route signals to workers... */
|
|
signal(SIGHUP, (void *) &grace_them_all);
|
|
signal(SIGTERM, (void *) &reap_them_all);
|
|
signal(SIGINT, (void *) &kill_them_all);
|
|
signal(SIGQUIT, (void *) &kill_them_all);
|
|
/* used only to avoid human-errors */
|
|
signal(SIGUSR1, (void *) &stats);
|
|
for(;;) {
|
|
if (ready_to_die >= uwsgi.numproc) {
|
|
#ifndef ROCK_SOLID
|
|
if (spool_dir && spooler_pid > 0) {
|
|
kill(spooler_pid, SIGKILL);
|
|
}
|
|
#endif
|
|
fprintf(stderr,"goodbye to uWSGI.\n");
|
|
exit(0);
|
|
}
|
|
if (ready_to_reload >= uwsgi.numproc) {
|
|
#ifndef ROCK_SOLID
|
|
if (spool_dir && spooler_pid > 0) {
|
|
kill(spooler_pid, SIGKILL);
|
|
}
|
|
#endif
|
|
fprintf(stderr,"binary reloading uWSGI...\n");
|
|
if (chdir(cwd)) {
|
|
perror("chdir()");
|
|
exit(1);
|
|
}
|
|
/* check fd table (a module can obviosly open some fd on initialization...) */
|
|
fprintf(stderr,"closing all fds > 2 (_SC_OPEN_MAX = %ld)...\n",sysconf(_SC_OPEN_MAX));
|
|
for(i=3;i<sysconf(_SC_OPEN_MAX);i++) {
|
|
if (i == serverfd) {
|
|
continue ;
|
|
}
|
|
close(i);
|
|
}
|
|
if (serverfd != 3) {
|
|
if (dup2(serverfd,3) < 0) {
|
|
perror("dup2()");
|
|
exit(1);
|
|
}
|
|
}
|
|
fprintf(stderr,"running %s\n", binary_path);
|
|
strcpy(argv[0], binary_path);
|
|
execve(binary_path, argv, envp);
|
|
perror("execve()");
|
|
exit(1);
|
|
}
|
|
diedpid = waitpid(WAIT_ANY , &waitpid_status, WNOHANG) ;
|
|
if (diedpid == -1) {
|
|
perror("waitpid()");
|
|
fprintf(stderr, "something horrible happened...\n");
|
|
reap_them_all();
|
|
exit(1);
|
|
}
|
|
else if (diedpid == 0) {
|
|
/* PLEASE, do not run python threads in the master process, you can potentially destroy the world,
|
|
we support this for hyperultramegagodprogrammer and systems
|
|
*/
|
|
if (uwsgi.has_threads) {
|
|
_save = PyEval_SaveThread();
|
|
}
|
|
/* all processes ok, doing status scan after 1 second */
|
|
select(0, NULL, NULL, NULL, &check_interval);
|
|
if (uwsgi.has_threads) {
|
|
PyEval_RestoreThread(_save);
|
|
}
|
|
check_interval.tv_sec = 1 ;
|
|
for(i=1;i<=uwsgi.numproc;i++) {
|
|
/* first check for harakiri */
|
|
if (uwsgi.workers[i].harakiri > 0) {
|
|
if (uwsgi.workers[i].harakiri < time(NULL)) {
|
|
/* first try to invoke the harakiri() custom handler */
|
|
/* TODO */
|
|
/* the brutally kill the worker */
|
|
kill(uwsgi.workers[i].pid, SIGKILL);
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
#ifndef ROCK_SOLID
|
|
/* reload the spooler */
|
|
if (spool_dir && spooler_pid > 0) {
|
|
if (diedpid == spooler_pid) {
|
|
spooler_pid = spooler_start(serverfd, uwsgi_module);
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
/* check for reloading */
|
|
if (WIFEXITED(waitpid_status)) {
|
|
if (WEXITSTATUS(waitpid_status) == UWSGI_RELOAD_CODE) {
|
|
ready_to_reload++;
|
|
continue;
|
|
}
|
|
else if (WEXITSTATUS(waitpid_status) == UWSGI_END_CODE) {
|
|
ready_to_die++;
|
|
continue;
|
|
}
|
|
}
|
|
fprintf(stderr,"DAMN ! process %d died :( trying respawn ...\n", diedpid);
|
|
gettimeofday(&last_respawn, NULL) ;
|
|
if (last_respawn.tv_sec == respawn_delta) {
|
|
fprintf(stderr,"worker respawning too fast !!! i have to sleep a bit...\n");
|
|
/* TODO, user configurable fork throttler */
|
|
sleep(2);
|
|
}
|
|
gettimeofday(&last_respawn, NULL) ;
|
|
respawn_delta = last_respawn.tv_sec;
|
|
uwsgi.mywid = find_worker_id(diedpid);
|
|
pid = fork();
|
|
if (pid == 0 ) {
|
|
uwsgi.mypid = getpid();
|
|
break;
|
|
}
|
|
else if (pid < 1) {
|
|
perror("fork()");
|
|
}
|
|
else {
|
|
fprintf(stderr, "Respawned uWSGI worker (new pid: %d)\n", pid);
|
|
if (uwsgi.mywid > 0) {
|
|
uwsgi.workers[uwsgi.mywid].pid = pid ;
|
|
uwsgi.workers[uwsgi.mywid].harakiri = 0 ;
|
|
uwsgi.workers[uwsgi.mywid].requests = 0 ;
|
|
uwsgi.workers[uwsgi.mywid].failed_requests = 0 ;
|
|
uwsgi.workers[uwsgi.mywid].respawn_count++ ;
|
|
uwsgi.workers[uwsgi.mywid].last_spawn = time(NULL) ;
|
|
}
|
|
else {
|
|
fprintf(stderr, "warning the died pid was not in the workers list. Probably you hit a BUG of uWSGI\n") ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
wsgi_req.app_id = uwsgi.default_app ;
|
|
wsgi_req.sendfile_fd = -1 ;
|
|
#endif
|
|
|
|
hvec = malloc(sizeof(struct iovec)*uwsgi.vec_size) ;
|
|
if (hvec == NULL) {
|
|
fprintf(stderr,"unable to allocate memory for iovec.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (uwsgi.harakiri_timeout > 0 && !uwsgi.master_process) {
|
|
signal(SIGALRM, (void *) &harakiri);
|
|
}
|
|
|
|
/* gracefully reload */
|
|
signal(SIGHUP, (void *) &gracefully_kill);
|
|
/* close the process (useful for master INT) */
|
|
signal(SIGINT, (void *) &end_me);
|
|
/* brutally reload */
|
|
signal(SIGTERM, (void *) &reload_me);
|
|
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
signal(SIGUSR1, (void *) &stats);
|
|
#endif
|
|
#endif
|
|
|
|
if (uwsgi.has_threads) {
|
|
_save = PyEval_SaveThread();
|
|
}
|
|
|
|
while(uwsgi.manage_next_request) {
|
|
|
|
uwsgi.in_request = 0 ;
|
|
uwsgi.poll.fd = accept(serverfd,(struct sockaddr *)&c_addr, (socklen_t *) &c_len) ;
|
|
uwsgi.in_request = 1 ;
|
|
|
|
if (uwsgi.poll.fd < 0){
|
|
perror("accept()");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
poll with timeout ;
|
|
*/
|
|
|
|
if (uwsgi.request_logging)
|
|
gettimeofday(&wsgi_req.start_of_request, NULL) ;
|
|
|
|
|
|
if (!uwsgi_parse_response(&uwsgi.poll, uwsgi.socket_timeout, (struct uwsgi_header *) &wsgi_req, buffer)) {
|
|
continue;
|
|
}
|
|
|
|
|
|
if (wsgi_req.modifier == UWSGI_MODIFIER_PING) {
|
|
fprintf(stderr,"PING\n");
|
|
wsgi_req.modifier_arg = 1 ;
|
|
if (write(uwsgi.poll.fd,&wsgi_req,4) != 4) {
|
|
perror("write()");
|
|
}
|
|
close(uwsgi.poll.fd);
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
continue;
|
|
}
|
|
else if (wsgi_req.modifier == UWSGI_MODIFIER_FASTFUNC) {
|
|
zero = PyList_GetItem(uwsgi.fastfuncslist, wsgi_req.modifier_arg) ;
|
|
if (zero) {
|
|
fprintf(stderr,"managing fastfunc %d\n", wsgi_req.modifier_arg) ;
|
|
wsgi_result = PyEval_CallObject(zero, NULL);
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
if (wsgi_result) {
|
|
wsgi_chunks = PyObject_GetIter(wsgi_result);
|
|
if (wsgi_chunks) {
|
|
while((wchunk = PyIter_Next(wsgi_chunks))) {
|
|
if (PyString_Check(wchunk)) {
|
|
wsgi_req.response_size += write(uwsgi.poll.fd, PyString_AsString(wchunk), PyString_Size(wchunk)) ;
|
|
}
|
|
Py_DECREF(wchunk);
|
|
}
|
|
Py_DECREF(wsgi_chunks);
|
|
}
|
|
Py_DECREF(wsgi_result);
|
|
}
|
|
}
|
|
PyErr_Clear();
|
|
close(uwsgi.poll.fd);
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
continue;
|
|
}
|
|
/* check for marshalled message */
|
|
else if (wsgi_req.modifier == UWSGI_MODIFIER_MESSAGE_MARSHAL) {
|
|
PyObject *umm = PyDict_GetItemString(uwsgi.embedded_dict, "message_manager_marshal");
|
|
if (umm) {
|
|
PyObject *ummo = PyMarshal_ReadObjectFromString(buffer, wsgi_req.size) ;
|
|
if (ummo) {
|
|
if (!PyTuple_SetItem(uwsgi.embedded_args, 0, ummo)) {
|
|
if (!PyTuple_SetItem(uwsgi.embedded_args, 1, PyInt_FromLong(wsgi_req.modifier_arg))) {
|
|
wsgi_result = PyEval_CallObject(umm, uwsgi.embedded_args);
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
if (wsgi_result) {
|
|
PyObject *marshalled = PyMarshal_WriteObjectToString(wsgi_result, 1);
|
|
if (!marshalled) {
|
|
PyErr_Print() ;
|
|
}
|
|
else {
|
|
if (PyString_Size(marshalled) <= 0xFFFF) {
|
|
wsgi_req.size = (uint16_t) PyString_Size(marshalled) ;
|
|
if (write(uwsgi.poll.fd, &wsgi_req, 4) == 4) {
|
|
if (write(uwsgi.poll.fd, PyString_AsString(marshalled), wsgi_req.size) != wsgi_req.size) {
|
|
perror("write()");
|
|
}
|
|
}
|
|
else {
|
|
perror("write()");
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr,"marshalled object is too big. skip\n");
|
|
}
|
|
Py_DECREF(marshalled);
|
|
}
|
|
Py_DECREF(wsgi_result);
|
|
}
|
|
}
|
|
}
|
|
//Py_DECREF(ummo);
|
|
}
|
|
}
|
|
PyErr_Clear();
|
|
close(uwsgi.poll.fd);
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
continue;
|
|
}
|
|
/* check for spooler request */
|
|
else if (wsgi_req.modifier == UWSGI_MODIFIER_SPOOL_REQUEST) {
|
|
|
|
if (spool_dir == NULL) {
|
|
fprintf(stderr,"the spooler is inactive !!!...skip\n");
|
|
wsgi_req.modifier = 255 ;
|
|
wsgi_req.size = 0 ;
|
|
wsgi_req.modifier_arg = 0 ;
|
|
i = write(uwsgi.poll.fd,&wsgi_req,4);
|
|
if (i != 4) {
|
|
perror("write()");
|
|
}
|
|
close(uwsgi.poll.fd);
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
continue;
|
|
}
|
|
|
|
fprintf(stderr,"managing spool request...\n");
|
|
i = spool_request(spool_filename, uwsgi.workers[0].requests+1, buffer,wsgi_req.size) ;
|
|
wsgi_req.modifier = 255 ;
|
|
wsgi_req.size = 0 ;
|
|
if (i > 0) {
|
|
wsgi_req.modifier_arg = 1 ;
|
|
if (write(uwsgi.poll.fd,&wsgi_req,4) != 4) {
|
|
fprintf(stderr,"disconnected client, remove spool file.\n");
|
|
/* client disconnect, remove spool file */
|
|
if (unlink(spool_filename)) {
|
|
perror("unlink()");
|
|
fprintf(stderr,"something horrible happened !!! check your spooler ASAP !!!\n");
|
|
goodbye_cruel_world();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* announce a failed spool request */
|
|
wsgi_req.modifier_arg = 0 ;
|
|
i = write(uwsgi.poll.fd,&wsgi_req,4);
|
|
if (i != 4) {
|
|
perror("write()");
|
|
}
|
|
}
|
|
close(uwsgi.poll.fd);
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
continue;
|
|
}
|
|
|
|
/* Standard WSGI request */
|
|
|
|
if (!wsgi_req.size) {
|
|
fprintf(stderr,"Invalid WSGI request. skip.\n");
|
|
close(uwsgi.poll.fd);
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
continue;
|
|
}
|
|
|
|
ptrbuf = buffer ;
|
|
bufferend = ptrbuf+wsgi_req.size ;
|
|
|
|
|
|
/* set an HTTP 500 status as default */
|
|
wsgi_req.status = 500;
|
|
|
|
|
|
while(ptrbuf < bufferend) {
|
|
if (ptrbuf+2 < bufferend) {
|
|
memcpy(&strsize,ptrbuf,2);
|
|
#ifdef __BIG_ENDIAN__
|
|
strsize = uwsgi_swap16(strsize);
|
|
#endif
|
|
ptrbuf+=2;
|
|
if (ptrbuf+strsize < bufferend) {
|
|
// var key
|
|
hvec[wsgi_req.var_cnt].iov_base = ptrbuf ;
|
|
hvec[wsgi_req.var_cnt].iov_len = strsize ;
|
|
ptrbuf+=strsize;
|
|
if (ptrbuf+2 < bufferend) {
|
|
memcpy(&strsize,ptrbuf,2);
|
|
#ifdef __BIG_ENDIAN__
|
|
strsize = uwsgi_swap16(strsize);
|
|
#endif
|
|
ptrbuf+=2 ;
|
|
if ( ptrbuf+strsize <= bufferend) {
|
|
#ifndef ROCK_SOLID
|
|
#ifdef UNBIT
|
|
if (single_app_mode == 0 && !strncmp("SCRIPT_NAME", hvec[wsgi_req.var_cnt].iov_base , hvec[wsgi_req.var_cnt].iov_len)) {
|
|
#else
|
|
if (!strncmp("SCRIPT_NAME", hvec[wsgi_req.var_cnt].iov_base , hvec[wsgi_req.var_cnt].iov_len)) {
|
|
#endif
|
|
// set the request app_id
|
|
// LOCKED SECTION
|
|
if (strsize > 0) {
|
|
if (uwsgi.has_threads) {
|
|
PyEval_RestoreThread(_save);
|
|
}
|
|
zero = PyString_FromStringAndSize(ptrbuf, strsize) ;
|
|
if (PyDict_Contains(uwsgi.py_apps, zero)) {
|
|
wsgi_req.app_id = PyInt_AsLong( PyDict_GetItem(uwsgi.py_apps, zero) );
|
|
}
|
|
else {
|
|
/* unavailable app for this SCRIPT_NAME */
|
|
wsgi_req.app_id = -1 ;
|
|
}
|
|
Py_DECREF(zero);
|
|
if (uwsgi.has_threads) {
|
|
_save = PyEval_SaveThread();
|
|
}
|
|
}
|
|
// UNLOCK
|
|
}
|
|
else if (!strncmp("SERVER_PROTOCOL", hvec[wsgi_req.var_cnt].iov_base , hvec[wsgi_req.var_cnt].iov_len)) {
|
|
#else
|
|
if (!strncmp("SERVER_PROTOCOL", hvec[wsgi_req.var_cnt].iov_base , hvec[wsgi_req.var_cnt].iov_len)) {
|
|
#endif
|
|
wsgi_req.protocol = ptrbuf ;
|
|
wsgi_req.protocol_len = strsize ;
|
|
}
|
|
else if (!strncmp("REQUEST_URI", hvec[wsgi_req.var_cnt].iov_base, hvec[wsgi_req.var_cnt].iov_len)) {
|
|
wsgi_req.uri = ptrbuf ;
|
|
wsgi_req.uri_len = strsize ;
|
|
}
|
|
else if (!strncmp("QUERY_STRING", hvec[wsgi_req.var_cnt].iov_base, hvec[wsgi_req.var_cnt].iov_len)) {
|
|
wsgi_req.query_string = ptrbuf ;
|
|
wsgi_req.query_string_len = strsize ;
|
|
}
|
|
else if (!strncmp("REQUEST_METHOD", hvec[wsgi_req.var_cnt].iov_base, hvec[wsgi_req.var_cnt].iov_len)) {
|
|
wsgi_req.method = ptrbuf ;
|
|
wsgi_req.method_len = strsize ;
|
|
}
|
|
else if (!strncmp("REMOTE_ADDR", hvec[wsgi_req.var_cnt].iov_base, hvec[wsgi_req.var_cnt].iov_len)) {
|
|
wsgi_req.remote_addr = ptrbuf ;
|
|
wsgi_req.remote_addr_len = strsize ;
|
|
}
|
|
else if (!strncmp("REMOTE_USER", hvec[wsgi_req.var_cnt].iov_base, hvec[wsgi_req.var_cnt].iov_len)) {
|
|
wsgi_req.remote_user = ptrbuf ;
|
|
wsgi_req.remote_user_len = strsize ;
|
|
}
|
|
#ifdef UNBIT
|
|
else if (!strncmp("UNBIT_FLAGS", hvec[wsgi_req.var_cnt].iov_base, hvec[wsgi_req.var_cnt].iov_len)) {
|
|
wsgi_req.unbit_flags = *(unsigned long long *) ptrbuf ;
|
|
}
|
|
#endif
|
|
if (wsgi_req.var_cnt < uwsgi.vec_size-(4+1)) {
|
|
wsgi_req.var_cnt++ ;
|
|
}
|
|
else {
|
|
fprintf(stderr, "max vec size reached. skip this header.\n");
|
|
break;
|
|
}
|
|
// var value
|
|
hvec[wsgi_req.var_cnt].iov_base = ptrbuf ;
|
|
hvec[wsgi_req.var_cnt].iov_len = strsize ;
|
|
if (wsgi_req.var_cnt < uwsgi.vec_size-(4+1)) {
|
|
wsgi_req.var_cnt++ ;
|
|
}
|
|
else {
|
|
fprintf(stderr, "max vec size reached. skip this header.\n");
|
|
break;
|
|
}
|
|
ptrbuf+=strsize;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.has_threads) {
|
|
PyEval_RestoreThread(_save);
|
|
}
|
|
#endif
|
|
|
|
wsgi_file = fdopen(uwsgi.poll.fd,"r") ;
|
|
|
|
#ifndef ROCK_SOLID
|
|
|
|
#ifndef UNBIT
|
|
if (wsgi_req.app_id == -1 && uwsgi.xml_config == NULL) {
|
|
#else
|
|
if (wsgi_req.app_id == -1 && uwsgi.wsgi_config == NULL) {
|
|
#endif
|
|
for(i=0;i<wsgi_req.var_cnt;i+=2) {
|
|
if (!strncmp("SCRIPT_NAME", hvec[i].iov_base, hvec[i].iov_len)) {
|
|
wsgi_req.script_name = hvec[i+1].iov_base ;
|
|
wsgi_req.script_name_len = hvec[i+1].iov_len ;
|
|
}
|
|
if (!strncmp("UWSGI_SCRIPT", hvec[i].iov_base, hvec[i].iov_len)) {
|
|
wsgi_req.wsgi_script = hvec[i+1].iov_base ;
|
|
wsgi_req.wsgi_script_len = hvec[i+1].iov_len ;
|
|
}
|
|
if (!strncmp("UWSGI_MODULE", hvec[i].iov_base, hvec[i].iov_len)) {
|
|
wsgi_req.wsgi_module = hvec[i+1].iov_base ;
|
|
wsgi_req.wsgi_module_len = hvec[i+1].iov_len ;
|
|
}
|
|
if (!strncmp("UWSGI_CALLABLE", hvec[i].iov_base, hvec[i].iov_len)) {
|
|
wsgi_req.wsgi_callable = hvec[i+1].iov_base ;
|
|
wsgi_req.wsgi_callable_len = hvec[i+1].iov_len ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (wsgi_req.wsgi_script_len > 0 || (wsgi_req.wsgi_callable_len > 0 && wsgi_req.wsgi_module_len > 0)) {
|
|
if ((wsgi_req.app_id = init_uwsgi_app(NULL, NULL)) == -1) {
|
|
internal_server_error(uwsgi.poll.fd, "wsgi application not found");
|
|
goto clean ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (wsgi_req.app_id == -1) {
|
|
internal_server_error(uwsgi.poll.fd, "wsgi application not found");
|
|
goto clean;
|
|
}
|
|
|
|
|
|
wi = &uwsgi.wsgi_apps[wsgi_req.app_id] ;
|
|
|
|
if (uwsgi.single_interpreter == 0) {
|
|
if (!wi->interpreter) {
|
|
internal_server_error(uwsgi.poll.fd, "wsgi application's %d interpreter not found");
|
|
goto clean;
|
|
}
|
|
|
|
// set the interpreter
|
|
PyThreadState_Swap(wi->interpreter) ;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
if (wsgi_req.protocol_len < 5) {
|
|
fprintf(stderr,"INVALID PROTOCOL: %.*s", wsgi_req.protocol_len, wsgi_req.protocol);
|
|
internal_server_error(uwsgi.poll.fd, "invalid HTTP protocol !!!");
|
|
goto clean;
|
|
}
|
|
if (strncmp(wsgi_req.protocol, "HTTP/", 5)) {
|
|
fprintf(stderr,"INVALID PROTOCOL: %.*s", wsgi_req.protocol_len, wsgi_req.protocol);
|
|
internal_server_error(uwsgi.poll.fd, "invalid HTTP protocol !!!");
|
|
goto clean;
|
|
}
|
|
|
|
|
|
|
|
/* max 1 minute before harakiri */
|
|
if (uwsgi.harakiri_timeout > 0) {
|
|
#ifdef UNBIT
|
|
if (wsgi_req.modifier != 0) {
|
|
switch(wsgi_req.modifier) {
|
|
case UWSGI_MODIFIER_HT_S:
|
|
set_harakiri(wsgi_req.modifier_arg);
|
|
case UWSGI_MODIFIER_HT_M:
|
|
set_harakiri(wsgi_req.modifier_arg*60);
|
|
case UWSGI_MODIFIER_HT_H:
|
|
set_harakiri(wsgi_req.modifier_arg*3600);
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
set_harakiri(uwsgi.harakiri_timeout);
|
|
#ifdef UNBIT
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
for(i=0;i<wsgi_req.var_cnt;i+=2) {
|
|
/*fprintf(stderr,"%.*s: %.*s\n", hvec[i].iov_len, hvec[i].iov_base, hvec[i+1].iov_len, hvec[i+1].iov_base);*/
|
|
pydictkey = PyString_FromStringAndSize(hvec[i].iov_base, hvec[i].iov_len) ;
|
|
pydictvalue = PyString_FromStringAndSize(hvec[i+1].iov_base, hvec[i+1].iov_len) ;
|
|
PyDict_SetItem(wi->wsgi_environ, pydictkey, pydictvalue);
|
|
Py_DECREF(pydictkey);
|
|
Py_DECREF(pydictvalue);
|
|
}
|
|
|
|
if (wsgi_req.modifier == UWSGI_MODIFIER_MANAGE_PATH_INFO) {
|
|
pydictkey = PyDict_GetItemString(wi->wsgi_environ,"SCRIPT_NAME");
|
|
if (pydictkey) {
|
|
if (PyString_Check(pydictkey)) {
|
|
pydictvalue = PyDict_GetItemString(wi->wsgi_environ,"PATH_INFO");
|
|
if (pydictvalue) {
|
|
if (PyString_Check(pydictvalue)) {
|
|
path_info = PyString_AsString(pydictvalue);
|
|
PyDict_SetItemString(wi->wsgi_environ, "PATH_INFO", PyString_FromString(path_info + PyString_Size(pydictkey)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// set wsgi vars
|
|
|
|
wsgi_socket = PyFile_FromFile(wsgi_file,"wsgi_input","r", NULL) ;
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.input", wsgi_socket );
|
|
Py_DECREF(wsgi_socket) ;
|
|
|
|
#ifndef ROCK_SOLID
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.file_wrapper", wi->wsgi_sendfile );
|
|
#endif
|
|
|
|
zero = PyTuple_New(2);
|
|
PyTuple_SetItem(zero, 0 , PyInt_FromLong(1));
|
|
PyTuple_SetItem(zero, 1 , PyInt_FromLong(0));
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.version", zero);
|
|
Py_DECREF(zero);
|
|
|
|
zero = PyFile_FromFile(stderr, "wsgi_input","w", NULL) ;
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.errors", zero );
|
|
Py_DECREF(zero) ;
|
|
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.run_once", Py_False);
|
|
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.multithread", Py_False);
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.multiprocess", Py_True);
|
|
|
|
zero = PyString_FromString("http") ;
|
|
PyDict_SetItemString(wi->wsgi_environ, "wsgi.url_scheme", zero);
|
|
Py_DECREF(zero);
|
|
|
|
#ifdef UNBIT
|
|
if (wsgi_req.unbit_flags & (unsigned long long) 1) {
|
|
if (uri_to_hex() <= 0) {
|
|
tmp_filename[0] = 0 ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
// call
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.enable_profiler == 1) {
|
|
wsgi_result = PyEval_CallObject(wi->wsgi_cprofile_run, wi->wsgi_args);
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
if (wsgi_result) {
|
|
Py_DECREF(wsgi_result);
|
|
wsgi_result = PyDict_GetItemString(wi->pymain_dict, "uwsgi_out");
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
|
|
wsgi_result = PyEval_CallObject(wi->wsgi_callable, wi->wsgi_args);
|
|
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
#endif
|
|
|
|
|
|
if (wsgi_result) {
|
|
|
|
#ifndef ROCK_SOLID
|
|
if (wsgi_req.sendfile_fd > -1) {
|
|
rlen = lseek(wsgi_req.sendfile_fd, 0, SEEK_END) ;
|
|
if (rlen > 0) {
|
|
lseek(wsgi_req.sendfile_fd, 0, SEEK_SET) ;
|
|
#ifndef __linux__
|
|
#ifdef __freebsd__
|
|
|
|
wsgi_req.response_size = sendfile(wsgi_req.sendfile_fd, uwsgi.poll.fd, 0, 0, NULL, (off_t *) &rlen, 0) ;
|
|
#elif __OpenBSD__ || __sun__
|
|
char *no_sendfile_buf[4096] ;
|
|
int jlen = 0 ;
|
|
i = 0 ;
|
|
while(i < rlen) {
|
|
jlen = read(wsgi_req.sendfile_fd, no_sendfile_buf, 4096);
|
|
if (jlen<=0) {
|
|
perror("read()");
|
|
break;
|
|
}
|
|
i += jlen;
|
|
jlen = write(uwsgi.poll.fd, no_sendfile_buf, jlen);
|
|
if (jlen<=0) {
|
|
perror("write()");
|
|
break;
|
|
}
|
|
|
|
}
|
|
#else
|
|
wsgi_req.response_size = sendfile(wsgi_req.sendfile_fd, uwsgi.poll.fd, 0, (off_t *) &rlen, NULL, 0) ;
|
|
#endif
|
|
#else
|
|
wsgi_req.response_size = sendfile(uwsgi.poll.fd, wsgi_req.sendfile_fd, NULL, rlen) ;
|
|
#endif
|
|
}
|
|
Py_DECREF(uwsgi.py_sendfile);
|
|
}
|
|
else {
|
|
|
|
#endif
|
|
wsgi_chunks = PyObject_GetIter(wsgi_result);
|
|
if (wsgi_chunks) {
|
|
while((wchunk = PyIter_Next(wsgi_chunks))) {
|
|
if (PyString_Check(wchunk)) {
|
|
wsgi_req.response_size += write(uwsgi.poll.fd, PyString_AsString(wchunk), PyString_Size(wchunk)) ;
|
|
#ifdef UNBIT
|
|
if (save_to_disk >= 0) {
|
|
if (write(save_to_disk, PyString_AsString(wchunk), PyString_Size(wchunk)) < 0) {
|
|
perror("write()");
|
|
close(save_to_disk);
|
|
save_to_disk = -1 ;
|
|
unlinkat(tmp_dir_fd, tmp_filename, 0);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
fprintf(stderr,"invalid output returned by the wsgi callable !!!\n");
|
|
}
|
|
Py_DECREF(wchunk);
|
|
}
|
|
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
|
|
#ifdef UNBIT
|
|
else if (save_to_disk >= 0) {
|
|
close(save_to_disk);
|
|
save_to_disk = -1 ;
|
|
fprintf(stderr,"[uWSGI cacher] output of request %d (%.*s) on pid %d written to cache file %s\n",uwsgi.workers[0].requests+1, wsgi_req.uri_len, wsgi_req.uri, uwsgi.mypid,tmp_filename);
|
|
}
|
|
#endif
|
|
Py_DECREF(wsgi_chunks);
|
|
}
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
if (uwsgi.enable_profiler == 0) {
|
|
#endif
|
|
Py_DECREF(wsgi_result);
|
|
#ifndef ROCK_SOLID
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
PyDict_Clear(wi->wsgi_environ);
|
|
#ifndef ROCK_SOLID
|
|
wi->requests++;
|
|
#endif
|
|
PyErr_Clear();
|
|
if (uwsgi.harakiri_timeout > 0) {
|
|
set_harakiri(0);
|
|
}
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.single_interpreter == 0) {
|
|
// restoring main interpreter
|
|
PyThreadState_Swap(uwsgi.main_thread);
|
|
}
|
|
clean:
|
|
#endif
|
|
fclose(wsgi_file);
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.has_threads) {
|
|
_save = PyEval_SaveThread();
|
|
}
|
|
#endif
|
|
uwsgi.workers[0].requests++; uwsgi.workers[uwsgi.mywid].requests++;
|
|
// GO LOGGING...
|
|
if (uwsgi.request_logging)
|
|
log_request() ;
|
|
// defunct process reaper
|
|
if (process_reaper == 1) {
|
|
waitpid(-1, &waitpid_status, WNOHANG);
|
|
}
|
|
// reset request
|
|
memset(&wsgi_req, 0, sizeof(struct wsgi_request));
|
|
#ifdef UNBIT
|
|
if (tmp_filename && tmp_dir_fd >= 0) {
|
|
tmp_filename[0] = 0 ;
|
|
}
|
|
#endif
|
|
|
|
#ifndef ROCK_SOLID
|
|
wsgi_req.app_id = uwsgi.default_app ;
|
|
wsgi_req.sendfile_fd = -1 ;
|
|
#endif
|
|
|
|
if (max_requests > 0 && uwsgi.workers[uwsgi.mywid].requests >= max_requests) {
|
|
goodbye_cruel_world();
|
|
}
|
|
|
|
#ifdef UNBIT
|
|
if (check_for_memory_errors) {
|
|
if (syscall(357,&us,0) > 0) {
|
|
if (us.memory_errors > 0) {
|
|
fprintf(stderr,"Unbit Kernel found a memory allocation error for process %d.\n", uwsgi.mypid);
|
|
goodbye_cruel_world();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
if (uwsgi.manage_next_request == 0) {
|
|
reload_me();
|
|
}
|
|
else {
|
|
goodbye_cruel_world();
|
|
}
|
|
|
|
/* never here */
|
|
return 0 ;
|
|
}
|
|
|
|
void log_request() {
|
|
char *time_request ;
|
|
struct timeval end_request ;
|
|
time_t microseconds, microseconds2;
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
char *msg1 = " via sendfile() " ;
|
|
char *msg2 = " " ;
|
|
char *via ;
|
|
struct uwsgi_app *wi;
|
|
int app_req = -1 ;
|
|
|
|
if (wsgi_req.app_id >= 0) {
|
|
wi = &uwsgi.wsgi_apps[wsgi_req.app_id] ;
|
|
if (wi->requests > 0) {
|
|
app_req = wi->requests ;
|
|
}
|
|
}
|
|
via = msg2 ;
|
|
if (wsgi_req.sendfile_fd > -1) {
|
|
via = msg1 ;
|
|
}
|
|
#endif
|
|
|
|
time_request = ctime( (const time_t *) &wsgi_req.start_of_request.tv_sec);
|
|
gettimeofday(&end_request, NULL) ;
|
|
microseconds = end_request.tv_sec*1000000+end_request.tv_usec ;
|
|
microseconds2 = wsgi_req.start_of_request.tv_sec*1000000+wsgi_req.start_of_request.tv_usec ;
|
|
#ifndef ROCK_SOLID
|
|
if (uwsgi.memory_debug == 1) {
|
|
get_memusage();
|
|
#ifndef UNBIT
|
|
fprintf(stderr,"{address space usage: %lld bytes/%lluMB} {rss usage: %llu bytes/%lluMB} ", uwsgi.workers[uwsgi.mywid].vsz_size, uwsgi.workers[uwsgi.mywid].vsz_size/1024/1024, uwsgi.workers[uwsgi.mywid].rss_size, uwsgi.workers[uwsgi.mywid].rss_size/1024/1024) ;
|
|
#else
|
|
fprintf(stderr,"{address space usage: %lld bytes/%lluMB} ", uwsgi.workers[uwsgi.mywid].vsz_size, uwsgi.workers[uwsgi.mywid].vsz_size/1024/1024) ;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#ifdef ROCK_SOLID
|
|
fprintf(stderr, "[pid: %d|req: %d] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %d bytes in %ld msecs (%.*s %d) %d headers in %d bytes\n",
|
|
uwsgi.mypid, uwsgi.workers[0].requests, wsgi_req.remote_addr_len, wsgi_req.remote_addr,
|
|
wsgi_req.remote_user_len, wsgi_req.remote_user, wsgi_req.var_cnt, wsgi_req.size, 24, time_request,
|
|
wsgi_req.method_len, wsgi_req.method, wsgi_req.uri_len, wsgi_req.uri, wsgi_req.response_size,
|
|
(microseconds-microseconds2)/1000,
|
|
wsgi_req.protocol_len, wsgi_req.protocol, wsgi_req.status, wsgi_req.header_cnt, wsgi_req.headers_size) ;
|
|
#else
|
|
fprintf(stderr, "[pid: %d|app: %d|req: %d/%llu] %.*s (%.*s) {%d vars in %d bytes} [%.*s] %.*s %.*s => generated %d bytes in %ld msecs%s(%.*s %d) %d headers in %d bytes\n",
|
|
uwsgi.mypid, wsgi_req.app_id, app_req, uwsgi.workers[0].requests, wsgi_req.remote_addr_len, wsgi_req.remote_addr,
|
|
wsgi_req.remote_user_len, wsgi_req.remote_user, wsgi_req.var_cnt, wsgi_req.size, 24, time_request,
|
|
wsgi_req.method_len, wsgi_req.method, wsgi_req.uri_len, wsgi_req.uri, wsgi_req.response_size,
|
|
(microseconds-microseconds2)/1000, via,
|
|
wsgi_req.protocol_len, wsgi_req.protocol, wsgi_req.status, wsgi_req.header_cnt, wsgi_req.headers_size) ;
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef ROCK_SOLID
|
|
void get_memusage() {
|
|
|
|
#ifdef UNBIT
|
|
uwsgi.workers[uwsgi.mywid].vsz_size = syscall(356);
|
|
#else
|
|
#ifdef __linux__
|
|
FILE *procfile;
|
|
int i;
|
|
procfile = fopen("/proc/self/stat","r");
|
|
if (procfile) {
|
|
i = fscanf(procfile,"%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %llu %lld",&uwsgi.workers[uwsgi.mywid].vsz_size, &uwsgi.workers[uwsgi.mywid].rss_size) ;
|
|
if (i != 2) {
|
|
fprintf(stderr, "warning: invalid record in /proc/self/stat\n");
|
|
}
|
|
fclose(procfile);
|
|
}
|
|
uwsgi.workers[uwsgi.mywid].rss_size = uwsgi.workers[uwsgi.mywid].rss_size*PAGE_SIZE;
|
|
#endif
|
|
#ifdef __APPLE__
|
|
/* darwin documentation says that the value are in pages, bot they are bytes !!! */
|
|
struct task_basic_info t_info;
|
|
mach_msg_type_number_t t_size = sizeof(struct task_basic_info);
|
|
|
|
if (task_info(mach_task_self(),TASK_BASIC_INFO, (task_info_t)&t_info, &t_size) == KERN_SUCCESS) {
|
|
uwsgi.workers[uwsgi.mywid].rss_size = t_info.resident_size;
|
|
uwsgi.workers[uwsgi.mywid].vsz_size = t_info.virtual_size;
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void init_uwsgi_vars() {
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
int i;
|
|
#endif
|
|
#endif
|
|
PyObject *wsgi_argv, *zero ;
|
|
PyObject *pysys, *pysys_dict, *pypath ;
|
|
|
|
/* stolen from mod_wsgi, sorry ;) */
|
|
wsgi_argv = PyList_New(0);
|
|
zero = PyString_FromString("uwsgi");
|
|
PyList_Append(wsgi_argv, zero);
|
|
PySys_SetObject("argv", wsgi_argv);
|
|
Py_DECREF(zero);
|
|
Py_DECREF(wsgi_argv);
|
|
|
|
|
|
/* add cwd and cvalue(TODO) to pythonpath */
|
|
pysys = PyImport_ImportModule("sys");
|
|
if (!pysys) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
pysys_dict = PyModule_GetDict(pysys);
|
|
pypath = PyDict_GetItemString(pysys_dict, "path");
|
|
if (!pypath) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyList_Insert(pypath,0,PyString_FromString(".")) != 0) {
|
|
PyErr_Print();
|
|
}
|
|
|
|
#ifndef UNBIT
|
|
#ifndef ROCK_SOLID
|
|
for(i=0; i< uwsgi.python_path_cnt; i++) {
|
|
if (PyList_Insert(pypath,0,PyString_FromString(uwsgi.python_path[i])) != 0) {
|
|
PyErr_Print();
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifndef ROCK_SOLID
|
|
int init_uwsgi_app(PyObject *force_wsgi_dict, PyObject *my_callable) {
|
|
PyObject *wsgi_module, *wsgi_dict ;
|
|
PyObject *pymain, *zero;
|
|
PyObject *pycprof, *pycprof_dict;
|
|
char tmpstring[256] ;
|
|
int id ;
|
|
|
|
struct uwsgi_app *wi ;
|
|
|
|
memset(tmpstring,0, 256) ;
|
|
|
|
|
|
if (wsgi_req.wsgi_script_len == 0 && ( (wsgi_req.wsgi_module_len == 0 || wsgi_req.wsgi_callable_len == 0) && uwsgi.wsgi_config == NULL && my_callable == NULL) ) {
|
|
fprintf(stderr, "invalid application (%.*s). skip.\n", wsgi_req.script_name_len, wsgi_req.script_name);
|
|
return -1;
|
|
}
|
|
|
|
if (uwsgi.wsgi_config && wsgi_req.wsgi_callable_len == 0 && my_callable == NULL) {
|
|
fprintf(stderr, "invalid application (%.*s). skip.\n", wsgi_req.script_name_len, wsgi_req.script_name);
|
|
return -1;
|
|
}
|
|
|
|
if (wsgi_req.wsgi_script_len > 255 || wsgi_req.wsgi_module_len > 255 || wsgi_req.wsgi_callable_len > 255) {
|
|
fprintf(stderr, "invalid application's string size. skip.\n");
|
|
return -1;
|
|
}
|
|
|
|
id = uwsgi.wsgi_cnt ;
|
|
|
|
|
|
if (wsgi_req.script_name_len == 0) {
|
|
wsgi_req.script_name_len = 1 ;
|
|
wsgi_req.script_name = (char *) app_slash ;
|
|
id = 0 ;
|
|
}
|
|
else if (wsgi_req.script_name_len == 1) {
|
|
if (wsgi_req.script_name[0] == '/') {
|
|
id = 0 ;
|
|
}
|
|
}
|
|
|
|
zero = PyString_FromStringAndSize(wsgi_req.script_name, wsgi_req.script_name_len);
|
|
if (!zero) {
|
|
Py_FatalError("cannot get mountpoint python object !\n");
|
|
}
|
|
|
|
if (PyDict_GetItem(uwsgi.py_apps, zero) != NULL) {
|
|
Py_DECREF(zero);
|
|
fprintf(stderr, "mountpoint %.*s already configured. skip.\n", wsgi_req.script_name_len, wsgi_req.script_name);
|
|
return -1;
|
|
}
|
|
|
|
Py_DECREF(zero);
|
|
|
|
wi = &uwsgi.wsgi_apps[id] ;
|
|
|
|
memset(wi, 0, sizeof(struct uwsgi_app));
|
|
|
|
if (uwsgi.single_interpreter == 0) {
|
|
wi->interpreter = Py_NewInterpreter();
|
|
if (!wi->interpreter) {
|
|
fprintf(stderr,"unable to initialize the new interpreter\n");
|
|
exit(1);
|
|
}
|
|
PyThreadState_Swap(wi->interpreter) ;
|
|
#ifndef PYTHREE
|
|
init_uwsgi_embedded_module();
|
|
#endif
|
|
init_uwsgi_vars();
|
|
fprintf(stderr,"interpreter for app %d initialized.\n", id);
|
|
}
|
|
|
|
|
|
|
|
if (uwsgi.wsgi_config == NULL) {
|
|
if (wsgi_req.wsgi_script_len > 0) {
|
|
memcpy(tmpstring, wsgi_req.wsgi_script, wsgi_req.wsgi_script_len) ;
|
|
wsgi_module = PyImport_ImportModule(tmpstring) ;
|
|
if (!wsgi_module) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
wsgi_req.wsgi_callable = "application" ;
|
|
wsgi_req.wsgi_callable_len = 11;
|
|
}
|
|
else {
|
|
memcpy(tmpstring, wsgi_req.wsgi_module, wsgi_req.wsgi_module_len) ;
|
|
wsgi_module = PyImport_ImportModule(tmpstring) ;
|
|
if (!wsgi_module) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
}
|
|
|
|
wsgi_dict = PyModule_GetDict(wsgi_module);
|
|
if (!wsgi_dict) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
|
|
}
|
|
else {
|
|
wsgi_dict = force_wsgi_dict;
|
|
}
|
|
|
|
|
|
memset(tmpstring, 0, 256);
|
|
memcpy(tmpstring, wsgi_req.wsgi_callable, wsgi_req.wsgi_callable_len) ;
|
|
if (my_callable) {
|
|
wi->wsgi_callable = my_callable;
|
|
Py_INCREF(my_callable);
|
|
}
|
|
else if (wsgi_dict) {
|
|
wi->wsgi_callable = PyDict_GetItemString(wsgi_dict, tmpstring);
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (!wi->wsgi_callable) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
|
|
|
|
wi->wsgi_environ = PyDict_New();
|
|
if (!wi->wsgi_environ) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
|
|
wi->wsgi_harakiri = PyDict_GetItemString(wsgi_dict, "harakiri");
|
|
if (wi->wsgi_harakiri) {
|
|
fprintf(stderr, "initialized Harakiri custom handler: %p.\n", wi->wsgi_harakiri);
|
|
}
|
|
|
|
|
|
if (uwsgi.enable_profiler) {
|
|
pymain = PyImport_AddModule("__main__");
|
|
if (!pymain) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
wi->pymain_dict = PyModule_GetDict(pymain);
|
|
if (!wi->pymain_dict) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyDict_SetItem(wi->pymain_dict, PyString_FromFormat("uwsgi_application__%d", id), wi->wsgi_callable)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyDict_SetItem(wi->pymain_dict, PyString_FromFormat("uwsgi_environ__%d", id), wi->wsgi_environ)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyDict_SetItem(wi->pymain_dict, PyString_FromFormat("uwsgi_spit__%d", id), wsgi_spitout)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
pycprof = PyImport_ImportModule("cProfile");
|
|
if (!pycprof) {
|
|
PyErr_Print();
|
|
fprintf(stderr, "trying old profile module... ");
|
|
pycprof = PyImport_ImportModule("profile");
|
|
if (!pycprof) {
|
|
fprintf(stderr, "doh!!!\n");
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
else {
|
|
fprintf(stderr, "ok and set stdout to linebuf mode.\n");
|
|
}
|
|
}
|
|
pycprof_dict = PyModule_GetDict(pycprof);
|
|
if (!pycprof_dict) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
wi->wsgi_cprofile_run = PyDict_GetItemString(pycprof_dict, "run");
|
|
if (!wi->wsgi_cprofile_run) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
wi->wsgi_args = PyTuple_New(1) ;
|
|
if (PyTuple_SetItem(wi->wsgi_args,0, PyString_FromFormat("uwsgi_out = uwsgi_application__%d(uwsgi_environ__%d,uwsgi_spit__%d)", id, id, id) )) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
}
|
|
else {
|
|
wi->wsgi_args = PyTuple_New(2) ;
|
|
if (PyTuple_SetItem(wi->wsgi_args,0, wi->wsgi_environ)) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
if (PyTuple_SetItem(wi->wsgi_args,1, wsgi_spitout)) {
|
|
PyErr_Print();
|
|
if (uwsgi.single_interpreter == 0) {
|
|
Py_EndInterpreter(wi->interpreter);
|
|
PyThreadState_Swap(uwsgi.main_thread) ;
|
|
}
|
|
return -1 ;
|
|
}
|
|
}
|
|
|
|
// prepare sendfile()
|
|
wi->wsgi_sendfile = PyCFunction_New(uwsgi_sendfile_method,NULL) ;
|
|
|
|
if (uwsgi.single_interpreter == 0) {
|
|
PyThreadState_Swap(uwsgi.main_thread);
|
|
}
|
|
|
|
memset(tmpstring, 0, 256);
|
|
memcpy(tmpstring, wsgi_req.script_name, wsgi_req.script_name_len);
|
|
PyDict_SetItemString(uwsgi.py_apps, tmpstring, PyInt_FromLong(id));
|
|
PyErr_Print();
|
|
|
|
fprintf(stderr,"application %d (%s) ready\n", id, tmpstring);
|
|
|
|
if (id == 0){
|
|
fprintf(stderr,"setting default application to 0\n");
|
|
uwsgi.default_app = 0 ;
|
|
}
|
|
else {
|
|
uwsgi.wsgi_cnt++;
|
|
}
|
|
|
|
return id ;
|
|
}
|
|
|
|
|
|
void uwsgi_wsgi_config() {
|
|
|
|
PyObject *wsgi_module, *wsgi_dict ;
|
|
PyObject *uwsgi_module, *uwsgi_dict ;
|
|
PyObject *applications;
|
|
PyObject *app_list;
|
|
int ret;
|
|
Py_ssize_t i;
|
|
PyObject *app_mnt, *app_app ;
|
|
|
|
wsgi_module = PyImport_ImportModule(uwsgi.wsgi_config) ;
|
|
if (!wsgi_module) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
wsgi_dict = PyModule_GetDict(wsgi_module);
|
|
if (!wsgi_dict) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(stderr,"...getting the applications list from the '%s' module...\n", uwsgi.wsgi_config);
|
|
|
|
uwsgi_module = PyImport_ImportModule("uwsgi") ;
|
|
if (!uwsgi_module) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
uwsgi_dict = PyModule_GetDict(uwsgi_module);
|
|
if (!uwsgi_dict) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
|
|
applications = PyDict_GetItemString(uwsgi_dict, "applications");
|
|
if (!PyDict_Check(applications)) {
|
|
fprintf(stderr,"uwsgi.applications dictionary is not defined, trying with the (deprecated) \"applications\" one...\n");
|
|
applications = PyDict_GetItemString(wsgi_dict, "applications");
|
|
if (!applications) {
|
|
fprintf(stderr,"applications dictionary is not defined, now you have to use dynamic apps.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!PyDict_Check(applications)) {
|
|
fprintf(stderr,"The 'applications' object must be a dictionary.\n");
|
|
exit(1);
|
|
}
|
|
|
|
app_list = PyDict_Keys(applications);
|
|
if (!app_list) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
if (PyList_Size(app_list) < 1) {
|
|
fprintf(stderr,"You must define an app.\n");
|
|
exit(1);
|
|
}
|
|
|
|
for(i=0;i<PyList_Size(app_list);i++) {
|
|
app_mnt = PyList_GetItem(app_list, i) ;
|
|
|
|
if (!PyString_Check(app_mnt)) {
|
|
fprintf(stderr, "the app mountpoint must be a string.\n");
|
|
exit(1);
|
|
}
|
|
|
|
wsgi_req.script_name = PyString_AsString(app_mnt);
|
|
wsgi_req.script_name_len = strlen(wsgi_req.script_name);
|
|
|
|
app_app = PyDict_GetItem(applications, app_mnt);
|
|
|
|
if (!PyString_Check(app_app) && !PyFunction_Check(app_app) && !PyCallable_Check(app_app)) {
|
|
fprintf(stderr, "the app callable must be a string, a function or a callable. (found %s)\n", app_app->ob_type->tp_name);
|
|
exit(1);
|
|
}
|
|
|
|
if (PyString_Check(app_app)) {
|
|
wsgi_req.wsgi_callable = PyString_AsString(app_app) ;
|
|
wsgi_req.wsgi_callable_len = strlen(wsgi_req.wsgi_callable);
|
|
fprintf(stderr,"initializing [%s => %s] app...\n", wsgi_req.script_name, wsgi_req.wsgi_callable);
|
|
ret = init_uwsgi_app(wsgi_dict, NULL);
|
|
}
|
|
else {
|
|
fprintf(stderr,"initializing [%s] app...\n", wsgi_req.script_name);
|
|
ret = init_uwsgi_app(wsgi_dict, app_app);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
fprintf(stderr,"...goodbye cruel world...\n");
|
|
exit(1);
|
|
}
|
|
Py_DECREF(app_mnt);
|
|
Py_DECREF(app_app);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// useless part for Unbit
|
|
#ifndef UNBIT
|
|
|
|
#ifndef ROCK_SOLID
|
|
|
|
void uwsgi_xml_config() {
|
|
xmlDoc *doc = NULL;
|
|
xmlNode *element = NULL;
|
|
xmlNode *node = NULL;
|
|
xmlNode *node2 = NULL;
|
|
|
|
xmlChar *xml_uwsgi_mountpoint = NULL;
|
|
xmlChar *xml_uwsgi_script = NULL ;
|
|
|
|
|
|
doc = xmlReadFile(uwsgi.xml_config, NULL, 0);
|
|
if (doc == NULL) {
|
|
fprintf(stderr, "could not parse file %s.\n", uwsgi.xml_config);
|
|
exit(1);
|
|
}
|
|
|
|
fprintf(stderr, "parsing config file %s\n", uwsgi.xml_config);
|
|
|
|
element = xmlDocGetRootElement(doc);
|
|
if (element == NULL) {
|
|
fprintf(stderr, "invalid xml config file.\n");
|
|
exit(1);
|
|
}
|
|
if (strcmp((char *)element->name, "uwsgi")) {
|
|
fprintf(stderr, "invalid xml root element, <uwsgi> expected.\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
// first check for pythonpath
|
|
for(node = element->children; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
if (!strcmp((char *) node->name, "pythonpath")) {
|
|
if (!node->children) {
|
|
fprintf(stderr, "no path defined for pythonpath. skip.\n");
|
|
continue;
|
|
}
|
|
if (!node->children->content) {
|
|
fprintf(stderr, "invalid path for pythonpath. skip.\n");
|
|
continue;
|
|
}
|
|
if (uwsgi.python_path_cnt < 63) {
|
|
uwsgi.python_path[uwsgi.python_path_cnt] = malloc( strlen((char *)node->children->content) + 1 );
|
|
memset(uwsgi.python_path[uwsgi.python_path_cnt], 0, strlen( (char *) node->children->content) + 1);
|
|
strcpy(uwsgi.python_path[uwsgi.python_path_cnt], (char *) node->children->content);
|
|
fprintf(stderr, "added %s to pythonpath.\n", uwsgi.python_path[uwsgi.python_path_cnt]);
|
|
uwsgi.python_path_cnt++;
|
|
}
|
|
else {
|
|
fprintf(stderr, "max pythonpath element reached. skip.\n");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ... then for wsgi apps
|
|
for(node = element->children; node; node = node->next) {
|
|
if (node->type == XML_ELEMENT_NODE) {
|
|
|
|
if (!strcmp((char *) node->name, "app")) {
|
|
xml_uwsgi_mountpoint = xmlGetProp(node, (const xmlChar *)"mountpoint");
|
|
if (xml_uwsgi_mountpoint == NULL) {
|
|
fprintf(stderr, "no mountpoint defined for app. skip.\n");
|
|
continue;
|
|
}
|
|
wsgi_req.script_name = (char *) xml_uwsgi_mountpoint ;
|
|
wsgi_req.script_name_len = strlen(wsgi_req.script_name);
|
|
|
|
for(node2 = node->children; node2; node2 = node2->next) {
|
|
if (node2->type == XML_ELEMENT_NODE) {
|
|
if (!strcmp((char *) node2->name, "script")) {
|
|
if (!node2->children) {
|
|
fprintf(stderr, "no wsgi script defined. skip.\n");
|
|
continue;
|
|
}
|
|
xml_uwsgi_script = node2->children->content ;
|
|
if (xml_uwsgi_script == NULL) {
|
|
fprintf(stderr, "no wsgi script defined. skip.\n");
|
|
continue;
|
|
}
|
|
wsgi_req.wsgi_script = (char *) xml_uwsgi_script ;
|
|
wsgi_req.wsgi_script_len = strlen(wsgi_req.wsgi_script);
|
|
init_uwsgi_app(NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
xmlFreeDoc(doc);
|
|
xmlCleanupParser();
|
|
|
|
fprintf(stderr, "config file parsed.\n");
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef UNBIT
|
|
int uri_to_hex()
|
|
{
|
|
int i=0,j=0 ;
|
|
|
|
if (wsgi_req.uri_len < 1) {
|
|
return 0 ;
|
|
}
|
|
|
|
if (wsgi_req.uri_len*2 > 8192) {
|
|
return 0 ;
|
|
}
|
|
|
|
for ( i = 0;i < wsgi_req.uri_len ; i++ ) {
|
|
sprintf(tmp_filename+j, "%02X", wsgi_req.uri[i]); j+=2;
|
|
}
|
|
|
|
return j ;
|
|
}
|
|
#endif
|
|
|
|
#ifndef PYTHREE
|
|
void init_uwsgi_embedded_module() {
|
|
PyObject *new_uwsgi_module, *zero;
|
|
int i ;
|
|
|
|
/* initialize for stats */
|
|
uwsgi.workers_tuple = PyTuple_New(uwsgi.numproc);
|
|
for(i=0;i<uwsgi.numproc;i++) {
|
|
zero = PyDict_New() ;
|
|
Py_INCREF(zero);
|
|
PyTuple_SetItem(uwsgi.workers_tuple, i, zero);
|
|
}
|
|
|
|
|
|
new_uwsgi_module = Py_InitModule("uwsgi", null_methods);
|
|
if (new_uwsgi_module == NULL) {
|
|
fprintf(stderr,"could not initialize the uwsgi python module\n");
|
|
exit(1);
|
|
}
|
|
|
|
uwsgi.embedded_dict = PyModule_GetDict(new_uwsgi_module);
|
|
if (!uwsgi.embedded_dict) {
|
|
fprintf(stderr,"could not get uwsgi module __dict__\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "SPOOL_RETRY", PyInt_FromLong(17))) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "numproc", PyInt_FromLong(uwsgi.numproc))) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "buffer_size", PyInt_FromLong(uwsgi.buffer_size))) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "started_on", PyInt_FromLong(uwsgi.start_tv.tv_sec))) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "start_response", wsgi_spitout)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "fastfuncs", PyList_New(256))) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
#ifndef ROCK_SOLID
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "applist", uwsgi.py_apps)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "applications", Py_None)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
uwsgi.embedded_args = PyTuple_New(2);
|
|
if (!uwsgi.embedded_args) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
if (PyDict_SetItemString(uwsgi.embedded_dict, "message_manager_marshal", Py_None)) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
uwsgi.fastfuncslist = PyDict_GetItemString(uwsgi.embedded_dict, "fastfuncs");
|
|
if (!uwsgi.fastfuncslist) {
|
|
PyErr_Print();
|
|
exit(1);
|
|
}
|
|
|
|
init_uwsgi_module_advanced(new_uwsgi_module);
|
|
|
|
if (spool_dir != NULL) {
|
|
init_uwsgi_module_spooler(new_uwsgi_module);
|
|
}
|
|
|
|
|
|
if (uwsgi.sharedareasize > 0 && uwsgi.sharedarea) {
|
|
init_uwsgi_module_sharedarea(new_uwsgi_module);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef ROCK_SOLID
|
|
pid_t spooler_start(int serverfd, PyObject *uwsgi_module) {
|
|
pid_t pid ;
|
|
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
perror("fork()");
|
|
exit(1);
|
|
}
|
|
else if (pid == 0) {
|
|
close(serverfd);
|
|
spooler(uwsgi_module);
|
|
}
|
|
else if (pid > 0) {
|
|
fprintf(stderr,"spawned the uWSGI spooler on dir %s with pid %d\n", spool_dir, pid);
|
|
}
|
|
|
|
return pid ;
|
|
}
|
|
#endif
|