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 static 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 static 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];
357 arc4random_buf(id, sizeof id);
358 make_tid(ttid, "fn", 0);
359 debugf("Sending find_node.\n");
360 return send_find_node((struct sockaddr *)&ss, sslen, ttid, 4, id, want);
365 newSock(const char *host, const char *port)
367 struct addrinfo hints;
368 memset(&hints, 0, sizeof(hints));
369 hints.ai_family = AF_UNSPEC;
370 hints.ai_socktype = SOCK_DGRAM;
371 struct addrinfo *res = NULL;
372 int err = getaddrinfo(host, port, &hints, &res);
374 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
377 int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
382 if (bind(sock, res->ai_addr, res->ai_addrlen) != 0) {
386 int rc = fcntl(sock, F_GETFL, 0);
391 rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
401 main(int argc, char **argv)
405 char *ipv4addr = NULL;
406 char *ipv6addr = NULL;
410 opt = getopt(argc, argv, "q4:6:");
419 ipv4addr = strdup(optarg);
422 ipv6addr = strdup(optarg);
434 const char *ourPort = strdup(argv[i++]);
435 if (ipv4addr != NULL) {
436 dht_socket = newSock(ipv4addr, ourPort);
438 if (ipv6addr != NULL) {
439 dht_socket6 = newSock(ipv6addr, ourPort);
442 arc4random_buf(myid, sizeof myid);
444 memcpy(my_v, "1:v4:JB\0\0", 9);
451 unsigned char ttid[4];
454 struct addrinfo hints, *info, *infop;
455 memset(&hints, 0, sizeof(hints));
456 hints.ai_socktype = SOCK_DGRAM;
459 hints.ai_family = AF_INET6;
460 else if (dht_socket6 < 0)
461 hints.ai_family |= AF_INET;
462 rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
464 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc));
474 make_tid(ttid, "pn", 0);
475 debugf("Sending ping.\n");
476 send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4);
477 infop = infop->ai_next;
484 token_bucket_time = time(NULL);
485 token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
487 struct pollfd fds[2];
488 fds[0].fd = dht_socket;
489 fds[0].events = POLLIN;
490 fds[1].fd = dht_socket6;
491 fds[1].events = POLLIN;
495 if ((dht_socket >= 0 && list_elements(&v4_confirmed) <= 16) ||
496 (dht_socket6 >= 0 && list_elements(&v6_confirmed) <= 16))
499 tv_sec = random() % 30;
500 int tv_msec = random() % 1000;
505 list_elements(&v4_confirmed),
506 list_elements(&v6_confirmed),
507 list_elements(&v4_new),
508 list_elements(&v6_new));
510 rc = poll(fds, 2, tv_sec * 1000 + tv_msec);
518 unsigned char tid[16], id[20], info_hash[20], target[20];
519 unsigned char buf[1536], nodes[256], nodes6[1024], token[128];
520 int tid_len = 16, token_len = 128;
521 int nodes_len = 256, nodes6_len = 1024;
523 unsigned char values[2048], values6[2048];
524 int values_len = 2048, values6_len = 2048;
526 struct sockaddr_storage source_storage;
527 struct sockaddr *source = (struct sockaddr *)&source_storage;
528 socklen_t sourcelen = sizeof(source_storage);
529 if (fds[0].revents != 0) {
530 if ((fds[0].revents & (POLLERR | POLLNVAL)) > 0) {
531 fprintf(stderr, "error in fds[0]");
534 rc = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
536 } else if (fds[1].revents != 0) {
537 if ((fds[1].revents & (POLLERR | POLLNVAL)) > 0) {
538 fprintf(stderr, "error in fds[1]");
541 rc = recvfrom(dht_socket6, buf, 1536, 0, source, &sourcelen);
545 if (rc < 0 || sourcelen > sizeof(struct sockaddr_storage))
548 if (is_martian(source))
551 /* There's a bug in parse_message -- it will happily overflow the
552 buffer if it's not NUL-terminated. For now, put a NUL at the
558 debugf("Overlong message.\n");
562 message = parse_message(
583 if (id_cmp(id, myid) == 0) {
584 debugf("Received message from self.\n");
588 if (message > REPLY) {
589 /* Rate limit requests. */
590 if (!token_bucket()) {
591 debugf("Dropping request due to rate limiting.\n");
599 debugf("Broken node truncates transaction ids.\n");
602 if (tid_match(tid, "pn", NULL)) {
604 new_node(id, source, sourcelen, 2);
605 } else if (tid_match(tid, "fn", NULL)) {
606 debugf("Nodes found!\n");
607 if (nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
608 debugf("Unexpected length for node info!\n");
610 new_node(id, source, sourcelen, 2);
611 for (i = 0; i < nodes_len / 26; i++) {
612 unsigned char *ni = nodes + i * 26;
613 struct sockaddr_in sin;
614 if (id_cmp(ni, myid) == 0)
616 memset(&sin, 0, sizeof(sin));
617 sin.sin_family = AF_INET;
618 memcpy(&sin.sin_addr, ni + 20, 4);
619 memcpy(&sin.sin_port, ni + 24, 2);
620 new_node(ni, (struct sockaddr *)&sin, sizeof(sin), 0);
622 for (i = 0; i < nodes6_len / 38; i++) {
623 unsigned char *ni = nodes6 + i * 38;
624 struct sockaddr_in6 sin6;
625 if (id_cmp(ni, myid) == 0)
627 memset(&sin6, 0, sizeof(sin6));
628 sin6.sin6_family = AF_INET6;
629 memcpy(&sin6.sin6_addr, ni + 20, 16);
630 memcpy(&sin6.sin6_port, ni + 36, 2);
631 new_node(ni, (struct sockaddr *)&sin6, sizeof(sin6), 0);
635 debugf("Unexpected reply!\n");
640 debugf("Ping (%d)!\n", tid_len);
641 new_node(id, source, sourcelen, 1);
642 debugf("Sending pong.\n");
643 send_pong(source, sourcelen, tid, tid_len);
648 if (message == FIND_NODE)
649 debugf("Find node!\n");
651 debugf("Get peers!\n");
652 new_node(id, source, sourcelen, 1);
653 debugf("Sending nodes (%d).\n", want);
654 send_random_nodes(source, sourcelen, tid, tid_len, target, want);
657 debugf("Announce peer!\n");
664 "This node doesn't accept announces");
671 /* We need to be careful to avoid a positive feedback loop. Make
672 sure we send at most one packet each time through the select
677 else if (dht_socket < 0)
680 send4 = random() % 2;
683 int want = dht_socket6 >= 0 && list_free(&v6_new) > 8 ? (WANT4 | WANT6) : 0;
684 if (!list_empty(&v4_new))
685 send_request(&v4_new, 1, list_free(&v4_new) < 8, want);
686 else if (!list_empty(&v4_confirmed))
687 send_request(&v4_confirmed, 0, 0, want);
689 int want = dht_socket >= 0 && list_free(&v4_new) > 8 ? (WANT4 | WANT6) : 0;
690 if (!list_empty(&v6_new))
691 send_request(&v6_new, 1, list_free(&v6_new) < 8, want);
692 else if (!list_empty(&v6_confirmed))
693 send_request(&v6_confirmed, 0, 0, want);
698 fprintf(stderr, "dht-bootstrap [-q] [-4 ADDR4] [-6 ADDR6] port [node port...]\n");
702 /* We could use a proper bencoding printer and parser, but the format of
703 DHT messages is fairly stylised, so this seemed simpler. */
705 #define CHECK(offset, delta, size) \
706 if (delta < 0 || offset + delta > size) \
709 #define INC(offset, delta, size) \
710 CHECK(offset, delta, size); \
713 #define COPY(buf, offset, src, delta, size) \
714 CHECK(offset, delta, size); \
715 memcpy(buf + offset, src, delta); \
718 #define ADD_V(buf, offset, size) \
720 COPY(buf, offset, my_v, sizeof(my_v), size); \
724 dht_send(const void *buf, size_t len, int flags, const struct sockaddr *sa, int salen)
731 if (sa->sa_family == AF_INET)
733 else if (sa->sa_family == AF_INET6)
739 errno = EAFNOSUPPORT;
743 return sendto(s, buf, len, flags, sa, salen);
747 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
751 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
753 COPY(buf, i, myid, 20, 512);
754 rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
756 COPY(buf, i, tid, tid_len, 512);
758 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
760 return dht_send(buf, i, 0, sa, salen);
768 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
772 rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:");
774 COPY(buf, i, myid, 20, 512);
775 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
777 COPY(buf, i, tid, tid_len, 512);
779 rc = snprintf(buf + i, 512 - i, "1:y1:re");
781 return dht_send(buf, i, 0, sa, salen);
792 const unsigned char *tid,
794 const unsigned char *target,
799 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
801 COPY(buf, i, myid, 20, 512);
802 rc = snprintf(buf + i, 512 - i, "6:target20:");
804 COPY(buf, i, target, 20, 512);
810 (want & WANT4) ? "2:n4" : "",
811 (want & WANT6) ? "2:n6" : "");
814 rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
816 COPY(buf, i, tid, tid_len, 512);
818 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
820 return dht_send(buf, i, 0, sa, salen);
831 const unsigned char *tid,
833 const unsigned char *nodes,
835 const unsigned char *nodes6,
841 rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:");
843 COPY(buf, i, myid, 20, 2048);
845 rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
847 COPY(buf, i, nodes, nodes_len, 2048);
849 if (nodes6_len > 0) {
850 rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
852 COPY(buf, i, nodes6, nodes6_len, 2048);
855 rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len);
857 COPY(buf, i, tid, tid_len, 2048);
859 rc = snprintf(buf + i, 2048 - i, "1:y1:re");
862 return dht_send(buf, i, 0, sa, salen);
870 buffer_random_nodes(int af, unsigned char *nodes)
872 struct circular_list *list;
873 struct sockaddr_storage ss;
875 unsigned char id[20];
881 list = &v4_confirmed;
884 list = &v6_confirmed;
892 rc = list_random(list, id, &ss, &sslen);
897 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
898 memcpy(nodes + n * 26, id, 20);
899 memcpy(nodes + n * 26 + 20, &sin->sin_addr, 4);
900 memcpy(nodes + n * 26 + 24, &sin->sin_port, 2);
905 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
906 memcpy(nodes + n * 38, id, 20);
907 memcpy(nodes + n * 38 + 20, &sin6->sin6_addr, 16);
908 memcpy(nodes + n * 38 + 36, &sin6->sin6_port, 2);
923 const unsigned char *tid,
925 const unsigned char *id,
928 unsigned char nodes[8 * 26];
929 unsigned char nodes6[8 * 38];
930 int numnodes = 0, numnodes6 = 0;
933 want = sa->sa_family == AF_INET ? WANT4 : WANT6;
936 numnodes = buffer_random_nodes(AF_INET, nodes);
939 numnodes6 = buffer_random_nodes(AF_INET6, nodes6);
942 sa, salen, tid, tid_len, nodes, numnodes * 26, nodes6, numnodes6 * 38);
957 rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, (int)strlen(message));
959 COPY(buf, i, message, (int)strlen(message), 512);
960 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
962 COPY(buf, i, tid, tid_len, 512);
964 rc = snprintf(buf + i, 512 - i, "1:y1:ee");
966 return dht_send(buf, i, 0, sa, salen);
980 const unsigned char *buf,
982 unsigned char *tid_return,
984 unsigned char *id_return,
985 unsigned char *info_hash_return,
986 unsigned char *target_return,
987 unsigned short *port_return,
988 unsigned char *token_return,
990 unsigned char *nodes_return,
992 unsigned char *nodes6_return,
994 unsigned char *values_return,
996 unsigned char *values6_return,
1000 const unsigned char *p;
1002 /* This code will happily crash if the buffer is not NUL-terminated. */
1003 if (buf[buflen] != '\0') {
1004 debugf("Eek! parse_message with unterminated buffer.\n");
1008 #define CHECK(ptr, len) \
1009 if (((unsigned char *)ptr) + (len) > (buf) + (buflen)) \
1013 p = memmem(buf, buflen, "1:t", 3);
1017 l = strtol((char *)p + 3, &q, 10);
1018 if (q && *q == ':' && l > 0 && l < *tid_len) {
1020 memcpy(tid_return, q + 1, l);
1027 p = memmem(buf, buflen, "2:id20:", 7);
1030 memcpy(id_return, p + 7, 20);
1032 memset(id_return, 0, 20);
1035 if (info_hash_return) {
1036 p = memmem(buf, buflen, "9:info_hash20:", 14);
1039 memcpy(info_hash_return, p + 14, 20);
1041 memset(info_hash_return, 0, 20);
1045 p = memmem(buf, buflen, "porti", 5);
1049 l = strtol((char *)p + 5, &q, 10);
1050 if (q && *q == 'e' && l > 0 && l < 0x10000)
1057 if (target_return) {
1058 p = memmem(buf, buflen, "6:target20:", 11);
1061 memcpy(target_return, p + 11, 20);
1063 memset(target_return, 0, 20);
1067 p = memmem(buf, buflen, "5:token", 7);
1071 l = strtol((char *)p + 7, &q, 10);
1072 if (q && *q == ':' && l > 0 && l < *token_len) {
1074 memcpy(token_return, q + 1, l);
1083 p = memmem(buf, buflen, "5:nodes", 7);
1087 l = strtol((char *)p + 7, &q, 10);
1088 if (q && *q == ':' && l > 0 && l < *nodes_len) {
1090 memcpy(nodes_return, q + 1, l);
1099 p = memmem(buf, buflen, "6:nodes6", 8);
1103 l = strtol((char *)p + 8, &q, 10);
1104 if (q && *q == ':' && l > 0 && l < *nodes6_len) {
1106 memcpy(nodes6_return, q + 1, l);
1114 if (values_len || values6_len) {
1115 p = memmem(buf, buflen, "6:valuesl", 9);
1117 int i = p - buf + 9;
1122 l = strtol((char *)buf + i, &q, 10);
1123 if (q && *q == ':' && l > 0) {
1126 if (j + l > *values_len)
1128 i = q + 1 + l - (char *)buf;
1129 memcpy((char *)values_return + j, q + 1, l);
1131 } else if (l == 18) {
1132 if (j6 + l > *values6_len)
1134 i = q + 1 + l - (char *)buf;
1135 memcpy((char *)values6_return + j6, q + 1, l);
1138 debugf("Received weird value -- %d bytes.\n", (int)l);
1139 i = q + 1 + l - (char *)buf;
1145 if (i >= buflen || buf[i] != 'e')
1146 debugf("eek... unexpected end for values.\n");
1158 p = memmem(buf, buflen, "4:wantl", 7);
1160 int i = p - buf + 7;
1162 while (buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' &&
1163 i + 2 + buf[i] - '0' < buflen) {
1164 CHECK(buf + i + 2, buf[i] - '0');
1165 if (buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0)
1166 *want_return |= WANT4;
1167 else if (buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0)
1168 *want_return |= WANT6;
1170 debugf("eek... unexpected want flag (%c)\n", buf[i]);
1171 i += 2 + buf[i] - '0';
1173 if (i >= buflen || buf[i] != 'e')
1174 debugf("eek... unexpected end for want.\n");
1182 if (memmem(buf, buflen, "1:y1:r", 6))
1184 if (memmem(buf, buflen, "1:y1:e", 6))
1186 if (!memmem(buf, buflen, "1:y1:q", 6))
1188 if (memmem(buf, buflen, "1:q4:ping", 9))
1190 if (memmem(buf, buflen, "1:q9:find_node", 14))
1192 if (memmem(buf, buflen, "1:q9:get_peers", 14))
1194 if (memmem(buf, buflen, "1:q13:announce_peer", 19))
1195 return ANNOUNCE_PEER;
1199 debugf("Truncated message.\n");