From 6f77a64adbb908dff572ee3a1e91624a385f60c0 Mon Sep 17 00:00:00 2001 From: John Jones Date: Wed, 9 Aug 2017 08:03:40 -0500 Subject: [PATCH] IPFS protocols now implement an interface to make marshalling easier --- include/libp2p/net/protocol.h | 38 +++++++++++++++++++ include/libp2p/routing/dht_protocol.h | 3 ++ include/libp2p/secio/secio.h | 3 ++ net/Makefile | 2 +- net/protocol.c | 27 ++++++++++++++ routing/dht_protocol.c | 39 +++++++++++++++++++ secio/secio.c | 54 ++++++++++++++++++--------- 7 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 include/libp2p/net/protocol.h create mode 100644 net/protocol.c diff --git a/include/libp2p/net/protocol.h b/include/libp2p/net/protocol.h new file mode 100644 index 0000000..579040f --- /dev/null +++ b/include/libp2p/net/protocol.h @@ -0,0 +1,38 @@ +#pragma once +#include "libp2p/conn/session.h" +#include "libp2p/utils/vector.h" + +/*** + * An "interface" for different IPFS protocols + */ +struct Libp2pProtocolHandler { + /** + * A protocol dependent context (often an IpfsNode pointer, but libp2p doesn't know about that) + */ + void* context; + /** + * Determines if this protocol can handle the incoming message + * @param incoming the incoming data + * @param incoming_size the size of the incoming data buffer + * @returns true(1) if it can handle this message, false(0) if not + */ + int (*CanHandle)(const uint8_t* incoming, size_t incoming_size); + /*** + * Handles the message + * @param incoming the incoming data buffer + * @param incoming_size the size of the incoming data buffer + * @param session_context the information about the incoming connection + * @param protocol_context the protocol-dependent context + * @returns 0 if the caller should not continue looping, <0 on error, >0 on success + */ + int (*HandleMessage)(const uint8_t* incoming, size_t incoming_size, struct SessionContext* session_context, void* protocol_context); + + /** + * Shutting down. Clean up any memory allocations + * @param protocol_context the context + * @returns true(1) + */ + int (*Shutdown)(void* protocol_context); +}; + +int libp2p_protocol_marshal(const uint8_t* incoming, size_t incoming_size, struct SessionContext* context, struct Libp2pVector* protocol_handlers); diff --git a/include/libp2p/routing/dht_protocol.h b/include/libp2p/routing/dht_protocol.h index 28f98e3..61fd3e1 100644 --- a/include/libp2p/routing/dht_protocol.h +++ b/include/libp2p/routing/dht_protocol.h @@ -3,12 +3,15 @@ #include "libp2p/conn/session.h" #include "libp2p/peer/peerstore.h" #include "libp2p/peer/providerstore.h" +#include "libp2p/net/protocol.h" /*** * This is where kademlia and dht talk to the outside world */ +struct Libp2pProtocolHandler* libp2p_routing_dht_build_protocol_handler(struct Peerstore* peer_store, struct ProviderStore* provider_store); + /** * Take existing stream and upgrade to the Kademlia / DHT protocol/codec * @param context the context diff --git a/include/libp2p/secio/secio.h b/include/libp2p/secio/secio.h index be1b701..9240d4d 100644 --- a/include/libp2p/secio/secio.h +++ b/include/libp2p/secio/secio.h @@ -4,12 +4,15 @@ #include "libp2p/crypto/rsa.h" #include "libp2p/conn/session.h" #include "libp2p/peer/peerstore.h" +#include "libp2p/net/protocol.h" /** * Handling of a secure connection */ +struct Libp2pProtocolHandler* libp2p_secio_build_protocol_handler(struct RsaPrivateKey* private_key, struct Peerstore* peer_store); + /*** * performs initial communication over an insecure channel to share * keys, IDs, and initiate connection. This is a framed messaging system diff --git a/net/Makefile b/net/Makefile index a0d0f47..c04b95d 100644 --- a/net/Makefile +++ b/net/Makefile @@ -7,7 +7,7 @@ endif LFLAGS = DEPS = -OBJS = sctp.o socket.o tcp.o udp.o multistream.o +OBJS = sctp.o socket.o tcp.o udp.o multistream.o protocol.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/net/protocol.c b/net/protocol.c new file mode 100644 index 0000000..1fb15ad --- /dev/null +++ b/net/protocol.c @@ -0,0 +1,27 @@ +#include +#include "libp2p/net/protocol.h" + +/*** + * Compare incoming to see if they are requesting a protocol upgrade + * @param incoming the incoming string + * @param incoming_size the size of the incoming string + * @param test the protocol string to compare it with (i.e. "/secio" or "/nodeio" + * @returns true(1) if there was a match, false(0) otherwise + */ +const struct Libp2pProtocolHandler* protocol_compare(const unsigned char* incoming, size_t incoming_size, struct Libp2pVector* protocol_handlers) { + for(int i = 0; i < protocol_handlers->total; i++) { + const struct Libp2pProtocolHandler* handler = (const struct Libp2pProtocolHandler*) libp2p_utils_vector_get(protocol_handlers, i); + if (handler->CanHandle(incoming, incoming_size)) { + return handler; + } + } + return NULL; +} + +int libp2p_protocol_marshal(const unsigned char* incoming, size_t incoming_size, struct SessionContext* session, struct Libp2pVector* handlers) { + const struct Libp2pProtocolHandler* handler = protocol_compare(incoming, incoming_size, handlers); + if (handler != NULL) { + return handler->HandleMessage(incoming, incoming_size, session, handler->context); + } + return 0; +} diff --git a/routing/dht_protocol.c b/routing/dht_protocol.c index 0f27a20..c02e115 100644 --- a/routing/dht_protocol.c +++ b/routing/dht_protocol.c @@ -13,6 +13,45 @@ * This is where kademlia and dht talk to the outside world */ +struct DhtContext { + struct Peerstore* peer_store; + struct ProviderStore* provider_store; +}; + +int libp2p_routing_dht_can_handle(const uint8_t* incoming, size_t incoming_size) { + if (incoming_size < 8) + return 0; + char* result = strstr((char*)incoming, "/ipfs/kad"); + if (result == NULL || result != (char*)incoming) + return 0; + return 1; +} + +int libp2p_routing_dht_shutdown(void* context) { + free(context); + return 1; +} + +int libp2p_routing_dht_handle_msg(const uint8_t* incoming, size_t incoming_size, struct SessionContext* session_context, void* context) { + struct DhtContext* ctx = (struct DhtContext*)context; + if (!libp2p_routing_dht_handshake(session_context)) + return 0; + return libp2p_routing_dht_handle_message(session_context, ctx->peer_store, ctx->provider_store); +} + +struct Libp2pProtocolHandler* libp2p_routing_dht_build_protocol_handler(struct Peerstore* peer_store, struct ProviderStore* provider_store) { + struct Libp2pProtocolHandler* handler = (struct Libp2pProtocolHandler*) malloc(sizeof(struct Libp2pProtocolHandler)); + if (handler != NULL) { + struct DhtContext* ctx = (struct DhtContext*) malloc(sizeof(struct DhtContext)); + ctx->peer_store = peer_store; + ctx->provider_store = provider_store; + handler->context = ctx; + handler->CanHandle = libp2p_routing_dht_can_handle; + handler->HandleMessage = libp2p_routing_dht_handle_msg; + handler->Shutdown = libp2p_routing_dht_shutdown; + } + return handler; +} /*** * Helper method to protobuf a message diff --git a/secio/secio.c b/secio/secio.c index a0d9f48..239a0b0 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -23,6 +23,7 @@ #include "libp2p/utils/string_list.h" #include "libp2p/utils/vector.h" #include "libp2p/utils/logger.h" +#include "libp2p/net/protocol.h" #include "mbedtls/md.h" #include "mbedtls/cipher.h" #include "mbedtls/md_internal.h" @@ -32,26 +33,43 @@ const char* SupportedExchanges = "P-256,P-384,P-521"; const char* SupportedCiphers = "AES-256,AES-128,Blowfish"; const char* SupportedHashes = "SHA256,SHA512"; -/*** - * Create a new SecureSession struct - * @returns a pointer to a new SecureSession object - */ -struct SessionContext* libp2p_secio_secure_session_new() { - struct SessionContext* ss = (struct SessionContext*) malloc(sizeof(struct SessionContext)); - if (ss == NULL) - return NULL; - ss->insecure_stream = NULL; - ss->secure_stream = NULL; - return ss; +struct SecioContext { + struct RsaPrivateKey* private_key; + struct Peerstore* peer_store; +}; + +int libp2p_secio_can_handle(const uint8_t* incoming, size_t incoming_size) { + // sanity checks + if (incoming_size < 11) + return 0; + char* result = strstr((char*)incoming, "/ipfs/secio"); + if (result != NULL && result == (char*)incoming) + return 0; + return 1; } -/*** - * Clean up resources from a SecureSession struct - * @param in the SecureSession to be deallocated - */ -void libp2p_secio_secure_session_free(struct SessionContext* in) { - //TODO: should we close the socket? - free(in); +int libp2p_secio_handle_message(const uint8_t* incoming, size_t incoming_size, struct SessionContext* session_context, void* protocol_context) { + struct SecioContext* ctx = (struct SecioContext*)protocol_context; + return libp2p_secio_handshake(session_context, ctx->private_key, ctx->peer_store, 1); +} + +int libp2p_secio_shutdown(void* context) { + free(context); + return 1; +} + +struct Libp2pProtocolHandler* libp2p_secio_build_protocol_handler(struct RsaPrivateKey* private_key, struct Peerstore* peer_store) { + struct Libp2pProtocolHandler* handler = (struct Libp2pProtocolHandler*) malloc(sizeof(struct Libp2pProtocolHandler)); + if (handler != NULL) { + struct SecioContext* context = (struct SecioContext*) malloc(sizeof(struct SecioContext)); + context->private_key = private_key; + context->peer_store = peer_store; + handler->context = context; + handler->CanHandle = libp2p_secio_can_handle; + handler->HandleMessage = libp2p_secio_handle_message; + handler->Shutdown = libp2p_secio_shutdown; + } + return handler; } /**