1 /* This example code was written by Juliusz Chroboczek.
2 You are free to cut'n'paste from it to your heart's content. */
14 #include <arpa/inet.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
18 #include <sys/signal.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;
53 sa
.sa_handler
= sigdump
;
56 sigaction(SIGUSR1
, &sa
, NULL
);
59 sa
.sa_handler
= sigtest
;
62 sigaction(SIGUSR2
, &sa
, NULL
);
65 sa
.sa_handler
= sigexit
;
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. */
80 callback(void *closure
,
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));
92 main(int argc
, char **argv
)
95 int s
= -1, s6
= -1, port
;
97 unsigned char myid
[20];
99 char *id_file
= "dht-example.id";
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
;
114 opt
= getopt(argc
, argv
, "q46b:i:");
119 case 'q': quiet
= 1; break;
120 case '4': ipv6
= 0; break;
121 case '6': ipv4
= 0; break;
125 rc
= inet_pton(AF_INET
, optarg
, buf
);
127 memcpy(&sin
.sin_addr
, buf
, 4);
130 rc
= inet_pton(AF_INET6
, optarg
, buf
);
132 memcpy(&sin6
.sin6_addr
, buf
, 16);
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
149 fd
= open(id_file
, O_RDONLY
);
151 rc
= read(fd
, myid
, 20);
157 fd
= open("/dev/urandom", O_RDONLY
);
159 perror("open(random)");
166 rc
= read(fd
, myid
, 20);
168 perror("read(random)");
174 ofd
= open(id_file
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
176 rc
= write(ofd
, myid
, 20);
185 read(fd
, &seed
, sizeof(seed
));
199 port
= atoi(argv
[i
++]);
200 if(port
<= 0 || port
>= 0x10000)
204 struct addrinfo hints
, *info
, *infop
;
205 memset(&hints
, 0, sizeof(hints
));
206 hints
.ai_socktype
= SOCK_DGRAM
;
208 hints
.ai_family
= AF_INET
;
210 hints
.ai_family
= AF_INET6
;
213 rc
= getaddrinfo(argv
[i
], argv
[i
+ 1], &hints
, &info
);
215 fprintf(stderr
, "getaddrinfo: %s\n", gai_strerror(rc
));
225 memcpy(&bootstrap_nodes
[num_bootstrap_nodes
],
226 infop
->ai_addr
, infop
->ai_addrlen
);
227 infop
= infop
->ai_next
;
228 num_bootstrap_nodes
++;
235 /* If you set dht_debug to a stream, every action taken by the DHT will
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
244 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
246 perror("socket(IPv4)");
251 s6
= socket(PF_INET6
, SOCK_DGRAM
, 0);
253 perror("socket(IPv6)");
257 if(s
< 0 && s6
< 0) {
258 fprintf(stderr
, "Eek!");
264 sin
.sin_port
= htons(port
);
265 rc
= bind(s
, (struct sockaddr
*)&sin
, sizeof(sin
));
267 perror("bind(IPv4)");
276 rc
= setsockopt(s6
, IPPROTO_IPV6
, IPV6_V6ONLY
,
277 (char *)&val
, sizeof(val
));
279 perror("setsockopt(IPV6_V6ONLY)");
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
));
290 perror("bind(IPv6)");
295 /* Init the dht. This sets the socket into non-blocking mode. */
296 rc
= dht_init(s
, s6
, myid
, (unsigned char*)"JC\0\0");
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);
323 tv
.tv_usec
= random() % 1000000;
329 FD_SET(s6
, &readfds
);
330 rc
= select(s
> s6
? s
+ 1 : s6
+ 1, &readfds
, NULL
, NULL
, &tv
);
341 rc
= dht_periodic(rc
> 0, &tosleep
, callback
, NULL
);
346 perror("dht_periodic");
347 if(rc
== EINVAL
|| rc
== EFAULT
)
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. */
359 dht_search(hash
, 0, AF_INET
, callback
, NULL
);
361 dht_search(hash
, 0, AF_INET6
, callback
, NULL
);
365 /* For debugging, or idle curiosity. */
367 dht_dump_tables(stdout
);
373 struct sockaddr_in sin
[500];
374 struct sockaddr_in6 sin6
[500];
375 int num
= 500, num6
= 500;
377 i
= dht_get_nodes(sin
, &num
, sin6
, &num6
);
378 printf("Found %d (%d + %d) good nodes.\n", i
, num
, num6
);
385 printf("Usage: dht-example [-q] [-4] [-6] [-i filename] [-b address]...\n"
386 " port [address port]...\n");
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. */
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
)
401 MD5Update(&ctx
, v1
, len1
);
402 MD5Update(&ctx
, v2
, len2
);
403 MD5Update(&ctx
, v3
, len3
);
406 memset((char*)hash_return
+ 16, 0, hash_size
- 16);
407 memcpy(hash_return
, ctx
.digest
, hash_size
> 16 ? 16 : hash_size
);
410 /* But for this example, we might as well use something weaker. */
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 */
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
);
435 dht_random_bytes(void *buf
, size_t size
)
439 fd
= open("/dev/urandom", O_RDONLY
);
443 rc
= read(fd
, buf
, size
);