dovecot-2.2: lib-dns: Added alternative API for doing longer con...
dovecot at dovecot.org
dovecot at dovecot.org
Tue Oct 22 15:35:17 EEST 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/a6abdf4b6222
changeset: 16860:a6abdf4b6222
user: Timo Sirainen <tss at iki.fi>
date: Tue Oct 22 15:34:55 2013 +0300
description:
lib-dns: Added alternative API for doing longer connections to dns-client process.
diffstat:
src/lib-dns/dns-lookup.c | 303 ++++++++++++++++++++++++++++++++--------------
src/lib-dns/dns-lookup.h | 26 ++++
2 files changed, 237 insertions(+), 92 deletions(-)
diffs (truncated from 432 to 300 lines):
diff -r cce994007aad -r a6abdf4b6222 src/lib-dns/dns-lookup.c
--- a/src/lib-dns/dns-lookup.c Mon Oct 21 21:38:17 2013 +0300
+++ b/src/lib-dns/dns-lookup.c Tue Oct 22 15:34:55 2013 +0300
@@ -3,6 +3,7 @@
#include "lib.h"
#include "ioloop.h"
#include "net.h"
+#include "llist.h"
#include "istream.h"
#include "write-full.h"
#include "time-util.h"
@@ -14,12 +15,10 @@
#define MAX_INBUF_SIZE 512
struct dns_lookup {
- int fd;
- char *path;
+ struct dns_lookup *prev, *next;
+ struct dns_client *client;
bool ptr_lookup;
- struct istream *input;
- struct io *io;
struct timeout *to;
struct timeval start_time;
@@ -34,20 +33,51 @@
void *context;
};
+struct dns_client {
+ int fd;
+ char *path;
+
+ unsigned int timeout_msecs, idle_timeout_msecs;
+
+ struct istream *input;
+ struct io *io;
+ struct timeout *to_idle;
+
+ struct dns_lookup *head, *tail;
+ bool deinit_client_at_free;
+};
+
+#undef dns_lookup
+#undef dns_lookup_ptr
+#undef dns_client_lookup
+#undef dns_client_lookup_ptr
+
static void dns_lookup_free(struct dns_lookup **_lookup);
-static void dns_lookup_close(struct dns_lookup *lookup)
+static void dns_client_disconnect(struct dns_client *client, const char *error)
{
- if (lookup->to != NULL)
- timeout_remove(&lookup->to);
- if (lookup->io != NULL)
- io_remove(&lookup->io);
- if (lookup->input != NULL)
- i_stream_destroy(&lookup->input);
- if (lookup->fd != -1) {
- if (close(lookup->fd) < 0)
- i_error("close(%s) failed: %m", lookup->path);
- lookup->fd = -1;
+ struct dns_lookup *lookup;
+ struct dns_lookup_result result;
+
+ memset(&result, 0, sizeof(result));
+ result.ret = EAI_FAIL;
+ result.error = error;
+
+ while (client->head != NULL) {
+ lookup = client->head;
+ lookup->callback(&result, lookup->context);
+ dns_lookup_free(&lookup);
+ }
+ if (client->to_idle != NULL)
+ timeout_remove(&client->to_idle);
+ if (client->io != NULL)
+ io_remove(&client->io);
+ if (client->input != NULL)
+ i_stream_destroy(&client->input);
+ if (client->fd != -1) {
+ if (close(client->fd) < 0)
+ i_error("close(%s) failed: %m", client->path);
+ client->fd = -1;
}
}
@@ -107,129 +137,117 @@
lookup->result.msecs = diff;
}
-static void dns_lookup_input(struct dns_lookup *lookup)
+static void dns_client_input(struct dns_client *client)
{
const char *line;
- struct dns_lookup_result *result = &lookup->result;
+ struct dns_lookup *lookup = client->head;
+ bool retry = FALSE;
int ret = 0;
- while ((line = i_stream_read_next_line(lookup->input)) != NULL) {
+ while ((line = i_stream_read_next_line(client->input)) != NULL) {
+ if (lookup == NULL) {
+ dns_client_disconnect(client, t_strdup_printf(
+ "Unexpected input from %s", client->path));
+ return;
+ }
ret = dns_lookup_input_line(lookup, line);
if (ret > 0)
break;
if (ret < 0) {
- result->error = t_strdup_printf(
- "Invalid input from %s", lookup->path);
- break;
+ dns_client_disconnect(client, t_strdup_printf(
+ "Invalid input from %s", client->path));
+ return;
}
}
+ if (ret == 0)
+ return;
- if (result->error != NULL) {
+ if (lookup->result.error != NULL) {
/* already got the error */
- } else if (lookup->input->stream_errno != 0) {
- result->error = t_strdup_printf("read(%s) failed: %m",
- lookup->path);
- ret = -1;
- } else if (lookup->input->eof) {
- result->error = t_strdup_printf("Unexpected EOF from %s",
- lookup->path);
- ret = -1;
+ } else if (client->input->stream_errno != 0) {
+ dns_client_disconnect(client, t_strdup_printf(
+ "read(%s) failed: %s", client->path,
+ i_stream_get_error(client->input)));
+ return;
+ } else if (client->input->eof) {
+ dns_client_disconnect(client, t_strdup_printf(
+ "Unexpected EOF from %s", client->path));
+ return;
}
- if (ret != 0) {
+ if (ret > 0) {
dns_lookup_save_msecs(lookup);
- dns_lookup_close(lookup);
- lookup->callback(result, lookup->context);
+ lookup->callback(&lookup->result, lookup->context);
+ retry = !lookup->client->deinit_client_at_free;
dns_lookup_free(&lookup);
}
+ if (retry)
+ dns_client_input(client);
}
static void dns_lookup_timeout(struct dns_lookup *lookup)
{
lookup->result.error = "DNS lookup timed out";
- dns_lookup_close(lookup);
lookup->callback(&lookup->result, lookup->context);
dns_lookup_free(&lookup);
}
-static int
-dns_lookup_common(const char *cmd, bool ptr_lookup,
- const struct dns_lookup_settings *set,
- dns_lookup_callback_t *callback, void *context,
- struct dns_lookup **lookup_r)
-{
- struct dns_lookup *lookup;
- struct dns_lookup_result result;
- int fd;
-
- memset(&result, 0, sizeof(result));
- result.ret = EAI_FAIL;
-
- fd = net_connect_unix(set->dns_client_socket_path);
- if (fd == -1) {
- result.error = t_strdup_printf("connect(%s) failed: %m",
- set->dns_client_socket_path);
- callback(&result, context);
- return -1;
- }
-
- if (write_full(fd, cmd, strlen(cmd)) < 0) {
- result.error = t_strdup_printf("write(%s) failed: %m",
- set->dns_client_socket_path);
- i_close_fd(&fd);
- callback(&result, context);
- return -1;
- }
-
- lookup = i_new(struct dns_lookup, 1);
- lookup->ptr_lookup = ptr_lookup;
- lookup->fd = fd;
- lookup->path = i_strdup(set->dns_client_socket_path);
- lookup->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
- lookup->io = io_add(fd, IO_READ, dns_lookup_input, lookup);
- if (set->timeout_msecs != 0) {
- lookup->to = timeout_add(set->timeout_msecs,
- dns_lookup_timeout, lookup);
- }
- lookup->result.ret = EAI_FAIL;
- lookup->callback = callback;
- lookup->context = context;
- if (gettimeofday(&lookup->start_time, NULL) < 0)
- i_fatal("gettimeofday() failed: %m");
-
- *lookup_r = lookup;
- return 0;
-}
-
-#undef dns_lookup
int dns_lookup(const char *host, const struct dns_lookup_settings *set,
dns_lookup_callback_t *callback, void *context,
struct dns_lookup **lookup_r)
{
- return dns_lookup_common(t_strconcat("IP\t", host, "\n", NULL), FALSE,
- set, callback, context, lookup_r);
+ struct dns_client *client;
+
+ client = dns_client_init(set);
+ client->deinit_client_at_free = TRUE;
+ if (dns_client_lookup(client, host, callback, context, lookup_r) < 0) {
+ dns_client_deinit(&client);
+ return -1;
+ }
+ return 0;
}
-#undef dns_lookup_ptr
int dns_lookup_ptr(const struct ip_addr *ip,
const struct dns_lookup_settings *set,
dns_lookup_callback_t *callback, void *context,
struct dns_lookup **lookup_r)
{
- const char *cmd = t_strconcat("NAME\t", net_ip2addr(ip), "\n", NULL);
- return dns_lookup_common(cmd, TRUE, set, callback, context, lookup_r);
+ struct dns_client *client;
+
+ client = dns_client_init(set);
+ client->deinit_client_at_free = TRUE;
+ if (dns_client_lookup_ptr(client, ip, callback, context, lookup_r) < 0) {
+ dns_client_deinit(&client);
+ return -1;
+ }
+ return 0;
+}
+
+static void dns_client_idle_timeout(struct dns_client *client)
+{
+ i_assert(client->head == NULL);
+
+ dns_client_disconnect(client, "Idle timeout");
}
static void dns_lookup_free(struct dns_lookup **_lookup)
{
struct dns_lookup *lookup = *_lookup;
+ struct dns_client *client = lookup->client;
*_lookup = NULL;
- dns_lookup_close(lookup);
+ DLLIST2_REMOVE(&client->head, &client->tail, lookup);
+ if (lookup->to != NULL)
+ timeout_remove(&lookup->to);
i_free(lookup->name);
i_free(lookup->ips);
- i_free(lookup->path);
+ if (client->deinit_client_at_free)
+ dns_client_deinit(&client);
+ else if (client->head == NULL) {
+ client->to_idle = timeout_add(client->idle_timeout_msecs,
+ dns_client_idle_timeout, client);
+ }
i_free(lookup);
}
@@ -242,5 +260,106 @@
{
if (lookup->to != NULL)
lookup->to = io_loop_move_timeout(&lookup->to);
- lookup->io = io_loop_move_io(&lookup->io);
+ lookup->client->io = io_loop_move_io(&lookup->client->io);
}
+
+struct dns_client *dns_client_init(const struct dns_lookup_settings *set)
+{
+ struct dns_client *client;
+
+ client = i_new(struct dns_client, 1);
+ client->path = i_strdup(set->dns_client_socket_path);
+ client->timeout_msecs = set->timeout_msecs;
+ client->idle_timeout_msecs = set->idle_timeout_msecs;
+ client->fd = -1;
More information about the dovecot-cvs
mailing list