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