Handling finding of peer via swarm

Also included is a way to pass port and swarm info to methods that build
the config file. This makes testing easier. Multiple peers can be
started on the same machine easily.
yamux
John Jones 2017-04-13 09:31:58 -05:00
parent 5d558f5229
commit 62096ffc1c
18 changed files with 210 additions and 42 deletions

View File

@ -61,7 +61,7 @@ int do_init(FILE* out_file, char* repo_root, int empty, int num_bits_for_keypair
return 0;
//TODO: If the conf is null, make one
if ( conf->identity->peer_id == NULL) {
int retVal = ipfs_repo_config_init(conf, num_bits_for_keypair, repo_root);
int retVal = ipfs_repo_config_init(conf, num_bits_for_keypair, repo_root, 4001, NULL);
if (retVal == 0)
return 0;
}

View File

@ -139,7 +139,9 @@ int ipfs_exporter_to_console(const unsigned char* hash, const struct FSRepo* fs_
}
/***
* Called from the command line with ipfs object get [hash]. Retrieves the object pointed to by hash, and displays its block data (links and data elements)
* Called from the command line with ipfs object get [hash].
* Retrieves the object pointed to by hash, and displays
* its block data (links and data elements)
* @param argc number of arguments
* @param argv arguments
* @returns true(1) on success

View File

@ -4,6 +4,8 @@
#include "ipfs/importer/resolver.h"
#include "libp2p/crypto/encoding/base58.h"
#include "libp2p/conn/session.h"
#include "libp2p/routing/dht_protocol.h"
#include "ipfs/merkledag/node.h"
#include "ipfs/merkledag/merkledag.h"
#include "ipfs/repo/fsrepo/fs_repo.h"
@ -142,11 +144,17 @@ struct Node* ipfs_resolver_remote_get(const char* path, struct Node* from, const
size_t message_protobuf_size = libp2p_message_protobuf_encode_size(message);
unsigned char message_protobuf[message_protobuf_size];
libp2p_message_protobuf_encode(message, message_protobuf, message_protobuf_size, &message_protobuf_size);
stream->write(stream, message_protobuf, message_protobuf_size);
struct SessionContext session_context;
session_context.insecure_stream = stream;
session_context.default_stream = stream;
// switch to kademlia
if (!libp2p_routing_dht_upgrade_stream(&session_context))
return NULL;
stream->write(&session_context, message_protobuf, message_protobuf_size);
unsigned char* response;
size_t response_size;
// we should get back a protobuf'd record
stream->read(stream, &response, &response_size);
stream->read(&session_context, &response, &response_size);
if (response_size == 1)
return NULL;
// turn the protobuf into a Node

View File

@ -70,9 +70,11 @@ int config_path(char* config_root, char* extension, char* result, int max_len);
* create a configuration based on the passed in parameters
* @param config the configuration struct
* @param num_bits_for_keypair number of bits for the key pair
* @param swarm_port port for swarm
* @param bootstrap_peers a vector of Multiaddress of fellow peers
* @returns true(1) on success, otherwise 0
*/
int ipfs_repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypair, const char* repo_path);
int ipfs_repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypair, const char* repo_path, int swarm_port, struct Libp2pVector *bootstrap_peers);
/***
* Initialize memory for a RepoConfig struct

View File

@ -1,12 +1,16 @@
#pragma once
/***
* Makes a new ipfs repository
* @param path the path to the repository, should end
* with .ipfs, and the directory should already exist.
* @returns true(1) on success
#include "libp2p/utils/vector.h"
/**
* Make an IPFS directory at the passed in path
* @param path the path
* @param swarm_port the port that the swarm will run on
* @param bootstrap_peers a Vector of MultiAddress of fellow peers
* @param peer_id the peer id generated
* @returns true(1) on success, false(0) on failure
*/
int make_ipfs_repository(const char* path);
int make_ipfs_repository(const char* path, int swarm_port, struct Libp2pVector* bootstrap_peers, char **peer_id);
/**
* Initialize a repository, called from the command line

View File

@ -78,18 +78,27 @@ int repo_config_get_file_name(char* path, char** result) {
* create a configuration based on the passed in parameters
* @param config the configuration struct to be filled in
* @param num_bits_for_keypair number of bits for the key pair
* @param repo_path the path to the configuration
* @param swarm_port the port to run on
* @param bootstrap_peers vector of Multiaddresses of fellow peers
* @returns true(1) on success, otherwise 0
*/
int ipfs_repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypair, const char* repo_path) {
int ipfs_repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_keypair, const char* repo_path, int swarm_port, struct Libp2pVector *bootstrap_peers) {
// identity
int retVal = repo_config_identity_init(config->identity, num_bits_for_keypair);
if (retVal == 0)
return 0;
// bootstrap peers
retVal = repo_config_bootstrap_peers_retrieve(&(config->bootstrap_peers));
if (retVal == 0)
return 0;
if (bootstrap_peers != NULL) {
config->bootstrap_peers = libp2p_utils_vector_new(bootstrap_peers->total);
for(int i = 0; i < bootstrap_peers->total; i++)
libp2p_utils_vector_add(config->bootstrap_peers, libp2p_utils_vector_get(bootstrap_peers, i));
}
else {
if (!repo_config_bootstrap_peers_retrieve(&(config->bootstrap_peers)))
return 0;
}
// datastore
retVal = libp2p_datastore_init(config->datastore, repo_path);
@ -97,14 +106,17 @@ int ipfs_repo_config_init(struct RepoConfig* config, unsigned int num_bits_for_k
return 0;
// swarm addresses
const char* addr1 = "/ip4/0.0.0.0/tcp/4001";
const char* addr2 = "/ip6/::/tcp/4001";
char* addr1 = malloc(50);
sprintf(addr1, "/ip4/0.0.0.0/tcp/%d", swarm_port);
config->addresses->swarm_head = libp2p_utils_linked_list_new();
config->addresses->swarm_head->item = malloc(strlen(addr1) + 1);
strcpy(config->addresses->swarm_head->item, addr1);
sprintf(addr1, "/ip6/::/tcp/%d", swarm_port);
config->addresses->swarm_head->next = libp2p_utils_linked_list_new();
config->addresses->swarm_head->next->item = malloc(strlen(addr2) + 1);
strcpy(config->addresses->swarm_head->next->item, addr2);
config->addresses->swarm_head->next->item = malloc(strlen(addr1) + 1);
strcpy(config->addresses->swarm_head->next->item, addr1);
free(addr1);
config->discovery.mdns.enabled = 1;
config->discovery.mdns.interval = 10;

View File

@ -3,6 +3,7 @@
#include "libp2p/crypto/encoding/base64.h"
#include "libp2p/crypto/key.h"
#include "libp2p/utils/vector.h"
#include "ipfs/blocks/blockstore.h"
#include "ipfs/datastore/ds_helper.h"
#include "libp2p/db/datastore.h"
@ -92,16 +93,14 @@ int repo_config_write_config_file(char* full_filename, struct RepoConfig* config
fprintf(out_file, " \"RecordLifetime\": \"\",\n");
fprintf(out_file, " \"ResolveCacheSize\": %d\n", config->ipns.resolve_cache_size);
fprintf(out_file, " },\n \"Bootstrap\": [\n");
/*
for(int i = 0; i < config->peer_addresses.num_peers; i++) {
struct IPFSAddr* peer = config->peer_addresses.peers[i];
fprintf(out_file, " \"%s\"", peer->entire_string);
if (i < config->peer_addresses.num_peers - 1)
for(int i = 0; i < config->bootstrap_peers->total; i++) {
struct MultiAddress* peer = libp2p_utils_vector_get(config->bootstrap_peers, i);
fprintf(out_file, " \"%s\"", peer->string);
if (i < config->bootstrap_peers->total - 1)
fprintf(out_file, ",\n");
else
fprintf(out_file, "\n");
}
*/
fprintf(out_file, " ],\n \"Tour\": {\n \"Last\": \"\"\n },\n");
fprintf(out_file, " \"Gateway\": {\n");
fprintf(out_file, " \"HTTPHeaders\": {\n");

View File

@ -55,9 +55,12 @@ int ipfs_repo_get_directory(int argc, char** argv, char** repo_dir) {
/**
* Make an IPFS directory at the passed in path
* @param path the path
* @param swarm_port the port that the swarm will run on
* @param bootstrap_peers a Vector of MultiAddress of fellow peers
* @param peer_id the peer id generated
* @returns true(1) on success, false(0) on failure
*/
int make_ipfs_repository(const char* path) {
int make_ipfs_repository(const char* path, int swarm_port, struct Libp2pVector* bootstrap_peers, char **peer_id) {
int retVal;
char currDirectory[1024];
struct RepoConfig* repo_config;
@ -68,7 +71,7 @@ int make_ipfs_repository(const char* path) {
if (retVal == 0)
return 0;
printf("generating 2048-bit RSA keypair...");
retVal = ipfs_repo_config_init(repo_config, 2048, path);
retVal = ipfs_repo_config_init(repo_config, 2048, path, swarm_port, bootstrap_peers);
if (retVal == 0)
return 0;
printf("done\n");
@ -86,6 +89,10 @@ int make_ipfs_repository(const char* path) {
// give some results to the user
printf("peer identity: %s\n", fs_repo->config->identity->peer_id);
if (peer_id != NULL) {
*peer_id = malloc(strlen(fs_repo->config->identity->peer_id) + 1);
strcpy(*peer_id, fs_repo->config->identity->peer_id);
}
// clean up
ipfs_repo_fsrepo_free(fs_repo);
@ -120,5 +127,5 @@ int ipfs_repo_init(int argc, char** argv) {
return 0;
}
// make the repository
return make_ipfs_repository(repo_directory);
return make_ipfs_repository(repo_directory, 4001, NULL, NULL);
}

View File

@ -51,6 +51,29 @@ int ipfs_routing_online_find_providers(struct IpfsRouting* routing, char* val1,
return 0;
}
/***
* helper method. Connect to a peer and ask it for information
* about another peer
*/
int ipfs_routing_online_ask_peer_for_peer(struct Libp2pPeer* whoToAsk, const char* peer_id, size_t peer_id_size, struct Libp2pPeer **result) {
if (whoToAsk->connection_type == CONNECTION_TYPE_CONNECTED) {
struct Libp2pMessage *message = libp2p_message_new();
if (message == NULL)
return 0;
message->message_type = MESSAGE_TYPE_FIND_NODE;
message->key_size = peer_id_size;
message->key = malloc(peer_id_size);
if (message->key == NULL)
return 0;
memcpy(message->key, peer_id, peer_id_size);
struct Libp2pMessage *return_message = ipfs_routing_online_send_receive_message(whoToAsk->connection, message);
if (return_message != NULL)
*result = return_message->provider_peer_head->item;
return 1;
}
return 0;
}
/**
* Find a peer
* @param routing the context
@ -66,7 +89,16 @@ int ipfs_routing_online_find_peer(struct IpfsRouting* routing, const char* peer_
if (*result != NULL) {
return 1;
}
//TODO: ask the swarm to find the peer
//ask the swarm to find the peer
// TODO: Multithread
struct Libp2pLinkedList *current = peerstore->head_entry;
while(current != NULL) {
struct Libp2pPeer *current_peer = ((struct PeerEntry*)current->item)->peer;
ipfs_routing_online_ask_peer_for_peer(current_peer, peer_id, peer_id_size, result);
if (*result != NULL)
return 1;
current = current->next;
}
return 0;
}

View File

@ -5,7 +5,7 @@
struct FSRepo* createAndOpenRepo(const char* dir) {
int retVal = 1;
// create a fresh repo
retVal = drop_and_build_repository(dir);
retVal = drop_and_build_repository(dir, 4001, NULL, NULL);
if (retVal == 0)
return NULL;

View File

@ -18,7 +18,7 @@ int test_import_large_file() {
create_file(fileName, file_bytes, bytes_size);
// get the repo
drop_and_build_repository("/tmp/.ipfs");
drop_and_build_repository("/tmp/.ipfs", 4001, NULL, NULL);
struct FSRepo* fs_repo;
ipfs_repo_fsrepo_new("/tmp/.ipfs", NULL, &fs_repo);
ipfs_repo_fsrepo_open(fs_repo);
@ -167,7 +167,7 @@ int test_import_small_file() {
create_file(fileName, file_bytes, bytes_size);
// get the repo
drop_and_build_repository("/tmp/.ipfs");
drop_and_build_repository("/tmp/.ipfs", 4001, NULL, NULL);
struct FSRepo* fs_repo;
ipfs_repo_fsrepo_new("/tmp/.ipfs", NULL, &fs_repo);
ipfs_repo_fsrepo_open(fs_repo);

View File

@ -10,7 +10,7 @@ int test_resolver_get() {
const char* ipfs_path = "/tmp/.ipfs";
os_utils_setenv("IPFS_PATH", ipfs_path, 1);
drop_and_build_repository(ipfs_path);
drop_and_build_repository(ipfs_path, 4001, NULL, NULL);
// this should point to a test directory with files and directories
char* home_dir = os_utils_get_homedir();
@ -79,11 +79,11 @@ void* test_resolver_daemon_start(void* arg) {
int test_resolver_remote_get() {
// clean out repository
const char* ipfs_path = "/tmp/.ipfs";
const char* ipfs_path = "/tmp";
os_utils_setenv("IPFS_PATH", ipfs_path, 1);
char remote_peer_id[255];
char path[255];
drop_and_build_repository(ipfs_path);
drop_and_build_repository(ipfs_path, 4001, NULL, NULL);
// start the daemon in a separate thread
pthread_t thread;

View File

@ -24,7 +24,7 @@ int test_repo_config_init() {
if (retVal == 0)
return 0;
retVal = ipfs_repo_config_init(repoConfig, 2048, "/Users/JohnJones/.ipfs");
retVal = ipfs_repo_config_init(repoConfig, 2048, "/Users/JohnJones/.ipfs", 4001, NULL);
if (retVal == 0)
return 0;
@ -73,7 +73,7 @@ int test_repo_config_write() {
// now build a new one
struct RepoConfig* repoConfig;
ipfs_repo_config_new(&repoConfig);
if (!ipfs_repo_config_init(repoConfig, 2048, "/tmp/.ipfs")) {
if (!ipfs_repo_config_init(repoConfig, 2048, "/tmp/.ipfs", 4001, NULL)) {
ipfs_repo_config_free(repoConfig);
return 0;
}

View File

@ -0,0 +1,92 @@
#include <pthread.h>
#include "libp2p/os/utils.h"
#include "multiaddr/multiaddr.h"
#include "ipfs/core/daemon.h"
#include "../test_helper.h"
#include "ipfs/routing/routing.h"
void* test_routing_daemon_start(void* arg) {
ipfs_daemon_start((char*)arg);
return NULL;
}
int test_routing_find_peer() {
// clean out repository
char* ipfs_path = "/tmp/test1";
os_utils_setenv("IPFS_PATH", ipfs_path, 1);
char* peer_id_1;
char* peer_id_2;
struct FSRepo* fs_repo_2;
char* peer_id_3;
pthread_t thread1;
pthread_t thread2;
struct MultiAddress* ma_peer1;
// create peer 1
drop_and_build_repository(ipfs_path, 4001, NULL, &peer_id_1);
char multiaddress_string[255];
sprintf(multiaddress_string, "/ip4/127.0.0.1/tcp/4001/ipfs/%s", peer_id_1);
ma_peer1 = multiaddress_new_from_string(multiaddress_string);
// start the daemon in a separate thread
if (pthread_create(&thread1, NULL, test_routing_daemon_start, (void*)ipfs_path) < 0)
return 0;
// create peer 2
ipfs_path = "/tmp/test2";
os_utils_setenv("IPFS_PATH", ipfs_path, 1);
struct Libp2pVector* ma_vector = libp2p_utils_vector_new(1);
libp2p_utils_vector_add(ma_vector, ma_peer1);
drop_and_build_repository(ipfs_path, 4002, ma_vector, &peer_id_2);
// add a file, to prime the connection to peer 1
//TODO: Find a better way to do this...
size_t bytes_written = 0;
ipfs_repo_fsrepo_new(ipfs_path, NULL, &fs_repo_2);
ipfs_repo_fsrepo_open(fs_repo_2);
struct Node* node = NULL;
ipfs_import_file(NULL, "/home/parallels/ipfstest/hello_world.txt", &node, fs_repo_2, &bytes_written, 0);
ipfs_repo_fsrepo_free(fs_repo_2);
// start the daemon in a separate thread
if (pthread_create(&thread2, NULL, test_routing_daemon_start, (void*)ipfs_path) < 0)
return 0;
// create my peer, peer 3
ipfs_path = "/tmp/test3";
os_utils_setenv("IPFS_PATH", ipfs_path, 1);
drop_and_build_repository(ipfs_path, 4003, ma_vector, &peer_id_3);
struct FSRepo* fs_repo;
ipfs_repo_fsrepo_new(ipfs_path, NULL, &fs_repo);
ipfs_repo_fsrepo_open(fs_repo);
// We know peer 1, try to find peer 2
struct IpfsNode local_node;
local_node.mode = MODE_ONLINE;
local_node.peerstore = libp2p_peerstore_new();
local_node.repo = fs_repo;
local_node.identity = fs_repo->config->identity;
local_node.routing = ipfs_routing_new_online(&local_node, &fs_repo->config->identity->private_key, NULL);
local_node.routing->Bootstrap(local_node.routing);
struct Libp2pPeer* result;
struct Libp2pPeer* first_peer = ((struct PeerEntry*)local_node.peerstore->head_entry->item)->peer;
if (!local_node.routing->FindPeer(local_node.routing, peer_id_2, strlen(peer_id_2), &result))
return 0;
if (result == NULL) {
ipfs_repo_fsrepo_free(fs_repo);
pthread_cancel(thread1);
pthread_cancel(thread2);
return 0;
}
struct MultiAddress *remote_address = result->addr_head->item;
fprintf(stderr, "Remote address is: %s\n", remote_address->string);
ipfs_repo_fsrepo_free(fs_repo);
pthread_cancel(thread1);
pthread_cancel(thread2);
return 1;
}

View File

@ -18,7 +18,7 @@ int test_ipfs_datastore_put() {
const unsigned char* input = (unsigned char*)"Hello, world!";
// build the ipfs repository, then shut it down, so we can start fresh
retVal = drop_and_build_repository("/tmp/.ipfs");
retVal = drop_and_build_repository("/tmp/.ipfs", 4001, NULL, NULL);
if (retVal == 0)
return 0;

View File

@ -93,7 +93,14 @@ int remove_directory(const char *path)
return r;
}
int drop_and_build_repository(const char* path) {
/**
* drops and builds a repository at the specified path
* @param path the path
* @param swarm_port the port that the swarm should run on
* @param bootstrap_peers a vector of fellow peers as MultiAddresses, can be NULL
* @returns true(1) on success, otherwise false(0)
*/
int drop_and_build_repository(const char* path, int swarm_port, struct Libp2pVector* bootstrap_peers, char **peer_id) {
int retVal = 0;
char currDirectory[strlen(path) + 20];
@ -115,14 +122,14 @@ int drop_and_build_repository(const char* path) {
}
return make_ipfs_repository(path);
return make_ipfs_repository(path, swarm_port, bootstrap_peers, peer_id);
}
int drop_build_and_open_repo(const char* path, struct FSRepo** fs_repo) {
int retVal = 0;
retVal = drop_and_build_repository("/tmp/.ipfs");
retVal = drop_and_build_repository("/tmp/.ipfs", 4001, NULL, NULL);
if (retVal == 0)
return 0;
retVal = ipfs_repo_fsrepo_new("/tmp/.ipfs", NULL, fs_repo);

View File

@ -6,7 +6,7 @@
* Create a new repository in the directory, erasing old one
* NOTE: base directory must already exist
*/
int drop_and_build_repository(const char* dir);
int drop_and_build_repository(const char* dir, int swarm_port, struct Libp2pVector* bootstrap_peers, char** peer_id);
int drop_build_and_open_repo(const char* path, struct FSRepo** fs_repo);

View File

@ -9,6 +9,7 @@
#include "repo/test_repo_config.h"
#include "repo/test_repo_fsrepo.h"
#include "repo/test_repo_identity.h"
#include "routing/test_routing.h"
#include "routing/test_supernode.h"
#include "storage/test_ds_helper.h"
#include "storage/test_datastore.h"
@ -59,6 +60,7 @@ const char* names[] = {
"test_resolver_get",
"test_routing_supernode_get_value",
"test_routing_supernode_get_remote_value",
"test_routing_find_peer",
"test_unixfs_encode_decode",
"test_unixfs_encode_smallfile",
"test_ping",
@ -99,6 +101,7 @@ int (*funcs[])(void) = {
test_resolver_get,
test_routing_supernode_get_value,
test_routing_supernode_get_remote_value,
test_routing_find_peer,
test_unixfs_encode_decode,
test_unixfs_encode_smallfile,
test_ping,