More implementation of the yamux protocol
This commit is contained in:
parent
5e1cdac4cf
commit
9200e0f09c
4 changed files with 149 additions and 7 deletions
|
@ -37,7 +37,16 @@ struct yamux_frame
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
/***
|
||||||
|
* convert the frame so it can be sent over the network (makes the endienness correct)
|
||||||
|
* @param frame the frame to encode
|
||||||
|
*/
|
||||||
void encode_frame(struct yamux_frame* frame);
|
void encode_frame(struct yamux_frame* frame);
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Convert the frame from the network format to the local format (corrects endienness)
|
||||||
|
* @param frame the frame to decode
|
||||||
|
*/
|
||||||
void decode_frame(struct yamux_frame* frame);
|
void decode_frame(struct yamux_frame* frame);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,16 @@
|
||||||
* Declarations for the Yamux protocol
|
* Declarations for the Yamux protocol
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const int yamux_default_timeout = 10;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Context struct for Yamux
|
||||||
|
*/
|
||||||
|
struct YamuxContext {
|
||||||
|
struct Stream* stream;
|
||||||
|
struct yamux_session* session;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a handler that can handle the yamux protocol
|
* Build a handler that can handle the yamux protocol
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,6 +22,10 @@ static void set_eness()
|
||||||
eness = big;
|
eness = big;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* convert the frame so it can be sent over the network (makes the endienness correct)
|
||||||
|
* @param frame the frame to encode
|
||||||
|
*/
|
||||||
void encode_frame(struct yamux_frame* frame)
|
void encode_frame(struct yamux_frame* frame)
|
||||||
{
|
{
|
||||||
if (eness == unk)
|
if (eness == unk)
|
||||||
|
@ -31,6 +35,11 @@ void encode_frame(struct yamux_frame* frame)
|
||||||
frame->streamid = htonl(frame->streamid);
|
frame->streamid = htonl(frame->streamid);
|
||||||
frame->length = htonl(frame->length );
|
frame->length = htonl(frame->length );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Convert the frame from the network format to the local format (corrects endienness)
|
||||||
|
* @param frame the frame to decode
|
||||||
|
*/
|
||||||
void decode_frame(struct yamux_frame* frame)
|
void decode_frame(struct yamux_frame* frame)
|
||||||
{
|
{
|
||||||
if (eness == unk)
|
if (eness == unk)
|
||||||
|
|
128
yamux/yamux.c
128
yamux/yamux.c
|
@ -2,6 +2,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "varint.h"
|
#include "varint.h"
|
||||||
#include "libp2p/yamux/session.h"
|
#include "libp2p/yamux/session.h"
|
||||||
|
#include "libp2p/yamux/yamux.h"
|
||||||
#include "libp2p/net/protocol.h"
|
#include "libp2p/net/protocol.h"
|
||||||
#include "libp2p/net/stream.h"
|
#include "libp2p/net/stream.h"
|
||||||
#include "libp2p/conn/session.h"
|
#include "libp2p/conn/session.h"
|
||||||
|
@ -171,14 +172,130 @@ struct Libp2pProtocolHandler* yamux_build_protocol_handler(struct Libp2pVector*
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int libp2p_yamux_close(void* stream_context) {
|
||||||
|
//TODO: Implement
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from the network, expecting a yamux frame.
|
||||||
|
* NOTE: This will also dispatch the frame to the correct protocol
|
||||||
|
* @param stream_context the YamuxContext
|
||||||
|
* @param message the resultant message
|
||||||
|
* @param timeout_secs when to give up
|
||||||
|
* @returns true(1) on success, false(0) on failure
|
||||||
|
*/
|
||||||
|
int libp2p_yamux_read(void* stream_context, struct StreamMessage** message, int timeout_secs) {
|
||||||
|
struct YamuxContext* ctx = (struct YamuxContext*)stream_context;
|
||||||
|
struct Stream* parent_stream = ctx->stream->parent_stream;
|
||||||
|
|
||||||
|
struct StreamMessage* incoming;
|
||||||
|
if (!parent_stream->read(parent_stream->stream_context, &incoming, timeout_secs))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// we've got bytes from the network. process them as a yamux frame
|
||||||
|
return yamux_decode(ctx->session, incoming->data, incoming->data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int libp2p_yamux_write(void* stream_context, struct StreamMessage* message) {
|
||||||
|
//TODO: Implement
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* Check to see if there is anything waiting on the network.
|
||||||
|
* @param stream_context the YamuxContext
|
||||||
|
* @returns the number of bytes waiting, or -1 on error
|
||||||
|
*/
|
||||||
|
int libp2p_yamux_peek(void* stream_context) {
|
||||||
|
if (stream_context == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
struct YamuxContext* ctx = (struct YamuxContext*)stream_context;
|
||||||
|
struct Stream* parent_stream = ctx->stream->parent_stream;
|
||||||
|
if (parent_stream == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return parent_stream->peek(parent_stream->stream_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int libp2p_yamux_read_raw(void* stream_context, uint8_t* buffer, int buffer_size, int timeout_secs) {
|
||||||
|
//TODO: Implement
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct YamuxContext* libp2p_yamux_context_new() {
|
||||||
|
struct YamuxContext* ctx = (struct YamuxContext*) malloc(sizeof(struct YamuxContext));
|
||||||
|
if (ctx != NULL) {
|
||||||
|
ctx->stream = NULL;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libp2p_yamux_stream_free(struct Stream* yamux_stream) {
|
||||||
|
//TODO: Implement
|
||||||
|
}
|
||||||
|
|
||||||
|
int libp2p_yamux_negotiate(struct YamuxContext* ctx) {
|
||||||
|
const char* protocolID = "/yamux/1.0.0\n";
|
||||||
|
struct StreamMessage outgoing;
|
||||||
|
struct StreamMessage* results = NULL;
|
||||||
|
int retVal = 0;
|
||||||
|
int haveTheirs = 0;
|
||||||
|
int peek_result = 0;
|
||||||
|
|
||||||
|
// see if they're trying to send something first
|
||||||
|
peek_result = libp2p_yamux_peek(ctx);
|
||||||
|
if (peek_result > 0) {
|
||||||
|
libp2p_logger_debug("yamux", "There is %d bytes waiting for us. Perhaps it is the yamux header we're expecting.\n", peek_result);
|
||||||
|
// get the protocol
|
||||||
|
ctx->stream->parent_stream->read(ctx->stream->parent_stream, &results, yamux_default_timeout);
|
||||||
|
if (results == NULL || results->data_size == 0) {
|
||||||
|
libp2p_logger_error("yamux", "We thought we had a yamux header, but we got nothing.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0) {
|
||||||
|
libp2p_logger_error("yamux", "We thought we had a yamux header, but we received %d bytes that contained %s.\n", (int)results->data_size, results->data);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
haveTheirs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the protocol id
|
||||||
|
outgoing.data = (uint8_t*)protocolID;
|
||||||
|
outgoing.data_size = strlen(protocolID);
|
||||||
|
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");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for them to send the protocol id back
|
||||||
|
if (!haveTheirs) {
|
||||||
|
// expect the same back
|
||||||
|
ctx->stream->parent_stream->read(ctx->stream->parent_stream->stream_context, &results, yamux_default_timeout);
|
||||||
|
if (results == NULL || results->data_size == 0) {
|
||||||
|
libp2p_logger_error("yamux", "We tried to retrieve the yamux header, but we got nothing.\n");
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
if (strncmp((char*)results->data, protocolID, strlen(protocolID)) != 0) {
|
||||||
|
libp2p_logger_error("yamux", "We tried to retrieve the yamux header, but we received %d bytes that contained %s.\n", (int)results->data_size, results->data);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retVal = 1;
|
||||||
|
exit:
|
||||||
|
if (results != NULL)
|
||||||
|
free(results);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Negotiate the Yamux protocol
|
* Negotiate the Yamux protocol
|
||||||
* @param parent_stream the parent stream
|
* @param parent_stream the parent stream
|
||||||
* @returns a Stream initialized and ready for yamux
|
* @returns a Stream initialized and ready for yamux
|
||||||
*/
|
*/
|
||||||
struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream) {
|
struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream) {
|
||||||
struct Stream* out = NULL;
|
|
||||||
/*
|
|
||||||
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->parent_stream = parent_stream;
|
out->parent_stream = parent_stream;
|
||||||
|
@ -189,21 +306,18 @@ struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream) {
|
||||||
out->read_raw = libp2p_yamux_read_raw;
|
out->read_raw = libp2p_yamux_read_raw;
|
||||||
out->address = parent_stream->address;
|
out->address = parent_stream->address;
|
||||||
// build YamuxContext
|
// build YamuxContext
|
||||||
struct YamuxContext* ctx = (struct YamuxContext*) malloc(sizeof(struct YamuxContext));
|
struct YamuxContext* ctx = libp2p_yamux_context_new();
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
libp2p_net_multistream_stream_free(out);
|
libp2p_yamux_stream_free(out);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
out->stream_context = ctx;
|
out->stream_context = ctx;
|
||||||
ctx->stream = out;
|
ctx->stream = out;
|
||||||
ctx->handlers = NULL;
|
|
||||||
ctx->session_context = NULL;
|
|
||||||
// attempt to negotiate yamux protocol
|
// attempt to negotiate yamux protocol
|
||||||
if (!libp2p_yamux_negotiate(ctx)) {
|
if (!libp2p_yamux_negotiate(ctx)) {
|
||||||
libp2p_yamux_stream_free(out);
|
libp2p_yamux_stream_free(out);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue