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

Re: [Libevent-users] Problems with deferred HTTP handlers over SSL



Thanks for the help Mark.

On Sun, Jan 15, 2012 at 12:30 AM, Mark Ellzey <mthomas@xxxxxxxxxx> wrote:
> evhtp_use_threads() is a connection pooler, each thread having its own
> event_base, and each connection being accepted to that threads evbase.
>
> in this case here, you are double threading, thus you break out of evhtp
> and back into thread safety in libevent itself.
>
> Libevent needs to be setup as thread-safe too if it is to be used this
> way via one of the evthread_use_* functions.

I modified Amarin's test program to call evthread_use_pthreads()
[attached]. I also added BEV_OPT_THREADSAFE to the
bufferevent_openssl_socket_new/bufferevent_socket_new calls in
evhtp.c.

This improves things, however, I now see that the calls to
evhtp_send_reply in DeferredHandler do not return. Possibly internal
deadlock?

Additionally, about 1 in 5 requests never display in the browser but
instead wait forever (likely related to evhtp_send_reply not
returning).

Thanks,
-Andy
#include <unistd.h>
#include <pthread.h>
#include "evhtp.h"

void *DeferredHandler(void *arg) {
  sleep(1);
  evhtp_request_t *req = (evhtp_request_t*)arg;
  evhtp_headers_add_header(
      req->headers_out,
      evhtp_header_new("content-type", "text/plain; charset=utf-8", 0, 0));
  evbuffer_add(req->buffer_out, "hello", 5);
  printf("DeferredHandler -- before send_reply\n");
  evhtp_send_reply(req, EVHTP_RES_OK);
  printf("DeferredHandler -- after send_reply\n");
  pthread_exit(NULL);
}

void Handler(evhtp_request_t *req, void *) {
  pthread_t t;
  pthread_create(&t, NULL, DeferredHandler, (void*)req);
  pthread_detach(t);  // this fails
  // pthread_join(t, NULL);  // but this works
}

int main() {
  if (evthread_use_pthreads() != 0) {
    return 1;
  }

  evbase_t *base = event_base_new();
  if (!base) return 1;

  evhtp_t *http = evhtp_new(base, NULL);
  if (!http) return 1;

  evhtp_set_gencb(http, Handler, NULL);
  evhtp_use_threads(http, NULL, 4, NULL);

  evhtp_ssl_cfg_t scfg;
  char ciphers[] = "RC4+RSA:HIGH:+MEDIUM:+LOW";
  char libevhtp_pemfile[] = "libevhtp.pem";
  scfg.pemfile = libevhtp_pemfile;
  char libevhtp_privfile[] = "libevhtp.key";
  scfg.privfile = libevhtp_privfile;
  scfg.cafile = NULL;
  scfg.capath = NULL;
  scfg.ciphers = ciphers;
  scfg.ssl_opts = SSL_OP_NO_SSLv2;
  scfg.verify_peer = SSL_VERIFY_NONE;
  scfg.verify_depth = 0;
  scfg.x509_verify_cb = NULL;
  scfg.x509_chk_issued_cb = NULL;
  scfg.store_flags = 0;
  scfg.scache_type = evhtp_ssl_scache_type_internal;
  scfg.scache_timeout = 1024;
  scfg.scache_size = 1024;
  scfg.scache_init = NULL;
  scfg.scache_add = NULL;
  scfg.scache_get = NULL;
  scfg.scache_del = NULL;
  scfg.args = NULL;
  evhtp_ssl_init(http, &scfg);

  // bind and serve
  if (evhtp_bind_socket(http, "127.0.0.1", 1025, 128) == -1) return 1;
  event_base_loop(base, 0);
  event_base_free(base);

  return 0;
}