Make yamux compatible with GO. Still testing

This commit is contained in:
John Jones 2017-11-30 20:58:47 -05:00
parent 4218876198
commit 2e0391f68c
13 changed files with 271 additions and 128 deletions

View file

@ -143,13 +143,35 @@ int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer
// yamux over multistream // yamux over multistream
new_stream = libp2p_yamux_stream_new(peer->sessionContext->default_stream, 0, dialer->swarm->protocol_handlers); new_stream = libp2p_yamux_stream_new(peer->sessionContext->default_stream, 0, dialer->swarm->protocol_handlers);
if (new_stream != NULL) { if (new_stream != NULL) {
if (!libp2p_yamux_stream_ready(peer->sessionContext, 5)) if (!libp2p_yamux_stream_ready(peer->sessionContext, 5)) {
libp2p_logger_error("dialer", "Unable to get yamux into the ready status.\n");
return 0; return 0;
}
libp2p_logger_debug("dialer", "We successfully negotiated yamux.\n"); libp2p_logger_debug("dialer", "We successfully negotiated yamux.\n");
//peer->sessionContext->default_stream = new_stream; // the rest should be done on another thread
// we have our swarm connection. Now we ask for some "channels" // we have our swarm connection. Now we ask for some "channels"
// id over yamux // id over multistream over yamux
//libp2p_yamux_stream_add(new_stream->stream_context, libp2p_identify_stream_new(new_stream)); const struct Libp2pProtocolHandler* handler = libp2p_protocol_get_handler(dialer->swarm->protocol_handlers, "/ipfs/id/1.0.0\n");
if (handler != NULL) {
Identify* identify = handler->context;
if (peer->sessionContext->default_stream->stream_type == STREAM_TYPE_YAMUX) {
struct YamuxContext* ctx = libp2p_yamux_get_context(peer->sessionContext->default_stream->stream_context);
// first get a new frame. It should be ready to go
struct Stream* new_channel = yamux_channel_new(ctx, 0, NULL);
if (new_channel != NULL && new_channel->channel > 0) {
// then get a multistream
struct Stream* yamux_multistream = libp2p_net_multistream_stream_new(new_channel, 0);
if (!libp2p_net_multistream_ready(new_channel->stream_context, 10)) {
libp2p_logger_error("dialer", "Unable to get multistream over yamux into the ready status.\n");
return 0;
}
// then get an identify
struct Stream* identify_stream = libp2p_identify_stream_new(yamux_multistream, identify, 1);
}
} else {
libp2p_logger_error("dialer", "Expected a yamux context, but got a context of type %d.\n", peer->sessionContext->default_stream->stream_type);
}
}
// kademlia over yamux // kademlia over yamux
//libp2p_yamux_stream_add(new_stream->stream_context, libp2p_kademlia_stream_new(new_stream)); //libp2p_yamux_stream_add(new_stream->stream_context, libp2p_kademlia_stream_new(new_stream));
// circuit relay over yamux // circuit relay over yamux

View file

@ -10,6 +10,7 @@
#include "libp2p/conn/session.h" #include "libp2p/conn/session.h"
#include "libp2p/identify/identify.h" #include "libp2p/identify/identify.h"
#include "libp2p/utils/logger.h" #include "libp2p/utils/logger.h"
#include "libp2p/yamux/yamux.h"
@ -41,17 +42,21 @@ int libp2p_identify_can_handle(const struct StreamMessage* msg) {
* @param context the context * @param context the context
* @returns true(1) on success, false(0) otherwise * @returns true(1) on success, false(0) otherwise
*/ */
int libp2p_identify_send_protocol(struct Stream *stream, Identify* identify) { int libp2p_identify_send_protocol(struct Stream *stream, Identify* identify, int initiatedByUs) {
size_t max_buffer_size = 6000; size_t max_buffer_size = 6000;
uint8_t buffer[max_buffer_size]; uint8_t buffer[max_buffer_size];
char *protocol = "/ipfs/id/1.0.0\n"; char *protocol = "/ipfs/id/1.0.0\n";
int protocol_len = strlen(protocol); int protocol_len = strlen(protocol);
// throw the protocol into the buffer // throw the protocol into the buffer
memcpy(&buffer[0], protocol, protocol_len); memcpy(&buffer[0], protocol, protocol_len);
if (!initiatedByUs) {
if (!libp2p_identify_protobuf_encode(identify, &buffer[protocol_len], max_buffer_size-protocol_len, &max_buffer_size)) { if (!libp2p_identify_protobuf_encode(identify, &buffer[protocol_len], max_buffer_size-protocol_len, &max_buffer_size)) {
libp2p_logger_error("identify", "Unable to protobuf the identity.\n"); libp2p_logger_error("identify", "Unable to protobuf the identity.\n");
return 0; return 0;
} }
} else {
max_buffer_size = 0;
}
struct StreamMessage msg; struct StreamMessage msg;
msg.data_size = protocol_len + max_buffer_size; msg.data_size = protocol_len + max_buffer_size;
msg.data = buffer; msg.data = buffer;
@ -331,13 +336,26 @@ exit:
* @returns <0 on error, 0 if loop should not continue, >0 on success * @returns <0 on error, 0 if loop should not continue, >0 on success
*/ */
int libp2p_identify_handle_message(const struct StreamMessage* msg, struct Stream* stream, void* protocol_context) { int libp2p_identify_handle_message(const struct StreamMessage* msg, struct Stream* stream, void* protocol_context) {
struct YamuxChannelContext* yamuxChannelContext = libp2p_yamux_get_parent_channel_context(stream);
struct YamuxContext* yamuxContext = libp2p_yamux_get_context(yamuxChannelContext);
struct Stream* new_stream = NULL;
if (yamuxChannelContext != NULL && yamuxChannelContext->child_stream->stream_type == STREAM_TYPE_YAMUX) {
if ( (yamuxContext->am_server && yamuxChannelContext->channel % 2 == 0)
|| (!yamuxContext->am_server && yamuxChannelContext->channel % 2 == 1)) {
// we initiated it, and they are replying
return 1;
}
} else {
// they initiated it.
// attempt to create a new Identify connection with them. // attempt to create a new Identify connection with them.
// send the protocol id back, and set up the channel // send the protocol id back, and set up the channel
Identify* identify = (Identify*)protocol_context; Identify* identify = (Identify*)protocol_context;
struct Stream* new_stream = libp2p_identify_stream_new(stream, identify); new_stream = libp2p_identify_stream_new(stream, identify, 0);
if (new_stream == NULL) if (new_stream == NULL)
return -1; return -1;
return stream->handle_upgrade(stream, new_stream); return stream->handle_upgrade(stream, new_stream);
}
return 1;
} }
/** /**
@ -377,6 +395,17 @@ int libp2p_identify_close(struct Stream* stream) {
return 1; return 1;
} }
int libp2p_identify_read(void* stream_context, struct StreamMessage** msg, int timeout_secs) {
struct IdentifyContext* ctx = (struct IdentifyContext*) stream_context;
struct StreamMessage* internal = NULL;
if (ctx->parent_stream->read(ctx->parent_stream->stream_context, &internal, timeout_secs)) {
// we got an identity, but we should not do anything with it right now
// TODO: send a fin
libp2p_stream_message_free(internal);
}
return 0;
}
/*** /***
* Create a new stream that negotiates the identify protocol * Create a new stream that negotiates the identify protocol
* *
@ -387,7 +416,7 @@ int libp2p_identify_close(struct Stream* stream) {
* @param parent_stream the parent stream * @param parent_stream the parent stream
* @returns a new Stream that can talk "identify" * @returns a new Stream that can talk "identify"
*/ */
struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream, Identify* identify) { struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream, Identify* identify, int initiatedByUs) {
if (parent_stream == NULL) if (parent_stream == NULL)
return NULL; return NULL;
struct Stream* out = libp2p_stream_new(); struct Stream* out = libp2p_stream_new();
@ -404,8 +433,9 @@ struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream, Identify
out->close = libp2p_identify_close; out->close = libp2p_identify_close;
out->negotiate = NULL; out->negotiate = NULL;
out->bytes_waiting = NULL; out->bytes_waiting = NULL;
out->read = libp2p_identify_read;
// do we expect a reply? // do we expect a reply?
if (!libp2p_identify_send_protocol(parent_stream, identify) /* || !libp2p_identify_receive_protocol(parent_stream) */) { if (!libp2p_identify_send_protocol(parent_stream, identify, initiatedByUs) /* || !libp2p_identify_receive_protocol(parent_stream) */) {
libp2p_stream_free(out); libp2p_stream_free(out);
free(ctx); free(ctx);
return NULL; return NULL;
@ -425,6 +455,7 @@ struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream, Identify
* @param parent_stream the parent stream * @param parent_stream the parent stream
* @returns a new Stream that is a multistream, but with "identify" already negotiated * @returns a new Stream that is a multistream, but with "identify" already negotiated
*/ */
/*
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;
@ -451,3 +482,4 @@ struct Stream* libp2p_identify_stream_new_with_multistream(struct Stream* parent
} }
return out; return out;
} }
*/

View file

@ -33,7 +33,7 @@ struct IdentifyContext {
}; };
int libp2p_identify_can_handle(const struct StreamMessage* msg); int libp2p_identify_can_handle(const struct StreamMessage* msg);
int libp2p_identify_send_protocol(struct Stream* stream, Identify* identify); int libp2p_identify_send_protocol(struct Stream* stream, Identify* identify, int initiatedByUs);
int libp2p_identify_receive_protocol(struct Stream* stream); int libp2p_identify_receive_protocol(struct Stream* stream);
Identify* libp2p_identify_new(); Identify* libp2p_identify_new();
void libp2p_identify_free(Identify* in); void libp2p_identify_free(Identify* in);
@ -55,5 +55,5 @@ struct Libp2pProtocolHandler* libp2p_identify_build_protocol_handler(char* publi
* @param parent_stream the parent stream * @param parent_stream the parent stream
* @returns a new Stream that can talk "identify" * @returns a new Stream that can talk "identify"
*/ */
struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream, Identify* identify); struct Stream* libp2p_identify_stream_new(struct Stream* parent_stream, Identify* identify, int initiatedByUs);

View file

@ -123,9 +123,9 @@ void libp2p_net_multistream_stream_free(struct Stream* stream);
/*** /***
* Wait for multistream stream to become ready * Wait for multistream stream to become ready
* @param session_context the session context to check * @param context the session context to check, can also be a YamuxChannelContext
* @param timeout_secs the number of seconds to wait for things to become ready * @param timeout_secs the number of seconds to wait for things to become ready
* @returns true(1) if it becomes ready, false(0) otherwise * @returns true(1) if it becomes ready, false(0) otherwise
*/ */
int libp2p_net_multistream_ready(struct SessionContext* session_context, int timeout_secs); int libp2p_net_multistream_ready(void* context, int timeout_secs);

View file

@ -70,3 +70,11 @@ int libp2p_protocol_handlers_shutdown(struct Libp2pVector* handlers);
* @param handlers the vector of handlers * @param handlers the vector of handlers
*/ */
int libp2p_protocol_is_valid_protocol(struct StreamMessage* msg, struct Libp2pVector* handlers); int libp2p_protocol_is_valid_protocol(struct StreamMessage* msg, struct Libp2pVector* handlers);
/***
* Retrieve the correct protocol handlder for a particular protocol id
* @param protocol_handlers the collection of protocol handlers
* @param id the protocol id
* @returns a protocol handler that can handle id (or NULL if none found)
*/
const struct Libp2pProtocolHandler* libp2p_protocol_get_handler(struct Libp2pVector* protocol_handlers, const char* id);

View file

@ -129,3 +129,24 @@ struct StreamMessage* libp2p_yamux_prepare_to_send(struct StreamMessage* incomin
* @returns true(1) if it becomes ready, false(0) otherwise * @returns true(1) if it becomes ready, false(0) otherwise
*/ */
int libp2p_yamux_stream_ready(struct SessionContext* session_context, int timeout_secs); int libp2p_yamux_stream_ready(struct SessionContext* session_context, int timeout_secs);
/**
* 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);
/***
* 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);
/***
* Walks down the tree, looking for the nearest YamuxChannelContext
* @param in the stream
* @returns the YamuxChannelContext or NULL
*/
struct YamuxChannelContext* libp2p_yamux_get_parent_channel_context(struct Stream* in);

View file

@ -16,6 +16,7 @@
#include "libp2p/net/multistream.h" #include "libp2p/net/multistream.h"
#include "libp2p/utils/logger.h" #include "libp2p/utils/logger.h"
#include "multiaddr/multiaddr.h" #include "multiaddr/multiaddr.h"
#include "libp2p/yamux/yamux.h"
// NOTE: this is normally set to 5 seconds, but you may want to increase this during debugging // NOTE: this is normally set to 5 seconds, but you may want to increase this during debugging
int multistream_default_timeout = 5; int multistream_default_timeout = 5;
@ -189,26 +190,43 @@ int libp2p_net_multistream_write_without_check(void* stream_context, struct Stre
return num_bytes; return num_bytes;
} }
/*** int multistream_wait(struct Stream* stream, int timeout_secs) {
* Wait for multistream stream to become ready
* @param session_context the session context to check
* @param timeout_secs the number of seconds to wait for things to become ready
* @returns true(1) if it becomes ready, false(0) otherwise
*/
int libp2p_net_multistream_ready(struct SessionContext* session_context, int timeout_secs) {
int counter = 0; int counter = 0;
while (session_context->default_stream->stream_type != STREAM_TYPE_MULTISTREAM && counter <= timeout_secs) { struct MultistreamContext* ctx = (struct MultistreamContext*)stream->stream_context;
counter++;
sleep(1);
}
if (session_context->default_stream->stream_type == STREAM_TYPE_MULTISTREAM && counter < 5) {
struct MultistreamContext* ctx = (struct MultistreamContext*)session_context->default_stream->stream_context;
while (ctx->status != multistream_status_ack && counter <= timeout_secs) { while (ctx->status != multistream_status_ack && counter <= timeout_secs) {
counter++; counter++;
sleep(1); sleep(1);
} }
if (ctx->status == multistream_status_ack) if (ctx->status == multistream_status_ack)
return 1; return 1;
return 0;
}
/***
* Wait for multistream stream to become ready
* @param session_context the session context to check
* @param timeout_secs the number of seconds to wait for things to become ready
* @returns true(1) if it becomes ready, false(0) otherwise
*/
int libp2p_net_multistream_ready(void* context, int timeout_secs) {
int counter = 0;
struct YamuxChannelContext* yamuxChannelContext = libp2p_yamux_get_channel_context(context);
if (yamuxChannelContext != NULL) {
while (yamuxChannelContext->child_stream->stream_type != STREAM_TYPE_MULTISTREAM && counter <= timeout_secs) {
counter++;
sleep(1);
}
if (counter <= 5)
return multistream_wait(yamuxChannelContext->child_stream, timeout_secs - counter);
} else {
struct SessionContext* session_context = (struct SessionContext*)context;
while (session_context->default_stream->stream_type != STREAM_TYPE_MULTISTREAM && counter <= timeout_secs) {
counter++;
sleep(1);
}
if (counter <= 5) {
return multistream_wait(session_context->default_stream, timeout_secs - counter);
}
} }
return 0; return 0;
} }

View file

@ -7,6 +7,7 @@
* Handle the different protocols * Handle the different protocols
*/ */
/*** /***
* Compare incoming to see if they are requesting a protocol upgrade * Compare incoming to see if they are requesting a protocol upgrade
* @param incoming the incoming string * @param incoming the incoming string
@ -26,6 +27,19 @@ const struct Libp2pProtocolHandler* protocol_compare(struct StreamMessage* msg,
return NULL; return NULL;
} }
/***
* Retrieve the correct protocol handlder for a particular protocol id
* @param protocol_handlers the collection of protocol handlers
* @param id the protocol id
* @returns a protocol handler that can handle id (or NULL if none found)
*/
const struct Libp2pProtocolHandler* libp2p_protocol_get_handler(struct Libp2pVector* protocol_handlers, const char* id) {
struct StreamMessage message;
message.data_size = strlen(id);
message.data = (uint8_t*)id;
return protocol_compare(&message, protocol_handlers);
}
/** /**
* Allocate resources for a new Libp2pProtocolHandler * Allocate resources for a new Libp2pProtocolHandler
* @returns an allocated struct * @returns an allocated struct
@ -50,6 +64,16 @@ void libp2p_protocol_handler_free(struct Libp2pProtocolHandler* handler) {
free(handler); free(handler);
} }
int appears_to_be_a_protocol(struct StreamMessage* msg) {
if (msg == NULL)
return 0;
if (msg->data_size < 2)
return 0;
if (memchr(&msg->data[1], '\n', msg->data_size-1) != NULL)
return 1;
return 0;
}
/*** /***
* Handle an incoming message * Handle an incoming message
* @param message the incoming message * @param message the incoming message
@ -61,6 +85,12 @@ int libp2p_protocol_marshal(struct StreamMessage* msg, struct Stream* stream, st
const struct Libp2pProtocolHandler* handler = protocol_compare(msg, handlers); const struct Libp2pProtocolHandler* handler = protocol_compare(msg, handlers);
if (handler == NULL) { if (handler == NULL) {
if (appears_to_be_a_protocol(msg)) {
struct StreamMessage na_message;
na_message.data = (uint8_t*)"na\n";
na_message.data_size = 3;
stream->write(stream->stream_context, &na_message);
}
// set the msg->error code // set the msg->error code
msg->error_number = 100; msg->error_number = 100;
return -1; return -1;

View file

@ -20,6 +20,7 @@ struct SwarmSession {
int DEFAULT_NETWORK_TIMEOUT = 5; int DEFAULT_NETWORK_TIMEOUT = 5;
/*** /***
* Listens on a particular stream, and marshals the request * Listens on a particular stream, and marshals the request
* @param stream the stream to listen to * @param stream the stream to listen to
@ -29,6 +30,8 @@ int DEFAULT_NETWORK_TIMEOUT = 5;
int libp2p_swarm_listen_and_handle(struct Stream* stream, struct Libp2pVector* protocol_handlers) { int libp2p_swarm_listen_and_handle(struct Stream* stream, struct Libp2pVector* protocol_handlers) {
struct StreamMessage* results = NULL; struct StreamMessage* results = NULL;
int retVal = 0; int retVal = 0;
if (stream == NULL)
return -1;
// Read from the network // Read from the network
libp2p_logger_debug("swarm", "Attempting to get read lock.\n"); libp2p_logger_debug("swarm", "Attempting to get read lock.\n");
pthread_mutex_lock(stream->socket_mutex); pthread_mutex_lock(stream->socket_mutex);

View file

@ -140,7 +140,7 @@ int test_yamux_identify() {
goto exit; goto exit;
// Now add in another protocol // Now add in another protocol
mock_stream->read = mock_identify_read_protocol; mock_stream->read = mock_identify_read_protocol;
if (!libp2p_yamux_stream_add(yamux_stream->stream_context, libp2p_identify_stream_new(yamux_stream, handler->context))) { if (!libp2p_yamux_stream_add(yamux_stream->stream_context, libp2p_identify_stream_new(yamux_stream, handler->context, 1))) {
goto exit; goto exit;
} }
// tear down // tear down

View file

@ -282,7 +282,7 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
libp2p_logger_debug("yamux", "We found our stream id of %d.\n", f.streamid); libp2p_logger_debug("yamux", "We found our stream id of %d.\n", f.streamid);
if (f.flags & yamux_frame_rst) if (f.flags & yamux_frame_rst)
{ {
libp2p_logger_debug("yamux", "They are asking that this stream be reset.\n"); libp2p_logger_debug("yamux", "They are asking that stream %d be reset.\n", f.streamid);
// close the stream // close the stream
s->state = yamux_stream_closed; s->state = yamux_stream_closed;
@ -291,10 +291,10 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
} }
else if (f.flags & yamux_frame_fin) else if (f.flags & yamux_frame_fin)
{ {
libp2p_logger_debug("yamux", "They are asking that this stream be closed.\n"); libp2p_logger_debug("yamux", "They are asking that stream %d be closed.\n", f.streamid);
// local stream didn't initiate FIN // local stream didn't initiate FIN
if (s->state != yamux_stream_closing) if (s->state != yamux_stream_closing)
yamux_stream_close(context); yamux_stream_close(libp2p_yamux_get_parent_channel_context(s->stream));
s->state = yamux_stream_closed; s->state = yamux_stream_closed;
@ -303,7 +303,7 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
} }
else if (f.flags & yamux_frame_ack) else if (f.flags & yamux_frame_ack)
{ {
libp2p_logger_debug("yamux", "They sent an ack.\n"); libp2p_logger_debug("yamux", "They sent an ack for stream %d.\n", f.streamid);
// acknowldegement // acknowldegement
if (s->state != yamux_stream_syn_sent) { if (s->state != yamux_stream_syn_sent) {
libp2p_logger_debug("yamux", "We received an ack, but it seems we never sent anything!\n"); libp2p_logger_debug("yamux", "We received an ack, but it seems we never sent anything!\n");
@ -317,15 +317,10 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
return -EPROTO; return -EPROTO;
} }
libp2p_logger_debug("yamux", "Processing the data after the frame, which is %d bytes.\n", incoming_size - frame_size); libp2p_logger_debug("yamux", "Processing the data after the frame for stream %d, which is %d bytes.\n", f.streamid, incoming_size - frame_size);
if (f.streamid == 2) {
ssize_t re = yamux_stream_process(s, &f, &incoming[frame_size], incoming_size - frame_size); ssize_t re = yamux_stream_process(s, &f, &incoming[frame_size], incoming_size - frame_size);
libp2p_logger_debug("yamux", "decode: yamux_stream_process returned %d.\n", (int)re); libp2p_logger_debug("yamux", "decode: yamux_stream_process for stream %d returned %d.\n", f.streamid, (int)re);
return (re < 0) ? re : (re + incoming_size); return (re < 0) ? re : (re + incoming_size);
} else {
libp2p_logger_debug("yamux", "Only handling stream 2 for now.\n");
return 0;
}
//yamux_pull_message_from_frame(incoming, incoming_size, return_message); //yamux_pull_message_from_frame(incoming, incoming_size, return_message);
} // stream id matches } // stream id matches
} }
@ -339,8 +334,6 @@ 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) ) {
// JMJ just debugging stream 2 for now
if (f.streamid == 2) {
libp2p_logger_debug("yamux", "Stream id %d is a new stream. Creating it...\n", f.streamid); libp2p_logger_debug("yamux", "Stream id %d is a new stream. Creating it...\n", f.streamid);
struct Stream* yamuxChannelStream = yamux_channel_new(yamuxContext, f.streamid, *return_message); struct Stream* yamuxChannelStream = yamux_channel_new(yamuxContext, f.streamid, *return_message);
if (yamuxChannelStream == NULL) { if (yamuxChannelStream == NULL) {
@ -348,7 +341,6 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
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 for stream %d.\n", f.streamid); libp2p_logger_debug("yamux", "session->yamux_decode: Calling new_stream_fn for stream %d.\n", f.streamid);
yamux_session->new_stream_fn(yamuxContext, yamuxContext->stream, *return_message); yamux_session->new_stream_fn(yamuxContext, yamuxContext->stream, *return_message);
@ -377,11 +369,6 @@ int yamux_decode(void* context, const uint8_t* incoming, size_t incoming_size, s
} else { } else {
libp2p_logger_error("yamux", "Unable to negotiate multistream on stream %d.\n", f.streamid); libp2p_logger_error("yamux", "Unable to negotiate multistream on stream %d.\n", f.streamid);
} }
} else {
libp2p_logger_error("yamux", "Temporarily not doing anthing for streams other than stream 2.\n");
return 0;
}
} else { } else {
libp2p_logger_debug("yamux", "I thought this was supposed to be a new channel, but the numbering is off. The stream number is %d, and I am a %s", f.streamid, (yamuxContext->am_server ? "server" : "client)")); libp2p_logger_debug("yamux", "I thought this was supposed to be a new channel, but the numbering is off. The stream number is %d, and I am a %s", f.streamid, (yamuxContext->am_server ? "server" : "client)"));
} }
@ -404,7 +391,7 @@ struct yamux_session_stream* yamux_get_session_stream(struct yamux_session* sess
for (size_t i = 0; i < session->cap_streams; ++i) for (size_t i = 0; i < session->cap_streams; ++i)
{ {
struct yamux_session_stream* ss = &session->streams[i]; struct yamux_session_stream* ss = &session->streams[i];
if (ss->stream->stream->channel == channel) if (ss != NULL && ss->stream != NULL && ss->stream->stream != NULL && ss->stream->stream->channel == channel)
return ss; return ss;
} }
return NULL; return NULL;

View file

@ -92,7 +92,7 @@ FOUND:;
// success // success
} }
*/ */
struct Stream* channelStream = libp2p_yamux_channel_stream_new(context->stream, id); struct Stream* channelStream = nst.stream;
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;
@ -152,6 +152,9 @@ ssize_t yamux_stream_init(struct YamuxChannelContext* channel_ctx)
*/ */
ssize_t yamux_stream_close(void* context) ssize_t yamux_stream_close(void* context)
{ {
if (context == NULL)
return 0;
if ( ((char*)context)[0] == YAMUX_CHANNEL_CONTEXT) { if ( ((char*)context)[0] == YAMUX_CHANNEL_CONTEXT) {
struct YamuxChannelContext* channel_ctx = (struct YamuxChannelContext*) context; struct YamuxChannelContext* channel_ctx = (struct YamuxChannelContext*) context;
if (!channel_ctx || channel_ctx->state != yamux_stream_est || channel_ctx->closed) if (!channel_ctx || channel_ctx->state != yamux_stream_est || channel_ctx->closed)
@ -373,23 +376,31 @@ struct yamux_stream* yamux_stream_new() {
*/ */
void* yamux_read_method(void* args) { void* yamux_read_method(void* args) {
struct YamuxChannelContext* context = (struct YamuxChannelContext*) args; struct YamuxChannelContext* context = (struct YamuxChannelContext*) args;
context->read_running = 1;
struct StreamMessage* message = NULL; struct StreamMessage* message = NULL;
// continue to read until the buffer is empty // continue to read until the buffer is empty
while (context->buffer->buffer_size > 0) { while (context->buffer->buffer_size > 0) {
if (!context->read_running) { if (context->child_stream == NULL || context->child_stream->stream_context == NULL || context->child_stream->read == NULL) {
context->read_running = 1; libp2p_logger_error("yamux", "read_method: Child stream not set up properly for channel %d.\n", context->channel);
if (context->child_stream->read(context->child_stream->stream_context, &message, 5) && message != NULL) {
context->read_running = 0; context->read_running = 0;
return NULL;
}
struct Stream* child_stream = context->child_stream;
if (child_stream == NULL || child_stream->read == NULL) {
libp2p_logger_error("yamux", "read_method: Child stream not set up properly for channel %d.\n", context->channel);
context->read_running = 0;
return NULL;
}
if (context->child_stream->read(context->child_stream->stream_context, &message, 5) && message != NULL) {
libp2p_logger_debug("yamux", "read_method: read returned a message of %d bytes. [%s]\n", message->data_size, message->data); libp2p_logger_debug("yamux", "read_method: read returned a message of %d bytes. [%s]\n", message->data_size, message->data);
int retVal = libp2p_protocol_marshal(message, context->child_stream, context->yamux_context->protocol_handlers); int retVal = libp2p_protocol_marshal(message, context->child_stream, context->yamux_context->protocol_handlers);
libp2p_logger_debug("yamux", "read_method: protocol_marshal returned %d.\n", retVal); libp2p_logger_debug("yamux", "read_method: protocol_marshal returned %d.\n", retVal);
libp2p_stream_message_free(message); libp2p_stream_message_free(message);
} else { } else {
context->read_running = 0;
libp2p_logger_debug("yamux", "read_method: read returned false.\n"); libp2p_logger_debug("yamux", "read_method: read returned false.\n");
} }
} }
} context->read_running = 0;
return NULL; return NULL;
} }
@ -398,10 +409,12 @@ void* yamux_read_method(void* args) {
* @param context the YamuxChannelContext * @param context the YamuxChannelContext
*/ */
int libp2p_yamux_notify_child_stream_has_data(struct YamuxChannelContext* context) { int libp2p_yamux_notify_child_stream_has_data(struct YamuxChannelContext* context) {
if (!context->read_running) {
pthread_t new_thread; pthread_t new_thread;
if (pthread_create(&new_thread, NULL, yamux_read_method, context) == 0) if (pthread_create(&new_thread, NULL, yamux_read_method, context) == 0)
return 1; return 1;
}
return 0; return 0;
} }

View file

@ -13,6 +13,20 @@
int libp2p_yamux_channels_free(struct YamuxContext* ctx); int libp2p_yamux_channels_free(struct YamuxContext* ctx);
struct Stream* libp2p_yamux_get_parent_stream(void* context); struct Stream* libp2p_yamux_get_parent_stream(void* context);
/***
* Walks down the tree, looking for the nearest YamuxChannelContext
* @param in the stream
* @returns the YamuxChannelContext or NULL
*/
struct YamuxChannelContext* libp2p_yamux_get_parent_channel_context(struct Stream* in) {
if (in == NULL)
return NULL;
struct YamuxChannelContext* retVal = libp2p_yamux_get_channel_context(in->stream_context);
if (retVal == NULL) {
return libp2p_yamux_get_parent_channel_context(in->parent_stream);
}
return NULL;
}
/** /**
* Given a context, get the YamuxChannelContext * Given a context, get the YamuxChannelContext
* @param stream_context the context * @param stream_context the context
@ -32,6 +46,8 @@ struct YamuxChannelContext* libp2p_yamux_get_channel_context(void* stream_contex
* @returns the YamuxContext, or NULL on error * @returns the YamuxContext, or NULL on error
*/ */
struct YamuxContext* libp2p_yamux_get_context(void* stream_context) { struct YamuxContext* libp2p_yamux_get_context(void* stream_context) {
if (stream_context == NULL)
return NULL;
char proto = ((uint8_t*)stream_context)[0]; char proto = ((uint8_t*)stream_context)[0];
struct YamuxChannelContext* channel = NULL; struct YamuxChannelContext* channel = NULL;
struct YamuxContext* ctx = NULL; struct YamuxContext* ctx = NULL;
@ -527,13 +543,13 @@ int libp2p_yamux_read_raw(void* stream_context, uint8_t* buffer, int buffer_size
* @param stream the parent stream * @param stream the parent stream
* @returns a YamuxContext * @returns a YamuxContext
*/ */
struct YamuxContext* libp2p_yamux_context_new(struct Stream* stream) { struct YamuxContext* libp2p_yamux_context_new(struct Stream* stream, int amServer) {
struct YamuxContext* ctx = (struct YamuxContext*) malloc(sizeof(struct YamuxContext)); struct YamuxContext* ctx = (struct YamuxContext*) malloc(sizeof(struct YamuxContext));
if (ctx != NULL) { if (ctx != NULL) {
ctx->type = YAMUX_CONTEXT; ctx->type = YAMUX_CONTEXT;
ctx->stream = NULL; ctx->stream = NULL;
ctx->channels = libp2p_utils_vector_new(1); ctx->channels = libp2p_utils_vector_new(1);
ctx->session = yamux_session_new(NULL, stream, yamux_session_server, NULL); ctx->session = yamux_session_new(NULL, stream, amServer ? yamux_session_server : yamux_session_client, NULL);
ctx->am_server = 0; ctx->am_server = 0;
ctx->state = 0; ctx->state = 0;
ctx->buffered_message = NULL; ctx->buffered_message = NULL;
@ -568,11 +584,7 @@ int libp2p_yamux_send_protocol(struct Stream* stream) {
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")) { if (libp2p_logger_watching_class("yamux")) {
const char* stream_type = ""; libp2p_logger_debug("yamux", "handle_upgrade called for stream type %d.\n", new_stream->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 = libp2p_yamux_get_context(yamux_stream->stream_context); struct YamuxContext* yamux_context = libp2p_yamux_get_context(yamux_stream->stream_context);
struct YamuxChannelContext* yamux_channel_context = libp2p_yamux_get_channel_context(yamux_stream->stream_context); struct YamuxChannelContext* yamux_channel_context = libp2p_yamux_get_channel_context(yamux_stream->stream_context);
@ -624,7 +636,7 @@ struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream, int am_serv
out->address = parent_stream->address; out->address = parent_stream->address;
out->socket_mutex = parent_stream->socket_mutex; out->socket_mutex = parent_stream->socket_mutex;
// build YamuxContext // build YamuxContext
struct YamuxContext* ctx = libp2p_yamux_context_new(out); struct YamuxContext* ctx = libp2p_yamux_context_new(out, am_server);
if (ctx == NULL) { if (ctx == NULL) {
libp2p_yamux_stream_free(out); libp2p_yamux_stream_free(out);
return NULL; return NULL;
@ -778,18 +790,15 @@ int libp2p_yamux_channel_null_close(struct Stream* stream) {
* @returns a new Stream that has a YamuxChannelContext * @returns a new Stream that has a YamuxChannelContext
*/ */
struct Stream* libp2p_yamux_channel_stream_new(struct Stream* incoming_stream, int channelNumber) { struct Stream* libp2p_yamux_channel_stream_new(struct Stream* incoming_stream, int channelNumber) {
struct YamuxContext* yamuxContext = libp2p_yamux_get_context(incoming_stream->stream_context);
struct Stream* out = libp2p_stream_new(); struct Stream* out = libp2p_stream_new();
if (out != NULL) { if (out != NULL) {
int isYamux = 0;
char first_char = ((uint8_t*)incoming_stream->stream_context)[0];
if (first_char == YAMUX_CONTEXT)
isYamux = 1;
out->stream_type = STREAM_TYPE_YAMUX; out->stream_type = STREAM_TYPE_YAMUX;
out->address = incoming_stream->address; out->address = incoming_stream->address;
// don't allow the incoming_stream to close the channel // don't allow the incoming_stream to close the channel
out->close = libp2p_yamux_channel_null_close; out->close = libp2p_yamux_channel_null_close;
struct YamuxChannelContext* ctx = (struct YamuxChannelContext*)malloc(sizeof(struct YamuxChannelContext)); struct YamuxChannelContext* ctx = (struct YamuxChannelContext*)malloc(sizeof(struct YamuxChannelContext));
if (!isYamux) { if (yamuxContext == NULL) {
out->parent_stream = incoming_stream->parent_stream; out->parent_stream = incoming_stream->parent_stream;
out->peek = incoming_stream->parent_stream->peek; out->peek = incoming_stream->parent_stream->peek;
out->read = incoming_stream->parent_stream->read; out->read = incoming_stream->parent_stream->read;