/* * Ouroboros - Copyright (C) 2016 - 2024 * * The IPC Resource Manager - Registry - Names * * Dimitri Staessens * Sander Vrijders * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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., http://www.fsf.org/about/contact/. */ #define _POSIX_C_SOURCE 200809L #define OUROBOROS_PREFIX "reg/name" #include #include #include "name.h" #include #include #include #include struct prog_entry { struct list_head next; char ** exec; }; struct proc_entry { struct list_head next; pid_t pid; }; static void __free_prog_entry(struct prog_entry * entry) { assert(entry != NULL); assert(entry->exec != NULL); argvfree(entry->exec); free(entry); } struct reg_name * reg_name_create(const struct name_info * info) { struct reg_name * name; assert(info != NULL); name = malloc(sizeof(*name)); if (name == NULL) { log_err("Failed to malloc name."); goto fail_malloc; } list_head_init(&name->next); list_head_init(&name->progs); list_head_init(&name->procs); list_head_init(&name->active); name->info = *info; name->n_progs = 0; name->n_procs = 0; name->n_active = 0; return name; fail_malloc: return NULL; } void reg_name_destroy(struct reg_name * name) { assert(name != NULL); assert(list_is_empty(&name->next)); assert(name->n_progs == 0); assert(name->n_procs == 0); assert(name->n_active == 0); assert(list_is_empty(&name->progs)); assert(list_is_empty(&name->procs)); assert(list_is_empty(&name->active)); free(name); } static struct proc_entry * __reg_name_get_active(const struct reg_name * name, pid_t pid) { struct list_head * p; assert(name != NULL); assert(pid > 0); list_for_each(p, &name->active) { struct proc_entry * entry; entry = list_entry(p, struct proc_entry, next); if (entry->pid == pid) return entry; } return NULL; } 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->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--; } } } static struct proc_entry * __reg_name_get_proc(const struct reg_name * name, pid_t pid) { struct list_head * p; assert(name != NULL); assert(pid > 0); 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 struct prog_entry * __reg_name_get_prog(const struct reg_name * name, const char * prog) { struct list_head * p; 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 NULL; } int reg_name_add_active(struct reg_name * name, pid_t pid) { struct proc_entry * entry; assert(name != NULL); assert(pid > 0); assert(__reg_name_get_proc(name, pid) != NULL); log_dbg("Process %d accepting flows for %s.", pid, name->info.name); if (__reg_name_get_active(name, pid) != NULL) log_dbg("Process calling accept from multiple threads."); entry = malloc(sizeof(*entry)); if (entry == NULL) { log_err("Failed to malloc active."); goto fail_malloc; } entry->pid = pid; switch (name->info.pol_lb) { case LB_RR: /* Round robin policy. */ list_add_tail(&entry->next, &name->active); break; case LB_SPILL: /* Keep accepting flows on the current process */ list_add(&entry->next, &name->active); break; default: goto fail_unreachable; } name->n_active++; return 0; fail_unreachable: free(entry); assert(false); fail_malloc: return -1; } void reg_name_del_active(struct reg_name * name, pid_t pid) { struct proc_entry * entry; entry = __reg_name_get_active(name, pid); if (entry == NULL) return; list_del(&entry->next); name->n_active--; free(entry); } pid_t reg_name_get_active(struct reg_name * name) { assert(name != NULL); if (list_is_empty(&name->active)) return -1; return list_first_entry(&name->active, struct proc_entry, next)->pid; } int reg_name_add_proc(struct reg_name * name, pid_t pid) { struct proc_entry * entry; assert(name != NULL); assert(pid > 0); assert(__reg_name_get_proc(name, pid) == NULL); entry = malloc(sizeof(*entry)); if (entry == NULL) { log_err("Failed to malloc proc."); goto fail_malloc; } entry->pid = pid; list_add(&entry->next, &name->procs); name->n_procs++; return 0; fail_malloc: return -1; } void reg_name_del_proc(struct reg_name * name, pid_t pid) { struct proc_entry * entry; assert(name != NULL); assert(pid > 0); entry = __reg_name_get_proc(name, pid); if (entry == NULL) return; __reg_name_del_all_active(name, pid); list_del(&entry->next); free(entry); name->n_procs--; assert(__reg_name_get_proc(name, pid) == NULL); } 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) { 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; } list_add(&entry->next, &name->progs); log_dbg("Add prog %s to name %s.", exec[0], name->info.name); name->n_progs++; return 0; fail_exec: free(entry); fail_malloc: return -1; } void reg_name_del_prog(struct reg_name * name, const char * prog) { struct prog_entry * entry; assert(name != NULL); assert(prog != NULL); entry = __reg_name_get_prog(name, prog); if (entry == NULL) return; list_del(&entry->next); __free_prog_entry(entry); name->n_progs--; assert(__reg_name_get_prog(name, prog) == NULL); } 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 list_first_entry(&name->progs, struct prog_entry, next)->exec; }