summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSander Vrijders <[email protected]>2016-07-05 17:10:42 +0200
committerSander Vrijders <[email protected]>2016-07-05 17:10:42 +0200
commitdb96f7d488681be47abfeec6c636fd4159a37660 (patch)
treeca4c17706164fbfe772a613225d87df22e6f35e0
parent51ccc34e0fe15aaf711f30fa8b63de1e1881029f (diff)
parent72469bafa9d81a5578f53ec40175001f4c77cff6 (diff)
downloadouroboros-db96f7d488681be47abfeec6c636fd4159a37660.tar.gz
ouroboros-db96f7d488681be47abfeec6c636fd4159a37660.zip
Merged in dstaesse/ouroboros/irmd-refactor (pull request #156)
irmd: Move registry to its own sources
-rw-r--r--include/ouroboros/config.h.in3
-rw-r--r--src/irmd/CMakeLists.txt1
-rw-r--r--src/irmd/main.c654
-rw-r--r--src/irmd/registry.c593
-rw-r--r--src/irmd/registry.h148
5 files changed, 767 insertions, 632 deletions
diff --git a/include/ouroboros/config.h.in b/include/ouroboros/config.h.in
index a3f6e87c..4cbed554 100644
--- a/include/ouroboros/config.h.in
+++ b/include/ouroboros/config.h.in
@@ -41,5 +41,8 @@
#define DU_BUFF_TAILSPACE 0
#define SHM_AP_RBUFF_PREFIX "ouroboros_rb_"
#define SHM_RBUFF_SIZE (1 << 14)
+#define IRMD_MAX_FLOWS 4096
+#define IRMD_THREADPOOL_SIZE 3
+#define IRMD_FLOW_TIMEOUT 5000 /* ms */
#endif
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index a402b242..bf810d96 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -7,6 +7,7 @@ include_directories(${CMAKE_BINARY_DIR}/include)
set(SOURCE_FILES
# Add source files here
main.c
+ registry.c
utils.c
)
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 38e10cc5..8475839b 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -3,7 +3,8 @@
*
* The IPC Resource Manager
*
- * Sander Vrijders <[email protected]>
+ * Dimitri Staessens <[email protected]>
+ * Sander Vrijders <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +39,7 @@
#include <ouroboros/time_utils.h>
#include "utils.h"
+#include "registry.h"
#include <sys/socket.h>
#include <sys/un.h>
@@ -51,18 +53,8 @@
#define API_INVALID 0
-#define IRMD_MAX_FLOWS 4096
-
-#define IRMD_THREADPOOL_SIZE 3
-
-#define IRMD_FLOW_TIMEOUT 5000 /* ms */
-
#define IRMD_CLEANUP_TIMER ((IRMD_FLOW_TIMEOUT / 20) * MILLION) /* ns */
-#define reg_entry_has_api(e, id) (reg_entry_get_reg_instance(e, id) != NULL)
-#define reg_entry_has_ap_name(e, name) (reg_entry_get_ap_name(e, name) != NULL)
-#define reg_entry_has_ap_auto(e, name) (reg_entry_get_reg_auto(e, name) != NULL)
-
struct ipcp_entry {
struct list_head next;
char * name;
@@ -76,144 +68,6 @@ enum irm_state {
IRMD_SHUTDOWN
};
-enum reg_name_state {
- REG_NAME_NULL = 0,
- REG_NAME_IDLE,
- REG_NAME_AUTO_ACCEPT,
- REG_NAME_AUTO_EXEC,
- REG_NAME_FLOW_ACCEPT,
- REG_NAME_FLOW_ARRIVED
-};
-
-enum reg_i_state {
- REG_I_NULL = 0,
- REG_I_SLEEP,
- REG_I_WAKE
-};
-
-struct reg_instance {
- struct list_head next;
- pid_t api;
-
- /* the api will block on this */
- enum reg_i_state state;
- pthread_cond_t wakeup;
- pthread_mutex_t mutex;
-};
-
-static struct reg_instance * reg_instance_create(pid_t api)
-{
- struct reg_instance * i;
- i = malloc(sizeof(*i));
- if (i == NULL)
- return NULL;
-
- i->api = api;
- i->state = REG_I_WAKE;
-
- pthread_mutex_init(&i->mutex, NULL);
- pthread_cond_init(&i->wakeup, NULL);
-
- INIT_LIST_HEAD(&i->next);
-
- return i;
-}
-
-static void reg_instance_sleep(struct reg_instance * i)
-{
- pthread_mutex_lock(&i->mutex);
- if (i->state != REG_I_WAKE) {
- pthread_mutex_unlock(&i->mutex);
- return;
- }
-
- i->state = REG_I_SLEEP;
-
- pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock,
- (void *) &i->mutex);
-
- while (i->state == REG_I_SLEEP)
- pthread_cond_wait(&i->wakeup, &i->mutex);
-
- pthread_cleanup_pop(true);
-}
-
-static void reg_instance_wake(struct reg_instance * i)
-{
- pthread_mutex_lock(&i->mutex);
-
- if (i->state == REG_I_NULL) {
- pthread_mutex_unlock(&i->mutex);
- return;
- }
-
- i->state = REG_I_WAKE;
-
- pthread_cond_signal(&i->wakeup);
- pthread_mutex_unlock(&i->mutex);
-}
-
-static void reg_instance_destroy(struct reg_instance * i)
-{
- bool wait = true;
- pthread_mutex_lock(&i->mutex);
- i->state = REG_I_NULL;
-
- pthread_cond_broadcast(&i->wakeup);
- pthread_mutex_unlock(&i->mutex);
-
- while (wait) {
- pthread_mutex_lock(&i->mutex);
- if (pthread_cond_destroy(&i->wakeup))
- pthread_cond_broadcast(&i->wakeup);
- else
- wait = false;
- pthread_mutex_unlock(&i->mutex);
- }
-
- pthread_mutex_destroy(&i->mutex);
-
- free(i);
-}
-
-struct reg_auto {
- struct list_head next;
- char * ap_name;
- char ** argv;
-};
-
-struct reg_ap_name {
- struct list_head next;
- char * ap_name;
-};
-
-/* an entry in the registry */
-struct reg_entry {
- struct list_head next;
-
- /* generic name */
- char * name;
-
- /* names of the aps that can listen to this name */
- struct list_head ap_names;
-
- enum reg_name_state state;
-
- uint32_t flags;
-
- /* auto execution info */
- struct list_head auto_ap_info;
-
- /* known instances */
- struct list_head ap_instances;
-
- char * req_ae_name;
- int response;
-
- pthread_cond_t acc_signal;
- pthread_mutex_t state_lock;
-};
-
/* keeps track of port_id's between N and N - 1 */
struct port_map_entry {
struct list_head next;
@@ -405,475 +259,6 @@ static pid_t get_ipcp_by_dst_name(char * dst_name,
return 0;
}
-static struct reg_entry * reg_entry_create()
-{
- struct reg_entry * e = malloc(sizeof(*e));
- if (e == NULL)
- return NULL;
-
- e->name = NULL;
- e->state = REG_NAME_NULL;
- e->flags = 0;
-
- e->req_ae_name = NULL;
- e->response = -1;
-
- return e;
-}
-
-static struct reg_entry * reg_entry_init(struct reg_entry * e,
- char * name,
- char * ap_name,
- uint32_t flags)
-{
- if (e == NULL || name == NULL || ap_name == NULL)
- return NULL;
-
- struct reg_ap_name * n = malloc(sizeof(*n));
- if (n == NULL)
- return NULL;
-
- INIT_LIST_HEAD(&e->next);
- INIT_LIST_HEAD(&e->ap_names);
- INIT_LIST_HEAD(&e->auto_ap_info);
- INIT_LIST_HEAD(&e->ap_instances);
-
- e->name = name;
- e->flags = flags;
- n->ap_name = ap_name;
-
- list_add(&n->next, &e->ap_names);
-
- if (pthread_cond_init(&e->acc_signal, NULL)) {
- free(e);
- return NULL;
- }
-
- if (pthread_mutex_init(&e->state_lock, NULL)) {
- free(e);
- return NULL;
- }
-
- e->state = REG_NAME_IDLE;
-
- return e;
-}
-
-static void reg_entry_destroy(struct reg_entry * e)
-{
- struct list_head * pos = NULL;
- struct list_head * n = NULL;
-
- bool wait = true;
-
- if (e == NULL)
- return;
-
- pthread_mutex_lock(&e->state_lock);
-
- e->state = REG_NAME_NULL;
-
- pthread_cond_broadcast(&e->acc_signal);
- pthread_mutex_unlock(&e->state_lock);
-
- while (wait) {
- pthread_mutex_lock(&e->state_lock);
- if (pthread_cond_destroy(&e->acc_signal))
- pthread_cond_broadcast(&e->acc_signal);
- else
- wait = false;
- pthread_mutex_unlock(&e->state_lock);
- }
-
- pthread_mutex_destroy(&e->state_lock);
-
- if (e->name != NULL)
- free(e->name);
-
- if (e->req_ae_name != NULL)
- free(e->req_ae_name);
-
- list_for_each_safe(pos, n, &e->ap_instances) {
- struct reg_instance * i =
- list_entry(pos, struct reg_instance, next);
- reg_instance_destroy(i);
- }
-
- list_for_each_safe(pos, n, &e->auto_ap_info) {
- struct reg_auto * a =
- list_entry(pos, struct reg_auto, next);
-
- if (a->argv != NULL) {
- char ** t = a->argv;
- while (*a->argv != NULL)
- free(*(a->argv++));
- free(t);
- }
-
- free(a->ap_name);
- free(a);
- }
-
- list_for_each_safe(pos, n, &e->ap_names) {
- struct reg_ap_name * n =
- list_entry(pos, struct reg_ap_name, next);
-
- free(n->ap_name);
- free(n);
- }
-
- free(e);
-}
-
-static struct reg_ap_name * reg_entry_get_ap_name(struct reg_entry * e,
- char * ap_name)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &e->ap_names) {
- struct reg_ap_name * n =
- list_entry(pos, struct reg_ap_name, next);
-
- if (strcmp(ap_name, n->ap_name) == 0)
- return n;
- }
-
- return NULL;
-}
-
-static struct reg_instance * reg_entry_get_reg_instance(struct reg_entry * e,
- pid_t api)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &e->ap_instances) {
- struct reg_instance * r =
- list_entry(pos, struct reg_instance, next);
-
- if (r->api == api)
- return r;
- }
-
- return NULL;
-}
-
-static struct reg_auto * reg_entry_get_reg_auto(struct reg_entry * e,
- char * ap_name)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &e->auto_ap_info) {
- struct reg_auto * a =
- list_entry(pos, struct reg_auto, next);
-
- if (strcmp(ap_name, a->ap_name) == 0)
- return a;
- }
-
- return NULL;
-}
-
-static struct reg_entry * get_reg_entry_by_name(char * name)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &instance->registry) {
- struct reg_entry * e =
- list_entry(pos, struct reg_entry, next);
-
- if (strcmp(name, e->name) == 0)
- return e;
- }
-
- return NULL;
-}
-
-static struct reg_entry * get_reg_entry_by_ap_name(char * ap_name)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &instance->registry) {
- struct list_head * p = NULL;
- struct reg_entry * e =
- list_entry(pos, struct reg_entry, next);
-
- list_for_each(p, &e->ap_names) {
- struct reg_ap_name * n =
- list_entry(p, struct reg_ap_name, next);
-
- if (strcmp(n->ap_name, ap_name) == 0)
- return e;
- }
- }
-
- return NULL;
-}
-
-static struct reg_entry * get_reg_entry_by_ap_id(pid_t api)
-{
- struct list_head * pos = NULL;
-
- list_for_each(pos, &instance->registry) {
- struct list_head * p = NULL;
- struct reg_entry * e =
- list_entry(pos, struct reg_entry, next);
-
- list_for_each(p, &e->ap_instances) {
- struct reg_instance * r =
- list_entry(p, struct reg_instance, next);
-
- if (r->api == api)
- return e;
- }
- }
-
- return NULL;
-}
-
-static int registry_add_entry(char * name, char * ap_name, uint16_t flags)
-{
- struct reg_entry * e = NULL;
-
- if (name == NULL || ap_name == NULL)
- return -EINVAL;
-
- e = get_reg_entry_by_name(name);
- if (e != NULL) {
- LOG_DBG("Name %s already registered.", name);
- return -1;
- }
-
- e = reg_entry_create();
- if (e == NULL) {
- LOG_DBG("Could not create registry entry.");
- return -1;
- }
-
- e = reg_entry_init(e, name, ap_name, flags);
- if (e == NULL) {
- LOG_DBG("Could not initialize registry entry.");
- reg_entry_destroy(e);
- return -1;
- }
-
- list_add(&e->next, &instance->registry);
-
- return 0;
-}
-
-static int registry_add_ap_auto(char * name,
- char * ap_name,
- char ** argv)
-{
- struct reg_entry * e;
- struct reg_auto * a;
-
- if (name == NULL || ap_name == NULL)
- return -EINVAL;
-
- e = get_reg_entry_by_name(name);
- if (e == NULL) {
- LOG_DBG("Name %s not found in registry.", name);
- return -1;
- }
-
- if (!(e->flags & BIND_AP_AUTO)) {
- LOG_DBG("%s does not allow auto-instantiation.", name);
- return -1;
- }
-
- if (!reg_entry_has_ap_name(e, ap_name)) {
- LOG_DBG("AP name %s not associated with %s.", ap_name, name);
- return -1;
- }
-
- if (e->state == REG_NAME_NULL) {
- LOG_DBG("Tried to add instantiation info in NULL state.");
- return -1;
- }
-
- a = reg_entry_get_reg_auto(e, ap_name);
- if (a != NULL) {
- LOG_DBG("Updating auto-instantiation info for %s.", ap_name);
- list_del(&a->next);
- free(a->ap_name);
- if (a->argv != NULL) {
- while (*a->argv != NULL)
- free(*a->argv++);
- }
- } else {
- a = malloc(sizeof(*a));
- if (a == NULL)
- return -1;
- }
-
- a->ap_name = ap_name;
- a->argv = argv;
-
- if (e->state == REG_NAME_IDLE)
- e->state = REG_NAME_AUTO_ACCEPT;
-
- list_add(&a->next, &e->auto_ap_info);
-
- return 0;
-}
-
-#if 0
-static int registry_remove_ap_auto(char * name,
- char * ap_name)
-{
- struct reg_entry * e;
- struct reg_auto * a;
-
- if (name == NULL || ap_name == NULL)
- return -EINVAL;
-
- e = get_reg_entry_by_name(name);
- if (e == NULL) {
- LOG_DBG("Name %s not found in registry.", name);
- return -1;
- }
-
- a = reg_entry_get_reg_auto(e, ap_name);
- if (a == NULL) {
- LOG_DBG("Auto-instantiation info for %s not found.", ap_name);
- return -1;
- }
-
- list_del(&a->next);
-
- if (e->state == REG_NAME_AUTO_ACCEPT && list_empty(&e->auto_ap_info))
- e->state = REG_NAME_IDLE;
-
- return 0;
-}
-#endif
-
-static struct reg_instance * registry_add_ap_instance(char * name,
- pid_t api)
-{
- struct reg_entry * e = NULL;
- struct reg_instance * i = NULL;
-
- if (name == NULL || api == 0)
- return NULL;
-
- e = get_reg_entry_by_name(name);
- if (e == NULL) {
- LOG_DBG("Name %s not found in registry.", name);
- return NULL;
- }
-
- if (api == API_INVALID) {
- LOG_DBG("Invalid api.");
- return NULL;
- }
-
- if (reg_entry_has_api(e, api)) {
- LOG_DBG("Instance already registered with this name.");
- return NULL;
- }
-
- if (e->state == REG_NAME_NULL) {
- LOG_DBG("Tried to add instance in NULL state.");
- return NULL;
- }
-
- i = reg_instance_create(api);
- if (i == NULL) {
- LOG_DBG("Failed to create reg_instance");
- return NULL;
- }
-
- if (e->state == REG_NAME_IDLE || e->state == REG_NAME_AUTO_ACCEPT
- || e->state == REG_NAME_AUTO_EXEC) {
- e->state = REG_NAME_FLOW_ACCEPT;
- pthread_cond_signal(&e->acc_signal);
- }
-
- list_add(&i->next, &e->ap_instances);
-
- return i;
-}
-
-static int registry_remove_ap_instance(char * name, pid_t api)
-{
- struct reg_entry * e = NULL;
- struct reg_instance * i = NULL;
-
- if (name == NULL || api == 0)
- return -1;
-
- e = get_reg_entry_by_name(name);
- if (e == NULL) {
- LOG_DBG("Name %s is not registered.", name);
- return -1;
- }
-
- i = reg_entry_get_reg_instance(e, api);
- if (i == NULL) {
- LOG_DBG("Instance %d is not accepting flows for %s.",
- api, name);
- return -1;
- }
-
- list_del(&i->next);
-
- reg_instance_destroy(i);
-
- if (list_empty(&e->ap_instances)) {
- if ((e->flags & BIND_AP_AUTO) &&
- !list_empty(&e->auto_ap_info))
- e->state = REG_NAME_AUTO_ACCEPT;
- else
- e->state = REG_NAME_IDLE;
- } else {
- e->state = REG_NAME_FLOW_ACCEPT;
- }
-
- return 0;
-}
-
-static pid_t registry_resolve_api(struct reg_entry * e)
-{
- struct list_head * pos = NULL;
-
- /* FIXME: now just returns the first accepting instance */
- list_for_each(pos, &e->ap_instances) {
- struct reg_instance * r =
- list_entry(pos, struct reg_instance, next);
- return r->api;
- }
-
- return 0;
-}
-
-static char ** registry_resolve_auto(struct reg_entry * e)
-{
- struct list_head * pos = NULL;
-
- /* FIXME: now just returns the first accepting instance */
- list_for_each(pos, &e->auto_ap_info) {
- struct reg_auto * r =
- list_entry(pos, struct reg_auto, next);
- return r->argv;
- }
-
- return NULL;
-}
-
-static void registry_del_name(char * name)
-{
- struct reg_entry * e = get_reg_entry_by_name(name);
- if (e == NULL)
- return;
-
- list_del(&e->next);
- reg_entry_destroy(e);
-
- return;
-}
-
static pid_t create_ipcp(char * name,
enum ipcp_type ipcp_type)
{
@@ -1080,7 +465,8 @@ static int bind_name(char * name,
pthread_rwlock_wrlock(&instance->reg_lock);
- if (registry_add_entry(strdup(name), strdup(apn), opts) < 0) {
+ if (registry_add_entry(&instance->registry,
+ strdup(name), strdup(apn), opts) < 0) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
LOG_ERR("Failed to register %s.", name);
@@ -1097,7 +483,8 @@ static int bind_name(char * name,
argv_dup[argc + 1] = NULL;
}
- registry_add_ap_auto(name, strdup(apn), argv_dup);
+ registry_add_ap_auto(&instance->registry,
+ name, strdup(apn), argv_dup);
}
pthread_rwlock_unlock(&instance->reg_lock);
@@ -1127,7 +514,7 @@ static int unbind_name(char * name,
pthread_rwlock_wrlock(&instance->reg_lock);
- rne = get_reg_entry_by_name(name);
+ rne = registry_get_entry_by_name(&instance->registry, name);
if (rne == NULL) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1139,7 +526,7 @@ static int unbind_name(char * name,
* FIXME: Remove the mapping of name to ap_name.
* Remove the name only if it was the last mapping.
*/
- registry_del_name(rne->name);
+ registry_del_name(&instance->registry, rne->name);
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1206,7 +593,7 @@ static int ap_reg(char * name,
return -1;
}
- reg = get_reg_entry_by_name(name);
+ reg = registry_get_entry_by_name(&instance->registry, name);
if (reg == NULL) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1315,7 +702,7 @@ static struct port_map_entry * flow_accept(pid_t api,
pthread_rwlock_wrlock(&instance->reg_lock);
- rne = get_reg_entry_by_ap_name(srv_ap_name);
+ rne = registry_get_entry_by_ap_name(&instance->registry, srv_ap_name);
if (rne == NULL) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1324,7 +711,8 @@ static struct port_map_entry * flow_accept(pid_t api,
}
if (!reg_entry_has_api(rne, api)) {
- rgi = registry_add_ap_instance(rne->name, api);
+ rgi = registry_add_ap_instance(&instance->registry,
+ rne->name, api);
if (rgi == NULL) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1392,7 +780,7 @@ static int flow_alloc_resp(pid_t n_api,
pthread_rwlock_wrlock(&instance->reg_lock);
- rne = get_reg_entry_by_ap_id(n_api);
+ rne = registry_get_entry_by_ap_id(&instance->registry, n_api);
if (rne == NULL) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1408,7 +796,7 @@ static int flow_alloc_resp(pid_t n_api,
pthread_mutex_lock(&rne->state_lock);
- registry_remove_ap_instance(rne->name, n_api);
+ registry_remove_ap_instance(&instance->registry, rne->name, n_api);
pthread_mutex_unlock(&rne->state_lock);
@@ -1677,7 +1065,7 @@ static struct port_map_entry * flow_req_arr(pid_t api,
pthread_rwlock_rdlock(&instance->state_lock);
pthread_rwlock_rdlock(&instance->reg_lock);
- rne = get_reg_entry_by_name(dst_name);
+ rne = registry_get_entry_by_name(&instance->registry, dst_name);
if (rne == NULL) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -1702,7 +1090,7 @@ static struct port_map_entry * flow_req_arr(pid_t api,
rne->state = REG_NAME_AUTO_EXEC;
pthread_mutex_unlock(&rne->state_lock);
- if (auto_execute(registry_resolve_auto(rne)) < 0) {
+ if (auto_execute(reg_entry_resolve_auto(rne)) < 0) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
free(pme);
@@ -1724,7 +1112,7 @@ static struct port_map_entry * flow_req_arr(pid_t api,
pthread_rwlock_rdlock(&instance->reg_lock);
case REG_NAME_FLOW_ACCEPT:
- pme->n_api = registry_resolve_api(rne);
+ pme->n_api = reg_entry_resolve_api(rne);
if (pme->n_api == 0) {
pthread_rwlock_unlock(&instance->reg_lock);
pthread_rwlock_unlock(&instance->state_lock);
@@ -2002,8 +1390,10 @@ void * irm_flow_cleaner()
LOG_INFO("Process %d gone, "
"instance deleted.",
r->api);
- registry_remove_ap_instance(e->name,
- r->api);
+ registry_remove_ap_instance(
+ &instance->registry,
+ e->name,
+ r->api);
}
}
}
diff --git a/src/irmd/registry.c b/src/irmd/registry.c
new file mode 100644
index 00000000..063309a4
--- /dev/null
+++ b/src/irmd/registry.c
@@ -0,0 +1,593 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * The IPC Resource Manager - Registry
+ *
+ * Dimitri Staessens <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "registry.h"
+
+#include <ouroboros/config.h>
+
+#define OUROBOROS_PREFIX "registry"
+
+#include <ouroboros/logs.h>
+#include <ouroboros/irm_config.h>
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+
+struct reg_instance * reg_instance_create(pid_t api)
+{
+ struct reg_instance * i;
+ i = malloc(sizeof(*i));
+ if (i == NULL)
+ return NULL;
+
+ i->api = api;
+ i->state = REG_I_WAKE;
+
+ pthread_mutex_init(&i->mutex, NULL);
+ pthread_cond_init(&i->wakeup, NULL);
+
+ INIT_LIST_HEAD(&i->next);
+
+ return i;
+}
+
+void reg_instance_destroy(struct reg_instance * i)
+{
+ bool wait = true;
+ pthread_mutex_lock(&i->mutex);
+ i->state = REG_I_NULL;
+
+ pthread_cond_broadcast(&i->wakeup);
+ pthread_mutex_unlock(&i->mutex);
+
+ while (wait) {
+ pthread_mutex_lock(&i->mutex);
+ if (pthread_cond_destroy(&i->wakeup))
+ pthread_cond_broadcast(&i->wakeup);
+ else
+ wait = false;
+ pthread_mutex_unlock(&i->mutex);
+ }
+
+ pthread_mutex_destroy(&i->mutex);
+
+ free(i);
+}
+
+void reg_instance_sleep(struct reg_instance * i)
+{
+ pthread_mutex_lock(&i->mutex);
+ if (i->state != REG_I_WAKE) {
+ pthread_mutex_unlock(&i->mutex);
+ return;
+ }
+
+ i->state = REG_I_SLEEP;
+
+ pthread_cleanup_push((void(*)(void *)) pthread_mutex_unlock,
+ (void *) &i->mutex);
+
+ while (i->state == REG_I_SLEEP)
+ pthread_cond_wait(&i->wakeup, &i->mutex);
+
+ pthread_cleanup_pop(true);
+}
+
+void reg_instance_wake(struct reg_instance * i)
+{
+ pthread_mutex_lock(&i->mutex);
+
+ if (i->state == REG_I_NULL) {
+ pthread_mutex_unlock(&i->mutex);
+ return;
+ }
+
+ i->state = REG_I_WAKE;
+
+ pthread_cond_signal(&i->wakeup);
+ pthread_mutex_unlock(&i->mutex);
+}
+
+struct reg_entry * reg_entry_create()
+{
+ struct reg_entry * e = malloc(sizeof(*e));
+ if (e == NULL)
+ return NULL;
+
+ e->name = NULL;
+ e->state = REG_NAME_NULL;
+ e->flags = 0;
+
+ e->req_ae_name = NULL;
+ e->response = -1;
+
+ return e;
+}
+
+struct reg_entry * reg_entry_init(struct reg_entry * e,
+ char * name,
+ char * ap_name,
+ uint32_t flags)
+{
+ struct reg_ap_name * n = NULL;
+
+ if (e == NULL || name == NULL || ap_name == NULL)
+ return NULL;
+
+ n = malloc(sizeof(*n));
+ if (n == NULL)
+ return NULL;
+
+ INIT_LIST_HEAD(&e->next);
+ INIT_LIST_HEAD(&e->ap_names);
+ INIT_LIST_HEAD(&e->auto_ap_info);
+ INIT_LIST_HEAD(&e->ap_instances);
+
+ e->name = name;
+ e->flags = flags;
+ n->ap_name = ap_name;
+
+ list_add(&n->next, &e->ap_names);
+
+ if (pthread_cond_init(&e->acc_signal, NULL)) {
+ free(e);
+ return NULL;
+ }
+
+ if (pthread_mutex_init(&e->state_lock, NULL)) {
+ free(e);
+ return NULL;
+ }
+
+ e->state = REG_NAME_IDLE;
+
+ return e;
+}
+
+void reg_entry_destroy(struct reg_entry * e)
+{
+ struct list_head * pos = NULL;
+ struct list_head * n = NULL;
+
+ bool wait = true;
+
+ if (e == NULL)
+ return;
+
+ pthread_mutex_lock(&e->state_lock);
+
+ e->state = REG_NAME_NULL;
+
+ pthread_cond_broadcast(&e->acc_signal);
+ pthread_mutex_unlock(&e->state_lock);
+
+ while (wait) {
+ pthread_mutex_lock(&e->state_lock);
+ if (pthread_cond_destroy(&e->acc_signal))
+ pthread_cond_broadcast(&e->acc_signal);
+ else
+ wait = false;
+ pthread_mutex_unlock(&e->state_lock);
+ }
+
+ pthread_mutex_destroy(&e->state_lock);
+
+ if (e->name != NULL)
+ free(e->name);
+
+ if (e->req_ae_name != NULL)
+ free(e->req_ae_name);
+
+ list_for_each_safe(pos, n, &e->ap_instances) {
+ struct reg_instance * i =
+ list_entry(pos, struct reg_instance, next);
+ reg_instance_destroy(i);
+ }
+
+ list_for_each_safe(pos, n, &e->auto_ap_info) {
+ struct reg_auto * a =
+ list_entry(pos, struct reg_auto, next);
+
+ if (a->argv != NULL) {
+ char ** t = a->argv;
+ while (*a->argv != NULL)
+ free(*(a->argv++));
+ free(t);
+ }
+
+ free(a->ap_name);
+ free(a);
+ }
+
+ list_for_each_safe(pos, n, &e->ap_names) {
+ struct reg_ap_name * n =
+ list_entry(pos, struct reg_ap_name, next);
+
+ free(n->ap_name);
+ free(n);
+ }
+
+ free(e);
+}
+
+struct reg_ap_name * reg_entry_get_ap_name(struct reg_entry * e,
+ char * ap_name)
+{
+ struct list_head * pos = NULL;
+
+ list_for_each(pos, &e->ap_names) {
+ struct reg_ap_name * n =
+ list_entry(pos, struct reg_ap_name, next);
+
+ if (strcmp(ap_name, n->ap_name) == 0)
+ return n;
+ }
+
+ return NULL;
+}
+
+struct reg_instance * reg_entry_get_reg_instance(struct reg_entry * e,
+ pid_t api)
+{
+ struct list_head * pos = NULL;
+
+ list_for_each(pos, &e->ap_instances) {
+ struct reg_instance * r =
+ list_entry(pos, struct reg_instance, next);
+
+ if (r->api == api)
+ return r;
+ }
+
+ return NULL;
+}
+
+struct reg_auto * reg_entry_get_reg_auto(struct reg_entry * e,
+ char * ap_name)
+{
+ struct list_head * pos = NULL;
+
+ list_for_each(pos, &e->auto_ap_info) {
+ struct reg_auto * a =
+ list_entry(pos, struct reg_auto, next);
+
+ if (strcmp(ap_name, a->ap_name) == 0)
+ return a;
+ }
+
+ return NULL;
+}
+
+pid_t reg_entry_resolve_api(struct reg_entry * e)
+{
+ struct list_head * pos = NULL;
+
+ /* FIXME: now just returns the first accepting instance */
+ list_for_each(pos, &e->ap_instances) {
+ struct reg_instance * r =
+ list_entry(pos, struct reg_instance, next);
+ return r->api;
+ }
+
+ return 0;
+}
+
+char ** reg_entry_resolve_auto(struct reg_entry * e)
+{
+ struct list_head * pos = NULL;
+
+ /* FIXME: now just returns the first accepting instance */
+ list_for_each(pos, &e->auto_ap_info) {
+ struct reg_auto * r =
+ list_entry(pos, struct reg_auto, next);
+ return r->argv;
+ }
+
+ return NULL;
+}
+
+struct reg_entry * registry_get_entry_by_name(struct list_head * registry,
+ char * name)
+{
+ struct list_head * pos = NULL;
+
+ list_for_each(pos, registry) {
+ struct reg_entry * e =
+ list_entry(pos, struct reg_entry, next);
+
+ if (strcmp(name, e->name) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
+struct reg_entry * registry_get_entry_by_ap_name(struct list_head * registry,
+ char * ap_name)
+{
+ struct list_head * pos = NULL;
+
+ list_for_each(pos, registry) {
+ struct list_head * p = NULL;
+ struct reg_entry * e =
+ list_entry(pos, struct reg_entry, next);
+
+ list_for_each(p, &e->ap_names) {
+ struct reg_ap_name * n =
+ list_entry(p, struct reg_ap_name, next);
+
+ if (strcmp(n->ap_name, ap_name) == 0)
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+struct reg_entry * registry_get_entry_by_ap_id(struct list_head * registry,
+ pid_t api)
+{
+ struct list_head * pos = NULL;
+
+ list_for_each(pos, registry) {
+ struct list_head * p = NULL;
+ struct reg_entry * e =
+ list_entry(pos, struct reg_entry, next);
+
+ list_for_each(p, &e->ap_instances) {
+ struct reg_instance * r =
+ list_entry(p, struct reg_instance, next);
+
+ if (r->api == api)
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+int registry_add_entry(struct list_head * registry,
+ char * name,
+ char * ap_name,
+ uint16_t flags)
+{
+ struct reg_entry * e = NULL;
+
+ if (name == NULL || ap_name == NULL)
+ return -EINVAL;
+
+ e = registry_get_entry_by_name(registry, name);
+ if (e != NULL) {
+ LOG_DBG("Name %s already registered.", name);
+ return -1;
+ }
+
+ e = reg_entry_create();
+ if (e == NULL) {
+ LOG_DBG("Could not create registry entry.");
+ return -1;
+ }
+
+ e = reg_entry_init(e, name, ap_name, flags);
+ if (e == NULL) {
+ LOG_DBG("Could not initialize registry entry.");
+ reg_entry_destroy(e);
+ return -1;
+ }
+
+ list_add(&e->next, registry);
+
+ return 0;
+}
+
+int registry_add_ap_auto(struct list_head * registry,
+ char * name,
+ char * ap_name,
+ char ** argv)
+{
+ struct reg_entry * e;
+ struct reg_auto * a;
+
+ if (name == NULL || ap_name == NULL)
+ return -EINVAL;
+
+ e = registry_get_entry_by_name(registry, name);
+ if (e == NULL) {
+ LOG_DBG("Name %s not found in registry.", name);
+ return -1;
+ }
+
+ if (!(e->flags & BIND_AP_AUTO)) {
+ LOG_DBG("%s does not allow auto-instantiation.", name);
+ return -1;
+ }
+
+ if (!reg_entry_has_ap_name(e, ap_name)) {
+ LOG_DBG("AP name %s not associated with %s.", ap_name, name);
+ return -1;
+ }
+
+ if (e->state == REG_NAME_NULL) {
+ LOG_DBG("Tried to add instantiation info in NULL state.");
+ return -1;
+ }
+
+ a = reg_entry_get_reg_auto(e, ap_name);
+ if (a != NULL) {
+ LOG_DBG("Updating auto-instantiation info for %s.", ap_name);
+ list_del(&a->next);
+ free(a->ap_name);
+ if (a->argv != NULL) {
+ while (*a->argv != NULL)
+ free(*a->argv++);
+ }
+ } else {
+ a = malloc(sizeof(*a));
+ if (a == NULL)
+ return -1;
+ }
+
+ a->ap_name = ap_name;
+ a->argv = argv;
+
+ if (e->state == REG_NAME_IDLE)
+ e->state = REG_NAME_AUTO_ACCEPT;
+
+ list_add(&a->next, &e->auto_ap_info);
+
+ return 0;
+}
+
+
+int registry_remove_ap_auto(struct list_head * registry,
+ char * name,
+ char * ap_name)
+{
+ struct reg_entry * e;
+ struct reg_auto * a;
+
+ if (name == NULL || ap_name == NULL)
+ return -EINVAL;
+
+ e = registry_get_entry_by_name(registry, name);
+ if (e == NULL) {
+ LOG_DBG("Name %s not found in registry.", name);
+ return -1;
+ }
+
+ a = reg_entry_get_reg_auto(e, ap_name);
+ if (a == NULL) {
+ LOG_DBG("Auto-instantiation info for %s not found.", ap_name);
+ return -1;
+ }
+
+ list_del(&a->next);
+
+ if (e->state == REG_NAME_AUTO_ACCEPT && list_empty(&e->auto_ap_info))
+ e->state = REG_NAME_IDLE;
+
+ return 0;
+}
+
+
+struct reg_instance * registry_add_ap_instance(struct list_head * registry,
+ char * name,
+ pid_t api)
+{
+ struct reg_entry * e = NULL;
+ struct reg_instance * i = NULL;
+
+ if (name == NULL || api == 0)
+ return NULL;
+
+ e = registry_get_entry_by_name(registry, name);
+ if (e == NULL) {
+ LOG_DBG("Name %s not found in registry.", name);
+ return NULL;
+ }
+
+ if (api == 0) {
+ LOG_DBG("Invalid api.");
+ return NULL;
+ }
+
+ if (reg_entry_has_api(e, api)) {
+ LOG_DBG("Instance already registered with this name.");
+ return NULL;
+ }
+
+ if (e->state == REG_NAME_NULL) {
+ LOG_DBG("Tried to add instance in NULL state.");
+ return NULL;
+ }
+
+ i = reg_instance_create(api);
+ if (i == NULL) {
+ LOG_DBG("Failed to create reg_instance");
+ return NULL;
+ }
+
+ if (e->state == REG_NAME_IDLE || e->state == REG_NAME_AUTO_ACCEPT
+ || e->state == REG_NAME_AUTO_EXEC) {
+ e->state = REG_NAME_FLOW_ACCEPT;
+ pthread_cond_signal(&e->acc_signal);
+ }
+
+ list_add(&i->next, &e->ap_instances);
+
+ return i;
+}
+
+int registry_remove_ap_instance(struct list_head * registry,
+ char * name,
+ pid_t api)
+{
+ struct reg_entry * e = NULL;
+ struct reg_instance * i = NULL;
+
+ if (name == NULL || api == 0)
+ return -1;
+
+ e = registry_get_entry_by_name(registry, name);
+ if (e == NULL) {
+ LOG_DBG("Name %s is not registered.", name);
+ return -1;
+ }
+
+ i = reg_entry_get_reg_instance(e, api);
+ if (i == NULL) {
+ LOG_DBG("Instance %d is not accepting flows for %s.",
+ api, name);
+ return -1;
+ }
+
+ list_del(&i->next);
+
+ reg_instance_destroy(i);
+
+ if (list_empty(&e->ap_instances)) {
+ if ((e->flags & BIND_AP_AUTO) &&
+ !list_empty(&e->auto_ap_info))
+ e->state = REG_NAME_AUTO_ACCEPT;
+ else
+ e->state = REG_NAME_IDLE;
+ } else {
+ e->state = REG_NAME_FLOW_ACCEPT;
+ }
+
+ return 0;
+}
+
+void registry_del_name(struct list_head * registry,
+ char * name)
+{
+ struct reg_entry * e = registry_get_entry_by_name(registry, name);
+ if (e == NULL)
+ return;
+
+ list_del(&e->next);
+ reg_entry_destroy(e);
+
+ return;
+}
diff --git a/src/irmd/registry.h b/src/irmd/registry.h
new file mode 100644
index 00000000..36b68dcd
--- /dev/null
+++ b/src/irmd/registry.h
@@ -0,0 +1,148 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * The IPC Resource Manager - Registry
+ *
+ * Dimitri Staessens <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef OUROBOROS_IRMD_REGISTRY_H
+#define OUROBOROS_IRMD_REGISTRY_H
+
+#include <ouroboros/list.h>
+
+#include <stdint.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#define reg_entry_has_api(e, id) (reg_entry_get_reg_instance(e, id) != NULL)
+#define reg_entry_has_ap_name(e, name) (reg_entry_get_ap_name(e, name) != NULL)
+#define reg_entry_has_ap_auto(e, name) (reg_entry_get_reg_auto(e, name) != NULL)
+
+enum reg_name_state {
+ REG_NAME_NULL = 0,
+ REG_NAME_IDLE,
+ REG_NAME_AUTO_ACCEPT,
+ REG_NAME_AUTO_EXEC,
+ REG_NAME_FLOW_ACCEPT,
+ REG_NAME_FLOW_ARRIVED
+};
+
+enum reg_i_state {
+ REG_I_NULL = 0,
+ REG_I_SLEEP,
+ REG_I_WAKE
+};
+
+struct reg_instance {
+ struct list_head next;
+ pid_t api;
+
+ /* the api will block on this */
+ enum reg_i_state state;
+ pthread_cond_t wakeup;
+ pthread_mutex_t mutex;
+};
+
+/* an entry in the registry */
+struct reg_entry {
+ struct list_head next;
+
+ /* generic name */
+ char * name;
+
+ /* names of the aps that can listen to this name */
+ struct list_head ap_names;
+
+ enum reg_name_state state;
+
+ uint32_t flags;
+
+ /* auto execution info */
+ struct list_head auto_ap_info;
+
+ /* known instances */
+ struct list_head ap_instances;
+
+ char * req_ae_name;
+ int response;
+
+ pthread_cond_t acc_signal;
+ pthread_mutex_t state_lock;
+};
+
+struct reg_auto {
+ struct list_head next;
+ char * ap_name;
+ char ** argv;
+};
+
+struct reg_ap_name {
+ struct list_head next;
+ char * ap_name;
+};
+
+struct reg_instance * reg_instance_create(pid_t api);
+void reg_instance_destroy(struct reg_instance * i);
+
+void reg_instance_sleep(struct reg_instance * i);
+void reg_instance_wake(struct reg_instance * i);
+
+struct reg_entry * reg_entry_create();
+struct reg_entry * reg_entry_init(struct reg_entry * e,
+ char * name,
+ char * ap_name,
+ uint32_t flags);
+void reg_entry_destroy(struct reg_entry * e);
+
+struct reg_ap_name * reg_entry_get_ap_name(struct reg_entry * e,
+ char * ap_name);
+struct reg_instance * reg_entry_get_reg_instance(struct reg_entry * e,
+ pid_t api);
+
+struct reg_auto * reg_entry_get_reg_auto(struct reg_entry * e,
+ char * ap_name);
+pid_t reg_entry_resolve_api(struct reg_entry * e);
+char ** reg_entry_resolve_auto(struct reg_entry * e);
+
+int registry_add_entry(struct list_head * registry,
+ char * name,
+ char * ap_name,
+ uint16_t flags);
+int registry_add_ap_auto(struct list_head * registry,
+ char * name,
+ char * ap_name,
+ char ** argv);
+int registry_remove_ap_auto(struct list_head * registry,
+ char * name,
+ char * ap_name);
+struct reg_instance * registry_add_ap_instance(struct list_head * registry,
+ char * name,
+ pid_t api);
+int registry_remove_ap_instance(struct list_head * registry,
+ char * name,
+ pid_t api);
+struct reg_entry * registry_get_entry_by_name(struct list_head * registry,
+ char * name);
+struct reg_entry * registry_get_entry_by_ap_name(struct list_head * registry,
+ char * ap_name);
+struct reg_entry * registry_get_entry_by_ap_id(struct list_head * registry,
+ pid_t api);
+void registry_del_name(struct list_head * registry,
+ char * name);
+
+#endif