summaryrefslogtreecommitdiff
path: root/ccan/antithread/examples/dns_lookup.c
blob: 4c0a4eaad84992aac96b10211aee529dfb52a9a8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* Async DNS lookup.  Shows passing complex data through pool. */
#include <ccan/antithread/antithread.h>
#include <ccan/str/str.h>
#include <ccan/talloc/talloc.h>
#include <err.h>
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>

struct lookup_answer {
	bool ok;
	union {
		struct hostent hent;
		int herrno; /* If !ok */
	};
};

/* Including NULL terminator. */
static inline unsigned count_entries(char **entries)
{
	unsigned int i;

	for (i = 0; entries[i]; i++);
	return i+1;
}

/* Copy as one nice tallocated object.  Since ans is in the pool, it
 * all gets put in the pool. */
static void copy_answer(struct lookup_answer *ans, const struct hostent *host)
{
	unsigned int i;

	ans->hent.h_name = talloc_strdup(ans, host->h_name);
	ans->hent.h_aliases = talloc_array(ans, char *,
					   count_entries(host->h_aliases));
	for (i = 0; host->h_aliases[i]; i++)
		ans->hent.h_aliases[i] = talloc_strdup(ans->hent.h_aliases,
						       host->h_aliases[i]);
	ans->hent.h_aliases[i] = NULL;
	ans->hent.h_addrtype = host->h_addrtype;
	ans->hent.h_length = host->h_length;
	ans->hent.h_addr_list = talloc_array(ans, char *,
					     count_entries(host->h_addr_list));
	for (i = 0; host->h_addr_list[i]; i++)
		ans->hent.h_addr_list[i] = talloc_memdup(ans->hent.h_addr_list,
							 host->h_addr_list[i],
							 ans->hent.h_length);
}

static void *lookup_dns(struct at_pool *atp, char *name)
{
	struct lookup_answer *ans;
	struct hostent *host;

	host = gethostbyname(name);

	ans = talloc(at_pool_ctx(atp), struct lookup_answer);
	if (!host) {
		ans->ok = false;
		ans->herrno = h_errno;
	} else {
		ans->ok = true;
		copy_answer(ans, host);
	}

	return ans;
}

static void report_answer(const char *name, const struct lookup_answer *ans)
{
	unsigned int i;

	if (!ans->ok) {
		printf("%s: %s\n", name, hstrerror(ans->herrno));
		return;
	}

	printf("%s: ", name);
	for (i = 0; ans->hent.h_aliases[i]; i++)
		printf("%c%s", i == 0 ? '[' : ' ', ans->hent.h_aliases[i]);
	if (i)
		printf("]");
	printf("%#x", ans->hent.h_addrtype);
	for (i = 0; ans->hent.h_addr_list[i]; i++) {
		unsigned int j;
		printf(" ");
		for (j = 0; j < ans->hent.h_length; j++)
			printf("%02x", ans->hent.h_addr_list[i][j]);
	}
	printf("\n");
}

int main(int argc, char *argv[])
{
	struct at_pool *atp;
	struct athread **at;
	unsigned int i;

	if (argc < 2)
		errx(1, "Usage: dns_lookup [--sync] name...");

	/* Give it plenty of room. */
	atp = at_pool(argc * 1024*1024);
	if (!atp)
		err(1, "Can't create pool");

	/* Free pool on exit. */
	talloc_steal(talloc_autofree_context(), atp);

	if (streq(argv[1], "--sync")) {
		for (i = 2; i < argc; i++) {
			struct lookup_answer *ans = lookup_dns(atp, argv[i]);
			report_answer(argv[i], ans);
			talloc_free(ans);
		}
		return 0;
	}			

	at = talloc_array(atp, struct athread *, argc);

	for (i = 1; i < argc; i++) {
		at[i] = at_run(atp, lookup_dns, argv[i]);
		if (!at[i])
			err(1, "Can't spawn child");
	}

	for (i = 1; i < argc; i++) {
		struct lookup_answer *ans = at_read(at[i]);
		if (!ans)
			warn("Child died on '%s'", argv[i]);
		else {
			report_answer(argv[i], ans);
			talloc_free(ans);
		}
	}
	return 0;
}