forked from agorise/c-ipfs
171 lines
5.5 KiB
C
171 lines
5.5 KiB
C
#include "ipfs/journal/journal_message.h"
|
|
#include "ipfs/journal/journal_entry.h"
|
|
#include "libp2p/utils/logger.h"
|
|
#include "protobuf.h"
|
|
|
|
struct JournalMessage* ipfs_journal_message_new() {
|
|
struct JournalMessage *message = (struct JournalMessage*) malloc(sizeof(struct JournalMessage));
|
|
if (message != NULL) {
|
|
message->current_epoch = 0;
|
|
message->end_epoch = 0;
|
|
message->start_epoch = 0;
|
|
message->journal_entries = libp2p_utils_vector_new(1);
|
|
}
|
|
return message;
|
|
}
|
|
|
|
int ipfs_journal_message_free(struct JournalMessage* message) {
|
|
if (message != NULL) {
|
|
if (message->journal_entries != NULL) {
|
|
for(int i = 0; i < message->journal_entries->total; i++) {
|
|
struct JournalEntry* entry = (struct JournalEntry*) libp2p_utils_vector_get(message->journal_entries, i);
|
|
ipfs_journal_entry_free(entry);
|
|
}
|
|
libp2p_utils_vector_free(message->journal_entries);
|
|
message->journal_entries = NULL;
|
|
}
|
|
free(message);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Determine the maximum size of a protobuf'd JournalMessage
|
|
* @param message the JournalMessage
|
|
* @returns the maximum size of this message in bytes if it were protobuf'd
|
|
*/
|
|
int ipfs_journal_message_encode_size(struct JournalMessage* message) {
|
|
// 3 epochs
|
|
int sz = 33;
|
|
// journal entries
|
|
for (int i = 0; i < message->journal_entries->total; i++) {
|
|
struct JournalEntry* entry = (struct JournalEntry*) libp2p_utils_vector_get(message->journal_entries, i);
|
|
sz += ipfs_journal_entry_encode_size(entry);
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
/***
|
|
* Protobuf the journal message
|
|
* @param message the JournalMessage to protobuf
|
|
* @param buffer where to place the results
|
|
* @param max_buffer_size the amount of memory allocated for the buffer
|
|
* @param bytes_used the amount of the buffer used
|
|
* @returns true(1) on success, false(0) otherwise
|
|
*/
|
|
int ipfs_journal_message_encode(struct JournalMessage* message, uint8_t *buffer, size_t max_buffer_size, size_t *bytes_written) {
|
|
/*
|
|
message JournalMessage {
|
|
int32 current_epoch = 1;
|
|
int32 start_epoch = 2;
|
|
int32 end_epoch = 3;
|
|
repeated JournalEntry journal_entries = 4;
|
|
}
|
|
*/
|
|
// sanity checks
|
|
if (buffer == NULL)
|
|
return 0;
|
|
if (max_buffer_size <= 0)
|
|
return 0;
|
|
*bytes_written = 0;
|
|
size_t bytes_used;
|
|
// current_epoch
|
|
if (!protobuf_encode_varint(1, WIRETYPE_VARINT, message->current_epoch, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used))
|
|
return 0;
|
|
*bytes_written += bytes_used;
|
|
// start_epoch
|
|
if (!protobuf_encode_varint(2, WIRETYPE_VARINT, message->start_epoch, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used))
|
|
return 0;
|
|
*bytes_written += bytes_used;
|
|
// end_epoch
|
|
if (!protobuf_encode_varint(3, WIRETYPE_VARINT, message->end_epoch, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used))
|
|
return 0;
|
|
*bytes_written += bytes_used;
|
|
// journal_entries
|
|
for (int i = 0; i < message->journal_entries->total; i++) {
|
|
struct JournalEntry* entry = (struct JournalEntry*) libp2p_utils_vector_get(message->journal_entries, i);
|
|
// encode the journal entry
|
|
size_t temp_size = ipfs_journal_entry_encode_size(entry);
|
|
uint8_t temp[temp_size];
|
|
if (!ipfs_journal_entry_encode(entry, &temp[0], temp_size, &temp_size))
|
|
return 0;
|
|
if (!protobuf_encode_length_delimited(4, WIRETYPE_LENGTH_DELIMITED, (char*)&temp[0], temp_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used)) {
|
|
return 0;
|
|
}
|
|
*bytes_written += bytes_used;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/***
|
|
* Turn a protobuf'd JournalMessage and turn it into a real JournalMessage
|
|
* @param incoming the incoming bytes
|
|
* @param incoming_size the size of the incoming buffer
|
|
* @param results where to put the new JournalMessage
|
|
* @returns true(1) on success, false(0) otherwise
|
|
*/
|
|
int ipfs_journal_message_decode(uint8_t *incoming, size_t incoming_size, struct JournalMessage **out) {
|
|
size_t pos = 0;
|
|
int retVal = 0, got_something = 0;;
|
|
|
|
if ( (*out = ipfs_journal_message_new()) == NULL)
|
|
goto exit;
|
|
|
|
while(pos < incoming_size) {
|
|
size_t bytes_read = 0;
|
|
int field_no;
|
|
enum WireType field_type;
|
|
if (protobuf_decode_field_and_type(&incoming[pos], incoming_size, &field_no, &field_type, &bytes_read) == 0) {
|
|
goto exit;
|
|
}
|
|
if (field_no < 1 || field_no > 5) {
|
|
libp2p_logger_error("journal_message", "Invalid character in journal_message protobuf at position %lu. Value: %02x\n", pos, incoming[pos]);
|
|
}
|
|
pos += bytes_read;
|
|
switch(field_no) {
|
|
case (1): // current_epoch
|
|
if (protobuf_decode_varint(&incoming[pos], incoming_size - pos, &(*out)->current_epoch, &bytes_read) == 0)
|
|
goto exit;
|
|
pos += bytes_read;
|
|
got_something = 1;
|
|
break;
|
|
case (2): // start_epoch
|
|
if (protobuf_decode_varint(&incoming[pos], incoming_size - pos, &(*out)->start_epoch, &bytes_read) == 0)
|
|
goto exit;
|
|
pos += bytes_read;
|
|
got_something = 1;
|
|
break;
|
|
case (3): // end_epoch
|
|
if (protobuf_decode_varint(&incoming[pos], incoming_size - pos, &(*out)->end_epoch, &bytes_read) == 0)
|
|
goto exit;
|
|
pos += bytes_read;
|
|
got_something = 1;
|
|
break;
|
|
case (4): { // journal entry
|
|
uint8_t *temp;
|
|
size_t temp_length;
|
|
protobuf_decode_length_delimited(&incoming[pos], incoming_size - pos, (char**)&temp, &temp_length, &bytes_read);
|
|
pos += bytes_read;
|
|
struct JournalEntry* entry = NULL;
|
|
if (ipfs_journal_entry_decode(&temp[0], temp_length, &entry)) {
|
|
libp2p_utils_vector_add((*out)->journal_entries, (void*)entry);
|
|
free(temp);
|
|
} else {
|
|
free(temp);
|
|
goto exit;
|
|
}
|
|
got_something = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
retVal = got_something;
|
|
|
|
exit:
|
|
if (retVal == 0) {
|
|
ipfs_journal_message_free(*out);
|
|
}
|
|
return retVal;
|
|
|
|
}
|