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

Re: [Libevent-users] Crash in evhttp_send_reply_chunk()

The example code you sent is expected to crash and burn randomly:

- You use multiple threads, but you do not configure libevent to use multithreading
- You do not synchronize the threads in your own code. For example, accessing startSend and req from multiple threads.
- You do not handle the connection close event - it should stop the sendChunk thread. 

I suggest to use the event loop -  Instead of the sendChunk thread, keep a 5 seconds timeout event for each connected client. Each time the timer runs, send a chunk if available.

On Wed, May 23, 2012 at 5:24 PM, Alap Kumar Sinha <alapks@xxxxxxxxx> wrote:
I am using libevent to implement a HTTP server. I am observing a crash & connection disconnect in libevent in the following scenario.
1.       The process starts a libevent HTTP server & registers for callbacks for different URLs.
2.       For one of the GET request from the client, the server needs to keep the connection open & send chunk replies as when data from some other source arrive.
3.       So it does a *_reply_start() & then *_reply_chunk() when data is available
Everything works fine at the beginning , but after a while (random could in 30 mins or couple of hours) observe the following issues
1.                 1. The libevent crashes. Checked the core dump analysis of multiple crashes & it points to the following code.
a.  0x0042b0a8 in evbuffer_add_buffer (outbuf=0x4924b8, inbuf=0x496428) at buffer.c:774
2.  Sometimes the connection between server & client gets disconnected. When checked through wireshark, observed a FIN ACK coming from the HTTP server.
Below is a simplified code snippet showcasing the implementation & use case.
I would appreciate if someone could let know, if I am doing something wrong in the usage of the libevent APIs & what could be the cause of the crash.

struct evhttp_request *req;  //Structure holds the req, on which chunk reply is sent
pthread_t SenderThread;
bool startSend = false;
void connectionClosed(struct evhttp_connection* evcon, void* key)
     printf("Connection closed by client");

//****** Function to send some data every 5 secs************/
void sendChunk(struct evhttp_connection* evcon, void* key)
     int counter = 0;
     printf("Start sending data everyy 5 secs");
           if(startSend) //startSend is set to true when client does a GET & SSEEvents_cb() is invoked
                 evbuffer *databuf = evbuffer_new();
                   if (databuf != NULL)
                        evhttp_send_reply_chunk(req, databuf);
                                        if(10000 == counter)
                                            counter = 0;
                                sleep(2); //Sleep for 2 secs & then check if the flag is set or not
 ///******Callback when Client does a GET on URL "/SSEEvents"********

void SSEEvents_cb(struct evhttp_request *aReq, void *key)
     if (EVHTTP_REQ_GET == aReq->type)
           const char * getUri = evhttp_request_get_uri(aReq);
           if( NULL == getUri )
                evhttp_send_reply(aReq, 400, "Bad request", NULL);   //Response back to client
           req = (evhttp_request*) aReq;
          evhttp_connection_set_closecb(evhttp_request_get_connection(aReq),&connectionClosed, KEY_STRING);
           evhttp_add_header(aReq->output_headers,"Content-Type","text/event-stream"); //Mandatory
           evhttp_send_reply_start(aReq, 200, "OK"); ///Start the reply & then set the flag so that chunk reply can be sent every 5 secs
           // Set this flag to true so that the sender thread can start sending chunk data
           startSend = true;
           evhttp_send_reply(aReq, 501, " SET Not Implemented", NULL);
int StartServer(char *aIPAddress, char *aPort)
     base = event_base_new();
     if (!base)
           printf("Couldn't create an event_base: So Exiting");
           return 1;
     /* Create a new evhttp object to handle requests. */
     http = evhttp_new(base);
     if (!http)
           printf("Couldn't create evhttp: So Exiting....");
           return 1;
     //Register for callback for any HTTP request for url "SSEEvents"
     evhttp_set_cb(http, "/SSEEvents", SSEEvents_cb, this);
     /* Now we tell the evhttp what port to listen on */
     uint16_t port = atoi(aPort);   
     handle = evhttp_bind_socket_with_handle(http, aIPAddress, port);
     if (!handle)
           printf("couldn't bind to IP & port %d. Exiting.",(uint16_t)port);
           return -1;
     ///** Launch Thread to send chunk reply after http client makes request   
     pthread_attr_t attr;
     pthread_attr_setstacksize(&attr, (128 * 1024));     //128kbs
     int threadCreate = -1;
     threadCreate = pthread_create(&SenderThread, NULL, &sendChunk, NULL);
     return 0;
int main(int argc , char *argv[])
     StartServer(argv[1], argv[2]);