/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
-#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
+#include "array.h"
+#include "strfuncs.h"
+#include "connection.h"
#include "restrict-access.h"
#include "master-service.h"
#include <unistd.h>
-struct dns_client {
- int fd;
- struct istream *input;
- struct ostream *output;
- struct io *io;
-};
-
-#define MAX_INBUF_SIZE 1024
-#define MAX_OUTBUF_SIZE (1024*64)
-#define INPUT_TIMEOUT_MSECS (1000*10)
-
-static struct dns_client *dns_client = NULL;
-
-static void dns_client_destroy(struct dns_client **client);
+static struct connection_list *dns_clients = NULL;
-static int dns_client_input_line(struct dns_client *client, const char *line)
+static int dns_client_input_args(struct connection *client, const char *const *args)
{
struct ip_addr *ips, ip;
const char *name;
unsigned int i, ips_count;
int ret;
- if (str_begins(line, "IP\t")) {
- ret = net_gethostbyname(line + 3, &ips, &ips_count);
+ if (strcmp(args[0], "QUIT") == 0) {
+ return -1;
+ } else if (args[1] == NULL) {
+ i_error("Got empty request");
+ return -1;
+ }
+
+ if (strcmp(args[0], "IP") == 0) {
+ ret = net_gethostbyname(args[1], &ips, &ips_count);
if (ret == 0 && ips_count == 0) {
/* shouldn't happen, but fix it anyway.. */
ret = EAI_NONAME;
o_stream_nsend_str(client->output,
t_strdup_printf("0 %u\n", ips_count));
for (i = 0; i < ips_count; i++) {
+ const char *ip = net_ip2addr(&ips[i]);
o_stream_nsend_str(client->output, t_strconcat(
net_ip2addr(&ips[i]), "\n", NULL));
}
}
- } else if (str_begins(line, "NAME\t")) {
- if (net_addr2ip(line+5, &ip) < 0)
+ } else if (strcmp(args[0], "NAME") == 0) {
+ if (net_addr2ip(args[1], &ip) < 0)
o_stream_nsend_str(client->output, "-1\n");
else if ((ret = net_gethostbyaddr(&ip, &name)) != 0) {
o_stream_nsend_str(client->output,
o_stream_nsend_str(client->output,
t_strdup_printf("0 %s\n", name));
}
- } else if (strcmp(line, "QUIT") == 0) {
- return -1;
} else {
o_stream_nsend_str(client->output, "Unknown command\n");
}
- if (client->output->overflow)
- return -1;
- return 0;
-}
-
-static void dns_client_input(struct dns_client *client)
-{
- const char *line;
- int ret = 0;
-
- o_stream_cork(client->output);
- while ((line = i_stream_read_next_line(client->input)) != NULL) {
- if (dns_client_input_line(client, line) < 0) {
- ret = -1;
- break;
- }
- }
- o_stream_uncork(client->output);
-
- if (client->input->eof || client->input->stream_errno != 0 || ret < 0)
- dns_client_destroy(&client);
-}
-
-static struct dns_client *dns_client_create(int fd)
-{
- struct dns_client *client;
-
- client = i_new(struct dns_client, 1);
- client->fd = fd;
- client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE);
- client->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE);
- o_stream_set_no_error_handling(client->output, TRUE);
- client->io = io_add(fd, IO_READ, dns_client_input, client);
- return client;
+ return 1;
}
-static void dns_client_destroy(struct dns_client **_client)
+static void dns_client_destroy(struct connection *client)
{
- struct dns_client *client = *_client;
-
- *_client = NULL;
-
- io_remove(&client->io);
- i_stream_destroy(&client->input);
- o_stream_destroy(&client->output);
- if (close(client->fd) < 0)
- i_error("close() failed: %m");
+ connection_deinit(client);
i_free(client);
-
- dns_client = NULL;
master_service_client_connection_destroyed(master_service);
}
-static void client_connected(struct master_service_connection *conn)
-{
- if (dns_client != NULL) {
- i_error("dns-client must be configured with client_limit=1");
- return;
- }
+static const struct connection_vfuncs dns_client_vfuncs = {
+ .input_args = dns_client_input_args,
+ .destroy = dns_client_destroy
+};
+
+static const struct connection_settings dns_client_set = {
+ .dont_send_version = TRUE,
+ .input_max_size = (size_t)-1,
+ .output_max_size = (size_t)-1
+};
- master_service_client_connection_accept(conn);
- dns_client = dns_client_create(conn->fd);
+static void client_connected(struct master_service_connection *master_conn)
+{
+ struct connection *conn = i_new(struct connection, 1);
+ master_service_client_connection_accept(master_conn);
+ connection_init_server(dns_clients, conn, master_conn->name,
+ master_conn->fd, master_conn->fd);
}
int main(int argc, char *argv[])
master_service_init_finish(master_service);
+ /* setup connection list */
+ dns_clients = connection_list_init(&dns_client_set, &dns_client_vfuncs);
+
master_service_run(master_service, client_connected);
- if (dns_client != NULL)
- dns_client_destroy(&dns_client);
+
+ /* disconnect all clients */
+ connection_list_deinit(&dns_clients);
master_service_deinit(&master_service);
return 0;