Replace peers linked list with hash

This commit is contained in:
emanuele-f 2019-06-09 23:41:47 +02:00
parent b5c59c0e56
commit 447c3ad8c3
4 changed files with 100 additions and 267 deletions

View File

@ -222,42 +222,15 @@ edge_init_error:
return(NULL);
}
/* ***************************************************** */
static inline void update_peer_seen(struct peer_info *peer, time_t t) {
peer->last_seen = t;
}
/* ***************************************************** */
static void remove_peer_from_list(struct peer_info **head, struct peer_info *prev,
struct peer_info *scan) {
/* Remove the peer. */
if(prev == NULL)
/* scan was head of list */
*head = scan->next;
else
prev->next = scan->next;
free(scan);
}
/* ************************************** */
static int find_and_remove_peer(struct peer_info **head, const n2n_mac_t mac) {
struct peer_info *prev = NULL;
struct peer_info *scan = *head;
struct peer_info *peer;
while(scan != NULL) {
if(memcmp(scan->mac_addr, mac, N2N_MAC_SIZE) == 0)
break; /* found. */
prev = scan;
scan = scan->next;
}
if(scan) {
remove_peer_from_list(head, prev, scan);
HASH_FIND_PEER(*head, mac, peer);
if(peer) {
HASH_DEL(*head, peer);
free(peer);
return(1);
}
@ -376,10 +349,12 @@ static void register_with_new_peer(n2n_edge_t * eee,
const n2n_mac_t mac,
const n2n_sock_t * peer) {
/* REVISIT: purge of pending_peers not yet done. */
struct peer_info * scan = find_peer_by_mac(eee->pending_peers, mac);
struct peer_info * scan;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
HASH_FIND_PEER(eee->pending_peers, mac, scan);
/* NOTE: pending_peers are purged periodically with purge_expired_registrations */
if(scan == NULL) {
scan = calloc(1, sizeof(struct peer_info));
@ -387,16 +362,16 @@ static void register_with_new_peer(n2n_edge_t * eee,
memcpy(scan->mac_addr, mac, N2N_MAC_SIZE);
scan->sock = *peer;
scan->timeout = REGISTER_SUPER_INTERVAL_DFL; /* TODO: should correspond to the peer supernode registration timeout */
update_peer_seen(scan, time(NULL)); /* Don't change this it marks the pending peer for removal. */
scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */
peer_list_add(&(eee->pending_peers), scan);
HASH_ADD_PEER(eee->pending_peers, scan);
traceEvent(TRACE_DEBUG, "=== new pending %s -> %s",
macaddr_str(mac_buf, scan->mac_addr),
sock_to_cstr(sockbuf, &(scan->sock)));
traceEvent(TRACE_INFO, "Pending peers list size=%u",
(unsigned int)peer_list_size(eee->pending_peers));
HASH_COUNT(eee->pending_peers));
/* trace Sending REGISTER */
send_register(eee, &(scan->sock), mac);
@ -416,7 +391,9 @@ static void check_peer_registration_needed(n2n_edge_t * eee,
uint8_t from_supernode,
const n2n_mac_t mac,
const n2n_sock_t * peer) {
struct peer_info * scan = find_peer_by_mac(eee->known_peers, mac);
struct peer_info *scan;
HASH_FIND_PEER(eee->known_peers, mac, scan);
if(scan == NULL) {
/* Not in known_peers - start the REGISTER process. */
@ -445,66 +422,38 @@ static void peer_set_p2p_confirmed(n2n_edge_t * eee,
const n2n_mac_t mac,
const n2n_sock_t * peer,
time_t now) {
struct peer_info * prev = NULL;
struct peer_info * scan;
struct peer_info *scan;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
scan=eee->pending_peers;
HASH_FIND_PEER(eee->pending_peers, mac, scan);
while (NULL != scan)
{
if(0 == memcmp(scan->mac_addr, mac, N2N_MAC_SIZE))
{
break; /* found. */
}
if(scan) {
HASH_DEL(eee->pending_peers, scan);
prev = scan;
scan = scan->next;
}
/* Add scan to known_peers. */
HASH_ADD_PEER(eee->known_peers, scan);
if(scan)
{
scan->sock = *peer;
scan->last_p2p = now;
traceEvent(TRACE_NORMAL, "P2P connection enstablished: %s [%s]",
macaddr_str(mac_buf, mac),
sock_to_cstr(sockbuf, peer));
/* Remove scan from pending_peers. */
if(prev)
{
prev->next = scan->next;
}
else
{
eee->pending_peers = scan->next;
}
traceEvent(TRACE_DEBUG, "=== new peer %s -> %s",
macaddr_str(mac_buf, scan->mac_addr),
sock_to_cstr(sockbuf, &(scan->sock)));
/* Add scan to known_peers. */
scan->next = eee->known_peers;
eee->known_peers = scan;
traceEvent(TRACE_INFO, "Pending peers list size=%u",
HASH_COUNT(eee->pending_peers));
scan->sock = *peer;
scan->last_p2p = now;
traceEvent(TRACE_INFO, "Known peers list size=%u",
HASH_COUNT(eee->known_peers));
traceEvent(TRACE_NORMAL, "P2P connection enstablished: %s [%s]",
macaddr_str(mac_buf, mac),
sock_to_cstr(sockbuf, peer));
traceEvent(TRACE_DEBUG, "=== new peer %s -> %s",
macaddr_str(mac_buf, scan->mac_addr),
sock_to_cstr(sockbuf, &(scan->sock)));
traceEvent(TRACE_INFO, "Pending peers list size=%u",
(unsigned int)peer_list_size(eee->pending_peers));
traceEvent(TRACE_INFO, "Known peers list size=%u",
(unsigned int)peer_list_size(eee->known_peers));
update_peer_seen(scan, now);
}
else
{
traceEvent(TRACE_DEBUG, "Failed to find sender in pending_peers.");
}
scan->last_seen = now;
} else
traceEvent(TRACE_DEBUG, "Failed to find sender in pending_peers.");
}
/* ************************************** */
@ -548,8 +497,7 @@ static void check_known_peer_sock_change(n2n_edge_t * eee,
const n2n_mac_t mac,
const n2n_sock_t * peer,
time_t when) {
struct peer_info *scan = eee->known_peers;
struct peer_info *prev = NULL; /* use to remove bad registrations. */
struct peer_info *scan;
n2n_sock_str_t sockbuf1;
n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
macstr_t mac_buf;
@ -561,13 +509,7 @@ static void check_known_peer_sock_change(n2n_edge_t * eee,
return;
/* Search the peer in known_peers */
while(scan != NULL) {
if(memcmp(mac, scan->mac_addr, N2N_MAC_SIZE) == 0)
break;
prev = scan;
scan = scan->next;
}
HASH_FIND_PEER(eee->known_peers, mac, scan);
if(!scan)
/* Not in known_peers */
@ -581,14 +523,15 @@ static void check_known_peer_sock_change(n2n_edge_t * eee,
sock_to_cstr(sockbuf1, &(scan->sock)),
sock_to_cstr(sockbuf2, peer));
/* The peer has changed public socket. It can no longer be assumed to be reachable. */
remove_peer_from_list(&eee->known_peers, prev, scan);
HASH_DEL(eee->known_peers, scan);
free(scan);
register_with_new_peer(eee, from_supernode, mac, peer);
} else {
/* Don't worry about what the supernode reports, it could be seeing a different socket. */
}
} else
update_peer_seen(scan, when);
scan->last_seen = when;
}
/* ************************************** */
@ -1043,8 +986,8 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) {
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
"peers pend:%u full:%u\n",
(unsigned int)peer_list_size(eee->pending_peers),
(unsigned int)peer_list_size(eee->known_peers));
HASH_COUNT(eee->pending_peers),
HASH_COUNT(eee->known_peers));
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
"last super:%lu(%ld sec ago) p2p:%lu(%ld sec ago)\n",
@ -1104,23 +1047,18 @@ static int is_ethMulticast(const void * buf, size_t bufsize) {
/* ************************************** */
static int check_query_peer_info(n2n_edge_t *eee, time_t now, n2n_mac_t mac) {
struct peer_info *scan = eee->pending_peers;
struct peer_info *scan;
while(scan != NULL) {
if(memcmp(scan->mac_addr, mac, N2N_MAC_SIZE) == 0)
break;
scan = scan->next;
}
HASH_FIND_PEER(eee->pending_peers, mac, scan);
if(!scan) {
scan = calloc(1, sizeof(struct peer_info));
memcpy(scan->mac_addr, mac, N2N_MAC_SIZE);
scan->timeout = REGISTER_SUPER_INTERVAL_DFL; /* TODO: should correspond to the peer supernode registration timeout */
update_peer_seen(scan, now); /* Don't change this it marks the pending peer for removal. */
scan->last_seen = now; /* Don't change this it marks the pending peer for removal. */
peer_list_add(&(eee->pending_peers), scan);
HASH_ADD_PEER(eee->pending_peers, scan);
}
if(now - scan->last_sent_query > REGISTER_SUPER_INTERVAL_DFL) {
@ -1138,8 +1076,7 @@ static int check_query_peer_info(n2n_edge_t *eee, time_t now, n2n_mac_t mac) {
static int find_peer_destination(n2n_edge_t * eee,
n2n_mac_t mac_address,
n2n_sock_t * destination) {
struct peer_info *scan = eee->known_peers;
struct peer_info *prev = NULL;
struct peer_info *scan;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
int retval=0;
@ -1155,31 +1092,21 @@ static int find_peer_destination(n2n_edge_t * eee,
mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF,
mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF);
while(scan != NULL) {
traceEvent(TRACE_DEBUG, "Evaluating peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X]",
scan->mac_addr[0] & 0xFF, scan->mac_addr[1] & 0xFF, scan->mac_addr[2] & 0xFF,
scan->mac_addr[3] & 0xFF, scan->mac_addr[4] & 0xFF, scan->mac_addr[5] & 0xFF
);
HASH_FIND_PEER(eee->known_peers, mac_address, scan);
if((scan->last_seen > 0) &&
(memcmp(mac_address, scan->mac_addr, N2N_MAC_SIZE) == 0)) {
if((now - scan->last_p2p) >= (scan->timeout / 2)) {
/* Too much time passed since we saw the peer, need to register again
* since the peer address may have changed. */
traceEvent(TRACE_DEBUG, "Refreshing idle known peer");
remove_peer_from_list(&eee->known_peers, prev, scan);
/* NOTE: registration will be performed upon the receival of the next response packet */
} else {
/* Valid known peer found */
memcpy(destination, &scan->sock, sizeof(n2n_sock_t));
retval=1;
}
break;
if(scan && (scan->last_seen > 0)) {
if((now - scan->last_p2p) >= (scan->timeout / 2)) {
/* Too much time passed since we saw the peer, need to register again
* since the peer address may have changed. */
traceEvent(TRACE_DEBUG, "Refreshing idle known peer");
HASH_DEL(eee->known_peers, scan);
free(scan);
/* NOTE: registration will be performed upon the receival of the next response packet */
} else {
/* Valid known peer found */
memcpy(destination, &scan->sock, sizeof(n2n_sock_t));
retval=1;
}
prev = scan;
scan = scan->next;
}
if(retval == 0) {
@ -1593,7 +1520,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
break;
}
scan = find_peer_by_mac( eee->pending_peers, pi.mac );
HASH_FIND_PEER(eee->pending_peers, pi.mac, scan);
if (scan) {
scan->sock = pi.sock;
traceEvent(TRACE_INFO, "Rx PEER_INFO on %s",
@ -1728,14 +1655,14 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
/* Finished processing select data. */
update_supernode_reg(eee, nowTime);
numPurged = purge_expired_registrations(&(eee->known_peers), &last_purge_known);
numPurged += purge_expired_registrations(&(eee->pending_peers), &last_purge_pending);
numPurged = purge_expired_registrations(&eee->known_peers, &last_purge_known);
numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending);
if(numPurged > 0) {
traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u",
numPurged,
(unsigned int)peer_list_size(eee->pending_peers),
(unsigned int)peer_list_size(eee->known_peers));
HASH_COUNT(eee->pending_peers),
HASH_COUNT(eee->known_peers));
}
if(eee->conf.dyn_ip_mode &&
@ -1773,8 +1700,8 @@ void edge_term(n2n_edge_t * eee) {
if(eee->udp_multicast_sock >= 0)
closesocket(eee->udp_multicast_sock);
clear_peer_list(&(eee->pending_peers));
clear_peer_list(&(eee->known_peers));
clear_peer_list(&eee->pending_peers);
clear_peer_list(&eee->known_peers);
eee->transop.deinit(&eee->transop);
free(eee);

113
n2n.c
View File

@ -263,57 +263,6 @@ void print_n2n_version() {
/* *********************************************** */
/** Find the peer entry in list with mac_addr equal to mac.
*
* Does not modify the list.
*
* @return NULL if not found; otherwise pointer to peer entry.
*/
struct peer_info * find_peer_by_mac(struct peer_info * list, const n2n_mac_t mac)
{
while(list != NULL)
{
if(0 == memcmp(mac, list->mac_addr, 6))
{
return list;
}
list = list->next;
}
return NULL;
}
/** Return the number of elements in the list.
*
*/
size_t peer_list_size(const struct peer_info * list)
{
size_t retval=0;
while(list)
{
++retval;
list = list->next;
}
return retval;
}
/** Add new to the head of list. If list is NULL; create it.
*
* The item new is added to the head of the list. New is modified during
* insertion. list takes ownership of new.
*/
void peer_list_add(struct peer_info * * list,
struct peer_info * newp)
{
newp->next = *list;
newp->last_seen = time(NULL);
*list = newp;
}
size_t purge_expired_registrations(struct peer_info ** peer_list, time_t* p_last_purge) {
time_t now = time(NULL);
size_t num_reg = 0;
@ -334,37 +283,16 @@ size_t purge_expired_registrations(struct peer_info ** peer_list, time_t* p_last
size_t purge_peer_list(struct peer_info ** peer_list,
time_t purge_before)
{
struct peer_info *scan;
struct peer_info *prev;
struct peer_info *scan, *tmp;
size_t retval=0;
scan = *peer_list;
prev = NULL;
while(scan != NULL)
{
if(scan->last_seen < purge_before)
{
struct peer_info *next = scan->next;
if(prev == NULL)
{
*peer_list = next;
}
else
{
prev->next = next;
}
++retval;
free(scan);
scan = next;
}
else
{
prev = scan;
scan = scan->next;
}
HASH_ITER(hh, *peer_list, scan, tmp) {
if(scan->last_seen < purge_before) {
HASH_DEL(*peer_list, scan);
retval++;
free(scan);
}
}
return retval;
}
@ -372,29 +300,14 @@ size_t purge_peer_list(struct peer_info ** peer_list,
/** Purge all items from the peer_list and return the number of items that were removed. */
size_t clear_peer_list(struct peer_info ** peer_list)
{
struct peer_info *scan;
struct peer_info *prev;
struct peer_info *scan, *tmp;
size_t retval=0;
scan = *peer_list;
prev = NULL;
while(scan != NULL)
{
struct peer_info *next = scan->next;
if(prev == NULL)
{
*peer_list = next;
}
else
{
prev->next = next;
}
++retval;
free(scan);
scan = next;
}
HASH_ITER(hh, *peer_list, scan, tmp) {
HASH_DEL(*peer_list, scan);
retval++;
free(scan);
}
return retval;
}

15
n2n.h
View File

@ -169,16 +169,22 @@ typedef char ipstr_t[32];
typedef char macstr_t[N2N_MACSTR_SIZE];
struct peer_info {
struct peer_info * next;
n2n_community_t community_name;
n2n_mac_t mac_addr;
n2n_community_t community_name;
n2n_sock_t sock;
int timeout;
time_t last_seen;
time_t last_p2p;
time_t last_sent_query;
UT_hash_handle hh; /* makes this structure hashable */
};
#define HASH_ADD_PEER(head,add) \
HASH_ADD(hh,head,mac_addr,sizeof(n2n_mac_t),add)
#define HASH_FIND_PEER(head,mac,out) \
HASH_FIND(hh,head,mac,sizeof(n2n_mac_t),out)
#define N2N_EDGE_SN_HOST_SIZE 48
#define N2N_EDGE_NUM_SUPERNODES 2
#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */
@ -275,11 +281,6 @@ int sock_equal( const n2n_sock_t * a,
const n2n_sock_t * b );
/* Operations on peer_info lists. */
struct peer_info * find_peer_by_mac( struct peer_info * list,
const n2n_mac_t mac );
void peer_list_add( struct peer_info * * list,
struct peer_info * newp );
size_t peer_list_size( const struct peer_info * list );
size_t purge_peer_list( struct peer_info ** peer_list,
time_t purge_before );
size_t clear_peer_list( struct peer_info ** peer_list );

32
sn.c
View File

@ -106,7 +106,7 @@ static void deinit_sn(n2n_sn_t * sss)
}
sss->mgmt_sock=-1;
purge_peer_list(&(sss->edges), 0xffffffff);
clear_peer_list(&sss->edges);
}
@ -136,7 +136,7 @@ static int update_edge(n2n_sn_t * sss,
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
scan = find_peer_by_mac(sss->edges, edgeMac);
HASH_FIND_PEER(sss->edges, edgeMac, scan);
if(NULL == scan) {
/* Not known */
@ -147,9 +147,7 @@ static int update_edge(n2n_sn_t * sss,
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
/* insert this guy at the head of the edges list */
scan->next = sss->edges; /* first in list */
sss->edges = scan; /* head of list points to new scan */
HASH_ADD_PEER(sss->edges, scan);
traceEvent(TRACE_INFO, "update_edge created %s ==> %s",
macaddr_str(mac_buf, edgeMac),
@ -229,7 +227,7 @@ static int try_forward(n2n_sn_t * sss,
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
scan = find_peer_by_mac(sss->edges, dstMac);
HASH_FIND_PEER(sss->edges, dstMac, scan);
if(NULL != scan)
{
@ -276,15 +274,13 @@ static int try_broadcast(n2n_sn_t * sss,
const uint8_t * pktbuf,
size_t pktsize)
{
struct peer_info * scan;
struct peer_info *scan, *tmp;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
traceEvent(TRACE_DEBUG, "try_broadcast");
scan = sss->edges;
while(scan != NULL)
{
HASH_ITER(hh, sss->edges, scan, tmp) {
if(0 == (memcmp(scan->community_name, cmn->community, sizeof(n2n_community_t)))
&& (0 != memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t))))
/* REVISIT: exclude if the destination socket is where the packet came from. */
@ -311,9 +307,7 @@ static int try_broadcast(n2n_sn_t * sss,
macaddr_str(mac_buf, scan->mac_addr));
}
}
scan = scan->next;
} /* while */
}
return 0;
}
@ -339,7 +333,7 @@ static int process_mgmt(n2n_sn_t * sss,
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"edges %u\n",
(unsigned int)peer_list_size(sss->edges));
HASH_COUNT(sss->edges));
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"errors %u\n",
@ -684,7 +678,7 @@ static int process_udp(n2n_sn_t * sss,
macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) );
scan = find_peer_by_mac( sss->edges, query.targetMac );
HASH_FIND_PEER(sss->edges, query.targetMac, scan);
if (scan) {
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_peer_info;
@ -895,14 +889,14 @@ static int loadFromFile(const char *path, n2n_sn_t *sss) {
/* *************************************************** */
static void dump_registrations(int signo) {
struct peer_info * list = sss_node.edges;
struct peer_info *list, *tmp;
char buf[32];
time_t now = time(NULL);
u_int num = 0;
traceEvent(TRACE_NORMAL, "====================================");
while(list != NULL) {
HASH_ITER(hh, sss_node.edges, list, tmp) {
if(list->sock.family == AF_INET)
traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: %u.%u.%u.%u:%u][community: %s][last seen: %u sec ago]",
++num, macaddr_str(buf, list->mac_addr),
@ -915,8 +909,6 @@ static void dump_registrations(int signo) {
++num, macaddr_str(buf, list->mac_addr), list->sock.port,
(char*)list->community_name,
now-list->last_seen);
list = list->next;
}
traceEvent(TRACE_NORMAL, "====================================");
@ -1063,7 +1055,7 @@ static int run_loop(n2n_sn_t * sss) {
traceEvent(TRACE_DEBUG, "timeout");
}
purge_expired_registrations( &(sss->edges), &last_purge_edges );
purge_expired_registrations( &sss->edges, &last_purge_edges );
} /* while */