diff --git a/core/Makefile b/core/Makefile index 3786d50..4de62f5 100644 --- a/core/Makefile +++ b/core/Makefile @@ -7,7 +7,7 @@ endif LFLAGS = DEPS = builder.h ipfs_node.h -OBJS = builder.o daemon.o null.o ping.o bootstrap.o ipfs_node.o api.o client_api.o http_request.o +OBJS = builder.o daemon.o null.o ping.o bootstrap.o ipfs_node.o api.o client_api.o http_request.o swarm.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/core/http_request.c b/core/http_request.c index 0e8ac89..312e926 100644 --- a/core/http_request.c +++ b/core/http_request.c @@ -291,6 +291,63 @@ int ipfs_core_http_process_dht(struct IpfsNode* local_node, struct HttpRequest* return retVal; } +int ipfs_core_http_process_swarm_connect(struct IpfsNode* local_node, struct HttpRequest* request, struct HttpResponse** resp) { + // get the address + if (request->arguments == NULL || request->arguments->total < 0) + return 0; + const char* address = (char*) libp2p_utils_vector_get(request->arguments, 0); + if (address == NULL) + return 0; + // TODO: see if we are already connected, or at least already have this peer in our peerstore + // attempt to connect + struct MultiAddress* ma = multiaddress_new_from_string(address); + if (ma == NULL) { + libp2p_logger_error("http_request", "swarm_connect: Unable to convert %s to a MultiAddress.\n", address); + return 0; + } + struct Libp2pPeer* new_peer = libp2p_peer_new_from_multiaddress(ma); + if (!libp2p_peer_connect(&local_node->identity->private_key, new_peer, local_node->peerstore, local_node->repo->config->datastore, 30)) { + libp2p_logger_error("http_request", "swarm_connect: Unable to connect to peer %s.\n", libp2p_peer_id_to_string(new_peer)); + libp2p_peer_free(new_peer); + multiaddress_free(ma); + return 0; + } + // ok, we're good. Send stuff back to the user + *resp = ipfs_core_http_response_new(); + struct HttpResponse* response = *resp; + if (response == NULL) { + libp2p_logger_error("http_response", "swarm_connect: Unable to allocate memory for the response.\n"); + libp2p_peer_free(new_peer); + multiaddress_free(ma); + return 0; + } + response->content_type = "application/json"; + char* json = "{ \"Strings\": [ \"%s\"] }"; + response->bytes_size = strlen(json) + strlen(address) + 1; + response->bytes = (uint8_t*) malloc(response->bytes_size); + if (response->bytes == NULL) { + response->bytes_size = 0; + response->content_type = NULL; + libp2p_peer_free(new_peer); + multiaddress_free(ma); + return 0; + } + sprintf((char*)response->bytes, json, address); + libp2p_peer_free(new_peer); + multiaddress_free(ma); + return 1; + +} + +int ipfs_core_http_process_swarm(struct IpfsNode* local_node, struct HttpRequest* request, struct HttpResponse** response) { + int retVal = 0; + if (strcmp(request->sub_command, "connect") == 0) { + // connect to a peer + retVal = ipfs_core_http_process_swarm_connect(local_node, request, response); + } + return retVal; +} + /*** * Process the parameters passed in from an http request * @param local_node the context @@ -309,6 +366,8 @@ int ipfs_core_http_request_process(struct IpfsNode* local_node, struct HttpReque retVal = ipfs_core_http_process_object(local_node, request, response); } else if (strcmp(request->command, "dht") == 0) { retVal = ipfs_core_http_process_dht(local_node, request, response); + } else if (strcmp(request->command, "swarm") == 0) { + retVal = ipfs_core_http_process_swarm(local_node, request, response); } return retVal; } diff --git a/core/swarm.c b/core/swarm.c new file mode 100644 index 0000000..1c924e2 --- /dev/null +++ b/core/swarm.c @@ -0,0 +1,68 @@ +#include +#include + +#include "libp2p/utils/logger.h" +#include "ipfs/core/ipfs_node.h" +#include "ipfs/core/swarm.h" +#include "ipfs/core/http_request.h" + +int ipfs_swarm_connect(struct IpfsNode* local_node, const char* address) { + char* response = NULL; + size_t response_size; + // use the API to connect + struct HttpRequest* request = ipfs_core_http_request_new(); + if (request == NULL) + return 0; + request->command = "swarm"; + request->sub_command = "connect"; + libp2p_utils_vector_add(request->arguments, address); + int retVal = ipfs_core_http_request_get(local_node, request, &response, &response_size); + if (response != NULL && response_size > 0) { + fwrite(response, 1, response_size, stdout); + free(response); + } + ipfs_core_http_request_free(request); + return retVal; +} + +/*** + * Handle command line swarm call + */ +int ipfs_swarm (struct CliArguments* args) { + int retVal = 0; + struct IpfsNode* client_node = NULL; + + if (args->argc < (args->verb_index + 2)) { + libp2p_logger_error("swarm", "Not enough command line arguments. Should be \"swarm connect\" or \"swarm disconnect\" etc.\n"); + goto exit; + } + + // make sure API is running + if (!ipfs_node_offline_new(args->config_dir, &client_node)) { + libp2p_logger_error("swarm", "Unable to create offline node.\n"); + goto exit; + } + if (client_node->mode != MODE_API_AVAILABLE) { + libp2p_logger_error("swarm", "API must be running.\n"); + goto exit; + } + + const char* which = args->argv[args->verb_index + 1]; + const char* path = args->argv[args->verb_index + 2]; + // determine what we're doing + if (strcmp(which, "connect") == 0) { + retVal = ipfs_swarm_connect(client_node, path); + } else if (strcmp(which, "disconnect") == 0) { + libp2p_logger_error("swarm", "Swarm disconnect not implemented yet.\n"); + retVal = 0; + } else { + libp2p_logger_error("swarm", "Nothing useful found on command line. Should be \"swarm connect\" or \"swarm disconnect\".\n"); + goto exit; + } + + exit: + // shut everything down + ipfs_node_free(client_node); + + return retVal; +} diff --git a/include/ipfs/core/swarm.h b/include/ipfs/core/swarm.h new file mode 100644 index 0000000..0d8e336 --- /dev/null +++ b/include/ipfs/core/swarm.h @@ -0,0 +1,8 @@ +#pragma once + +#include "ipfs/cmd/cli.h" + +/*** + * Handle command line swarm call + */ +int ipfs_swarm (struct CliArguments* args); diff --git a/main/main.c b/main/main.c index db2e1ae..1d93d22 100644 --- a/main/main.c +++ b/main/main.c @@ -7,6 +7,7 @@ #include "ipfs/importer/exporter.h" #include "ipfs/dnslink/dnslink.h" #include "ipfs/core/daemon.h" +#include "ipfs/core/swarm.h" #include "ipfs/cmd/cli.h" #include "ipfs/namesys/name.h" @@ -69,6 +70,7 @@ void strip_quotes(int argc, char** argv) { #define PING 7 #define GET 8 #define NAME 9 +#define SWARM 10 /** * Find out if this command line argument is part of a switch @@ -146,6 +148,9 @@ int parse_arguments(int argc, char** argv) { if (strcmp("name", argv[index]) == 0) { return NAME; } + if (strcmp("swarm", argv[index]) == 0) { + return SWARM; + } return -1; } @@ -188,6 +193,9 @@ int main(int argc, char** argv) { case (NAME): retVal = ipfs_name(args); break; + case (SWARM): + retVal = ipfs_swarm(args); + break; default: libp2p_logger_error("main", "Invalid command line arguments.\n"); break; diff --git a/test/scripts/test_go.sh b/test/scripts/test_go.sh new file mode 100755 index 0000000..70e540e --- /dev/null +++ b/test/scripts/test_go.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +#### +# Attempt to connect to a go swarm +# +#### + +source ./test_helpers.sh + +IPFS="../../main/ipfs --config /tmp/ipfs_1" + +function pre { + rm -Rf /tmp/ipfs_1 + eval "$IPFS" init; + check_failure_with_exit "pre" $? + cp ../config.test1.wo_journal /tmp/ipfs_1/config +} + +function post { + echo cleanup complete +} + +function body { + #start the daemon + eval "../../main/ipfs --config /tmp/ipfs_1 daemon &" + daemon_id=$! + sleep 5 + + eval "$IPFS" swarm connect /ip4/107.170.104.234/tcp/4001/ipfs/QmRvKrhY2k55uQmGBq4da5XkfGEQvbhiJ4dCLKiG9qMGNF + + sleep 10 + + kill -9 $daemon_id +}