AC_CHECK_LIB(dl, dlopen)
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(event, event_dispatch,, AC_MSG_ERROR(
-[libevent or libevent2 must be installed to build iauthd-c.]))
+ [libevent2 must be installed to build iauthd-c.]))
AC_CHECK_TYPE(evutil_socket_t,
AC_DEFINE(HAVE_EVUTIL_SOCKET_T, 1, [Define if <evutil.h> defines evutil_socket_t]),, [#include <evutil.h>])
*/
int holds;
- /** Timer event that fires when the IAuth request has been active
- * for too long.
- */
- struct event timeout;
-
/** Number of "soft holds" on the client. IAuth will send a "Soft
* Done" message when the number of holds less than one but this
* is positive.
*/
int soft_holds;
+ /** Timer event that fires when the IAuth request has been active
+ * for too long.
+ */
+ struct event *timeout;
+
/** Boolean flags of which events have occurred for the client.
* This includes indications of which fields are set.
* Indexed by enum iauth_flags.
/** Set of all registered IAuth modules. */
static struct set *iauth_modules;
-/** Event descriptor for input data. */
-static struct bufferevent *iauth_in;
+/** Input event object for IAuth. */
+static struct event *iauth_ev;
+
+/** Buffer object for input data. */
+static struct evbuffer *iauth_in;
/** Bitset containing all requested policies. */
static struct iauth_policyset iauth_policies;
static void iauth_req_cleanup(void *ptr)
{
struct iauth_request *req = ptr;
- event_del(&req->timeout);
+ event_free(req->timeout);
stats.n_req_data_frees += set_size(&req->data);
set_clear(&req->data, 0);
}
/* Do we have a timeout? */
timeout.tv_sec = iauth_conf_timeout->parsed.p_interval;
timeout.tv_usec = 0;
- evtimer_set(&req->timeout, iauth_timeout, req);
+ req->timeout = evtimer_new(ev_base, iauth_timeout, req);
if (timeout.tv_sec > 0)
- evtimer_add(&req->timeout, &timeout);
+ evtimer_add(req->timeout, &timeout);
/* Broadcast the message. */
for (node = set_first(iauth_modules); node; node = set_next(node)) {
log_message(iauth_log, LOG_WARNING, "Unrecognized info request: %s", argv[1]);
}
-static void iauth_read(struct bufferevent *buf, UNUSED_ARG(void *arg))
+static void iauth_read(evutil_socket_t fd, short events, void *iauth_in_v)
{
struct iauth_request *req;
char *argv[16];
char *line;
char *sep;
size_t argc, len;
- int id;
+ int id, res;
+
+ if (!(events & EV_READ))
+ return;
+
+ /* Read a chunk of data from the FD into our evbuffer. */
+ res = evbuffer_read(iauth_in_v, fd, 4096);
+ if (res < 0) {
+ if (errno != EWOULDBLOCK)
+ log_message(iauth_log, LOG_ERROR, "Unable to read input: %s", strerror(errno));
+ return;
+ }
+ if (res == 0) {
+ log_message(log_core, LOG_INFO, "Terminating due to EOF on input");
+ event_base_loopbreak(ev_base);
+ return;
+ }
/* Parse out the start of the line (simple, standard bits). */
- while ((line = evbuffer_readline(buf->input)) != NULL)
- {
- len = strlen(line);
- if (len > 0 && line[len-1] == '\r')
- {
- line[len-1] = '\0';
- }
+ while ((line = evbuffer_readln(iauth_in_v, &len, EVBUFFER_EOL_CRLF)) != NULL) {
log_message(iauth_log, LOG_DEBUG, "> %s", line);
id = strtol(line, &sep, 10);
* client disconnects.
log_message(iauth_log, LOG_DEBUG, " .. no client found for id %d", id);
*/
+ free(line);
return;
}
parse_info_request(argc, argv);
break;
}
- }
-}
-static void iauth_io_error(UNUSED_ARG(struct bufferevent *buf), short events, UNUSED_ARG(void *arg))
-{
- if (events & EVBUFFER_EOF) {
- log_message(log_core, LOG_INFO, "Terminating due to EOF on input");
- event_loopbreak();
+ /* We are responsible for freeing the line. */
+ free(line);
}
}
iauth_modules = set_alloc(set_compare_charp, NULL);
iauth_conf = conf_register_object(NULL, "iauth");
iauth_conf_timeout = conf_register_string(iauth_conf, CONF_STRING_INTERVAL, "timeout", "0");
- event_once(-1, EV_TIMEOUT, iauth_startup, NULL, &tv_zero);
- iauth_in = bufferevent_new(STDIN_FILENO, iauth_read, NULL, iauth_io_error, NULL);
- bufferevent_enable(iauth_in, EV_READ);
+
+ event_base_once(ev_base, -1, EV_TIMEOUT, iauth_startup, NULL, &tv_zero);
+ iauth_in = evbuffer_new();
+ if (!iauth_in) {
+ log_message(iauth_log, LOG_FATAL, "Unable to create IAuth evbuffer");
+ return;
+ }
+ iauth_ev = event_new(ev_base, STDIN_FILENO, EV_PERSIST | EV_READ, iauth_read, iauth_in);
+ if (!iauth_ev) {
+ log_message(iauth_log, LOG_FATAL, "Unable to create IAuth event");
+ return;
+ }
+ event_add(iauth_ev, NULL);
}
void module_destructor(void)
{
- bufferevent_free(iauth_in);
+ evbuffer_free(iauth_in);
+ event_free(iauth_ev);
set_clear(iauth_reqs, 0);
free(iauth_reqs);
set_clear(iauth_modules, 1);
#include "src/compat.h"
/* Include the libevent headers. */
-#include <evdns.h>
-#include <event.h>
+#include <event2/event.h>
+#include <event2/dns.h>
+#include <event2/buffer.h>
+extern struct event_base *ev_base;
+extern struct evdns_base *ev_dns;
/** Evaluates to the length of an array \a x. */
#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
} conf;
static const struct argument args[];
-static struct event sighup_evt;
-static struct event sigusr1_evt;
+static struct event *sighup_evt;
+static struct event *sigusr1_evt;
static const char *config_filename = SYSCONFDIR "/iauthd-c.conf";
static const char *iauthd_executable;
static int verbose_debug;
static int early_exit;
static int no_chdir;
static int restart;
+static int ev_arbitrary_fds;
+struct event_base *ev_base;
+struct evdns_base *ev_dns;
int clean_exit;
static int do_arg_help(UNUSED_ARG(const char *arg))
return 0;
}
+static int do_arg_arbitrary_fds(UNUSED_ARG(const char *arg))
+{
+ ev_arbitrary_fds = 1;
+ return 0;
+}
+
static const struct argument args[] = {
{ "help", '?', do_arg_help, 0, "Show usage information" },
{ "version", 'v', do_arg_version, 0, "Show software version" },
{ "config", 'f', do_arg_config, 1, "Use specific configuration file" },
{ "debug", 'd', do_arg_debug, 0, "Enable verbose debug output" },
{ "no-chdir", 'n', do_arg_no_chdir, 0, "Disable chdir(LOGDIR) at startup" },
+ { "arbitrary-fds", 'A', do_arg_arbitrary_fds, 0, "Request libevent support for arbitrary FD types"},
{ NULL, '\0', NULL, 0, NULL }
};
{
log_message(log_core, LOG_INFO, "break_loop() called due to signal");
clean_exit = 1;
- event_loopbreak();
+ event_base_loopbreak(ev_base);
}
static void reload_config(UNUSED_ARG(int fd), UNUSED_ARG(short event), UNUSED_ARG(void *arg))
conf_read(config_filename);
}
+static void main_cleanup(void)
+{
+ event_free(sigusr1_evt);
+ event_free(sighup_evt);
+ evdns_base_free(ev_dns, 0);
+ event_base_free(ev_base);
+}
+
int main(int argc, char *argv[])
{
+ struct event_config *ev_cfg;
+
iauthd_executable = argv[0];
atexit(call_exit_funcs);
parse_arguments(argc, argv);
conf.modules = conf_register_string_list(conf.root, "modules", NULL);
/* Initialize libevent. */
- if (!event_init()) {
+ ev_cfg = event_config_new();
+ if (!ev_cfg) {
+ fprintf(stderr, "Allocation of event_config structure failed.\n");
+ return EXIT_FAILURE;
+ }
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ ev_arbitrary_fds = 1;
+#endif
+ if (ev_arbitrary_fds && event_config_require_features(ev_cfg, EV_FEATURE_FDS)) {
+ fprintf(stderr, "libevent rejected EV_FEATURE_FDS.\n");
+ return EXIT_FAILURE;
+ }
+ ev_base = event_base_new_with_config(ev_cfg);
+ event_config_free(ev_cfg);
+ if (!ev_base) {
fprintf(stderr, "Unable to initialize event library.\n");
return EXIT_FAILURE;
}
/* Initialize libevent's DNS module. */
- if (evdns_init()) {
+ ev_dns = evdns_base_new(ev_base, 0);
+ if (!ev_dns) {
fprintf(stderr, "Unable to initialize DNS library.\n");
return EXIT_FAILURE;
}
- evdns_search_clear();
+ reg_exit_func(main_cleanup);
/* Capture libevent's error messages to our own log. */
event_set_log_callback(log_for_libevent);
log_set_verbosity(verbose_debug ? 2 : 0);
/* Handle signals. */
- signal_set(&sighup_evt, SIGHUP, break_loop, NULL);
- if (event_add(&sighup_evt, NULL))
- log_message(log_core, LOG_FATAL, "Unable to handle SIGHUP handler.");
- signal_set(&sigusr1_evt, SIGUSR1, reload_config, NULL);
- if (event_add(&sigusr1_evt, NULL))
- log_message(log_core, LOG_FATAL, "Unable to handle SIGUSR1 handler.");
+ sighup_evt = event_new(ev_base, SIGHUP, EV_SIGNAL | EV_PERSIST, break_loop, NULL);
+ if (!sighup_evt)
+ log_message(log_core, LOG_FATAL, "Unable to create SIGHUP handler.");
+ if (event_add(sighup_evt, NULL))
+ log_message(log_core, LOG_FATAL, "Unable to add SIGHUP handler.");
+ sigusr1_evt = event_new(ev_base, SIGUSR1, EV_SIGNAL | EV_PERSIST, reload_config, NULL);
+ if (!sigusr1_evt)
+ log_message(log_core, LOG_FATAL, "Unable to create SIGUSR1 handler.");
+ if (event_add(sigusr1_evt, NULL))
+ log_message(log_core, LOG_FATAL, "Unable to add SIGUSR1 handler.");
/* Run the event loop. */
- event_dispatch();
+ event_base_dispatch(ev_base);
if (restart)
{
static struct set sar_requests;
static struct set sar_nameservers;
-static struct event sar_fd;
-static struct event sar_timeout;
+static struct event *sar_fd;
+static struct event *sar_timeout;
static int sar_fd_fd;
#define TV_LESS(A, B) evutil_timercmp(&(A), &(B), <)
sar_abort(req);
}
-static void sar_timeout_cb(UNUSED_ARG(int fd), UNUSED_ARG(short event), void *timer)
+static void sar_timeout_cb(UNUSED_ARG(int fd), UNUSED_ARG(short event), UNUSED_ARG(void *datum))
{
struct set_node *it;
struct set_node *next;
sar_request_send(req);
}
if (next_timeout.tv_sec < INT_MAX)
- evtimer_add(timer, &next_timeout);
+ evtimer_add(sar_timeout, &next_timeout);
}
static void sar_check_timeout(struct timeval when)
{
- if (!evutil_timerisset(&sar_timeout.ev_timeout))
+ struct timeval previous;
+
+ if (!evtimer_pending(sar_timeout, &previous))
{
- evtimer_add(&sar_timeout, &when);
+ evtimer_add(sar_timeout, &when);
}
- else if (TV_LESS(when, sar_timeout.ev_timeout))
+ else if (TV_LESS(when, previous))
{
- evtimer_del(&sar_timeout);
- evtimer_add(&sar_timeout, &when);
+ evtimer_del(sar_timeout);
+ evtimer_add(sar_timeout, &when);
}
/* else existing timeout is sooner */
}
return raw + rr->rd_start;
}
-static void sar_fd_cb(int fd, short event, void *arg)
+static void sar_fd_cb(int fd, short event, UNUSED_ARG(void *arg))
{
struct sockaddr_storage ss;
struct dns_header hdr;
int id, res, rcode, buf_len;
assert(fd == sar_fd_fd);
- assert(arg == &sar_fd);
if (event != EV_READ)
return;
buf_len = conf.sar_edns0->parsed.p_integer;
id = hdr.id;
req = set_find(&sar_requests, &id);
- log_message(sar_log, LOG_DEBUG, "sar_fd_cb(%d, EV_READ, %p): hdr {id=%d, flags=0x%x, qdcount=%d, ancount=%d, nscount=%d, arcount=%d} -> req %p", fd, arg, hdr.id, hdr.flags, hdr.qdcount, hdr.ancount, hdr.nscount, hdr.arcount, req);
+ log_message(sar_log, LOG_DEBUG, "sar_fd_cb(%d, EV_READ): hdr {id=%d, flags=0x%x, qdcount=%d, ancount=%d, nscount=%d, arcount=%d} -> req %p", fd, hdr.id, hdr.flags, hdr.qdcount, hdr.ancount, hdr.nscount, hdr.arcount, req);
if (!req || !req->retries || !(hdr.flags & REQ_FLAG_QR)) {
ns->resp_ignored++;
return;
}
}
- event_set(&sar_fd, sar_fd_fd, EV_READ, sar_fd_cb, &sar_fd);
- if (event_add(&sar_fd, NULL)) {
+ sar_fd = event_new(ev_base, sar_fd_fd, EV_READ | EV_PERSIST, sar_fd_cb, NULL);
+ if (event_add(sar_fd, NULL)) {
log_message(sar_log, LOG_FATAL, "Unable to register resolver socket with event loop.");
return 1;
}
struct set_node *it;
/* make sure we have our local socket */
- if (!event_initialized(&sar_fd) && sar_open_fd()) {
+ if (!sar_fd && sar_open_fd()) {
sar_request_fail(req, RCODE_SOCKET_FAILURE);
return;
}
static void sar_cleanup(void)
{
- event_del(&sar_fd);
+ event_free(sar_timeout);
+ if (sar_fd)
+ event_free(sar_fd);
set_clear(&sar_nameservers, 0);
set_clear(&services_byname, 0);
set_clear(&services_byport, 0);
conf.sar_root = conf_register_object(NULL, "resolver");
services_byname.compare = set_compare_charp;
services_byport.compare = set_compare_int;
- evtimer_set(&sar_timeout, sar_timeout_cb, &sar_timeout);
+ sar_timeout = evtimer_new(ev_base, sar_timeout_cb, NULL);
sar_register_helper(&sar_ipv4_helper);
#if defined(AF_INET6)