Permalink
Browse files

Refactoring of @k3d3's initial Unix socket patch.

The 'port' argument of 'bjoern.run' may now be omitted if using
Unix sockets.
  • Loading branch information...
1 parent 59c44f2 commit 741f16914d6b5197146cbc297d563dbdd3df8cbe @jonashaag committed Jan 14, 2012
Showing with 71 additions and 61 deletions.
  1. +20 −7 bjoern/bjoernmodule.c
  2. +1 −1 bjoern/request.c
  3. +37 −23 bjoern/server.c
  4. +1 −1 http-parser
  5. +2 −1 tests/hello.py
  6. +10 −28 tests/hello_unix.py
View
@@ -14,7 +14,7 @@ static PyObject*
listen(PyObject* self, PyObject* args)
{
const char* host;
- int port;
+ int port = 0;
if(wsgi_app) {
PyErr_SetString(
@@ -24,20 +24,33 @@ listen(PyObject* self, PyObject* args)
return NULL;
}
- if(!PyArg_ParseTuple(args, "Osi:run/listen", &wsgi_app, &host, &port))
+ if(!PyArg_ParseTuple(args, "Os|i:run/listen", &wsgi_app, &host, &port))
return NULL;
_initialize_request_module(host, port);
+ if(!port) {
+ /* Unix socket: "unix:/tmp/foo.sock" or "unix:@abstract-socket" (Linux) */
+ if(strncmp("unix:", host, 5)) {
+ PyErr_Format(PyExc_ValueError, "'port' missing but 'host' is not a Unix socket");
+ goto err;
+ }
+ host += 5;
+ }
+
if(!server_init(host, port)) {
- PyErr_Format(
- PyExc_RuntimeError,
- "Could not start server on %s:%d", host, port
- );
- return NULL;
+ if(port)
+ PyErr_Format(PyExc_RuntimeError, "Could not start server on %s:%d", host, port);
+ else
+ PyErr_Format(PyExc_RuntimeError, "Could not start server on %s", host);
+ goto err;
}
Py_RETURN_NONE;
+
+err:
+ wsgi_app = NULL;
+ return NULL;
}
PyDoc_STRVAR(run_doc,
View
@@ -354,6 +354,6 @@ void _initialize_request_module(const char* server_host, const int server_port)
PyDict_SetItemString(
wsgi_base_dict,
"SERVER_PORT",
- PyString_FromFormat("%d", server_port)
+ server_port ? PyString_FromFormat("%d", server_port) : _empty_string
);
}
View
@@ -18,7 +18,6 @@
#define GIL_LOCK(n) PyGILState_STATE _gilstate_##n = PyGILState_Ensure()
#define GIL_UNLOCK(n) PyGILState_Release(_gilstate_##n)
-static int sockfd;
static const char* http_error_messages[4] = {
NULL, /* Error codes start at 1 because 0 means "no error" */
"HTTP/1.1 400 Bad Request\r\n\r\n",
@@ -38,12 +37,14 @@ static bool send_chunk(Request*);
static bool do_sendfile(Request*);
static bool handle_nonzero_errno(Request*);
+static struct { int fd; const char* filename; } sockinfo;
+
void server_run(void)
{
struct ev_loop* mainloop = ev_default_loop(0);
ev_io accept_watcher;
- ev_io_init(&accept_watcher, ev_io_on_request, sockfd, EV_READ);
+ ev_io_init(&accept_watcher, ev_io_on_request, sockinfo.fd, EV_READ);
ev_io_start(mainloop, &accept_watcher);
#if WANT_SIGINT_HANDLING
@@ -55,42 +56,51 @@ void server_run(void)
/* This is the program main loop */
Py_BEGIN_ALLOW_THREADS
ev_loop(mainloop, 0);
+ ev_default_destroy();
Py_END_ALLOW_THREADS
}
+static void cleanup() {
+ close(sockinfo.fd);
+ if(sockinfo.filename)
+ unlink(sockinfo.filename);
+}
+
#if WANT_SIGINT_HANDLING
static void
ev_signal_on_sigint(struct ev_loop* mainloop, ev_signal* watcher, const int events)
{
/* Clean up and shut down this thread.
* (Shuts down the Python interpreter if this is the main thread) */
+ cleanup();
ev_unloop(mainloop, EVUNLOOP_ALL);
PyErr_SetInterrupt();
}
#endif
bool server_init(const char* hostaddr, const int port)
{
- if(strncmp("unix:", hostaddr, 5) == 0) {
- if((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ if(!port) {
+ /* Unix socket */
+ if((sockinfo.fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
return false;
struct sockaddr_un sockaddr;
sockaddr.sun_family = PF_UNIX;
- strcpy(sockaddr.sun_path, hostaddr+5);
- if(hostaddr[5] == '@') sockaddr.sun_path[0] = '\0'; /* Use @ for abstract */
+ strcpy(sockaddr.sun_path, hostaddr);
- if(bind(sockfd, (struct sockaddr*)&sockaddr, strlen(hostaddr+5)+2) < 0)
- return false;
+ /* Use @ for abstract */
+ if(hostaddr[0] == '@')
+ sockaddr.sun_path[0] = '\0';
+ else
+ sockinfo.filename = hostaddr;
- if(listen(sockfd, LISTEN_BACKLOG) < 0)
- return false;
-
- DBG("Listening on %s...", hostaddr);
- return true;
+ if(bind(sockinfo.fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0)
+ goto err;
}
else {
- if((sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ /* IP bind */
+ if((sockinfo.fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return false;
struct sockaddr_in sockaddr;
@@ -100,17 +110,21 @@ bool server_init(const char* hostaddr, const int port)
/* Set SO_REUSEADDR t make the IP address available for reuse */
int optval = true;
- setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+ setsockopt(sockinfo.fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
- if(bind(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0)
- return false;
+ if(bind(sockinfo.fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0)
+ goto err;
+ }
- if(listen(sockfd, LISTEN_BACKLOG) < 0)
- return false;
+ if(listen(sockinfo.fd, LISTEN_BACKLOG) < 0)
+ goto err;
- DBG("Listening on %s:%d...", hostaddr, port);
- return true;
- }
+ DBG("Listening on %s:%d...", hostaddr, port);
+ return true;
+
+err:
+ cleanup();
+ return false;
}
static void
@@ -205,7 +219,7 @@ ev_io_on_read(struct ev_loop* mainloop, ev_io* watcher, const int events)
return;
}
-/* XXX too much gotos */
+/* XXX too many gotos */
static void
ev_io_on_write(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
View
@@ -25,4 +25,5 @@ def app4(e, s):
def wsgi_app(env, start_response):
return choice(apps)(env, start_response)
-bjoern.run(wsgi_app, '0.0.0.0', 8080)
+if __name__ == '__main__':
+ bjoern.run(wsgi_app, '0.0.0.0', 8080)
View
@@ -1,28 +1,10 @@
-import bjoern
-from random import choice
-
-def app1(env, sr):
- sr('200 ok', [('Foo', 'Bar'), ('Blah', 'Blubb'), ('Spam', 'Eggs'), ('Blurg', 'asdasjdaskdasdjj asdk jaks / /a jaksdjkas jkasd jkasdj '),
- ('asd2easdasdjaksdjdkskjkasdjka', 'oasdjkadk kasdk k k k k k ')])
- return ['hello', 'world']
-
-def app2(env, sr):
- sr('200 ok', [])
- return 'hello'
-
-def app3(env, sr):
- sr('200 abc', [('Content-Length', '12')])
- yield 'Hello'
- yield ' World'
- yield '\n'
-
-def app4(e, s):
- s('200 ok', [])
- return ['hello\n']
-
-apps = (app1, app2, app3, app4)
-
-def wsgi_app(env, start_response):
- return choice(apps)(env, start_response)
-
-bjoern.run(wsgi_app, 'unix:@hello_unix', 0)
+import sys
+from hello import *
+
+if __name__ == '__main__':
+ try:
+ host = sys.argv[1]
+ except IndexError:
+ host = 'hello_unix'
+ host = 'unix:' + host
+ bjoern.run(wsgi_app, host)

0 comments on commit 741f169

Please sign in to comment.