Implementing protobuf objects for bitswap messages

This commit is contained in:
jmjatlanta 2017-07-20 15:03:49 -05:00
parent 1fe5be1c5c
commit 2232d03854
17 changed files with 934 additions and 21 deletions

View file

@ -9,6 +9,7 @@ all:
cd cmd; make all; cd cmd; make all;
cd commands; make all; cd commands; make all;
cd core; make all; cd core; make all;
cd exchange; make all;
cd importer; make all; cd importer; make all;
cd merkledag; make all; cd merkledag; make all;
cd multibase; make all; cd multibase; make all;
@ -32,6 +33,7 @@ clean:
cd cmd; make clean; cd cmd; make clean;
cd commands; make clean; cd commands; make clean;
cd core; make clean; cd core; make clean;
cd exchange; make clean;
cd importer; make clean; cd importer; make clean;
cd merkledag; make clean; cd merkledag; make clean;
cd multibase; make clean; cd multibase; make clean;

View file

@ -65,7 +65,8 @@ int ipfs_blocks_block_protobuf_decode(const unsigned char* buffer, const size_t
unsigned char* temp_buffer = NULL; unsigned char* temp_buffer = NULL;
size_t temp_size; size_t temp_size;
if (ipfs_blocks_block_new(block) == 0) *block = ipfs_blocks_block_new();
if (*block == NULL)
goto exit; goto exit;
while(pos < buffer_length) { while(pos < buffer_length) {
@ -114,16 +115,16 @@ exit:
* @param block a pointer to the struct Block that will be created * @param block a pointer to the struct Block that will be created
* @returns true(1) on success * @returns true(1) on success
*/ */
int ipfs_blocks_block_new(struct Block** block) { struct Block* ipfs_blocks_block_new() {
// allocate memory for structure // allocate memory for structure
(*block) = (struct Block*)malloc(sizeof(struct Block)); struct Block* block = (struct Block*)malloc(sizeof(struct Block));
if ((*block) == NULL) if ( block == NULL)
return 0; return 0;
(*block)->data = NULL; block->data = NULL;
(*block)->data_length = 0; block->data_length = 0;
return 1; return block;
} }
int ipfs_blocks_block_add_data(const unsigned char* data, size_t data_size, struct Block* block) { int ipfs_blocks_block_add_data(const unsigned char* data, size_t data_size, struct Block* block) {

18
exchange/Makefile Normal file
View file

@ -0,0 +1,18 @@
CC = gcc
CFLAGS = -O0 -I../include -I../../c-libp2p/include -std=c99
ifdef DEBUG
CFLAGS += -g3
endif
DEPS =
OBJS =
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
all: $(OBJS)
cd bitswap; make all;
clean:
rm -f *.o
cd bitswap; make clean;

18
exchange/bitswap/Makefile Normal file
View file

@ -0,0 +1,18 @@
CC = gcc
CFLAGS = -O0 -I../../include -I../../../c-libp2p/include -I../../../c-multiaddr/include -I../../../c-multihash/include -I../../../c-protobuf -Wall -std=c99
ifdef DEBUG
CFLAGS += -g3
endif
LFLAGS =
DEPS =
OBJS = bitswap.o message.o network.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
all: $(OBJS)
clean:
rm -f *.o

108
exchange/bitswap/bitswap.c Normal file
View file

@ -0,0 +1,108 @@
/**
* Methods for the Bitswap exchange
*/
#include <stdlib.h>
#include "ipfs/exchange/exchange.h"
#include "ipfs/exchange/bitswap/bitswap.h"
#include "ipfs/exchange/bitswap/message.h"
/**
* Create a new bitswap exchange
* @param sessionContext the context
* @returns an allocated Exchange structure
*/
struct Exchange* ipfs_bitswap_new(struct SessionContext* sessionContext) {
struct Exchange* exchange = (struct Exchange*) malloc(sizeof(struct Exchange));
if (exchange != NULL) {
struct BitswapContext* bitswapContext = (struct BitswapContext*) malloc(sizeof(struct BitswapContext));
if (exchange->exchangeContext == NULL) {
free(exchange);
return NULL;
}
exchange->exchangeContext = (void*) bitswapContext;
bitswapContext->sessionContext = sessionContext;
//TODO: fill in the exchangeContext
exchange->IsOnline = ipfs_bitswap_is_online;
exchange->Close = ipfs_bitswap_close;
exchange->HasBlock = ipfs_bitswap_has_block;
exchange->GetBlock = ipfs_bitswap_get_block;
exchange->GetBlocks = ipfs_bitswap_get_blocks;
}
return exchange;
}
/**
* Clean up resources within an Exchange struct
* @param exchange the exchange to free
* @returns true(1)
*/
int ipfs_bitswap_free(struct Exchange* exchange) {
if (exchange != NULL) {
if (exchange->exchangeContext != NULL) {
free(exchange->exchangeContext);
}
free(exchange);
}
return 1;
}
/**
* Implements the Exchange->IsOnline method
*/
int ipfs_bitswap_is_online(void* exchangeContext) {
if (exchangeContext != NULL) {
struct BitswapContext* bitswapContext = (struct BitswapContext*)exchangeContext;
//TODO: Is this an accurate way to determine if we're running?
if (bitswapContext->sessionContext != NULL)
return 1;
}
return 0;
}
/***
* Implements the Exchange->Close method
*/
int ipfs_bitswap_close(void* exchangeContext) {
//TODO: Implement this method
// Should it close the exchange?
return 0;
}
/**
* Implements the Exchange->HasBlock method
*/
int ipfs_bitswap_has_block(void* exchangeContext, struct Block* block) {
//TODO: Implement this method
// NOTE: The GO version adds the block to the blockstore. I have yet to
// understand the flow and if this is correct for us.
return 0;
}
/**
* Implements the Exchange->GetBlock method
*/
int ipfs_bitswap_get_block(void* exchangeContext, struct Cid* cid, struct Block** block) {
// TODO: Implement this method
return 0;
}
/**
* Implements the Exchange->GetBlocks method
*/
int ipfs_bitswap_get_blocks(void* exchangeContext, struct Libp2pVector* Cids, struct Libp2pVector** blocks) {
// TODO: Implement this method
return 0;
}
/***
* Receive a BitswapMessage from a peer.
* @param exchangeContext the context
* @param peer_id the origin
* @param peer_id_size the size of the peer_id
* @param message the message
* @returns true(1) on success, otherwise false(0)
*/
int ipfs_bitswap_receive_message(void* exchangeContext, unsigned char* peer_id, int peer_id_size, struct BitswapMessage* message) {
return 0;
}

645
exchange/bitswap/message.c Normal file
View file

@ -0,0 +1,645 @@
#include <stdlib.h>
#include "protobuf.h"
#include "varint.h"
#include "libp2p/utils/vector.h"
#include "ipfs/blocks/block.h"
#include "ipfs/exchange/bitswap/message.h"
/***
* Allocate memory for a struct BitswapBlock
* @returns a new BitswapBlock
*/
struct BitswapBlock* ipfs_bitswap_block_new() {
struct BitswapBlock* block = (struct BitswapBlock*) malloc(sizeof(struct BitswapBlock));
if (block != NULL) {
block->bytes_size = 0;
block->bytes = NULL;
block->prefix_size = 0;
block->prefix = NULL;
}
return block;
}
/**
* Deallocate memory for a struct BitswapBlock
* @param block the block to deallocate
* @returns true(1)
*/
int ipfs_bitswap_block_free(struct BitswapBlock* block) {
if (block != NULL) {
if (block->bytes != NULL)
free(block->bytes);
if (block->prefix != NULL)
free(block->prefix);
free(block);
}
return 1;
}
/**
* Retrieve an estimate of the size of a protobuf'd BitswapBlock
* @returns the approximate (maximum actually) size of a protobuf'd BitswapBlock
*/
size_t ipfs_bitswap_message_block_protobuf_size(struct BitswapBlock* block) {
// protobuf prefix + prefix + bytes = 33 + array sizes
return 33 + block->prefix_size + block->bytes_size;
}
/***
* Encode a BitswapBlock
* @param incoming the block to encode
* @param outgoing where to place the results
* @param max_size the maximum allocated space for outgoing
* @param bytes_written the number of bytes written to outgoing
*/
int ipfs_bitswap_message_block_protobuf_encode(struct BitswapBlock* incoming, uint8_t* outgoing, size_t max_size, size_t* bytes_written) {
// 2 WIRETYPE_LENGTH_DELIMITED fields of prefix and bytes
size_t bytes_used;
*bytes_written = 0;
if (incoming != NULL) {
if (!protobuf_encode_length_delimited(1, WIRETYPE_LENGTH_DELIMITED, (char*)incoming->prefix, incoming->prefix_size, outgoing, max_size, &bytes_used))
return 0;
*bytes_written += bytes_used;
if (!protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, (char*)incoming->bytes, incoming->bytes_size, &outgoing[*bytes_written], max_size - (*bytes_written), &bytes_used))
return 0;
*bytes_written += bytes_used;
}
return 1;
}
/***
* Decode a protobuf to a BitswapBlock
* @param buffer the incoming protobuf
* @param buffer_length the length of the incoming protobuf buffer
* @param output a pointer to the BitswapBlock that will be allocated
* @returns true(1) on success, false(0) if not. If false, any memory was deallocated
*/
int ipfs_bitswap_message_block_protobuf_decode(uint8_t* buffer, size_t buffer_length, struct BitswapBlock** output) {
size_t pos = 0;
int retVal = 0;
*output = NULL;
// short cut for nulls
if (buffer_length == 0)
return 1;
*output = (struct BitswapBlock*) malloc(sizeof(struct BitswapBlock));
if (*output == NULL)
goto exit;
struct BitswapBlock* block = *output;
while(pos < buffer_length) {
size_t bytes_read = 0;
int field_no;
enum WireType field_type;
if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) {
goto exit;
}
pos += bytes_read;
switch(field_no) {
case (1):
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&block->prefix, &block->prefix_size, &bytes_read))
goto exit;
break;
case (2):
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&block->bytes, &block->bytes_size, &bytes_read))
goto exit;
break;
}
}
retVal = 1;
exit:
if (retVal == 0) {
if (*output != NULL)
free(*output);
*output = NULL;
}
return retVal;
}
/***
* Allocate memory for a new WantlistEntry
* @returns the newly allocated WantlistEntry
*/
struct WantlistEntry* ipfs_bitswap_wantlist_entry_new() {
struct WantlistEntry* entry = (struct WantlistEntry*) malloc(sizeof(struct WantlistEntry));
if (entry == NULL)
return NULL;
entry->block = NULL;
entry->block_size = 0;
entry->cancel = 0;
entry->priority = 1;
return entry;
}
/***
* Free allocations of a WantlistEntry
* @param entry the WantlistEntry
* @returns true(1)
*/
int ipfs_bitswap_wantlist_entry_free(struct WantlistEntry* entry) {
if (entry != NULL) {
if (entry->block != NULL)
free(entry->block);
free(entry);
entry = NULL;
}
return 1;
}
/**
* Retrieve an estimate of the size of a protobuf'd WantlistEntry
* @param entry the struct to examine
* @returns the approximate (maximum actually) size of a protobuf'd WantlistEntry
*/
size_t ipfs_bitswap_wantlist_entry_protobuf_encode_size(struct WantlistEntry* entry) {
// protobuf prefix + block + cancel + priority
return 33 + entry->block_size;
}
/***
* Encode a WantlistEntry into a Protobuf
* @param entry the WantlistEntry to encode
* @param buffer where to put the results
* @param buffer_length the maximum size of the buffer
* @param bytes_written the number of bytes written into the buffer
* @returns true(1) on success, false(0) otherwise
*/
int ipfs_bitswap_wantlist_entry_protobuf_encode(struct WantlistEntry* entry, unsigned char* buffer, size_t buffer_length, size_t* bytes_written) {
size_t bytes_used;
*bytes_written = 0;
if (entry != NULL) {
if (!protobuf_encode_length_delimited(1, WIRETYPE_LENGTH_DELIMITED, (char*)entry->block, entry->block_size, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used))
return 0;
*bytes_written += bytes_used;
if (!protobuf_encode_varint(2, WIRETYPE_VARINT, entry->cancel, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used))
return 0;
*bytes_written += bytes_used;
if (!protobuf_encode_varint(3, WIRETYPE_VARINT, entry->priority, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used))
return 0;
*bytes_written += bytes_used;
}
return 1;
}
/***
* Decode a protobuf into a struct WantlistEntry
* @param buffer the protobuf buffer
* @param buffer_length the length of the data in the protobuf buffer
* @param output the resultant WantlistEntry
* @returns true(1) on success, otherwise false(0)
*/
int ipfs_bitswap_wantlist_entry_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct WantlistEntry** output) {
size_t pos = 0;
int retVal = 0;
struct WantlistEntry* entry = NULL;
*output = NULL;
// short cut for nulls
if (buffer_length == 0)
return 1;
*output = (struct WantlistEntry*) malloc(sizeof(struct WantlistEntry));
if (*output == NULL)
goto exit;
entry = *output;
while(pos < buffer_length) {
size_t bytes_read = 0;
int field_no;
enum WireType field_type;
if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) {
goto exit;
}
pos += bytes_read;
switch(field_no) {
case (1):
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&entry->block, &entry->block_size, &bytes_read))
goto exit;
pos += bytes_read;
break;
case (2):
entry->cancel = varint_decode(&buffer[pos], buffer_length - pos, &bytes_read);
pos += bytes_read;
break;
case (3):
entry->priority = varint_decode(&buffer[pos], buffer_length - pos, &bytes_read);
pos += bytes_read;
break;
}
}
retVal = 1;
exit:
if (retVal == 0) {
if (entry != NULL)
free(entry);
*output = NULL;
}
return retVal;
}
/***
* Allocate memory for a new Bitswap Message WantList
* @returns the allocated struct BitswapWantlist
*/
struct BitswapWantlist* ipfs_bitswap_wantlist_new() {
struct BitswapWantlist* list = (struct BitswapWantlist*) malloc(sizeof(struct BitswapWantlist));
if (list != NULL) {
list->entries = NULL;
list->full = 1;
}
return list;
}
/**
* Free the resources used by a Wantlist
* @param list the list to free
* @returns true(1)
*/
int ipfs_bitswap_wantlist_free(struct BitswapWantlist* list) {
if (list != NULL) {
if (list->entries != NULL) {
for(int i = 0; i < list->entries->total; i++) {
// free each item in the vector
struct WantlistEntry* entry = (struct WantlistEntry*) libp2p_utils_vector_get(list->entries, i);
ipfs_bitswap_wantlist_entry_free(entry);
}
libp2p_utils_vector_free(list->entries);
}
free(list);
}
return 1;
}
/***
* Calculate the maximum size of a protobuf'd BitswapWantlist
* @param list the Wantlist
* @returns the maximum size of the protobuf'd list
*/
size_t ipfs_bitswap_wantlist_protobuf_encode_size(struct BitswapWantlist* list) {
size_t total = 0;
if (list != NULL) {
for(int i = 0; i < list->entries->total; i++) {
struct WantlistEntry* entry = (struct WantlistEntry*) libp2p_utils_vector_get(list->entries, i);
total += ipfs_bitswap_wantlist_entry_protobuf_encode_size(entry);
}
total += 11 + 12 + 11;
}
return total;
}
/***
* Encode a BitswapWantlist into a protobuf buffer
* @param list the list to encode
* @param buffer the buffer to fill
* @param buffer_length the length of the allocated buffer
* @param bytes_written the total number of bytes written to the buffer
* @returns true(1) on success, otherwise false(0)
*/
int ipfs_bitswap_wantlist_protobuf_encode(struct BitswapWantlist* list, unsigned char* buffer, size_t buffer_length, size_t* bytes_written) {
size_t bytes_used = 0;
*bytes_written = 0;
if (list != NULL) {
// the vector of entries
for(int i = 0; i < list->entries->total; i++) {
struct WantlistEntry* entry = (struct WantlistEntry*) libp2p_utils_vector_get(list->entries, i);
// protobuf the entry
size_t temp_buffer_size = ipfs_bitswap_wantlist_entry_protobuf_encode_size(entry);
uint8_t* temp_buffer = (uint8_t*) malloc(temp_buffer_size);
if (temp_buffer == NULL)
return 0;
if (!ipfs_bitswap_wantlist_entry_protobuf_encode(entry, temp_buffer, temp_buffer_size, &temp_buffer_size)) {
free(temp_buffer);
return 0;
}
// we've got the protobuf'd entry, now put it in the real buffer
if (!protobuf_encode_length_delimited(1, WIRETYPE_LENGTH_DELIMITED, (char*)temp_buffer, temp_buffer_size, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used)) {
free(temp_buffer);
return 0;
}
// all went okay. Clean up and do it again...
free(temp_buffer);
*bytes_written += bytes_used;
}
// if this is the full list or not...
if (!protobuf_encode_varint(2, WIRETYPE_VARINT, list->full, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used))
return 0;
*bytes_written += bytes_used;
}
return 1;
}
/***
* Decode a Wantlist from a protobuf
* @param buffer the protobuf
* @param buffer_length the length of the protobuf
* @param output the newly allocated BitswapWantlist
* @returns true(1) on success, otherwise false(0)
*/
int ipfs_bitswap_wantlist_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct BitswapWantlist** output) {
size_t pos = 0;
*output = NULL;
// short cut for nulls
if (buffer_length == 0)
return 1;
*output = (struct BitswapWantlist*) malloc(sizeof(struct BitswapWantlist));
if (*output == NULL)
return 0;
struct BitswapWantlist* list = *output;
while(pos < buffer_length) {
size_t bytes_read = 0;
int field_no;
enum WireType field_type;
if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) {
return 0;
}
pos += bytes_read;
switch(field_no) {
case (1): {
// a WantlistEntry
size_t temp_size = 0;
uint8_t* temp = NULL;
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp, &temp_size, &bytes_read)) {
return 0;
}
struct WantlistEntry* entry = NULL;
if (!ipfs_bitswap_wantlist_entry_protobuf_decode(temp, temp_size, &entry)) {
free(temp);
return 0;
}
free(temp);
if (list->entries == NULL) {
list->entries = libp2p_utils_vector_new(1);
}
libp2p_utils_vector_add(list->entries, (void*)entry);
free(entry);
pos += bytes_read;
break;
}
case (2): {
list->full = varint_decode(&buffer[pos], buffer_length - pos, &bytes_read);
pos += bytes_read;
break;
}
}
}
return 1;
}
/***
* Bitswap Message
*
*/
/***
* Allocate memory for a new Bitswap Message
* @returns the allocated struct BitswapMessage
*/
struct BitswapMessage* ipfs_bitswap_message_new() {
struct BitswapMessage* message = (struct BitswapMessage*) malloc(sizeof(struct BitswapMessage));
if (message != NULL) {
message->blocks = NULL;
message->payload = NULL;
message->wantlist = NULL;
}
return message;
}
/**
* Free the resources used by a BitswapMessage
* @param message the BitswapMessage to free
* @returns true(1)
*/
int ipfs_bitswap_message_free(struct BitswapMessage* message) {
if (message != NULL) {
if (message->blocks != NULL) {
// blocks are just byte arrays in bitswap 1.0.0, so throw it in a struct
// so it can be put in a vector
for(int i = 0; i < message->blocks->total; i++) {
// free each item in the vector
struct Block* entry = (struct Block*) libp2p_utils_vector_get(message->blocks, i);
ipfs_blocks_block_free(entry);
}
libp2p_utils_vector_free(message->blocks);
}
if (message->payload != NULL) {
for(int i = 0; i < message->payload->total; i++) {
// free each item in the vector
struct Block* entry = (struct Block*) libp2p_utils_vector_get(message->payload, i);
ipfs_blocks_block_free(entry);
}
libp2p_utils_vector_free(message->payload);
}
if (message->wantlist != NULL) {
ipfs_bitswap_wantlist_free(message->wantlist);
}
free(message);
}
return 1;
}
/***
* Calculate the maximum size of a protobuf'd BitswapMessage
* @param message the BitswapMessage
* @returns the maximum size of the protobuf'd BitswapMessage
*/
size_t ipfs_bitswap_message_protobuf_encode_size(struct BitswapMessage* message) {
size_t total = 0;
if (message != NULL) {
if (message->blocks != NULL) {
for(int i = 0; i < message->blocks->total; i++) {
struct Block* entry = (struct Block*) libp2p_utils_vector_get(message->blocks, i);
total += 11 + entry->data_length;
}
}
if (message->payload != NULL) {
for(int i = 0; i < message->payload->total; i++) {
struct Block* entry = (struct Block*) libp2p_utils_vector_get(message->payload, i);
total += 11 + ipfs_blocks_block_protobuf_encode_size(entry);
}
}
if (message->wantlist != NULL) {
total += ipfs_bitswap_wantlist_protobuf_encode_size(message->wantlist);
}
total += 11 + 12 + 11;
}
return total;
}
/***
* Encode a BitswapMessage into a protobuf buffer
* @param message the message to encode
* @param buffer the buffer to fill
* @param buffer_length the length of the allocated buffer
* @param bytes_written the total number of bytes written to the buffer
* @returns true(1) on success, otherwise false(0)
*/
int ipfs_bitswap_message_protobuf_encode(struct BitswapMessage* message, unsigned char* buffer, size_t buffer_length, size_t* bytes_written) {
size_t bytes_used = 0;
*bytes_written = 0;
if (message != NULL) {
// the vector of blocks that are actually to be turned back into byte arrays
if (message->blocks != NULL) {
for(int i = 0; i < message->blocks->total; i++) {
struct Block* entry = (struct Block*) libp2p_utils_vector_get(message->blocks, i);
// blocks are just variable length byte streams
if (!protobuf_encode_length_delimited(1, WIRETYPE_LENGTH_DELIMITED, (char*)entry->data, entry->data_length, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used)) {
return 0;
}
*bytes_written += bytes_used;
}
}
// the vector of Blocks that are actually blocks
if (message->payload != NULL) {
for(int i = 0; i < message->payload->total; i++) {
struct Block* entry = (struct Block*) libp2p_utils_vector_get(message->payload, i);
// protobuf it
size_t temp_size = ipfs_blocks_block_protobuf_encode_size(entry);
uint8_t* temp = (uint8_t*) malloc(temp_size);
if (!ipfs_blocks_block_protobuf_encode(entry, temp, temp_size, &temp_size)) {
free(temp);
return 0;
}
// put it in the buffer
if (!protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, (char*)temp, temp_size, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used)) {
free(temp);
return 0;
}
*bytes_written += bytes_used;
free(temp);
}
}
// the WantList
if (message->wantlist != NULL) {
size_t temp_size = ipfs_bitswap_wantlist_protobuf_encode_size(message->wantlist);
uint8_t* temp = (uint8_t*) malloc(temp_size);
if (!ipfs_bitswap_wantlist_protobuf_encode(message->wantlist, temp, temp_size, &temp_size)) {
free(temp);
return 0;
}
if (!protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, (char*)temp, temp_size, &buffer[*bytes_written], buffer_length - (*bytes_written), &bytes_used)) {
free(temp);
return 0;
}
*bytes_written += bytes_used;
free(temp);
}
}
return 1;
}
/***
* Decode a BitswapMessage from a protobuf
* @param buffer the protobuf
* @param buffer_length the length of the protobuf
* @param output the newly allocated BitswapMessage
* @returns true(1) on success, otherwise false(0)
*/
int ipfs_bitswap_message_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct BitswapMessage** output) {
size_t pos = 0;
*output = NULL;
// short cut for nulls
if (buffer_length == 0)
return 1;
*output = (struct BitswapMessage*) malloc(sizeof(struct BitswapMessage));
if (*output == NULL)
return 0;
struct BitswapMessage* message = *output;
while(pos < buffer_length) {
size_t bytes_read = 0;
int field_no;
enum WireType field_type;
if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) {
return 0;
}
pos += bytes_read;
switch(field_no) {
case (1): {
// a Blocks entry that is just an array of bytes
struct Block* temp = ipfs_blocks_block_new();
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp->data, &temp->data_length, &bytes_read)) {
return 0;
}
if (message->blocks == NULL) {
message->blocks = libp2p_utils_vector_new(1);
}
libp2p_utils_vector_add(message->blocks, (void*)temp);
ipfs_blocks_block_free(temp);
pos += bytes_read;
break;
}
case (2): {
// a block entry that is a real block struct
size_t temp_size = 0;
uint8_t* temp = NULL;
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp, &temp_size, &bytes_read)) {
return 0;
}
// we have the bytes, turn it into a Block struct
struct Block* block = NULL;
if (!ipfs_blocks_block_protobuf_decode(temp, temp_size, &block)) {
free(temp);
return 0;
}
free(temp);
if (message->payload == NULL) {
message->payload = libp2p_utils_vector_new(1);
}
libp2p_utils_vector_add(message->payload, (void*)block);
ipfs_blocks_block_free(block);
pos += bytes_read;
break;
}
case(3): {
// a Wantlist
size_t temp_size = 0;
uint8_t* temp = NULL;
if (!protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&temp, &temp_size, &bytes_read)) {
return 0;
}
// we have the protobuf'd wantlist, now turn it into a Wantlist struct.
if (!ipfs_bitswap_wantlist_protobuf_decode(temp, temp_size, &message->wantlist)) {
free(temp);
return 0;
}
free(temp);
pos += bytes_read;
break;
}
}
}
return 1;
}

View file

@ -15,13 +15,10 @@ struct Block {
}; };
/*** /***
* Create a new block based on the incoming data. * Create a new block
* @param data the data to base the block on * @returns a new allocated Block struct
* @param data_size the length of the data array
* @param block a pointer to the struct Block that will be created
* @returns true(1) on success
*/ */
int ipfs_blocks_block_new(struct Block** block); struct Block* ipfs_blocks_block_new();
int ipfs_blocks_block_add_data(const unsigned char* data, size_t data_size, struct Block* block); int ipfs_blocks_block_add_data(const unsigned char* data, size_t data_size, struct Block* block);

View file

@ -19,6 +19,13 @@
#define CID_ZCASH_BLOCK 0xc0 #define CID_ZCASH_BLOCK 0xc0
#define CID_ZCASH_TX 0xc1 #define CID_ZCASH_TX 0xc1
/***
* A note about CID versions:
* Version 0 only contained the multihash address. The extra parameters of multibase,
* multicodec, cid-version were implied (base58btc, protobuf-mdag, and cidv0
* respectively) are implied.
*/
struct Cid { struct Cid {
int version; int version;
char codec; char codec;

View file

@ -0,0 +1,13 @@
struct BitswapContext {
struct SessionContext* sessionContext;
};
int ipfs_bitswap_is_online(void* exchangeContext);
int ipfs_bitswap_close(void* exchangeContext);
int ipfs_bitswap_has_block(void* exchangeContext, struct Block* block);
int ipfs_bitswap_get_block(void* exchangeContext, struct Cid* cid, struct Block** block);
int ipfs_bitswap_get_blocks(void* exchangeContext, struct Libp2pVector* Cids, struct Libp2pVector** blocks);

View file

@ -0,0 +1,42 @@
/***
* A protobuf-able Bitswap Message
*/
#include <stdint.h>
#include <stddef.h>
#include "libp2p/utils/vector.h"
struct WantlistEntry {
// optional string block = 1, the block cid (cidV0 in bitswap 1.0.0, cidV1 in bitswap 1.1.0
unsigned char* block;
size_t block_size;
// optional int32 priority = 2, the priority (normalized). default to 1
uint32_t priority;
// optional bool cancel = 3, whether this revokes an entry
uint8_t cancel;
};
struct BitswapWantlist {
// repeated WantlistEntry entries = 1, a list of wantlist entries
struct Libp2pVector* entries;
// optional bool full = 2, whether this is the full wantlist. default to false
uint8_t full;
};
struct BitswapBlock {
// optional bytes prefix = 1, // CID prefix (cid version, multicodec, and multihash prefix (type + length))
uint8_t* prefix;
size_t prefix_size;
// optional bytes data = 2
uint8_t* bytes;
size_t bytes_size;
};
struct BitswapMessage {
// optional Wantlist wantlist = 1
struct BitswapWantlist* wantlist;
// repeated bytes blocks = 2, used to send Blocks in bitswap 1.0.0
struct Libp2pVector* blocks;
// repeated Block payload = 3, used to send Blocks in bitswap 1.1.0
struct Libp2pVector* payload;
};

View file

@ -3,6 +3,9 @@
* smartly handle queues of local and remote requests. * smartly handle queues of local and remote requests.
*/ */
#include "libp2p/conn/session.h"
#include "ipfs/exchange/bitswap/message.h"
struct BitswapRouting { struct BitswapRouting {
/** /**
* Find the provider of a key asyncronously * Find the provider of a key asyncronously
@ -39,7 +42,8 @@ struct BitswapNetwork {
* @param receiver the struct that contains function pointers for receiving messages * @param receiver the struct that contains function pointers for receiving messages
* @returns true(1) on success, otherwise false(0) * @returns true(1) on success, otherwise false(0)
*/ */
int (*SetDelegate)(struct BitswapReceiver* receiver); //TODO: Implement this
//int (*SetDelegate)(struct BitswapReceiver* receiver);
/** /**
* Attempt a connection to a particular peer * Attempt a connection to a particular peer

View file

@ -0,0 +1,57 @@
/**
* This is the definition of an "Exchange"
*
* Anything that implements the Exchange interface can be used as
* an IPFS block exchange protocol.
*/
#include "ipfs/blocks/block.h"
#include "ipfs/cid/cid.h"
#include "libp2p/utils/vector.h"
struct Exchange {
/**
* Retrieve a block from peers within the deadline enforced
* by the context
* @param context the context
* @param cid the hash of the block to retrieve
* @param block a pointer to the block (allocated by this method if return is true)
* @returns true(1) on success, false(0) otherwise
*/
int (*GetBlock)(void* exchangeContext, struct Cid* cid, struct Block** block);
/**
* Retrieve several blocks
* @param context the context
* @param Cids a vector of hashes for the blocks to be retrieved
* @param blocks a pointer to a vector of retrieved blocks (will be NULL on error)
* @returns true(1) on success, otherwise false(0)
*/
int (*GetBlocks)(void* exchangeContext, struct Libp2pVector* Cids, struct Libp2pVector** blocks);
/**
* Announces the existance of a block to this bitswap service. The service will
* potentially notify its peers.
* NOTE: This is mainly designed to announce blocks added by non-bitswap methods (i.e. the local user)
* @param block the block being announced
* @returns true(1) on success, false(0) if not
*/
int (*HasBlock)(void* exchangeContext, struct Block* block);
/**
* Determine if we're online
* @returns true(1) if we're online
*/
int (*IsOnline)(void* exchangeContext);
/**
* Close up the exchange, and go offline
* @returns true(1);
*/
int (*Close)(void* exchangeContext);
/**
* Used by each implementation to maintain state
* (will be cast-ed to an implementation-specific structure)
*/
void* exchangeContext;
};

View file

@ -11,6 +11,7 @@ OBJS = main.o \
../datastore/ds_helper.o \ ../datastore/ds_helper.o \
../datastore/key.o \ ../datastore/key.o \
../dnslink/*.o \ ../dnslink/*.o \
../exchange/bitswap/*.o \
../flatfs/flatfs.o \ ../flatfs/flatfs.o \
../importer/importer.o ../importer/exporter.o ../importer/resolver.o \ ../importer/importer.o ../importer/exporter.o ../importer/resolver.o \
../path/path.o \ ../path/path.o \

View file

@ -14,6 +14,7 @@ OBJS = testit.o test_helper.o \
../core/ping.o \ ../core/ping.o \
../core/ipfs_node.o \ ../core/ipfs_node.o \
../datastore/ds_helper.o \ ../datastore/ds_helper.o \
../exchange/bitswap/*.o \
../flatfs/flatfs.o \ ../flatfs/flatfs.o \
../importer/importer.o ../importer/exporter.o ../importer/resolver.o \ ../importer/importer.o ../importer/exporter.o ../importer/resolver.o \
../merkledag/merkledag.o ../merkledag/node.o \ ../merkledag/merkledag.o ../merkledag/node.o \

View file

@ -47,8 +47,8 @@ int test_repo_fsrepo_write_read_block() {
} }
// create and write the block // create and write the block
retVal = ipfs_blocks_block_new(&block); block = ipfs_blocks_block_new();
if (retVal == 0) { if (block == NULL) {
ipfs_repo_fsrepo_free(fs_repo); ipfs_repo_fsrepo_free(fs_repo);
return 0; return 0;
} }

View file

@ -3,9 +3,8 @@
int test_blocks_new() { int test_blocks_new() {
const unsigned char* input = (const unsigned char*)"Hello, World!"; const unsigned char* input = (const unsigned char*)"Hello, World!";
int retVal = 0; int retVal = 0;
struct Block* block; struct Block* block = ipfs_blocks_block_new();
retVal = ipfs_blocks_block_new(&block); if (block == NULL)
if (retVal == 0)
return 0; return 0;
retVal = ipfs_blocks_block_add_data(input, strlen((const char*)input) + 1, block); retVal = ipfs_blocks_block_add_data(input, strlen((const char*)input) + 1, block);

View file

@ -23,8 +23,8 @@ int test_ipfs_datastore_put() {
return 0; return 0;
// build the block // build the block
retVal = ipfs_blocks_block_new(&block); block = ipfs_blocks_block_new();
if (retVal == 0) if (block == NULL)
return 0; return 0;
retVal = ipfs_blocks_block_add_data(input, strlen((char*)input), block); retVal = ipfs_blocks_block_add_data(input, strlen((char*)input), block);