diff --git a/conn/dialer.c b/conn/dialer.c index 3b7a6c3..c22b5c7 100644 --- a/conn/dialer.c +++ b/conn/dialer.c @@ -9,6 +9,7 @@ #include "libp2p/conn/transport_dialer.h" #include "libp2p/crypto/key.h" #include "libp2p/utils/linked_list.h" +#include "libp2p/utils/logger.h" #include "multiaddr/multiaddr.h" #include "libp2p/net/multistream.h" #include "libp2p/secio/secio.h" @@ -144,9 +145,17 @@ int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer // kademlia over yamux // circuit relay over yamux return 1; + } else { + libp2p_logger_error("dialer", "Unable to do yamux negotiation.\n"); } + } else { + libp2p_logger_error("dialer", "Unable to do secio/multistream negotiation.\n"); } + } else { + libp2p_logger_error("dialer", "Unable to do secio negotiation.\n"); } + } else { + libp2p_logger_error("dialer", "Unable to do initial multistream negotiation.\n"); } return 0; diff --git a/include/libp2p/net/stream.h b/include/libp2p/net/stream.h index 5936a0a..a6a920a 100644 --- a/include/libp2p/net/stream.h +++ b/include/libp2p/net/stream.h @@ -91,7 +91,7 @@ struct Stream { * Checks to see if something is waiting on the stream * * @param stream the stream context - * @returns true(1) if something is waiting, false(0) otherwise + * @returns true(1) if something is waiting, false(0) if not, -1 on error */ int (*peek)(void* stream_context); }; diff --git a/net/connectionstream.c b/net/connectionstream.c index 779b24a..6884f9c 100644 --- a/net/connectionstream.c +++ b/net/connectionstream.c @@ -8,8 +8,10 @@ #include #include #include +#include #include "libp2p/net/stream.h" #include "libp2p/net/p2pnet.h" +#include "libp2p/utils/logger.h" #include "multiaddr/multiaddr.h" /** @@ -47,8 +49,10 @@ int libp2p_net_connection_peek(void* stream_context) { return -1; int bytes = 0; - if (ioctl(socket_fd, FIONREAD, &bytes) < 0) { + int retVal = ioctl(socket_fd, FIONREAD, &bytes); + if (retVal < 0) { // Ooff, we're having problems. Don't use this socket again. + libp2p_logger_error("connectionstream", "Attempted a peek, but ioctl reported %s.\n", strerror(errno)); return -1; } return bytes; diff --git a/net/multistream.c b/net/multistream.c index e1cfeda..2facd5a 100644 --- a/net/multistream.c +++ b/net/multistream.c @@ -249,7 +249,7 @@ int libp2p_net_multistream_read(void* stream_context, struct StreamMessage** res size_t num_bytes_requested = 0; size_t varint_length = 0; for(int i = 0; i < 12; i++) { - if (!parent_stream->read_raw(parent_stream->stream_context, &varint[i], 1, timeout_secs)) { + if (parent_stream->read_raw(parent_stream->stream_context, &varint[i], 1, timeout_secs) == -1) { return 0; } if (varint[i] >> 7 == 0) { @@ -363,17 +363,45 @@ int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx) { struct StreamMessage outgoing; struct StreamMessage* results = NULL; int retVal = 0; + int haveTheirs = 0; + int peek_result = 0; + + // see if they're trying to send something first + peek_result = libp2p_net_multistream_peek(ctx); + /* + if (peek_result < 0) { + libp2p_logger_error("multistream", "Attempted a peek, but received an error.\n"); + return 0; + } + */ + if (peek_result > 0) { + libp2p_logger_debug("multistream", "There is %d bytes waiting for us. Perhaps it is the multistream header we're expecting.\n", peek_result); + // get the protocol + //ctx->stream->parent_stream->read(ctx->stream->parent_stream->stream_context, &results, multistream_default_timeout); + libp2p_net_multistream_read(ctx, &results, multistream_default_timeout); + if (results == NULL || results->data_size == 0) + goto exit; + if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0) + goto exit; + haveTheirs = 1; + } + // send the protocol id outgoing.data = (uint8_t*)protocolID; outgoing.data_size = strlen(protocolID); if (!libp2p_net_multistream_write(ctx, &outgoing)) goto exit; - // expect the same back - libp2p_net_multistream_read(ctx, &results, multistream_default_timeout); - if (results == NULL || results->data_size == 0) - goto exit; - if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0) - goto exit; + + // wait for them to send the protocol id back + if (!haveTheirs) { + // expect the same back + libp2p_net_multistream_read(ctx, &results, multistream_default_timeout); + if (results == NULL || results->data_size == 0) + goto exit; + if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0) + goto exit; + } + retVal = 1; exit: if (results != NULL) @@ -388,6 +416,13 @@ void libp2p_net_multistream_stream_free(struct Stream* stream) { } } +int libp2p_net_multistream_read_raw(void* stream_context, uint8_t* buffer, int buffer_len, int timeout_secs) { + if (stream_context == NULL) + return 0; + struct MultistreamContext* ctx = (struct MultistreamContext*) stream_context; + return ctx->stream->parent_stream->read_raw(ctx->stream->parent_stream->stream_context, buffer, buffer_len, timeout_secs); +} + /** * Create a new MultiStream structure * @param socket_fd the file descriptor @@ -402,6 +437,7 @@ struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream) { out->read = libp2p_net_multistream_read; out->write = libp2p_net_multistream_write; out->peek = libp2p_net_multistream_peek; + out->read_raw = libp2p_net_multistream_read_raw; out->address = parent_stream->address; // build MultistreamContext struct MultistreamContext* ctx = (struct MultistreamContext*) malloc(sizeof(struct MultistreamContext)); diff --git a/secio/secio.c b/secio/secio.c index abf61a3..580c193 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -35,6 +35,9 @@ const char* SupportedExchanges = "P-256,P-384,P-521"; const char* SupportedCiphers = "AES-256,AES-128,Blowfish"; const char* SupportedHashes = "SHA256,SHA512"; +static struct StreamMessage* secio_buffered_message; +static size_t secio_buffered_message_pos = -1; + int libp2p_secio_can_handle(const struct StreamMessage* msg) { const char* protocol = "/secio/1.0.0"; // sanity checks @@ -1298,6 +1301,41 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) { return retVal; } +int libp2p_secio_peek(void* stream_context) { + if (stream_context == NULL) { + return -1; + } + struct SecioContext* ctx = (struct SecioContext*)stream_context; + return ctx->stream->parent_stream->peek(ctx->stream->parent_stream->stream_context); +} + +int libp2p_secio_read_raw(void* stream_context, uint8_t* buffer, int buffer_size, int timeout_secs) { + if (stream_context == NULL) { + return -1; + } + struct SecioContext* ctx = (struct SecioContext*)stream_context; + if (secio_buffered_message_pos == -1) { + // we need to get info from the network + if (!ctx->stream->read(ctx->stream->stream_context, &secio_buffered_message, timeout_secs)) { + return -1; + } + secio_buffered_message_pos = 0; + } + int max_to_read = (buffer_size > secio_buffered_message->data_size ? secio_buffered_message->data_size : buffer_size); + memcpy(buffer, &secio_buffered_message->data[secio_buffered_message_pos], max_to_read); + secio_buffered_message_pos += max_to_read; + if (secio_buffered_message_pos == secio_buffered_message->data_size) { + // we read everything + libp2p_stream_message_free(secio_buffered_message); + secio_buffered_message = NULL; + secio_buffered_message_pos = -1; + } else { + // we didn't read everything. + secio_buffered_message_pos = max_to_read; + } + return max_to_read; +} + /*** * Initiates a secio handshake. Use this method when you want to initiate a secio * session. This should not be used to respond to incoming secio requests @@ -1323,9 +1361,9 @@ struct Stream* libp2p_secio_stream_new(struct Stream* parent_stream, struct Libp ctx->private_key = rsa_private_key; new_stream->parent_stream = parent_stream; new_stream->close = libp2p_secio_shutdown; - new_stream->peek = libp2p_net_connection_peek; + new_stream->peek = libp2p_secio_peek; new_stream->read = libp2p_secio_encrypted_read; - new_stream->read_raw = libp2p_net_connection_read_raw; + new_stream->read_raw = libp2p_secio_read_raw; new_stream->write = libp2p_secio_encrypted_write; if (!libp2p_secio_send_protocol(ctx) || !libp2p_secio_receive_protocol(ctx)