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 <ala...@yahoo.com> wrote:

> Hi,
>
> 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.
>
> #define KEY_STRING "CHECK"
>
> 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");
>           while(1)
>           {
>            if(startSend) //startSend is set to true when client does a
> GET & SSEEvents_cb() is invoked
>            {
>                  evbuffer *databuf = evbuffer_new();
>                    if (databuf != NULL)
>                    {
>
> evbuffer_add(databuf,"event:remoteEvent\n",strlen("event:remoteEvent\n"));
>
> evbuffer_add_printf(databuf,"data:TestDATA%d\n",counter);
>
>                         evhttp_send_reply_chunk(req, databuf);
>                         evbuffer_free(databuf);
>                         counter++;
>                                         if(10000 == counter)
>                                             counter = 0;
>                    }
>                    sleep(5);
>                         }
>                         else
>                         {
>                                 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_request_own(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;
>
>      }
>      else
>      {
>            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_init(&attr);
>      pthread_attr_setstacksize(&attr, (128 * 1024));     //128kbs
>      int threadCreate = -1;
>      threadCreate = pthread_create(&SenderThread, NULL, &sendChunk, NULL);
>
>      event_base_dispatch(base);
>      return 0;
> }
> int main(int argc , char *argv[])
> {
>      StartServer(argv[1], argv[2]);
> }
>
>
> Regards,
> Alap
>
>

Reply via email to