2017-02-20 23:53:20 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "libp2p/peer/peerstore.h"
|
2017-04-04 01:54:41 +00:00
|
|
|
#include "libp2p/utils/logger.h"
|
2017-02-20 23:53:20 +00:00
|
|
|
|
2017-07-31 19:51:29 +00:00
|
|
|
/***
|
|
|
|
* Creates a new PeerEntry struct
|
|
|
|
* @returns the newly allocated struct or NULL
|
|
|
|
*/
|
2017-02-20 23:53:20 +00:00
|
|
|
struct PeerEntry* libp2p_peer_entry_new() {
|
|
|
|
struct PeerEntry* out = (struct PeerEntry*)malloc(sizeof(struct PeerEntry));
|
|
|
|
if (out != NULL) {
|
|
|
|
out->peer = NULL;
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2017-07-31 19:51:29 +00:00
|
|
|
/***
|
|
|
|
* Frees resources
|
|
|
|
* @param in the PeerEntry to free
|
|
|
|
*/
|
2017-02-20 23:53:20 +00:00
|
|
|
void libp2p_peer_entry_free(struct PeerEntry* in) {
|
|
|
|
if (in != NULL) {
|
|
|
|
libp2p_peer_free(in->peer);
|
|
|
|
free(in);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 19:51:29 +00:00
|
|
|
/***
|
|
|
|
* Copies a PeerEntry
|
|
|
|
* @param in the PeerEntry to copy
|
|
|
|
* @returns a newly allocated PeerEntry with the values from "in"
|
|
|
|
*/
|
2017-02-20 23:53:20 +00:00
|
|
|
struct PeerEntry* libp2p_peer_entry_copy(struct PeerEntry* in) {
|
|
|
|
struct PeerEntry* out = libp2p_peer_entry_new();
|
|
|
|
if (out != NULL) {
|
|
|
|
out->peer = libp2p_peer_copy(in->peer);
|
|
|
|
if (out->peer == NULL) {
|
|
|
|
free(out);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new empty peerstore
|
2017-05-11 12:04:28 +00:00
|
|
|
* @param peer_id the peer id as a null terminated string
|
2017-02-20 23:53:20 +00:00
|
|
|
* @returns an empty peerstore or NULL on error
|
|
|
|
*/
|
2017-07-31 17:49:41 +00:00
|
|
|
struct Peerstore* libp2p_peerstore_new(const struct Libp2pPeer* local_peer) {
|
2017-02-20 23:53:20 +00:00
|
|
|
struct Peerstore* out = (struct Peerstore*)malloc(sizeof(struct Peerstore));
|
|
|
|
if (out != NULL) {
|
|
|
|
out->head_entry = NULL;
|
2017-04-20 22:55:18 +00:00
|
|
|
out->last_entry = NULL;
|
2017-05-11 12:04:28 +00:00
|
|
|
// now add this peer as the first entry
|
2017-07-31 17:49:41 +00:00
|
|
|
libp2p_peerstore_add_peer(out, local_peer);
|
2017-02-20 23:53:20 +00:00
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deallocate resources used by the peerstore
|
|
|
|
* @param in the struct to deallocate
|
|
|
|
* @returns true(1) on success, otherwise false(0)
|
|
|
|
*/
|
|
|
|
int libp2p_peerstore_free(struct Peerstore* in) {
|
|
|
|
if (in != NULL) {
|
|
|
|
struct Libp2pLinkedList* current = in->head_entry;
|
|
|
|
struct Libp2pLinkedList* next = NULL;
|
|
|
|
while (current != NULL) {
|
|
|
|
next = current->next;
|
|
|
|
libp2p_peer_entry_free((struct PeerEntry*)current->item);
|
|
|
|
current->item = NULL;
|
2017-07-31 19:51:29 +00:00
|
|
|
libp2p_utils_linked_list_free(current);
|
2017-02-20 23:53:20 +00:00
|
|
|
current = next;
|
|
|
|
}
|
|
|
|
free(in);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a Peer to the Peerstore
|
|
|
|
* @param peerstore the peerstore to add the entry to
|
|
|
|
* @param peer_entry the entry to add
|
|
|
|
* @returns true(1) on success, otherwise false
|
|
|
|
*/
|
|
|
|
int libp2p_peerstore_add_peer_entry(struct Peerstore* peerstore, struct PeerEntry* peer_entry) {
|
2017-07-31 19:51:29 +00:00
|
|
|
if (peer_entry == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2017-02-20 23:53:20 +00:00
|
|
|
struct Libp2pLinkedList* new_item = libp2p_utils_linked_list_new();
|
|
|
|
if (new_item == NULL)
|
|
|
|
return 0;
|
2017-07-31 19:51:29 +00:00
|
|
|
|
|
|
|
new_item->item = peer_entry;
|
2017-02-20 23:53:20 +00:00
|
|
|
if (peerstore->head_entry == NULL) {
|
|
|
|
peerstore->head_entry = new_item;
|
|
|
|
peerstore->last_entry = new_item;
|
|
|
|
} else {
|
|
|
|
peerstore->last_entry->next = new_item;
|
|
|
|
peerstore->last_entry = new_item;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-02-27 17:27:14 +00:00
|
|
|
/***
|
|
|
|
* Add a peer to the peerstore
|
|
|
|
* @param peerstore the peerstore to add the entry to
|
|
|
|
* @param peer the peer to add (will be wrapped in PeerEntry struct)
|
|
|
|
* @returns true(1) on success, otherwise false
|
|
|
|
*/
|
2017-07-26 12:37:28 +00:00
|
|
|
int libp2p_peerstore_add_peer(struct Peerstore* peerstore, const struct Libp2pPeer* peer) {
|
2017-04-20 22:55:18 +00:00
|
|
|
int retVal = 0;
|
|
|
|
|
|
|
|
char* ma_string = "";
|
|
|
|
if (peer != NULL && peer->addr_head != NULL && peer->addr_head->item != NULL) {
|
|
|
|
ma_string = ((struct MultiAddress*)peer->addr_head->item)->string;
|
|
|
|
}
|
2017-04-06 01:34:13 +00:00
|
|
|
// first check to see if it exists. If it does, return TRUE
|
2017-07-17 21:14:20 +00:00
|
|
|
if (libp2p_peerstore_get_peer_entry(peerstore, (unsigned char*)peer->id, peer->id_size) != NULL) {
|
2017-04-20 22:55:18 +00:00
|
|
|
libp2p_logger_debug("peerstore", "Attempted to add %s to peerstore, but already there.\n", ma_string);
|
2017-04-06 01:34:13 +00:00
|
|
|
return 1;
|
2017-04-20 22:55:18 +00:00
|
|
|
}
|
2017-04-06 01:34:13 +00:00
|
|
|
|
2017-04-20 22:55:18 +00:00
|
|
|
if (peer->id_size > 0) {
|
|
|
|
if (peer->addr_head != NULL) {
|
|
|
|
char* address = ((struct MultiAddress*)peer->addr_head->item)->string;
|
2017-07-31 19:51:29 +00:00
|
|
|
libp2p_logger_debug("peerstore", "Adding peer %s with address %s to peer store\n", peer->id, address);
|
2017-04-20 22:55:18 +00:00
|
|
|
}
|
|
|
|
struct PeerEntry* peer_entry = libp2p_peer_entry_new();
|
|
|
|
if (peer_entry == NULL) {
|
2017-08-03 16:15:40 +00:00
|
|
|
libp2p_logger_error("peerstore", "Unable to allocate memory for new PeerEntry.\n");
|
2017-04-20 22:55:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
peer_entry->peer = libp2p_peer_copy(peer);
|
2017-08-03 16:15:40 +00:00
|
|
|
if (peer_entry->peer == NULL) {
|
|
|
|
libp2p_logger_error("peerstore", "Could not copy peer for PeerEntry.\n");
|
2017-04-20 22:55:18 +00:00
|
|
|
return 0;
|
2017-08-03 16:15:40 +00:00
|
|
|
}
|
2017-04-20 22:55:18 +00:00
|
|
|
retVal = libp2p_peerstore_add_peer_entry(peerstore, peer_entry);
|
2017-07-31 19:51:29 +00:00
|
|
|
libp2p_logger_debug("peerstore", "Adding peer %s to peerstore was a success\n", peer->id);
|
2017-02-27 17:27:14 +00:00
|
|
|
}
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
2017-02-20 23:53:20 +00:00
|
|
|
/**
|
|
|
|
* Retrieve a peer from the peerstore based on the peer id
|
|
|
|
* @param peerstore the peerstore to search
|
|
|
|
* @param peer_id the id to search for as a binary array
|
|
|
|
* @param peer_id_size the size of the binary array
|
|
|
|
* @returns the PeerEntry struct if found, otherwise NULL
|
|
|
|
*/
|
2017-04-03 16:55:03 +00:00
|
|
|
struct PeerEntry* libp2p_peerstore_get_peer_entry(struct Peerstore* peerstore, const unsigned char* peer_id, size_t peer_id_size) {
|
2017-07-31 20:18:17 +00:00
|
|
|
if (peer_id_size == 0 || peer_id == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2017-02-20 23:53:20 +00:00
|
|
|
struct Libp2pLinkedList* current = peerstore->head_entry;
|
|
|
|
while(current != NULL) {
|
|
|
|
struct Libp2pPeer* peer = ((struct PeerEntry*)current->item)->peer;
|
2017-04-13 14:30:28 +00:00
|
|
|
if (peer->id_size == peer_id_size) {
|
|
|
|
if (memcmp(peer_id, peer->id, peer->id_size) == 0) {
|
|
|
|
return (struct PeerEntry*)current->item;
|
|
|
|
}
|
2017-02-20 23:53:20 +00:00
|
|
|
}
|
2017-04-13 14:30:28 +00:00
|
|
|
current = current->next;
|
2017-02-20 23:53:20 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-02-27 17:27:14 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve a peer from the peerstore based on the peer id
|
|
|
|
* @param peerstore the peerstore to search
|
|
|
|
* @param peer_id the id to search for as a binary array
|
|
|
|
* @param peer_id_size the size of the binary array
|
|
|
|
* @returns the Peer struct if found, otherwise NULL
|
|
|
|
*/
|
2017-04-03 16:55:03 +00:00
|
|
|
struct Libp2pPeer* libp2p_peerstore_get_peer(struct Peerstore* peerstore, const unsigned char* peer_id, size_t peer_id_size) {
|
2017-02-27 17:27:14 +00:00
|
|
|
struct PeerEntry* entry = libp2p_peerstore_get_peer_entry(peerstore, peer_id, peer_id_size);
|
|
|
|
if (entry == NULL)
|
|
|
|
return NULL;
|
|
|
|
return entry->peer;
|
|
|
|
}
|
2017-04-20 22:55:18 +00:00
|
|
|
|
2017-08-02 13:52:55 +00:00
|
|
|
/***
|
|
|
|
* Look for a peer by id. If not found, add it to the peerstore
|
|
|
|
* @param peerstore the Peerstore
|
|
|
|
* @param peer_id the peer id
|
|
|
|
* @param peer_id_size the size of peer_id
|
|
|
|
* @returns a Peer struct, or NULL if error
|
|
|
|
*/
|
|
|
|
struct Libp2pPeer* libp2p_peerstore_get_or_add_peer_by_id(struct Peerstore* peerstore, const unsigned char* peer_id, size_t peer_id_size) {
|
|
|
|
if (peer_id_size == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
struct PeerEntry* entry = libp2p_peerstore_get_peer_entry(peerstore, peer_id, peer_id_size);
|
|
|
|
if (entry == NULL) {
|
|
|
|
// add it
|
|
|
|
struct Libp2pPeer* temp_peer = libp2p_peer_new();
|
|
|
|
temp_peer->id_size = peer_id_size;
|
|
|
|
temp_peer->id = (char*)peer_id;
|
|
|
|
libp2p_peerstore_add_peer(peerstore, temp_peer);
|
|
|
|
libp2p_peer_free(temp_peer);
|
|
|
|
entry = libp2p_peerstore_get_peer_entry(peerstore, peer_id, peer_id_size);
|
|
|
|
}
|
|
|
|
if (entry == NULL)
|
|
|
|
return NULL;
|
|
|
|
return entry->peer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-20 22:55:18 +00:00
|
|
|
/**
|
|
|
|
* Look for this peer in the peerstore. If it is found, return a reference to that object.
|
|
|
|
* If it is not found, add it, and return a reference to the new copy
|
|
|
|
* @param peerstore the peerstore to search
|
|
|
|
* @param in the peer to search for
|
|
|
|
*/
|
2017-07-26 12:37:28 +00:00
|
|
|
struct Libp2pPeer* libp2p_peerstore_get_or_add_peer(struct Peerstore* peerstore, const struct Libp2pPeer* in) {
|
2017-04-20 22:55:18 +00:00
|
|
|
struct Libp2pPeer* out = libp2p_peerstore_get_peer(peerstore, (unsigned char*)in->id, in->id_size);
|
|
|
|
if (out != NULL)
|
|
|
|
return out;
|
|
|
|
|
|
|
|
// we didn't find it. attempt to add
|
|
|
|
if (!libp2p_peerstore_add_peer(peerstore, in))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return libp2p_peerstore_get_peer(peerstore, (unsigned char*)in->id, in->id_size);
|
|
|
|
}
|