Exemplo n.º 1
0
int
main(int argc, char ** argv) {
    evbase_t           * evbase;
    evhtp_connection_t * conn;
    evhtp_request_t    * request;

    evbase  = event_base_new();
    conn    = evhtp_connection_new(evbase, "75.126.169.52", 80);
    request = evhtp_request_new(request_cb, evbase);

    evhtp_set_hook(&request->hooks, evhtp_hook_on_read, print_data, evbase);
    evhtp_set_hook(&request->hooks, evhtp_hook_on_new_chunk, print_new_chunk_len, NULL);
    evhtp_set_hook(&request->hooks, evhtp_hook_on_chunk_complete, print_chunk_complete, NULL);
    evhtp_set_hook(&request->hooks, evhtp_hook_on_chunks_complete, print_chunks_complete, NULL);

    evhtp_headers_add_header(request->headers_out,
                             evhtp_header_new("Host", "ieatfood.net", 0, 0));
    evhtp_headers_add_header(request->headers_out,
                             evhtp_header_new("User-Agent", "libevhtp", 0, 0));
    evhtp_headers_add_header(request->headers_out,
                             evhtp_header_new("Connection", "close", 0, 0));

    evhtp_make_request(conn, request, htp_method_GET, "/");

    event_base_loop(evbase, 0);
    event_base_free(evbase);

    return 0;
}
Exemplo n.º 2
0
int
upload_file_init (evhtp_t *htp)
{
    evhtp_callback_t *cb;

    if (g_mkdir_with_parents (TEMP_FILE_DIR, 0777) < 0) {
        seaf_warning ("Failed to create temp file dir %s.\n", TEMP_FILE_DIR);
        return -1;
    }

    cb = evhtp_set_regex_cb (htp, "^/upload/.*", upload_cb, NULL);
    /* upload_headers_cb() will be called after evhtp parsed all http headers. */
    evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL);

    cb = evhtp_set_regex_cb (htp, "^/update/.*", update_cb, NULL);
    evhtp_set_hook(&cb->hooks, evhtp_hook_on_headers, upload_headers_cb, NULL);

    evhtp_set_regex_cb (htp, "^/upload_progress.*", upload_progress_cb, NULL);

    upload_progress = g_hash_table_new_full (g_str_hash, g_str_equal,
                                             g_free, g_free);
    pthread_mutex_init (&pg_lock, NULL);

    return 0;
}
Exemplo n.º 3
0
static evhtp_res
set_my_connection_handlers(evhtp_connection_t * conn, void * arg) {
    struct timeval               tick;
    struct ev_token_bucket_cfg * tcfg = NULL;

    evhtp_set_hook(&conn->hooks, evhtp_hook_on_header, print_kv, "foo");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_headers, print_kvs, "bar");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_path, print_path, "baz");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_read, print_data, "derp");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_new_chunk, print_new_chunk_len, NULL);
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_chunk_complete, print_chunk_complete, NULL);
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_chunks_complete, print_chunks_complete, NULL);
    /* evhtp_set_hook(&conn->hooks, evhtp_hook_on_hostname, print_hostname, NULL); */

    if (bw_limit > 0) {
        tick.tv_sec  = 0;
        tick.tv_usec = 500 * 100;

        tcfg         = ev_token_bucket_cfg_new(bw_limit, bw_limit, bw_limit, bw_limit, &tick);

        bufferevent_set_rate_limit(conn->bev, tcfg);
    }

    evhtp_set_hook(&conn->hooks, evhtp_hook_on_request_fini, test_fini, tcfg);

    return EVHTP_RES_OK;
}
Exemplo n.º 4
0
static evhtp_res
pause_init_cb(evhtp_request_t * req, evhtp_path_t * path, void * arg) {
    evbase_t      * evbase = req->conn->evbase;
    struct pauser * pause  = calloc(sizeof(struct pauser), 1);

    pause->tv       = calloc(sizeof(struct timeval), 1);

    pause->timer_ev = evtimer_new(evbase, resume_request_timer, pause);
    pause->request  = req;

    evhtp_set_hook(&req->hooks, evhtp_hook_on_header, pause_cb, pause);
    evhtp_set_hook(&req->hooks, evhtp_hook_on_request_fini, pause_request_fini, pause);
    evhtp_set_hook(&req->conn->hooks, evhtp_hook_on_connection_fini, pause_connection_fini, NULL);

    return EVHTP_RES_OK;
}
Exemplo n.º 5
0
Arquivo: test.c Projeto: pibi/libevhtp
static evhtp_res
set_my_connection_handlers(evhtp_connection_t * conn, void * arg ) {
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_header, print_kv, "foo");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_headers, print_kvs, "bar");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_path, print_path, "baz");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_read, print_data, "derp");
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_new_chunk, print_new_chunk_len, NULL);
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_chunk_complete, print_chunk_complete, NULL);
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_chunks_complete, print_chunks_complete, NULL);
    evhtp_set_hook(&conn->hooks, evhtp_hook_on_request_fini, test_fini, NULL);

    return EVHTP_RES_OK;
}
Exemplo n.º 6
0
int
main(int argc, char ** argv) {
    struct event     * ev_sigint;
    evbase_t         * evbase = NULL;
    evhtp_t          * htp    = NULL;
    evhtp_callback_t * cb_1   = NULL;
    evhtp_callback_t * cb_2   = NULL;
    evhtp_callback_t * cb_3   = NULL;
    evhtp_callback_t * cb_4   = NULL;
    evhtp_callback_t * cb_5   = NULL;

#ifndef EVHTP_DISABLE_REGEX
    evhtp_callback_t * cb_6   = NULL;
#endif
    evhtp_callback_t * cb_7   = NULL;
#ifndef EVHTP_DISABLE_REGEX
    evhtp_callback_t * cb_8   = NULL;
#endif
    evhtp_callback_t * cb_9   = NULL;
    evhtp_callback_t * cb_10  = NULL;
    evhtp_callback_t * cb_11  = NULL;
    evhtp_callback_t * cb_12  = NULL;

    if (parse_args(argc, argv) < 0) {
        exit(1);
    }

    srand((unsigned)time(NULL));

    evbase = event_base_new();
    htp    = evhtp_new(evbase, NULL);

    evhtp_set_parser_flags(htp, EVHTP_PARSE_QUERY_FLAG_LENIENT);
    evhtp_set_max_keepalive_requests(htp, max_keepalives);

    //htp->enable_nodelay = 1;
    //htp->enable_defer_accept = 1;
    htp->enable_reuseport = 1;

    cb_1   = evhtp_set_cb(htp, "/ref", test_default_cb, "fjdkls");
    cb_2   = evhtp_set_cb(htp, "/foo", test_foo_cb, "bar");
    cb_3   = evhtp_set_cb(htp, "/foo/", test_foo_cb, "bar");
    cb_4   = evhtp_set_cb(htp, "/bar", test_bar_cb, "baz");
    cb_5   = evhtp_set_cb(htp, "/500", test_500_cb, "500");
#ifndef EVHTP_DISABLE_REGEX
    cb_6   = evhtp_set_regex_cb(htp, "^(/anything/).*", test_regex, NULL);
#endif
    cb_7   = evhtp_set_cb(htp, "/pause", test_pause_cb, NULL);
#ifndef EVHTP_DISABLE_REGEX
    cb_8   = evhtp_set_regex_cb(htp, "^/create/(.*)", create_callback, NULL);
#endif
    cb_9   = evhtp_set_glob_cb(htp, "*/glob/*", test_glob_cb, NULL);
    cb_10  = evhtp_set_cb(htp, "/max_body_size", test_max_body, NULL);

    /* set a callback to test out chunking API */
    cb_11  = evhtp_set_cb(htp, "/chunkme", test_chunking, NULL);

    /* set a callback which takes ownership of the underlying bufferevent and
     * just starts echoing things
     */
    cb_12  = evhtp_set_cb(htp, "/ownme", test_ownership, NULL);

    /* set a callback to pause on each header for cb_7 */
    evhtp_set_hook(&cb_7->hooks, evhtp_hook_on_path, pause_init_cb, NULL);

    /* set a callback to set hooks specifically for the cb_6 callback */
#ifndef EVHTP_DISABLE_REGEX
    evhtp_set_hook(&cb_6->hooks, evhtp_hook_on_headers, test_regex_hdrs_cb, NULL);
#endif

    evhtp_set_hook(&cb_10->hooks, evhtp_hook_on_headers, set_max_body, NULL);

    /* set a default request handler */
    evhtp_set_gencb(htp, test_default_cb, "foobarbaz");

    /* set a callback invoked before a connection is accepted */
    //evhtp_set_pre_accept_cb(htp, test_pre_accept, &bind_port);

    /* set a callback to set per-connection hooks (via a post_accept cb) */
    evhtp_set_post_accept_cb(htp, set_my_connection_handlers, NULL);

#ifndef EVHTP_DISABLE_SSL
    if (ssl_pem != NULL) {
        evhtp_ssl_cfg_t scfg = {
            .pemfile            = ssl_pem,
            .privfile           = ssl_pem,
            .cafile             = ssl_ca,
            .capath             = ssl_capath,
            .ciphers            = "RC4+RSA:HIGH:+MEDIUM:+LOW",
            .ssl_opts           = SSL_OP_NO_SSLv2,
            .ssl_ctx_timeout    = 60 * 60 * 48,
            .verify_peer        = SSL_VERIFY_PEER,
            .verify_depth       = 42,
            .x509_verify_cb     = dummy_ssl_verify_callback,
            .x509_chk_issued_cb = dummy_check_issued_cb,
            .scache_type        = evhtp_ssl_scache_type_internal,
            .scache_size        = 1024,
            .scache_timeout     = 1024,
            .scache_init        = NULL,
            .scache_add         = NULL,
            .scache_get         = NULL,
            .scache_del         = NULL,
        };

        evhtp_ssl_init(htp, &scfg);
#ifndef EVHTP_DISABLE_EVTHR
        if (use_threads) {
            #define OPENSSL_THREAD_DEFINES
#include <openssl/opensslconf.h>
#if defined(OPENSSL_THREADS)
#else
            fprintf(stderr, "Your version of OpenSSL does not support threading!\n");
            exit(-1);
#endif
        }
#endif
    }
#endif

#ifndef EVHTP_DISABLE_EVTHR
    if (use_threads) {
        evhtp_use_threads(htp, NULL, num_threads, NULL);
    }
#endif

    if (evhtp_bind_socket(htp, bind_addr, bind_port, backlog) < 0) {
        fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
        exit(-1);
    }

    ev_sigint = evsignal_new(evbase, SIGINT, sigint, evbase);
    evsignal_add(ev_sigint, NULL);

    event_base_loop(evbase, 0);

    event_free(ev_sigint);
    evhtp_unbind_socket(htp);

    evhtp_free(htp);
    event_base_free(evbase);

    return 0;
} /* main */
Exemplo n.º 7
0
Arquivo: test.c Projeto: pibi/libevhtp
int
main(int argc, char ** argv) {
    evbase_t         * evbase = NULL;
    evhtp_t          * htp    = NULL;
    evhtp_callback_t * cb_1   = NULL;
    evhtp_callback_t * cb_2   = NULL;
    evhtp_callback_t * cb_3   = NULL;
    evhtp_callback_t * cb_4   = NULL;
    evhtp_callback_t * cb_5   = NULL;
    evhtp_callback_t * cb_6   = NULL;
    evhtp_callback_t * cb_7   = NULL;
    evhtp_callback_t * cb_8   = NULL;

    if (parse_args(argc, argv) < 0) {
        exit(1);
    }

    srand((unsigned)time(NULL));

    evbase = event_base_new();
    htp    = evhtp_new(evbase, NULL);

    cb_1   = evhtp_set_cb(htp, "/ref", test_default_cb, "fjdkls");
    cb_2   = evhtp_set_cb(htp, "/foo", test_foo_cb, "bar");
    cb_3   = evhtp_set_cb(htp, "/foo/", test_foo_cb, "bar");
    cb_4   = evhtp_set_cb(htp, "/bar", test_bar_cb, "baz");
    cb_5   = evhtp_set_cb(htp, "/500", test_500_cb, "500");
    cb_6   = evhtp_set_regex_cb(htp, "^(/anything/).*", test_regex, NULL);
    cb_7   = evhtp_set_cb(htp, "/pause", test_pause_cb, NULL);
    cb_8   = evhtp_set_regex_cb(htp, "^/create/(.*)", create_callback, NULL);

    /* set a callback to pause on each header for cb_7 */
    evhtp_set_hook(&cb_7->hooks, evhtp_hook_on_path, pause_init_cb, NULL);

    /* set a callback to set hooks specifically for the cb_6 callback */
    evhtp_set_hook(&cb_6->hooks, evhtp_hook_on_headers, test_regex_hdrs_cb, NULL);

    /* set a default request handler */
    evhtp_set_gencb(htp, test_default_cb, "foobarbaz");

    /* set a callback invoked before a connection is accepted */
    evhtp_set_pre_accept_cb(htp, test_pre_accept, &bind_port);

    /* set a callback to set per-connection hooks (via a post_accept cb) */
    evhtp_set_post_accept_cb(htp, set_my_connection_handlers, NULL);

#ifndef DISABLE_SSL
    if (ssl_pem != NULL) {
        evhtp_ssl_cfg_t scfg = {
            .pemfile            = ssl_pem,
            .privfile           = ssl_pem,
            .cafile             = ssl_ca,
            .capath             = ssl_capath,
            .ciphers            = "RC4+RSA:HIGH:+MEDIUM:+LOW",
            .ssl_opts           = SSL_OP_NO_SSLv2,
            .verify_peer        = SSL_VERIFY_PEER,
            .verify_depth       = 42,
            .x509_verify_cb     = dummy_ssl_verify_callback,
            .x509_chk_issued_cb = dummy_check_issued_cb,
            .scache_type        = evhtp_ssl_scache_type_internal,
            .scache_size        = 1024,
            .scache_timeout     = 1024,
            .scache_init        = NULL,
            .scache_add         = NULL,
            .scache_get         = NULL,
            .scache_del         = NULL,
        };

        evhtp_ssl_init(htp, &scfg);

        if (use_threads) {
            #define OPENSSL_THREAD_DEFINES
#include <openssl/opensslconf.h>
#if defined(OPENSSL_THREADS)
#else
            fprintf(stderr, "Your version of OpenSSL does not support threading!\n");
            exit(-1);
#endif
        }
    }
#endif

#ifndef DISABLE_EVTHR
    if (use_threads) {
        evhtp_use_threads(htp, NULL, num_threads, NULL);
    }
#endif

    if (evhtp_bind_socket(htp, bind_addr, bind_port, 128) < 0) {
        fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
        exit(-1);
    }

    signal(SIGINT, sigint);

    event_base_loop(evbase, 0);
    return 0;
} /* main */
Exemplo n.º 8
0
static evhtp_res
upload_headers_cb (evhtp_request_t *req, evhtp_headers_t *hdr, void *arg)
{
    SearpcClient *rpc_client = NULL;
    char *token, *repo_id = NULL, *user = NULL;
    char *boundary = NULL;
    gint64 content_len;
    char *progress_id = NULL;
    char *err_msg = NULL;
    RecvFSM *fsm = NULL;
    Progress *progress = NULL;

    /* URL format: http://host:port/[upload|update]/<token>?X-Progress-ID=<uuid> */
    token = req->uri->path->file;
    if (!token) {
        seaf_warning ("[upload] No token in url.\n");
        err_msg = "Invalid URL";
        goto err;
    }

    rpc_client = ccnet_create_pooled_rpc_client (seaf->client_pool,
                                                 NULL,
                                                 "seafserv-rpcserver");

    if (check_access_token (rpc_client, token, &repo_id, &user) < 0) {
        seaf_warning ("[upload] Invalid token.\n");
        err_msg = "Access denied";
        goto err;
    }

    boundary = get_boundary (hdr);
    if (!boundary) {
        goto err;
    }

    if (get_progress_info (req, hdr, &content_len, &progress_id) < 0)
        goto err;

    progress = g_new0 (Progress, 1);
    progress->size = content_len;

    fsm = g_new0 (RecvFSM, 1);
    fsm->boundary = boundary;
    fsm->repo_id = repo_id;
    fsm->user = user;
    fsm->line = evbuffer_new ();
    fsm->form_kvs = g_hash_table_new_full (g_str_hash, g_str_equal,
                                           g_free, g_free);
    fsm->progress_id = progress_id;
    fsm->progress = progress;

    pthread_mutex_lock (&pg_lock);
    g_hash_table_insert (upload_progress, g_strdup(progress_id), progress);
    pthread_mutex_unlock (&pg_lock);

    /* Set up per-request hooks, so that we can read file data piece by piece. */
    evhtp_set_hook (&req->hooks, evhtp_hook_on_read, upload_read_cb, fsm);
    evhtp_set_hook (&req->hooks, evhtp_hook_on_request_fini, upload_finish_cb, fsm);
    /* Set arg for upload_cb or update_cb. */
    req->cbarg = fsm;

    ccnet_rpc_client_free (rpc_client);

    return EVHTP_RES_OK;

err:
    /* Don't receive any data before the connection is closed. */
    evhtp_request_pause (req);

    /* Set keepalive to 0. This will cause evhtp to close the
     * connection after sending the reply.
     */
    req->keepalive = 0;
    if (err_msg)
        evbuffer_add_printf (req->buffer_out, "%s\n", err_msg);
    evhtp_send_reply (req, EVHTP_RES_BADREQ);

    if (rpc_client)
        ccnet_rpc_client_free (rpc_client);

    g_free (repo_id);
    g_free (user);
    g_free (boundary);
    return EVHTP_RES_OK;
}
Exemplo n.º 9
0
int main(int argc, char **argv) {

  init_config(argc, argv);

  open_authorizations("r");

  init_webfinger();

  /** OPEN MAGIC DATABASE **/

  magic_cookie = magic_open(MAGIC_MIME);
  if(magic_load(magic_cookie, RS_MAGIC_DATABASE) != 0) {
    log_error("Failed to load magic database: %s", magic_error(magic_cookie));
    exit(EXIT_FAILURE);
  }

  log_info("starting process: main");

  if(prctl(PR_SET_NAME, "rs-serve [main]", 0, 0, 0) != 0) {
    log_error("Failed to set process name: %s", strerror(errno));
  }

  /** SETUP EVENT BASE **/

  rs_event_base = event_base_new();
  ASSERT_NOT_NULL(rs_event_base, "event_base_new()");
  log_debug("libevent method: %s", event_base_get_method(rs_event_base));
  event_set_log_callback(log_event_base_message);

  // TODO: add error cb to base

  /** SETUP AUTH TOKENS HASH TABLE **/

  auth_sessions = sm_new(1024); // FIXME: this a hardcoded value.

  /** SETUP MAIN LISTENER **/

  struct sockaddr_in sin;
  memset(&sin, 0, sizeof(struct sockaddr_in));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = htonl(0);
  sin.sin_port = htons(RS_PORT);

  evhtp_t *server = evhtp_new(rs_event_base, NULL);

  if(RS_USE_SSL) {
    evhtp_ssl_cfg_t ssl_config = {
      .pemfile = RS_SSL_CERT_PATH,
      .privfile = RS_SSL_KEY_PATH,
      .cafile = RS_SSL_CA_PATH,
      // what's this???
      .capath = NULL,
      .ciphers = "RC4+RSA:HIGH:+MEDIUM:+LOW",
      .ssl_opts = SSL_OP_NO_SSLv2,
      .ssl_ctx_timeout = 60*60*48,
      .verify_peer = SSL_VERIFY_PEER,
      .verify_depth = 42,
      .x509_verify_cb = dummy_ssl_verify_callback,
      .x509_chk_issued_cb = dummy_check_issued_cb,
      .scache_type = evhtp_ssl_scache_type_internal,
      .scache_size = 1024,
      .scache_timeout = 1024,
      .scache_init = NULL,
      .scache_add = NULL,
      .scache_get = NULL,
      .scache_del = NULL
    };

    if(evhtp_ssl_init(server, &ssl_config) != 0) {
      log_error("evhtp_ssl_init() failed");
      exit(EXIT_FAILURE);
    }
  }

  /* WEBFINGER */

  evhtp_callback_cb webfinger_cb = (RS_WEBFINGER_ENABLED ?
                                    handle_webfinger : reject_webfinger);
  evhtp_set_cb(server, "/.well-known/webfinger", webfinger_cb, NULL);
  // support legacy webfinger clients (we don't support XRD though):
  evhtp_set_cb(server, "/.well-known/host-meta", webfinger_cb, NULL);
  evhtp_set_cb(server, "/.well-known/host-meta.json", webfinger_cb, NULL);

  /* REMOTESTORAGE */

  evhtp_callback_t *storage_cb = evhtp_set_regex_cb(server, "^/storage/([^/]+)/.*$", handle_storage, NULL);

  evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_request_fini, finish_request, NULL);

  if(evhtp_bind_sockaddr(server, (struct sockaddr*)&sin, sizeof(sin), 1024) != 0) {
    log_error("evhtp_bind_sockaddr() failed: %s", strerror(errno));
    exit(EXIT_FAILURE);
  }

  /** SETUP AUTH LISTENER **/

  memset(&sin, 0, sizeof(struct sockaddr_in));
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = htonl(0);
  sin.sin_port = htons(RS_AUTH_PORT);

  evhtp_t *server_auth = evhtp_new(rs_event_base, NULL);

  if(RS_USE_SSL) {
    evhtp_ssl_cfg_t ssl_config = {
      .pemfile = RS_SSL_CERT_PATH,
      .privfile = RS_SSL_KEY_PATH,
      .cafile = RS_SSL_CA_PATH,
      // what's this???
      .capath = NULL,
      .ciphers = "RC4+RSA:HIGH:+MEDIUM:+LOW",
      .ssl_opts = SSL_OP_NO_SSLv2,
      .ssl_ctx_timeout = 60*60*48,
      .verify_peer = SSL_VERIFY_PEER,
      .verify_depth = 42,
      .x509_verify_cb = dummy_ssl_verify_callback,
      .x509_chk_issued_cb = dummy_check_issued_cb,
      .scache_type = evhtp_ssl_scache_type_internal,
      .scache_size = 1024,
      .scache_timeout = 1024,
      .scache_init = NULL,
      .scache_add = NULL,
      .scache_get = NULL,
      .scache_del = NULL
    };

    if(evhtp_ssl_init(server_auth, &ssl_config) != 0) {
      log_error("evhtp_ssl_init() failed");
      exit(EXIT_FAILURE);
    }
  }

  /* AUTH */

  evhtp_set_cb(server_auth, "/authenticate", handle_authenticate, NULL);
  evhtp_set_cb(server_auth, "/authorizations", handle_authorizations, NULL);

  evhtp_set_hook(&storage_cb->hooks, evhtp_hook_on_request_fini, finish_request, NULL);

  if(evhtp_bind_sockaddr(server_auth, (struct sockaddr*)&sin, sizeof(sin), 1024) != 0) {
    log_error("evhtp_bind_sockaddr() failed: %s", strerror(errno));
    exit(EXIT_FAILURE);
  }

  /** SETUP SIGNALS **/

  sigset_t sigmask;
  sigemptyset(&sigmask);
  sigaddset(&sigmask, SIGINT);
  sigaddset(&sigmask, SIGTERM);
  sigaddset(&sigmask, SIGCHLD);
  ASSERT_ZERO(sigprocmask(SIG_BLOCK, &sigmask, NULL), "sigprocmask()");
  int sfd = signalfd(-1, &sigmask, SFD_NONBLOCK);
  ASSERT_NOT_EQ(sfd, -1, "signalfd()");

  struct event *signal_event = event_new(rs_event_base, sfd, EV_READ | EV_PERSIST,
                                         handle_signal, NULL);
  event_add(signal_event, NULL);

  /** RUN EVENT LOOP **/

  if(RS_DETACH) {
    int pid = fork();
    if(pid == 0) {
      event_reinit(rs_event_base);

      if(RS_LOG_FILE == stdout) {
        log_warn("No --log-file option given. Future output will be lost.");
        freopen("/dev/null", "r", stdout);
        freopen("/dev/null", "r", stderr);
      }

      return event_base_dispatch(rs_event_base);
    } else {
      printf("rs-serve detached with pid %d\n", pid);
      if(RS_PID_FILE) {
        fprintf(RS_PID_FILE, "%d", pid);
        fflush(RS_PID_FILE);
      }
      _exit(EXIT_SUCCESS);
    }
  } else {
    if(RS_PID_FILE) {
      fprintf(RS_PID_FILE, "%d", getpid());
      fflush(RS_PID_FILE);
    }
    return event_base_dispatch(rs_event_base);
  }
}