diff options
Diffstat (limited to 'src/irmd/reg/name.c')
-rw-r--r-- | src/irmd/reg/name.c | 516 |
1 files changed, 222 insertions, 294 deletions
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c index db9842d1..1ac939a5 100644 --- a/src/irmd/reg/name.c +++ b/src/irmd/reg/name.c @@ -1,3 +1,4 @@ + /* * Ouroboros - Copyright (C) 2016 - 2024 * @@ -20,428 +21,355 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else #define _POSIX_C_SOURCE 200809L -#endif - -#include "config.h" -#define OUROBOROS_PREFIX "reg_name" +#define OUROBOROS_PREFIX "reg/name" -#include <ouroboros/errno.h> #include <ouroboros/logs.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/pthread.h> +#include <ouroboros/utils.h> #include "name.h" -#include "utils.h" +#include <assert.h> +#include <errno.h> #include <stdlib.h> -#include <stdbool.h> #include <string.h> -#include <signal.h> -#include <unistd.h> -#include <limits.h> -#include <assert.h> - -struct reg_name * reg_name_create(const char * name, - enum pol_balance lb) -{ - pthread_condattr_t cattr; - struct reg_name * n; - - assert(name != NULL); - n = malloc(sizeof(*n)); - if (n == NULL) - goto fail_malloc; - - if (pthread_condattr_init(&cattr)) - goto fail_cattr; - -#ifndef __APPLE__ - pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK); -#endif - if (pthread_cond_init(&n->cond, &cattr)) - goto fail_cond; - - if (pthread_mutex_init(&n->mtx, NULL)) - goto fail_mutex; +struct prog_entry { + struct list_head next; + char ** exec; +}; - n->name = strdup(name); - if (n->name == NULL) - goto fail_name; +struct proc_entry { + struct list_head next; + pid_t pid; +}; - pthread_condattr_destroy(&cattr); - - list_head_init(&n->next); - list_head_init(&n->reg_progs); - list_head_init(&n->reg_pids); - - n->pol_lb = lb; - n->state = NAME_IDLE; - - return n; +static void __free_prog_entry(struct prog_entry * entry) +{ + assert(entry != NULL); + assert(entry->exec != NULL); - fail_name: - pthread_mutex_destroy(&n->mtx); - fail_mutex: - pthread_cond_destroy(&n->cond); - fail_cond: - pthread_condattr_destroy(&cattr); - fail_cattr: - free(n); - fail_malloc: - return NULL; + argvfree(entry->exec); + free(entry); } -static void cancel_reg_name_destroy(void * o) +struct reg_name * reg_name_create(const struct name_info * info) { struct reg_name * name; - struct list_head * p; - struct list_head * h; - name = (struct reg_name *) o; + assert(info != NULL); - pthread_mutex_unlock(&name->mtx); - - pthread_cond_destroy(&name->cond); - pthread_mutex_destroy(&name->mtx); + name = malloc(sizeof(*name)); + if (name == NULL) { + log_err("Failed to malloc name."); + goto fail_malloc; + } - if (name->name != NULL) - free(name->name); + list_head_init(&name->next); + list_head_init(&name->progs); + list_head_init(&name->procs); + list_head_init(&name->active); - list_for_each_safe(p, h, &name->reg_pids) { - struct pid_el * pe = list_entry(p, struct pid_el, next); - list_del(&pe->next); - free(pe); - } + name->info = *info; + name->n_progs = 0; + name->n_procs = 0; + name->n_active = 0; - list_for_each_safe(p, h, &name->reg_progs) { - struct str_el * se = list_entry(p, struct str_el, next); - list_del(&se->next); - free(se->str); - free(se); - } + return name; - free(name); + fail_malloc: + return NULL; } void reg_name_destroy(struct reg_name * name) { - if (name == NULL) - return; - - pthread_mutex_lock(&name->mtx); - - if (name->state == NAME_DESTROY) { - pthread_mutex_unlock(&name->mtx); - return; - } - - if (name->state != NAME_FLOW_ACCEPT) - name->state = NAME_NULL; - else - name->state = NAME_DESTROY; + assert(name != NULL); - pthread_cond_broadcast(&name->cond); + assert(list_is_empty(&name->next)); - pthread_cleanup_push(cancel_reg_name_destroy, name); + assert(name->n_progs == 0); + assert(name->n_procs == 0); + assert(name->n_active == 0); - while (name->state != NAME_NULL) - pthread_cond_wait(&name->cond, &name->mtx); + assert(list_is_empty(&name->progs)); + assert(list_is_empty(&name->procs)); + assert(list_is_empty(&name->active)); - pthread_cleanup_pop(true); + free(name); } -static bool reg_name_has_prog(struct reg_name * name, - const char * prog) +static struct proc_entry * __reg_name_get_active(const struct reg_name * name, + pid_t pid) { struct list_head * p; - list_for_each(p, &name->reg_progs) { - struct str_el * name = list_entry(p, struct str_el, next); - if (!strcmp(name->str, prog)) - return true; - } - - return false; -} - -int reg_name_add_prog(struct reg_name * name, - struct reg_prog * a) -{ - struct str_el * n; - - if (reg_name_has_prog(name, a->prog)) { - log_warn("Program %s already accepting flows for %s.", - a->prog, name->name); - return 0; - } - - if (!(a->flags & BIND_AUTO)) { - log_dbg("Program %s cannot be auto-instantiated.", a->prog); - return 0; - } - - n = malloc(sizeof(*n)); - if (n == NULL) - return -ENOMEM; + assert(name != NULL); + assert(pid > 0); - n->str = strdup(a->prog); - if (n->str == NULL) { - free(n); - return -ENOMEM; + list_for_each(p, &name->active) { + struct proc_entry * entry; + entry = list_entry(p, struct proc_entry, next); + if (entry->pid == pid) + return entry; } - list_add(&n->next, &name->reg_progs); - - pthread_mutex_lock(&name->mtx); - - if (name->state == NAME_IDLE) - name->state = NAME_AUTO_ACCEPT; - - pthread_mutex_unlock(&name->mtx); - - return 0; + return NULL; } -void reg_name_del_prog(struct reg_name * name, - const char * prog) +static void __reg_name_del_all_active(struct reg_name * name, + pid_t pid) { struct list_head * p; struct list_head * h; - list_for_each_safe(p, h, &name->reg_progs) { - struct str_el * se = list_entry(p, struct str_el, next); - if (strcmp(prog, se->str) == 0) { - list_del(&se->next); - free(se->str); - free(se); + list_for_each_safe(p, h, &name->active) { + struct proc_entry * entry; + entry = list_entry(p, struct proc_entry, next); + if (entry->pid == pid) { + list_del(&entry->next); + free(entry); + name->n_active--; } } - - pthread_mutex_lock(&name->mtx); - - if (name->state == NAME_AUTO_ACCEPT && list_is_empty(&name->reg_progs)) { - name->state = NAME_IDLE; - pthread_cond_broadcast(&name->cond); - } - - pthread_mutex_unlock(&name->mtx); } -char * reg_name_get_prog(struct reg_name * name) +static struct proc_entry * __reg_name_get_proc(const struct reg_name * name, + pid_t pid) { - if (!list_is_empty(&name->reg_pids) || list_is_empty(&name->reg_progs)) - return NULL; + struct list_head * p; + + assert(name != NULL); + assert(pid > 0); - return list_first_entry(&name->reg_progs, struct str_el, next)->str; + list_for_each(p, &name->procs) { + struct proc_entry * entry; + entry = list_entry(p, struct proc_entry, next); + if (entry->pid == pid) + return entry; + } + + return NULL; } -static bool reg_name_has_pid(struct reg_name * name, - pid_t pid) +static struct prog_entry * __reg_name_get_prog(const struct reg_name * name, + const char * prog) { struct list_head * p; - list_for_each(p, &name->reg_progs) { - struct pid_el * name = list_entry(p, struct pid_el, next); - if (name->pid == pid) - return true; + assert(name != NULL); + assert(prog != NULL); + + list_for_each(p, &name->progs) { + struct prog_entry * entry; + entry = list_entry(p, struct prog_entry, next); + if (strcmp(entry->exec[0], prog) == 0) + return entry; } - return false; + return NULL; } -int reg_name_add_pid(struct reg_name * name, - pid_t pid) +int reg_name_add_active(struct reg_name * name, + pid_t pid) { - struct pid_el * i; + struct proc_entry * entry; - assert(name); + assert(name != NULL); + assert(pid > 0); - if (reg_name_has_pid(name, pid)) { - log_dbg("Process already registered with this name."); - return -EPERM; - } + assert(__reg_name_get_proc(name, pid) != NULL); - pthread_mutex_lock(&name->mtx); + log_dbg("Process %d accepting flows for %s.", pid, name->info.name); - if (name->state == NAME_NULL) { - pthread_mutex_unlock(&name->mtx); - log_dbg("Tried to add instance in NULL state."); - return -EPERM; - } + if (__reg_name_get_active(name, pid) != NULL) + log_dbg("Process calling accept from multiple threads."); - i = malloc(sizeof(*i)); - if (i == NULL) { - pthread_mutex_unlock(&name->mtx); - return -ENOMEM; + entry = malloc(sizeof(*entry)); + if (entry == NULL) { + log_err("Failed to malloc active."); + goto fail_malloc; } - i->pid = pid; + entry->pid = pid; - /* load balancing policy assigns queue order for this process. */ - switch(name->pol_lb) { + switch (name->info.pol_lb) { case LB_RR: /* Round robin policy. */ - list_add_tail(&i->next, &name->reg_pids); + list_add_tail(&entry->next, &name->active); break; case LB_SPILL: /* Keep accepting flows on the current process */ - list_add(&i->next, &name->reg_pids); + list_add(&entry->next, &name->active); break; default: - free(i); - assert(false); - }; - - if (name->state == NAME_IDLE || - name->state == NAME_AUTO_ACCEPT || - name->state == NAME_AUTO_EXEC) { - name->state = NAME_FLOW_ACCEPT; - pthread_cond_broadcast(&name->cond); + goto fail_unreachable; } - pthread_mutex_unlock(&name->mtx); + name->n_active++; return 0; -} -void reg_name_set_policy(struct reg_name * name, - enum pol_balance lb) -{ - name->pol_lb = lb; + fail_unreachable: + free(entry); + assert(false); + fail_malloc: + return -1; } -static void reg_name_check_state(struct reg_name * name) +void reg_name_del_active(struct reg_name * name, + pid_t pid) { - assert(name); + struct proc_entry * entry; - if (name->state == NAME_DESTROY) { - name->state = NAME_NULL; - pthread_cond_broadcast(&name->cond); + entry = __reg_name_get_active(name, pid); + if (entry == NULL) return; - } - if (list_is_empty(&name->reg_pids)) { - if (!list_is_empty(&name->reg_progs)) - name->state = NAME_AUTO_ACCEPT; - else - name->state = NAME_IDLE; - } else { - name->state = NAME_FLOW_ACCEPT; - } + list_del(&entry->next); + + name->n_active--; - pthread_cond_broadcast(&name->cond); + free(entry); } -void reg_name_del_pid_el(struct reg_name * name, - struct pid_el * p) +pid_t reg_name_get_active(struct reg_name * name) { - assert(name); - assert(p); + assert(name != NULL); - list_del(&p->next); - free(p); + if (list_is_empty(&name->active)) + return -1; - reg_name_check_state(name); + return list_first_entry(&name->active, struct proc_entry, next)->pid; } -void reg_name_del_pid(struct reg_name * name, +int reg_name_add_proc(struct reg_name * name, pid_t pid) { - struct list_head * p; - struct list_head * h; + struct proc_entry * entry; - assert(name); + assert(name != NULL); + assert(pid > 0); - if (name == NULL) - return; + assert(__reg_name_get_proc(name, pid) == NULL); - list_for_each_safe(p, h, &name->reg_pids) { - struct pid_el * a = list_entry(p, struct pid_el, next); - if (a->pid == pid) { - list_del(&a->next); - free(a); - } + entry = malloc(sizeof(*entry)); + if (entry == NULL) { + log_err("Failed to malloc proc."); + goto fail_malloc; } - reg_name_check_state(name); -} + entry->pid = pid; -pid_t reg_name_get_pid(struct reg_name * name) -{ - if (name == NULL) - return -1; + list_add(&entry->next, &name->procs); - if (list_is_empty(&name->reg_pids)) - return -1; + name->n_procs++; - return list_first_entry(&name->reg_pids, struct pid_el, next)->pid; + return 0; + + fail_malloc: + return -1; } -enum name_state reg_name_get_state(struct reg_name * name) +void reg_name_del_proc(struct reg_name * name, + pid_t pid) { - enum name_state state; + struct proc_entry * entry; - assert(name); + assert(name != NULL); + assert(pid > 0); - pthread_mutex_lock(&name->mtx); + entry = __reg_name_get_proc(name, pid); + if (entry == NULL) + return; + + __reg_name_del_all_active(name, pid); - state = name->state; + list_del(&entry->next); - pthread_mutex_unlock(&name->mtx); + free(entry); - return state; + name->n_procs--; + + assert(__reg_name_get_proc(name, pid) == NULL); } -int reg_name_set_state(struct reg_name * name, - enum name_state state) +bool reg_name_has_proc(const struct reg_name * name, + pid_t pid) +{ + return __reg_name_get_proc(name, pid) != NULL; +} char ** exec; + + +int reg_name_add_prog(struct reg_name * name, + char ** exec) { - assert(state != NAME_DESTROY); + struct prog_entry * entry; + + assert(name != NULL); + assert(exec != NULL); + assert(exec[0] != NULL); + + assert(__reg_name_get_prog(name, exec[0]) == NULL); + + entry = malloc(sizeof(*entry)); + if (entry == NULL) { + log_err("Failed to malloc prog."); + goto fail_malloc; + } + + entry->exec = argvdup(exec); + if (entry->exec == NULL) { + log_err("Failed to argvdup prog."); + goto fail_exec; + } - pthread_mutex_lock(&name->mtx); + list_add(&entry->next, &name->progs); - name->state = state; - pthread_cond_broadcast(&name->cond); + log_dbg("Add prog %s to name %s.", exec[0], name->info.name); - pthread_mutex_unlock(&name->mtx); + name->n_progs++; return 0; + + fail_exec: + free(entry); + fail_malloc: + return -1; } -int reg_name_leave_state(struct reg_name * name, - enum name_state state, - struct timespec * timeout) +void reg_name_del_prog(struct reg_name * name, + const char * prog) { - struct timespec ts; - struct timespec * abstime = NULL; - int ret = 0; + struct prog_entry * entry; - assert(name); - assert(state != NAME_DESTROY); + assert(name != NULL); + assert(prog != NULL); - if (timeout != NULL) { - clock_gettime(PTHREAD_COND_CLOCK, &ts); - ts_add(&ts, timeout, &ts); - abstime = &ts; - } + entry = __reg_name_get_prog(name, prog); + if (entry == NULL) + return; - pthread_mutex_lock(&name->mtx); + list_del(&entry->next); - pthread_cleanup_push(__cleanup_mutex_unlock, &name->mtx); + __free_prog_entry(entry); - while (name->state == state && ret != -ETIMEDOUT) - ret = -__timedwait(&name->cond,&name->mtx, abstime); + name->n_progs--; - if (name->state == NAME_DESTROY) { - ret = -1; - name->state = NAME_NULL; - pthread_cond_broadcast(&name->cond); - } + assert(__reg_name_get_prog(name, prog) == NULL); +} - pthread_cleanup_pop(true); +bool reg_name_has_prog(const struct reg_name * name, + const char * prog) +{ + assert(name != NULL); + assert(prog != NULL); + + return __reg_name_get_prog(name, prog) != NULL; +} + +char ** reg_name_get_exec(const struct reg_name * name) +{ + if (list_is_empty(&name->progs)) + return NULL; - return ret; + return list_first_entry(&name->progs, struct prog_entry, next)->exec; } |