1 /*
2 * Copyright (c) 2009-2010 by Juliusz Chroboczek
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 *
22 *
23 */
24
25 /* ansi */
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h> /* memcpy(), memset(), memchr(), strlen() */
29 #include <stdlib.h> /* atoi() */
30
31 /* posix */
32 #include <signal.h> /* sig_atomic_t */
33
34 #ifdef _WIN32
35 #include <inttypes.h>
36 #include <ws2tcpip.h>
37 #undef gai_strerror
38 #define gai_strerror gai_strerrorA
39 #else
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/socket.h> /* socket(), bind() */
43 #include <netdb.h>
44 #include <netinet/in.h> /* sockaddr_in */
45 #endif
46
47 /* third party */
48 #include <event2/event.h>
49 #include <dht/dht.h>
50
51 /* libT */
52 #include "transmission.h"
53 #include "crypto-utils.h"
54 #include "file.h"
55 #include "log.h"
56 #include "net.h"
57 #include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
58 #include "platform.h" /* tr_threadNew() */
59 #include "session.h"
60 #include "torrent.h" /* tr_torrentFindFromHash() */
61 #include "tr-assert.h"
62 #include "tr-dht.h"
63 #include "trevent.h" /* tr_runInEventThread() */
64 #include "utils.h"
65 #include "variant.h"
66
67 static struct event* dht_timer = NULL;
68 static unsigned char myid[20];
69 static tr_session* session = NULL;
70
71 static void timer_callback(evutil_socket_t s, short type, void* ignore);
72
73 struct bootstrap_closure
74 {
75 tr_session* session;
76 uint8_t* nodes;
77 uint8_t* nodes6;
78 size_t len;
79 size_t len6;
80 };
81
bootstrap_done(tr_session * session,int af)82 static bool bootstrap_done(tr_session* session, int af)
83 {
84 int status;
85
86 if (af == 0)
87 {
88 return bootstrap_done(session, AF_INET) && bootstrap_done(session, AF_INET6);
89 }
90
91 status = tr_dhtStatus(session, af, NULL);
92 return status == TR_DHT_STOPPED || status >= TR_DHT_FIREWALLED;
93 }
94
nap(int roughly_sec)95 static void nap(int roughly_sec)
96 {
97 int const roughly_msec = roughly_sec * 1000;
98 int const msec = roughly_msec / 2 + tr_rand_int_weak(roughly_msec);
99 tr_wait_msec(msec);
100 }
101
bootstrap_af(tr_session * session)102 static int bootstrap_af(tr_session* session)
103 {
104 if (bootstrap_done(session, AF_INET6))
105 {
106 return AF_INET;
107 }
108 else if (bootstrap_done(session, AF_INET))
109 {
110 return AF_INET6;
111 }
112 else
113 {
114 return 0;
115 }
116 }
117
bootstrap_from_name(char const * name,tr_port port,int af)118 static void bootstrap_from_name(char const* name, tr_port port, int af)
119 {
120 struct addrinfo hints;
121 struct addrinfo* info;
122 struct addrinfo* infop;
123 char pp[10];
124 int rc;
125
126 memset(&hints, 0, sizeof(hints));
127 hints.ai_socktype = SOCK_DGRAM;
128 hints.ai_family = af;
129 /* No, just passing p + 1 to gai won't work. */
130 tr_snprintf(pp, sizeof(pp), "%d", (int)port);
131
132 rc = getaddrinfo(name, pp, &hints, &info);
133
134 if (rc != 0)
135 {
136 tr_logAddNamedError("DHT", "%s:%s: %s", name, pp, gai_strerror(rc));
137 return;
138 }
139
140 infop = info;
141
142 while (infop != NULL)
143 {
144 dht_ping_node(infop->ai_addr, infop->ai_addrlen);
145
146 nap(15);
147
148 if (bootstrap_done(session, af))
149 {
150 break;
151 }
152
153 infop = infop->ai_next;
154 }
155
156 freeaddrinfo(info);
157 }
158
dht_bootstrap(void * closure)159 static void dht_bootstrap(void* closure)
160 {
161 struct bootstrap_closure* cl = closure;
162 int num = cl->len / 6;
163 int num6 = cl->len6 / 18;
164
165 if (session != cl->session)
166 {
167 return;
168 }
169
170 if (cl->len > 0)
171 {
172 tr_logAddNamedInfo("DHT", "Bootstrapping from %d IPv4 nodes", num);
173 }
174
175 if (cl->len6 > 0)
176 {
177 tr_logAddNamedInfo("DHT", "Bootstrapping from %d IPv6 nodes", num6);
178 }
179
180 for (int i = 0; i < MAX(num, num6); ++i)
181 {
182 if (i < num && !bootstrap_done(cl->session, AF_INET))
183 {
184 tr_port port;
185 struct tr_address addr;
186
187 memset(&addr, 0, sizeof(addr));
188 addr.type = TR_AF_INET;
189 memcpy(&addr.addr.addr4, &cl->nodes[i * 6], 4);
190 memcpy(&port, &cl->nodes[i * 6 + 4], 2);
191 port = ntohs(port);
192 tr_dhtAddNode(cl->session, &addr, port, 1);
193 }
194
195 if (i < num6 && !bootstrap_done(cl->session, AF_INET6))
196 {
197 tr_port port;
198 struct tr_address addr;
199
200 memset(&addr, 0, sizeof(addr));
201 addr.type = TR_AF_INET6;
202 memcpy(&addr.addr.addr6, &cl->nodes6[i * 18], 16);
203 memcpy(&port, &cl->nodes6[i * 18 + 16], 2);
204 port = ntohs(port);
205 tr_dhtAddNode(cl->session, &addr, port, 1);
206 }
207
208 /* Our DHT code is able to take up to 9 nodes in a row without
209 dropping any. After that, it takes some time to split buckets.
210 So ping the first 8 nodes quickly, then slow down. */
211 if (i < 8)
212 {
213 nap(2);
214 }
215 else
216 {
217 nap(15);
218 }
219
220 if (bootstrap_done(session, 0))
221 {
222 break;
223 }
224 }
225
226 if (!bootstrap_done(cl->session, 0))
227 {
228 char* bootstrap_file;
229 tr_sys_file_t f = TR_BAD_SYS_FILE;
230
231 bootstrap_file = tr_buildPath(cl->session->configDir, "dht.bootstrap", NULL);
232
233 if (bootstrap_file != NULL)
234 {
235 f = tr_sys_file_open(bootstrap_file, TR_SYS_FILE_READ, 0, NULL);
236 }
237
238 if (f != TR_BAD_SYS_FILE)
239 {
240 tr_logAddNamedInfo("DHT", "Attempting manual bootstrap");
241
242 for (;;)
243 {
244 char buf[201];
245 char* p;
246 int port = 0;
247
248 if (!tr_sys_file_read_line(f, buf, 200, NULL))
249 {
250 break;
251 }
252
253 p = memchr(buf, ' ', strlen(buf));
254
255 if (p != NULL)
256 {
257 port = atoi(p + 1);
258 }
259
260 if (p == NULL || port <= 0 || port >= 0x10000)
261 {
262 tr_logAddNamedError("DHT", "Couldn't parse %s", buf);
263 continue;
264 }
265
266 *p = '\0';
267
268 bootstrap_from_name(buf, port, bootstrap_af(session));
269
270 if (bootstrap_done(cl->session, 0))
271 {
272 break;
273 }
274 }
275
276 tr_sys_file_close(f, NULL);
277 }
278
279 tr_free(bootstrap_file);
280 }
281
282 if (!bootstrap_done(cl->session, 0))
283 {
284 for (int i = 0; i < 6; ++i)
285 {
286 /* We don't want to abuse our bootstrap nodes, so be very
287 slow. The initial wait is to give other nodes a chance
288 to contact us before we attempt to contact a bootstrap
289 node, for example because we've just been restarted. */
290 nap(40);
291
292 if (bootstrap_done(cl->session, 0))
293 {
294 break;
295 }
296
297 if (i == 0)
298 {
299 tr_logAddNamedInfo("DHT", "Attempting bootstrap from dht.transmissionbt.com");
300 }
301
302 bootstrap_from_name("dht.transmissionbt.com", 6881, bootstrap_af(session));
303 }
304 }
305
306 if (cl->nodes != NULL)
307 {
308 tr_free(cl->nodes);
309 }
310
311 if (cl->nodes6 != NULL)
312 {
313 tr_free(cl->nodes6);
314 }
315
316 tr_free(closure);
317 tr_logAddNamedDbg("DHT", "Finished bootstrapping");
318 }
319
tr_dhtInit(tr_session * ss)320 int tr_dhtInit(tr_session* ss)
321 {
322 tr_variant benc;
323 int rc;
324 bool have_id = false;
325 char* dat_file;
326 uint8_t* nodes = NULL;
327 uint8_t* nodes6 = NULL;
328 uint8_t const* raw;
329 size_t len;
330 size_t len6;
331 struct bootstrap_closure* cl;
332
333 if (session != NULL) /* already initialized */
334 {
335 return -1;
336 }
337
338 tr_logAddNamedDbg("DHT", "Initializing DHT");
339
340 if (tr_env_key_exists("TR_DHT_VERBOSE"))
341 {
342 dht_debug = stderr;
343 }
344
345 dat_file = tr_buildPath(ss->configDir, "dht.dat", NULL);
346 rc = tr_variantFromFile(&benc, TR_VARIANT_FMT_BENC, dat_file, NULL) ? 0 : -1;
347 tr_free(dat_file);
348
349 if (rc == 0)
350 {
351 have_id = tr_variantDictFindRaw(&benc, TR_KEY_id, &raw, &len);
352
353 if (have_id && len == 20)
354 {
355 memcpy(myid, raw, len);
356 }
357
358 if (ss->udp_socket != TR_BAD_SOCKET && tr_variantDictFindRaw(&benc, TR_KEY_nodes, &raw, &len) && len % 6 == 0)
359 {
360 nodes = tr_memdup(raw, len);
361 }
362
363 if (ss->udp6_socket != TR_BAD_SOCKET && tr_variantDictFindRaw(&benc, TR_KEY_nodes6, &raw, &len6) && len6 % 18 == 0)
364 {
365 nodes6 = tr_memdup(raw, len6);
366 }
367
368 tr_variantFree(&benc);
369 }
370
371 if (nodes == NULL)
372 {
373 len = 0;
374 }
375
376 if (nodes6 == NULL)
377 {
378 len6 = 0;
379 }
380
381 if (have_id)
382 {
383 tr_logAddNamedInfo("DHT", "Reusing old id");
384 }
385 else
386 {
387 /* Note that DHT ids need to be distributed uniformly,
388 * so it should be something truly random. */
389 tr_logAddNamedInfo("DHT", "Generating new id");
390 tr_rand_buffer(myid, 20);
391 }
392
393 rc = dht_init(ss->udp_socket, ss->udp6_socket, myid, NULL);
394
395 if (rc < 0)
396 {
397 goto fail;
398 }
399
400 session = ss;
401
402 cl = tr_new(struct bootstrap_closure, 1);
403 cl->session = session;
404 cl->nodes = nodes;
405 cl->nodes6 = nodes6;
406 cl->len = len;
407 cl->len6 = len6;
408 tr_threadNew(dht_bootstrap, cl);
409
410 dht_timer = evtimer_new(session->event_base, timer_callback, session);
411 tr_timerAdd(dht_timer, 0, tr_rand_int_weak(1000000));
412
413 tr_logAddNamedDbg("DHT", "DHT initialized");
414
415 return 1;
416
417 fail:
418 tr_free(nodes6);
419 tr_free(nodes);
420
421 tr_logAddNamedDbg("DHT", "DHT initialization failed (errno = %d)", errno);
422 session = NULL;
423 return -1;
424 }
425
tr_dhtUninit(tr_session * ss)426 void tr_dhtUninit(tr_session* ss)
427 {
428 if (session != ss)
429 {
430 return;
431 }
432
433 tr_logAddNamedDbg("DHT", "Uninitializing DHT");
434
435 if (dht_timer != NULL)
436 {
437 event_free(dht_timer);
438 dht_timer = NULL;
439 }
440
441 /* Since we only save known good nodes, avoid erasing older data if we
442 don't know enough nodes. */
443 if (tr_dhtStatus(ss, AF_INET, NULL) < TR_DHT_FIREWALLED && tr_dhtStatus(ss, AF_INET6, NULL) < TR_DHT_FIREWALLED)
444 {
445 tr_logAddNamedInfo("DHT", "Not saving nodes, DHT not ready");
446 }
447 else
448 {
449 tr_variant benc;
450 struct sockaddr_in sins[300];
451 struct sockaddr_in6 sins6[300];
452 char compact[300 * 6];
453 char compact6[300 * 18];
454 char* dat_file;
455 int num = 300;
456 int num6 = 300;
457 int n = dht_get_nodes(sins, &num, sins6, &num6);
458
459 tr_logAddNamedInfo("DHT", "Saving %d (%d + %d) nodes", n, num, num6);
460
461 for (int i = 0, j = 0; i < num; ++i, j += 6)
462 {
463 memcpy(compact + j, &sins[i].sin_addr, 4);
464 memcpy(compact + j + 4, &sins[i].sin_port, 2);
465 }
466
467 for (int i = 0, j = 0; i < num6; ++i, j += 18)
468 {
469 memcpy(compact6 + j, &sins6[i].sin6_addr, 16);
470 memcpy(compact6 + j + 16, &sins6[i].sin6_port, 2);
471 }
472
473 tr_variantInitDict(&benc, 3);
474 tr_variantDictAddRaw(&benc, TR_KEY_id, myid, 20);
475
476 if (num > 0)
477 {
478 tr_variantDictAddRaw(&benc, TR_KEY_nodes, compact, num * 6);
479 }
480
481 if (num6 > 0)
482 {
483 tr_variantDictAddRaw(&benc, TR_KEY_nodes6, compact6, num6 * 18);
484 }
485
486 dat_file = tr_buildPath(ss->configDir, "dht.dat", NULL);
487 tr_variantToFile(&benc, TR_VARIANT_FMT_BENC, dat_file);
488 tr_variantFree(&benc);
489 tr_free(dat_file);
490 }
491
492 dht_uninit();
493 tr_logAddNamedDbg("DHT", "Done uninitializing DHT");
494
495 session = NULL;
496 }
497
tr_dhtEnabled(tr_session const * ss)498 bool tr_dhtEnabled(tr_session const* ss)
499 {
500 return ss != NULL && ss == session;
501 }
502
503 struct getstatus_closure
504 {
505 int af;
506 sig_atomic_t status;
507 sig_atomic_t count;
508 };
509
getstatus(void * cl)510 static void getstatus(void* cl)
511 {
512 struct getstatus_closure* closure = cl;
513 int good;
514 int dubious;
515 int incoming;
516
517 dht_nodes(closure->af, &good, &dubious, NULL, &incoming);
518
519 closure->count = good + dubious;
520
521 if (good < 4 || good + dubious <= 8)
522 {
523 closure->status = TR_DHT_BROKEN;
524 }
525 else if (good < 40)
526 {
527 closure->status = TR_DHT_POOR;
528 }
529 else if (incoming < 8)
530 {
531 closure->status = TR_DHT_FIREWALLED;
532 }
533 else
534 {
535 closure->status = TR_DHT_GOOD;
536 }
537 }
538
tr_dhtStatus(tr_session * session,int af,int * nodes_return)539 int tr_dhtStatus(tr_session* session, int af, int* nodes_return)
540 {
541 struct getstatus_closure closure = { .af = af, .status = -1, .count = -1 };
542
543 if (!tr_dhtEnabled(session) || (af == AF_INET && session->udp_socket == TR_BAD_SOCKET) ||
544 (af == AF_INET6 && session->udp6_socket == TR_BAD_SOCKET))
545 {
546 if (nodes_return != NULL)
547 {
548 *nodes_return = 0;
549 }
550
551 return TR_DHT_STOPPED;
552 }
553
554 tr_runInEventThread(session, getstatus, &closure);
555
556 while (closure.status < 0)
557 {
558 tr_wait_msec(50 /*msec*/);
559 }
560
561 if (nodes_return != NULL)
562 {
563 *nodes_return = closure.count;
564 }
565
566 return closure.status;
567 }
568
tr_dhtPort(tr_session * ss)569 tr_port tr_dhtPort(tr_session* ss)
570 {
571 return tr_dhtEnabled(ss) ? ss->udp_port : 0;
572 }
573
tr_dhtAddNode(tr_session * ss,tr_address const * address,tr_port port,bool bootstrap)574 bool tr_dhtAddNode(tr_session* ss, tr_address const* address, tr_port port, bool bootstrap)
575 {
576 int af = address->type == TR_AF_INET ? AF_INET : AF_INET6;
577
578 if (!tr_dhtEnabled(ss))
579 {
580 return false;
581 }
582
583 /* Since we don't want to abuse our bootstrap nodes,
584 * we don't ping them if the DHT is in a good state. */
585
586 if (bootstrap)
587 {
588 if (tr_dhtStatus(ss, af, NULL) >= TR_DHT_FIREWALLED)
589 {
590 return false;
591 }
592 }
593
594 if (address->type == TR_AF_INET)
595 {
596 struct sockaddr_in sin;
597 memset(&sin, 0, sizeof(sin));
598 sin.sin_family = AF_INET;
599 memcpy(&sin.sin_addr, &address->addr.addr4, 4);
600 sin.sin_port = htons(port);
601 dht_ping_node((struct sockaddr*)&sin, sizeof(sin));
602 return true;
603 }
604 else if (address->type == TR_AF_INET6)
605 {
606 struct sockaddr_in6 sin6;
607 memset(&sin6, 0, sizeof(sin6));
608 sin6.sin6_family = AF_INET6;
609 memcpy(&sin6.sin6_addr, &address->addr.addr6, 16);
610 sin6.sin6_port = htons(port);
611 dht_ping_node((struct sockaddr*)&sin6, sizeof(sin6));
612 return true;
613 }
614
615 return false;
616 }
617
tr_dhtPrintableStatus(int status)618 char const* tr_dhtPrintableStatus(int status)
619 {
620 switch (status)
621 {
622 case TR_DHT_STOPPED:
623 return "stopped";
624
625 case TR_DHT_BROKEN:
626 return "broken";
627
628 case TR_DHT_POOR:
629 return "poor";
630
631 case TR_DHT_FIREWALLED:
632 return "firewalled";
633
634 case TR_DHT_GOOD:
635 return "good";
636
637 default:
638 return "???";
639 }
640 }
641
callback(void * ignore UNUSED,int event,unsigned char const * info_hash,void const * data,size_t data_len)642 static void callback(void* ignore UNUSED, int event, unsigned char const* info_hash, void const* data, size_t data_len)
643 {
644 if (event == DHT_EVENT_VALUES || event == DHT_EVENT_VALUES6)
645 {
646 tr_torrent* tor;
647 tr_sessionLock(session);
648 tor = tr_torrentFindFromHash(session, info_hash);
649
650 if (tor != NULL && tr_torrentAllowsDHT(tor))
651 {
652 size_t n;
653 tr_pex* pex;
654
655 if (event == DHT_EVENT_VALUES)
656 {
657 pex = tr_peerMgrCompactToPex(data, data_len, NULL, 0, &n);
658 }
659 else
660 {
661 pex = tr_peerMgrCompact6ToPex(data, data_len, NULL, 0, &n);
662 }
663
664 for (size_t i = 0; i < n; ++i)
665 {
666 tr_peerMgrAddPex(tor, TR_PEER_FROM_DHT, pex + i, -1);
667 }
668
669 tr_free(pex);
670 tr_logAddTorDbg(tor, "Learned %d %s peers from DHT", (int)n, event == DHT_EVENT_VALUES6 ? "IPv6" : "IPv4");
671 }
672
673 tr_sessionUnlock(session);
674 }
675 else if (event == DHT_EVENT_SEARCH_DONE || event == DHT_EVENT_SEARCH_DONE6)
676 {
677 tr_torrent* tor = tr_torrentFindFromHash(session, info_hash);
678
679 if (tor != NULL)
680 {
681 if (event == DHT_EVENT_SEARCH_DONE)
682 {
683 tr_logAddTorInfo(tor, "%s", "IPv4 DHT announce done");
684 tor->dhtAnnounceInProgress = false;
685 }
686 else
687 {
688 tr_logAddTorInfo(tor, "%s", "IPv6 DHT announce done");
689 tor->dhtAnnounce6InProgress = false;
690 }
691 }
692 }
693 }
694
tr_dhtAnnounce(tr_torrent * tor,int af,bool announce)695 static int tr_dhtAnnounce(tr_torrent* tor, int af, bool announce)
696 {
697 int rc;
698 int status;
699 int numnodes;
700 int ret = 0;
701
702 if (!tr_torrentAllowsDHT(tor))
703 {
704 return -1;
705 }
706
707 status = tr_dhtStatus(tor->session, af, &numnodes);
708
709 if (status == TR_DHT_STOPPED)
710 {
711 /* Let the caller believe everything is all right. */
712 return 1;
713 }
714
715 if (status >= TR_DHT_POOR)
716 {
717 rc = dht_search(tor->info.hash, announce ? tr_sessionGetPeerPort(session) : 0, af, callback, NULL);
718
719 if (rc >= 0)
720 {
721 tr_logAddTorInfo(tor, "Starting %s DHT announce (%s, %d nodes)", af == AF_INET6 ? "IPv6" : "IPv4",
722 tr_dhtPrintableStatus(status), numnodes);
723
724 if (af == AF_INET)
725 {
726 tor->dhtAnnounceInProgress = true;
727 }
728 else
729 {
730 tor->dhtAnnounce6InProgress = true;
731 }
732
733 ret = 1;
734 }
735 else
736 {
737 tr_logAddTorErr(tor, "%s DHT announce failed (%s, %d nodes): %s", af == AF_INET6 ? "IPv6" : "IPv4",
738 tr_dhtPrintableStatus(status), numnodes, tr_strerror(errno));
739 }
740 }
741 else
742 {
743 tr_logAddTorDbg(tor, "%s DHT not ready (%s, %d nodes)", af == AF_INET6 ? "IPv6" : "IPv4", tr_dhtPrintableStatus(status),
744 numnodes);
745 }
746
747 return ret;
748 }
749
tr_dhtUpkeep(tr_session * session)750 void tr_dhtUpkeep(tr_session* session)
751 {
752 tr_torrent* tor = NULL;
753 time_t const now = tr_time();
754
755 while ((tor = tr_torrentNext(session, tor)) != NULL)
756 {
757 if (!tor->isRunning || !tr_torrentAllowsDHT(tor))
758 {
759 continue;
760 }
761
762 if (tor->dhtAnnounceAt <= now)
763 {
764 int const rc = tr_dhtAnnounce(tor, AF_INET, true);
765
766 tor->dhtAnnounceAt = now + ((rc == 0) ? 5 + tr_rand_int_weak(5) : 25 * 60 + tr_rand_int_weak(3 * 60));
767 }
768
769 if (tor->dhtAnnounce6At <= now)
770 {
771 int const rc = tr_dhtAnnounce(tor, AF_INET6, true);
772
773 tor->dhtAnnounce6At = now + ((rc == 0) ? 5 + tr_rand_int_weak(5) : 25 * 60 + tr_rand_int_weak(3 * 60));
774 }
775 }
776 }
777
tr_dhtCallback(unsigned char * buf,int buflen,struct sockaddr * from,socklen_t fromlen,void * sv)778 void tr_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, socklen_t fromlen, void* sv)
779 {
780 TR_ASSERT(tr_isSession(sv));
781
782 if (sv != session)
783 {
784 return;
785 }
786
787 time_t tosleep;
788 int rc = dht_periodic(buf, buflen, from, fromlen, &tosleep, callback, NULL);
789
790 if (rc < 0)
791 {
792 if (errno == EINTR)
793 {
794 tosleep = 0;
795 }
796 else
797 {
798 tr_logAddNamedError("DHT", "dht_periodic failed: %s", tr_strerror(errno));
799
800 if (errno == EINVAL || errno == EFAULT)
801 {
802 abort();
803 }
804
805 tosleep = 1;
806 }
807 }
808
809 /* Being slightly late is fine,
810 and has the added benefit of adding some jitter. */
811 tr_timerAdd(dht_timer, tosleep, tr_rand_int_weak(1000000));
812 }
813
timer_callback(evutil_socket_t s UNUSED,short type UNUSED,void * session)814 static void timer_callback(evutil_socket_t s UNUSED, short type UNUSED, void* session)
815 {
816 tr_dhtCallback(NULL, 0, NULL, 0, session);
817 }
818
819 /* This function should return true when a node is blacklisted. We do
820 not support using a blacklist with the DHT in Transmission, since
821 massive (ab)use of this feature could harm the DHT. However, feel
822 free to add support to your private copy as long as you don't
823 redistribute it. */
824
dht_blacklisted(struct sockaddr const * sa UNUSED,int salen UNUSED)825 int dht_blacklisted(struct sockaddr const* sa UNUSED, int salen UNUSED)
826 {
827 return 0;
828 }
829
dht_hash(void * hash_return,int hash_size,void const * v1,int len1,void const * v2,int len2,void const * v3,int len3)830 void dht_hash(void* hash_return, int hash_size, void const* v1, int len1, void const* v2, int len2, void const* v3, int len3)
831 {
832 unsigned char sha1[SHA_DIGEST_LENGTH];
833 tr_sha1(sha1, v1, len1, v2, len2, v3, len3, NULL);
834 memset(hash_return, 0, hash_size);
835 memcpy(hash_return, sha1, MIN(hash_size, SHA_DIGEST_LENGTH));
836 }
837
dht_random_bytes(void * buf,size_t size)838 int dht_random_bytes(void* buf, size_t size)
839 {
840 tr_rand_buffer(buf, size);
841 return size;
842 }
843
dht_sendto(int sockfd,void const * buf,int len,int flags,struct sockaddr const * to,int tolen)844 int dht_sendto(int sockfd, void const* buf, int len, int flags, struct sockaddr const* to, int tolen)
845 {
846 return sendto(sockfd, buf, len, flags, to, tolen);
847 }
848
849 #if defined(_WIN32) && !defined(__MINGW32__)
850
dht_gettimeofday(struct timeval * tv,struct timezone * tz)851 int dht_gettimeofday(struct timeval* tv, struct timezone* tz)
852 {
853 TR_ASSERT(tz == NULL);
854
855 return tr_gettimeofday(tv);
856 }
857
858 #endif
859