diff --git a/include/libp2p/net/multistream.h b/include/libp2p/net/multistream.h index ef4083c..cbf9464 100644 --- a/include/libp2p/net/multistream.h +++ b/include/libp2p/net/multistream.h @@ -14,6 +14,14 @@ * So in short, much of this will change. But for now, think of it as a Proof of Concept. */ + +/*** + * The handler to handle calls to the protocol + * @param stream_context the context + * @returns the protocol handler + */ +struct Libp2pProtocolHandler* libp2p_net_multistream_build_protocol_handler(void* stream_context); + /** * Read from a multistream socket * @param socket_fd the socket file descriptor diff --git a/include/libp2p/net/protocol.h b/include/libp2p/net/protocol.h index 579040f..21f50e3 100644 --- a/include/libp2p/net/protocol.h +++ b/include/libp2p/net/protocol.h @@ -35,4 +35,10 @@ struct Libp2pProtocolHandler { int (*Shutdown)(void* protocol_context); }; +/** + * Allocate resources for a new Libp2pProtocolHandler + * @returns an allocated struct + */ +struct Libp2pProtocolHandler* libp2p_protocol_handler_new(); + int libp2p_protocol_marshal(const uint8_t* incoming, size_t incoming_size, struct SessionContext* context, struct Libp2pVector* protocol_handlers); diff --git a/include/libp2p/secio/secio.h b/include/libp2p/secio/secio.h index 73b0c7b..8e9a0dd 100644 --- a/include/libp2p/secio/secio.h +++ b/include/libp2p/secio/secio.h @@ -32,3 +32,16 @@ int libp2p_secio_handshake(struct SessionContext* session, struct RsaPrivateKey* * @returns true(1) on success, false(0) otherwise */ int libp2p_secio_initiate_handshake(struct SessionContext* session_context, struct RsaPrivateKey* private_key, struct Peerstore* peer_store); + +/*** + * Send the protocol string to the remote stream + * @param session the context + * @returns true(1) on success, false(0) otherwise + */ +int libp2p_secio_send_protocol(struct SessionContext* session); +/*** + * Attempt to read the secio protocol as a reply from the remote + * @param session the context + * @returns true(1) if we received what we think we should have, false(0) otherwise + */ +int libp2p_secio_receive_protocol(struct SessionContext* session); diff --git a/net/multistream.c b/net/multistream.c index 31bdaad..097bd51 100644 --- a/net/multistream.c +++ b/net/multistream.c @@ -23,6 +23,43 @@ int multistream_default_timeout = 5; * An implementation of the libp2p multistream */ +int libp2p_net_multistream_can_handle(const uint8_t *incoming, const size_t incoming_size) { + char *protocol = "/multistream/1.0.0\n"; + int protocol_size = strlen(protocol); + // is there a varint in front? + size_t num_bytes = 0; + varint_decode(incoming, incoming_size, &num_bytes); + if (incoming_size >= protocol_size - num_bytes) { + if (strncmp(protocol, (char*) &incoming[num_bytes], protocol_size) == 0) + return 1; + } + return 0; +} + +int libp2p_net_multistream_handle_message(const uint8_t *incoming, size_t incoming_size, struct SessionContext* context, void* protocol_context) { + return 0; +} + +int libp2p_net_multistream_shutdown(void* protocol_context) { + return 1; +} + +/*** + * The handler to handle calls to the protocol + * @param stream_context the context + * @returns the protocol handler + */ +struct Libp2pProtocolHandler* libp2p_net_multistream_build_protocol_handler(void* stream_context) { + struct Libp2pProtocolHandler *handler = libp2p_protocol_handler_new(); + if (handler != NULL) { + handler->context = stream_context; + handler->CanHandle = libp2p_net_multistream_can_handle; + handler->HandleMessage = libp2p_net_multistream_handle_message; + handler->Shutdown = libp2p_net_multistream_shutdown; + } + return handler; +} + /*** * Close the Multistream interface * NOTE: This also closes the socket diff --git a/net/protocol.c b/net/protocol.c index f7b0846..2f5ec6c 100644 --- a/net/protocol.c +++ b/net/protocol.c @@ -20,6 +20,21 @@ const struct Libp2pProtocolHandler* protocol_compare(const unsigned char* incomi return NULL; } +/** + * Allocate resources for a new Libp2pProtocolHandler + * @returns an allocated struct + */ +struct Libp2pProtocolHandler* libp2p_protocol_handler_new() { + struct Libp2pProtocolHandler* h = (struct Libp2pProtocolHandler*) malloc(sizeof(struct Libp2pProtocolHandler)); + if (h != NULL) { + h->CanHandle = NULL; + h->HandleMessage = NULL; + h->Shutdown = NULL; + h->context = NULL; + } + return h; +} + /*** * Handle an incoming message * @param incoming the incoming data diff --git a/secio/secio.c b/secio/secio.c index 149d346..67bd05a 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -59,6 +59,9 @@ int libp2p_secio_can_handle(const uint8_t* incoming, size_t incoming_size) { int libp2p_secio_handle_message(const uint8_t* incoming, size_t incoming_size, struct SessionContext* session_context, void* protocol_context) { libp2p_logger_debug("secio", "Handling incoming secio message.\n"); struct SecioContext* ctx = (struct SecioContext*)protocol_context; + // send them the protocol + if (!libp2p_secio_send_protocol(session_context)) + return -1; int retVal = libp2p_secio_handshake(session_context, ctx->private_key, ctx->peer_store); if (retVal) return 0; @@ -79,13 +82,10 @@ int libp2p_secio_shutdown(void* context) { * @returns true(1) on success, false(0) otherwise */ int libp2p_secio_initiate_handshake(struct SessionContext* session_context, struct RsaPrivateKey* private_key, struct Peerstore* peer_store) { - // send the protocol id first - const unsigned char* protocol = (unsigned char*)"/ipfs/secio/1.0.0\n"; - int protocol_len = strlen((char*)protocol); - if (!session_context->default_stream->write(session_context, protocol, protocol_len)) - return 0; - return libp2p_secio_handshake(session_context, private_key, peer_store); - + if (libp2p_secio_send_protocol(session_context) && libp2p_secio_receive_protocol(session_context)) { + return libp2p_secio_handshake(session_context, private_key, peer_store); + } + return 0; } struct Libp2pProtocolHandler* libp2p_secio_build_protocol_handler(struct RsaPrivateKey* private_key, struct Peerstore* peer_store) { @@ -628,6 +628,35 @@ int libp2p_secio_unencrypted_read(struct SessionContext* session, unsigned char* return buffer_size; } +/*** + * Send the protocol string to the remote stream + * @param session the context + * @returns true(1) on success, false(0) otherwise + */ +int libp2p_secio_send_protocol(struct SessionContext* session) { + char* protocol = "/secio/1.0.0\n"; + int protocol_len = strlen(protocol); + return session->default_stream->write(session, (unsigned char *)protocol, protocol_len); +} + +/*** + * Attempt to read the secio protocol as a reply from the remote + * @param session the context + * @returns true(1) if we received what we think we should have, false(0) otherwise + */ +int libp2p_secio_receive_protocol(struct SessionContext* session) { + char* protocol = "/secio/1.0.0\n"; + int numSecs = 30; + unsigned char* buffer = NULL; + size_t buffer_size = 0; + int retVal = session->default_stream->read(session, &buffer, &buffer_size, numSecs); + if (retVal == 0 || buffer != NULL) { + if (strncmp(protocol, (char*)buffer, strlen(protocol)) == 0) + return 1; + } + return 0; +} + /** * Initialize state for the sha256 stream cipher * @param session the SessionContext struct that contains the variables to initialize