diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index cb7c2b2..9636614 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -599,13 +599,16 @@ typedef struct n2n_resolve_ip_sock { // structure to hold resolver thread's parameters typedef struct n2n_resolve_parameter { - n2n_resolve_ip_sock_t *list; /* pointer to list of to be resolved nodes */ - uint8_t changed; /* indicates a change */ + n2n_resolve_ip_sock_t *list; /* pointer to list of to be resolved nodes */ + uint8_t changed; /* indicates a change */ #ifdef HAVE_PTHREAD - pthread_t id; /* thread id */ - pthread_mutex_t access; /* mutex for shared access */ + pthread_t id; /* thread id */ + pthread_mutex_t access; /* mutex for shared access */ #endif - time_t last_checked; /* last time the resolver completed */ + uint8_t request; /* flags main thread's need for intermediate resolution */ + time_t check_interval;/* interval to checik resolover results */ + time_t last_checked; /* last time the resolver results were cheked */ + time_t last_resolved; /* last time the resolver completed */ } n2n_resolve_parameter_t; @@ -700,6 +703,7 @@ struct n2n_edge { struct n2n_edge_stats stats; /**< Statistics */ n2n_resolve_parameter_t *resolve_parameter; /**< Pointer to name resolver's parameter block */ + uint8_t resolution_request; /**< Flag an immediate DNS resolution request */ n2n_tuntap_priv_config_t tuntap_priv_conf; /**< Tuntap config */ diff --git a/src/edge.c b/src/edge.c index f57de58..3b670b4 100644 --- a/src/edge.c +++ b/src/edge.c @@ -51,7 +51,7 @@ int fetch_and_eventually_process_data (n2n_edge_t *eee, SOCKET sock, uint8_t *pktbuf, uint16_t *expected, uint16_t *position, time_t now); int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list); -int resolve_check (n2n_resolve_parameter_t *param, time_t now); +int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now); /* ***************************************************** */ @@ -1174,7 +1174,7 @@ int main (int argc, char* argv[]) { } seek_answer = 1; - resolve_check(eee->resolve_parameter, now); + resolve_check(eee->resolve_parameter, 0 /* no intermediate resolution requirement at this point */, now); } // allow a higher number of pings for first regular round of ping // to quicker get an inital 'supernode selection criterion overview' diff --git a/src/edge_utils.c b/src/edge_utils.c index ff1ea1c..5931b4d 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -26,7 +26,7 @@ static HEAP_ALLOC (wrkmem, LZO1X_1_MEM_COMPRESS); /* ************************************** */ -int resolve_check (n2n_resolve_parameter_t *param, time_t now); +int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now); int resolve_cancel_thread (n2n_resolve_parameter_t *param); static const char * supernode_ip (const n2n_edge_t * eee); @@ -1429,6 +1429,8 @@ void update_supernode_reg (n2n_edge_t * eee, time_t now) { traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee)); supernode_connect(eee); reset_sup_attempts(eee); + // trigger out-of-schedule DNS resolution + eee->resolution_request = 1; // in some multi-NATed scenarios communication gets stuck on losing connection to supernode // closing and re-opening the socket allows for re-establishing communication @@ -2959,7 +2961,7 @@ int run_edge_loop (n2n_edge_t *eee, int *keep_running) { sort_supernodes(eee, now); - resolve_check(eee->resolve_parameter, now); + eee->resolution_request = resolve_check(eee->resolve_parameter, eee->resolution_request, now); if(eee->cb.main_loop_period) eee->cb.main_loop_period(eee, now); diff --git a/src/n2n.c b/src/n2n.c index 5ad3822..54eb967 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -318,36 +318,47 @@ void *resolve_thread (void *p) { #ifdef HAVE_PTHREAD n2n_resolve_parameter_t *param = (n2n_resolve_parameter_t*)p; n2n_resolve_ip_sock_t *entry, *tmp_entry; - int sleep_time = N2N_RESOLVE_INTERVAL / 10; /* initially shorter sleep */ + time_t rep_time = N2N_RESOLVE_INTERVAL / 10; + time_t now; while(1) { - sleep(sleep_time); + sleep(N2N_RESOLVE_INTERVAL / 60); /* wake up in-between to check for signaled requests */ + + // what's the time? + now = time(NULL); // lock access pthread_mutex_lock(¶m->access); - HASH_ITER(hh, param->list, entry, tmp_entry) { - // resolve - entry->error_code = supernode2sock(&entry->sock, entry->org_ip); - // if socket changed and no error - if(!sock_equal(&entry->sock, entry->org_sock) - && (!entry->error_code)) { - // flag the change - param->changed = 1; + // is it time to resolve yet? + if(((param->request)) || ((now - param->last_resolved) > rep_time)) { + HASH_ITER(hh, param->list, entry, tmp_entry) { + // resolve + entry->error_code = supernode2sock(&entry->sock, entry->org_ip); + // if socket changed and no error + if(!sock_equal(&entry->sock, entry->org_sock) + && (!entry->error_code)) { + // flag the change + param->changed = 1; + } } - } + param->last_resolved = now; - // unlock access - pthread_mutex_unlock(¶m->access); + // any request fulfilled + param->request = 0; - // determine next sleep duration (shorter if resolver errors occured) - sleep_time = N2N_RESOLVE_INTERVAL; - HASH_ITER(hh, param->list, entry, tmp_entry) { - if(entry->error_code) { - sleep_time = N2N_RESOLVE_INTERVAL / 10; - break; + // determine next resolver repetition (shorter time if resolver errors occured) + rep_time = N2N_RESOLVE_INTERVAL; + HASH_ITER(hh, param->list, entry, tmp_entry) { + if(entry->error_code) { + rep_time = N2N_RESOLVE_INTERVAL / 10; + break; + } } } + + // unlock access + pthread_mutex_unlock(¶m->access); } #endif } @@ -376,6 +387,7 @@ int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn traceEvent(TRACE_WARNING, "resolve_create_thread was unable to add list entry for supernode '%s'", sn->ip_addr); } } + (*param)->check_interval = N2N_RESOLVE_CHECK_INTERVAL; } else { traceEvent(TRACE_WARNING, "resolve_create_thread was unable to create list of supernodes"); return -1; @@ -404,13 +416,18 @@ void resolve_cancel_thread (n2n_resolve_parameter_t *param) { } -void resolve_check (n2n_resolve_parameter_t *param, time_t now) { +uint8_t resolve_check (n2n_resolve_parameter_t *param, uint8_t requires_resolution, time_t now) { + uint8_t ret = requires_resolution; /* if trylock fails, it still requires resolution */ #ifdef HAVE_PTHREAD n2n_resolve_ip_sock_t *entry, *tmp_entry; n2n_sock_str_t sock_buf; - if(now - param->last_checked > N2N_RESOLVE_CHECK_INTERVAL) { + // check_interval and last_check do not need to be guarded by the mutex because + // their values get changed and evaluated only here + + + if((now - param->last_checked > param->check_interval) || (requires_resolution)) { // try to lock access if(pthread_mutex_trylock(¶m->access) == 0) { // any changes? @@ -421,17 +438,32 @@ void resolve_check (n2n_resolve_parameter_t *param, time_t now) { // sockets do not get overwritten in case of error in resolve_thread) from list to supernode list HASH_ITER(hh, param->list, entry, tmp_entry) { memcpy(entry->org_sock, &entry->sock, sizeof(n2n_sock_t)); - traceEvent(TRACE_DEBUG, "resolve_check renews ip address of supernode '%s' to %s", - entry->org_ip, sock_to_cstr(sock_buf, &(entry->sock))); + traceEvent(TRACE_INFO, "resolve_check renews ip address of supernode '%s' to %s", + entry->org_ip, sock_to_cstr(sock_buf, &(entry->sock))); } } + + // let the resolver thread know eventual difficulties in reaching the supernode + if(requires_resolution) { + param->request = 1; + ret = 0; + } + param->last_checked = now; + // next appointment + if(param->request) + // earlier if resolver still working on fulfilling a request + param->check_interval = N2N_RESOLVE_CHECK_INTERVAL / 10; + else + param->check_interval = N2N_RESOLVE_CHECK_INTERVAL; + // unlock access pthread_mutex_unlock(¶m->access); } } #endif + return ret; } diff --git a/src/sn_utils.c b/src/sn_utils.c index 0d09819..8d90211 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -20,7 +20,7 @@ #define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) -int resolve_check (n2n_resolve_parameter_t *param, time_t now); +int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now); int resolve_cancel_thread (n2n_resolve_parameter_t *param); static ssize_t sendto_peer (n2n_sn_t *sss, @@ -2364,7 +2364,7 @@ int run_sn_loop (n2n_sn_t *sss, int *keep_running) { re_register_and_purge_supernodes(sss, sss->federation, &last_re_reg_and_purge, now); purge_expired_communities(sss, &last_purge_edges, now); sort_communities(sss, &last_sort_communities, now); - resolve_check(sss->resolve_parameter, now); + resolve_check(sss->resolve_parameter, 0 /* presumably, no special resolution requirement */, now); } /* while */ sn_term(sss);