From 447c3ad8c33a1d45596ca9307ae72943763fa0d0 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Sun, 9 Jun 2019 23:41:47 +0200 Subject: [PATCH] Replace peers linked list with hash --- edge_utils.c | 209 +++++++++++++++++---------------------------------- n2n.c | 113 ++++------------------------ n2n.h | 15 ++-- sn.c | 32 +++----- 4 files changed, 101 insertions(+), 268 deletions(-) diff --git a/edge_utils.c b/edge_utils.c index 8fe7032..173ec28 100644 --- a/edge_utils.c +++ b/edge_utils.c @@ -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; - - while(scan != NULL) { - if(memcmp(scan->mac_addr, mac, N2N_MAC_SIZE) == 0) - break; /* found. */ - - prev = scan; - scan = scan->next; - } + struct peer_info *peer; - 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; - - while (NULL != scan) - { - if(0 == memcmp(scan->mac_addr, mac, N2N_MAC_SIZE)) - { - break; /* found. */ - } - - prev = scan; - scan = scan->next; - } - - if(scan) - { - - - /* Remove scan from pending_peers. */ - if(prev) - { - prev->next = scan->next; - } - else - { - eee->pending_peers = scan->next; - } + HASH_FIND_PEER(eee->pending_peers, mac, scan); - /* Add scan to known_peers. */ - scan->next = eee->known_peers; - eee->known_peers = scan; + if(scan) { + HASH_DEL(eee->pending_peers, scan); - scan->sock = *peer; - scan->last_p2p = now; + /* Add scan to known_peers. */ + HASH_ADD_PEER(eee->known_peers, scan); - traceEvent(TRACE_NORMAL, "P2P connection enstablished: %s [%s]", - macaddr_str(mac_buf, mac), - sock_to_cstr(sockbuf, peer)); + scan->sock = *peer; + scan->last_p2p = now; - traceEvent(TRACE_DEBUG, "=== new peer %s -> %s", - macaddr_str(mac_buf, scan->mac_addr), - sock_to_cstr(sockbuf, &(scan->sock))); + traceEvent(TRACE_NORMAL, "P2P connection enstablished: %s [%s]", + macaddr_str(mac_buf, mac), + sock_to_cstr(sockbuf, peer)); - traceEvent(TRACE_INFO, "Pending peers list size=%u", - (unsigned int)peer_list_size(eee->pending_peers)); + traceEvent(TRACE_DEBUG, "=== new peer %s -> %s", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf, &(scan->sock))); - traceEvent(TRACE_INFO, "Known peers list size=%u", - (unsigned int)peer_list_size(eee->known_peers)); + traceEvent(TRACE_INFO, "Pending peers list size=%u", + HASH_COUNT(eee->pending_peers)); + traceEvent(TRACE_INFO, "Known peers list size=%u", + HASH_COUNT(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; - - while(scan != NULL) { - if(memcmp(scan->mac_addr, mac, N2N_MAC_SIZE) == 0) - break; + struct peer_info *scan; - 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 - ); - - 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; + HASH_FIND_PEER(eee->known_peers, mac_address, scan); + + 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); diff --git a/n2n.c b/n2n.c index b17cff9..78c5010 100644 --- a/n2n.c +++ b/n2n.c @@ -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; } diff --git a/n2n.h b/n2n.h index 8904b71..caf824b 100644 --- a/n2n.h +++ b/n2n.h @@ -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 ); diff --git a/sn.c b/sn.c index 0e41826..b8d8507 100644 --- a/sn.c +++ b/sn.c @@ -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 */