Revert "transmission: update from 2.13 to 2.22"
[tomato.git] / release / src / router / transmission / third-party / dht / dht-example.c
blob150ed8886520ee8f3134e8b14c94c715bc9510f8
1 /* This example code was written by Juliusz Chroboczek.
2 You are free to cut'n'paste from it to your heart's content. */
4 /* For crypt */
5 #define _GNU_SOURCE
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/time.h>
14 #include <arpa/inet.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netdb.h>
18 #include <sys/signal.h>
20 #include "dht.h"
22 #define MAX_BOOTSTRAP_NODES 20
23 static struct sockaddr_storage bootstrap_nodes[MAX_BOOTSTRAP_NODES];
24 static int num_bootstrap_nodes = 0;
26 static volatile sig_atomic_t dumping = 0, searching = 0, exiting = 0;
28 static void
29 sigdump(int signo)
31 dumping = 1;
34 static void
35 sigtest(int signo)
37 searching = 1;
40 static void
41 sigexit(int signo)
43 exiting = 1;
46 static void
47 init_signals(void)
49 struct sigaction sa;
50 sigset_t ss;
52 sigemptyset(&ss);
53 sa.sa_handler = sigdump;
54 sa.sa_mask = ss;
55 sa.sa_flags = 0;
56 sigaction(SIGUSR1, &sa, NULL);
58 sigemptyset(&ss);
59 sa.sa_handler = sigtest;
60 sa.sa_mask = ss;
61 sa.sa_flags = 0;
62 sigaction(SIGUSR2, &sa, NULL);
64 sigemptyset(&ss);
65 sa.sa_handler = sigexit;
66 sa.sa_mask = ss;
67 sa.sa_flags = 0;
68 sigaction(SIGINT, &sa, NULL);
71 const unsigned char hash[20] = {
72 0x54, 0x57, 0x87, 0x89, 0xdf, 0xc4, 0x23, 0xee, 0xf6, 0x03,
73 0x1f, 0x81, 0x94, 0xa9, 0x3a, 0x16, 0x98, 0x8b, 0x72, 0x7b
76 /* The call-back function is called by the DHT whenever something
77 interesting happens. Right now, it only happens when we get a new value or
78 when a search completes, but this may be extended in future versions. */
79 static void
80 callback(void *closure,
81 int event,
82 unsigned char *info_hash,
83 void *data, size_t data_len)
85 if(event == DHT_EVENT_SEARCH_DONE)
86 printf("Search done.\n");
87 else if(event == DHT_EVENT_VALUES)
88 printf("Received %d values.\n", (int)(data_len / 6));
91 int
92 main(int argc, char **argv)
94 int i, rc, fd;
95 int s = -1, s6 = -1, port;
96 int have_id = 0;
97 unsigned char myid[20];
98 time_t tosleep = 0;
99 char *id_file = "dht-example.id";
100 int opt;
101 int quiet = 0, ipv4 = 1, ipv6 = 1;
102 struct sockaddr_in sin;
103 struct sockaddr_in6 sin6;
105 memset(&sin, 0, sizeof(sin));
106 sin.sin_family = AF_INET;
108 memset(&sin6, 0, sizeof(sin6));
109 sin6.sin6_family = AF_INET6;
113 while(1) {
114 opt = getopt(argc, argv, "q46b:i:");
115 if(opt < 0)
116 break;
118 switch(opt) {
119 case 'q': quiet = 1; break;
120 case '4': ipv6 = 0; break;
121 case '6': ipv4 = 0; break;
122 case 'b': {
123 char buf[16];
124 int rc;
125 rc = inet_pton(AF_INET, optarg, buf);
126 if(rc == 1) {
127 memcpy(&sin.sin_addr, buf, 4);
128 break;
130 rc = inet_pton(AF_INET6, optarg, buf);
131 if(rc == 1) {
132 memcpy(&sin6.sin6_addr, buf, 16);
133 break;
135 goto usage;
137 break;
138 case 'i':
139 id_file = optarg;
140 break;
141 default:
142 goto usage;
146 /* Ids need to be distributed evenly, so you cannot just use your
147 bittorrent id. Either generate it randomly, or take the SHA-1 of
148 something. */
149 fd = open(id_file, O_RDONLY);
150 if(fd >= 0) {
151 rc = read(fd, myid, 20);
152 if(rc == 20)
153 have_id = 1;
154 close(fd);
157 fd = open("/dev/urandom", O_RDONLY);
158 if(fd < 0) {
159 perror("open(random)");
160 exit(1);
163 if(!have_id) {
164 int ofd;
166 rc = read(fd, myid, 20);
167 if(rc < 0) {
168 perror("read(random)");
169 exit(1);
171 have_id = 1;
172 close(fd);
174 ofd = open(id_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
175 if(ofd >= 0) {
176 rc = write(ofd, myid, 20);
177 if(rc < 20)
178 unlink(id_file);
179 close(ofd);
184 unsigned seed;
185 read(fd, &seed, sizeof(seed));
186 srandom(seed);
189 close(fd);
191 if(argc < 2)
192 goto usage;
194 i = optind;
196 if(argc < i + 1)
197 goto usage;
199 port = atoi(argv[i++]);
200 if(port <= 0 || port >= 0x10000)
201 goto usage;
203 while(i < argc) {
204 struct addrinfo hints, *info, *infop;
205 memset(&hints, 0, sizeof(hints));
206 hints.ai_socktype = SOCK_DGRAM;
207 if(!ipv6)
208 hints.ai_family = AF_INET;
209 else if(!ipv4)
210 hints.ai_family = AF_INET6;
211 else
212 hints.ai_family = 0;
213 rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
214 if(rc != 0) {
215 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc));
216 exit(1);
219 i++;
220 if(i >= argc)
221 goto usage;
223 infop = info;
224 while(infop) {
225 memcpy(&bootstrap_nodes[num_bootstrap_nodes],
226 infop->ai_addr, infop->ai_addrlen);
227 infop = infop->ai_next;
228 num_bootstrap_nodes++;
230 freeaddrinfo(info);
232 i++;
235 /* If you set dht_debug to a stream, every action taken by the DHT will
236 be logged. */
237 if(!quiet)
238 dht_debug = stdout;
240 /* We need an IPv4 and an IPv6 socket, bound to a stable port. Rumour
241 has it that uTorrent works better when it is the same as your
242 Bittorrent port. */
243 if(ipv4) {
244 s = socket(PF_INET, SOCK_DGRAM, 0);
245 if(s < 0) {
246 perror("socket(IPv4)");
250 if(ipv6) {
251 s6 = socket(PF_INET6, SOCK_DGRAM, 0);
252 if(s6 < 0) {
253 perror("socket(IPv6)");
257 if(s < 0 && s6 < 0) {
258 fprintf(stderr, "Eek!");
259 exit(1);
263 if(s >= 0) {
264 sin.sin_port = htons(port);
265 rc = bind(s, (struct sockaddr*)&sin, sizeof(sin));
266 if(rc < 0) {
267 perror("bind(IPv4)");
268 exit(1);
272 if(s6 >= 0) {
273 int rc;
274 int val = 1;
276 rc = setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY,
277 (char *)&val, sizeof(val));
278 if(rc < 0) {
279 perror("setsockopt(IPV6_V6ONLY)");
280 exit(1);
283 /* BEP-32 mandates that we should bind this socket to one of our
284 global IPv6 addresses. In this simple example, this only
285 happens if the user used the -b flag. */
287 sin6.sin6_port = htons(port);
288 rc = bind(s6, (struct sockaddr*)&sin6, sizeof(sin6));
289 if(rc < 0) {
290 perror("bind(IPv6)");
291 exit(1);
295 /* Init the dht. This sets the socket into non-blocking mode. */
296 rc = dht_init(s, s6, myid, (unsigned char*)"JC\0\0");
297 if(rc < 0) {
298 perror("dht_init");
299 exit(1);
302 init_signals();
304 /* For bootstrapping, we need an initial list of nodes. This could be
305 hard-wired, but can also be obtained from the nodes key of a torrent
306 file, or from the PORT bittorrent message.
308 Dht_ping_node is the brutal way of bootstrapping -- it actually
309 sends a message to the peer. If you're going to bootstrap from
310 a massive number of nodes (for example because you're restoring from
311 a dump) and you already know their ids, it's better to use
312 dht_insert_node. If the ids are incorrect, the DHT will recover. */
313 for(i = 0; i < num_bootstrap_nodes; i++) {
314 dht_ping_node((struct sockaddr*)&bootstrap_nodes[i],
315 sizeof(bootstrap_nodes[i]));
316 usleep(random() % 100000);
319 while(1) {
320 struct timeval tv;
321 fd_set readfds;
322 tv.tv_sec = tosleep;
323 tv.tv_usec = random() % 1000000;
325 FD_ZERO(&readfds);
326 if(s >= 0)
327 FD_SET(s, &readfds);
328 if(s6 >= 0)
329 FD_SET(s6, &readfds);
330 rc = select(s > s6 ? s + 1 : s6 + 1, &readfds, NULL, NULL, &tv);
331 if(rc < 0) {
332 if(errno != EINTR) {
333 perror("select");
334 sleep(1);
338 if(exiting)
339 break;
341 rc = dht_periodic(rc > 0, &tosleep, callback, NULL);
342 if(rc < 0) {
343 if(errno == EINTR) {
344 continue;
345 } else {
346 perror("dht_periodic");
347 if(rc == EINVAL || rc == EFAULT)
348 abort();
349 tosleep = 1;
353 /* This is how you trigger a search for a torrent hash. If port
354 (the second argument) is non-zero, it also performs an announce.
355 Since peers expire announced data after 30 minutes, it's a good
356 idea to reannounce every 28 minutes or so. */
357 if(searching) {
358 if(s >= 0)
359 dht_search(hash, 0, AF_INET, callback, NULL);
360 if(s6 >= 0)
361 dht_search(hash, 0, AF_INET6, callback, NULL);
362 searching = 0;
365 /* For debugging, or idle curiosity. */
366 if(dumping) {
367 dht_dump_tables(stdout);
368 dumping = 0;
373 struct sockaddr_in sin[500];
374 struct sockaddr_in6 sin6[500];
375 int num = 500, num6 = 500;
376 int i;
377 i = dht_get_nodes(sin, &num, sin6, &num6);
378 printf("Found %d (%d + %d) good nodes.\n", i, num, num6);
381 dht_uninit(1);
382 return 0;
384 usage:
385 printf("Usage: dht-example [-q] [-4] [-6] [-i filename] [-b address]...\n"
386 " port [address port]...\n");
387 exit(1);
390 /* We need to provide a reasonably strong cryptographic hashing function.
391 Here's how we'd do it if we had RSA's MD5 code. */
392 #if 0
393 void
394 dht_hash(void *hash_return, int hash_size,
395 const void *v1, int len1,
396 const void *v2, int len2,
397 const void *v3, int len3)
399 static MD5_CTX ctx;
400 MD5Init(&ctx);
401 MD5Update(&ctx, v1, len1);
402 MD5Update(&ctx, v2, len2);
403 MD5Update(&ctx, v3, len3);
404 MD5Final(&ctx);
405 if(hash_size > 16)
406 memset((char*)hash_return + 16, 0, hash_size - 16);
407 memcpy(hash_return, ctx.digest, hash_size > 16 ? 16 : hash_size);
409 #else
410 /* But for this example, we might as well use something weaker. */
411 void
412 dht_hash(void *hash_return, int hash_size,
413 const void *v1, int len1,
414 const void *v2, int len2,
415 const void *v3, int len3)
417 const char *c1 = v1, *c2 = v2, *c3 = v3;
418 char key[9]; /* crypt is limited to 8 characters */
419 int i;
421 memset(key, 0, 9);
422 #define CRYPT_HAPPY(c) ((c % 0x60) + 0x20)
424 for(i = 0; i < 2 && i < len1; i++)
425 key[i] = CRYPT_HAPPY(c1[i]);
426 for(i = 0; i < 4 && i < len1; i++)
427 key[2 + i] = CRYPT_HAPPY(c2[i]);
428 for(i = 0; i < 2 && i < len1; i++)
429 key[6 + i] = CRYPT_HAPPY(c3[i]);
430 strncpy(hash_return, crypt(key, "jc"), hash_size);
432 #endif
435 dht_random_bytes(void *buf, size_t size)
437 int fd, rc, save;
439 fd = open("/dev/urandom", O_RDONLY);
440 if(fd < 0)
441 return -1;
443 rc = read(fd, buf, size);
445 save = errno;
446 close(fd);
447 errno = save;
449 return rc;