[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[Libevent-users] after the http client abruptly closes socket libevent (2.0.3-alpha) http server crashes


I want to slowly produce an http response (eg. one chunk per second),
so I extracted the http chunked test code from test/regress_http.c
into a separated file [0], adapted it a bit: use an timer instead of
directly calling event_once, and ignore the SIGPIPE signal.

The code workflow is something like:

1. when a http client connects, the http_chunked_cb function is called.
2. http_chunked_cb starts the http response by calling
evhttp_send_reply_start; it also starts a timer to call
3. http_chunked_trickle_cb writes a single chunk of data using
evhttp_send_reply_chunk and restarts the timer to call itself soon.
4. after some iterations, http_chunked_trickle_cb eventually calls
evhttp_send_reply_end to end the http response.

If the http client waits for all these steps to finish, all is good.
But if it abruptly closes the socket, the libevent code crashes
somewhere inside the evhttp_send_reply_chunk function:

Program received signal SIGSEGV, Segmentation fault.
0x0025f0e3 in evhttp_send_reply_chunk (req=0x804b930,
databuf=0x804bab0) at http.c:2082
2082		struct evbuffer *output = bufferevent_get_output(req->evcon->bufev);
(gdb) bt
#0  0x0025f0e3 in evhttp_send_reply_chunk (req=0x804b930,
databuf=0x804bab0) at http.c:2082
#1  0x08048b18 in http_chunked_trickle_cb (fd=-1, events=1,
arg=0x804bb68) at chunk.c:90
#2  0x0024df58 in event_process_active_single_queue (base=0x804b020,
flags=<value optimized out>) at event.c:925
#3  event_process_active (base=0x804b020, flags=<value optimized out>)
at event.c:978
#4  event_base_loop (base=0x804b020, flags=<value optimized out>) at
#5  0x0024eb95 in event_base_dispatch (event_base=0x804b020) at event.c:1005
#6  0x08048dd6 in main () at chunk.c:174

Here is the relevant code:

static void
http_chunked_cb(struct evhttp_request *req, void *arg)
        struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));

        memset(state, 0, sizeof(struct chunk_req_state));
        state->req = req;
        state->base = arg;
        state->timer = evtimer_new(state->base, http_chunked_trickle_cb, state);

        evhttp_send_reply_start(req, HTTP_OK, "OK");

        schedule_trickle(state, 0);

static void
http_chunked_trickle_cb(evutil_socket_t fd, short events, void *arg)
        struct chunk_req_state *state = arg;
        struct evbuffer *evb = evbuffer_new();

        evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
        evhttp_send_reply_chunk(state->req, evb);

        if (++state->i < sizeof(CHUNKS)/sizeof(CHUNKS[0])) {
                schedule_trickle(state, 1000);
        } else {
                // XXX TODO why no evtimer_free?

static void
schedule_trickle(struct chunk_req_state *state, int ms)
        struct timeval tv;
        tv.tv_sec = 0;
        tv.tv_usec = ms * 1000;
        // XXX TODO why no base argument in evtimer_add?
        evtimer_add(state->timer, &tv);

Please, see the entire code at [0].

I'm guessing that the evhttp_request req object is freed before
http_chunked_trickle_cb is called. At first I though on using
evhttp_request_own(req) would do the trick, but it didn't... So, what
you think is going on and how to fix it?


Best regards,
Rui Lopes

[0] chunk.c http://gist.github.com/291085

PS: This is my first piece of code that uses libevent, so if you find
anything to be improved, please let me known.
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.