Add antithread. Not finished, but useful as example of module whose
[ccan] / ccan / antithread / examples / md5_server.c
1 /* Tries to find data with a given MD5 (up to N bits). */
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
11 static void usage(void)
12 {
13         errx(1, "Usage: md5calc <hexstring> <numcpus>");
14 }
15
16 static void parse_hexstring(const char *string, struct md5_search *md5s)
17 {
18         unsigned int i;
19
20         if (strstarts(string, "0x") || strstarts(string, "0X"))
21                 string += 2;
22
23         for (i = 0; i < MD5_HASH_WORDS; i++) {
24                 unsigned int n[4], j;
25                 int ret;
26
27                 ret = sscanf(string, "%02x%02x%02x%02x",
28                              &n[0], &n[1], &n[2], &n[3]);
29                 string += 8;
30
31                 if (ret == EOF)
32                         break;
33                 for (j = 0; j < ret; j++) {
34                         md5s->mask[MD5_HASH_WORDS-i-1] |= (0xFF << (8*j));
35                         md5s->md5[MD5_HASH_WORDS-i-1] |= (n[j] << (8*j));
36                 }
37
38                 if (ret != 4)
39                         break;
40         }
41 }
42
43 static void init_pattern(u8 *pattern, unsigned int num_bytes, u64 total)
44 {
45         unsigned int i;
46
47         for (i = 0; i < num_bytes; i++) {
48                 pattern[i] = 'A' + (total % 26);
49                 total /= 26;
50         }
51 }
52
53 #define PATTERN_BYTES 32
54
55 int main(int argc, char *argv[])
56 {
57         struct at_pool *atp;
58         struct md5_search md5s;
59         unsigned int i, maxfd, numathreads = argc == 3 ? atoi(argv[2]) : 0;
60         u64 total = 0;
61         fd_set fds;
62         char *cmdline[] = { "./md5_worker", NULL };
63         struct athread *at[numathreads];
64
65         if (numathreads == 0)
66                 usage();
67
68         memset(&md5s, 0, sizeof(md5s));
69         parse_hexstring(argv[1], &md5s);
70
71         md5s.num_tries = 1024*1024;
72         md5s.num_bytes = PATTERN_BYTES;
73
74         /* *2 to allow for allocation inefficiency. */
75         atp = at_pool((sizeof(md5s) + PATTERN_BYTES) * (numathreads + 1) * 2);
76         if (!atp)
77                 err(1, "Can't create pool");
78
79         /* Free pool on exit. */
80 //      talloc_steal(talloc_autofree_context(), atp);
81
82         FD_ZERO(&fds);
83         maxfd = 0;
84         for (i = 0; i < numathreads; i++) {
85                 at[i] = at_spawn(atp, NULL, cmdline);
86                 if (!at[i])
87                         err(1, "Can't spawn child");
88                 FD_SET(at_fd(at[i]), &fds);
89                 if (at_fd(at[i]) > maxfd)
90                         maxfd = at_fd(at[i]);
91         }
92
93         for (;;) {
94                 struct md5_search *m, *res;
95                 fd_set in = fds;
96
97                 /* Shouldn't fail! */
98                 m = talloc(at_pool_ctx(atp), struct md5_search);
99                 *m = md5s;
100                 md5s.num_tries++;
101                 m->pattern = talloc_array(m, u8, m->num_bytes);
102                 init_pattern(m->pattern, m->num_bytes, total);
103
104                 select(maxfd+1, &in, NULL, NULL, NULL);
105                 for (i = 0; i < numathreads; i++)
106                         if (FD_ISSET(at_fd(at[i]), &in))
107                                 break;
108                 if (i == numathreads)
109                         errx(1, "Select returned, but noone ready?");
110
111                 res = at_read(at[i]);
112                 if (res == NULL) {
113                         warn("Thread died?");
114                         FD_CLR(at_fd(at[i]), &fds);
115                         continue;
116                 }
117                 if (res != INITIAL_POINTER) {
118                         if (res->success) {
119                                 printf("Success! '%.*s'\n",
120                                        res->num_bytes, (char *)res->pattern);
121                                 exit(0);
122                         }
123                         m->num_tries++;
124                         talloc_free(res);
125                 }
126                 at_tell(at[i], m);
127                 total += m->num_tries;
128         }
129 }