More updates to the yamux protocol
This commit is contained in:
parent
2d74c53b62
commit
e05e02188a
12 changed files with 437 additions and 97 deletions
|
@ -116,14 +116,14 @@ int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer
|
||||||
if (conn_stream == NULL)
|
if (conn_stream == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
// multistream
|
// multistream
|
||||||
struct Stream* new_stream = libp2p_net_multistream_stream_new(conn_stream);
|
struct Stream* new_stream = libp2p_net_multistream_stream_new(conn_stream, 0);
|
||||||
if (new_stream != NULL) {
|
if (new_stream != NULL) {
|
||||||
// secio over multistream
|
// secio over multistream
|
||||||
new_stream = libp2p_secio_stream_new(new_stream, peer, dialer->peerstore, dialer->private_key);
|
new_stream = libp2p_secio_stream_new(new_stream, peer, dialer->peerstore, dialer->private_key);
|
||||||
if (new_stream != NULL) {
|
if (new_stream != NULL) {
|
||||||
peer->sessionContext->default_stream = new_stream;
|
peer->sessionContext->default_stream = new_stream;
|
||||||
// multistream over secio
|
// multistream over secio
|
||||||
new_stream = libp2p_net_multistream_stream_new(new_stream);
|
new_stream = libp2p_net_multistream_stream_new(new_stream, 0);
|
||||||
if (new_stream != NULL) {
|
if (new_stream != NULL) {
|
||||||
peer->sessionContext->default_stream = new_stream;
|
peer->sessionContext->default_stream = new_stream;
|
||||||
// yamux over multistream
|
// yamux over multistream
|
||||||
|
|
|
@ -397,7 +397,7 @@ struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream) {
|
||||||
struct Stream* libp2p_identify_stream_new_with_multistream(struct Stream* parent_stream) {
|
struct Stream* libp2p_identify_stream_new_with_multistream(struct Stream* parent_stream) {
|
||||||
if (parent_stream == NULL)
|
if (parent_stream == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
struct Stream* multistream = libp2p_net_multistream_stream_new(parent_stream);
|
struct Stream* multistream = libp2p_net_multistream_stream_new(parent_stream, 0);
|
||||||
struct Stream* out = libp2p_stream_new();
|
struct Stream* out = libp2p_stream_new();
|
||||||
if (out != NULL) {
|
if (out != NULL) {
|
||||||
out->stream_type = STREAM_TYPE_IDENTIFY;
|
out->stream_type = STREAM_TYPE_IDENTIFY;
|
||||||
|
|
|
@ -83,10 +83,11 @@ struct Stream* libp2p_net_multistream_connect_with_timeout(const char* hostname,
|
||||||
* NOTE: the SessionContext should already contain the connected stream. If not, use
|
* NOTE: the SessionContext should already contain the connected stream. If not, use
|
||||||
* libp2p_net_multistream_connect instead of this method.
|
* libp2p_net_multistream_connect instead of this method.
|
||||||
*
|
*
|
||||||
* @param ctx the MultistreamContext
|
* @param ctx a MultistreamContext
|
||||||
|
* @param theyRequested true(1) if the multistream ID has already been received from the client
|
||||||
* @returns true(1) on success, or false(0)
|
* @returns true(1) on success, or false(0)
|
||||||
*/
|
*/
|
||||||
int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx);
|
int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx, int theyRequested);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expect to read a message, and follow its instructions
|
* Expect to read a message, and follow its instructions
|
||||||
|
@ -104,6 +105,12 @@ struct KademliaMessage* libp2p_net_multistream_get_message(struct Stream* stream
|
||||||
*/
|
*/
|
||||||
struct StreamMessage* libp2p_net_multistream_prepare_to_send(struct StreamMessage* incoming);
|
struct StreamMessage* libp2p_net_multistream_prepare_to_send(struct StreamMessage* incoming);
|
||||||
|
|
||||||
struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream);
|
/**
|
||||||
|
* Create a new MultiStream structure
|
||||||
|
* @param parent_stream the stream
|
||||||
|
* @param they_requested true(1) if they requested it (i.e. protocol id has already been sent)
|
||||||
|
* @returns the new Stream
|
||||||
|
*/
|
||||||
|
struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream, int theyRequested);
|
||||||
|
|
||||||
void libp2p_net_multistream_stream_free(struct Stream* stream);
|
void libp2p_net_multistream_stream_free(struct Stream* stream);
|
||||||
|
|
|
@ -24,6 +24,13 @@ struct YamuxContext {
|
||||||
int am_server;
|
int am_server;
|
||||||
int state; // the state of the connection
|
int state; // the state of the connection
|
||||||
struct Libp2pVector* protocol_handlers;
|
struct Libp2pVector* protocol_handlers;
|
||||||
|
/**
|
||||||
|
* What is stored here is from a read_raw call. It could
|
||||||
|
* be garbage, but it could be a decent message. It has
|
||||||
|
* been "unframed" so contains the data portion of the
|
||||||
|
* last frame captured in a read_raw call, or if it was
|
||||||
|
* empty, the data from a new read call.
|
||||||
|
*/
|
||||||
struct StreamMessage* buffered_message;
|
struct StreamMessage* buffered_message;
|
||||||
long buffered_message_pos;
|
long buffered_message_pos;
|
||||||
};
|
};
|
||||||
|
@ -36,7 +43,7 @@ struct YamuxChannelContext {
|
||||||
// the child protocol's stream
|
// the child protocol's stream
|
||||||
struct Stream* child_stream;
|
struct Stream* child_stream;
|
||||||
// the channel number
|
// the channel number
|
||||||
int channel;
|
uint32_t channel;
|
||||||
// the window size for this channel
|
// the window size for this channel
|
||||||
int window_size;
|
int window_size;
|
||||||
// the state of the connection
|
// the state of the connection
|
||||||
|
|
|
@ -73,9 +73,10 @@ int libp2p_net_connection_read(void* stream_context, struct StreamMessage** msg,
|
||||||
int current_size = 0;
|
int current_size = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
int retVal = socket_read(ctx->socket_descriptor, (char*)&buffer[0], 4096, 0, timeout_secs);
|
int retVal = socket_read(ctx->socket_descriptor, (char*)&buffer[0], 4096, 0, timeout_secs);
|
||||||
|
libp2p_logger_debug("connectionstream", "Retrieved %d bytes from socket %d.\n", retVal, ctx->socket_descriptor);
|
||||||
if (retVal < 1) { // get out of the loop
|
if (retVal < 1) { // get out of the loop
|
||||||
if (retVal < 0) // error
|
if (retVal < 0) // error
|
||||||
return -1;
|
return 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// add what we got to the message
|
// add what we got to the message
|
||||||
|
@ -104,13 +105,14 @@ int libp2p_net_connection_read(void* stream_context, struct StreamMessage** msg,
|
||||||
*msg = libp2p_stream_message_new();
|
*msg = libp2p_stream_message_new();
|
||||||
struct StreamMessage* result = *msg;
|
struct StreamMessage* result = *msg;
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
|
libp2p_logger_error("connectionstream", "read: Attempted to allocate memory for message, but allocation failed.\n");
|
||||||
free(result_buffer);
|
free(result_buffer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
result->data = result_buffer;
|
result->data = result_buffer;
|
||||||
result->data_size = current_size;
|
result->data_size = current_size;
|
||||||
result->error_number = 0;
|
result->error_number = 0;
|
||||||
libp2p_logger_debug("connectionstream", "libp2p_connectionstream_read: Received %d bytes", result->data_size);
|
libp2p_logger_debug("connectionstream", "libp2p_connectionstream_read: Received %d bytes from socket %d.\n", result->data_size, ctx->socket_descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return current_size;
|
return current_size;
|
||||||
|
@ -148,9 +150,12 @@ int libp2p_net_connection_read_raw(void* stream_context, uint8_t* buffer, int bu
|
||||||
* @returns number of bytes written
|
* @returns number of bytes written
|
||||||
*/
|
*/
|
||||||
int libp2p_net_connection_write(void* stream_context, struct StreamMessage* msg) {
|
int libp2p_net_connection_write(void* stream_context, struct StreamMessage* msg) {
|
||||||
if (stream_context == NULL)
|
if (stream_context == NULL) {
|
||||||
|
libp2p_logger_error("connectionstream", "write called with no context.\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
struct ConnectionContext* ctx = (struct ConnectionContext*) stream_context;
|
struct ConnectionContext* ctx = (struct ConnectionContext*) stream_context;
|
||||||
|
libp2p_logger_debug("connectionstream", "write: About to write %d bytes to socket %d.\n", msg->data_size, ctx->socket_descriptor);
|
||||||
return socket_write(ctx->socket_descriptor, (char*)msg->data, msg->data_size, 0);
|
return socket_write(ctx->socket_descriptor, (char*)msg->data, msg->data_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,8 @@ int libp2p_net_multistream_shutdown(void* protocol_context) {
|
||||||
* @returns true(1) on success, otherwise false(0)
|
* @returns true(1) on success, otherwise false(0)
|
||||||
*/
|
*/
|
||||||
int libp2p_net_multistream_context_free(struct MultistreamContext* ctx) {
|
int libp2p_net_multistream_context_free(struct MultistreamContext* ctx) {
|
||||||
int retVal = ctx->stream->close(ctx->stream);
|
struct Stream* parent_stream = ctx->stream->parent_stream;
|
||||||
|
int retVal = parent_stream->close(parent_stream);
|
||||||
// regardless of retVal, free the context
|
// regardless of retVal, free the context
|
||||||
// TODO: Evaluate if this is the correct way to do it:
|
// TODO: Evaluate if this is the correct way to do it:
|
||||||
free(ctx);
|
free(ctx);
|
||||||
|
@ -200,6 +201,7 @@ int libp2p_net_multistream_read(void* stream_context, struct StreamMessage** res
|
||||||
size_t varint_length = 0;
|
size_t varint_length = 0;
|
||||||
for(int i = 0; i < 12; i++) {
|
for(int i = 0; i < 12; i++) {
|
||||||
if (parent_stream->read_raw(parent_stream->stream_context, &varint[i], 1, timeout_secs) == -1) {
|
if (parent_stream->read_raw(parent_stream->stream_context, &varint[i], 1, timeout_secs) == -1) {
|
||||||
|
libp2p_logger_debug("multistream", "read->read_raw returned false.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (varint[i] >> 7 == 0) {
|
if (varint[i] >> 7 == 0) {
|
||||||
|
@ -217,11 +219,13 @@ int libp2p_net_multistream_read(void* stream_context, struct StreamMessage** res
|
||||||
rslts->data_size = num_bytes_requested;
|
rslts->data_size = num_bytes_requested;
|
||||||
rslts->data = (uint8_t*) malloc(num_bytes_requested);
|
rslts->data = (uint8_t*) malloc(num_bytes_requested);
|
||||||
if (rslts->data == NULL) {
|
if (rslts->data == NULL) {
|
||||||
|
libp2p_logger_error("multistream", "read: Attempted allocation of stream message failed.\n");
|
||||||
libp2p_stream_message_free(rslts);
|
libp2p_stream_message_free(rslts);
|
||||||
rslts = NULL;
|
rslts = NULL;
|
||||||
}
|
}
|
||||||
// now get the data from the parent stream
|
// now get the data from the parent stream
|
||||||
if (!parent_stream->read_raw(parent_stream->stream_context, rslts->data, rslts->data_size, timeout_secs)) {
|
if (!parent_stream->read_raw(parent_stream->stream_context, rslts->data, rslts->data_size, timeout_secs)) {
|
||||||
|
libp2p_logger_error("multistream", "read: Was supposed to read %d bytes, but read_raw returned false.\n", num_bytes_requested);
|
||||||
// problem reading from the parent stream
|
// problem reading from the parent stream
|
||||||
libp2p_stream_message_free(*results);
|
libp2p_stream_message_free(*results);
|
||||||
*results = NULL;
|
*results = NULL;
|
||||||
|
@ -306,9 +310,10 @@ struct Stream* libp2p_net_multistream_connect_with_timeout(const char* hostname,
|
||||||
* libp2p_net_multistream_connect instead of this method.
|
* libp2p_net_multistream_connect instead of this method.
|
||||||
*
|
*
|
||||||
* @param ctx a MultistreamContext
|
* @param ctx a MultistreamContext
|
||||||
|
* @param theyRequested true(1) if the multistream ID has already been received from the client
|
||||||
* @returns true(1) on success, or false(0)
|
* @returns true(1) on success, or false(0)
|
||||||
*/
|
*/
|
||||||
int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx) {
|
int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx, int theyRequested) {
|
||||||
const char* protocolID = "/multistream/1.0.0\n";
|
const char* protocolID = "/multistream/1.0.0\n";
|
||||||
struct StreamMessage outgoing;
|
struct StreamMessage outgoing;
|
||||||
struct StreamMessage* results = NULL;
|
struct StreamMessage* results = NULL;
|
||||||
|
@ -316,6 +321,7 @@ int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx) {
|
||||||
int haveTheirs = 0;
|
int haveTheirs = 0;
|
||||||
int peek_result = 0;
|
int peek_result = 0;
|
||||||
|
|
||||||
|
if (!theyRequested) {
|
||||||
// see if they're trying to send something first
|
// see if they're trying to send something first
|
||||||
peek_result = libp2p_net_multistream_peek(ctx);
|
peek_result = libp2p_net_multistream_peek(ctx);
|
||||||
/*
|
/*
|
||||||
|
@ -325,7 +331,7 @@ int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (peek_result > 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);
|
libp2p_logger_debug("multistream", "negotiate: There is %d bytes waiting for us. Perhaps it is the multistream header we're expecting.\n", peek_result);
|
||||||
// get the protocol
|
// get the protocol
|
||||||
//ctx->stream->parent_stream->read(ctx->stream->parent_stream->stream_context, &results, multistream_default_timeout);
|
//ctx->stream->parent_stream->read(ctx->stream->parent_stream->stream_context, &results, multistream_default_timeout);
|
||||||
libp2p_net_multistream_read(ctx, &results, multistream_default_timeout);
|
libp2p_net_multistream_read(ctx, &results, multistream_default_timeout);
|
||||||
|
@ -335,22 +341,29 @@ int libp2p_net_multistream_negotiate(struct MultistreamContext* ctx) {
|
||||||
goto exit;
|
goto exit;
|
||||||
haveTheirs = 1;
|
haveTheirs = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// send the protocol id
|
// send the protocol id
|
||||||
outgoing.data = (uint8_t*)protocolID;
|
outgoing.data = (uint8_t*)protocolID;
|
||||||
outgoing.data_size = strlen(protocolID);
|
outgoing.data_size = strlen(protocolID);
|
||||||
if (!libp2p_net_multistream_write(ctx, &outgoing))
|
if (!libp2p_net_multistream_write(ctx, &outgoing)) {
|
||||||
|
libp2p_logger_debug("multistream", "negotiate: Attempted to send the multistream id, but the write failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
// wait for them to send the protocol id back
|
// wait for them to send the protocol id back
|
||||||
if (!haveTheirs) {
|
if (!theyRequested && !haveTheirs) {
|
||||||
|
libp2p_logger_debug("multistream", "negotiate: Wrote multistream id to network, awaiting reply...\n");
|
||||||
// expect the same back
|
// expect the same back
|
||||||
libp2p_net_multistream_read(ctx, &results, multistream_default_timeout);
|
int retVal = libp2p_net_multistream_read(ctx, &results, multistream_default_timeout);
|
||||||
if (results == NULL || results->data_size == 0)
|
if (retVal == 0 || results == NULL || results->data_size == 0) {
|
||||||
|
libp2p_logger_debug("multistream", "negotiate: expected the multistream id back, but got nothing. RetVal: %d.\n", retVal);
|
||||||
goto exit;
|
goto exit;
|
||||||
if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0)
|
}
|
||||||
|
if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0) {
|
||||||
|
libp2p_logger_debug("multistream", "negotiate: Expected the multistream id back, but did not receive it. We did receive %d bytes though.\n)", results->data_size);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retVal = 1;
|
retVal = 1;
|
||||||
exit:
|
exit:
|
||||||
|
@ -374,12 +387,20 @@ int libp2p_net_multistream_read_raw(void* stream_context, uint8_t* buffer, int b
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new MultiStream structure
|
* We want to try and negotiate Multistream on the incoming stream
|
||||||
* @param socket_fd the file descriptor
|
|
||||||
* @param ip the IP address
|
|
||||||
* @param port the port
|
|
||||||
*/
|
*/
|
||||||
struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream) {
|
struct Stream* libp2p_net_multistream_handshake(struct Stream* stream) {
|
||||||
|
//TODO: implement this method
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new MultiStream structure
|
||||||
|
* @param parent_stream the stream
|
||||||
|
* @param they_requested true(1) if they requested it (i.e. protocol id has already been sent)
|
||||||
|
* @returns the new Stream
|
||||||
|
*/
|
||||||
|
struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream, int theyRequested) {
|
||||||
struct Stream* out = (struct Stream*)malloc(sizeof(struct Stream));
|
struct Stream* out = (struct Stream*)malloc(sizeof(struct Stream));
|
||||||
if (out != NULL) {
|
if (out != NULL) {
|
||||||
out->stream_type = STREAM_TYPE_MULTISTREAM;
|
out->stream_type = STREAM_TYPE_MULTISTREAM;
|
||||||
|
@ -389,6 +410,7 @@ struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream) {
|
||||||
out->write = libp2p_net_multistream_write;
|
out->write = libp2p_net_multistream_write;
|
||||||
out->peek = libp2p_net_multistream_peek;
|
out->peek = libp2p_net_multistream_peek;
|
||||||
out->read_raw = libp2p_net_multistream_read_raw;
|
out->read_raw = libp2p_net_multistream_read_raw;
|
||||||
|
out->negotiate = libp2p_net_multistream_handshake;
|
||||||
out->address = parent_stream->address;
|
out->address = parent_stream->address;
|
||||||
// build MultistreamContext
|
// build MultistreamContext
|
||||||
struct MultistreamContext* ctx = (struct MultistreamContext*) malloc(sizeof(struct MultistreamContext));
|
struct MultistreamContext* ctx = (struct MultistreamContext*) malloc(sizeof(struct MultistreamContext));
|
||||||
|
@ -401,7 +423,8 @@ struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream) {
|
||||||
ctx->handlers = NULL;
|
ctx->handlers = NULL;
|
||||||
ctx->session_context = NULL;
|
ctx->session_context = NULL;
|
||||||
// attempt to negotiate multistream protocol
|
// attempt to negotiate multistream protocol
|
||||||
if (!libp2p_net_multistream_negotiate(ctx)) {
|
if (!libp2p_net_multistream_negotiate(ctx, theyRequested)) {
|
||||||
|
libp2p_logger_debug("multistream", "multistream_stream_new: negotiate failed\n");
|
||||||
libp2p_net_multistream_stream_free(out);
|
libp2p_net_multistream_stream_free(out);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -418,18 +441,17 @@ struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream) {
|
||||||
*/
|
*/
|
||||||
int libp2p_net_multistream_handle_message(const struct StreamMessage* msg, struct Stream* stream, void* protocol_context) {
|
int libp2p_net_multistream_handle_message(const struct StreamMessage* msg, struct Stream* stream, void* protocol_context) {
|
||||||
// attempt negotiations
|
// attempt negotiations
|
||||||
struct Stream* new_stream = libp2p_net_multistream_stream_new(stream);
|
struct Stream* new_stream = libp2p_net_multistream_stream_new(stream, 1);
|
||||||
if (new_stream != NULL) {
|
if (new_stream != NULL) {
|
||||||
// upgrade
|
// upgrade
|
||||||
return stream->handle_upgrade(stream, new_stream);
|
return stream->handle_upgrade(stream, new_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* The handler to handle calls to the protocol
|
* The handler to handle calls to the protocol
|
||||||
* @param stream_context the context
|
* @param handler_vector a Libp2pVector of protocol handlers
|
||||||
* @returns the protocol handler
|
* @returns the protocol handler
|
||||||
*/
|
*/
|
||||||
struct Libp2pProtocolHandler* libp2p_net_multistream_build_protocol_handler(void* handler_vector) {
|
struct Libp2pProtocolHandler* libp2p_net_multistream_build_protocol_handler(void* handler_vector) {
|
||||||
|
|
12
net/server.c
12
net/server.c
|
@ -60,20 +60,24 @@ void libp2p_net_connection (void *ptr) {
|
||||||
|
|
||||||
libp2p_logger_info("null", "Connection %d, count %d\n", connection_param->file_descriptor, connection_param->count);
|
libp2p_logger_info("null", "Connection %d, count %d\n", connection_param->file_descriptor, connection_param->count);
|
||||||
|
|
||||||
//TODO: build a stream from the given information
|
struct SessionContext sessionContext;
|
||||||
struct Stream* clientStream = libp2p_net_connection_established(connection_param->file_descriptor, connection_param->ip, connection_param->port, NULL);
|
struct Stream* clientStream = libp2p_net_connection_established(connection_param->file_descriptor, connection_param->ip, connection_param->port, &sessionContext);
|
||||||
|
sessionContext.default_stream = clientStream;
|
||||||
|
|
||||||
|
if (sessionContext.default_stream == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
// try to read from the network
|
// try to read from the network
|
||||||
struct StreamMessage *results = NULL;
|
struct StreamMessage *results = NULL;
|
||||||
// handle the call
|
// handle the call
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Read from the network
|
// Read from the network
|
||||||
if (!clientStream->read(clientStream->stream_context, &results, DEFAULT_NETWORK_TIMEOUT)) {
|
if (!sessionContext.default_stream->read(sessionContext.default_stream->stream_context, &results, DEFAULT_NETWORK_TIMEOUT)) {
|
||||||
// problem reading
|
// problem reading
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (results != NULL) {
|
if (results != NULL) {
|
||||||
retVal = libp2p_protocol_marshal(results, clientStream, connection_param->protocol_handlers);
|
retVal = libp2p_protocol_marshal(results, sessionContext.default_stream, connection_param->protocol_handlers);
|
||||||
libp2p_stream_message_free(results);
|
libp2p_stream_message_free(results);
|
||||||
results = NULL;
|
results = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,6 +356,11 @@ int test_yamux_client_server_connect() {
|
||||||
fprintf(stderr, "Was supposed to get yamux protocol id, but instead received nothing.\n");
|
fprintf(stderr, "Was supposed to get yamux protocol id, but instead received nothing.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
//TODO: make sure everything is negotiated and yamux is in a happy state
|
||||||
|
// hangup
|
||||||
|
yamux_stream->close(yamux_stream);
|
||||||
|
// for debugging
|
||||||
|
// sleep(30);
|
||||||
retVal = 1;
|
retVal = 1;
|
||||||
exit:
|
exit:
|
||||||
libp2p_net_server_stop();
|
libp2p_net_server_stop();
|
||||||
|
@ -365,3 +370,132 @@ int test_yamux_client_server_connect() {
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_yamux_client_server_multistream() {
|
||||||
|
int retVal = 0;
|
||||||
|
struct Libp2pVector* protocol_handlers = NULL;
|
||||||
|
struct StreamMessage* resultMessage = NULL;
|
||||||
|
|
||||||
|
libp2p_logger_add_class("connectionstream");
|
||||||
|
libp2p_logger_add_class("multistream");
|
||||||
|
libp2p_logger_add_class("yamux");
|
||||||
|
|
||||||
|
// setup
|
||||||
|
// build the protocol handler that can handle yamux
|
||||||
|
protocol_handlers = libp2p_utils_vector_new(1);
|
||||||
|
struct Libp2pProtocolHandler* handler = libp2p_yamux_build_protocol_handler(protocol_handlers);
|
||||||
|
libp2p_utils_vector_add(protocol_handlers, handler);
|
||||||
|
handler = libp2p_net_multistream_build_protocol_handler(protocol_handlers);
|
||||||
|
libp2p_utils_vector_add(protocol_handlers, handler);
|
||||||
|
// set up server
|
||||||
|
libp2p_net_server_start("127.0.0.1", 1234, protocol_handlers);
|
||||||
|
sleep(1);
|
||||||
|
// set up client (easiest to use transport dialers)
|
||||||
|
struct Dialer* dialer = libp2p_conn_dialer_new(NULL, NULL, NULL);
|
||||||
|
struct MultiAddress* server_ma = multiaddress_new_from_string("/ip4/127.0.0.1/tcp/1234");
|
||||||
|
struct Stream* stream = libp2p_conn_dialer_get_connection(dialer, server_ma);
|
||||||
|
if (stream == NULL) {
|
||||||
|
fprintf(stderr, "Unable to get stream.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// have client attempt to connect to server and negotiate yamux
|
||||||
|
struct Stream* yamux_stream = libp2p_yamux_stream_new(stream, 0, protocol_handlers);
|
||||||
|
if (yamux_stream == NULL) {
|
||||||
|
fprintf(stderr, "Was supposed to get yamux protocol id, but instead received nothing.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// now attempt multistream
|
||||||
|
struct Stream* multistream = libp2p_net_multistream_stream_new(yamux_stream, 0);
|
||||||
|
if (multistream == NULL) {
|
||||||
|
fprintf(stderr, "Was supposed to get a multistream, but instead got NULL.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// shut down nicely
|
||||||
|
multistream->close(multistream);
|
||||||
|
retVal = 1;
|
||||||
|
exit:
|
||||||
|
libp2p_net_server_stop();
|
||||||
|
if (protocol_handlers != NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_yamux_multistream_server() {
|
||||||
|
int retVal = 0;
|
||||||
|
struct Libp2pVector* protocol_handlers = NULL;
|
||||||
|
struct StreamMessage* resultMessage = NULL;
|
||||||
|
|
||||||
|
libp2p_logger_add_class("connectionstream");
|
||||||
|
libp2p_logger_add_class("multistream");
|
||||||
|
libp2p_logger_add_class("yamux");
|
||||||
|
|
||||||
|
// setup
|
||||||
|
// build the protocol handler that can handle yamux
|
||||||
|
protocol_handlers = libp2p_utils_vector_new(1);
|
||||||
|
struct Libp2pProtocolHandler* handler = libp2p_yamux_build_protocol_handler(protocol_handlers);
|
||||||
|
libp2p_utils_vector_add(protocol_handlers, handler);
|
||||||
|
handler = libp2p_net_multistream_build_protocol_handler(protocol_handlers);
|
||||||
|
libp2p_utils_vector_add(protocol_handlers, handler);
|
||||||
|
// set up server
|
||||||
|
libp2p_net_server_start("127.0.0.1", 1234, protocol_handlers);
|
||||||
|
// debugging
|
||||||
|
sleep(120);
|
||||||
|
retVal = 1;
|
||||||
|
exit:
|
||||||
|
libp2p_net_server_stop();
|
||||||
|
if (protocol_handlers != NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
int test_yamux_multistream_client() {
|
||||||
|
int retVal = 0;
|
||||||
|
struct Libp2pVector* protocol_handlers = NULL;
|
||||||
|
struct StreamMessage* resultMessage = NULL;
|
||||||
|
|
||||||
|
libp2p_logger_add_class("connectionstream");
|
||||||
|
libp2p_logger_add_class("multistream");
|
||||||
|
libp2p_logger_add_class("yamux");
|
||||||
|
|
||||||
|
// setup
|
||||||
|
// build the protocol handler that can handle yamux
|
||||||
|
protocol_handlers = libp2p_utils_vector_new(1);
|
||||||
|
struct Libp2pProtocolHandler* handler = libp2p_yamux_build_protocol_handler(protocol_handlers);
|
||||||
|
libp2p_utils_vector_add(protocol_handlers, handler);
|
||||||
|
handler = libp2p_net_multistream_build_protocol_handler(protocol_handlers);
|
||||||
|
libp2p_utils_vector_add(protocol_handlers, handler);
|
||||||
|
// set up client (easiest to use transport dialers)
|
||||||
|
struct Dialer* dialer = libp2p_conn_dialer_new(NULL, NULL, NULL);
|
||||||
|
struct MultiAddress* server_ma = multiaddress_new_from_string("/ip4/127.0.0.1/tcp/1234");
|
||||||
|
struct Stream* stream = libp2p_conn_dialer_get_connection(dialer, server_ma);
|
||||||
|
if (stream == NULL) {
|
||||||
|
fprintf(stderr, "Unable to get stream.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// have client attempt to connect to server and negotiate yamux
|
||||||
|
struct Stream* yamux_stream = libp2p_yamux_stream_new(stream, 0, protocol_handlers);
|
||||||
|
if (yamux_stream == NULL) {
|
||||||
|
fprintf(stderr, "Was supposed to get yamux protocol id, but instead received nothing.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// now attempt multistream
|
||||||
|
struct Stream* multistream = libp2p_net_multistream_stream_new(yamux_stream, 0);
|
||||||
|
if (multistream == NULL) {
|
||||||
|
fprintf(stderr, "Was supposed to get a multistream, but instead got NULL.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// shut down nicely
|
||||||
|
multistream->close(multistream);
|
||||||
|
// debugging
|
||||||
|
sleep(30);
|
||||||
|
retVal = 1;
|
||||||
|
exit:
|
||||||
|
if (protocol_handlers != NULL) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -120,6 +120,9 @@ int build_test_collection() {
|
||||||
add_test("test_yamux_incoming_protocol_request", test_yamux_incoming_protocol_request, 1);
|
add_test("test_yamux_incoming_protocol_request", test_yamux_incoming_protocol_request, 1);
|
||||||
add_test("test_net_server_startup_shutdown", test_net_server_startup_shutdown, 1);
|
add_test("test_net_server_startup_shutdown", test_net_server_startup_shutdown, 1);
|
||||||
add_test("test_yamux_client_server_connect", test_yamux_client_server_connect, 1);
|
add_test("test_yamux_client_server_connect", test_yamux_client_server_connect, 1);
|
||||||
|
add_test("test_yamux_client_server_multistream", test_yamux_client_server_multistream, 1);
|
||||||
|
add_test("test_yamux_multistream_server", test_yamux_multistream_server, 0);
|
||||||
|
add_test("test_yamux_multistream_client", test_yamux_multistream_client, 0);
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "libp2p/yamux/session.h"
|
#include "libp2p/yamux/session.h"
|
||||||
#include "libp2p/yamux/stream.h"
|
#include "libp2p/yamux/stream.h"
|
||||||
#include "libp2p/yamux/yamux.h"
|
#include "libp2p/yamux/yamux.h"
|
||||||
|
#include "libp2p/utils/logger.h"
|
||||||
|
|
||||||
static struct yamux_config dcfg = YAMUX_DEFAULT_CONFIG;
|
static struct yamux_config dcfg = YAMUX_DEFAULT_CONFIG;
|
||||||
|
|
||||||
|
@ -283,12 +284,16 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
|
||||||
// if we didn't initiate it, add this new channel (odd stream id is from client, even is from server)
|
// if we didn't initiate it, add this new channel (odd stream id is from client, even is from server)
|
||||||
if ( (f.streamid % 2 == 0 && yamuxContext->am_server) || (f.streamid % 2 == 1 && yamuxContext->am_server) ) {
|
if ( (f.streamid % 2 == 0 && yamuxContext->am_server) || (f.streamid % 2 == 1 && yamuxContext->am_server) ) {
|
||||||
struct Stream* yamuxChannelStream = yamux_channel_new(yamuxContext, f.streamid, msg);
|
struct Stream* yamuxChannelStream = yamux_channel_new(yamuxContext, f.streamid, msg);
|
||||||
if (yamuxChannelStream == NULL)
|
if (yamuxChannelStream == NULL) {
|
||||||
|
libp2p_logger_error("yamux", "session->yamux_decode: Unable to create new yamux channel for stream id %d.\n", f.streamid);
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
}
|
||||||
struct YamuxChannelContext* channelContext = (struct YamuxChannelContext*)yamuxChannelStream->stream_context;
|
struct YamuxChannelContext* channelContext = (struct YamuxChannelContext*)yamuxChannelStream->stream_context;
|
||||||
|
|
||||||
if (yamux_session->new_stream_fn)
|
if (yamux_session->new_stream_fn) {
|
||||||
|
libp2p_logger_debug("yamux", "session->yamux_decode: Calling new_stream_fn.\n");
|
||||||
yamux_session->new_stream_fn(yamuxContext, yamuxContext->stream, msg);
|
yamux_session->new_stream_fn(yamuxContext, yamuxContext->stream, msg);
|
||||||
|
}
|
||||||
|
|
||||||
channelContext->state = yamux_stream_syn_recv;
|
channelContext->state = yamux_stream_syn_recv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,11 +81,12 @@ FOUND:;
|
||||||
};
|
};
|
||||||
*y_stream = nst;
|
*y_stream = nst;
|
||||||
|
|
||||||
|
/*
|
||||||
if (libp2p_protocol_marshal(msg, nst.stream, context->protocol_handlers) >= 0) {
|
if (libp2p_protocol_marshal(msg, nst.stream, context->protocol_handlers) >= 0) {
|
||||||
// success
|
// success
|
||||||
}
|
}
|
||||||
/*
|
*/
|
||||||
struct Stream* channelStream = libp2p_yamux_channel_stream_new(context->stream);
|
struct Stream* channelStream = libp2p_yamux_channel_stream_new(context->stream, id);
|
||||||
struct YamuxChannelContext* channel = (struct YamuxChannelContext*)channelStream->stream_context;
|
struct YamuxChannelContext* channel = (struct YamuxChannelContext*)channelStream->stream_context;
|
||||||
channel->channel = id;
|
channel->channel = id;
|
||||||
channel->child_stream = NULL;
|
channel->child_stream = NULL;
|
||||||
|
@ -93,8 +94,6 @@ FOUND:;
|
||||||
|
|
||||||
|
|
||||||
return channelStream;
|
return channelStream;
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -280,7 +279,7 @@ ssize_t yamux_stream_write(struct YamuxChannelContext* channel_ctx, uint32_t dat
|
||||||
char* data = (char*)data_;
|
char* data = (char*)data_;
|
||||||
char* data_end = data + data_length;
|
char* data_end = data + data_length;
|
||||||
uint32_t ws = channel_ctx->window_size;
|
uint32_t ws = channel_ctx->window_size;
|
||||||
int id = channel_ctx->channel;
|
uint32_t id = channel_ctx->channel;
|
||||||
|
|
||||||
char sendd[ws + sizeof(struct yamux_frame)];
|
char sendd[ws + sizeof(struct yamux_frame)];
|
||||||
|
|
||||||
|
|
236
yamux/yamux.c
236
yamux/yamux.c
|
@ -9,6 +9,42 @@
|
||||||
#include "libp2p/conn/session.h"
|
#include "libp2p/conn/session.h"
|
||||||
#include "libp2p/utils/logger.h"
|
#include "libp2p/utils/logger.h"
|
||||||
|
|
||||||
|
// function declarations that we don't want in the header file
|
||||||
|
int libp2p_yamux_channels_free(struct YamuxContext* ctx);
|
||||||
|
struct Stream* libp2p_yamux_get_parent_stream(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a context, get the YamuxChannelContext
|
||||||
|
* @param stream_context the context
|
||||||
|
* @returns the YamuxChannelContext or NULL if there was none
|
||||||
|
*/
|
||||||
|
struct YamuxChannelContext* libp2p_yamux_get_channel_context(void* stream_context) {
|
||||||
|
char proto = ((uint8_t*)stream_context)[0];
|
||||||
|
if (proto == YAMUX_CHANNEL_CONTEXT) {
|
||||||
|
return (struct YamuxChannelContext*)stream_context;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Given a context, get the YamuxContext
|
||||||
|
* @param stream_context a YamuxChannelContext or a YamuxContext
|
||||||
|
* @returns the YamuxContext, or NULL on error
|
||||||
|
*/
|
||||||
|
struct YamuxContext* libp2p_yamux_get_context(void* stream_context) {
|
||||||
|
char proto = ((uint8_t*)stream_context)[0];
|
||||||
|
struct YamuxChannelContext* channel = NULL;
|
||||||
|
struct YamuxContext* ctx = NULL;
|
||||||
|
if (proto == YAMUX_CHANNEL_CONTEXT) {
|
||||||
|
channel = (struct YamuxChannelContext*)stream_context;
|
||||||
|
ctx = channel->yamux_context;
|
||||||
|
} else if (proto == YAMUX_CONTEXT) {
|
||||||
|
ctx = (struct YamuxContext*)stream_context;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if this protocol can handle the incoming message
|
* Determines if this protocol can handle the incoming message
|
||||||
* @param incoming the incoming data
|
* @param incoming the incoming data
|
||||||
|
@ -135,6 +171,35 @@ struct Libp2pProtocolHandler* libp2p_yamux_build_protocol_handler(struct Libp2pV
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the main yamux connection
|
||||||
|
* @param stream the stream to close
|
||||||
|
* @returns true(1) on success, false(0) on error
|
||||||
|
*/
|
||||||
|
int libp2p_yamux_send_go_away(struct Stream* stream) {
|
||||||
|
struct YamuxChannelContext* channel = libp2p_yamux_get_channel_context(stream->stream_context);
|
||||||
|
struct YamuxContext* ctx = libp2p_yamux_get_context(stream->stream_context);
|
||||||
|
if (ctx != NULL) {
|
||||||
|
struct StreamMessage* msg = libp2p_stream_message_new();
|
||||||
|
msg->data_size = sizeof(struct yamux_frame);
|
||||||
|
msg->data = malloc(msg->data_size);
|
||||||
|
struct yamux_frame* f = (struct yamux_frame*) msg->data;
|
||||||
|
f->type = yamux_frame_go_away;
|
||||||
|
f->flags = yamux_frame_fin;
|
||||||
|
f->streamid = 0;
|
||||||
|
f->version = 0;
|
||||||
|
f->length = 0;
|
||||||
|
if (channel != NULL) {
|
||||||
|
f->streamid = channel->channel;
|
||||||
|
}
|
||||||
|
encode_frame(f);
|
||||||
|
stream->parent_stream->write(stream->parent_stream->stream_context, msg);
|
||||||
|
libp2p_stream_message_free(msg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Close the stream and clean up all resources
|
* Close the stream and clean up all resources
|
||||||
* NOTE: This also goes through the channels
|
* NOTE: This also goes through the channels
|
||||||
|
@ -148,7 +213,9 @@ int libp2p_yamux_close(struct Stream* stream) {
|
||||||
return 0;
|
return 0;
|
||||||
struct Stream* parent_stream = stream->parent_stream;
|
struct Stream* parent_stream = stream->parent_stream;
|
||||||
// this should close everything above yamux (i.e. the protocols that are riding on top of yamux)
|
// this should close everything above yamux (i.e. the protocols that are riding on top of yamux)
|
||||||
libp2p_yamux_stream_free(stream);
|
libp2p_yamux_channels_free(stream->stream_context);
|
||||||
|
// send a FIN
|
||||||
|
libp2p_yamux_send_go_away(stream);
|
||||||
// and this should close everything below
|
// and this should close everything below
|
||||||
parent_stream->close(parent_stream);
|
parent_stream->close(parent_stream);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -163,8 +230,10 @@ int libp2p_yamux_close(struct Stream* stream) {
|
||||||
* @returns true(1) on success, false(0) on failure
|
* @returns true(1) on success, false(0) on failure
|
||||||
*/
|
*/
|
||||||
int libp2p_yamux_read(void* stream_context, struct StreamMessage** message, int timeout_secs) {
|
int libp2p_yamux_read(void* stream_context, struct StreamMessage** message, int timeout_secs) {
|
||||||
if (stream_context == NULL)
|
if (stream_context == NULL) {
|
||||||
|
libp2p_logger_error("yamux", "read was passed a null context.\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
// look at the first byte of the context to determine if this is a YamuxContext (we're negotiating)
|
// look at the first byte of the context to determine if this is a YamuxContext (we're negotiating)
|
||||||
// or a YamuxChannelContext (we're talking to an established channel)
|
// or a YamuxChannelContext (we're talking to an established channel)
|
||||||
struct YamuxContext* ctx = NULL;
|
struct YamuxContext* ctx = NULL;
|
||||||
|
@ -177,26 +246,38 @@ int libp2p_yamux_read(void* stream_context, struct StreamMessage** message, int
|
||||||
ctx = (struct YamuxContext*)stream_context;
|
ctx = (struct YamuxContext*)stream_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Stream* parent_stream = libp2p_yamux_get_parent_stream(stream_context);
|
||||||
if (channel != NULL && channel->channel != 0) {
|
if (channel != NULL && channel->channel != 0) {
|
||||||
// we have an established channel. Use it.
|
// we have an established channel. Use it.
|
||||||
if (!channel->yamux_context->stream->parent_stream->read(channel->yamux_context->stream->parent_stream->stream_context, message, yamux_default_timeout))
|
if (!parent_stream->read(parent_stream->stream_context, message, yamux_default_timeout)) {
|
||||||
|
libp2p_logger_error("yamux", "Read: Attepted to read from channel %d, but the read failed.\n", channel->channel);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
if (message == NULL) {
|
||||||
|
libp2p_logger_error("yamux", "Read: Successfully read from channel %d, but message was NULL.\n", channel->channel);
|
||||||
|
}
|
||||||
// TODO: This is not right. It must be sorted out.
|
// TODO: This is not right. It must be sorted out.
|
||||||
struct StreamMessage* msg = *message;
|
struct StreamMessage* msg = *message;
|
||||||
if (yamux_decode(channel, msg->data, msg->data_size, message) == 0)
|
libp2p_logger_debug("yamux", "Read: Received %d bytes on channel %d.\n", msg->data_size, channel->channel);
|
||||||
|
if (yamux_decode(channel, msg->data, msg->data_size, message) == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
libp2p_logger_error("yamux", "yamux_decode returned error.\n");
|
||||||
} else if (ctx != NULL) {
|
} else if (ctx != NULL) {
|
||||||
// We are still negotiating. They are probably attempting to negotiate a new protocol
|
// We are still negotiating. They are probably attempting to negotiate a new protocol
|
||||||
struct StreamMessage* incoming = NULL;
|
struct StreamMessage* incoming = NULL;
|
||||||
if (ctx->stream->parent_stream->read(ctx->stream->parent_stream->stream_context, &incoming, yamux_default_timeout)) {
|
if (parent_stream->read(parent_stream->stream_context, &incoming, yamux_default_timeout)) {
|
||||||
|
libp2p_logger_debug("yamux", "read: successfully read %d bytes from network.\n", incoming->data_size);
|
||||||
// parse the frame
|
// parse the frame
|
||||||
if (yamux_decode(ctx, incoming->data, incoming->data_size, message) == 0) {
|
if (yamux_decode(ctx, incoming->data, incoming->data_size, message) == 0) {
|
||||||
libp2p_stream_message_free(incoming);
|
libp2p_stream_message_free(incoming);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
libp2p_logger_error("yamux", "yamux_decode returned error.\n");
|
||||||
libp2p_stream_message_free(incoming);
|
libp2p_stream_message_free(incoming);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
libp2p_logger_error("yamux", "Unable to do network read.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +308,23 @@ struct StreamMessage* libp2p_yamux_prepare_to_send(struct StreamMessage* incomin
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Get the next usable ID for a channel
|
||||||
|
* NOTE: Also increments the yamux_session_.nextid counter
|
||||||
|
* NOTE: Odd = client, Even = server
|
||||||
|
* @param ctx the context
|
||||||
|
* @returns the next id
|
||||||
|
*/
|
||||||
|
uint32_t libp2p_yamux_get_next_id(struct YamuxContext* ctx) {
|
||||||
|
uint32_t next_id = ctx->session->nextid;
|
||||||
|
if ( (ctx->am_server && next_id % 2 == 1)
|
||||||
|
|| (!ctx->am_server && next_id % 2 == 0))
|
||||||
|
next_id += 1;
|
||||||
|
ctx->session->nextid = next_id + 1;
|
||||||
|
return next_id;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Write to the remote
|
* Write to the remote
|
||||||
* @param stream_context the context. Could be a YamuxContext or YamuxChannelContext
|
* @param stream_context the context. Could be a YamuxContext or YamuxChannelContext
|
||||||
|
@ -256,40 +354,29 @@ int libp2p_yamux_write(void* stream_context, struct StreamMessage* message) {
|
||||||
struct yamux_frame* frame = (struct yamux_frame*)outgoing_message->data;
|
struct yamux_frame* frame = (struct yamux_frame*)outgoing_message->data;
|
||||||
// set a few more flags
|
// set a few more flags
|
||||||
frame->flags = get_flags(stream_context);
|
frame->flags = get_flags(stream_context);
|
||||||
if (channel != NULL)
|
if (channel == NULL) {
|
||||||
|
// if we don't yet have a channel, set the id to the next available
|
||||||
|
frame->streamid = libp2p_yamux_get_next_id(ctx);
|
||||||
|
} else {
|
||||||
frame->streamid = channel->channel;
|
frame->streamid = channel->channel;
|
||||||
|
}
|
||||||
encode_frame(frame);
|
encode_frame(frame);
|
||||||
|
|
||||||
int retVal = 0;
|
int retVal = 0;
|
||||||
if (channel != NULL && channel->channel != 0) {
|
if (channel != NULL && channel->channel != 0) {
|
||||||
// we have an established channel. Use it.
|
// we have an established channel. Use it.
|
||||||
retVal = channel->stream->write(channel->stream->stream_context, outgoing_message);
|
libp2p_logger_debug("yamux", "About to write %d bytes to yamux channel %d.\n", outgoing_message->data_size, channel->channel);
|
||||||
|
struct Stream* parent_stream = libp2p_yamux_get_parent_stream(stream_context);
|
||||||
|
retVal = parent_stream->write(parent_stream->stream_context, outgoing_message);
|
||||||
} else if (ctx != NULL) {
|
} else if (ctx != NULL) {
|
||||||
retVal = ctx->stream->parent_stream->write(ctx->stream->parent_stream, outgoing_message);
|
libp2p_logger_debug("yamux", "About to write %d bytes to stream.\n", outgoing_message->data_size);
|
||||||
|
retVal = ctx->stream->parent_stream->write(ctx->stream->parent_stream->stream_context, outgoing_message);
|
||||||
}
|
}
|
||||||
libp2p_stream_message_free(outgoing_message);
|
libp2p_stream_message_free(outgoing_message);
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
* Given a context, get the YamuxContext
|
|
||||||
* @param stream_context a YamuxChannelContext or a YamuxContext
|
|
||||||
* @returns the YamuxContext, or NULL on error
|
|
||||||
*/
|
|
||||||
struct YamuxContext* libp2p_yamux_get_context(void* stream_context) {
|
|
||||||
char proto = ((uint8_t*)stream_context)[0];
|
|
||||||
struct YamuxChannelContext* channel = NULL;
|
|
||||||
struct YamuxContext* ctx = NULL;
|
|
||||||
if (proto == YAMUX_CHANNEL_CONTEXT) {
|
|
||||||
channel = (struct YamuxChannelContext*)stream_context;
|
|
||||||
ctx = channel->yamux_context;
|
|
||||||
} else if (proto == YAMUX_CONTEXT) {
|
|
||||||
ctx = (struct YamuxContext*)stream_context;
|
|
||||||
}
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Check to see if there is anything waiting on the network.
|
* Check to see if there is anything waiting on the network.
|
||||||
* @param stream_context the YamuxContext
|
* @param stream_context the YamuxContext
|
||||||
|
@ -321,15 +408,19 @@ int libp2p_yamux_read_raw(void* stream_context, uint8_t* buffer, int buffer_size
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
struct YamuxContext* ctx = libp2p_yamux_get_context(stream_context);
|
struct YamuxContext* ctx = libp2p_yamux_get_context(stream_context);
|
||||||
if (ctx->buffered_message_pos == -1) {
|
if (ctx->buffered_message_pos == -1 || ctx->buffered_message == NULL) {
|
||||||
// we need to get info from the network
|
// we need to get info from the network
|
||||||
if (!ctx->stream->read(ctx->stream->stream_context, &ctx->buffered_message, timeout_secs)) {
|
if (!libp2p_yamux_read(stream_context, &ctx->buffered_message, timeout_secs)) {
|
||||||
|
libp2p_logger_error("yamux", "read_raw: Unable to read from network.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ctx->buffered_message_pos = 0;
|
ctx->buffered_message_pos = 0;
|
||||||
|
} else {
|
||||||
|
// we have some data from a previous read_raw call the code
|
||||||
|
// below should handle this.
|
||||||
}
|
}
|
||||||
// max_to_read is the lesser of bytes read or buffer_size
|
// max_to_read is the lesser of bytes read or buffer_size
|
||||||
int max_to_read = (buffer_size > ctx->buffered_message->data_size ? ctx->buffered_message->data_size : buffer_size);
|
int max_to_read = (buffer_size > (ctx->buffered_message->data_size-ctx->buffered_message_pos) ? ctx->buffered_message->data_size-ctx->buffered_message_pos : buffer_size);
|
||||||
memcpy(buffer, &ctx->buffered_message->data[ctx->buffered_message_pos], max_to_read);
|
memcpy(buffer, &ctx->buffered_message->data[ctx->buffered_message_pos], max_to_read);
|
||||||
ctx->buffered_message_pos += max_to_read;
|
ctx->buffered_message_pos += max_to_read;
|
||||||
if (ctx->buffered_message_pos == ctx->buffered_message->data_size) {
|
if (ctx->buffered_message_pos == ctx->buffered_message->data_size) {
|
||||||
|
@ -397,6 +488,7 @@ int libp2p_yamux_negotiate(struct YamuxContext* ctx, int am_server) {
|
||||||
// send the protocol id
|
// send the protocol id
|
||||||
outgoing.data = (uint8_t*)protocolID;
|
outgoing.data = (uint8_t*)protocolID;
|
||||||
outgoing.data_size = strlen(protocolID);
|
outgoing.data_size = strlen(protocolID);
|
||||||
|
libp2p_logger_debug("yamux", "Attempting to write the yamux protocol id.\n");
|
||||||
if (!ctx->stream->parent_stream->write(ctx->stream->parent_stream->stream_context, &outgoing)) {
|
if (!ctx->stream->parent_stream->write(ctx->stream->parent_stream->stream_context, &outgoing)) {
|
||||||
libp2p_logger_error("yamux", "We attempted to write the yamux protocol id, but the write call failed.\n");
|
libp2p_logger_error("yamux", "We attempted to write the yamux protocol id, but the write call failed.\n");
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -436,6 +528,13 @@ int libp2p_yamux_negotiate(struct YamuxContext* ctx, int am_server) {
|
||||||
*/
|
*/
|
||||||
int libp2p_yamux_handle_upgrade(struct Stream* yamux_stream, struct Stream* new_stream) {
|
int libp2p_yamux_handle_upgrade(struct Stream* yamux_stream, struct Stream* new_stream) {
|
||||||
// put this stream in the collection, and tie it to an id
|
// put this stream in the collection, and tie it to an id
|
||||||
|
if (libp2p_logger_watching_class("yamux")) {
|
||||||
|
const char* stream_type = "";
|
||||||
|
if (new_stream->stream_type == STREAM_TYPE_MULTISTREAM) {
|
||||||
|
stream_type = "Multistream";
|
||||||
|
}
|
||||||
|
libp2p_logger_debug("yamux", "handle_upgrade called for stream %s.\n", stream_type);
|
||||||
|
}
|
||||||
struct YamuxContext* yamux_context = (struct YamuxContext*)yamux_stream->stream_context;
|
struct YamuxContext* yamux_context = (struct YamuxContext*)yamux_stream->stream_context;
|
||||||
return libp2p_yamux_stream_add(yamux_context, new_stream);
|
return libp2p_yamux_stream_add(yamux_context, new_stream);
|
||||||
}
|
}
|
||||||
|
@ -451,7 +550,7 @@ void libp2p_yamux_read_from_yamux_session(struct yamux_stream* stream, uint32_t
|
||||||
*/
|
*/
|
||||||
void libp2p_yamux_new_stream(struct YamuxContext* context, struct Stream* stream, struct StreamMessage* msg) {
|
void libp2p_yamux_new_stream(struct YamuxContext* context, struct Stream* stream, struct StreamMessage* msg) {
|
||||||
// ok, we have the new stream structure. We now need to read what was sent.
|
// ok, we have the new stream structure. We now need to read what was sent.
|
||||||
libp2p_protocol_marshal(msg, stream, context->protocol_handlers);
|
//libp2p_protocol_marshal(msg, stream, context->protocol_handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
|
@ -493,6 +592,49 @@ struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream, int am_serv
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* This will retrieve the stream that yamux is riding on top of
|
||||||
|
* @param context a YamuxContext or YamuxChannelContext
|
||||||
|
* @returns the Stream that yamux is riding on top of
|
||||||
|
*/
|
||||||
|
struct Stream* libp2p_yamux_get_parent_stream(void* context) {
|
||||||
|
if (context == NULL)
|
||||||
|
return NULL;
|
||||||
|
struct YamuxContext* ctx = libp2p_yamux_get_context(context);
|
||||||
|
if (ctx == NULL)
|
||||||
|
return NULL;
|
||||||
|
return ctx->stream->parent_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Sends a FIN to close a channel
|
||||||
|
* @param channel the channel to close
|
||||||
|
* @returns true(1) on success, false(0) otherwise
|
||||||
|
*/
|
||||||
|
int libp2p_yamux_channel_send_FIN(struct YamuxChannelContext* channel) {
|
||||||
|
if (channel == NULL)
|
||||||
|
return 0;
|
||||||
|
struct YamuxContext* ctx = channel->yamux_context;
|
||||||
|
if (ctx != NULL) {
|
||||||
|
struct StreamMessage* msg = libp2p_stream_message_new();
|
||||||
|
msg->data_size = sizeof(struct yamux_frame);
|
||||||
|
msg->data = malloc(msg->data_size);
|
||||||
|
struct yamux_frame* f = (struct yamux_frame*) msg->data;
|
||||||
|
f->type = yamux_frame_window_update;
|
||||||
|
f->flags = yamux_frame_fin;
|
||||||
|
f->streamid = channel->channel;
|
||||||
|
f->version = 0;
|
||||||
|
f->length = 0;
|
||||||
|
encode_frame(f);
|
||||||
|
struct Stream* parent_to_yamux = libp2p_yamux_get_parent_stream(channel);
|
||||||
|
if (parent_to_yamux != NULL)
|
||||||
|
parent_to_yamux->write(parent_to_yamux->stream_context, msg);
|
||||||
|
libp2p_stream_message_free(msg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up resources from libp2p_yamux_channel_new
|
* Clean up resources from libp2p_yamux_channel_new
|
||||||
|
@ -503,6 +645,8 @@ int libp2p_yamux_channel_close(void* context) {
|
||||||
return 0;
|
return 0;
|
||||||
struct YamuxChannelContext* ctx = (struct YamuxChannelContext*)context;
|
struct YamuxChannelContext* ctx = (struct YamuxChannelContext*)context;
|
||||||
if (ctx != NULL) {
|
if (ctx != NULL) {
|
||||||
|
//Send FIN
|
||||||
|
libp2p_yamux_channel_send_FIN(ctx);
|
||||||
// close the child's stream
|
// close the child's stream
|
||||||
ctx->child_stream->close(ctx->child_stream);
|
ctx->child_stream->close(ctx->child_stream);
|
||||||
libp2p_stream_free(ctx->stream);
|
libp2p_stream_free(ctx->stream);
|
||||||
|
@ -511,6 +655,23 @@ int libp2p_yamux_channel_close(void* context) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Close all channels
|
||||||
|
* @param ctx the YamuxContext that contains a vector of channels
|
||||||
|
* @returns true(1)
|
||||||
|
*/
|
||||||
|
int libp2p_yamux_channels_free(struct YamuxContext* ctx) {
|
||||||
|
if (ctx->channels) {
|
||||||
|
for(int i = 0; i < ctx->channels->total; i++) {
|
||||||
|
struct Stream* curr = (struct Stream*) libp2p_utils_vector_get(ctx->channels, i);
|
||||||
|
libp2p_yamux_channel_close(curr->stream_context);
|
||||||
|
}
|
||||||
|
libp2p_utils_vector_free(ctx->channels);
|
||||||
|
ctx->channels = NULL;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Free the resources from libp2p_yamux_context_new
|
* Free the resources from libp2p_yamux_context_new
|
||||||
* @param ctx the context
|
* @param ctx the context
|
||||||
|
@ -523,14 +684,7 @@ void libp2p_yamux_context_free(struct YamuxContext* ctx) {
|
||||||
ctx->buffered_message = NULL;
|
ctx->buffered_message = NULL;
|
||||||
}
|
}
|
||||||
// free all the channels
|
// free all the channels
|
||||||
if (ctx->channels) {
|
libp2p_yamux_channels_free(ctx);
|
||||||
for(int i = 0; i < ctx->channels->total; i++) {
|
|
||||||
struct Stream* curr = (struct Stream*) libp2p_utils_vector_get(ctx->channels, i);
|
|
||||||
//curr->close(curr->stream_context);
|
|
||||||
libp2p_yamux_channel_close(curr->stream_context);
|
|
||||||
}
|
|
||||||
libp2p_utils_vector_free(ctx->channels);
|
|
||||||
}
|
|
||||||
if (ctx->session != NULL)
|
if (ctx->session != NULL)
|
||||||
yamux_session_free(ctx->session);
|
yamux_session_free(ctx->session);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
|
@ -602,7 +756,7 @@ struct Stream* libp2p_yamux_channel_stream_new(struct Stream* incoming_stream, i
|
||||||
ctx->yamux_context = incoming_stream->stream_context;
|
ctx->yamux_context = incoming_stream->stream_context;
|
||||||
ctx->child_stream = NULL;
|
ctx->child_stream = NULL;
|
||||||
}
|
}
|
||||||
ctx->channel = channelNumber;
|
ctx->channel = (uint32_t) channelNumber;
|
||||||
ctx->closed = 0;
|
ctx->closed = 0;
|
||||||
ctx->state = 0;
|
ctx->state = 0;
|
||||||
ctx->window_size = 0;
|
ctx->window_size = 0;
|
||||||
|
@ -628,7 +782,7 @@ int libp2p_yamux_stream_add(struct YamuxContext* ctx, struct Stream* stream) {
|
||||||
return 0;
|
return 0;
|
||||||
struct YamuxChannelContext* channel_context = (struct YamuxChannelContext*)channel_stream->stream_context;
|
struct YamuxChannelContext* channel_context = (struct YamuxChannelContext*)channel_stream->stream_context;
|
||||||
// the negotiation was successful. Add it to the list of channels that we have
|
// the negotiation was successful. Add it to the list of channels that we have
|
||||||
int itemNo = libp2p_utils_vector_add(ctx->channels, channel_stream);
|
uint32_t itemNo = (uint32_t) libp2p_utils_vector_add(ctx->channels, channel_stream);
|
||||||
// There are 2 streams for each protocol. A server has the even numbered streams, the
|
// There are 2 streams for each protocol. A server has the even numbered streams, the
|
||||||
// client the odd number streams. If we are the server, we need to kick off the
|
// client the odd number streams. If we are the server, we need to kick off the
|
||||||
// process to add a stream of the same type.
|
// process to add a stream of the same type.
|
||||||
|
@ -636,7 +790,7 @@ int libp2p_yamux_stream_add(struct YamuxContext* ctx, struct Stream* stream) {
|
||||||
if (ctx->am_server && itemNo % 2 != 0) {
|
if (ctx->am_server && itemNo % 2 != 0) {
|
||||||
// we're the server, and they have a negotiated a new protocol.
|
// we're the server, and they have a negotiated a new protocol.
|
||||||
// negotiate a stream for us to talk to them.
|
// negotiate a stream for us to talk to them.
|
||||||
struct Stream* yamux_stream = stream->parent_stream->parent_stream;
|
struct Stream* yamux_stream = ctx->stream;
|
||||||
struct Stream* server_to_client_stream = stream->negotiate(yamux_stream);
|
struct Stream* server_to_client_stream = stream->negotiate(yamux_stream);
|
||||||
libp2p_yamux_stream_add(ctx, server_to_client_stream);
|
libp2p_yamux_stream_add(ctx, server_to_client_stream);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue