2 Copyright (c) 2009-2011 by Juliusz Chroboczek
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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
26 #include <netinet/in.h>
32 #include <sys/socket.h>
36 #define MIN(x, y) ((x) <= (y) ? (x) : (y))
39 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len);
41 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len);
46 const unsigned char *tid,
48 const unsigned char *target,
54 const unsigned char *tid,
56 const unsigned char *nodes,
58 const unsigned char *nodes6,
64 const unsigned char *tid,
66 const unsigned char *id,
82 #define ANNOUNCE_PEER 5
89 const unsigned char *buf,
91 unsigned char *tid_return,
93 unsigned char *id_return,
94 unsigned char *info_hash_return,
95 unsigned char *target_return,
96 unsigned short *port_return,
97 unsigned char *token_return,
99 unsigned char *nodes_return,
101 unsigned char *nodes6_return,
103 unsigned char *values_return,
105 unsigned char *values6_return,
109 static const unsigned char zeroes[20] = {0};
110 static const unsigned char v4prefix[16] =
111 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
113 static unsigned char myid[20];
114 static int have_v = 0;
115 static unsigned char my_v[9];
117 static int dht_socket = -1;
118 static int dht_socket6 = -1;
121 unsigned char id[160];
122 struct sockaddr_storage ss;
126 #define CIRCULAR_LIST_SIZE 256
128 struct circular_list {
131 struct node nodes[CIRCULAR_LIST_SIZE];
134 struct circular_list v4_new, v6_new, v4_confirmed, v6_confirmed;
136 #define MAX_TOKEN_BUCKET_TOKENS 40
137 static time_t token_bucket_time;
138 static int token_bucket_tokens;
140 FILE *dht_debug = NULL;
143 __attribute__((format(printf, 1, 2)))
146 debugf(const char *format, ...)
149 va_start(args, format);
151 vfprintf(dht_debug, format, args);
157 is_martian(struct sockaddr *sa)
159 switch (sa->sa_family) {
161 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
162 const unsigned char *address = (const unsigned char *)&sin->sin_addr;
163 return sin->sin_port == 0 || (address[0] == 0) || (address[0] == 127) ||
164 ((address[0] & 0xE0) == 0xE0);
167 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
168 const unsigned char *address = (const unsigned char *)&sin6->sin6_addr;
169 return sin6->sin6_port == 0 || (address[0] == 0xFF) ||
170 (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
171 (memcmp(address, zeroes, 15) == 0 &&
172 (address[15] == 0 || address[15] == 1)) ||
173 (memcmp(address, v4prefix, 12) == 0);
181 /* Forget about the ``XOR-metric''. An id is just a path from the
182 root of the tree, so bits are numbered from the start. */
185 id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2)
187 /* Memcmp is guaranteed to perform an unsigned comparison. */
188 return memcmp(id1, id2, 20);
191 /* Our transaction-ids are 4-bytes long, with the first two bytes identi-
192 fying the kind of request, and the remaining two a sequence number in
196 make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno)
198 tid_return[0] = prefix[0] & 0xFF;
199 tid_return[1] = prefix[1] & 0xFF;
200 memcpy(tid_return + 2, &seqno, 2);
204 tid_match(const unsigned char *tid, const char *prefix, unsigned short *seqno_return)
206 if (tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) {
208 memcpy(seqno_return, tid + 2, 2);
215 circular(int from, int to)
219 return x + CIRCULAR_LIST_SIZE;
224 list_elements(struct circular_list *list)
226 return circular(list->head, list->tail);
230 list_empty(struct circular_list *list)
232 return list_elements(list) == 0;
236 list_free(struct circular_list *list)
238 return circular(list->tail + 1, list->head);
242 list_pop(struct circular_list *list, struct sockaddr_storage *ss, socklen_t *sslen)
244 if (list->head == list->tail)
247 memcpy(ss, &list->nodes[list->head].ss, list->nodes[list->head].sslen);
248 *sslen = list->nodes[list->head].sslen;
249 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
255 struct circular_list *list,
257 struct sockaddr_storage *ss,
261 if (list->head == list->tail)
264 n = random() % (list->tail - list->head);
265 n = (list->head + n) % CIRCULAR_LIST_SIZE;
268 memcpy(id, &list->nodes[n].id, 20);
269 memcpy(ss, &list->nodes[n].ss, list->nodes[n].sslen);
270 *sslen = list->nodes[n].sslen;
274 /* We just learnt about a node, not necessarily a new one. Confirm is 1 if
275 the node sent a message, 2 if it sent us a reply. */
278 new_node(unsigned char *id, struct sockaddr *sa, socklen_t salen, int confirm)
280 struct circular_list *list;
283 if (sa->sa_family == AF_INET)
284 list = confirm >= 2 ? &v4_confirmed : &v4_new;
285 else if (sa->sa_family == AF_INET6)
286 list = confirm >= 2 ? &v6_confirmed : &v6_new;
290 /* A node that sends us a request is most probably bootstrapping.
291 We want to avoid getting our tables full of very young nodes -- only
292 include such a node if we have plenty of space. */
294 if (confirm == 1 && list_free(list) < 32)
297 for (i = list->head; i != list->tail; i = (i + 1) % CIRCULAR_LIST_SIZE) {
298 struct node *n = &list->nodes[i];
299 if (n->sslen == salen && memcmp(&n->ss, sa, salen) == 0)
303 memcpy(&list->nodes[list->tail].id, id, 160);
304 memcpy(&list->nodes[list->tail].ss, sa, salen);
305 list->nodes[list->tail].sslen = salen;
306 list->tail = (list->tail + 1) % CIRCULAR_LIST_SIZE;
307 if (list->head == list->tail)
308 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
316 time_t now = time(NULL);
317 if (token_bucket_tokens == 0) {
318 token_bucket_tokens =
319 MIN(MAX_TOKEN_BUCKET_TOKENS, 4 * (now - token_bucket_time));
320 token_bucket_time = now;
323 if (token_bucket_tokens == 0)
326 token_bucket_tokens--;
331 send_request(struct circular_list *list, int dopop, int doping, int want)
333 unsigned char ttid[4];
334 struct sockaddr_storage ss;
338 if (list_empty(list))
342 rc = list_pop(list, &ss, &sslen);
346 rc = list_random(list, NULL, &ss, &sslen);
352 make_tid(ttid, "pn", 0);
353 debugf("Sending ping.\n");
354 return send_ping((struct sockaddr *)&ss, sslen, ttid, 4);
356 unsigned char id[20];
358 for (i = 0; i < 20; i++)
359 id[i] = random() & 0xFF;
360 make_tid(ttid, "fn", 0);
361 debugf("Sending find_node.\n");
362 return send_find_node((struct sockaddr *)&ss, sslen, ttid, 4, id, want);
367 newSock(const char *host, const char *port)
369 struct addrinfo hints;
370 memset(&hints, 0, sizeof(hints));
371 hints.ai_family = AF_UNSPEC;
372 hints.ai_socktype = SOCK_DGRAM;
373 struct addrinfo *res = NULL;
374 int err = getaddrinfo(host, port, &hints, &res);
376 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
379 int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
384 if (bind(sock, res->ai_addr, res->ai_addrlen) != 0) {
388 int rc = fcntl(sock, F_GETFL, 0);
393 rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
403 main(int argc, char **argv)
407 char *ipv4addr = NULL;
408 char *ipv6addr = NULL;
412 opt = getopt(argc, argv, "q4:6:");
421 ipv4addr = strdup(optarg);
424 ipv6addr = strdup(optarg);
436 const char *port = strdup(argv[i++]);
438 if (ipv4addr != NULL) {
439 dht_socket = newSock(ipv4addr, port);
441 if (ipv6addr != NULL) {
442 dht_socket6 = newSock(ipv6addr, port);
447 int fd = open("/dev/urandom", O_RDONLY);
449 perror("open(random)");
453 rc = read(fd, myid, 20);
455 perror("open(random)");
460 rc = read(fd, &seed, sizeof(seed));
466 memcpy(my_v, "1:v4:JB\0\0", 9);
472 unsigned char ttid[4];
475 struct addrinfo hints, *info, *infop;
476 memset(&hints, 0, sizeof(hints));
477 hints.ai_socktype = SOCK_DGRAM;
480 hints.ai_family = AF_INET6;
481 else if (dht_socket6 < 0)
482 hints.ai_family |= AF_INET;
483 rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
485 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc));
495 make_tid(ttid, "pn", 0);
496 debugf("Sending ping.\n");
497 send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4);
498 infop = infop->ai_next;
505 token_bucket_time = time(NULL);
506 token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
508 struct pollfd fds[2];
509 fds[0].fd = dht_socket;
510 fds[0].events = POLLIN;
511 fds[1].fd = dht_socket6;
512 fds[1].events = POLLIN;
516 if ((dht_socket >= 0 && list_elements(&v4_confirmed) <= 16) ||
517 (dht_socket6 >= 0 && list_elements(&v6_confirmed) <= 16))
520 tv_sec = random() % 30;
521 int tv_msec = random() % 1000;
526 list_elements(&v4_confirmed),
527 list_elements(&v6_confirmed),
528 list_elements(&v4_new),
529 list_elements(&v6_new));
531 int rc = poll(fds, 2, tv_sec * 1000 + tv_msec);
541 unsigned char tid[16], id[20], info_hash[20], target[20];
542 unsigned char buf[1536], nodes[256], nodes6[1024], token[128];
543 int tid_len = 16, token_len = 128;
544 int nodes_len = 256, nodes6_len = 1024;
546 unsigned char values[2048], values6[2048];
547 int values_len = 2048, values6_len = 2048;
549 struct sockaddr_storage source_storage;
550 struct sockaddr *source = (struct sockaddr *)&source_storage;
551 socklen_t sourcelen = sizeof(source_storage);
552 if (fds[0].revents != 0) {
553 if ((fds[0].revents & (POLLERR | POLLNVAL)) > 0) {
554 fprintf(stderr, "error in fds[0]");
557 rc = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
559 } else if (fds[1].revents != 0) {
560 if ((fds[1].revents & (POLLERR | POLLNVAL)) > 0) {
561 fprintf(stderr, "error in fds[1]");
564 rc = recvfrom(dht_socket6, buf, 1536, 0, source, &sourcelen);
568 if (rc < 0 || sourcelen > sizeof(struct sockaddr_storage))
571 if (is_martian(source))
574 /* There's a bug in parse_message -- it will happily overflow the
575 buffer if it's not NUL-terminated. For now, put a NUL at the
581 debugf("Overlong message.\n");
585 message = parse_message(
606 if (id_cmp(id, myid) == 0) {
607 debugf("Received message from self.\n");
611 if (message > REPLY) {
612 /* Rate limit requests. */
613 if (!token_bucket()) {
614 debugf("Dropping request due to rate limiting.\n");
622 debugf("Broken node truncates transaction ids.\n");
625 if (tid_match(tid, "pn", NULL)) {
627 new_node(id, source, sourcelen, 2);
628 } else if (tid_match(tid, "fn", NULL)) {
629 debugf("Nodes found!\n");
630 if (nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
631 debugf("Unexpected length for node info!\n");
633 new_node(id, source, sourcelen, 2);
634 for (i = 0; i < nodes_len / 26; i++) {
635 unsigned char *ni = nodes + i * 26;
636 struct sockaddr_in sin;
637 if (id_cmp(ni, myid) == 0)
639 memset(&sin, 0, sizeof(sin));
640 sin.sin_family = AF_INET;
641 memcpy(&sin.sin_addr, ni + 20, 4);
642 memcpy(&sin.sin_port, ni + 24, 2);
643 new_node(ni, (struct sockaddr *)&sin, sizeof(sin), 0);
645 for (i = 0; i < nodes6_len / 38; i++) {
646 unsigned char *ni = nodes6 + i * 38;
647 struct sockaddr_in6 sin6;
648 if (id_cmp(ni, myid) == 0)
650 memset(&sin6, 0, sizeof(sin6));
651 sin6.sin6_family = AF_INET6;
652 memcpy(&sin6.sin6_addr, ni + 20, 16);
653 memcpy(&sin6.sin6_port, ni + 36, 2);
654 new_node(ni, (struct sockaddr *)&sin6, sizeof(sin6), 0);
658 debugf("Unexpected reply!\n");
663 debugf("Ping (%d)!\n", tid_len);
664 new_node(id, source, sourcelen, 1);
665 debugf("Sending pong.\n");
666 send_pong(source, sourcelen, tid, tid_len);
671 if (message == FIND_NODE)
672 debugf("Find node!\n");
674 debugf("Get peers!\n");
675 new_node(id, source, sourcelen, 1);
676 debugf("Sending nodes (%d).\n", want);
677 send_random_nodes(source, sourcelen, tid, tid_len, target, want);
680 debugf("Announce peer!\n");
687 "This node doesn't accept announces");
694 /* We need to be careful to avoid a positive feedback loop. Make
695 sure we send at most one packet each time through the select
700 else if (dht_socket < 0)
703 send4 = random() % 2;
706 int want = dht_socket6 >= 0 && list_free(&v6_new) > 8 ? (WANT4 | WANT6) : 0;
707 if (!list_empty(&v4_new))
708 send_request(&v4_new, 1, list_free(&v4_new) < 8, want);
709 else if (!list_empty(&v4_confirmed))
710 send_request(&v4_confirmed, 0, 0, want);
712 int want = dht_socket >= 0 && list_free(&v4_new) > 8 ? (WANT4 | WANT6) : 0;
713 if (!list_empty(&v6_new))
714 send_request(&v6_new, 1, list_free(&v6_new) < 8, want);
715 else if (!list_empty(&v6_confirmed))
716 send_request(&v6_confirmed, 0, 0, want);
723 fprintf(stderr, "dht-bootstrap [-q] [-4 ADDR4] [-6 ADDR6] port [node port...]\n");
727 /* We could use a proper bencoding printer and parser, but the format of
728 DHT messages is fairly stylised, so this seemed simpler. */
730 #define CHECK(offset, delta, size) \
731 if (delta < 0 || offset + delta > size) \
734 #define INC(offset, delta, size) \
735 CHECK(offset, delta, size); \
738 #define COPY(buf, offset, src, delta, size) \
739 CHECK(offset, delta, size); \
740 memcpy(buf + offset, src, delta); \
743 #define ADD_V(buf, offset, size) \
745 COPY(buf, offset, my_v, sizeof(my_v), size); \
749 dht_send(const void *buf, size_t len, int flags, const struct sockaddr *sa, int salen)
756 if (sa->sa_family == AF_INET)
758 else if (sa->sa_family == AF_INET6)
764 errno = EAFNOSUPPORT;
768 return sendto(s, buf, len, flags, sa, salen);
772 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
776 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
778 COPY(buf, i, myid, 20, 512);
779 rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
781 COPY(buf, i, tid, tid_len, 512);
783 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
785 return dht_send(buf, i, 0, sa, salen);
793 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
797 rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:");
799 COPY(buf, i, myid, 20, 512);
800 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
802 COPY(buf, i, tid, tid_len, 512);
804 rc = snprintf(buf + i, 512 - i, "1:y1:re");
806 return dht_send(buf, i, 0, sa, salen);
817 const unsigned char *tid,
819 const unsigned char *target,
824 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
826 COPY(buf, i, myid, 20, 512);
827 rc = snprintf(buf + i, 512 - i, "6:target20:");
829 COPY(buf, i, target, 20, 512);
835 (want & WANT4) ? "2:n4" : "",
836 (want & WANT6) ? "2:n6" : "");
839 rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
841 COPY(buf, i, tid, tid_len, 512);
843 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
845 return dht_send(buf, i, 0, sa, salen);
856 const unsigned char *tid,
858 const unsigned char *nodes,
860 const unsigned char *nodes6,
866 rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:");
868 COPY(buf, i, myid, 20, 2048);
870 rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
872 COPY(buf, i, nodes, nodes_len, 2048);
874 if (nodes6_len > 0) {
875 rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
877 COPY(buf, i, nodes6, nodes6_len, 2048);
880 rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len);
882 COPY(buf, i, tid, tid_len, 2048);
884 rc = snprintf(buf + i, 2048 - i, "1:y1:re");
887 return dht_send(buf, i, 0, sa, salen);
895 buffer_random_nodes(int af, unsigned char *nodes)
897 struct circular_list *list;
898 struct sockaddr_storage ss;
900 unsigned char id[20];
906 list = &v4_confirmed;
909 list = &v6_confirmed;
917 rc = list_random(list, id, &ss, &sslen);
922 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
923 memcpy(nodes + n * 26, id, 20);
924 memcpy(nodes + n * 26 + 20, &sin->sin_addr, 4);
925 memcpy(nodes + n * 26 + 24, &sin->sin_port, 2);
930 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
931 memcpy(nodes + n * 38, id, 20);
932 memcpy(nodes + n * 38 + 20, &sin6->sin6_addr, 16);
933 memcpy(nodes + n * 38 + 36, &sin6->sin6_port, 2);
948 const unsigned char *tid,
950 const unsigned char *id,
953 unsigned char nodes[8 * 26];
954 unsigned char nodes6[8 * 38];
955 int numnodes = 0, numnodes6 = 0;
958 want = sa->sa_family == AF_INET ? WANT4 : WANT6;
961 numnodes = buffer_random_nodes(AF_INET, nodes);
964 numnodes6 = buffer_random_nodes(AF_INET6, nodes6);
967 sa, salen, tid, tid_len, nodes, numnodes * 26, nodes6, numnodes6 * 38);
982 rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, (int)strlen(message));
984 COPY(buf, i, message, (int)strlen(message), 512);
985 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
987 COPY(buf, i, tid, tid_len, 512);
989 rc = snprintf(buf + i, 512 - i, "1:y1:ee");
991 return dht_send(buf, i, 0, sa, salen);
1005 const unsigned char *buf,
1007 unsigned char *tid_return,
1009 unsigned char *id_return,
1010 unsigned char *info_hash_return,
1011 unsigned char *target_return,
1012 unsigned short *port_return,
1013 unsigned char *token_return,
1015 unsigned char *nodes_return,
1017 unsigned char *nodes6_return,
1019 unsigned char *values_return,
1021 unsigned char *values6_return,
1025 const unsigned char *p;
1027 /* This code will happily crash if the buffer is not NUL-terminated. */
1028 if (buf[buflen] != '\0') {
1029 debugf("Eek! parse_message with unterminated buffer.\n");
1033 #define CHECK(ptr, len) \
1034 if (((unsigned char *)ptr) + (len) > (buf) + (buflen)) \
1038 p = memmem(buf, buflen, "1:t", 3);
1042 l = strtol((char *)p + 3, &q, 10);
1043 if (q && *q == ':' && l > 0 && l < *tid_len) {
1045 memcpy(tid_return, q + 1, l);
1052 p = memmem(buf, buflen, "2:id20:", 7);
1055 memcpy(id_return, p + 7, 20);
1057 memset(id_return, 0, 20);
1060 if (info_hash_return) {
1061 p = memmem(buf, buflen, "9:info_hash20:", 14);
1064 memcpy(info_hash_return, p + 14, 20);
1066 memset(info_hash_return, 0, 20);
1070 p = memmem(buf, buflen, "porti", 5);
1074 l = strtol((char *)p + 5, &q, 10);
1075 if (q && *q == 'e' && l > 0 && l < 0x10000)
1082 if (target_return) {
1083 p = memmem(buf, buflen, "6:target20:", 11);
1086 memcpy(target_return, p + 11, 20);
1088 memset(target_return, 0, 20);
1092 p = memmem(buf, buflen, "5:token", 7);
1096 l = strtol((char *)p + 7, &q, 10);
1097 if (q && *q == ':' && l > 0 && l < *token_len) {
1099 memcpy(token_return, q + 1, l);
1108 p = memmem(buf, buflen, "5:nodes", 7);
1112 l = strtol((char *)p + 7, &q, 10);
1113 if (q && *q == ':' && l > 0 && l < *nodes_len) {
1115 memcpy(nodes_return, q + 1, l);
1124 p = memmem(buf, buflen, "6:nodes6", 8);
1128 l = strtol((char *)p + 8, &q, 10);
1129 if (q && *q == ':' && l > 0 && l < *nodes6_len) {
1131 memcpy(nodes6_return, q + 1, l);
1139 if (values_len || values6_len) {
1140 p = memmem(buf, buflen, "6:valuesl", 9);
1142 int i = p - buf + 9;
1147 l = strtol((char *)buf + i, &q, 10);
1148 if (q && *q == ':' && l > 0) {
1151 if (j + l > *values_len)
1153 i = q + 1 + l - (char *)buf;
1154 memcpy((char *)values_return + j, q + 1, l);
1156 } else if (l == 18) {
1157 if (j6 + l > *values6_len)
1159 i = q + 1 + l - (char *)buf;
1160 memcpy((char *)values6_return + j6, q + 1, l);
1163 debugf("Received weird value -- %d bytes.\n", (int)l);
1164 i = q + 1 + l - (char *)buf;
1170 if (i >= buflen || buf[i] != 'e')
1171 debugf("eek... unexpected end for values.\n");
1183 p = memmem(buf, buflen, "4:wantl", 7);
1185 int i = p - buf + 7;
1187 while (buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' &&
1188 i + 2 + buf[i] - '0' < buflen) {
1189 CHECK(buf + i + 2, buf[i] - '0');
1190 if (buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0)
1191 *want_return |= WANT4;
1192 else if (buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0)
1193 *want_return |= WANT6;
1195 debugf("eek... unexpected want flag (%c)\n", buf[i]);
1196 i += 2 + buf[i] - '0';
1198 if (i >= buflen || buf[i] != 'e')
1199 debugf("eek... unexpected end for want.\n");
1207 if (memmem(buf, buflen, "1:y1:r", 6))
1209 if (memmem(buf, buflen, "1:y1:e", 6))
1211 if (!memmem(buf, buflen, "1:y1:q", 6))
1213 if (memmem(buf, buflen, "1:q4:ping", 9))
1215 if (memmem(buf, buflen, "1:q9:find_node", 14))
1217 if (memmem(buf, buflen, "1:q9:get_peers", 14))
1219 if (memmem(buf, buflen, "1:q13:announce_peer", 19))
1220 return ANNOUNCE_PEER;
1224 debugf("Truncated message.\n");