2017-03-09 23:03:21 +00:00
|
|
|
#include "ipfs/routing/routing.h"
|
2017-03-09 23:47:27 +00:00
|
|
|
#include "libp2p/routing/kademlia.h"
|
2017-03-19 19:40:16 +00:00
|
|
|
#include "libp2p/peer/providerstore.h"
|
|
|
|
#include "libp2p/utils/vector.h"
|
2017-03-09 23:03:21 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Routing using Kademlia and DHT
|
2017-03-19 12:47:19 +00:00
|
|
|
*
|
|
|
|
* The go version has "supernode" which is similar to this:
|
2017-03-09 23:03:21 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Put a value in the datastore
|
|
|
|
* @param routing the struct that contains connection information
|
|
|
|
* @param key the key
|
|
|
|
* @param key_size the size of the key
|
|
|
|
* @param value the value
|
|
|
|
* @param value_size the size of the value
|
|
|
|
* @returns 0 on success, otherwise -1
|
|
|
|
*/
|
2017-03-09 23:47:27 +00:00
|
|
|
int ipfs_routing_kademlia_put_value(struct s_ipfs_routing* routing, char* key, size_t key_size, void* value, size_t value_size) {
|
|
|
|
return 0;
|
2017-03-09 23:03:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a value from the datastore
|
|
|
|
* @param 1 the struct that contains the connection information
|
|
|
|
* @param 2 the key to look for
|
|
|
|
* @param 3 the size of the key
|
|
|
|
* @param 4 a place to store the value
|
|
|
|
* @param 5 the size of the value
|
|
|
|
*/
|
2017-03-09 23:47:27 +00:00
|
|
|
int ipfs_routing_kademlia_get_value(struct s_ipfs_routing* routing, char* key, size_t key_size, void** value, size_t* value_size) {
|
2017-03-09 23:03:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-03-23 20:05:09 +00:00
|
|
|
* Find a provider that can provide a particular key
|
2017-03-24 19:29:00 +00:00
|
|
|
* NOTE: It will look locally before asking the network. So
|
|
|
|
* if a peer announced, we already have an answer.
|
2017-03-23 20:05:09 +00:00
|
|
|
*
|
2017-03-19 12:47:19 +00:00
|
|
|
* @param routing the context
|
|
|
|
* @param key the key to what we're looking for
|
|
|
|
* @param key_size the size of the key
|
|
|
|
* @param results the results
|
|
|
|
* @param results_size the size of the results buffer
|
|
|
|
* @returns true(1) on success, otherwise false(0)
|
2017-03-09 23:03:21 +00:00
|
|
|
*/
|
2017-03-19 19:40:16 +00:00
|
|
|
int ipfs_routing_kademlia_find_providers(struct s_ipfs_routing* routing, char* key, size_t key_size, struct Libp2pVector** results) {
|
|
|
|
*results = libp2p_utils_vector_new(1);
|
|
|
|
struct Libp2pVector* vector = *results;
|
2017-03-19 12:47:19 +00:00
|
|
|
// see if I can provide it
|
2017-03-24 19:29:00 +00:00
|
|
|
// temporarily commented out for testing...
|
|
|
|
/*
|
2017-03-19 19:40:16 +00:00
|
|
|
unsigned char* peer_id = NULL;
|
|
|
|
int peer_id_size = 0;
|
|
|
|
if (libp2p_providerstore_get(routing->local_node->providerstore, (unsigned char*)key, key_size, &peer_id, &peer_id_size)) {
|
|
|
|
struct Libp2pPeer* peer = libp2p_peerstore_get_peer(routing->local_node->peerstore, peer_id, peer_id_size);
|
|
|
|
struct Libp2pLinkedList* current = peer->addr_head;
|
|
|
|
while (current != NULL) {
|
|
|
|
struct MultiAddress* ma = (struct MultiAddress*)current->item;
|
|
|
|
if (multiaddress_is_ip(ma)) {
|
|
|
|
libp2p_utils_vector_add(vector, ma);
|
|
|
|
}
|
|
|
|
current = current->next;
|
|
|
|
}
|
|
|
|
}
|
2017-03-24 19:29:00 +00:00
|
|
|
*/
|
|
|
|
//get a list of providers that are closest
|
2017-03-19 19:40:16 +00:00
|
|
|
if (vector->total == 0) {
|
2017-03-24 19:29:00 +00:00
|
|
|
// search requires null terminated key
|
|
|
|
char* key_nt = malloc(key_size + 1);
|
|
|
|
strncpy(key_nt, key, key_size);
|
|
|
|
key_nt[key_size] = 0;
|
|
|
|
struct MultiAddress** list = search_kademlia(key_nt, 3);
|
|
|
|
free(key_nt);
|
|
|
|
if (list != NULL) {
|
|
|
|
int i = 0;
|
|
|
|
while (list[i] != NULL) {
|
|
|
|
struct MultiAddress* current = list[i];
|
|
|
|
libp2p_utils_vector_add(vector, current);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
2017-03-23 20:05:09 +00:00
|
|
|
}
|
|
|
|
if (vector->total == 0) {
|
|
|
|
// we were unable to find it, even on the network
|
2017-03-19 19:40:16 +00:00
|
|
|
libp2p_utils_vector_free(vector);
|
|
|
|
vector = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2017-03-09 23:03:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find a peer
|
|
|
|
*/
|
2017-03-09 23:47:27 +00:00
|
|
|
int ipfs_routing_kademlia_find_peer(struct s_ipfs_routing* routing, char* param1, size_t param2, void* param3, size_t* param4) {
|
2017-03-09 23:03:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2017-03-23 20:05:09 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Calling this method notifies the network that this peer can provide this key
|
|
|
|
* @param routing the context
|
|
|
|
* @param key the key that can be provided
|
|
|
|
* @param key_size the size of the key
|
|
|
|
* @returns true(1) on success, otherwise false(0)
|
|
|
|
*/
|
2017-03-19 19:40:16 +00:00
|
|
|
int ipfs_routing_kademlia_provide(struct s_ipfs_routing* routing, char* key, size_t key_size) {
|
|
|
|
//TODO: Announce to the network that I can provide this file
|
|
|
|
// save in a cache
|
|
|
|
// store key and address in cache. Key is the hash, peer id is the value
|
|
|
|
libp2p_providerstore_add(routing->local_node->providerstore, (unsigned char*)key, key_size, (unsigned char*)routing->local_node->identity->peer_id, strlen(routing->local_node->identity->peer_id));
|
|
|
|
|
|
|
|
return 1;
|
2017-03-09 23:03:21 +00:00
|
|
|
}
|
|
|
|
|
2017-03-09 23:47:27 +00:00
|
|
|
// declared here so as to have the code in 1 place
|
|
|
|
int ipfs_routing_online_ping(struct s_ipfs_routing*, struct Libp2pMessage*);
|
2017-03-09 23:03:21 +00:00
|
|
|
/**
|
|
|
|
* Ping this instance
|
|
|
|
*/
|
|
|
|
int ipfs_routing_kademlia_ping(struct s_ipfs_routing* routing, struct Libp2pMessage* message) {
|
|
|
|
return ipfs_routing_online_ping(routing, message);
|
|
|
|
}
|
|
|
|
|
2017-03-09 23:47:27 +00:00
|
|
|
int ipfs_routing_kademlia_bootstrap(struct s_ipfs_routing* routing) {
|
2017-03-09 23:03:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct s_ipfs_routing* ipfs_routing_new_kademlia(struct IpfsNode* local_node, struct RsaPrivateKey* private_key, struct Stream* stream) {
|
2017-03-23 13:28:35 +00:00
|
|
|
char kademlia_id[21];
|
|
|
|
// generate kademlia compatible id by getting first 20 chars of peer id
|
2017-03-19 12:47:19 +00:00
|
|
|
if (local_node->identity->peer_id == NULL || strlen(local_node->identity->peer_id) < 20) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-03-23 13:28:35 +00:00
|
|
|
strncpy(kademlia_id, local_node->identity->peer_id, 20);
|
|
|
|
kademlia_id[20] = 0;
|
2017-03-09 23:03:21 +00:00
|
|
|
struct s_ipfs_routing* routing = (struct s_ipfs_routing*)malloc(sizeof(struct s_ipfs_routing));
|
|
|
|
if (routing != NULL) {
|
|
|
|
routing->local_node = local_node;
|
|
|
|
routing->sk = private_key;
|
|
|
|
routing->stream = stream;
|
|
|
|
routing->PutValue = ipfs_routing_kademlia_put_value;
|
|
|
|
routing->GetValue = ipfs_routing_kademlia_get_value;
|
|
|
|
routing->FindProviders = ipfs_routing_kademlia_find_providers;
|
|
|
|
routing->FindPeer = ipfs_routing_kademlia_find_peer;
|
|
|
|
routing->Provide = ipfs_routing_kademlia_provide;
|
|
|
|
routing->Ping = ipfs_routing_kademlia_ping;
|
|
|
|
routing->Bootstrap = ipfs_routing_kademlia_bootstrap;
|
|
|
|
}
|
|
|
|
// connect to nodes and listen for connections
|
2017-03-09 23:47:27 +00:00
|
|
|
struct MultiAddress* address = multiaddress_new_from_string(local_node->repo->config->addresses->api);
|
2017-03-09 23:03:21 +00:00
|
|
|
if (multiaddress_is_ip(address)) {
|
2017-03-24 19:29:00 +00:00
|
|
|
start_kademlia_multiaddress(address, kademlia_id, 10);
|
2017-03-09 23:03:21 +00:00
|
|
|
}
|
2017-03-19 12:47:19 +00:00
|
|
|
local_node->routing = routing;
|
2017-03-09 23:03:21 +00:00
|
|
|
return routing;
|
|
|
|
}
|