167 lines
4.7 KiB
C
167 lines
4.7 KiB
C
#include <stdlib.h>
|
|
|
|
#include "libp2p/record/message.h"
|
|
#include "libp2p/utils/linked_list.h"
|
|
#include "libp2p/utils/vector.h"
|
|
#include "protobuf.h"
|
|
/**
|
|
* create a new Peer struct
|
|
* @returns a struct or NULL if there was a problem
|
|
*/
|
|
struct Libp2pPeer* libp2p_message_peer_new() {
|
|
struct Libp2pPeer* out = (struct Libp2pPeer*)malloc(sizeof(struct Libp2pPeer));
|
|
if (out != NULL) {
|
|
out->id = NULL;
|
|
out->id_size = 0;
|
|
out->addr_head = NULL;
|
|
out->connection_type = CONNECTION_TYPE_NOT_CONNECTED;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
void libp2p_message_peer_free(struct Libp2pPeer* in) {
|
|
if (in != NULL) {
|
|
if (in->id != NULL)
|
|
free(in);
|
|
// free the memory in the linked list
|
|
struct Libp2pLinkedList* current = in->addr_head;
|
|
while (current != NULL) {
|
|
struct Libp2pLinkedList* temp = current->next;
|
|
free(current->item);
|
|
current = temp;
|
|
}
|
|
free(in);
|
|
}
|
|
}
|
|
|
|
size_t libp2p_message_peer_protobuf_encode_size(struct Libp2pPeer* in) {
|
|
// id + connection_type
|
|
int sz = 11 + in->id_size + 11;
|
|
// loop through the multiaddresses
|
|
struct Libp2pLinkedList* current = in->addr_head;
|
|
while (current != NULL) {
|
|
unsigned char* data = (unsigned char*)current->item;
|
|
struct Libp2pVector* vector;
|
|
if (!libp2p_utils_vector_unserialize(data, &vector))
|
|
return 0;
|
|
sz += 11 + vector->buffer_size;
|
|
libp2p_utils_vector_free(vector);
|
|
current = current->next;
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
int libp2p_message_peer_protobuf_encode(struct Libp2pPeer* in, unsigned char* buffer, size_t max_buffer_size, size_t* bytes_written) {
|
|
// data & data_size
|
|
size_t bytes_used = 0;
|
|
*bytes_written = 0;
|
|
int retVal = 0;
|
|
// field 1 (id)
|
|
retVal = protobuf_encode_length_delimited(1, WIRETYPE_LENGTH_DELIMITED, in->id, in->id_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
|
if (retVal == 0)
|
|
return 0;
|
|
*bytes_written += bytes_used;
|
|
// field 2 (repeated)
|
|
struct Libp2pLinkedList* current = in->addr_head;
|
|
while (current != NULL) {
|
|
struct Libp2pVector* vector;
|
|
if (!libp2p_utils_vector_unserialize(current->item, &vector))
|
|
return 0;
|
|
retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, vector->buffer, vector->buffer_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
|
libp2p_utils_vector_free(vector);
|
|
if (retVal == 0)
|
|
return 0;
|
|
*bytes_written += bytes_used;
|
|
current = current->next;
|
|
}
|
|
// field 3 (varint)
|
|
retVal = protobuf_encode_varint(3, WIRETYPE_VARINT, in->connection_type, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used);
|
|
if (retVal == 0)
|
|
return 0;
|
|
*bytes_written += bytes_used;
|
|
return 1;
|
|
}
|
|
|
|
int libp2p_message_peer_protobuf_decode(unsigned char* in, size_t in_size, struct Libp2pPeer** out) {
|
|
size_t pos = 0;
|
|
int retVal = 0;
|
|
unsigned char* buffer = NULL;
|
|
size_t buffer_size = 0;
|
|
struct Libp2pVector vector;
|
|
struct Libp2pLinkedList* current = NULL;
|
|
struct Libp2pLinkedList* last = NULL;
|
|
|
|
vector.buffer = NULL;
|
|
|
|
if ( (*out = (struct Libp2pPeer*)malloc(sizeof(struct Libp2pPeer))) == NULL)
|
|
goto exit;
|
|
|
|
struct Libp2pPeer* ptr = *out;
|
|
|
|
ptr->addr_head = NULL;
|
|
|
|
|
|
while(pos < in_size) {
|
|
size_t bytes_read = 0;
|
|
int field_no;
|
|
enum WireType field_type;
|
|
if (protobuf_decode_field_and_type(&in[pos], in_size, &field_no, &field_type, &bytes_read) == 0) {
|
|
goto exit;
|
|
}
|
|
pos += bytes_read;
|
|
switch(field_no) {
|
|
case (1): // id
|
|
if (!protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&(ptr->id),&(ptr->id_size), &bytes_read) == 0)
|
|
goto exit;
|
|
pos += bytes_read;
|
|
break;
|
|
case (2): { // array of bytes that is a multiaddress, put it in a vector
|
|
if (!protobuf_decode_length_delimited(&in[pos], in_size - pos, (char**)&vector.buffer, &vector.buffer_size, &bytes_read) == 0)
|
|
goto exit;
|
|
pos += bytes_read;
|
|
// now turn it into a byte array
|
|
struct Libp2pLinkedList* current = (struct Libp2pLinkedList*)malloc(sizeof(struct Libp2pLinkedList));
|
|
if (current == NULL)
|
|
goto exit;
|
|
current->next = NULL;
|
|
size_t vector_size;
|
|
if (!libp2p_utils_vector_serialize(&vector, (unsigned char**)¤t->item, &vector_size)) {
|
|
free(current);
|
|
goto exit;
|
|
}
|
|
// clean up vector
|
|
free(vector.buffer);
|
|
vector.buffer = NULL;
|
|
// assign the values
|
|
if (ptr->addr_head == NULL) {
|
|
ptr->addr_head = current;
|
|
} else {
|
|
last->next = current;
|
|
}
|
|
last = current;
|
|
current = NULL;
|
|
break;
|
|
}
|
|
case (3): // enum as varint
|
|
if (!protobuf_decode_varint(&in[pos], in_size - pos, (long long unsigned int*)&ptr->connection_type, &bytes_read) == 0)
|
|
goto exit;
|
|
pos += bytes_read;
|
|
break;
|
|
}
|
|
}
|
|
|
|
retVal = 1;
|
|
|
|
exit:
|
|
if (retVal == 0) {
|
|
free(*out);
|
|
*out = NULL;
|
|
}
|
|
if (buffer != NULL)
|
|
free(buffer);
|
|
if (vector.buffer != NULL)
|
|
free(vector.buffer);
|
|
return retVal;
|
|
|
|
}
|
|
|