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