Added ping functionality to multistream

This commit is contained in:
John Jones 2017-02-23 11:15:48 -05:00
parent e4a4226f5d
commit 8139dc9d48
11 changed files with 181 additions and 45 deletions

View file

@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include "libp2p/crypto/key.h"
#include "libp2p/crypto/rsa.h"
#include "libp2p/crypto/sha256.h"
@ -16,6 +17,21 @@
#include "mbedtls/oid.h"
#include "mbedtls/pk.h"
struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in) {
struct PrivateKey* out = libp2p_crypto_private_key_new();
if (out != NULL) {
out->data = (unsigned char*)malloc(in->der_length);
if (out->data == NULL) {
libp2p_crypto_private_key_free(out);
return NULL;
}
memcpy(out->data, in->der, in->der_length);
out->data_size = in->der_length;
out->type = KEYTYPE_RSA;
}
return out;
}
/**
* Take an rsa context and turn it into a der formatted byte stream.
* NOTE: the stream starts from the right. So there could be a lot of padding in front.

View file

@ -27,6 +27,13 @@ struct RsaPrivateKey {
size_t public_key_length;
};
/**
* Convert a struct RsaPrivateKey to a struct PrivateKey
* @param in the RsaPrivateKey
* @returns a struct PrivateKey
*/
struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in);
/**
* generate a new private key
* @param private_key the new private key

View file

@ -28,3 +28,27 @@ int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* result
* @returns the socket file descriptor of the connection, or -1 on error
*/
int libp2p_net_multistream_connect(const char* hostname, int port);
/**
* 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.
* @param fd the socket file descriptor
* @returns true(1) if the negotiation was successful.
*/
int libp2p_net_multistream_negotiate(int fd);
/**
* Expect to read a message, and follow its instructions
* @param fd the socket file descriptor
* @returns true(1) on success, false(0) if not
*/
int libp2p_net_multistream_handle_message(int fd);
/**
* 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
*/
int libp2p_net_multistream_connect(const char* hostname, int port);

View file

@ -64,3 +64,4 @@ int libp2p_message_protobuf_encode(struct Libp2pMessage* in, unsigned char* buff
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_message_protobuf_decode(unsigned char* buffer, size_t buffer_size, struct Libp2pMessage** out);

View file

@ -2,8 +2,10 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "libp2p/net/p2pnet.h"
#include "libp2p/record/message.h"
#include "varint.h"
/***
@ -135,3 +137,67 @@ int libp2p_net_multistream_connect(const char* hostname, int port) {
return retVal;
}
int libp2p_net_multistream_negotiate(int fd) {
const char* protocolID = "/multistream/1.0.0\n";
char* results;
size_t results_length = 0;
// send the protocol id
if (!libp2p_net_multistream_send(fd, (unsigned char*)protocolID, strlen(protocolID)))
return 0;
// expect the same back
libp2p_net_multistream_receive(fd, &results, &results_length);
if (results_length == 0)
return 0;
if (strncmp(results, protocolID, strlen(protocolID)) != 0)
return 0;
return 1;
}
/**
* The remote client requested a ping
* @param fd the socket file descriptor
* @param msg the incoming ping message
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_net_multistream_handle_ping(int fd, struct Libp2pMessage* msg) {
// protobuf the message
size_t protobuf_size = libp2p_message_protobuf_encode_size(msg);
unsigned char protobuf[protobuf_size];
libp2p_message_protobuf_encode(msg, &protobuf[0], protobuf_size, &protobuf_size);
libp2p_net_multistream_send(fd, protobuf, protobuf_size);
return 1;
}
/**
* Expect to read a message, and follow its instructions
* @param fd the socket file descriptor
* @returns true(1) on success, false(0) if not
*/
int libp2p_net_multistream_handle_message(int fd) {
int retVal = 0;
unsigned char* results = NULL;
size_t results_size = 0;
struct Libp2pMessage* msg = NULL;
// read what they sent
libp2p_net_multistream_receive(fd, (char**)&results, &results_size);
// unprotobuf it
if (!libp2p_message_protobuf_decode(results, results_size, &msg))
goto exit;
// do what they ask
switch (msg->message_type) {
case (MESSAGE_TYPE_PING):
libp2p_net_multistream_handle_ping(fd, msg);
break;
default:
break;
}
// clean up
retVal = 1;
exit:
if (results != NULL)
free(results);
if (msg != NULL)
libp2p_message_free(msg);
return retVal;
}

View file

@ -71,8 +71,10 @@ struct Libp2pPeer* libp2p_peer_copy(struct Libp2pPeer* in) {
}
size_t libp2p_peer_protobuf_encode_size(struct Libp2pPeer* in) {
int sz = 0;
if (in != NULL) {
// id + connection_type
int sz = 11 + in->id_size + 11;
sz = 11 + in->id_size + 11;
// loop through the multiaddresses
struct Libp2pLinkedList* current = in->addr_head;
while (current != NULL) {
@ -81,6 +83,7 @@ size_t libp2p_peer_protobuf_encode_size(struct Libp2pPeer* in) {
sz += 11 + data->bsize;
current = current->next;
}
}
return sz;
}

View file

@ -82,25 +82,34 @@ int libp2p_message_protobuf_encode(struct Libp2pMessage* in, unsigned char* buff
size_t bytes_used = 0;
*bytes_written = 0;
int retVal = 0;
size_t protobuf_size = 0;
unsigned char* protobuf = NULL;
// field 1
retVal = protobuf_encode_varint(1, WIRETYPE_VARINT, in->message_type, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
if (retVal == 0)
return 0;
*bytes_written += bytes_used;
// field 2
if (in->key != NULL) {
retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->key, in->key_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
if (retVal == 0)
return 0;
*bytes_written += bytes_used;
}
// field 3
size_t protobuf_size = libp2p_record_protobuf_encode_size(in->record);
unsigned char protobuf[protobuf_size];
if (!libp2p_record_protobuf_encode(in->record, protobuf, protobuf_size, &protobuf_size))
if (in->record != NULL) {
protobuf_size = libp2p_record_protobuf_encode_size(in->record);
protobuf = (unsigned char*) malloc(protobuf_size);
if (!libp2p_record_protobuf_encode(in->record, protobuf, protobuf_size, &protobuf_size)) {
free(protobuf);
return 0;
}
retVal = protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, protobuf, protobuf_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
free(protobuf);
if (retVal == 0)
return 0;
*bytes_written += bytes_used;
}
// field 8 (repeated)
struct Libp2pLinkedList* current = in->closer_peer_head;
while (current != NULL) {

View file

@ -97,11 +97,14 @@ int libp2p_record_protobuf_encode(const struct Libp2pRecord* in, unsigned char*
* @returns the approximate number of bytes required
*/
size_t libp2p_record_protobuf_encode_size(const struct Libp2pRecord* in) {
size_t retVal = 11 + in->key_size;
size_t retVal = 0;
if (in != NULL) {
retVal = 11 + in->key_size;
retVal += 11 + in->value_size;
retVal += 11 + in->author_size;
retVal += 11 + in->signature_size;
retVal += 11 + in->time_received_size;
}
return retVal;
}

View file

@ -499,21 +499,6 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
char* remote_peer_id = NULL;
struct EphemeralPrivateKey* e_private_key = NULL;
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, protocol, strlen((char*)protocol));
if (bytes_written <= 0)
goto exit;
// we should get back the secio confirmation
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
goto exit;
free(results);
results = NULL;
results_size = 0;
//TODO: make sure we're not talking to ourself
// generate 16 byte nonce
@ -561,9 +546,31 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
if (libp2p_secio_propose_protobuf_encode(propose_out, propose_out_bytes, propose_out_size, &propose_out_size) == 0)
goto exit;
// prepare the multistream send
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
int protocol_len = strlen((char*)protocol);
unsigned char* total = malloc(protocol_len + propose_out_size);
memcpy(total, protocol, protocol_len);
memcpy(&total[protocol_len], propose_out_bytes, propose_out_size);
bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, total, protocol_len + propose_out_size);
free(total);
if (bytes_written <= 0)
goto exit;
/*
bytes_written = libp2p_secio_write(local_session, propose_out_bytes, propose_out_size);
if (bytes_written < propose_out_size)
goto exit;
*/
// we should get back the secio confirmation
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
goto exit;
free(results);
results = NULL;
results_size = 0;
// now receive the proposal from the new connection
bytes_written = libp2p_secio_read(local_session, &propose_in_bytes, &propose_in_size);

View file

@ -42,7 +42,7 @@ int test_secio_handshake() {
if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key))
goto exit;
secure_session.host = "10.0.1.9";
secure_session.host = "192.210.179.217";
secure_session.port = 4001;
secure_session.traffic_type = TCP;
// connect to host

View file

@ -34,7 +34,7 @@ const char* names[] = {
//"test_crypto_rsa_sign",
"test_crypto_encoding_base32_encode",
"test_protobuf_private_key",
//"test_secio_handshake",
"test_secio_handshake",
"test_multistream_connect",
"test_multistream_get_list",
"test_ephemeral_key_generate",
@ -70,7 +70,7 @@ int (*funcs[])(void) = {
//test_crypto_rsa_sign,
test_crypto_encoding_base32_encode,
test_protobuf_private_key,
//test_secio_handshake,
test_secio_handshake,
test_multistream_connect,
test_multistream_get_list,
test_ephemeral_key_generate,