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
23 #include <arpa/inet.h>
27 #include <netinet/in.h>
32 #include <sys/socket.h>
34 #include <sys/types.h>
38 #define MAX(x, y) ((x) >= (y) ? (x) : (y))
39 #define MIN(x, y) ((x) <= (y) ? (x) : (y))
42 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len);
44 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len);
49 const unsigned char *tid,
51 const unsigned char *target,
57 const unsigned char *tid,
59 const unsigned char *nodes,
61 const unsigned char *nodes6,
67 const unsigned char *tid,
69 const unsigned char *id,
85 #define ANNOUNCE_PEER 5
92 const unsigned char *buf,
94 unsigned char *tid_return,
96 unsigned char *id_return,
97 unsigned char *info_hash_return,
98 unsigned char *target_return,
99 unsigned short *port_return,
100 unsigned char *token_return,
102 unsigned char *nodes_return,
104 unsigned char *nodes6_return,
106 unsigned char *values_return,
108 unsigned char *values6_return,
112 static const unsigned char zeroes[20] = {0};
113 static const unsigned char v4prefix[16] =
114 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0};
116 static unsigned char myid[20];
117 static int have_v = 0;
118 static unsigned char my_v[9];
120 static int dht_socket = -1;
121 static int dht_socket6 = -1;
124 unsigned char id[160];
125 struct sockaddr_storage ss;
129 #define CIRCULAR_LIST_SIZE 256
131 struct circular_list {
134 struct node nodes[CIRCULAR_LIST_SIZE];
137 struct circular_list v4_new, v6_new, v4_confirmed, v6_confirmed;
139 #define MAX_TOKEN_BUCKET_TOKENS 40
140 static time_t token_bucket_time;
141 static int token_bucket_tokens;
143 FILE *dht_debug = NULL;
146 __attribute__((format(printf, 1, 2)))
149 debugf(const char *format, ...)
152 va_start(args, format);
154 vfprintf(dht_debug, format, args);
160 is_martian(struct sockaddr *sa)
162 switch (sa->sa_family) {
164 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
165 const unsigned char *address = (const unsigned char *)&sin->sin_addr;
166 return sin->sin_port == 0 || (address[0] == 0) || (address[0] == 127) ||
167 ((address[0] & 0xE0) == 0xE0);
170 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
171 const unsigned char *address = (const unsigned char *)&sin6->sin6_addr;
172 return sin6->sin6_port == 0 || (address[0] == 0xFF) ||
173 (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
174 (memcmp(address, zeroes, 15) == 0 &&
175 (address[15] == 0 || address[15] == 1)) ||
176 (memcmp(address, v4prefix, 12) == 0);
184 /* Forget about the ``XOR-metric''. An id is just a path from the
185 root of the tree, so bits are numbered from the start. */
188 id_cmp(const unsigned char *restrict id1, const unsigned char *restrict id2)
190 /* Memcmp is guaranteed to perform an unsigned comparison. */
191 return memcmp(id1, id2, 20);
194 /* Our transaction-ids are 4-bytes long, with the first two bytes identi-
195 fying the kind of request, and the remaining two a sequence number in
199 make_tid(unsigned char *tid_return, const char *prefix, unsigned short seqno)
201 tid_return[0] = prefix[0] & 0xFF;
202 tid_return[1] = prefix[1] & 0xFF;
203 memcpy(tid_return + 2, &seqno, 2);
207 tid_match(const unsigned char *tid, const char *prefix, unsigned short *seqno_return)
209 if (tid[0] == (prefix[0] & 0xFF) && tid[1] == (prefix[1] & 0xFF)) {
211 memcpy(seqno_return, tid + 2, 2);
218 circular(int from, int to)
222 return x + CIRCULAR_LIST_SIZE;
227 list_elements(struct circular_list *list)
229 return circular(list->head, list->tail);
233 list_empty(struct circular_list *list)
235 return list_elements(list) == 0;
239 list_free(struct circular_list *list)
241 return circular(list->tail + 1, list->head);
245 list_pop(struct circular_list *list, struct sockaddr_storage *ss, socklen_t *sslen)
247 if (list->head == list->tail)
250 memcpy(ss, &list->nodes[list->head].ss, list->nodes[list->head].sslen);
251 *sslen = list->nodes[list->head].sslen;
252 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
258 struct circular_list *list,
260 struct sockaddr_storage *ss,
264 if (list->head == list->tail)
267 n = random() % (list->tail - list->head);
268 n = (list->head + n) % CIRCULAR_LIST_SIZE;
271 memcpy(id, &list->nodes[n].id, 20);
272 memcpy(ss, &list->nodes[n].ss, list->nodes[n].sslen);
273 *sslen = list->nodes[n].sslen;
277 /* We just learnt about a node, not necessarily a new one. Confirm is 1 if
278 the node sent a message, 2 if it sent us a reply. */
281 new_node(unsigned char *id, struct sockaddr *sa, socklen_t salen, int confirm)
283 struct circular_list *list;
286 if (sa->sa_family == AF_INET)
287 list = confirm >= 2 ? &v4_confirmed : &v4_new;
288 else if (sa->sa_family == AF_INET6)
289 list = confirm >= 2 ? &v6_confirmed : &v6_new;
293 /* A node that sends us a request is most probably bootstrapping.
294 We want to avoid getting our tables full of very young nodes -- only
295 include such a node if we have plenty of space. */
297 if (confirm == 1 && list_free(list) < 32)
300 for (i = list->head; i != list->tail; i = (i + 1) % CIRCULAR_LIST_SIZE) {
301 struct node *n = &list->nodes[i];
302 if (n->sslen == salen && memcmp(&n->ss, sa, salen) == 0)
306 memcpy(&list->nodes[list->tail].id, id, 160);
307 memcpy(&list->nodes[list->tail].ss, sa, salen);
308 list->nodes[list->tail].sslen = salen;
309 list->tail = (list->tail + 1) % CIRCULAR_LIST_SIZE;
310 if (list->head == list->tail)
311 list->head = (list->head + 1) % CIRCULAR_LIST_SIZE;
319 time_t now = time(NULL);
320 if (token_bucket_tokens == 0) {
321 token_bucket_tokens =
322 MIN(MAX_TOKEN_BUCKET_TOKENS, 4 * (now - token_bucket_time));
323 token_bucket_time = now;
326 if (token_bucket_tokens == 0)
329 token_bucket_tokens--;
334 send_request(struct circular_list *list, int dopop, int doping, int want)
336 unsigned char ttid[4];
337 struct sockaddr_storage ss;
341 if (list_empty(list))
345 rc = list_pop(list, &ss, &sslen);
349 rc = list_random(list, NULL, &ss, &sslen);
355 make_tid(ttid, "pn", 0);
356 debugf("Sending ping.\n");
357 return send_ping((struct sockaddr *)&ss, sslen, ttid, 4);
359 unsigned char id[20];
361 for (i = 0; i < 20; i++)
362 id[i] = random() & 0xFF;
363 make_tid(ttid, "fn", 0);
364 debugf("Sending find_node.\n");
365 return send_find_node((struct sockaddr *)&ss, sslen, ttid, 4, id, want);
370 newSock(const char *host, const char *port)
372 struct addrinfo hints;
373 memset(&hints, 0, sizeof(hints));
374 hints.ai_family = AF_UNSPEC;
375 hints.ai_socktype = SOCK_DGRAM;
376 struct addrinfo *res = NULL;
377 int err = getaddrinfo(host, port, &hints, &res);
379 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
382 int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
387 if (bind(sock, res->ai_addr, res->ai_addrlen) != 0) {
391 int rc = fcntl(sock, F_GETFL, 0);
396 rc = fcntl(sock, F_SETFL, (rc | O_NONBLOCK));
406 main(int argc, char **argv)
410 char *ipv4addr = NULL;
411 char *ipv6addr = NULL;
415 opt = getopt(argc, argv, "q4:6:");
424 ipv4addr = strdup(optarg);
427 ipv6addr = strdup(optarg);
439 const char *port = strdup(argv[i++]);
441 if (ipv4addr != NULL) {
442 dht_socket = newSock(ipv4addr, port);
444 if (ipv6addr != NULL) {
445 dht_socket6 = newSock(ipv6addr, port);
450 int fd = open("/dev/urandom", O_RDONLY);
452 perror("open(random)");
456 rc = read(fd, myid, 20);
458 perror("open(random)");
463 rc = read(fd, &seed, sizeof(seed));
469 memcpy(my_v, "1:v4:JB\0\0", 9);
475 unsigned char ttid[4];
478 struct addrinfo hints, *info, *infop;
479 memset(&hints, 0, sizeof(hints));
480 hints.ai_socktype = SOCK_DGRAM;
483 hints.ai_family = AF_INET6;
484 else if (dht_socket6 < 0)
485 hints.ai_family |= AF_INET;
486 rc = getaddrinfo(argv[i], argv[i + 1], &hints, &info);
488 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc));
498 make_tid(ttid, "pn", 0);
499 debugf("Sending ping.\n");
500 send_ping(infop->ai_addr, infop->ai_addrlen, ttid, 4);
501 infop = infop->ai_next;
508 token_bucket_time = time(NULL);
509 token_bucket_tokens = MAX_TOKEN_BUCKET_TOKENS;
516 if ((dht_socket >= 0 && list_elements(&v4_confirmed) <= 16) ||
517 (dht_socket6 >= 0 && list_elements(&v6_confirmed) <= 16))
520 tv.tv_sec = random() % 30;
521 tv.tv_usec = random() % 1000000;
525 FD_SET(dht_socket, &readfds);
526 if (dht_socket6 >= 0)
527 FD_SET(dht_socket6, &readfds);
532 list_elements(&v4_confirmed),
533 list_elements(&v6_confirmed),
534 list_elements(&v4_new),
535 list_elements(&v6_new));
537 int rc = select(MAX(dht_socket, dht_socket6) + 1, &readfds, NULL, NULL, &tv);
540 if (errno != EINTR) {
549 unsigned char tid[16], id[20], info_hash[20], target[20];
550 unsigned char buf[1536], nodes[256], nodes6[1024], token[128];
551 int tid_len = 16, token_len = 128;
552 int nodes_len = 256, nodes6_len = 1024;
554 unsigned char values[2048], values6[2048];
555 int values_len = 2048, values6_len = 2048;
557 struct sockaddr_storage source_storage;
558 struct sockaddr *source = (struct sockaddr *)&source_storage;
559 socklen_t sourcelen = sizeof(source_storage);
560 if (dht_socket >= 0 && FD_ISSET(dht_socket, &readfds)) {
561 rc = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
562 } else if (dht_socket6 >= 0 && FD_ISSET(dht_socket6, &readfds)) {
563 rc = recvfrom(dht_socket6, buf, 1536, 0, source, &sourcelen);
566 if (rc < 0 || sourcelen > sizeof(struct sockaddr_storage))
569 if (is_martian(source))
572 /* There's a bug in parse_message -- it will happily overflow the
573 buffer if it's not NUL-terminated. For now, put a NUL at the
579 debugf("Overlong message.\n");
583 message = parse_message(
604 if (id_cmp(id, myid) == 0) {
605 debugf("Received message from self.\n");
609 if (message > REPLY) {
610 /* Rate limit requests. */
611 if (!token_bucket()) {
612 debugf("Dropping request due to rate limiting.\n");
620 debugf("Broken node truncates transaction ids.\n");
623 if (tid_match(tid, "pn", NULL)) {
625 new_node(id, source, sourcelen, 2);
626 } else if (tid_match(tid, "fn", NULL)) {
627 debugf("Nodes found!\n");
628 if (nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
629 debugf("Unexpected length for node info!\n");
631 new_node(id, source, sourcelen, 2);
632 for (i = 0; i < nodes_len / 26; i++) {
633 unsigned char *ni = nodes + i * 26;
634 struct sockaddr_in sin;
635 if (id_cmp(ni, myid) == 0)
637 memset(&sin, 0, sizeof(sin));
638 sin.sin_family = AF_INET;
639 memcpy(&sin.sin_addr, ni + 20, 4);
640 memcpy(&sin.sin_port, ni + 24, 2);
641 new_node(ni, (struct sockaddr *)&sin, sizeof(sin), 0);
643 for (i = 0; i < nodes6_len / 38; i++) {
644 unsigned char *ni = nodes6 + i * 38;
645 struct sockaddr_in6 sin6;
646 if (id_cmp(ni, myid) == 0)
648 memset(&sin6, 0, sizeof(sin6));
649 sin6.sin6_family = AF_INET6;
650 memcpy(&sin6.sin6_addr, ni + 20, 16);
651 memcpy(&sin6.sin6_port, ni + 36, 2);
652 new_node(ni, (struct sockaddr *)&sin6, sizeof(sin6), 0);
656 debugf("Unexpected reply!\n");
661 debugf("Ping (%d)!\n", tid_len);
662 new_node(id, source, sourcelen, 1);
663 debugf("Sending pong.\n");
664 send_pong(source, sourcelen, tid, tid_len);
669 if (message == FIND_NODE)
670 debugf("Find node!\n");
672 debugf("Get peers!\n");
673 new_node(id, source, sourcelen, 1);
674 debugf("Sending nodes (%d).\n", want);
675 send_random_nodes(source, sourcelen, tid, tid_len, target, want);
678 debugf("Announce peer!\n");
685 "This node doesn't accept announces");
692 /* We need to be careful to avoid a positive feedback loop. Make
693 sure we send at most one packet each time through the select
698 else if (dht_socket < 0)
701 send4 = random() % 2;
704 int want = dht_socket6 >= 0 && list_free(&v6_new) > 8 ? (WANT4 | WANT6) : 0;
705 if (!list_empty(&v4_new))
706 send_request(&v4_new, 1, list_free(&v4_new) < 8, want);
707 else if (!list_empty(&v4_confirmed))
708 send_request(&v4_confirmed, 0, 0, want);
710 int want = dht_socket >= 0 && list_free(&v4_new) > 8 ? (WANT4 | WANT6) : 0;
711 if (!list_empty(&v6_new))
712 send_request(&v6_new, 1, list_free(&v6_new) < 8, want);
713 else if (!list_empty(&v6_confirmed))
714 send_request(&v6_confirmed, 0, 0, want);
721 fprintf(stderr, "dht-bootstrap [-q] [-4 ADDR4] [-6 ADDR6] port [node port...]\n");
725 /* We could use a proper bencoding printer and parser, but the format of
726 DHT messages is fairly stylised, so this seemed simpler. */
728 #define CHECK(offset, delta, size) \
729 if (delta < 0 || offset + delta > size) \
732 #define INC(offset, delta, size) \
733 CHECK(offset, delta, size); \
736 #define COPY(buf, offset, src, delta, size) \
737 CHECK(offset, delta, size); \
738 memcpy(buf + offset, src, delta); \
741 #define ADD_V(buf, offset, size) \
743 COPY(buf, offset, my_v, sizeof(my_v), size); \
747 dht_send(const void *buf, size_t len, int flags, const struct sockaddr *sa, int salen)
754 if (sa->sa_family == AF_INET)
756 else if (sa->sa_family == AF_INET6)
762 errno = EAFNOSUPPORT;
766 return sendto(s, buf, len, flags, sa, salen);
770 send_ping(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
774 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
776 COPY(buf, i, myid, 20, 512);
777 rc = snprintf(buf + i, 512 - i, "e1:q4:ping1:t%d:", tid_len);
779 COPY(buf, i, tid, tid_len, 512);
781 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
783 return dht_send(buf, i, 0, sa, salen);
791 send_pong(struct sockaddr *sa, int salen, const unsigned char *tid, int tid_len)
795 rc = snprintf(buf + i, 512 - i, "d1:rd2:id20:");
797 COPY(buf, i, myid, 20, 512);
798 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
800 COPY(buf, i, tid, tid_len, 512);
802 rc = snprintf(buf + i, 512 - i, "1:y1:re");
804 return dht_send(buf, i, 0, sa, salen);
815 const unsigned char *tid,
817 const unsigned char *target,
822 rc = snprintf(buf + i, 512 - i, "d1:ad2:id20:");
824 COPY(buf, i, myid, 20, 512);
825 rc = snprintf(buf + i, 512 - i, "6:target20:");
827 COPY(buf, i, target, 20, 512);
833 (want & WANT4) ? "2:n4" : "",
834 (want & WANT6) ? "2:n6" : "");
837 rc = snprintf(buf + i, 512 - i, "e1:q9:find_node1:t%d:", tid_len);
839 COPY(buf, i, tid, tid_len, 512);
841 rc = snprintf(buf + i, 512 - i, "1:y1:qe");
843 return dht_send(buf, i, 0, sa, salen);
854 const unsigned char *tid,
856 const unsigned char *nodes,
858 const unsigned char *nodes6,
864 rc = snprintf(buf + i, 2048 - i, "d1:rd2:id20:");
866 COPY(buf, i, myid, 20, 2048);
868 rc = snprintf(buf + i, 2048 - i, "5:nodes%d:", nodes_len);
870 COPY(buf, i, nodes, nodes_len, 2048);
872 if (nodes6_len > 0) {
873 rc = snprintf(buf + i, 2048 - i, "6:nodes6%d:", nodes6_len);
875 COPY(buf, i, nodes6, nodes6_len, 2048);
878 rc = snprintf(buf + i, 2048 - i, "e1:t%d:", tid_len);
880 COPY(buf, i, tid, tid_len, 2048);
882 rc = snprintf(buf + i, 2048 - i, "1:y1:re");
885 return dht_send(buf, i, 0, sa, salen);
893 buffer_random_nodes(int af, unsigned char *nodes)
895 struct circular_list *list;
896 struct sockaddr_storage ss;
898 unsigned char id[20];
904 list = &v4_confirmed;
907 list = &v6_confirmed;
915 rc = list_random(list, id, &ss, &sslen);
920 struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
921 memcpy(nodes + n * 26, id, 20);
922 memcpy(nodes + n * 26 + 20, &sin->sin_addr, 4);
923 memcpy(nodes + n * 26 + 24, &sin->sin_port, 2);
928 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
929 memcpy(nodes + n * 38, id, 20);
930 memcpy(nodes + n * 38 + 20, &sin6->sin6_addr, 16);
931 memcpy(nodes + n * 38 + 36, &sin6->sin6_port, 2);
946 const unsigned char *tid,
948 const unsigned char *id,
951 unsigned char nodes[8 * 26];
952 unsigned char nodes6[8 * 38];
953 int numnodes = 0, numnodes6 = 0;
956 want = sa->sa_family == AF_INET ? WANT4 : WANT6;
959 numnodes = buffer_random_nodes(AF_INET, nodes);
962 numnodes6 = buffer_random_nodes(AF_INET6, nodes6);
965 sa, salen, tid, tid_len, nodes, numnodes * 26, nodes6, numnodes6 * 38);
980 rc = snprintf(buf + i, 512 - i, "d1:eli%de%d:", code, (int)strlen(message));
982 COPY(buf, i, message, (int)strlen(message), 512);
983 rc = snprintf(buf + i, 512 - i, "e1:t%d:", tid_len);
985 COPY(buf, i, tid, tid_len, 512);
987 rc = snprintf(buf + i, 512 - i, "1:y1:ee");
989 return dht_send(buf, i, 0, sa, salen);
1003 const unsigned char *buf,
1005 unsigned char *tid_return,
1007 unsigned char *id_return,
1008 unsigned char *info_hash_return,
1009 unsigned char *target_return,
1010 unsigned short *port_return,
1011 unsigned char *token_return,
1013 unsigned char *nodes_return,
1015 unsigned char *nodes6_return,
1017 unsigned char *values_return,
1019 unsigned char *values6_return,
1023 const unsigned char *p;
1025 /* This code will happily crash if the buffer is not NUL-terminated. */
1026 if (buf[buflen] != '\0') {
1027 debugf("Eek! parse_message with unterminated buffer.\n");
1031 #define CHECK(ptr, len) \
1032 if (((unsigned char *)ptr) + (len) > (buf) + (buflen)) \
1036 p = memmem(buf, buflen, "1:t", 3);
1040 l = strtol((char *)p + 3, &q, 10);
1041 if (q && *q == ':' && l > 0 && l < *tid_len) {
1043 memcpy(tid_return, q + 1, l);
1050 p = memmem(buf, buflen, "2:id20:", 7);
1053 memcpy(id_return, p + 7, 20);
1055 memset(id_return, 0, 20);
1058 if (info_hash_return) {
1059 p = memmem(buf, buflen, "9:info_hash20:", 14);
1062 memcpy(info_hash_return, p + 14, 20);
1064 memset(info_hash_return, 0, 20);
1068 p = memmem(buf, buflen, "porti", 5);
1072 l = strtol((char *)p + 5, &q, 10);
1073 if (q && *q == 'e' && l > 0 && l < 0x10000)
1080 if (target_return) {
1081 p = memmem(buf, buflen, "6:target20:", 11);
1084 memcpy(target_return, p + 11, 20);
1086 memset(target_return, 0, 20);
1090 p = memmem(buf, buflen, "5:token", 7);
1094 l = strtol((char *)p + 7, &q, 10);
1095 if (q && *q == ':' && l > 0 && l < *token_len) {
1097 memcpy(token_return, q + 1, l);
1106 p = memmem(buf, buflen, "5:nodes", 7);
1110 l = strtol((char *)p + 7, &q, 10);
1111 if (q && *q == ':' && l > 0 && l < *nodes_len) {
1113 memcpy(nodes_return, q + 1, l);
1122 p = memmem(buf, buflen, "6:nodes6", 8);
1126 l = strtol((char *)p + 8, &q, 10);
1127 if (q && *q == ':' && l > 0 && l < *nodes6_len) {
1129 memcpy(nodes6_return, q + 1, l);
1137 if (values_len || values6_len) {
1138 p = memmem(buf, buflen, "6:valuesl", 9);
1140 int i = p - buf + 9;
1145 l = strtol((char *)buf + i, &q, 10);
1146 if (q && *q == ':' && l > 0) {
1149 if (j + l > *values_len)
1151 i = q + 1 + l - (char *)buf;
1152 memcpy((char *)values_return + j, q + 1, l);
1154 } else if (l == 18) {
1155 if (j6 + l > *values6_len)
1157 i = q + 1 + l - (char *)buf;
1158 memcpy((char *)values6_return + j6, q + 1, l);
1161 debugf("Received weird value -- %d bytes.\n", (int)l);
1162 i = q + 1 + l - (char *)buf;
1168 if (i >= buflen || buf[i] != 'e')
1169 debugf("eek... unexpected end for values.\n");
1181 p = memmem(buf, buflen, "4:wantl", 7);
1183 int i = p - buf + 7;
1185 while (buf[i] > '0' && buf[i] <= '9' && buf[i + 1] == ':' &&
1186 i + 2 + buf[i] - '0' < buflen) {
1187 CHECK(buf + i + 2, buf[i] - '0');
1188 if (buf[i] == '2' && memcmp(buf + i + 2, "n4", 2) == 0)
1189 *want_return |= WANT4;
1190 else if (buf[i] == '2' && memcmp(buf + i + 2, "n6", 2) == 0)
1191 *want_return |= WANT6;
1193 debugf("eek... unexpected want flag (%c)\n", buf[i]);
1194 i += 2 + buf[i] - '0';
1196 if (i >= buflen || buf[i] != 'e')
1197 debugf("eek... unexpected end for want.\n");
1205 if (memmem(buf, buflen, "1:y1:r", 6))
1207 if (memmem(buf, buflen, "1:y1:e", 6))
1209 if (!memmem(buf, buflen, "1:y1:q", 6))
1211 if (memmem(buf, buflen, "1:q4:ping", 9))
1213 if (memmem(buf, buflen, "1:q9:find_node", 14))
1215 if (memmem(buf, buflen, "1:q9:get_peers", 14))
1217 if (memmem(buf, buflen, "1:q13:announce_peer", 19))
1218 return ANNOUNCE_PEER;
1222 debugf("Truncated message.\n");