From f0646875d0bc941e339d305d0c68b13543cd6f2a Mon Sep 17 00:00:00 2001 From: Sander Vrijders Date: Tue, 25 Oct 2016 13:22:51 +0200 Subject: lib, irmd, ipcpd: Add name querying to IPCPs This adds the ability to query IPCPs if a name can be reached through them, e.g. if a name is available in a DIF. This means that in the shim-udp a DNS query is performed, in the shim-eth-llc an ARP-like query has been added, in the local a check is done to see if the name is registered, and in the normal currently no application is reachable through it. --- src/ipcpd/ipcp-data.c | 308 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 227 insertions(+), 81 deletions(-) (limited to 'src/ipcpd/ipcp-data.c') diff --git a/src/ipcpd/ipcp-data.c b/src/ipcpd/ipcp-data.c index ed7e578d..b3078054 100644 --- a/src/ipcpd/ipcp-data.c +++ b/src/ipcpd/ipcp-data.c @@ -21,14 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#include - #define OUROBOROS_PREFIX "ipcp-utils" +#include +#include +#include #include +#include #include "ipcp-data.h" +#include "ipcp.h" #include #include @@ -41,8 +43,8 @@ struct reg_entry { struct dir_entry { struct list_head list; - char * ap_name; - uint64_t addr; + char * name; + uint64_t addr; }; static struct reg_entry * reg_entry_create(char * name) @@ -70,18 +72,18 @@ static void reg_entry_destroy(struct reg_entry * entry) free(entry); } -static struct dir_entry * dir_entry_create(char * ap_name, +static struct dir_entry * dir_entry_create(char * name, uint64_t addr) { struct dir_entry * entry = malloc(sizeof(*entry)); if (entry == NULL) return NULL; - assert(ap_name); + assert(name); entry->addr = addr; - entry->ap_name = ap_name; - if (entry->ap_name == NULL) + entry->name = name; + if (entry->name == NULL) return NULL; return entry; @@ -91,8 +93,8 @@ static void dir_entry_destroy(struct dir_entry * entry) { assert(entry); - if (entry->ap_name != NULL) - free(entry->ap_name); + if (entry->name != NULL) + free(entry->name); free(entry); } @@ -120,10 +122,12 @@ struct ipcp_data * ipcp_data_init(struct ipcp_data * dst, /* init the lists */ INIT_LIST_HEAD(&dst->registry); INIT_LIST_HEAD(&dst->directory); + INIT_LIST_HEAD(&dst->dir_queries); /* init the locks */ pthread_rwlock_init(&dst->reg_lock, NULL); pthread_rwlock_init(&dst->dir_lock, NULL); + pthread_mutex_init(&dst->dir_queries_lock, NULL); return dst; } @@ -156,6 +160,20 @@ static void clear_directory(struct ipcp_data * data) } } +static void clear_dir_queries(struct ipcp_data * data) +{ + struct list_head * h; + struct list_head * t; + + assert(data); + + list_for_each_safe(h, t, &data->dir_queries) { + struct dir_query * e = list_entry(h, struct dir_query, next); + list_del(&e->next); + ipcp_data_dir_query_destroy(e); + } +} + void ipcp_data_destroy(struct ipcp_data * data) { if (data == NULL) @@ -163,27 +181,27 @@ void ipcp_data_destroy(struct ipcp_data * data) /* clear the lists */ pthread_rwlock_wrlock(&data->reg_lock); - clear_registry(data); - pthread_rwlock_unlock(&data->reg_lock); - pthread_rwlock_wrlock(&data->dir_lock); + pthread_rwlock_wrlock(&data->dir_lock); clear_directory(data); - pthread_rwlock_unlock(&data->dir_lock); + pthread_mutex_lock(&data->dir_queries_lock); + clear_dir_queries(data); + pthread_mutex_unlock(&data->dir_queries_lock); + if (data->dif_name != NULL) free(data->dif_name); pthread_rwlock_destroy(&data->dir_lock); pthread_rwlock_destroy(&data->reg_lock); + pthread_mutex_destroy(&data->dir_queries_lock); free(data); } - - static struct reg_entry * find_reg_entry_by_name(struct ipcp_data * data, const char * name) { @@ -202,13 +220,13 @@ static struct reg_entry * find_reg_entry_by_name(struct ipcp_data * data, } static struct dir_entry * find_dir_entry(struct ipcp_data * data, - const char * ap_name, + const char * name, uint64_t addr) { struct list_head * h; list_for_each(h, &data->directory) { struct dir_entry * e = list_entry(h, struct dir_entry, list); - if (e->addr == addr && !strcmp(e->ap_name, ap_name)) + if (e->addr == addr && !strcmp(e->name, name)) return e; } @@ -216,33 +234,47 @@ static struct dir_entry * find_dir_entry(struct ipcp_data * data, } static struct dir_entry * find_dir_entry_any(struct ipcp_data * data, - const char * ap_name) + const char * name) { struct list_head * h; list_for_each(h, &data->directory) { struct dir_entry * e = list_entry(h, struct dir_entry, list); - if (!strcmp(e->ap_name, ap_name)) + if (!strcmp(e->name, name)) return e; } return NULL; } -bool ipcp_data_is_in_directory(struct ipcp_data * data, - const char * ap_name) +int ipcp_data_reg_add_entry(struct ipcp_data * data, + char * name) { - bool ret = false; + struct reg_entry * entry; - pthread_rwlock_rdlock(&data->dir_lock); + if (data == NULL || name == NULL) + return -1; - ret = (find_dir_entry_any(data, ap_name) != NULL); + pthread_rwlock_wrlock(&data->reg_lock); - pthread_rwlock_unlock(&data->dir_lock); + if (find_reg_entry_by_name(data, name)) { + pthread_rwlock_unlock(&data->reg_lock); + return -1; + } - return ret; + entry = reg_entry_create(name); + if (entry == NULL) { + pthread_rwlock_unlock(&data->reg_lock); + return -1; + } + + list_add(&entry->list, &data->registry); + + pthread_rwlock_unlock(&data->reg_lock); + + return 0; } -int ipcp_data_del_reg_entry(struct ipcp_data * data, +int ipcp_data_reg_del_entry(struct ipcp_data * data, const char * name) { struct reg_entry * e; @@ -266,114 +298,109 @@ int ipcp_data_del_reg_entry(struct ipcp_data * data, return 0; } -int ipcp_data_del_dir_entry(struct ipcp_data * data, - const char * ap_name, - uint64_t addr) +bool ipcp_data_reg_has(struct ipcp_data * data, + const char * name) { - struct dir_entry * e; - if (data == NULL) - return -1; - - pthread_rwlock_wrlock(&data->dir_lock); + bool ret = false; - e = find_dir_entry(data, ap_name, addr); - if (e == NULL) { - pthread_rwlock_unlock(&data->dir_lock); - return 0; /* nothing to do */ - } + if (data == NULL || name == NULL) + return false; - list_del(&e->list); + pthread_rwlock_rdlock(&data->reg_lock); - pthread_rwlock_unlock(&data->dir_lock); + ret = (find_reg_entry_by_name(data, name) != NULL); - dir_entry_destroy(e); + pthread_rwlock_unlock(&data->reg_lock); - return 0; + return ret; } -int ipcp_data_add_reg_entry(struct ipcp_data * data, - char * name) +int ipcp_data_dir_add_entry(struct ipcp_data * data, + char * name, + uint64_t addr) { - struct reg_entry * entry; + struct dir_entry * entry; + char * entry_name; if (data == NULL || name == NULL) return -1; - pthread_rwlock_wrlock(&data->reg_lock); + pthread_rwlock_wrlock(&data->dir_lock); - if (find_reg_entry_by_name(data, name)) { - pthread_rwlock_unlock(&data->reg_lock); + if (find_dir_entry(data, name, addr) != NULL) { + pthread_rwlock_unlock(&data->dir_lock); return -1; } - entry = reg_entry_create(name); + entry_name = strdup(name); + if (entry_name == NULL) { + pthread_rwlock_unlock(&data->dir_lock); + return -1; + } + + entry = dir_entry_create(entry_name, addr); if (entry == NULL) { - pthread_rwlock_unlock(&data->reg_lock); + pthread_rwlock_unlock(&data->dir_lock); return -1; } - list_add(&entry->list, &data->registry); + list_add(&entry->list,&data->directory); - pthread_rwlock_unlock(&data->reg_lock); + pthread_rwlock_unlock(&data->dir_lock); + + LOG_DBG("Added directory entry for %s.", entry_name); return 0; } -int ipcp_data_add_dir_entry(struct ipcp_data * data, - char * ap_name, +int ipcp_data_dir_del_entry(struct ipcp_data * data, + const char * name, uint64_t addr) { - struct dir_entry * entry; - - if (data == NULL || ap_name == NULL) + struct dir_entry * e; + if (data == NULL) return -1; pthread_rwlock_wrlock(&data->dir_lock); - if (find_dir_entry(data, ap_name, addr) != NULL) { - pthread_rwlock_unlock(&data->dir_lock); - return -1; - } - - entry = dir_entry_create(ap_name, addr); - if (entry == NULL) { + e = find_dir_entry(data, name, addr); + if (e == NULL) { pthread_rwlock_unlock(&data->dir_lock); - return -1; + return 0; /* nothing to do */ } - list_add(&entry->list,&data->directory); + list_del(&e->list); pthread_rwlock_unlock(&data->dir_lock); + dir_entry_destroy(e); + return 0; } -bool ipcp_data_is_in_registry(struct ipcp_data * data, - const char * ap_name) +bool ipcp_data_dir_has(struct ipcp_data * data, + const char * name) { bool ret = false; - if (data == NULL || ap_name == NULL) - return false; - - pthread_rwlock_rdlock(&data->reg_lock); + pthread_rwlock_rdlock(&data->dir_lock); - ret = (find_reg_entry_by_name(data, ap_name) != NULL); + ret = (find_dir_entry_any(data, name) != NULL); - pthread_rwlock_unlock(&data->reg_lock); + pthread_rwlock_unlock(&data->dir_lock); return ret; } -uint64_t ipcp_data_get_addr(struct ipcp_data * data, - const char * ap_name) +uint64_t ipcp_data_dir_get_addr(struct ipcp_data * data, + const char * name) { struct dir_entry * entry; uint64_t addr; pthread_rwlock_rdlock(&data->dir_lock); - entry = find_dir_entry_any(data, ap_name); + entry = find_dir_entry_any(data, name); if (entry == NULL) { pthread_rwlock_unlock(&data->dir_lock); @@ -386,3 +413,122 @@ uint64_t ipcp_data_get_addr(struct ipcp_data * data, return addr; } + +struct dir_query * ipcp_data_dir_query_create(char * name) +{ + struct dir_query * query; + pthread_condattr_t cattr; + + query = malloc(sizeof(*query)); + if (query == NULL) + return NULL; + + query->name = strdup(name); + if (query->name == NULL) { + free(query); + return NULL; + } + + query->state = QUERY_INIT; + + pthread_condattr_init(&cattr); +#ifndef __APPLE__ + pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); +#endif + pthread_cond_init(&query->cond, &cattr); + pthread_mutex_init(&query->lock, NULL); + + INIT_LIST_HEAD(&query->next); + + return query; +} + +void ipcp_data_dir_query_respond(struct dir_query * query) +{ + assert(query); + + pthread_mutex_lock(&query->lock); + + if (query->state != QUERY_PENDING) { + pthread_mutex_unlock(&query->lock); + return; + } + + query->state = QUERY_RESPONSE; + pthread_cond_broadcast(&query->cond); + + while (query->state == QUERY_RESPONSE) + pthread_cond_wait(&query->cond, &query->lock); + + pthread_mutex_unlock(&query->lock); +} + +void ipcp_data_dir_query_destroy(struct dir_query * query) +{ + assert(query); + + pthread_mutex_lock(&query->lock); + + if (query->state == QUERY_DESTROY) { + pthread_mutex_unlock(&query->lock); + return; + } + + if (query->state == QUERY_INIT) + query->state = QUERY_DONE; + + if (query->state == QUERY_PENDING) { + query->state = QUERY_DESTROY; + pthread_cond_broadcast(&query->cond); + } + + while (query->state != QUERY_DONE) + pthread_cond_wait(&query->cond, &query->lock); + + pthread_mutex_unlock(&query->lock); + + pthread_cond_destroy(&query->cond); + pthread_mutex_destroy(&query->lock); + + free(query->name); + free(query); +} + +int ipcp_data_dir_query_wait(struct dir_query * query, + const struct timespec * timeout) +{ + struct timespec abstime; + int ret = 0; + + assert(query); + assert(timeout); + + clock_gettime(PTHREAD_COND_CLOCK, &abstime); + ts_add(&abstime, timeout, &abstime); + + pthread_mutex_lock(&query->lock); + + if (query->state != QUERY_INIT) { + pthread_mutex_unlock(&query->lock); + return -EINVAL; + } + + query->state = QUERY_PENDING; + + while (query->state == QUERY_PENDING) { + if ((ret = -pthread_cond_timedwait(&query->cond, + &query->lock, + &abstime)) == -ETIMEDOUT) + break; + } + + if (query->state == QUERY_DESTROY) + ret = -1; + + query->state = QUERY_DONE; + pthread_cond_broadcast(&query->cond); + + pthread_mutex_unlock(&query->lock); + + return ret; +} -- cgit v1.2.3