Import dht-0.16.
authorJuliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Sun, 9 Jan 2011 21:48:40 +0000 (21:48 +0000)
committerJuliusz Chroboczek <jch@pps.univ-paris-diderot.fr>
Sun, 9 Jan 2011 21:48:40 +0000 (21:48 +0000)
third-party/dht/CHANGES
third-party/dht/LICENCE
third-party/dht/README
third-party/dht/dht-example.c
third-party/dht/dht.c
third-party/dht/dht.h

index b9637f44c35d365f25277ab7413945c45d0b8cb8..bc7cad1bc0914c50ec957e23ef0bc35fb844048e 100644 (file)
@@ -1,3 +1,7 @@
+23 December 2010: dht-0.16:
+
+  * Change the interface to allow sharing of the UDP socket e.g. with uTP.
+
 1 July 2010: dht-0.15
 
   * Port to Windows, for the needs of Transmission.
index e5b0995c5917f2ad0e2b51aadc2a9b0db843c246..cf2d39000a76fefdaa8d57993643afa6ef877e32 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (c) 2009 by Juliusz Chroboczek
+Copyright (c) 2009, 2010 by Juliusz Chroboczek
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
index 36be0babffa5f0b74dad454acb1bab56557458cd..1c42fefb66dd3434f617e432d4a32334124e7705 100644 (file)
@@ -86,9 +86,8 @@ dht_periodic should be called if no data is available is returned in the
 parameter tosleep.  (You do not need to be particularly accurate; actually,
 it is a good idea to be late by a random value.)
 
-The parameter available indicates whether any data is available on the
-socket.  If it is 0, dht_periodic will not try to read data; if it is 1, it
-will.
+The parameters buf, buflen, from and fromlen optionally carry a received
+message.  If buflen is 0, then no message was received.
 
 Dht_periodic also takes a callback, which will be called whenever something
 interesting happens (see below).
index 150ed8886520ee8f3134e8b14c94c715bc9510f8..80037123a300ad37823229c34266cf63750da7be 100644 (file)
@@ -88,6 +88,8 @@ callback(void *closure,
         printf("Received %d values.\n", (int)(data_len / 6));
 }
 
+static unsigned char buf[4096];
+
 int
 main(int argc, char **argv)
 {
@@ -101,6 +103,8 @@ main(int argc, char **argv)
     int quiet = 0, ipv4 = 1, ipv6 = 1;
     struct sockaddr_in sin;
     struct sockaddr_in6 sin6;
+    struct sockaddr_storage from;
+    socklen_t fromlen;
 
     memset(&sin, 0, sizeof(sin));
     sin.sin_family = AF_INET;
@@ -338,7 +342,25 @@ main(int argc, char **argv)
         if(exiting)
             break;
 
-        rc = dht_periodic(rc > 0, &tosleep, callback, NULL);
+        if(rc > 0) {
+            fromlen = sizeof(from);
+            if(s >= 0 && FD_ISSET(s, &readfds))
+                rc = recvfrom(s, buf, sizeof(buf) - 1, 0,
+                              (struct sockaddr*)&from, &fromlen);
+            else if(s6 >= 0 && FD_ISSET(s6, &readfds))
+                rc = recvfrom(s6, buf, sizeof(buf) - 1, 0,
+                              (struct sockaddr*)&from, &fromlen);
+            else
+                abort();
+        }
+
+        if(rc > 0) {
+            buf[rc] = '\0';
+            rc = dht_periodic(buf, rc, (struct sockaddr*)&from, fromlen,
+                              &tosleep, callback, NULL);
+        } else {
+            rc = dht_periodic(NULL, 0, NULL, 0, &tosleep, callback, NULL);
+        }
         if(rc < 0) {
             if(errno == EINTR) {
                 continue;
index ea34c7715c6a953748476f8fb2e91986c259b443..723f8aaea93779106a1587ac2767796871d135f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2010 by Juliusz Chroboczek
+Copyright (c) 2009, 2010 by Juliusz Chroboczek
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -66,7 +66,6 @@ THE SOFTWARE.
 #ifdef WIN32
 
 #define EAFNOSUPPORT WSAEAFNOSUPPORT
-#define EAGAIN WSAEWOULDBLOCK
 static int
 set_nonblocking(int fd, int nonblocking)
 {
@@ -213,34 +212,34 @@ struct storage {
     struct storage *next;
 };
 
-static int send_ping(struct sockaddr *sa, int salen,
+static int send_ping(const struct sockaddr *sa, int salen,
                      const unsigned char *tid, int tid_len);
-static int send_pong(struct sockaddr *sa, int salen,
+static int send_pong(const struct sockaddr *sa, int salen,
                      const unsigned char *tid, int tid_len);
-static int send_find_node(struct sockaddr *sa, int salen,
+static int send_find_node(const struct sockaddr *sa, int salen,
                           const unsigned char *tid, int tid_len,
                           const unsigned char *target, int want, int confirm);
-static int send_nodes_peers(struct sockaddr *sa, int salen,
+static int send_nodes_peers(const struct sockaddr *sa, int salen,
                             const unsigned char *tid, int tid_len,
                             const unsigned char *nodes, int nodes_len,
                             const unsigned char *nodes6, int nodes6_len,
                             int af, struct storage *st,
                             const unsigned char *token, int token_len);
-static int send_closest_nodes(struct sockaddr *sa, int salen,
+static int send_closest_nodes(const struct sockaddr *sa, int salen,
                               const unsigned char *tid, int tid_len,
                               const unsigned char *id, int want,
                               int af, struct storage *st,
                               const unsigned char *token, int token_len);
-static int send_get_peers(struct sockaddr *sa, int salen,
+static int send_get_peers(const struct sockaddr *sa, int salen,
                           unsigned char *tid, int tid_len,
                           unsigned char *infohash, int want, int confirm);
-static int send_announce_peer(struct sockaddr *sa, int salen,
+static int send_announce_peer(const struct sockaddr *sa, int salen,
                               unsigned char *tid, int tid_len,
                               unsigned char *infohas, unsigned short port,
                               unsigned char *token, int token_len, int confirm);
-static int send_peer_announced(struct sockaddr *sa, int salen,
+static int send_peer_announced(const struct sockaddr *sa, int salen,
                                unsigned char *tid, int tid_len);
-static int send_error(struct sockaddr *sa, int salen,
+static int send_error(const struct sockaddr *sa, int salen,
                       unsigned char *tid, int tid_len,
                       int code, const char *message);
 
@@ -350,7 +349,7 @@ print_hex(FILE *f, const unsigned char *buf, int buflen)
 }
 
 static int
-is_martian(struct sockaddr *sa)
+is_martian(const struct sockaddr *sa)
 {
     switch(sa->sa_family) {
     case AF_INET: {
@@ -688,7 +687,8 @@ pinged(struct node *n, struct bucket *b)
 /* We just learnt about a node, not necessarily a new one.  Confirm is 1 if
    the node sent a message, 2 if it sent us a reply. */
 static struct node *
-new_node(const unsigned char *id, struct sockaddr *sa, int salen, int confirm)
+new_node(const unsigned char *id, const struct sockaddr *sa, int salen,
+         int confirm)
 {
     struct bucket *b = find_bucket(id, sa->sa_family);
     struct node *n;
@@ -790,7 +790,7 @@ new_node(const unsigned char *id, struct sockaddr *sa, int salen, int confirm)
 
         if(split) {
             debugf("Splitting.\n");
-            split_bucket(b);
+            b = split_bucket(b);
             return new_node(id, sa, salen, confirm);
         }
 
@@ -880,7 +880,7 @@ find_search(unsigned short tid, int af)
 
 static int
 insert_search_node(unsigned char *id,
-                   struct sockaddr *sa, int salen,
+                   const struct sockaddr *sa, int salen,
                    struct search *sr, int replied,
                    unsigned char *token, int token_len)
 {
@@ -1221,7 +1221,7 @@ find_storage(const unsigned char *id)
 }
 
 static int
-storage_store(const unsigned char *id, struct sockaddr *sa)
+storage_store(const unsigned char *id, const struct sockaddr *sa)
 {
     int i, len;
     struct storage *st;
@@ -1332,7 +1332,7 @@ expire_storage(void)
 
 /* We've just found out that a node is buggy. */
 static void
-broken_node(const unsigned char *id, struct sockaddr *sa, int salen)
+broken_node(const unsigned char *id, const struct sockaddr *sa, int salen)
 {
     int i;
 
@@ -1382,7 +1382,7 @@ rotate_secrets(void)
 #endif
 
 static void
-make_token(struct sockaddr *sa, int old, unsigned char *token_return)
+make_token(const struct sockaddr *sa, int old, unsigned char *token_return)
 {
     void *ip;
     int iplen;
@@ -1407,7 +1407,8 @@ make_token(struct sockaddr *sa, int old, unsigned char *token_return)
              ip, iplen, (unsigned char*)&port, 2);
 }
 static int
-token_match(unsigned char *token, int token_len, struct sockaddr *sa)
+token_match(const unsigned char *token, int token_len,
+            const struct sockaddr *sa)
 {
     unsigned char t[TOKEN_SIZE];
     if(token_len != TOKEN_SIZE)
@@ -1831,68 +1832,46 @@ bucket_maintenance(int af)
 }
 
 int
-dht_periodic(int available, time_t *tosleep,
+dht_periodic(const void *buf, size_t buflen,
+             const struct sockaddr *from, int fromlen,
+             time_t *tosleep,
              dht_callback *callback, void *closure)
 {
     int i;
 
     gettimeofday(&now, NULL);
 
-    if(available) {
-        int rc, message;
+    if(buflen > 0) {
+        int message;
         unsigned char tid[16], id[20], info_hash[20], target[20];
-        unsigned char buf[1536], nodes[256], nodes6[1024], token[128];
+        unsigned char nodes[256], nodes6[1024], token[128];
         int tid_len = 16, token_len = 128;
         int nodes_len = 256, nodes6_len = 1024;
         unsigned short port;
         unsigned char values[2048], values6[2048];
         int values_len = 2048, values6_len = 2048;
         int want;
-        struct sockaddr_storage source_storage;
-        struct sockaddr *source = (struct sockaddr*)&source_storage;
-        socklen_t sourcelen = sizeof(source_storage);
         unsigned short ttid;
 
-        rc = -1;
-        if(dht_socket >= 0) {
-            rc = recvfrom(dht_socket, buf, 1536, 0, source, &sourcelen);
-            if(rc < 0 && errno != EAGAIN) {
-                    return rc;
-            }
-        }
-        if(dht_socket6 >= 0 && rc < 0) {
-            rc = recvfrom(dht_socket6, buf, 1536, 0,
-                          source, &sourcelen);
-            if(rc < 0 && errno != EAGAIN) {
-                    return rc;
-            }
-        }
-
-        if(rc < 0 || sourcelen > sizeof(struct sockaddr_storage))
-            goto dontread;
-
-        if(is_martian(source))
+        if(is_martian(from))
             goto dontread;
 
         for(i = 0; i < DHT_MAX_BLACKLISTED; i++) {
-            if(memcmp(&blacklist[i], source, sourcelen) == 0) {
+            if(memcmp(&blacklist[i], from, fromlen) == 0) {
                 debugf("Received packet from blacklisted node.\n");
                 goto dontread;
             }
         }
 
-        /* There's a bug in parse_message -- it will happily overflow the
-           buffer if it's not NUL-terminated.  For now, put a NUL at the
-           end of buffers. */
+        /* See parse_message. */
 
-        if(rc < 1536) {
-            buf[rc] = '\0';
-        } else {
-            debugf("Overlong message.\n");
-            goto dontread;
+        if(((char*)buf)[buflen] != '\0') {
+            debugf("Unterminated message.\n");
+            errno = EINVAL;
+            return -1;
         }
 
-        message = parse_message(buf, rc, tid, &tid_len, id, info_hash,
+        message = parse_message(buf, buflen, tid, &tid_len, id, info_hash,
                                 target, &port, token, &token_len,
                                 nodes, &nodes_len, nodes6, &nodes6_len,
                                 values, &values_len, values6, &values6_len,
@@ -1900,7 +1879,7 @@ dht_periodic(int available, time_t *tosleep,
 
         if(message < 0 || message == ERROR || id_cmp(id, zeroes) == 0) {
             debugf("Unparseable message: ");
-            debug_printable(buf, rc);
+            debug_printable(buf, buflen);
             debugf("\n");
             goto dontread;
         }
@@ -1922,36 +1901,36 @@ dht_periodic(int available, time_t *tosleep,
         case REPLY:
             if(tid_len != 4) {
                 debugf("Broken node truncates transaction ids: ");
-                debug_printable(buf, rc);
+                debug_printable(buf, buflen);
                 debugf("\n");
                 /* This is really annoying, as it means that we will
                    time-out all our searches that go through this node.
                    Kill it. */
-                broken_node(id, source, sourcelen);
+                broken_node(id, from, fromlen);
                 goto dontread;
             }
             if(tid_match(tid, "pn", NULL)) {
                 debugf("Pong!\n");
-                new_node(id, source, sourcelen, 2);
+                new_node(id, from, fromlen, 2);
             } else if(tid_match(tid, "fn", NULL) ||
                       tid_match(tid, "gp", NULL)) {
                 int gp = 0;
                 struct search *sr = NULL;
                 if(tid_match(tid, "gp", &ttid)) {
                     gp = 1;
-                    sr = find_search(ttid, source->sa_family);
+                    sr = find_search(ttid, from->sa_family);
                 }
                 debugf("Nodes found (%d+%d)%s!\n", nodes_len/26, nodes6_len/38,
                        gp ? " for get_peers" : "");
                 if(nodes_len % 26 != 0 || nodes6_len % 38 != 0) {
                     debugf("Unexpected length for node info!\n");
-                    broken_node(id, source, sourcelen);
+                    broken_node(id, from, fromlen);
                 } else if(gp && sr == NULL) {
                     debugf("Unknown search!\n");
-                    new_node(id, source, sourcelen, 1);
+                    new_node(id, from, fromlen, 1);
                 } else {
                     int i;
-                    new_node(id, source, sourcelen, 2);
+                    new_node(id, from, fromlen, 2);
                     for(i = 0; i < nodes_len / 26; i++) {
                         unsigned char *ni = nodes + i * 26;
                         struct sockaddr_in sin;
@@ -1993,7 +1972,7 @@ dht_periodic(int available, time_t *tosleep,
                         search_send_get_peers(sr, NULL);
                 }
                 if(sr) {
-                    insert_search_node(id, source, sourcelen, sr,
+                    insert_search_node(id, from, fromlen, sr,
                                        1, token, token_len);
                     if(values_len > 0 || values6_len > 0) {
                         debugf("Got values (%d+%d)!\n",
@@ -2012,13 +1991,13 @@ dht_periodic(int available, time_t *tosleep,
             } else if(tid_match(tid, "ap", &ttid)) {
                 struct search *sr;
                 debugf("Got reply to announce_peer.\n");
-                sr = find_search(ttid, source->sa_family);
+                sr = find_search(ttid, from->sa_family);
                 if(!sr) {
                     debugf("Unknown search!\n");
-                    new_node(id, source, sourcelen, 1);
+                    new_node(id, from, fromlen, 1);
                 } else {
                     int i;
-                    new_node(id, source, sourcelen, 2);
+                    new_node(id, from, fromlen, 2);
                     for(i = 0; i < sr->numnodes; i++)
                         if(id_cmp(sr->nodes[i].id, id) == 0) {
                             sr->nodes[i].request_time = 0;
@@ -2032,47 +2011,47 @@ dht_periodic(int available, time_t *tosleep,
                 }
             } else {
                 debugf("Unexpected reply: ");
-                debug_printable(buf, rc);
+                debug_printable(buf, buflen);
                 debugf("\n");
             }
             break;
         case PING:
             debugf("Ping (%d)!\n", tid_len);
-            new_node(id, source, sourcelen, 1);
+            new_node(id, from, fromlen, 1);
             debugf("Sending pong.\n");
-            send_pong(source, sourcelen, tid, tid_len);
+            send_pong(from, fromlen, tid, tid_len);
             break;
         case FIND_NODE:
             debugf("Find node!\n");
-            new_node(id, source, sourcelen, 1);
+            new_node(id, from, fromlen, 1);
             debugf("Sending closest nodes (%d).\n", want);
-            send_closest_nodes(source, sourcelen,
+            send_closest_nodes(from, fromlen,
                                tid, tid_len, target, want,
                                0, NULL, NULL, 0);
             break;
         case GET_PEERS:
             debugf("Get_peers!\n");
-            new_node(id, source, sourcelen, 1);
+            new_node(id, from, fromlen, 1);
             if(id_cmp(info_hash, zeroes) == 0) {
                 debugf("Eek!  Got get_peers with no info_hash.\n");
-                send_error(source, sourcelen, tid, tid_len,
+                send_error(from, fromlen, tid, tid_len,
                            203, "Get_peers with no info_hash");
                 break;
             } else {
                 struct storage *st = find_storage(info_hash);
                 unsigned char token[TOKEN_SIZE];
-                make_token(source, 0, token);
+                make_token(from, 0, token);
                 if(st && st->numpeers > 0) {
                      debugf("Sending found%s peers.\n",
-                            source->sa_family == AF_INET6 ? " IPv6" : "");
-                     send_closest_nodes(source, sourcelen,
+                            from->sa_family == AF_INET6 ? " IPv6" : "");
+                     send_closest_nodes(from, fromlen,
                                         tid, tid_len,
                                         info_hash, want,
-                                        source->sa_family, st,
+                                        from->sa_family, st,
                                         token, TOKEN_SIZE);
                 } else {
                     debugf("Sending nodes for get_peers.\n");
-                    send_closest_nodes(source, sourcelen,
+                    send_closest_nodes(from, fromlen,
                                        tid, tid_len, info_hash, want,
                                        0, NULL, token, TOKEN_SIZE);
                 }
@@ -2080,31 +2059,31 @@ dht_periodic(int available, time_t *tosleep,
             break;
         case ANNOUNCE_PEER:
             debugf("Announce peer!\n");
-            new_node(id, source, sourcelen, 1);
+            new_node(id, from, fromlen, 1);
             if(id_cmp(info_hash, zeroes) == 0) {
                 debugf("Announce_peer with no info_hash.\n");
-                send_error(source, sourcelen, tid, tid_len,
+                send_error(from, fromlen, tid, tid_len,
                            203, "Announce_peer with no info_hash");
                 break;
             }
-            if(!token_match(token, token_len, source)) {
+            if(!token_match(token, token_len, from)) {
                 debugf("Incorrect token for announce_peer.\n");
-                send_error(source, sourcelen, tid, tid_len,
+                send_error(from, fromlen, tid, tid_len,
                            203, "Announce_peer with wrong token");
                 break;
             }
             if(port == 0) {
                 debugf("Announce_peer with forbidden port %d.\n", port);
-                send_error(source, sourcelen, tid, tid_len,
+                send_error(from, fromlen, tid, tid_len,
                            203, "Announce_peer with forbidden port number");
                 break;
             }
-            storage_store(info_hash, source);
+            storage_store(info_hash, from);
             /* Note that if storage_store failed, we lie to the requestor.
                This is to prevent them from backtracking, and hence
                polluting the DHT. */
             debugf("Sending peer announced.\n");
-            send_peer_announced(source, sourcelen, tid, tid_len);
+            send_peer_announced(from, fromlen, tid, tid_len);
         }
     }
 
@@ -2328,7 +2307,7 @@ dht_send(const void *buf, size_t len, int flags,
 }
 
 int
-send_ping(struct sockaddr *sa, int salen,
+send_ping(const struct sockaddr *sa, int salen,
           const unsigned char *tid, int tid_len)
 {
     char buf[512];
@@ -2348,7 +2327,7 @@ send_ping(struct sockaddr *sa, int salen,
 }
 
 int
-send_pong(struct sockaddr *sa, int salen,
+send_pong(const struct sockaddr *sa, int salen,
           const unsigned char *tid, int tid_len)
 {
     char buf[512];
@@ -2367,7 +2346,7 @@ send_pong(struct sockaddr *sa, int salen,
 }
 
 int
-send_find_node(struct sockaddr *sa, int salen,
+send_find_node(const struct sockaddr *sa, int salen,
                const unsigned char *tid, int tid_len,
                const unsigned char *target, int want, int confirm)
 {
@@ -2396,7 +2375,7 @@ send_find_node(struct sockaddr *sa, int salen,
 }
 
 int
-send_nodes_peers(struct sockaddr *sa, int salen,
+send_nodes_peers(const struct sockaddr *sa, int salen,
                  const unsigned char *tid, int tid_len,
                  const unsigned char *nodes, int nodes_len,
                  const unsigned char *nodes6, int nodes6_len,
@@ -2523,7 +2502,7 @@ buffer_closest_nodes(unsigned char *nodes, int numnodes,
 }
 
 int
-send_closest_nodes(struct sockaddr *sa, int salen,
+send_closest_nodes(const struct sockaddr *sa, int salen,
                    const unsigned char *tid, int tid_len,
                    const unsigned char *id, int want,
                    int af, struct storage *st,
@@ -2570,7 +2549,7 @@ send_closest_nodes(struct sockaddr *sa, int salen,
 }
 
 int
-send_get_peers(struct sockaddr *sa, int salen,
+send_get_peers(const struct sockaddr *sa, int salen,
                unsigned char *tid, int tid_len, unsigned char *infohash,
                int want, int confirm)
 {
@@ -2600,7 +2579,7 @@ send_get_peers(struct sockaddr *sa, int salen,
 }
 
 int
-send_announce_peer(struct sockaddr *sa, int salen,
+send_announce_peer(const struct sockaddr *sa, int salen,
                    unsigned char *tid, int tid_len,
                    unsigned char *infohash, unsigned short port,
                    unsigned char *token, int token_len, int confirm)
@@ -2630,7 +2609,7 @@ send_announce_peer(struct sockaddr *sa, int salen,
 }
 
 static int
-send_peer_announced(struct sockaddr *sa, int salen,
+send_peer_announced(const struct sockaddr *sa, int salen,
                     unsigned char *tid, int tid_len)
 {
     char buf[512];
@@ -2651,7 +2630,7 @@ send_peer_announced(struct sockaddr *sa, int salen,
 }
 
 static int
-send_error(struct sockaddr *sa, int salen,
+send_error(const struct sockaddr *sa, int salen,
            unsigned char *tid, int tid_len,
            int code, const char *message)
 {
index a673b2303b8e6cf8bed3bcef50dba135233be67b..2364ac927bf25ec44c5bfa3f0422d46d5aca134e 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Copyright (c) 2009 by Juliusz Chroboczek
+Copyright (c) 2009, 2010 by Juliusz Chroboczek
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -36,8 +36,9 @@ extern FILE *dht_debug;
 int dht_init(int s, int s6, const unsigned char *id, const unsigned char *v);
 int dht_insert_node(const unsigned char *id, struct sockaddr *sa, int salen);
 int dht_ping_node(struct sockaddr *sa, int salen);
-int dht_periodic(int available, time_t *tosleep,
-                 dht_callback *callback, void *closure);
+int dht_periodic(const void *buf, size_t buflen,
+                 const struct sockaddr *from, int fromlen,
+                 time_t *tosleep, dht_callback *callback, void *closure);
 int dht_search(const unsigned char *id, int port, int af,
                dht_callback *callback, void *closure);
 int dht_nodes(int af,