/* * Copyright (c) 2014, Vsevolod Stakhov * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef RDNS_EVENT_H_ #define RDNS_EVENT_H_ #include #include #include #include "rdns.h" #ifdef __cplusplus extern "C" { #endif static void* rdns_libevent_add_read (void *priv_data, int fd, void *user_data); static void rdns_libevent_del_read(void *priv_data, void *ev_data); static void* rdns_libevent_add_write (void *priv_data, int fd, void *user_data); static void rdns_libevent_del_write (void *priv_data, void *ev_data); static void* rdns_libevent_add_timer (void *priv_data, double after, void *user_data); static void* rdns_libevent_add_periodic (void *priv_data, double after, rdns_periodic_callback cb, void *user_data); static void rdns_libevent_del_periodic (void *priv_data, void *ev_data); static void rdns_libevent_repeat_timer (void *priv_data, void *ev_data); static void rdns_libevent_del_timer (void *priv_data, void *ev_data); struct rdns_event_periodic_cbdata { struct event *ev; rdns_periodic_callback cb; void *cbdata; }; static void rdns_bind_libevent (struct rdns_resolver *resolver, struct event_base *ev_base) { struct rdns_async_context ev_ctx = { .add_read = rdns_libevent_add_read, .del_read = rdns_libevent_del_read, .add_write = rdns_libevent_add_write, .del_write = rdns_libevent_del_write, .add_timer = rdns_libevent_add_timer, .add_periodic = rdns_libevent_add_periodic, .del_periodic = rdns_libevent_del_periodic, .repeat_timer = rdns_libevent_repeat_timer, .del_timer = rdns_libevent_del_timer, .cleanup = NULL }, *nctx; /* XXX: never got freed */ nctx = malloc (sizeof (struct rdns_async_context)); if (nctx != NULL) { memcpy (nctx, &ev_ctx, sizeof (struct rdns_async_context)); nctx->data = ev_base; } rdns_resolver_async_bind (resolver, nctx); } static void rdns_libevent_read_event (int fd, short what, void *ud) { rdns_process_read (fd, ud); } static void rdns_libevent_write_event (int fd, short what, void *ud) { rdns_process_retransmit (fd, ud); } static void rdns_libevent_timer_event (int fd, short what, void *ud) { rdns_process_timer (ud); } static void rdns_libevent_periodic_event (int fd, short what, void *ud) { struct rdns_event_periodic_cbdata *cbdata = ud; cbdata->cb (cbdata->cbdata); } static void* rdns_libevent_add_read (void *priv_data, int fd, void *user_data) { struct event *ev; ev = malloc (sizeof (struct event)); if (ev != NULL) { event_set (ev, fd, EV_READ | EV_PERSIST, rdns_libevent_read_event, user_data); event_base_set (priv_data, ev); event_add (ev, NULL); } return ev; } static void rdns_libevent_del_read(void *priv_data, void *ev_data) { struct event *ev = ev_data; if (ev != NULL) { event_del (ev); free (ev); } } static void* rdns_libevent_add_write (void *priv_data, int fd, void *user_data) { struct event *ev; ev = malloc (sizeof (struct event)); if (ev != NULL) { event_set (ev, fd, EV_WRITE | EV_PERSIST, rdns_libevent_write_event, user_data); event_base_set (priv_data, ev); event_add (ev, NULL); } return ev; } static void rdns_libevent_del_write (void *priv_data, void *ev_data) { struct event *ev = ev_data; if (ev != NULL) { event_del (ev); free (ev); } } #define rdns_event_double_to_tv(dbl, tv) do { \ (tv)->tv_sec = (int)(dbl); \ (tv)->tv_usec = ((dbl) - (int)(dbl))*1000*1000; \ } while(0) static void* rdns_libevent_add_timer (void *priv_data, double after, void *user_data) { struct event *ev; struct timeval tv; ev = malloc (sizeof (struct event)); if (ev != NULL) { rdns_event_double_to_tv (after, &tv); event_set (ev, -1, EV_TIMEOUT|EV_PERSIST, rdns_libevent_timer_event, user_data); event_base_set (priv_data, ev); event_add (ev, &tv); } return ev; } static void* rdns_libevent_add_periodic (void *priv_data, double after, rdns_periodic_callback cb, void *user_data) { struct event *ev; struct timeval tv; struct rdns_event_periodic_cbdata *cbdata = NULL; ev = malloc (sizeof (struct event)); if (ev != NULL) { cbdata = malloc (sizeof (struct rdns_event_periodic_cbdata)); if (cbdata != NULL) { rdns_event_double_to_tv (after, &tv); cbdata->cb = cb; cbdata->cbdata = user_data; cbdata->ev = ev; event_set (ev, -1, EV_TIMEOUT|EV_PERSIST, rdns_libevent_periodic_event, cbdata); event_base_set (priv_data, ev); event_add (ev, &tv); } else { free (ev); return NULL; } } return cbdata; } static void rdns_libevent_del_periodic (void *priv_data, void *ev_data) { struct rdns_event_periodic_cbdata *cbdata = ev_data; if (cbdata != NULL) { event_del (cbdata->ev); free (cbdata->ev); free (cbdata); } } static void rdns_libevent_repeat_timer (void *priv_data, void *ev_data) { /* XXX: libevent hides timeval, so timeouts are persistent here */ } #undef rdns_event_double_to_tv static void rdns_libevent_del_timer (void *priv_data, void *ev_data) { struct event *ev = ev_data; if (ev != NULL) { event_del (ev); free (ev); } } #ifdef __cplusplus } #endif #endif /* RDNS_EV_H_ */