Implemented kademlia thread.
This commit is contained in:
parent
6d9473069b
commit
386fe24f70
1 changed files with 137 additions and 0 deletions
|
@ -13,6 +13,7 @@
|
|||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/signal.h>
|
||||
#include <pthread.h>
|
||||
#include <libp2p/crypto/sha256.h>
|
||||
#include <dht.h>
|
||||
|
||||
|
@ -20,6 +21,22 @@
|
|||
static struct sockaddr_storage bootstrap_nodes[MAX_BOOTSTRAP_NODES];
|
||||
static int num_bootstrap_nodes = 0;
|
||||
|
||||
pthread_t pth;
|
||||
time_t tosleep = 0;
|
||||
int ksock = -1;
|
||||
int net_family = 0;
|
||||
volatile int searching = 0; // search lock, -1 to busy, 0 to free, 1 to running.
|
||||
volatile char hash[20]; // hash to be search or announce.
|
||||
volatile int announce_port = 0;
|
||||
|
||||
struct bs_list {
|
||||
char *ip;
|
||||
uint16_t port;
|
||||
} bootstrap_list[] = {
|
||||
{ "127.0.0.1", 1234 },
|
||||
{ "127.0.0.1", 4321 }
|
||||
};
|
||||
|
||||
/* The call-back function is called by the DHT whenever something
|
||||
interesting happens. Right now, it only happens when we get a new value or
|
||||
when a search completes, but this may be extended in future versions. */
|
||||
|
@ -43,6 +60,126 @@ callback(void *closure,
|
|||
}
|
||||
}
|
||||
|
||||
void *kademlia_thread (void *ptr)
|
||||
{
|
||||
int rc;
|
||||
struct timeval tv;
|
||||
fd_set readfds;
|
||||
char buf[4096];
|
||||
struct sockaddr from;
|
||||
socklen_t fromlen;
|
||||
|
||||
for(;;) {
|
||||
tv.tv_sec = tosleep;
|
||||
tv.tv_usec = random() % 1000000;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(ksock, &readfds);
|
||||
rc = select(ksock + 1, &readfds, NULL, NULL, &tv);
|
||||
if(rc < 0) {
|
||||
if(errno != EINTR) {
|
||||
perror("select");
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(rc > 0 && FD_ISSET(ksock, &readfds)) {
|
||||
fromlen = sizeof(from);
|
||||
rc = recvfrom(ksock, buf, sizeof(buf) - 1, 0,
|
||||
(struct sockaddr*)&from, &fromlen);
|
||||
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;
|
||||
} else {
|
||||
perror("dht_periodic");
|
||||
if(rc == EINVAL || rc == EFAULT)
|
||||
abort();
|
||||
tosleep = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is how you trigger a search for a torrent hash. If port
|
||||
(the second argument) is non-zero, it also performs an announce.
|
||||
Since peers expire announced data after 30 minutes, it's a good
|
||||
idea to reannounce every 28 minutes or so. */
|
||||
if(searching > 0) {
|
||||
char h[sizeof hash];
|
||||
int i;
|
||||
for (i = 0 ; i < sizeof hash ; i++) {
|
||||
h[i] = hash[i];
|
||||
}
|
||||
dht_search(h, announce_port, net_family, callback, NULL);
|
||||
searching = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bootstrap_kademlia(int sock, int family, char* peer_id, int timeout)
|
||||
{
|
||||
int rc, i, len;
|
||||
unsigned char id[20];
|
||||
struct sockaddr_in sa;
|
||||
|
||||
len = sizeof(bootstrap_list) / sizeof(bootstrap_list[0]); // array length
|
||||
|
||||
if (len > MAX_BOOTSTRAP_NODES) {
|
||||
len = MAX_BOOTSTRAP_NODES; // limit array length
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
for (i = 0 ; i < len ; i++) {
|
||||
if (family == AF_INET6 && inet_pton(AF_INET6, bootstrap_list[i].ip, &(sa.sin_addr.s_addr)) == 1) {
|
||||
sa.sin_family = AF_INET6;
|
||||
} else if (inet_pton(AF_INET, bootstrap_list[i].ip, &(sa.sin_addr.s_addr)) == 1) {
|
||||
sa.sin_family = AF_INET;
|
||||
} else {
|
||||
continue; // not an ipv6 or ipv4?
|
||||
}
|
||||
|
||||
sa.sin_port = htons (bootstrap_list[i].port);
|
||||
|
||||
memcpy(&bootstrap_nodes[num_bootstrap_nodes++], &sa, sizeof(sa));
|
||||
}
|
||||
|
||||
dht_hash (id, sizeof(id), peer_id, strlen(peer_id), NULL, 0, NULL, 0);
|
||||
|
||||
if (family == AF_INET6) {
|
||||
rc = dht_init(-1, sock, id, NULL);
|
||||
} else {
|
||||
rc = dht_init(sock, -1, id, NULL);
|
||||
}
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* For bootstrapping, we need an initial list of nodes. This could be
|
||||
hard-wired, but can also be obtained from the nodes key of a torrent
|
||||
file, or from the PORT bittorrent message.
|
||||
|
||||
Dht_ping_node is the brutal way of bootstrapping -- it actually
|
||||
sends a message to the peer. If you're going to bootstrap from
|
||||
a massive number of nodes (for example because you're restoring from
|
||||
a dump) and you already know their ids, it's better to use
|
||||
dht_insert_node. If the ids are incorrect, the DHT will recover. */
|
||||
for(i = 0; i < num_bootstrap_nodes; i++) {
|
||||
dht_ping_node((struct sockaddr*)&bootstrap_nodes[i],
|
||||
sizeof (bootstrap_nodes[i]));
|
||||
usleep(random() % 100000);
|
||||
}
|
||||
|
||||
ksock = sock;
|
||||
net_family = family;
|
||||
tosleep = timeout;
|
||||
|
||||
return pthread_create(&pth, NULL, kademlia_thread, NULL);
|
||||
}
|
||||
|
||||
/* Functions called by the DHT. */
|
||||
|
||||
int dht_blacklisted (const struct sockaddr *sa, int salen)
|
||||
|
|
Loading…
Reference in a new issue