diff --git a/Makefile b/Makefile index bf75a299..8a1b693e 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ UWSGI_CFLAGS=`python uwsgiconfig.py --cflags` UWSGI_LDFLAGS=`python uwsgiconfig.py --ldflags` CFLAGS=$(PYTHON_CFLAGS) $(UWSGI_CFLAGS) -LD_FLAGS=$(PYTHON_LIBS) $(UWSGI_LDFLAGS) +LD_FLAGS=$(PYTHON_LIBS) $(UWSGI_LDFLAGS) -export-dynamic PROGRAM=uwsgi diff --git a/plugins/example/example_plugin.c b/plugins/example/example_plugin.c index a83a654b..b8a1ffe7 100644 --- a/plugins/example/example_plugin.c +++ b/plugins/example/example_plugin.c @@ -1,20 +1,22 @@ #include "../../uwsgi.h" -/* gcc `python2.5-config --cflags` -o example_plugin.so -fPIC -shared example_plugin.c */ +/* gcc `python-config --cflags` `python ../../uwsgiconfig.py --cflags` -o example_plugin.so -fPIC -shared example_plugin.c */ int uwsgi_init(struct uwsgi_server *uwsgi, char *args){ fprintf(stderr,"i am the example plugin initialization function with arg: %s\n", args); return 0; } -int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, char *buffer) { +int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { char *http = "HTTP/1.1 200 Ok\r\nContent-type: text/html\r\n\r\n

Hello World

" ; wsgi_req->response_size += write(uwsgi->poll.fd, http, strlen(http)); + fprintf(stderr,"UWSGI POLL: %p\n", &uwsgi->poll); + return 0; } -void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, char *buffer) { +void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { fprintf(stderr,"i am the example plugin after request function\n"); } diff --git a/plugins/lua/lua_plugin.c b/plugins/lua/lua_plugin.c index 2004fe6b..ab13aaf1 100644 --- a/plugins/lua/lua_plugin.c +++ b/plugins/lua/lua_plugin.c @@ -85,9 +85,10 @@ int uwsgi_init(struct uwsgi_server *uwsgi, char *args){ } -int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, char *buffer) { +int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { char *ptrbuf; + char *buffer = uwsgi->buffer ; char *bufferend; uint16_t strsize = 0; int i; @@ -197,9 +198,18 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, cha // send status if (lua_type(ulua.L, -3) == LUA_TSTRING || lua_type(ulua.L, -3) == LUA_TNUMBER) { http = lua_tolstring(ulua.L, -3, &slen); - write(uwsgi->poll.fd, "HTTP/1.1 ", 9); - write(uwsgi->poll.fd, http, slen); - write(uwsgi->poll.fd, "\r\n", 2); + if (write(uwsgi->poll.fd, "HTTP/1.1 ", 9) != 9) { + perror("write()"); + return -1 ; + } + if (write(uwsgi->poll.fd, http, slen) != slen) { + perror("write()"); + return -1 ; + } + if (write(uwsgi->poll.fd, "\r\n", 2) != 2) { + perror("write()"); + return -1 ; + } } // send headers @@ -207,15 +217,30 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, cha lua_pushnil(ulua.L); while(lua_next(ulua.L, -3) != 0) { http = lua_tolstring(ulua.L, -2, &slen); - write(uwsgi->poll.fd, http, slen); - write(uwsgi->poll.fd, ": ", 2); + if (write(uwsgi->poll.fd, http, slen) != slen) { + perror("write()"); + return -1 ; + } + if (write(uwsgi->poll.fd, ": ", 2) != 2) { + perror("write()"); + return -1 ; + } http = lua_tolstring(ulua.L, -1, &slen); - write(uwsgi->poll.fd, http, slen); - write(uwsgi->poll.fd, "\r\n", 2); + if (write(uwsgi->poll.fd, http, slen) != slen) { + perror("write()"); + return -1 ; + } + if (write(uwsgi->poll.fd, "\r\n", 2) != 2) { + perror("write()"); + return -1 ; + } lua_pop(ulua.L, 1); } - write(uwsgi->poll.fd, "\r\n", 2); + if (write(uwsgi->poll.fd, "\r\n", 2) != 2) { + perror("write()"); + return -1 ; + } // send body with coroutine lua_pushvalue(ulua.L, -1); @@ -223,7 +248,10 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, cha while ( (i = lua_pcall(ulua.L, 0, 1, 0)) == 0) { if (lua_type(ulua.L, -1) == LUA_TSTRING) { http = lua_tolstring(ulua.L, -1, &slen); - write(uwsgi->poll.fd, http, slen); + if (write(uwsgi->poll.fd, http, slen) != slen) { + perror("write()"); + return -1 ; + } //fprintf(stderr,"%.*s\n", slen, http); } lua_pop(ulua.L, 1); @@ -236,6 +264,6 @@ int uwsgi_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, cha } -void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, char *buffer) { +void uwsgi_after_request(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { return; } diff --git a/protocol.c b/protocol.c index f06168c0..211c8a28 100644 --- a/protocol.c +++ b/protocol.c @@ -230,6 +230,75 @@ int uwsgi_parse_response(struct pollfd * upoll, int timeout, struct uwsgi_header return 1; } +int uwsgi_parse_vars(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req) { + + char *buffer = uwsgi->buffer ; + + char *ptrbuf, *bufferend ; + + uint16_t strsize = 0; + + 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 + uwsgi->hvec[wsgi_req->var_cnt].iov_base = ptrbuf; + uwsgi->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) { + 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"); + return -1; + } + // var value + uwsgi->hvec[wsgi_req->var_cnt].iov_base = ptrbuf; + uwsgi->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"); + return -1 ; + } + ptrbuf += strsize; + } + else { + return -1; + } + } + else { + return -1; + } + } + } + else { + return -1; + } + } + + return 0 ; +} + int uwsgi_ping_node(int node, struct wsgi_request *wsgi_req) { diff --git a/proxy.c b/proxy.c index 1de281c5..e7b0d34e 100644 --- a/proxy.c +++ b/proxy.c @@ -1,5 +1,17 @@ #ifdef UWSGI_PROXY +/* + + uWSGI proxy + + it needs one of this tecnology to work: + + - epoll (linux 2.6) + - kqueue (various BSD) + - /dev/poll Solaris + +*/ + #include "uwsgi.h" #include @@ -37,6 +49,10 @@ static void uwsgi_proxy_close(struct uwsgi_proxy_connection *upcs, int fd) { upcs[upcs[fd].dest_fd].dest_fd = -1 ; upcs[upcs[fd].dest_fd].status = 0 ; upcs[upcs[fd].dest_fd].retry = 0 ; + if (upcs[upcs[fd].dest_fd].node > -1) { + if (uwsgi.shared->nodes[upcs[upcs[fd].dest_fd].node].connections > 0) + uwsgi.shared->nodes[upcs[upcs[fd].dest_fd].node].connections--; + } } if (fd >= 0) { @@ -44,6 +60,10 @@ static void uwsgi_proxy_close(struct uwsgi_proxy_connection *upcs, int fd) { upcs[fd].dest_fd = -1 ; upcs[fd].status = 0 ; upcs[fd].retry = 0 ; + if (upcs[fd].node > -1) { + if (uwsgi.shared->nodes[upcs[fd].node].connections > 0) + uwsgi.shared->nodes[upcs[fd].node].connections--; + } } } @@ -59,11 +79,24 @@ static int uwsgi_proxy_find_next_node(int current_node) { // is it a good node ? if (uwsgi.shared->nodes[current_node].name[0] != 0 && uwsgi.shared->nodes[current_node].status == UWSGI_NODE_OK) { - return current_node ; + if (uwsgi.shared->nodes[current_node].connections < uwsgi.shared->nodes[current_node].workers) + return current_node ; } // try to find a better one + for(i=0;inodes[i].name[0] != 0 && uwsgi.shared->nodes[i].status == UWSGI_NODE_OK) { + if (uwsgi.shared->nodes[i].connections < uwsgi.shared->nodes[i].workers) + return i ; + } + } + + // ok, it is a very loaded system, fallback to round robin + if (uwsgi.shared->nodes[current_node].name[0] != 0 && uwsgi.shared->nodes[current_node].status == UWSGI_NODE_OK) { + return current_node ; + } + for(i=0;inodes[i].name[0] != 0 && uwsgi.shared->nodes[i].status == UWSGI_NODE_OK) { return i ; @@ -162,6 +195,7 @@ void uwsgi_proxy(int proxyfd) { perror("accept()"); continue; } + upcs[ee.data.fd].node = -1; // now connect to the first worker available @@ -171,6 +205,7 @@ void uwsgi_proxy(int proxyfd) { uwsgi_proxy_close(upcs, ee.data.fd); continue; } + upcs[upcs[ee.data.fd].dest_fd].node = -1; // set nonblocking if (ioctl(upcs[ee.data.fd].dest_fd, FIONBIO, &nonblocking)) { @@ -189,6 +224,7 @@ void uwsgi_proxy(int proxyfd) { } upcs[upcs[ee.data.fd].dest_fd].node = next_node ; rc = connect(upcs[ee.data.fd].dest_fd, (struct sockaddr *) &uwsgi.shared->nodes[next_node].ucn_addr, sizeof(struct sockaddr_in)); + uwsgi.shared->nodes[next_node].connections++; if (!rc) { // connected to worker, put it in the epoll_list diff --git a/uwsgi.c b/uwsgi.c index 02f46108..564b9405 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -130,20 +130,23 @@ void reap_them_all () { void harakiri () { PyThreadState *_myself; -#ifndef ROCK_SOLID + +/* CHECK ROCK_SOLID struct uwsgi_app *wi = NULL; if (wsgi_req.app_id >= 0) { wi = &uwsgi.wsgi_apps[wsgi_req.app_id]; } -#endif + end rock_solid */ + 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); @@ -196,7 +199,8 @@ PyObject *py_uwsgi_write (PyObject * self, PyObject * args) { if (PyString_Check (data)) { content = PyString_AsString (data); len = PyString_Size (data); -#ifndef ROCK_SOLID + +#ifdef UWSGI_THREADING if (uwsgi.has_threads && uwsgi.shared->options[UWSGI_OPTION_THREADS] == 1) { Py_BEGIN_ALLOW_THREADS wsgi_req.response_size = write (uwsgi.poll.fd, content, len); Py_END_ALLOW_THREADS} @@ -212,7 +216,7 @@ PyObject *py_uwsgi_write (PyObject * self, PyObject * args) { } } #endif -#ifndef ROCK_SOLID +#ifdef UWSGI_THREADING } #endif } @@ -234,12 +238,9 @@ 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 @@ -464,11 +465,9 @@ int main (int argc, char *argv[], char *envp[]) { uint64_t master_cycles = 0 ; struct timeval check_interval = {.tv_sec = 1,.tv_usec = 0 }; -#ifndef PYTHREE -#ifndef ROCK_SOLID +#ifdef UWSGI_EMBEDDED PyObject *uwsgi_module; -#endif #endif char *pyargv[MAX_PYARGV]; int pyargc = 1; @@ -654,6 +653,8 @@ int main (int argc, char *argv[], char *envp[]) { } } + uwsgi.binary_path = argv[0] ; + #ifndef UNBIT 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 @@ -669,7 +670,7 @@ int main (int argc, char *argv[], char *envp[]) { } #endif - if (uwsgi.binary_path == NULL) { + if (uwsgi.binary_path == argv[0]) { cwd = uwsgi_get_cwd (); uwsgi.binary_path = malloc (strlen (argv[0]) + 1); if (uwsgi.binary_path == NULL) { @@ -680,9 +681,7 @@ int main (int argc, char *argv[], char *envp[]) { } #ifndef UNBIT -#ifndef ROCK_SOLID if (uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] == 0) { -#endif #endif if (uwsgi.test_module == NULL) { fprintf (stderr, "*** Starting uWSGI (%dbit) on [%.*s] ***\n", (int) (sizeof (void *)) * 8, 24, ctime ((const time_t *) &uwsgi.start_tv.tv_sec)); @@ -848,8 +847,7 @@ int main (int argc, char *argv[], char *envp[]) { wsgi_spitout = PyCFunction_New (uwsgi_spit_method, NULL); wsgi_writeout = PyCFunction_New (uwsgi_write_method, NULL); -#ifndef PYTHREE -#ifndef ROCK_SOLID +#ifdef UWSGI_EMBEDDED uwsgi_module = Py_InitModule ("uwsgi", null_methods); if (uwsgi_module == NULL) { fprintf (stderr, "could not initialize the uwsgi python module\n"); @@ -898,7 +896,6 @@ int main (int argc, char *argv[], char *envp[]) { init_uwsgi_embedded_module (); #endif -#endif @@ -1198,13 +1195,11 @@ int main (int argc, char *argv[], char *envp[]) { #ifndef UNBIT -#ifndef ROCK_SOLID if (no_server) { fprintf (stderr, "no-server mode requested. Goodbye.\n"); exit (0); } #endif -#endif // is this a proxy only worker ? @@ -1678,6 +1673,7 @@ int main (int argc, char *argv[], char *envp[]) { } else { #endif + fprintf(stderr,"POLL ADDR: %p\n", &uwsgi.poll); if (!uwsgi_parse_response (&uwsgi.poll, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], (struct uwsgi_header *) &wsgi_req, uwsgi.buffer)) { continue; } @@ -1791,7 +1787,6 @@ void init_uwsgi_vars () { } -#ifndef ROCK_SOLID int init_uwsgi_app (PyObject * force_wsgi_dict, PyObject * my_callable) { PyObject *wsgi_module, *wsgi_dict = NULL; PyObject *pymain, *zero; @@ -2310,7 +2305,6 @@ void uwsgi_wsgi_config () { } -#endif #ifdef UNBIT int uri_to_hex () { @@ -2511,7 +2505,6 @@ pid_t spooler_start (int serverfd, PyObject * uwsgi_module) { void manage_opt(int i, char *optarg) { switch (i) { -#ifndef ROCK_SOLID #ifndef UNBIT case LONG_ARGS_PIDFILE: uwsgi.pidfile = optarg; @@ -2565,7 +2558,6 @@ void manage_opt(int i, char *optarg) { uwsgi.rl.rlim_cur = (atoi (optarg)) * 1024 * 1024; uwsgi.rl.rlim_max = uwsgi.rl.rlim_cur; break; -#endif case LONG_ARGS_PASTE: uwsgi.single_interpreter = 1; uwsgi.paste = optarg; @@ -2650,7 +2642,6 @@ void manage_opt(int i, char *optarg) { case 'r': uwsgi.shared->options[UWSGI_OPTION_REAPER] = 1; break; -#ifndef ROCK_SOLID case 'w': uwsgi.single_interpreter = 1; uwsgi.wsgi_config = optarg; @@ -2661,7 +2652,6 @@ void manage_opt(int i, char *optarg) { case 'O': uwsgi.py_optimize = atoi (optarg); break; -#endif case 't': uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] = atoi (optarg); break; @@ -2669,11 +2659,9 @@ void manage_opt(int i, char *optarg) { uwsgi.buffer_size = atoi (optarg); break; #ifndef UNBIT -#ifndef ROCK_SOLID case 'c': uwsgi.shared->options[UWSGI_OPTION_CGI_MODE] = 1; break; -#endif case 'a': uwsgi.abstract_socket = 1; break; @@ -2692,7 +2680,6 @@ void manage_opt(int i, char *optarg) { uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT] = atoi (optarg); } break; -#ifndef ROCK_SOLID case 'T': uwsgi.has_threads = 1; uwsgi.shared->options[UWSGI_OPTION_THREADS] = 1; @@ -2703,7 +2690,6 @@ void manage_opt(int i, char *optarg) { case 'i': uwsgi.single_interpreter = 1; break; -#endif #ifndef UNBIT case 'h': fprintf (stdout, "Usage: %s [options...]\n\ @@ -2746,6 +2732,14 @@ void manage_opt(int i, char *optarg) { \t--pyargv \t\t\tassign args to python sys.argv\n\ \t--limit-as \t\t\tlimit the address space of processes to MB megabytes\n\ \t--udp \t\t\tbind master process to udp socket on ip:port\n\ +\t--erlang \t\tenable the Erlang server with node name \n\ +\t--erlang-cookie \ttset the erlang cookie to \n\ +\t--nagios\t\t\tdo a nagios check\n\ +\t--binary-path \ttset the path for the next reload of uWSGI (needed for chroot environments)\n\ +\t--proxy \t\trun the uwsgi proxy on socket \n\ +\t--proxy-node \t\tadd the node to the proxy\n\ +\t--proxy-max-connections \tset the max number of concurrent connections mnaged by the proxy\n\ +\t--wsgi-file \t\tload the wsgi file\n\ \t-d|--daemonize \tdaemonize and log into \n", uwsgi.binary_path); exit (1); case 0: diff --git a/uwsgi.h b/uwsgi.h index b7eff705..20de96b1 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -394,6 +394,7 @@ struct uwsgi_cluster_node { struct sockaddr_in ucn_addr; int workers ; + int connections ; int status ; time_t last_seen; @@ -528,6 +529,7 @@ struct uwsgi_cluster_node { PyObject *uwsgi_send_message (const char *, int, uint8_t, uint8_t, char *, int, int); int uwsgi_parse_response (struct pollfd *, int, struct uwsgi_header *, char *); + int uwsgi_parse_vars (struct uwsgi_server *, struct wsgi_request *); int uwsgi_enqueue_message (char *, int, uint8_t, uint8_t, char *, int, int); diff --git a/uwsgi_pymodule.c b/uwsgi_pymodule.c index bcbf910e..72f8a7be 100644 --- a/uwsgi_pymodule.c +++ b/uwsgi_pymodule.c @@ -541,7 +541,7 @@ PyObject *py_uwsgi_load_plugin(PyObject *self, PyObject *args) { return NULL ; } - plugin_handle = dlopen(plugin_name, RTLD_LAZY); + plugin_handle = dlopen(plugin_name, RTLD_NOW|RTLD_GLOBAL); if (!plugin_handle) { fprintf (stderr, "%s\n", dlerror()); }