diff --git a/cmd/ipfs/init.c b/cmd/ipfs/init.c index 31ac6a2..77956aa 100644 --- a/cmd/ipfs/init.c +++ b/cmd/ipfs/init.c @@ -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; } diff --git a/importer/exporter.c b/importer/exporter.c index 8cf4311..9517d30 100644 --- a/importer/exporter.c +++ b/importer/exporter.c @@ -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 diff --git a/importer/resolver.c b/importer/resolver.c index c264784..6bf9c0d 100644 --- a/importer/resolver.c +++ b/importer/resolver.c @@ -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 diff --git a/include/ipfs/repo/config/config.h b/include/ipfs/repo/config/config.h index 48e0f69..35d0f36 100644 --- a/include/ipfs/repo/config/config.h +++ b/include/ipfs/repo/config/config.h @@ -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 diff --git a/include/ipfs/repo/init.h b/include/ipfs/repo/init.h index 6be0212..9970c6d 100644 --- a/include/ipfs/repo/init.h +++ b/include/ipfs/repo/init.h @@ -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 diff --git a/repo/config/config.c b/repo/config/config.c index 566b5f2..160099c 100644 --- a/repo/config/config.c +++ b/repo/config/config.c @@ -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; diff --git a/repo/fsrepo/fs_repo.c b/repo/fsrepo/fs_repo.c index 9fa2880..00fd4a1 100644 --- a/repo/fsrepo/fs_repo.c +++ b/repo/fsrepo/fs_repo.c @@ -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"); diff --git a/repo/init.c b/repo/init.c index 8e29d0e..20dd07e 100644 --- a/repo/init.c +++ b/repo/init.c @@ -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); } diff --git a/routing/online.c b/routing/online.c index 8477817..01eacad 100644 --- a/routing/online.c +++ b/routing/online.c @@ -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; } diff --git a/test/merkledag/test_merkledag.h b/test/merkledag/test_merkledag.h index 22286df..8d20fde 100644 --- a/test/merkledag/test_merkledag.h +++ b/test/merkledag/test_merkledag.h @@ -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; diff --git a/test/node/test_importer.h b/test/node/test_importer.h index 5aa8046..1d8691e 100644 --- a/test/node/test_importer.h +++ b/test/node/test_importer.h @@ -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); diff --git a/test/node/test_resolver.h b/test/node/test_resolver.h index e068f18..d5666cf 100644 --- a/test/node/test_resolver.h +++ b/test/node/test_resolver.h @@ -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; diff --git a/test/repo/test_repo_config.h b/test/repo/test_repo_config.h index 78eb828..36ee9cf 100644 --- a/test/repo/test_repo_config.h +++ b/test/repo/test_repo_config.h @@ -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; } diff --git a/test/routing/test_routing.h b/test/routing/test_routing.h new file mode 100644 index 0000000..cad8a23 --- /dev/null +++ b/test/routing/test_routing.h @@ -0,0 +1,92 @@ +#include + +#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; + +} diff --git a/test/storage/test_datastore.h b/test/storage/test_datastore.h index 1152de4..4d4e05c 100644 --- a/test/storage/test_datastore.h +++ b/test/storage/test_datastore.h @@ -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; diff --git a/test/test_helper.c b/test/test_helper.c index 7b8fe62..17ccc14 100644 --- a/test/test_helper.c +++ b/test/test_helper.c @@ -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); diff --git a/test/test_helper.h b/test/test_helper.h index 32874a9..34fe49c 100644 --- a/test/test_helper.h +++ b/test/test_helper.h @@ -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); diff --git a/test/testit.c b/test/testit.c index 66aab17..358c58f 100644 --- a/test/testit.c +++ b/test/testit.c @@ -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,