c-libp2p/conn/dialer.c

185 lines
6.6 KiB
C
Raw Permalink Normal View History

2017-02-13 18:26:41 +00:00
#include <stdlib.h>
2017-02-13 13:47:55 +00:00
/**
* Functions for handling the local dialer
*/
2017-02-13 18:26:41 +00:00
2017-10-25 17:28:53 +00:00
#include "libp2p/crypto/encoding/x509.h"
2017-02-13 18:26:41 +00:00
#include "libp2p/conn/dialer.h"
#include "libp2p/conn/connection.h"
#include "libp2p/conn/transport_dialer.h"
#include "libp2p/crypto/key.h"
#include "libp2p/utils/linked_list.h"
#include "libp2p/utils/logger.h"
2017-03-09 23:48:28 +00:00
#include "multiaddr/multiaddr.h"
2017-03-02 21:14:52 +00:00
#include "libp2p/net/multistream.h"
2017-10-23 23:03:38 +00:00
#include "libp2p/secio/secio.h"
#include "libp2p/yamux/yamux.h"
#include "libp2p/identify/identify.h"
2017-02-13 18:26:41 +00:00
struct TransportDialer* libp2p_conn_tcp_transport_dialer_new();
2017-02-13 18:26:41 +00:00
/**
* Create a Dialer with the specified local information
2017-10-25 17:28:53 +00:00
* @param peer the local peer
* @param peerstore the local peerstore
* @param private_key the local private key
* @returns a new Dialer struct
2017-02-13 18:26:41 +00:00
*/
struct Dialer* libp2p_conn_dialer_new(struct Libp2pPeer* peer, struct Peerstore* peerstore, struct RsaPrivateKey* rsa_private_key, struct SwarmContext* swarm) {
int success = 0;
2017-02-13 18:26:41 +00:00
struct Dialer* dialer = (struct Dialer*)malloc(sizeof(struct Dialer));
if (dialer != NULL) {
2017-10-25 17:28:53 +00:00
dialer->peerstore = peerstore;
2017-11-20 00:29:40 +00:00
dialer->private_key = rsa_private_key;
dialer->transport_dialers = NULL;
dialer->fallback_dialer = libp2p_conn_tcp_transport_dialer_new(dialer->peer_id, rsa_private_key);
dialer->swarm = swarm;
2017-11-20 00:29:40 +00:00
if (peer != NULL) {
dialer->peer_id = malloc(peer->id_size + 1);
memset(dialer->peer_id, 0, peer->id_size + 1);
if (dialer->peer_id != NULL) {
strncpy(dialer->peer_id, peer->id, peer->id_size);
2017-10-25 17:28:53 +00:00
}
2017-02-13 22:41:31 +00:00
}
2017-11-20 00:29:40 +00:00
return dialer;
2017-02-13 18:26:41 +00:00
}
2017-02-13 22:41:31 +00:00
libp2p_conn_dialer_free(dialer);
return NULL;
2017-02-13 18:26:41 +00:00
}
/**
* Free resources from the Dialer
* NOTE: this frees the fallback dialer too (should we be doing this?
* @param in the Dialer struct to free
2017-02-13 18:26:41 +00:00
*/
void libp2p_conn_dialer_free(struct Dialer* in) {
if (in != NULL) {
2017-11-20 00:29:40 +00:00
if (in->peer_id != NULL)
free(in->peer_id);
2017-10-25 17:28:53 +00:00
libp2p_crypto_rsa_rsa_private_key_free(in->private_key);
2017-02-13 18:26:41 +00:00
if (in->transport_dialers != NULL) {
struct Libp2pLinkedList* current = in->transport_dialers;
while(current != NULL) {
libp2p_conn_transport_dialer_free((struct TransportDialer*)current->item);
current = current->next;
}
}
if (in->fallback_dialer != NULL)
libp2p_conn_transport_dialer_free((struct TransportDialer*)in->fallback_dialer);
free(in);
2017-02-13 18:26:41 +00:00
}
return;
}
/**
* Retrieve a Connection struct from the dialer
2017-03-02 21:14:52 +00:00
* NOTE: This should no longer be used. _get_stream should
* be used instead (which calls this method internally).
2017-02-13 18:26:41 +00:00
* @param dialer the dialer to use
* @param muiltiaddress who to connect to
2017-10-23 23:03:38 +00:00
* @returns a stream that is a ConnectionStream, or NULL
2017-02-13 18:26:41 +00:00
*/
2017-10-23 23:03:38 +00:00
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);
2017-02-13 18:26:41 +00:00
if (conn == NULL) {
conn = dialer->fallback_dialer->dial(dialer->fallback_dialer, multiaddress);
2017-02-13 18:26:41 +00:00
}
return conn;
}
2017-03-02 21:14:52 +00:00
2017-10-23 21:21:03 +00:00
/***
2017-10-23 23:03:38 +00:00
* Attempt to connect to a particular peer. This will negotiate several protocols
2017-10-23 21:21:03 +00:00
* @param dialer the dialer
* @param peer the peer to join
2017-10-23 23:03:38 +00:00
* @returns true(1) on success, false(0) otherwise
2017-10-23 21:21:03 +00:00
*/
int libp2p_conn_dialer_join_swarm(const struct Dialer* dialer, struct Libp2pPeer* peer, int timeout_secs) {
2017-10-25 17:28:53 +00:00
if (dialer == NULL || peer == NULL)
return 0;
2017-10-23 23:03:38 +00:00
// 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) {
2017-10-25 17:28:53 +00:00
if (peer->sessionContext == NULL) {
peer->sessionContext = libp2p_session_context_new();
struct ConnectionContext* conn_ctx = conn_stream->stream_context;
conn_ctx->session_context = peer->sessionContext;
2017-10-25 17:28:53 +00:00
}
peer->sessionContext->insecure_stream = conn_stream;
peer->sessionContext->default_stream = conn_stream;
peer->sessionContext->port = multiaddress_get_ip_port(ma);
multiaddress_get_ip_address(ma, &peer->sessionContext->host);
2017-10-23 23:03:38 +00:00
break;
}
current_entry = current_entry->next;
}
if (conn_stream == NULL)
return 0;
// we're connected. start listening for responses
libp2p_swarm_add_peer(dialer->swarm, peer);
// wait for multistream
if (!libp2p_net_multistream_ready(peer->sessionContext, 5)) {
return 0;
}
struct Stream* new_stream = peer->sessionContext->default_stream;
2017-10-23 23:03:38 +00:00
if (new_stream != NULL) {
// secio over multistream
new_stream = libp2p_secio_stream_new(new_stream, dialer->peerstore, dialer->private_key);
2017-10-23 23:03:38 +00:00
if (new_stream != NULL) {
2017-11-29 04:41:46 +00:00
if (!libp2p_secio_ready(peer->sessionContext, 10) ) {
return 0;
}
libp2p_logger_debug("dialer", "We successfully negotiated secio.\n");
2017-10-23 23:03:38 +00:00
// multistream over secio
2017-11-29 04:41:46 +00:00
// Don't bother, as the other side requests multistream
//new_stream = libp2p_net_multistream_stream_new(new_stream, 0);
2017-10-23 23:03:38 +00:00
if (new_stream != NULL) {
2017-11-29 04:41:46 +00:00
if (!libp2p_net_multistream_ready(peer->sessionContext, 5))
return 0;
libp2p_logger_debug("dialer", "We successfully negotiated multistream over secio.\n");
2017-10-23 23:03:38 +00:00
// yamux over multistream
2017-11-29 04:58:28 +00:00
new_stream = libp2p_yamux_stream_new(peer->sessionContext->default_stream, 0, NULL);
2017-10-23 23:03:38 +00:00
if (new_stream != NULL) {
2017-11-29 04:41:46 +00:00
if (!libp2p_yamux_stream_ready(peer->sessionContext, 5))
return 0;
libp2p_logger_debug("dialer", "We successfully negotiated yamux.\n");
//peer->sessionContext->default_stream = new_stream;
// we have our swarm connection. Now we ask for some "channels"
// id over yamux
2017-11-27 14:06:33 +00:00
//libp2p_yamux_stream_add(new_stream->stream_context, libp2p_identify_stream_new(new_stream));
2017-10-23 23:03:38 +00:00
// kademlia over yamux
//libp2p_yamux_stream_add(new_stream->stream_context, libp2p_kademlia_stream_new(new_stream));
2017-10-23 23:03:38 +00:00
// circuit relay over yamux
//libp2p_yamux_stream_add(new_stream->stream_context, libp2p_circuit_relay_stream_new(new_stream));
2017-10-25 17:28:53 +00:00
return 1;
} else {
libp2p_logger_error("dialer", "Unable to do yamux negotiation.\n");
2017-10-23 23:03:38 +00:00
}
} else {
libp2p_logger_error("dialer", "Unable to do secio/multistream negotiation.\n");
2017-10-23 23:03:38 +00:00
}
} else {
libp2p_logger_error("dialer", "Unable to do secio negotiation.\n");
2017-10-23 23:03:38 +00:00
}
} else {
libp2p_logger_error("dialer", "Unable to do initial multistream negotiation.\n");
2017-10-23 23:03:38 +00:00
}
2017-10-25 17:28:53 +00:00
return 0;
2017-10-23 21:21:03 +00:00
}
2017-03-02 21:14:52 +00:00
/**
* 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 protocol the protocol to use (right now only 'multistream' is supported)
* @returns the ready-to-use stream
*/
2017-10-23 23:03:38 +00:00
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct Libp2pPeer* peer, const char* protocol) {
// TODO: Implement this method
return NULL;
2017-03-02 21:14:52 +00:00
}