From e6b4ae8904582984b09186d798f97bde83eb193b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pavel=20=C5=A0imerda?= Date: Mon, 10 Feb 2014 15:40:08 +0100 Subject: [PATCH] support multiple queries per channel --- lib/channel.c | 118 ++++++++++++++++++++++++--------------- lib/netresolve-private.h | 7 ++- 2 files changed, 76 insertions(+), 49 deletions(-) diff --git a/lib/channel.c b/lib/channel.c index 228950b..7bb35e7 100644 --- a/lib/channel.c +++ b/lib/channel.c @@ -59,12 +59,14 @@ netresolve_open(void) void netresolve_close(netresolve_t channel) { + int i; + if (!channel) return; - /* TODO: Loop through queries when they're decoupled from the channel. */ - if (channel->query) - netresolve_query_done(channel->query); + for (i = 0; i < channel->nqueries; i++) + netresolve_query_done(channel->queries[i]); + free(channel->queries); netresolve_set_backend_string(channel, ""); close(channel->epoll_fd); @@ -147,20 +149,28 @@ netresolve_query_start(netresolve_query_t query) static bool dispatch_fd(netresolve_t channel, int fd, int events) { - struct netresolve_backend *backend = *channel->query->backend; + int i; + + for (i = 0; i < channel->nqueries; i++) { + netresolve_query_t query = channel->queries[i]; + struct netresolve_backend *backend = *query->backend; - if (!backend && netresolve_connect_dispatch(channel->query, fd, events)) - return true; + if (query->state != NETRESOLVE_STATE_WAITING) + continue; - if (backend && backend->dispatch) { - backend->dispatch(channel->query, fd, events); - return true; + if (!backend && netresolve_connect_dispatch(query, fd, events)) + return true; + + if (backend && backend->dispatch) { + backend->dispatch(query, fd, events); + return true; + } } return false; } -void +bool netresolve_epoll(netresolve_t channel, int timeout) { static const int maxevents = 1; @@ -168,19 +178,15 @@ netresolve_epoll(netresolve_t channel, int timeout) int nevents; int i; - /* Sanity check number of descriptors. */ - if (channel->epoll_count <= 0) { - netresolve_query_set_state(channel->query, NETRESOLVE_STATE_FAILED); - return; - } + assert(channel->epoll_count > 0); nevents = epoll_wait(channel->epoll_fd, events, maxevents, channel->callbacks.watch_fd ? 0 : -1); - if (nevents == -1) { - netresolve_query_set_state(channel->query, NETRESOLVE_STATE_FAILED); - return; - } - for (i = 0; channel->query->state == NETRESOLVE_STATE_WAITING && i < nevents; i++) + if (nevents == -1) + return false; + for (i = 0; i < nevents; i++) dispatch_fd(channel, events[i].data.fd, events[i].events); + + return true; } void @@ -190,9 +196,6 @@ netresolve_watch_fd(netresolve_t channel, int fd, int events) debug("watching file descriptor: %d %d\n", fd, events); - if (!channel->query->backend || channel->epoll_fd == -1) - abort(); - if (epoll_ctl(channel->epoll_fd, EPOLL_CTL_DEL, fd, &event) != -1) channel->epoll_count--; else if (errno != ENOENT && errno != EBADF) @@ -251,40 +254,55 @@ state_to_errno(enum netresolve_state state) } netresolve_query_t -netresolve_query(netresolve_t channel, const char *node, const char *service) +netresolve_query_new(netresolve_t channel, const char *nodename, const char *servname) { + netresolve_query_t query; + netresolve_query_t *queries; + if (!channel->backends) netresolve_set_backend_string(channel, secure_getenv("NETRESOLVE_BACKENDS")); if (!channel->backends) { errno = ENODATA; return NULL; } - - /* TODO: A list of queries will be used. */ - if (channel->query) - return NULL; - channel->query = calloc(1, sizeof *channel->query); - if (!channel->query) + if (!(query = calloc(1, sizeof *query))) return NULL; - channel->query->channel = channel; - channel->query->first_connect_timeout = -1; - - netresolve_query_set_state(channel->query, NETRESOLVE_STATE_INIT); - channel->query->backend = channel->backends; + if (!(queries = realloc(channel->queries, ++channel->nqueries * sizeof *queries))) + goto fail_queries; + + channel->queries = queries; + channel->queries[channel->nqueries - 1] = query; + + query->channel = channel; + query->first_connect_timeout = -1; + query->backend = channel->backends; + memcpy(&query->request, &channel->request, sizeof channel->request); + query->request.nodename = nodename; + query->request.servname = servname; + + netresolve_query_set_state(query, NETRESOLVE_STATE_WAITING); + + return query; +fail_queries: + free(query); + return NULL; +} - memcpy(&channel->query->request, &channel->request, sizeof channel->request); - channel->query->request.nodename = node; - channel->query->request.servname = service; +netresolve_query_t +netresolve_query(netresolve_t channel, const char *nodename, const char *servname) +{ + netresolve_query_t query = netresolve_query_new(channel, nodename, servname); - netresolve_query_set_state(channel->query, NETRESOLVE_STATE_WAITING); + if (!query) + return NULL; /* Blocking mode. */ if (!channel->callbacks.watch_fd) - while (channel->query->state == NETRESOLVE_STATE_WAITING) + while (query->state == NETRESOLVE_STATE_WAITING) netresolve_epoll(channel, -1); - errno = state_to_errno(channel->query->state); - return channel->query; + errno = state_to_errno(query->state); + return query; } bool @@ -299,8 +317,7 @@ netresolve_dispatch_fd(netresolve_t channel, int fd, int events) return false; } - netresolve_epoll(channel, 0); - return true; + return netresolve_epoll(channel, 0); } /* netresolve_query_done: @@ -313,9 +330,18 @@ netresolve_dispatch_fd(netresolve_t channel, int fd, int events) void netresolve_query_done(netresolve_query_t query) { + netresolve_t channel = query->channel; + int i; + netresolve_query_set_state(query, NETRESOLVE_STATE_INIT); - /* TODO: Will be removed propery from a query list. */ - query->channel->query = NULL; + for (i = 0; i < channel->nqueries; i++) + if (channel->queries[i] == query) + break; + assert(i < channel->nqueries); + + memmove(&channel->queries[i], &channel->queries[i+1], --channel->nqueries - i); + channel->queries = realloc(channel->queries, channel->nqueries * sizeof *channel->queries); + free(query); } diff --git a/lib/netresolve-private.h b/lib/netresolve-private.h index d605f9e..81b8bee 100644 --- a/lib/netresolve-private.h +++ b/lib/netresolve-private.h @@ -107,8 +107,9 @@ struct netresolve_channel { bool default_loopback; bool dns_srv_lookup; } request; - /* TODO: A list of queries will be used. */ - struct netresolve_query *query; + /* A list of queries */ + netresolve_query_t *queries; + size_t nqueries; }; struct netresolve_query { @@ -134,7 +135,7 @@ struct netresolve_query { void netresolve_query_set_state(netresolve_query_t query, enum netresolve_state state); void netresolve_query_start(netresolve_query_t channel); -void netresolve_epoll(netresolve_t channel, int timeout); +bool netresolve_epoll(netresolve_t channel, int timeout); void netresolve_watch_fd(netresolve_t channel, int fd, int events); int netresolve_add_timeout(netresolve_t channel, time_t sec, long nsec); void netresolve_remove_timeout(netresolve_t channel, int fd); -- 2.43.7