More implementation of dialer

yamux
jmjatlanta 2017-10-23 18:03:38 -05:00
parent 05f2620054
commit 9dd1dab8e4
16 changed files with 156 additions and 168 deletions

View File

@ -10,6 +10,8 @@
#include "libp2p/utils/linked_list.h"
#include "multiaddr/multiaddr.h"
#include "libp2p/net/multistream.h"
#include "libp2p/secio/secio.h"
#include "libp2p/yamux/yamux.h"
struct TransportDialer* libp2p_conn_tcp_transport_dialer_new();
@ -64,10 +66,10 @@ void libp2p_conn_dialer_free(struct Dialer* in) {
* be used instead (which calls this method internally).
* @param dialer the dialer to use
* @param muiltiaddress who to connect to
* @returns a Connection, or NULL
* @returns a stream that is a ConnectionStream, or NULL
*/
struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress) {
struct Connection* conn = libp2p_conn_transport_dialer_get(dialer->transport_dialers, multiaddress);
struct Stream* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress) {
struct Stream* conn = libp2p_conn_transport_dialer_get(dialer->transport_dialers, multiaddress);
if (conn == NULL) {
conn = dialer->fallback_dialer->dial(dialer->fallback_dialer, multiaddress);
}
@ -75,12 +77,51 @@ struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer
}
/***
* Attempt to connect to a particular peer
* Attempt to connect to a particular peer. This will negotiate several protocols
* @param dialer the dialer
* @param peer the peer to join
* @returns true(1) on success, false(0) otherwise
*/
int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer* peer, int timeout_secs) {
return 0;
// find the right Multiaddress
struct Libp2pLinkedList* current_entry = peer->addr_head;
struct Stream* conn_stream = NULL;
while (current_entry != NULL) {
struct MultiAddress* ma = current_entry->item;
conn_stream = libp2p_conn_dialer_get_connection(dialer, ma);
if (conn_stream != NULL) {
break;
}
current_entry = current_entry->next;
}
if (conn_stream == NULL)
return 0;
peer->sessionContext->insecure_stream = conn_stream;
peer->sessionContext->default_stream = conn_stream;
// multistream
struct Stream* new_stream = libp2p_net_multistream_stream_new(conn_stream);
if (new_stream != NULL) {
// secio over multistream
new_stream = libp2p_secio_stream_new(new_stream);
if (new_stream != NULL) {
peer->sessionContext->default_stream = new_stream;
// multistream over secio
new_stream = libp2p_net_multistream_stream_new(new_stream);
if (new_stream != NULL) {
peer->sessionContext->default_stream = new_stream;
// yamux over multistream
new_stream = libp2p_yamux_stream_new(new_stream);
if (new_stream != NULL) {
peer->sessionContext->default_stream = new_stream;
// identity over yamux
// kademlia over yamux
// circuit relay over yamux
}
}
}
}
return 1;
}
/**
@ -90,17 +131,7 @@ int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer
* @param protocol the protocol to use (right now only 'multistream' is supported)
* @returns the ready-to-use stream
*/
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct MultiAddress* multiaddress, const char* protocol) {
// this is a shortcut for now. Other protocols will soon be implemented
if (strcmp(protocol, "multistream") != 0)
return NULL;
char* ip;
int port = multiaddress_get_ip_port(multiaddress);
if (!multiaddress_get_ip_address(multiaddress, &ip)) {
free(ip);
return NULL;
}
struct Stream* stream = libp2p_net_multistream_connect(ip, port);
free(ip);
return stream;
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct Libp2pPeer* peer, const char* protocol) {
// TODO: Implement this method
return NULL;
}

View File

@ -4,6 +4,7 @@
#include "multiaddr/multiaddr.h"
#include "libp2p/net/p2pnet.h"
#include "libp2p/net/connectionstream.h"
#include "libp2p/conn/connection.h"
#include "libp2p/conn/transport_dialer.h"
#include "multiaddr/multiaddr.h"
@ -13,36 +14,20 @@
*/
int libp2p_conn_tcp_can_handle(const struct MultiAddress* addr) {
return 1;
return multiaddress_is_ip(addr);
}
int libp2p_conn_tcp_read(const struct Connection* connection, char** out, size_t* num_bytes) {
int buffer_size = 65535;
*out = (char*)malloc(buffer_size);
ssize_t bytes = socket_read(connection->socket_handle, *out, buffer_size, 0, 5);
*num_bytes = bytes;
return bytes > 0;
}
int libp2p_conn_tcp_write(const struct Connection* connection, const char* in, size_t num_bytes) {
ssize_t bytes = socket_write(connection->socket_handle, in, num_bytes, 0);
return bytes == num_bytes;
}
struct Connection* libp2p_conn_tcp_dial(const struct TransportDialer* transport_dialer, const struct MultiAddress* addr) {
struct Connection* conn = (struct Connection*) malloc(sizeof(struct Connection));
conn->socket_handle = socket_open4();
struct Stream* libp2p_conn_tcp_dial(const struct TransportDialer* transport_dialer, const struct MultiAddress* addr) {
int socket_descriptor = socket_open4();
char* ip;
int port = multiaddress_get_ip_port(addr);
if (!multiaddress_get_ip_address(addr, &ip))
return NULL;
struct hostent* host = gethostbyname(ip);
struct Stream* stream = libp2p_net_connection_new(socket_descriptor, ip, port);
free(ip);
struct in_addr** addr_list = (struct in_addr**)host->h_addr_list;
socket_connect4(conn->socket_handle, (*addr_list[0]).s_addr, port);
conn->read = libp2p_conn_tcp_read;
conn->write = libp2p_conn_tcp_write;
return conn;
return stream;
}
struct TransportDialer* libp2p_conn_tcp_transport_dialer_new(char* peer_id, struct PrivateKey* private_key) {

View File

@ -33,7 +33,7 @@ void libp2p_conn_transport_dialer_free(struct TransportDialer* in) {
* @param multiaddr the address
* @returns a connection, or NULL if no appropriate dialer was found
*/
struct Connection* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr) {
struct Stream* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr) {
const struct Libp2pLinkedList* current = transport_dialers;
struct TransportDialer* t_dialer = NULL;
while (current != NULL) {

View File

@ -65,14 +65,14 @@ int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer
* @param muiltiaddress who to connect to
* @returns a Connection, or NULL
*/
struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress);
struct Stream* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress);
/**
* return a Stream that is already set up to use the passed in protocol
* @param dialer the dialer to use
* @param multiaddress the host to dial
* @param peer the host
* @param protocol the protocol to use (right now only 'multistream' is supported)
* @returns the ready-to-use stream
*/
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct MultiAddress* multiaddress, const char* protocol);
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct Libp2pPeer* peer, const char* protocol);

View File

@ -1,16 +1,17 @@
#pragma once
#include "multiaddr/multiaddr.h"
#include "libp2p/net/stream.h"
#include "libp2p/utils/linked_list.h"
struct TransportDialer {
char* peer_id;
struct PrivateKey* private_key;
int (*can_handle)(const struct MultiAddress* multiaddr);
struct Connection* (*dial)(const struct TransportDialer* transport_dialer, const struct MultiAddress* multiaddr);
struct Stream* (*dial)(const struct TransportDialer* transport_dialer, const struct MultiAddress* multiaddr);
};
struct TransportDialer* libp2p_conn_transport_dialer_new(char* peer_id, struct PrivateKey* private_key);
void libp2p_conn_transport_dialer_free(struct TransportDialer* in);
struct Connection* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr);
struct Stream* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr);

View File

@ -95,6 +95,6 @@ int libp2p_net_multistream_negotiate(struct SessionContext* session);
*/
struct KademliaMessage* libp2p_net_multistream_get_message(struct Stream* stream);
struct Stream* libp2p_net_multistream_stream_new(int socket_fd, const char* ip, int port);
struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream);
void libp2p_net_multistream_stream_free(struct Stream* stream);

View File

@ -1,6 +1,7 @@
#pragma once
#include <pthread.h>
#include <stdint.h>
/**
* Encapsulates a message that (was/will be) sent
@ -94,6 +95,10 @@ struct Stream {
int (*peek)(void* stream_context);
};
struct Stream* libp2p_stream_new();
void libp2p_stream_free(struct Stream* stream);
/***
* Attempt to lock a stream for personal use. Does not block.
* @param stream the stream to lock

View File

@ -20,12 +20,12 @@ struct SecioContext {
struct Libp2pProtocolHandler* libp2p_secio_build_protocol_handler(struct RsaPrivateKey* private_key, struct Peerstore* peer_store);
/***
* performs initial communication over an insecure channel to share
* keys, IDs, and initiate connection. This is a framed messaging system
* @param ctx the SecioContext
* @returns true(1) on success, false(0) otherwise
* Initiates a secio handshake. Use this method when you want to initiate a secio
* session. This should not be used to respond to incoming secio requests
* @param parent_stream the parent stream
* @returns a Secio Stream
*/
int libp2p_secio_handshake(struct SecioContext* ctx);
struct Stream* libp2p_secio_stream_new(struct Stream* parent_stream);
/***
* Initiates a secio handshake. Use this method when you want to initiate a secio
@ -47,3 +47,15 @@ int libp2p_secio_send_protocol(struct SecioContext* session);
* @returns true(1) if we received what we think we should have, false(0) otherwise
*/
int libp2p_secio_receive_protocol(struct SecioContext* session);
/***
* performs initial communication over an insecure channel to share
* keys, IDs, and initiate connection. This is a framed messaging system
* NOTE: session must contain a valid socket_descriptor that is a multistream.
* @param local_session the secure session to be filled
* @param private_key our private key to use
* @param peerstore the collection of peers
* @returns true(1) on success, false(0) otherwise
*/
int libp2p_secio_handshake(struct SecioContext* secio_context);

View File

@ -1,6 +1,11 @@
#pragma once
#include "libp2p/net/protocol.h"
#include "libp2p/net/stream.h"
/***
* Declarations for the Yamux protocol
*/
/**
* Build a handler that can handle the yamux protocol
@ -21,3 +26,5 @@ int yamux_send_protocol(struct SessionContext* context);
* @returns true(1) on success, false(0) otherwise
*/
int yamux_receive_protocol(struct SessionContext* context);
struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream);

View File

@ -7,7 +7,7 @@ endif
LFLAGS =
DEPS =
OBJS = sctp.o socket.o tcp.o udp.o multistream.o protocol.o connectionstream.o
OBJS = sctp.o socket.o tcp.o udp.o multistream.o protocol.o connectionstream.o stream.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

View File

@ -310,7 +310,8 @@ struct Stream* libp2p_net_multistream_connect_with_timeout(const char* hostname,
goto exit;
// send the multistream handshake
stream = libp2p_net_multistream_stream_new(socket, hostname, port);
// TODO: wire this back in
//stream = libp2p_net_multistream_stream_new(socket, hostname, port, NULL);
if (stream == NULL)
goto exit;
@ -391,17 +392,15 @@ void libp2p_net_multistream_stream_free(struct Stream* stream) {
* @param ip the IP address
* @param port the port
*/
struct Stream* libp2p_net_multistream_stream_new(int socket_fd, const char* ip, int port) {
struct Stream* libp2p_net_multistream_stream_new(struct Stream* parent_stream) {
struct Stream* out = (struct Stream*)malloc(sizeof(struct Stream));
if (out != NULL) {
out->parent_stream = NULL;
out->parent_stream = parent_stream;
out->close = libp2p_net_multistream_close;
out->read = libp2p_net_multistream_read;
out->write = libp2p_net_multistream_write;
out->peek = libp2p_net_multistream_peek;
char str[strlen(ip) + 50];
sprintf(str, "/ip4/%s/tcp/%d", ip, port);
out->address = multiaddress_new_from_string(str);
out->address = parent_stream->address;
}
return out;
}

25
net/stream.c Normal file
View File

@ -0,0 +1,25 @@
#include <stdlib.h>
#include "libp2p/net/stream.h"
struct Stream* libp2p_stream_new() {
struct Stream* stream = (struct Stream*) malloc(sizeof(struct Stream));
if (stream != NULL) {
stream->address = NULL;
stream->close = NULL;
stream->parent_stream = NULL;
stream->peek = NULL;
stream->read = NULL;
stream->read_raw = NULL;
stream->socket_mutex = NULL;
stream->stream_context = NULL;
stream->write = NULL;
}
return stream;
}
void libp2p_stream_free(struct Stream* stream) {
if (stream != NULL) {
free(stream);
}
}

View File

@ -72,17 +72,28 @@ int libp2p_secio_shutdown(void* context) {
/***
* Initiates a secio handshake. Use this method when you want to initiate a secio
* session. This should not be used to respond to incoming secio requests
* @param session_context the session context
* @param private_key the RSA private key to use
* @param peer_store the peer store
* @returns true(1) on success, false(0) otherwise
* @param parent_stream the parent stream
* @returns a Secio Stream
*/
int libp2p_secio_initiate_handshake(struct SecioContext* ctx) {
if (libp2p_secio_send_protocol(ctx) && libp2p_secio_receive_protocol(ctx)) {
return libp2p_secio_handshake(ctx);
struct Stream* libp2p_secio_stream_new(struct Stream* parent_stream) {
struct Stream* new_stream = libp2p_stream_new();
if (new_stream != NULL) {
struct SecioContext* ctx = (struct SecioContext*) malloc(sizeof(struct SecioContext));
if (ctx == NULL) {
libp2p_stream_free(new_stream);
new_stream = NULL;
return NULL;
}
new_stream->stream_context = ctx;
new_stream->parent_stream = parent_stream;
if (!libp2p_secio_send_protocol(ctx)
|| !libp2p_secio_receive_protocol(ctx)
|| !libp2p_secio_handshake(ctx)) {
libp2p_stream_free(new_stream);
new_stream = NULL;
}
}
libp2p_logger_error("secio", "Secio protocol exchange failed.\n");
return 0;
return new_stream;
}
struct Libp2pProtocolHandler* libp2p_secio_build_protocol_handler(struct RsaPrivateKey* private_key, struct Peerstore* peer_store) {

View File

@ -29,7 +29,7 @@ int test_dialer_dial() {
struct PrivateKey* private_key = NULL;
struct Dialer* dialer = NULL;
struct MultiAddress* destination_address = NULL;
struct Connection* conn = NULL;
struct Stream* conn = NULL;
char* result = NULL;
size_t result_size = 0;
struct Libp2pPeer* peer = libp2p_peer_new();
@ -60,7 +60,6 @@ int test_dialer_dial() {
free(peer_id);
multiaddress_free(destination_address);
libp2p_conn_dialer_free(dialer);
libp2p_conn_connection_free(conn);
return retVal;
}
@ -92,7 +91,7 @@ int test_dialer_dial_multistream() {
goto exit;
// now try to dial
stream = libp2p_conn_dialer_get_stream(dialer, destination_address, "multistream");
stream = libp2p_conn_dialer_get_stream(dialer, peer, "multistream");
if (stream == NULL)
goto exit;

View File

@ -95,33 +95,6 @@ int test_secio_handshake() {
}
// attempt to write the protocol, and see what comes back
/*
char* protocol = "/secio/1.0.0\n";
int protocol_size = strlen(protocol);
secure_session->insecure_stream->write(secure_session, (unsigned char*)protocol, protocol_size);
unsigned char* buffer = NULL;
size_t bytes_read = 0;
int timeout = 30;
secure_session->insecure_stream->read(secure_session, &buffer, &bytes_read, timeout);
if (!libp2p_secio_handshake(secure_session, rsa_private_key, peerstore)) {
fprintf(stderr, "test_secio_handshake: Unable to do handshake\n");
if (secure_session->shared_key != NULL) {
fprintf(stdout, "Shared key: ");
for(int i = 0; i < secure_session->shared_key_size; i++)
fprintf(stdout, "%d ", secure_session->shared_key[i]);
fprintf(stdout, "\nLocal stretched key: ");
print_stretched_key(secure_session->local_stretched_key);
fprintf(stdout, "\nRemote stretched key: ");
print_stretched_key(secure_session->remote_stretched_key);
fprintf(stdout, "\n");
}
goto exit;
}
*/
/*
// a new way to do the above
if (!libp2p_secio_initiate_handshake(secure_session, rsa_private_key, peerstore)) {
libp2p_logger_error("test_secio", "Unable to do handshake\n");
if (secure_session->shared_key != NULL) {
@ -137,17 +110,6 @@ int test_secio_handshake() {
goto exit;
}
/*
fprintf(stdout, "Shared key: ");
for(int i = 0; i < secure_session.shared_key_size; i++)
fprintf(stdout, "%d ", secure_session.shared_key[i]);
fprintf(stdout, "\nLocal stretched key: ");
print_stretched_key(secure_session.local_stretched_key);
fprintf(stdout, "\nRemote stretched key: ");
print_stretched_key(secure_session.remote_stretched_key);
fprintf(stdout, "\n");
*/
/*
// now attempt to do something with it... try to negotiate a multistream
if (libp2p_net_multistream_negotiate(secure_session) == 0) {
fprintf(stdout, "Unable to negotiate multistream\n");
@ -197,27 +159,6 @@ int test_secio_handshake() {
exit:
if (peerstore != NULL)
libp2p_peerstore_free(peerstore);
/*
if (secure_session.insecure_stream != NULL)
libp2p_net_multistream_stream_free(secure_session.insecure_stream);
if (secure_session.local_stretched_key != NULL)
libp2p_crypto_ephemeral_stretched_key_free(secure_session.local_stretched_key);
if (secure_session.remote_stretched_key != NULL)
libp2p_crypto_ephemeral_stretched_key_free(secure_session.remote_stretched_key);
if (secure_session.ephemeral_private_key != NULL)
libp2p_crypto_ephemeral_key_free(secure_session.ephemeral_private_key);
if (secure_session.remote_ephemeral_public_key != NULL)
free(secure_session.remote_ephemeral_public_key);
if (secure_session.chosen_cipher != NULL)
free(secure_session.chosen_cipher);
if (secure_session.chosen_curve != NULL)
free(secure_session.chosen_curve);
if (secure_session.chosen_hash != NULL)
free(secure_session.chosen_hash);
if (secure_session.shared_key != NULL)
free(secure_session.shared_key);
*/
/*
if (private_key != NULL)
libp2p_crypto_private_key_free(private_key);
if (decode_base64 != NULL)
@ -442,32 +383,6 @@ int test_secio_handshake_go() {
}
// attempt to write the protocol, and see what comes back
/*
char* protocol = "/secio/1.0.0\n";
int protocol_size = strlen(protocol);
secure_session->insecure_stream->write(secure_session, (unsigned char*)protocol, protocol_size);
unsigned char* buffer = NULL;
size_t bytes_read = 0;
int timeout = 30;
secure_session->insecure_stream->read(secure_session, &buffer, &bytes_read, timeout);
if (!libp2p_secio_handshake(secure_session, rsa_private_key, peerstore)) {
fprintf(stderr, "test_secio_handshake: Unable to do handshake\n");
if (secure_session->shared_key != NULL) {
fprintf(stdout, "Shared key: ");
for(int i = 0; i < secure_session->shared_key_size; i++)
fprintf(stdout, "%d ", secure_session->shared_key[i]);
fprintf(stdout, "\nLocal stretched key: ");
print_stretched_key(secure_session->local_stretched_key);
fprintf(stdout, "\nRemote stretched key: ");
print_stretched_key(secure_session->remote_stretched_key);
fprintf(stdout, "\n");
}
goto exit;
}
*/
/*
// a new way to do the above
if (!libp2p_secio_initiate_handshake(secure_session, rsa_private_key, peerstore)) {
libp2p_logger_error("test_secio", "Unable to do handshake.\n");
if (secure_session->shared_key != NULL) {
@ -483,17 +398,6 @@ int test_secio_handshake_go() {
goto exit;
}
/*
fprintf(stdout, "Shared key: ");
for(int i = 0; i < secure_session.shared_key_size; i++)
fprintf(stdout, "%d ", secure_session.shared_key[i]);
fprintf(stdout, "\nLocal stretched key: ");
print_stretched_key(secure_session.local_stretched_key);
fprintf(stdout, "\nRemote stretched key: ");
print_stretched_key(secure_session.remote_stretched_key);
fprintf(stdout, "\n");
*/
/*
// now attempt to do something with it... try to negotiate a multistream
if (libp2p_net_multistream_negotiate(secure_session) == 0) {
fprintf(stdout, "Unable to negotiate multistream\n");

View File

@ -170,3 +170,12 @@ struct Libp2pProtocolHandler* yamux_build_protocol_handler(struct Libp2pVector*
}
return handler;
}
/***
* Negotiate the Yamux protocol
* @param parent_stream the parent stream
* @returns a Stream initialized and ready for yamux
*/
struct Stream* libp2p_yamux_stream_new(struct Stream* parent_stream) {
return NULL;
}