2017-02-02 19:10:12 +00:00
# include <stdlib.h>
2017-02-23 20:16:04 +00:00
# include <unistd.h>
2017-02-09 08:34:12 +00:00
# include <stdio.h>
2017-02-02 19:10:12 +00:00
# include <string.h>
2017-02-09 08:34:12 +00:00
# include <errno.h>
2017-02-23 16:15:48 +00:00
# include <netinet/in.h>
# include <arpa/inet.h>
2017-08-03 16:15:40 +00:00
# include <sys/ioctl.h>
2017-08-31 11:41:06 +00:00
# include "libp2p/os/utils.h"
2017-02-02 19:10:12 +00:00
# include "libp2p/net/p2pnet.h"
2017-11-08 15:51:43 +00:00
# include "libp2p/net/connectionstream.h"
2017-02-23 16:15:48 +00:00
# include "libp2p/record/message.h"
2017-03-09 15:00:45 +00:00
# include "libp2p/secio/secio.h"
2017-02-02 19:10:12 +00:00
# include "varint.h"
2017-02-23 20:16:04 +00:00
# include "libp2p/net/multistream.h"
2017-07-13 14:01:50 +00:00
# include "libp2p/utils/logger.h"
2017-04-04 01:54:41 +00:00
# include "multiaddr/multiaddr.h"
2017-02-02 19:10:12 +00:00
2017-05-11 18:53:23 +00:00
// NOTE: this is normally set to 5 seconds, but you may want to increase this during debugging
int multistream_default_timeout = 5 ;
2017-02-02 19:10:12 +00:00
/***
* An implementation of the libp2p multistream
*/
2017-10-23 20:21:50 +00:00
int libp2p_net_multistream_can_handle ( const struct StreamMessage * msg ) {
2017-11-27 14:06:33 +00:00
if ( msg = = NULL | | msg - > data = = NULL | | msg - > data_size = = 0 )
return 0 ;
2017-08-31 21:40:35 +00:00
char * protocol = " /multistream/1.0.0 \n " ;
int protocol_size = strlen ( protocol ) ;
2017-10-23 20:21:50 +00:00
unsigned char * incoming = msg - > data ;
size_t incoming_size = msg - > data_size ;
2017-08-31 21:40:35 +00:00
// is there a varint in front?
size_t num_bytes = 0 ;
2017-09-04 16:01:17 +00:00
if ( incoming [ 0 ] ! = ' / ' & & incoming [ 1 ] ! = ' m ' ) {
varint_decode ( incoming , incoming_size , & num_bytes ) ;
}
2017-08-31 21:40:35 +00:00
if ( incoming_size > = protocol_size - num_bytes ) {
if ( strncmp ( protocol , ( char * ) & incoming [ num_bytes ] , protocol_size ) = = 0 )
return 1 ;
}
return 0 ;
}
2017-10-12 17:37:40 +00:00
/***
* Send the multistream header out the default stream
* @ param context the context
* @ returns true ( 1 ) on success , false ( 0 ) otherwise
*/
2017-09-04 16:01:17 +00:00
int libp2p_net_multistream_send_protocol ( struct SessionContext * context ) {
2017-10-23 14:47:54 +00:00
const char * protocol = " /multistream/1.0.0 \n " ;
struct StreamMessage msg ;
msg . data = ( uint8_t * ) protocol ;
msg . data_size = strlen ( protocol ) ;
if ( ! context - > default_stream - > write ( context , & msg ) ) {
2017-10-12 17:37:40 +00:00
libp2p_logger_error ( " multistream " , " send_protocol: Unable to send multistream protocol header. \n " ) ;
return 0 ;
}
return 1 ;
}
/***
* Check to see if the reply is the multistream protocol header we expect
* NOTE : if we initiate the connection , we should expect the same back
* @ param context the SessionContext
* @ returns true ( 1 ) on success , false ( 0 ) otherwise
*/
int libp2p_net_multistream_receive_protocol ( struct SessionContext * context ) {
char * protocol = " /multistream/1.0.0 \n " ;
2017-10-23 14:01:03 +00:00
struct StreamMessage * results = NULL ;
if ( ! context - > default_stream - > read ( context , & results , 30 ) ) {
2017-10-12 17:37:40 +00:00
libp2p_logger_error ( " multistream " , " receive_protocol: Unable to read results. \n " ) ;
return 0 ;
}
// the first byte is the size, so skip it
char * ptr = strstr ( ( char * ) & results [ 1 ] , protocol ) ;
if ( ptr = = NULL | | ptr - ( char * ) results > 1 ) {
return 0 ;
}
return 1 ;
2017-09-04 16:01:17 +00:00
}
2017-08-31 21:40:35 +00:00
int libp2p_net_multistream_shutdown ( void * protocol_context ) {
2017-09-07 16:05:06 +00:00
struct MultistreamContext * context = ( struct MultistreamContext * ) protocol_context ;
if ( context ! = NULL ) {
free ( context ) ;
}
2017-08-31 21:40:35 +00:00
return 1 ;
}
2017-10-23 20:21:50 +00:00
/**
* Close the connection and free memory
* @ param ctx the context
* @ returns true ( 1 ) on success , otherwise false ( 0 )
*/
int libp2p_net_multistream_context_free ( struct MultistreamContext * ctx ) {
2017-11-23 11:23:50 +00:00
struct Stream * parent_stream = ctx - > stream - > parent_stream ;
int retVal = parent_stream - > close ( parent_stream ) ;
2017-10-23 20:21:50 +00:00
// regardless of retVal, free the context
// TODO: Evaluate if this is the correct way to do it:
free ( ctx ) ;
return retVal ;
}
2017-07-27 19:32:42 +00:00
/***
* Close the Multistream interface
* NOTE : This also closes the socket
* @ param stream_context a SessionContext
2017-10-23 20:21:50 +00:00
* @ returns true ( 1 ) on success , otherwise false ( 0 )
2017-07-27 19:32:42 +00:00
*/
2017-11-08 15:51:43 +00:00
int libp2p_net_multistream_close ( struct Stream * stream ) {
if ( stream - > stream_context = = NULL ) {
2017-10-23 20:21:50 +00:00
return 0 ;
}
2017-11-08 15:51:43 +00:00
struct MultistreamContext * multistream_context = ( struct MultistreamContext * ) stream - > stream_context ;
2017-10-23 20:21:50 +00:00
return libp2p_net_multistream_context_free ( multistream_context ) ;
2017-02-23 20:16:04 +00:00
}
2017-08-03 16:15:40 +00:00
/***
* Check the stream to see if there is something to read
2017-10-23 20:21:50 +00:00
* @ param stream_context a MultistreamContext
2017-08-03 16:15:40 +00:00
* @ returns number of bytes to be read , or - 1 if there was an error
*/
int libp2p_net_multistream_peek ( void * stream_context ) {
if ( stream_context = = NULL )
return - 1 ;
2017-10-23 20:21:50 +00:00
struct MultistreamContext * multistream_context = ( struct MultistreamContext * ) stream_context ;
struct Stream * parent_stream = multistream_context - > stream - > parent_stream ;
if ( parent_stream = = NULL )
2017-08-03 16:15:40 +00:00
return - 1 ;
2017-10-25 17:28:53 +00:00
return parent_stream - > peek ( parent_stream - > stream_context ) ;
2017-08-03 16:15:40 +00:00
}
2017-11-19 18:37:03 +00:00
/**
* Add the transmission size to the front of a StreamMessage .
* NOTE : This is used internally by multistream . It is accessible to help
* with testing .
* @ param incoming the incoming message
* @ returns a new StreamMessage , in the format of a MessageStream buffer
*/
struct StreamMessage * libp2p_net_multistream_prepare_to_send ( struct StreamMessage * incoming ) {
struct StreamMessage * out = libp2p_stream_message_new ( ) ;
if ( out ! = NULL ) {
unsigned char varint [ 12 ] ;
size_t varint_size = 0 ;
varint_encode ( incoming - > data_size , & varint [ 0 ] , 12 , & varint_size ) ;
out - > data_size = varint_size + incoming - > data_size ;
out - > data = malloc ( out - > data_size ) ;
if ( out - > data = = NULL ) {
libp2p_stream_message_free ( out ) ;
return NULL ;
}
memcpy ( & out - > data [ 0 ] , varint , varint_size ) ;
memcpy ( & out - > data [ varint_size ] , incoming - > data , incoming - > data_size ) ;
}
return out ;
}
2017-02-02 19:10:12 +00:00
/**
* Write to an open multistream host
2017-07-27 17:06:27 +00:00
* @ param stream_context the session context
2017-10-23 14:47:54 +00:00
* @ param msg the data to send
2017-02-02 19:10:12 +00:00
* @ returns the number of bytes written
*/
2017-10-23 20:21:50 +00:00
int libp2p_net_multistream_write ( void * stream_context , struct StreamMessage * incoming ) {
struct MultistreamContext * multistream_context = ( struct MultistreamContext * ) stream_context ;
struct Stream * parent_stream = multistream_context - > stream - > parent_stream ;
2017-02-02 19:10:12 +00:00
int num_bytes = 0 ;
2017-10-23 20:21:50 +00:00
if ( incoming - > data_size > 0 ) { // only do this is if there is something to send
2017-11-19 18:37:03 +00:00
struct StreamMessage * out = libp2p_net_multistream_prepare_to_send ( incoming ) ;
2017-10-23 20:21:50 +00:00
// now ship it
2017-11-19 18:37:03 +00:00
libp2p_logger_debug ( " multistream " , " Attempting write %d bytes. \n " , ( int ) out - > data_size ) ;
num_bytes = parent_stream - > write ( parent_stream - > stream_context , out ) ;
2017-10-25 17:28:53 +00:00
// subtract the varint if all went well
2017-11-19 18:37:03 +00:00
if ( num_bytes = = out - > data_size )
2017-10-25 17:28:53 +00:00
num_bytes = incoming - > data_size ;
2017-11-19 18:37:03 +00:00
libp2p_stream_message_free ( out ) ;
2017-02-02 19:10:12 +00:00
}
return num_bytes ;
}
/**
* Read from a multistream socket
* @ param socket_fd the socket file descriptor
* @ param results where to put the results . NOTE : this memory is allocated
* @ param results_size the size of the results in bytes
2017-04-17 19:03:27 +00:00
* @ param timeout_secs the seconds before a timeout
2017-10-23 20:21:50 +00:00
* @ returns true ( 1 ) on success , false ( 0 ) otherwise
2017-02-02 19:10:12 +00:00
*/
2017-10-23 14:01:03 +00:00
int libp2p_net_multistream_read ( void * stream_context , struct StreamMessage * * results , int timeout_secs ) {
2017-10-23 20:21:50 +00:00
struct MultistreamContext * multistream_context = ( struct MultistreamContext * ) stream_context ;
struct Stream * parent_stream = multistream_context - > stream - > parent_stream ;
// find out the length
uint8_t varint [ 12 ] ;
2017-10-25 17:28:53 +00:00
memset ( varint , 0 , 12 ) ;
2017-10-23 20:21:50 +00:00
size_t num_bytes_requested = 0 ;
size_t varint_length = 0 ;
for ( int i = 0 ; i < 12 ; i + + ) {
2017-11-02 18:20:40 +00:00
if ( parent_stream - > read_raw ( parent_stream - > stream_context , & varint [ i ] , 1 , timeout_secs ) = = - 1 ) {
2017-11-23 11:23:50 +00:00
libp2p_logger_debug ( " multistream " , " read->read_raw returned false. \n " ) ;
2017-07-13 14:01:50 +00:00
return 0 ;
2017-07-27 20:13:35 +00:00
}
2017-10-23 20:21:50 +00:00
if ( varint [ i ] > > 7 = = 0 ) {
num_bytes_requested = varint_decode ( & varint [ 0 ] , i + 1 , & varint_length ) ;
break ;
}
}
2017-07-13 14:01:50 +00:00
2017-10-23 20:21:50 +00:00
if ( num_bytes_requested < = 0 )
return 0 ;
2017-07-13 14:01:50 +00:00
2017-10-23 20:21:50 +00:00
// now get the data
* results = libp2p_stream_message_new ( ) ;
struct StreamMessage * rslts = * results ;
rslts - > data_size = num_bytes_requested ;
rslts - > data = ( uint8_t * ) malloc ( num_bytes_requested ) ;
if ( rslts - > data = = NULL ) {
2017-11-23 11:23:50 +00:00
libp2p_logger_error ( " multistream " , " read: Attempted allocation of stream message failed. \n " ) ;
2017-10-23 20:21:50 +00:00
libp2p_stream_message_free ( rslts ) ;
rslts = NULL ;
}
// now get the data from the parent stream
if ( ! parent_stream - > read_raw ( parent_stream - > stream_context , rslts - > data , rslts - > data_size , timeout_secs ) ) {
2017-11-23 11:23:50 +00:00
libp2p_logger_error ( " multistream " , " read: Was supposed to read %d bytes, but read_raw returned false. \n " , num_bytes_requested ) ;
2017-10-23 20:21:50 +00:00
// problem reading from the parent stream
libp2p_stream_message_free ( * results ) ;
* results = NULL ;
return 0 ;
2017-07-13 14:01:50 +00:00
}
2017-10-23 20:21:50 +00:00
return 1 ;
2017-02-02 19:10:12 +00:00
}
/**
* Connect to a multistream host , and this includes the multistream handshaking .
* @ param hostname the host
* @ param port the port
* @ returns the socket file descriptor of the connection , or - 1 on error
*/
2017-02-23 20:16:04 +00:00
struct Stream * libp2p_net_multistream_connect ( const char * hostname , int port ) {
2017-08-30 16:09:28 +00:00
return libp2p_net_multistream_connect_with_timeout ( hostname , port , multistream_default_timeout ) ;
}
/**
* Connect to a multistream host , and this includes the multistream handshaking .
* @ param hostname the host
* @ param port the port
* @ param timeout_secs number of secs before timeout
* @ returns the socket file descriptor of the connection , or - 1 on error
*/
struct Stream * libp2p_net_multistream_connect_with_timeout ( const char * hostname , int port , int timeout_secs ) {
2017-02-02 20:43:35 +00:00
int retVal = - 1 , return_result = - 1 , socket = - 1 ;
2017-10-23 14:01:03 +00:00
struct StreamMessage * results = NULL ;
2017-02-23 20:16:04 +00:00
struct Stream * stream = NULL ;
2017-02-02 19:10:12 +00:00
uint32_t ip = hostname_to_ip ( hostname ) ;
socket = socket_open4 ( ) ;
// connect
2017-08-30 16:09:28 +00:00
if ( socket_connect4_with_timeout ( socket , ip , port , timeout_secs ) ! = 0 )
2017-02-02 19:10:12 +00:00
goto exit ;
// send the multistream handshake
2017-10-23 23:03:38 +00:00
// TODO: wire this back in
//stream = libp2p_net_multistream_stream_new(socket, hostname, port, NULL);
2017-02-23 20:16:04 +00:00
if ( stream = = NULL )
goto exit ;
2017-03-19 12:42:52 +00:00
struct SessionContext session ;
2017-03-09 17:49:47 +00:00
session . insecure_stream = stream ;
2017-07-13 14:01:50 +00:00
session . secure_stream = NULL ;
2017-03-09 17:49:47 +00:00
session . default_stream = stream ;
2017-02-08 17:32:41 +00:00
// try to receive the protocol id
2017-10-23 14:01:03 +00:00
return_result = libp2p_net_multistream_read ( & session , & results , timeout_secs ) ;
2017-10-23 20:21:50 +00:00
if ( results = = NULL | | return_result = = 0 | | results - > data_size < 1 | | ! libp2p_net_multistream_can_handle ( results ) ) {
2017-09-04 16:01:17 +00:00
libp2p_logger_error ( " multistream " , " Attempted to receive the multistream protocol header, but received %s. \n " , results ) ;
2017-03-02 21:14:52 +00:00
goto exit ;
2017-09-04 16:01:17 +00:00
}
2017-03-02 21:14:52 +00:00
2017-09-04 16:01:17 +00:00
if ( ! libp2p_net_multistream_send_protocol ( & session ) ) {
libp2p_logger_error ( " multistream " , " Attempted to send the multistream protocol header, but could not. \n " ) ;
2017-02-08 17:32:41 +00:00
goto exit ;
2017-09-04 16:01:17 +00:00
}
2017-02-08 17:32:41 +00:00
2017-02-02 23:27:57 +00:00
// we are now in the loop, so we can switch to another protocol (i.e. /secio/1.0.0)
2017-02-02 19:10:12 +00:00
retVal = socket ;
exit :
if ( results ! = NULL )
free ( results ) ;
2017-02-23 20:16:04 +00:00
if ( retVal < 0 & & stream ! = NULL ) {
libp2p_net_multistream_stream_free ( stream ) ;
stream = NULL ;
}
2017-07-07 01:09:38 +00:00
if ( retVal < 0 & & socket > 0 )
close ( socket ) ;
2017-02-23 20:16:04 +00:00
return stream ;
2017-02-02 19:10:12 +00:00
}
2017-07-17 18:04:43 +00:00
/**
* Negotiate the multistream protocol by sending and receiving the protocol id . This is a server side function .
* Servers should send the protocol ID , and then expect it back .
* NOTE : the SessionContext should already contain the connected stream . If not , use
* libp2p_net_multistream_connect instead of this method .
*
2017-10-25 17:28:53 +00:00
* @ param ctx a MultistreamContext
2017-11-23 11:23:50 +00:00
* @ param theyRequested true ( 1 ) if the multistream ID has already been received from the client
2017-07-17 18:04:43 +00:00
* @ returns true ( 1 ) on success , or false ( 0 )
*/
2017-11-23 11:23:50 +00:00
int libp2p_net_multistream_negotiate ( struct MultistreamContext * ctx , int theyRequested ) {
2017-02-23 16:15:48 +00:00
const char * protocolID = " /multistream/1.0.0 \n " ;
2017-10-23 14:47:54 +00:00
struct StreamMessage outgoing ;
2017-10-23 14:01:03 +00:00
struct StreamMessage * results = NULL ;
2017-02-23 20:16:04 +00:00
int retVal = 0 ;
2017-11-02 18:20:40 +00:00
int haveTheirs = 0 ;
int peek_result = 0 ;
2017-11-23 11:23:50 +00:00
if ( ! theyRequested ) {
// see if they're trying to send something first
peek_result = libp2p_net_multistream_peek ( ctx ) ;
/*
if ( peek_result < 0 ) {
libp2p_logger_error ( " multistream " , " Attempted a peek, but received an error. \n " ) ;
return 0 ;
}
*/
if ( peek_result > 0 ) {
libp2p_logger_debug ( " multistream " , " negotiate: There is %d bytes waiting for us. Perhaps it is the multistream header we're expecting. \n " , peek_result ) ;
// get the protocol
//ctx->stream->parent_stream->read(ctx->stream->parent_stream->stream_context, &results, multistream_default_timeout);
libp2p_net_multistream_read ( ctx , & results , multistream_default_timeout ) ;
if ( results = = NULL | | results - > data_size = = 0 )
goto exit ;
if ( strncmp ( ( char * ) results - > data , protocolID , strlen ( protocolID ) ) ! = 0 )
goto exit ;
haveTheirs = 1 ;
}
2017-11-02 18:20:40 +00:00
}
2017-02-23 16:15:48 +00:00
// send the protocol id
2017-10-23 14:47:54 +00:00
outgoing . data = ( uint8_t * ) protocolID ;
outgoing . data_size = strlen ( protocolID ) ;
2017-11-23 11:23:50 +00:00
if ( ! libp2p_net_multistream_write ( ctx , & outgoing ) ) {
libp2p_logger_debug ( " multistream " , " negotiate: Attempted to send the multistream id, but the write failed. \n " ) ;
2017-02-23 20:16:04 +00:00
goto exit ;
2017-11-23 11:23:50 +00:00
}
2017-11-02 18:20:40 +00:00
// wait for them to send the protocol id back
2017-11-23 11:23:50 +00:00
if ( ! theyRequested & & ! haveTheirs ) {
libp2p_logger_debug ( " multistream " , " negotiate: Wrote multistream id to network, awaiting reply... \n " ) ;
2017-11-02 18:20:40 +00:00
// expect the same back
2017-11-23 11:23:50 +00:00
int retVal = libp2p_net_multistream_read ( ctx , & results , multistream_default_timeout ) ;
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 ) ;
2017-11-02 18:20:40 +00:00
goto exit ;
2017-11-23 11:23:50 +00:00
}
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 ) ;
2017-11-02 18:20:40 +00:00
goto exit ;
2017-11-23 11:23:50 +00:00
}
2017-11-02 18:20:40 +00:00
}
2017-02-23 20:16:04 +00:00
retVal = 1 ;
exit :
if ( results ! = NULL )
free ( results ) ;
return retVal ;
2017-02-23 16:15:48 +00:00
}
2017-02-23 20:16:04 +00:00
void libp2p_net_multistream_stream_free ( struct Stream * stream ) {
if ( stream ! = NULL ) {
2017-11-19 18:37:03 +00:00
stream - > parent_stream - > close ( stream - > parent_stream ) ;
2017-10-23 20:21:50 +00:00
// TODO: free memory allocations
2017-02-23 20:16:04 +00:00
}
2017-02-23 16:15:48 +00:00
}
2017-02-23 20:16:04 +00:00
2017-11-02 18:20:40 +00:00
int libp2p_net_multistream_read_raw ( void * stream_context , uint8_t * buffer , int buffer_len , int timeout_secs ) {
if ( stream_context = = NULL )
return 0 ;
struct MultistreamContext * ctx = ( struct MultistreamContext * ) stream_context ;
return ctx - > stream - > parent_stream - > read_raw ( ctx - > stream - > parent_stream - > stream_context , buffer , buffer_len , timeout_secs ) ;
}
2017-11-23 11:23:50 +00:00
/**
* We want to try and negotiate Multistream on the incoming stream
*/
struct Stream * libp2p_net_multistream_handshake ( struct Stream * stream ) {
//TODO: implement this method
return NULL ;
}
2017-11-27 14:06:33 +00:00
/***
* The protocol above is asking for an upgrade
* @ param multistream this stream ( a multistream )
* @ param new_stream the protocol above
* @ returns true ( 1 ) on success , false ( 0 ) otherwise
*/
int libp2p_net_multistream_handle_upgrade ( struct Stream * multistream , struct Stream * new_stream ) {
// take multistream out of the picture
if ( new_stream - > parent_stream = = multistream ) {
new_stream - > parent_stream = multistream - > parent_stream ;
}
return 1 ;
}
2017-04-04 01:54:41 +00:00
/**
* Create a new MultiStream structure
2017-11-23 11:23:50 +00:00
* @ 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
2017-04-04 01:54:41 +00:00
*/
2017-11-23 11:23:50 +00:00
struct Stream * libp2p_net_multistream_stream_new ( struct Stream * parent_stream , int theyRequested ) {
2017-02-23 20:16:04 +00:00
struct Stream * out = ( struct Stream * ) malloc ( sizeof ( struct Stream ) ) ;
if ( out ! = NULL ) {
2017-11-19 18:37:03 +00:00
out - > stream_type = STREAM_TYPE_MULTISTREAM ;
2017-10-23 23:03:38 +00:00
out - > parent_stream = parent_stream ;
2017-02-23 20:16:04 +00:00
out - > close = libp2p_net_multistream_close ;
out - > read = libp2p_net_multistream_read ;
out - > write = libp2p_net_multistream_write ;
2017-08-03 16:15:40 +00:00
out - > peek = libp2p_net_multistream_peek ;
2017-11-02 18:20:40 +00:00
out - > read_raw = libp2p_net_multistream_read_raw ;
2017-11-23 11:23:50 +00:00
out - > negotiate = libp2p_net_multistream_handshake ;
2017-11-27 14:06:33 +00:00
out - > handle_upgrade = libp2p_net_multistream_handle_upgrade ;
2017-10-23 23:03:38 +00:00
out - > address = parent_stream - > address ;
2017-10-25 17:28:53 +00:00
// build MultistreamContext
struct MultistreamContext * ctx = ( struct MultistreamContext * ) malloc ( sizeof ( struct MultistreamContext ) ) ;
if ( ctx = = NULL ) {
libp2p_net_multistream_stream_free ( out ) ;
return NULL ;
}
out - > stream_context = ctx ;
ctx - > stream = out ;
ctx - > handlers = NULL ;
ctx - > session_context = NULL ;
// attempt to negotiate multistream protocol
2017-11-23 11:23:50 +00:00
if ( ! libp2p_net_multistream_negotiate ( ctx , theyRequested ) ) {
libp2p_logger_debug ( " multistream " , " multistream_stream_new: negotiate failed \n " ) ;
2017-10-25 17:28:53 +00:00
libp2p_net_multistream_stream_free ( out ) ;
return NULL ;
}
2017-02-23 20:16:04 +00:00
}
return out ;
}
2017-11-08 15:51:43 +00:00
/***
* The remote is attempting to negotiate the multistream protocol
* @ param msg incoming message
* @ param stream the incoming stream
* @ param protocol_context the context for the Multistream protocol ( not stream specific )
* @ returns < 0 on error , 0 for the caller to stop handling this , 1 for success
*/
int libp2p_net_multistream_handle_message ( const struct StreamMessage * msg , struct Stream * stream , void * protocol_context ) {
// attempt negotiations
2017-11-23 11:23:50 +00:00
struct Stream * new_stream = libp2p_net_multistream_stream_new ( stream , 1 ) ;
2017-11-08 15:51:43 +00:00
if ( new_stream ! = NULL ) {
// upgrade
return stream - > handle_upgrade ( stream , new_stream ) ;
}
return - 1 ;
}
/***
* The handler to handle calls to the protocol
2017-11-23 11:23:50 +00:00
* @ param handler_vector a Libp2pVector of protocol handlers
2017-11-08 15:51:43 +00:00
* @ returns the protocol handler
*/
struct Libp2pProtocolHandler * libp2p_net_multistream_build_protocol_handler ( void * handler_vector ) {
// build the context
struct MultistreamContext * context = ( struct MultistreamContext * ) malloc ( sizeof ( struct MultistreamContext ) ) ;
if ( context = = NULL )
return NULL ;
context - > handlers = ( struct Libp2pVector * ) handler_vector ;
// build the handler
struct Libp2pProtocolHandler * handler = libp2p_protocol_handler_new ( ) ;
if ( handler ! = NULL ) {
handler - > context = context ;
handler - > CanHandle = libp2p_net_multistream_can_handle ;
handler - > HandleMessage = libp2p_net_multistream_handle_message ;
handler - > Shutdown = libp2p_net_multistream_shutdown ;
}
return handler ;
}