c-ipfs/exchange/bitswap/bitswap.c

159 lines
5.1 KiB
C
Raw Normal View History

/**
* Methods for the Bitswap exchange
*/
#include <stdlib.h>
2017-07-24 21:03:56 +00:00
#include <unistd.h> // for sleep()
2017-07-24 19:56:30 +00:00
#include "ipfs/core/ipfs_node.h"
#include "ipfs/exchange/exchange.h"
#include "ipfs/exchange/bitswap/bitswap.h"
#include "ipfs/exchange/bitswap/message.h"
2017-07-31 15:01:06 +00:00
#include "ipfs/exchange/bitswap/peer_request_queue.h"
2017-07-24 21:03:56 +00:00
#include "ipfs/exchange/bitswap/want_manager.h"
/**
* Create a new bitswap exchange
* @param sessionContext the context
* @returns an allocated Exchange structure
*/
2017-07-27 17:05:41 +00:00
struct Exchange* ipfs_bitswap_new(struct IpfsNode* ipfs_node) {
struct Exchange* exchange = (struct Exchange*) malloc(sizeof(struct Exchange));
if (exchange != NULL) {
struct BitswapContext* bitswapContext = (struct BitswapContext*) malloc(sizeof(struct BitswapContext));
2017-07-26 14:48:04 +00:00
if (bitswapContext == NULL) {
free(exchange);
return NULL;
}
2017-07-27 17:05:41 +00:00
bitswapContext->bitswap_engine = ipfs_bitswap_engine_new();
if (bitswapContext->bitswap_engine == NULL) {
free(bitswapContext);
free(exchange);
return NULL;
}
2017-07-31 15:01:06 +00:00
bitswapContext->localWantlist = ipfs_bitswap_wantlist_queue_new();
bitswapContext->peerRequestQueue = ipfs_bitswap_peer_request_queue_new();
2017-07-24 19:56:30 +00:00
bitswapContext->ipfsNode = ipfs_node;
2017-07-27 17:05:41 +00:00
exchange->exchangeContext = (void*) bitswapContext;
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;
2017-07-27 17:05:41 +00:00
// Start the threads for the network
ipfs_bitswap_engine_start(bitswapContext);
}
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) {
2017-07-27 19:33:19 +00:00
struct BitswapContext* bitswapContext = (struct BitswapContext*) exchange->exchangeContext;
if (bitswapContext != NULL)
ipfs_bitswap_engine_stop(bitswapContext);
free(exchange->exchangeContext);
}
free(exchange);
}
return 1;
}
/**
* Implements the Exchange->IsOnline method
*/
2017-07-26 14:48:04 +00:00
int ipfs_bitswap_is_online(struct Exchange* exchange) {
return 1;
}
/***
* Implements the Exchange->Close method
*/
2017-07-26 14:48:04 +00:00
int ipfs_bitswap_close(struct Exchange* exchange) {
ipfs_bitswap_free(exchange);
return 0;
}
/**
* Implements the Exchange->HasBlock method
2017-07-24 14:09:22 +00:00
* Some notes from the GO version say that this is normally called by user
* interaction (i.e. user added a file).
* But this does not make sense right now, as the GO code looks like it
* adds the block to the blockstore. This still has to be sorted.
*/
2017-07-26 14:48:04 +00:00
int ipfs_bitswap_has_block(struct Exchange* exchange, struct Block* block) {
// add the block to the blockstore
struct BitswapContext* context = exchange->exchangeContext;
context->ipfsNode->blockstore->Put(context->ipfsNode->blockstore->blockstoreContext, block);
// update requests
struct WantListQueueEntry* queueEntry = ipfs_bitswap_wantlist_queue_find(context->localWantlist, block->cid);
if (queueEntry != NULL) {
queueEntry->block = block;
}
// TODO: Announce to world that we now have the block
return 0;
}
/**
* Implements the Exchange->GetBlock method
2017-07-24 14:09:22 +00:00
* We're asking for this method to get the block from peers. Perhaps this should be
* taking in a pointer to a callback, as this could take a while (or fail).
2017-07-24 21:03:56 +00:00
* @param exchangeContext a BitswapContext
* @param cid the Cid to look for
* @param block a pointer to where to put the result
* @returns true(1) if found, false(0) if not
*/
2017-07-26 14:48:04 +00:00
int ipfs_bitswap_get_block(struct Exchange* exchange, struct Cid* cid, struct Block** block) {
struct BitswapContext* bitswapContext = (struct BitswapContext*)exchange->exchangeContext;
2017-07-24 19:56:30 +00:00
if (bitswapContext != NULL) {
// check locally first
if (bitswapContext->ipfsNode->blockstore->Get(bitswapContext->ipfsNode->blockstore->blockstoreContext, cid, block))
return 1;
// now ask the network
2017-07-24 21:03:56 +00:00
//NOTE: this timeout should be configurable
2017-07-31 15:01:06 +00:00
int timeout = 60;
2017-07-24 21:03:56 +00:00
int waitSecs = 1;
int timeTaken = 0;
struct WantListSession wantlist_session;
wantlist_session.type = WANTLIST_SESSION_TYPE_LOCAL;
wantlist_session.context = (void*)bitswapContext->ipfsNode;
struct WantListQueueEntry* want_entry = ipfs_bitswap_want_manager_add(bitswapContext, cid, &wantlist_session);
2017-07-24 22:58:39 +00:00
if (want_entry != NULL) {
2017-07-24 21:03:56 +00:00
// loop waiting for it to fill
while(1) {
2017-07-24 22:58:39 +00:00
if (want_entry->block != NULL) {
*block = ipfs_block_copy(want_entry->block);
// error or not, we no longer need the block (decrement reference count)
ipfs_bitswap_want_manager_remove(bitswapContext, cid);
if (*block == NULL) {
return 0;
2017-07-24 21:03:56 +00:00
}
2017-07-24 22:58:39 +00:00
return 1;
2017-07-24 21:03:56 +00:00
}
//TODO: This is a busy-loop. Find another way.
timeTaken += waitSecs;
if (timeTaken >= timeout) {
// It took too long. Stop looking.
ipfs_bitswap_want_manager_remove(bitswapContext, cid);
break;
}
sleep(waitSecs);
}
}
2017-07-24 19:56:30 +00:00
}
return 0;
}
/**
* Implements the Exchange->GetBlocks method
*/
2017-07-26 14:48:04 +00:00
int ipfs_bitswap_get_blocks(struct Exchange* exchange, struct Libp2pVector* Cids, struct Libp2pVector** blocks) {
// TODO: Implement this method
return 0;
}