diff --git a/Makefile b/Makefile index f918bf8..192abfb 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ OBJS = \ db/*.o \ thirdparty/mbedtls/*.o \ hashmap/hashmap.o \ + identify/*.o \ net/*.o \ os/*.o \ peer/*.o \ @@ -29,6 +30,7 @@ compile: cd db; make all; cd thirdparty; make all; cd hashmap; make all; + cd identify; make all; cd net; make all; cd os; make all; cd peer; make all; @@ -50,6 +52,7 @@ clean: cd crypto; make clean; cd db; make clean; cd hashmap; make clean; + cd identify; make clean; cd net; make clean; cd os; make clean; cd peer; make clean; diff --git a/identify/Makefile b/identify/Makefile new file mode 100644 index 0000000..e15ce81 --- /dev/null +++ b/identify/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CFLAGS = -O0 -Wall -Werror -I../include -I../../c-protobuf -std=c11 + +ifdef DEBUG +CFLAGS += -g3 +endif + +LFLAGS = +DEPS = +OBJS = identify.o + +%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) + +all: $(OBJS) + +clean: + rm -f *.o diff --git a/identify/identify.c b/identify/identify.c new file mode 100644 index 0000000..e625641 --- /dev/null +++ b/identify/identify.c @@ -0,0 +1,94 @@ +#include + +#include "varint.h" +#include "libp2p/net/protocol.h" +#include "libp2p/net/protocol.h" +#include "libp2p/utils/vector.h" +#include "libp2p/net/stream.h" +#include "libp2p/conn/session.h" +#include "libp2p/identify/identify.h" +#include "libp2p/utils/logger.h" + +/** + * 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 libp2p_identify_can_handle(const struct StreamMessage* msg) { + const char *protocol = "/ipfs/id/1.0.0\n"; + int protocol_size = strlen(protocol); + // is there a varint in front? + size_t num_bytes = 0; + if (msg->data[0] != protocol[0] && msg->data[1] != protocol[1]) { + varint_decode(msg->data, msg->data_size, &num_bytes); + } + if (msg->data_size >= protocol_size - num_bytes) { + if (strncmp(protocol, (char*) &msg->data[num_bytes], protocol_size) == 0) + return 1; + } + return 0; +} + +/*** + * Send the identify header out the default stream + * @param context the context + * @returns true(1) on success, false(0) otherwise + */ +int libp2p_identify_send_protocol(struct SessionContext *context) { + char *protocol = "/ipfs/id/1.0.0\n"; + struct StreamMessage msg; + msg.data = (uint8_t*) protocol; + msg.data_size = strlen(protocol); + if (!context->default_stream->write(context, &msg)) { + libp2p_logger_error("identify", "send_protocol: Unable to send identify protocol header.\n"); + return 0; + } + return 1; +} + +/*** + * Check to see if the reply is the identify header we expect + * NOTE: if we initiate the connection, we should expect the same back + * @param context the SessionContext + * @returns true(1) on success, false(0) otherwise + */ +int libp2p_identify_receive_protocol(struct SessionContext* context) { + const char *protocol = "/ipfs/id/1.0.0\n"; + struct StreamMessage* results = NULL; + if (!context->default_stream->read(context, &results, 30)) { + libp2p_logger_error("identify", "receive_protocol: Unable to read results.\n"); + return 0; + } + // the first byte is the size, so skip it + char* ptr = strstr((char*)&results[1], protocol); + if (ptr == NULL || ptr - (char*)results > 1) { + return 0; + } + return 1; +} + +int libp2p_identify_handle_message(const struct StreamMessage* msg, struct SessionContext* context, void* protocol_context) { + //TODO: Implement + return 0; +} + +/** + * Shutting down. Clean up any memory allocations + * @param protocol_context the context + * @returns true(1) + */ +int libp2p_identify_shutdown(void* protocol_context) { + return 0; +} + +struct Libp2pProtocolHandler* libp2p_identify_build_protocol_handler(struct Libp2pVector* handlers) { + struct Libp2pProtocolHandler* handler = libp2p_protocol_handler_new(); + if (handler != NULL) { + handler->context = handlers; + handler->CanHandle = libp2p_identify_can_handle; + handler->HandleMessage = libp2p_identify_handle_message; + handler->Shutdown = libp2p_identify_shutdown; + } + return handler; +} diff --git a/include/libp2p/identify/identify.h b/include/libp2p/identify/identify.h new file mode 100644 index 0000000..a7f8110 --- /dev/null +++ b/include/libp2p/identify/identify.h @@ -0,0 +1,29 @@ +#pragma once + +typedef struct { + // publicKey is this node's public key (which also gives its node.ID) + // - may not need to be sent, as secure channel implies it has been sent. + // - then again, if we change / disable secure channel, may still want it. + char *PublicKey; + // listenAddrs are the multiaddrs the sender node listens for open connections on + char **ListenAddrs; + // protocols are the services this node is running + char **Protocols; + // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives + // this is useful information to convey to the other side, as it helps the remote endpoint + // determine whether its connection to the local peer goes through NAT. + char *ObservedAddr; + // protocolVersion determines compatibility between peers + char *ProtocolVersion; + // agentVersion is like a UserAgent string in browsers, or client version in bittorrent + // includes the client name and client. + char *AgentVersion; + char *XXX_unrecognized; +} Identify; + +int libp2p_identify_can_handle(const struct StreamMessage* msg); +int libp2p_identify_send_protocol(struct SessionContext *context); +int libp2p_identify_receive_protocol(struct SessionContext* context); +int libp2p_identify_handle_message(const struct StreamMessage* msg, struct SessionContext* context, void* protocol_context); +int libp2p_identify_shutdown(void* protocol_context); +struct Libp2pProtocolHandler* libp2p_identify_build_protocol_handler(struct Libp2pVector* handlers);