]> git.ozlabs.org Git - ccan/blob - ccan/antithread/examples/dns_lookup.c
ccanlint clean and move endian.h to top of #includes (tests that it doesn't need...
[ccan] / ccan / antithread / examples / dns_lookup.c
1 /* Async DNS lookup.  Shows passing complex data through pool. */
2 #include <ccan/antithread/antithread.h>
3 #include <ccan/str/str.h>
4 #include <ccan/talloc/talloc.h>
5 #include <err.h>
6 #include <sys/select.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <netdb.h>
10
11 struct lookup_answer {
12         bool ok;
13         union {
14                 struct hostent hent;
15                 int herrno; /* If !ok */
16         };
17 };
18
19 /* Including NULL terminator. */
20 static inline unsigned count_entries(char **entries)
21 {
22         unsigned int i;
23
24         for (i = 0; entries[i]; i++);
25         return i+1;
26 }
27
28 /* Copy as one nice tallocated object.  Since ans is in the pool, it
29  * all gets put in the pool. */
30 static void copy_answer(struct lookup_answer *ans, const struct hostent *host)
31 {
32         unsigned int i;
33
34         ans->hent.h_name = talloc_strdup(ans, host->h_name);
35         ans->hent.h_aliases = talloc_array(ans, char *,
36                                            count_entries(host->h_aliases));
37         for (i = 0; host->h_aliases[i]; i++)
38                 ans->hent.h_aliases[i] = talloc_strdup(ans->hent.h_aliases,
39                                                        host->h_aliases[i]);
40         ans->hent.h_aliases[i] = NULL;
41         ans->hent.h_addrtype = host->h_addrtype;
42         ans->hent.h_length = host->h_length;
43         ans->hent.h_addr_list = talloc_array(ans, char *,
44                                              count_entries(host->h_addr_list));
45         for (i = 0; host->h_addr_list[i]; i++)
46                 ans->hent.h_addr_list[i] = talloc_memdup(ans->hent.h_addr_list,
47                                                          host->h_addr_list[i],
48                                                          ans->hent.h_length);
49 }
50
51 static void *lookup_dns(struct at_pool *atp, char *name)
52 {
53         struct lookup_answer *ans;
54         struct hostent *host;
55
56         host = gethostbyname(name);
57
58         ans = talloc(at_pool_ctx(atp), struct lookup_answer);
59         if (!host) {
60                 ans->ok = false;
61                 ans->herrno = h_errno;
62         } else {
63                 ans->ok = true;
64                 copy_answer(ans, host);
65         }
66
67         return ans;
68 }
69
70 static void report_answer(const char *name, const struct lookup_answer *ans)
71 {
72         unsigned int i;
73
74         if (!ans->ok) {
75                 printf("%s: %s\n", name, hstrerror(ans->herrno));
76                 return;
77         }
78
79         printf("%s: ", name);
80         for (i = 0; ans->hent.h_aliases[i]; i++)
81                 printf("%c%s", i == 0 ? '[' : ' ', ans->hent.h_aliases[i]);
82         if (i)
83                 printf("]");
84         printf("%#x", ans->hent.h_addrtype);
85         for (i = 0; ans->hent.h_addr_list[i]; i++) {
86                 unsigned int j;
87                 printf(" ");
88                 for (j = 0; j < ans->hent.h_length; j++)
89                         printf("%02x", ans->hent.h_addr_list[i][j]);
90         }
91         printf("\n");
92 }
93
94 int main(int argc, char *argv[])
95 {
96         struct at_pool *atp;
97         struct athread **at;
98         unsigned int i;
99
100         if (argc < 2)
101                 errx(1, "Usage: dns_lookup [--sync] name...");
102
103         /* Give it plenty of room. */
104         atp = at_pool(argc * 1024*1024);
105         if (!atp)
106                 err(1, "Can't create pool");
107
108         /* Free pool on exit. */
109         talloc_steal(talloc_autofree_context(), atp);
110
111         if (streq(argv[1], "--sync")) {
112                 for (i = 2; i < argc; i++) {
113                         struct lookup_answer *ans = lookup_dns(atp, argv[i]);
114                         report_answer(argv[i], ans);
115                         talloc_free(ans);
116                 }
117                 return 0;
118         }                       
119
120         at = talloc_array(atp, struct athread *, argc);
121
122         for (i = 1; i < argc; i++) {
123                 at[i] = at_run(atp, lookup_dns, argv[i]);
124                 if (!at[i])
125                         err(1, "Can't spawn child");
126         }
127
128         for (i = 1; i < argc; i++) {
129                 struct lookup_answer *ans = at_read(at[i]);
130                 if (!ans)
131                         warn("Child died on '%s'", argv[i]);
132                 else {
133                         report_answer(argv[i], ans);
134                         talloc_free(ans);
135                 }
136         }
137         return 0;
138 }