diff options
author | Dimitri Staessens <[email protected]> | 2021-03-26 20:47:25 +0100 |
---|---|---|
committer | Sander Vrijders <[email protected]> | 2021-03-28 12:46:32 +0200 |
commit | 809e4d1957daa701a3390b0526b125cc263bfe26 (patch) | |
tree | 207564cc3fd5d3218624cfa114a92fd9b152fd37 /src | |
parent | 994465e34a732db3bce542ee021674473f32d572 (diff) | |
download | ouroboros-809e4d1957daa701a3390b0526b125cc263bfe26.tar.gz ouroboros-809e4d1957daa701a3390b0526b125cc263bfe26.zip |
build: Move connmgr and enrolment to common ground
The connection manager and enrolment components of the unicast and
broadcast IPCP have a lot in common, as conjectured in the paper. The
initial implementation of the broadcast IPCP just duplicated the
code. This moves the shared functionality to common ground.
Signed-off-by: Dimitri Staessens <[email protected]>
Signed-off-by: Sander Vrijders <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/ipcpd/broadcast/comp.h | 45 | ||||
-rw-r--r-- | src/ipcpd/broadcast/connmgr.c | 490 | ||||
-rw-r--r-- | src/ipcpd/broadcast/connmgr.h | 71 | ||||
-rw-r--r-- | src/ipcpd/broadcast/dt.c | 4 | ||||
-rw-r--r-- | src/ipcpd/broadcast/enroll.c | 343 | ||||
-rw-r--r-- | src/ipcpd/broadcast/enroll.h | 47 | ||||
-rw-r--r-- | src/ipcpd/broadcast/main.c | 7 | ||||
-rw-r--r-- | src/ipcpd/common/comp.h (renamed from src/ipcpd/unicast/comp.h) | 10 | ||||
-rw-r--r-- | src/ipcpd/common/connmgr.c | 518 | ||||
-rw-r--r-- | src/ipcpd/common/connmgr.h (renamed from src/ipcpd/unicast/connmgr.h) | 6 | ||||
-rw-r--r-- | src/ipcpd/common/enroll.c | 385 | ||||
-rw-r--r-- | src/ipcpd/common/enroll.h (renamed from src/ipcpd/unicast/enroll.h) | 6 | ||||
-rw-r--r-- | src/ipcpd/unicast/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ipcpd/unicast/connmgr.c | 497 | ||||
-rw-r--r-- | src/ipcpd/unicast/dht.c | 2 | ||||
-rw-r--r-- | src/ipcpd/unicast/dir.h | 2 | ||||
-rw-r--r-- | src/ipcpd/unicast/dt.c | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/enroll.c | 383 | ||||
-rw-r--r-- | src/ipcpd/unicast/main.c | 7 | ||||
-rw-r--r-- | src/ipcpd/unicast/pol/link_state.c | 4 | ||||
-rw-r--r-- | src/ipcpd/unicast/psched.c | 2 |
21 files changed, 944 insertions, 1890 deletions
diff --git a/src/ipcpd/broadcast/comp.h b/src/ipcpd/broadcast/comp.h deleted file mode 100644 index 6cb42847..00000000 --- a/src/ipcpd/broadcast/comp.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Components for the broadcast IPC process - * - * 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 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/. - */ - -#ifndef OUROBOROS_IPCPD_BROADCAST_COMP_H -#define OUROBOROS_IPCPD_BROADCAST_COMP_H - -#include <ouroboros/cacep.h> - -#define DST_MAX_STRLEN 64 - -enum comp_id { - COMPID_DT = 0, - COMPID_ENROLL, - COMPID_MAX -}; - -struct conn { - struct conn_info conn_info; - struct { - char dst[DST_MAX_STRLEN + 1]; - int fd; - qosspec_t qs; - } flow_info; -}; - -#endif /* OUROBOROS_IPCPD_BROADCAST_COMP_H */ diff --git a/src/ipcpd/broadcast/connmgr.c b/src/ipcpd/broadcast/connmgr.c index 1311a916..b65f48b0 100644 --- a/src/ipcpd/broadcast/connmgr.c +++ b/src/ipcpd/broadcast/connmgr.c @@ -20,496 +20,16 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ +#include "config.h" + #if defined(__linux__) || defined(__CYGWIN__) #define _DEFAULT_SOURCE #else #define _POSIX_C_SOURCE 200112L #endif -#define OUROBOROS_PREFIX "connection-manager" - -#include <ouroboros/dev.h> -#include <ouroboros/cacep.h> -#include <ouroboros/errno.h> -#include <ouroboros/list.h> -#include <ouroboros/logs.h> -#include <ouroboros/notifier.h> - -#include "comp.h" -#include "connmgr.h" -#include "enroll.h" -#include "ipcp.h" - -#include <pthread.h> -#include <string.h> -#include <stdlib.h> -#include <assert.h> - -enum connmgr_state { - CONNMGR_NULL = 0, - CONNMGR_INIT, - CONNMGR_RUNNING -}; - -struct conn_el { - struct list_head next; - struct conn conn; -}; - -struct comp { - struct conn_info info; - - struct list_head conns; - struct list_head pending; - - pthread_cond_t cond; - pthread_mutex_t lock; -}; - -struct { - struct comp comps[COMPID_MAX]; - enum connmgr_state state; - - pthread_t acceptor; -} connmgr; - -static int get_id_by_name(const char * name) -{ - enum comp_id i; - - for (i = 0; i < COMPID_MAX; ++i) - if (strcmp(name, connmgr.comps[i].info.comp_name) == 0) - return i; - - return -1; -} - -static int get_conn_by_fd(int fd, - enum comp_id id, - struct conn * conn) -{ - struct list_head * p; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_for_each(p, &connmgr.comps[id].conns) { - struct conn_el * c = - list_entry(p, struct conn_el, next); - if (c->conn.flow_info.fd == fd) { - *conn = c->conn; - pthread_mutex_unlock(&connmgr.comps[id].lock); - return 0; - } - } - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return -1; -} - -static int add_comp_conn(enum comp_id id, - int fd, - qosspec_t qs, - struct conn_info * rcv_info) -{ - struct conn_el * el; - - el = malloc(sizeof(*el)); - if (el == NULL) { - log_err("Not enough memory."); - return -1; - } - - el->conn.conn_info = *rcv_info; - el->conn.flow_info.fd = fd; - el->conn.flow_info.qs = qs; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_add(&el->next, &connmgr.comps[id].pending); - pthread_cond_signal(&connmgr.comps[id].cond); - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -static void * flow_acceptor(void * o) -{ - int fd; - qosspec_t qs; - struct conn_info rcv_info; - struct conn_info fail_info; - - (void) o; - - memset(&fail_info, 0, sizeof(fail_info)); - - while (true) { - int id; - - fd = flow_accept(&qs, NULL); - if (fd < 0) { - if (fd != -EIRMD) - log_warn("Flow accept failed: %d", fd); - continue; - } - - if (cacep_rcv(fd, &rcv_info)) { - log_dbg("Error establishing application connection."); - flow_dealloc(fd); - continue; - } - - id = get_id_by_name(rcv_info.comp_name); - if (id < 0) { - log_dbg("Connection request for unknown component %s.", - rcv_info.comp_name); - cacep_snd(fd, &fail_info); - flow_dealloc(fd); - continue; - } - - assert(id < COMPID_MAX); - - if (cacep_snd(fd, &connmgr.comps[id].info)) { - log_dbg("Failed to respond to request."); - flow_dealloc(fd); - continue; - } - - if (add_comp_conn(id, fd, qs, &rcv_info)) { - log_dbg("Failed to add new connection."); - flow_dealloc(fd); - continue; - } - } - - return (void *) 0; -} - -static void handle_event(void * self, - int event, - const void * o) -{ - struct conn conn; - - (void) self; - - if (!(event == NOTIFY_DT_FLOW_UP || - event == NOTIFY_DT_FLOW_DOWN || - event == NOTIFY_DT_FLOW_DEALLOC)) - return; - - if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn)) - return; - - switch (event) { - case NOTIFY_DT_FLOW_UP: - notifier_event(NOTIFY_DT_CONN_UP, &conn); - break; - case NOTIFY_DT_FLOW_DOWN: - notifier_event(NOTIFY_DT_CONN_DOWN, &conn); - break; - case NOTIFY_DT_FLOW_DEALLOC: - notifier_event(NOTIFY_DT_CONN_DEL, &conn); - break; - default: - break; - } -} - -int connmgr_init(void) -{ - connmgr.state = CONNMGR_INIT; - - if (notifier_reg(handle_event, NULL)) - return -1; - - return 0; -} - -void connmgr_fini(void) -{ - int i; - - notifier_unreg(handle_event); - - if (connmgr.state == CONNMGR_RUNNING) - pthread_join(connmgr.acceptor, NULL); - - for (i = 0; i < COMPID_MAX; ++i) - connmgr_comp_fini(i); -} - -int connmgr_start(void) -{ - if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL)) - return -1; - - connmgr.state = CONNMGR_RUNNING; - - return 0; -} - -void connmgr_stop(void) -{ - if (connmgr.state == CONNMGR_RUNNING) - pthread_cancel(connmgr.acceptor); -} - -int connmgr_comp_init(enum comp_id id, - const struct conn_info * info) -{ - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - - comp = connmgr.comps + id; - - if (pthread_mutex_init(&comp->lock, NULL)) - return -1; - - if (pthread_cond_init(&comp->cond, NULL)) { - pthread_mutex_destroy(&comp->lock); - return -1; - } - - list_head_init(&comp->conns); - list_head_init(&comp->pending); - - memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info)); - - return 0; -} - -void connmgr_comp_fini(enum comp_id id) -{ - struct list_head * p; - struct list_head * h; - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - - if (strlen(connmgr.comps[id].info.comp_name) == 0) - return; - - comp = connmgr.comps + id; - - pthread_mutex_lock(&comp->lock); - - list_for_each_safe(p, h, &comp->conns) { - struct conn_el * e = list_entry(p, struct conn_el, next); - list_del(&e->next); - free(e); - } - - list_for_each_safe(p, h, &comp->pending) { - struct conn_el * e = list_entry(p, struct conn_el, next); - list_del(&e->next); - free(e); - } - - pthread_mutex_unlock(&comp->lock); - - pthread_cond_destroy(&comp->cond); - pthread_mutex_destroy(&comp->lock); - - memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info)); -} - -int connmgr_ipcp_connect(const char * dst, - const char * component, - qosspec_t qs) -{ - struct conn_el * ce; - int id; - - assert(dst); - assert(component); - - ce = malloc(sizeof(*ce)); - if (ce == NULL) { - log_dbg("Out of memory."); - return -1; - } - - id = get_id_by_name(component); - if (id < 0) { - log_dbg("No such component: %s", component); - free(ce); - return -1; - } - - if (connmgr_alloc(id, dst, &qs, &ce->conn)) { - free(ce); - return -1; - } - - if (strlen(dst) > DST_MAX_STRLEN) { - log_warn("Truncating dst length for connection."); - memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN); - ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0'; - } else { - strcpy(ce->conn.flow_info.dst, dst); - } - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_add(&ce->next, &connmgr.comps[id].conns); - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -int connmgr_ipcp_disconnect(const char * dst, - const char * component) -{ - struct list_head * p; - struct list_head * h; - int id; - - assert(dst); - assert(component); - - id = get_id_by_name(component); - if (id < 0) - return -1; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_for_each_safe(p,h, &connmgr.comps[id].conns) { - struct conn_el * el = list_entry(p, struct conn_el, next); - if (strcmp(el->conn.flow_info.dst, dst) == 0) { - int ret; - pthread_mutex_unlock(&connmgr.comps[id].lock); - list_del(&el->next); - ret = connmgr_dealloc(id, &el->conn); - free(el); - return ret; - } - } - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -int connmgr_alloc(enum comp_id id, - const char * dst, - qosspec_t * qs, - struct conn * conn) -{ - assert(id >= 0 && id < COMPID_MAX); - assert(dst); - - conn->flow_info.fd = flow_alloc(dst, qs, NULL); - if (conn->flow_info.fd < 0) { - log_dbg("Failed to allocate flow to %s.", dst); - return -1; - } - - if (qs != NULL) - conn->flow_info.qs = *qs; - else - memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs)); - - log_dbg("Sending cacep info for protocol %s to fd %d.", - connmgr.comps[id].info.protocol, conn->flow_info.fd); - - if (cacep_snd(conn->flow_info.fd, &connmgr.comps[id].info)) { - log_dbg("Failed to create application connection."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (cacep_rcv(conn->flow_info.fd, &conn->conn_info)) { - log_dbg("Failed to connect to application."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (strcmp(connmgr.comps[id].info.protocol, conn->conn_info.protocol)) { - log_dbg("Unknown protocol (requested %s, got %s).", - connmgr.comps[id].info.protocol, - conn->conn_info.protocol); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (connmgr.comps[id].info.pref_version != - conn->conn_info.pref_version) { - log_dbg("Unknown protocol version."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (connmgr.comps[id].info.pref_syntax != conn->conn_info.pref_syntax) { - log_dbg("Unknown protocol syntax."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - switch (id) { - case COMPID_DT: - notifier_event(NOTIFY_DT_CONN_ADD, conn); - break; - default: - break; - } - - return 0; -} - -int connmgr_dealloc(enum comp_id id, - struct conn * conn) -{ - switch (id) { - case COMPID_DT: - notifier_event(NOTIFY_DT_CONN_DEL, conn); - break; - default: - break; - } - - return flow_dealloc(conn->flow_info.fd); -} - - -int connmgr_wait(enum comp_id id, - struct conn * conn) -{ - struct conn_el * el; - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - assert(conn); - - comp = connmgr.comps + id; - - pthread_mutex_lock(&comp->lock); - - pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, - (void *) &comp->lock); - - while (list_is_empty(&comp->pending)) - pthread_cond_wait(&comp->cond, &comp->lock); - - pthread_cleanup_pop(false); - - el = list_first_entry((&comp->pending), struct conn_el, next); - if (el == NULL) { - pthread_mutex_unlock(&comp->lock); - return -1; - } - - *conn = el->conn; - - list_del(&el->next); - list_add(&el->next, &connmgr.comps[id].conns); +#include <ouroboros/ipcp.h> - pthread_mutex_unlock(&comp->lock); +#define BUILD_IPCP_BROADCAST - return 0; -} +#include "common/connmgr.c" diff --git a/src/ipcpd/broadcast/connmgr.h b/src/ipcpd/broadcast/connmgr.h deleted file mode 100644 index 49ff61d8..00000000 --- a/src/ipcpd/broadcast/connmgr.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Handles the different AP connections - * - * 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 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/. - */ - -#ifndef OUROBOROS_IPCPD_BROADCAST_CONNMGR_H -#define OUROBOROS_IPCPD_BROADCAST_CONNMGR_H - -#include <ouroboros/cacep.h> -#include <ouroboros/qos.h> - -#include "comp.h" - -#define NOTIFY_DT_CONN_ADD 0x00D0 -#define NOTIFY_DT_CONN_DEL 0x00D1 -#define NOTIFY_DT_CONN_QOS 0x00D2 -#define NOTIFY_DT_CONN_UP 0x00D3 -#define NOTIFY_DT_CONN_DOWN 0x00D4 -#define NOTIFY_DT_FLOW_UP 0x00D5 -#define NOTIFY_DT_FLOW_DOWN 0x00D6 -#define NOTIFY_DT_FLOW_DEALLOC 0x00D7 - -int connmgr_init(void); - -void connmgr_fini(void); - -int connmgr_start(void); - -void connmgr_stop(void); - -int connmgr_comp_init(enum comp_id id, - const struct conn_info * info); - -void connmgr_comp_fini(enum comp_id id); - -int connmgr_ipcp_connect(const char * dst, - const char * component, - qosspec_t qs); - -int connmgr_ipcp_disconnect(const char * dst, - const char * component); - -int connmgr_alloc(enum comp_id id, - const char * dst, - qosspec_t * qs, - struct conn * conn); - -int connmgr_dealloc(enum comp_id id, - struct conn * conn); - -int connmgr_wait(enum comp_id id, - struct conn * conn); - -#endif /* OUROBOROS_IPCPD_BROADCAST_CONNMGR_H */ diff --git a/src/ipcpd/broadcast/dt.c b/src/ipcpd/broadcast/dt.c index 77f6204d..c3f40909 100644 --- a/src/ipcpd/broadcast/dt.c +++ b/src/ipcpd/broadcast/dt.c @@ -42,8 +42,8 @@ #include <ouroboros/notifier.h> #include <ouroboros/utils.h> -#include "comp.h" -#include "connmgr.h" +#include "common/comp.h" +#include "common/connmgr.h" #include "dt.h" #include "ipcp.h" diff --git a/src/ipcpd/broadcast/enroll.c b/src/ipcpd/broadcast/enroll.c index c05c6d8e..143f16d5 100644 --- a/src/ipcpd/broadcast/enroll.c +++ b/src/ipcpd/broadcast/enroll.c @@ -19,345 +19,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., http://www.fsf.org/about/contact/. */ +#define BUILD_IPCP_BROADCAST -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 199309L -#endif - -#define OUROBOROS_PREFIX "enrollment" - -#include <ouroboros/endian.h> -#include <ouroboros/errno.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/dev.h> -#include <ouroboros/logs.h> -#include <ouroboros/errno.h> -#include <ouroboros/sockets.h> - -#include "connmgr.h" -#include "enroll.h" -#include "ipcp.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> - -#include "ipcp_config.pb-c.h" -typedef EnrollMsg enroll_msg_t; - -#define ENROLL_COMP "Enrollment" -#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */ -#define ENROLL_WARN_TIME_OFFSET 20 -#define ENROLL_BUF_LEN 1024 - -enum enroll_state { - ENROLL_NULL = 0, - ENROLL_INIT, - ENROLL_RUNNING -}; - -struct { - struct ipcp_config conf; - enum enroll_state state; - pthread_t listener; -} enroll; - -static int send_rcv_enroll_msg(int fd) -{ - enroll_msg_t req = ENROLL_MSG__INIT; - enroll_msg_t * reply; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - ssize_t delta_t; - struct timespec t0; - struct timespec rtt; - - req.code = ENROLL_CODE__ENROLL_REQ; - - len = enroll_msg__get_packed_size(&req); - if (len < 0) { - log_dbg("Failed pack request message."); - return -1; - } - - enroll_msg__pack(&req, buf); - - clock_gettime(CLOCK_REALTIME, &t0); - - if (flow_write(fd, buf, len) < 0) { - log_dbg("Failed to send request message."); - return -1; - } - - len = flow_read(fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_dbg("No enrollment reply received."); - return -1; - } - - log_dbg("Received enrollment info (%zd bytes).", len); - - reply = enroll_msg__unpack(NULL, len, buf); - if (reply == NULL) { - log_dbg("No enrollment response."); - return -1; - } - - if (reply->code != ENROLL_CODE__ENROLL_BOOT) { - log_dbg("Failed to unpack enrollment response."); - enroll_msg__free_unpacked(reply, NULL); - return -1; - } - - if (!(reply->has_t_sec && reply->has_t_nsec)) { - log_dbg("No time in response message."); - enroll_msg__free_unpacked(reply, NULL); - return -1; - } - - clock_gettime(CLOCK_REALTIME, &rtt); - - delta_t = ts_diff_ms(&t0, &rtt); - - rtt.tv_sec = reply->t_sec; - rtt.tv_nsec = reply->t_nsec; - - if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) - log_warn("Clock offset above threshold."); - - strcpy(enroll.conf.layer_info.layer_name, - reply->conf->layer_info->layer_name); - enroll.conf.layer_info.dir_hash_algo - = reply->conf->layer_info->dir_hash_algo; - - enroll_msg__free_unpacked(reply, NULL); - - return 0; -} - -static ssize_t enroll_pack(uint8_t ** buf) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT; - layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT; - struct timespec now; - ssize_t len; - - clock_gettime(CLOCK_REALTIME, &now); - - msg.code = ENROLL_CODE__ENROLL_BOOT; - msg.has_t_sec = true; - msg.t_sec = now.tv_sec; - msg.has_t_nsec = true; - msg.t_nsec = now.tv_nsec; - msg.conf = &config; - - config.ipcp_type = enroll.conf.type; - config.layer_info = &layer_info; - - layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name; - layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo; - - len = enroll_msg__get_packed_size(&msg); - - *buf = malloc(len); - if (*buf == NULL) - return -1; - - enroll_msg__pack(&msg, *buf); - - return len; -} - -static void * enroll_handle(void * o) -{ - struct conn conn; - uint8_t buf[ENROLL_BUF_LEN]; - uint8_t * reply; - ssize_t len; - enroll_msg_t * msg; - - (void) o; - - while (true) { - if (connmgr_wait(COMPID_ENROLL, &conn)) { - log_err("Failed to get next connection."); - continue; - } - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_err("Failed to read from flow."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->code != ENROLL_CODE__ENROLL_REQ) { - log_err("Wrong message type."); - connmgr_dealloc(COMPID_ENROLL, &conn); - enroll_msg__free_unpacked(msg, NULL); - continue; - } - - log_dbg("Enrolling a new neighbor."); - - enroll_msg__free_unpacked(msg, NULL); - - len = enroll_pack(&reply); - if (reply == NULL) { - log_err("Failed to pack enrollment message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - log_dbg("Sending enrollment info (%zd bytes).", len); - - if (flow_write(conn.flow_info.fd, reply, len) < 0) { - log_err("Failed respond to enrollment request."); - connmgr_dealloc(COMPID_ENROLL, &conn); - free(reply); - continue; - } - - free(reply); - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_err("Failed to read from flow."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) { - log_err("Wrong message type."); - enroll_msg__free_unpacked(msg, NULL); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->result == 0) - log_dbg("Neighbor enrollment successful."); - else - log_dbg("Neigbor reported failed enrollment."); - - enroll_msg__free_unpacked(msg, NULL); - - connmgr_dealloc(COMPID_ENROLL, &conn); - } - - return 0; -} - -int enroll_boot(struct conn * conn) -{ - log_dbg("Getting boot information."); - - if (send_rcv_enroll_msg(conn->flow_info.fd)) { - log_err("Failed to enroll."); - return -1; - } - - return 0; -} - -int enroll_done(struct conn * conn, - int result) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - - msg.code = ENROLL_CODE__ENROLL_DONE; - msg.has_result = true; - msg.result = result; - - len = enroll_msg__get_packed_size(&msg); - if (len < 0) { - log_dbg("Failed pack request message."); - return -1; - } - - enroll_msg__pack(&msg, buf); - - if (flow_write(conn->flow_info.fd, buf, len) < 0) { - log_dbg("Failed to send acknowledgment."); - return -1; - } - - return 0; -} - -void enroll_bootstrap(const struct ipcp_config * conf) -{ - assert(conf); - - memcpy(&enroll.conf, conf, sizeof(enroll.conf)); -} - -struct ipcp_config * enroll_get_conf(void) -{ - return &enroll.conf; -} - -int enroll_init(void) -{ - struct conn_info info; - - memset(&info, 0, sizeof(info)); - - strcpy(info.comp_name, ENROLL_COMP); - strcpy(info.protocol, ENROLL_PROTO); - info.pref_version = 1; - info.pref_syntax = PROTO_GPB; - info.addr = 0; - - if (connmgr_comp_init(COMPID_ENROLL, &info)) { - log_err("Failed to register with connmgr."); - return -1; - } - - enroll.state = ENROLL_INIT; - - return 0; -} - -void enroll_fini(void) -{ - if (enroll.state == ENROLL_RUNNING) - pthread_join(enroll.listener, NULL); - - connmgr_comp_fini(COMPID_ENROLL); -} - -int enroll_start(void) -{ - if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL)) - return -1; - - enroll.state = ENROLL_RUNNING; - - return 0; -} - -void enroll_stop(void) -{ - if (enroll.state == ENROLL_RUNNING) - pthread_cancel(enroll.listener); -} +#include "common/enroll.c" diff --git a/src/ipcpd/broadcast/enroll.h b/src/ipcpd/broadcast/enroll.h deleted file mode 100644 index 5c7f1a02..00000000 --- a/src/ipcpd/broadcast/enroll.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Enrollment Task - * - * 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 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/. - */ - -#ifndef OUROBOROS_IPCPD_BROADCAST_ENROLL_H -#define OUROBOROS_IPCPD_BROADCAST_ENROLL_H - -#include <ouroboros/ipcp.h> - -#include "comp.h" - -int enroll_init(void); - -void enroll_fini(void); - -int enroll_start(void); - -void enroll_stop(void); - -void enroll_bootstrap(const struct ipcp_config * conf); - -int enroll_boot(struct conn * conn); - -int enroll_done(struct conn * conn, - int result); - -struct ipcp_config * enroll_get_conf(void); - -#endif /* OUROBOROS_IPCPD_BROADCAST_ENROLL_H */ diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c index b7555803..a2643029 100644 --- a/src/ipcpd/broadcast/main.c +++ b/src/ipcpd/broadcast/main.c @@ -29,6 +29,7 @@ #include "config.h" #define OUROBOROS_PREFIX "broadcast-ipcp" +#define THIS_TYPE IPCP_BROADCAST #include <ouroboros/errno.h> #include <ouroboros/hash.h> @@ -39,9 +40,9 @@ #include <ouroboros/rib.h> #include <ouroboros/time_utils.h> -#include "connmgr.h" +#include "common/connmgr.h" +#include "common/enroll.h" #include "dt.h" -#include "enroll.h" #include "ipcp.h" #include <stdbool.h> @@ -51,8 +52,6 @@ #include <assert.h> #include <inttypes.h> -#define THIS_TYPE IPCP_BROADCAST - struct ipcp ipcpi; static int initialize_components(const struct ipcp_config * conf) diff --git a/src/ipcpd/unicast/comp.h b/src/ipcpd/common/comp.h index 45880aab..95e59b24 100644 --- a/src/ipcpd/unicast/comp.h +++ b/src/ipcpd/common/comp.h @@ -1,7 +1,7 @@ /* * Ouroboros - Copyright (C) 2016 - 2021 * - * Components for the unicast IPC process + * Components for the unicast/broadcast IPC process * * Dimitri Staessens <[email protected]> * Sander Vrijders <[email protected]> @@ -20,13 +20,11 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_COMP_H -#define OUROBOROS_IPCPD_UNICAST_COMP_H +#ifndef OUROBOROS_IPCPD_COMMON_COMP_H +#define OUROBOROS_IPCPD_COMMON_COMP_H #include <ouroboros/cacep.h> -#include "dt.h" - #define DST_MAX_STRLEN 64 enum comp_id { @@ -45,4 +43,4 @@ struct conn { } flow_info; }; -#endif /* OUROBOROS_IPCPD_UNICAST_COMP_H */ +#endif /* OUROBOROS_IPCPD_COMMON_COMP_H */ diff --git a/src/ipcpd/common/connmgr.c b/src/ipcpd/common/connmgr.c new file mode 100644 index 00000000..9002467c --- /dev/null +++ b/src/ipcpd/common/connmgr.c @@ -0,0 +1,518 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2021 + * + * Handles connections between components + * + * 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 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 OUROBOROS_PREFIX "connection-manager" + +#include <ouroboros/dev.h> +#include <ouroboros/cacep.h> +#include <ouroboros/errno.h> +#include <ouroboros/list.h> +#include <ouroboros/logs.h> +#include <ouroboros/notifier.h> + +#include "connmgr.h" +#include "ipcp.h" + +#include <pthread.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +enum connmgr_state { + CONNMGR_NULL = 0, + CONNMGR_INIT, + CONNMGR_RUNNING +}; + +struct conn_el { + struct list_head next; + struct conn conn; +}; + +struct comp { + struct conn_info info; + + struct list_head conns; + struct list_head pending; + + pthread_cond_t cond; + pthread_mutex_t lock; +}; + +struct { + struct comp comps[COMPID_MAX]; + enum connmgr_state state; + + pthread_t acceptor; +} connmgr; + +static int get_id_by_name(const char * name) +{ + enum comp_id i; + + for (i = 0; i < COMPID_MAX; ++i) + if (strcmp(name, connmgr.comps[i].info.comp_name) == 0) + return i; + + return -1; +} + +static int get_conn_by_fd(int fd, + enum comp_id id, + struct conn * conn) +{ + struct list_head * p; + + pthread_mutex_lock(&connmgr.comps[id].lock); + + list_for_each(p, &connmgr.comps[id].conns) { + struct conn_el * c = + list_entry(p, struct conn_el, next); + if (c->conn.flow_info.fd == fd) { + *conn = c->conn; + pthread_mutex_unlock(&connmgr.comps[id].lock); + return 0; + } + } + + pthread_mutex_unlock(&connmgr.comps[id].lock); + + return -1; +} + +static int add_comp_conn(enum comp_id id, + int fd, + qosspec_t qs, + struct conn_info * rcv_info) +{ + struct conn_el * el; + + el = malloc(sizeof(*el)); + if (el == NULL) { + log_err("Not enough memory."); + return -1; + } + + el->conn.conn_info = *rcv_info; + el->conn.flow_info.fd = fd; + el->conn.flow_info.qs = qs; + + pthread_mutex_lock(&connmgr.comps[id].lock); + + list_add(&el->next, &connmgr.comps[id].pending); + pthread_cond_signal(&connmgr.comps[id].cond); + + pthread_mutex_unlock(&connmgr.comps[id].lock); + + return 0; +} + +static void * flow_acceptor(void * o) +{ + int fd; + qosspec_t qs; + struct conn_info rcv_info; + struct conn_info fail_info; + + (void) o; + + memset(&fail_info, 0, sizeof(fail_info)); + + while (true) { + int id; + + fd = flow_accept(&qs, NULL); + if (fd < 0) { + if (fd != -EIRMD) + log_warn("Flow accept failed: %d", fd); + continue; + } + + if (cacep_rcv(fd, &rcv_info)) { + log_dbg("Error establishing application connection."); + flow_dealloc(fd); + continue; + } + + id = get_id_by_name(rcv_info.comp_name); + if (id < 0) { + log_dbg("Connection request for unknown component %s.", + rcv_info.comp_name); + cacep_snd(fd, &fail_info); + flow_dealloc(fd); + continue; + } + + assert(id < COMPID_MAX); + + if (cacep_snd(fd, &connmgr.comps[id].info)) { + log_dbg("Failed to respond to request."); + flow_dealloc(fd); + continue; + } + + if (add_comp_conn(id, fd, qs, &rcv_info)) { + log_dbg("Failed to add new connection."); + flow_dealloc(fd); + continue; + } + } + + return (void *) 0; +} + +static void handle_event(void * self, + int event, + const void * o) +{ + struct conn conn; + + (void) self; + + if (!(event == NOTIFY_DT_FLOW_UP || + event == NOTIFY_DT_FLOW_DOWN || + event == NOTIFY_DT_FLOW_DEALLOC)) + return; + + if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn)) + return; + + switch (event) { + case NOTIFY_DT_FLOW_UP: + notifier_event(NOTIFY_DT_CONN_UP, &conn); + break; + case NOTIFY_DT_FLOW_DOWN: + notifier_event(NOTIFY_DT_CONN_DOWN, &conn); + break; + case NOTIFY_DT_FLOW_DEALLOC: + notifier_event(NOTIFY_DT_CONN_DEL, &conn); + break; + default: + break; + } +} + +int connmgr_init(void) +{ + connmgr.state = CONNMGR_INIT; + + if (notifier_reg(handle_event, NULL)) + return -1; + + return 0; +} + +void connmgr_fini(void) +{ + int i; + + notifier_unreg(handle_event); + + if (connmgr.state == CONNMGR_RUNNING) + pthread_join(connmgr.acceptor, NULL); + + for (i = 0; i < COMPID_MAX; ++i) + connmgr_comp_fini(i); +} + +int connmgr_start(void) +{ + if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL)) + return -1; + + connmgr.state = CONNMGR_RUNNING; + + return 0; +} + +void connmgr_stop(void) +{ + if (connmgr.state == CONNMGR_RUNNING) + pthread_cancel(connmgr.acceptor); +} + +int connmgr_comp_init(enum comp_id id, + const struct conn_info * info) +{ + struct comp * comp; + + assert(id >= 0 && id < COMPID_MAX); + + comp = connmgr.comps + id; + + if (pthread_mutex_init(&comp->lock, NULL)) + return -1; + + if (pthread_cond_init(&comp->cond, NULL)) { + pthread_mutex_destroy(&comp->lock); + return -1; + } + + list_head_init(&comp->conns); + list_head_init(&comp->pending); + + memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info)); + + return 0; +} + +void connmgr_comp_fini(enum comp_id id) +{ + struct list_head * p; + struct list_head * h; + struct comp * comp; + + assert(id >= 0 && id < COMPID_MAX); + + if (strlen(connmgr.comps[id].info.comp_name) == 0) + return; + + comp = connmgr.comps + id; + + pthread_mutex_lock(&comp->lock); + + list_for_each_safe(p, h, &comp->conns) { + struct conn_el * e = list_entry(p, struct conn_el, next); + list_del(&e->next); + free(e); + } + + list_for_each_safe(p, h, &comp->pending) { + struct conn_el * e = list_entry(p, struct conn_el, next); + list_del(&e->next); + free(e); + } + + pthread_mutex_unlock(&comp->lock); + + pthread_cond_destroy(&comp->cond); + pthread_mutex_destroy(&comp->lock); + + memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info)); +} + +int connmgr_ipcp_connect(const char * dst, + const char * component, + qosspec_t qs) +{ + struct conn_el * ce; + int id; + + assert(dst); + assert(component); + + ce = malloc(sizeof(*ce)); + if (ce == NULL) { + log_dbg("Out of memory."); + return -1; + } + + id = get_id_by_name(component); + if (id < 0) { + log_dbg("No such component: %s", component); + free(ce); + return -1; + } + + if (connmgr_alloc(id, dst, &qs, &ce->conn)) { + free(ce); + return -1; + } + + if (strlen(dst) > DST_MAX_STRLEN) { + log_warn("Truncating dst length for connection."); + memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN); + ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0'; + } else { + strcpy(ce->conn.flow_info.dst, dst); + } + + pthread_mutex_lock(&connmgr.comps[id].lock); + + list_add(&ce->next, &connmgr.comps[id].conns); + + pthread_mutex_unlock(&connmgr.comps[id].lock); + + return 0; +} + +int connmgr_ipcp_disconnect(const char * dst, + const char * component) +{ + struct list_head * p; + struct list_head * h; + int id; + + assert(dst); + assert(component); + + id = get_id_by_name(component); + if (id < 0) + return -1; + + pthread_mutex_lock(&connmgr.comps[id].lock); + + list_for_each_safe(p,h, &connmgr.comps[id].conns) { + struct conn_el * el = list_entry(p, struct conn_el, next); + if (strcmp(el->conn.flow_info.dst, dst) == 0) { + int ret; + pthread_mutex_unlock(&connmgr.comps[id].lock); + list_del(&el->next); + ret = connmgr_dealloc(id, &el->conn); + free(el); + return ret; + } + } + + pthread_mutex_unlock(&connmgr.comps[id].lock); + + return 0; +} + +int connmgr_alloc(enum comp_id id, + const char * dst, + qosspec_t * qs, + struct conn * conn) +{ + assert(id >= 0 && id < COMPID_MAX); + assert(dst); + + conn->flow_info.fd = flow_alloc(dst, qs, NULL); + if (conn->flow_info.fd < 0) { + log_dbg("Failed to allocate flow to %s.", dst); + return -1; + } + + if (qs != NULL) + conn->flow_info.qs = *qs; + else + memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs)); + + log_dbg("Sending cacep info for protocol %s to fd %d.", + connmgr.comps[id].info.protocol, conn->flow_info.fd); + + if (cacep_snd(conn->flow_info.fd, &connmgr.comps[id].info)) { + log_dbg("Failed to create application connection."); + flow_dealloc(conn->flow_info.fd); + return -1; + } + + if (cacep_rcv(conn->flow_info.fd, &conn->conn_info)) { + log_dbg("Failed to connect to application."); + flow_dealloc(conn->flow_info.fd); + return -1; + } + + if (strcmp(connmgr.comps[id].info.protocol, conn->conn_info.protocol)) { + log_dbg("Unknown protocol (requested %s, got %s).", + connmgr.comps[id].info.protocol, + conn->conn_info.protocol); + flow_dealloc(conn->flow_info.fd); + return -1; + } + + if (connmgr.comps[id].info.pref_version != + conn->conn_info.pref_version) { + log_dbg("Unknown protocol version."); + flow_dealloc(conn->flow_info.fd); + return -1; + } + + if (connmgr.comps[id].info.pref_syntax != conn->conn_info.pref_syntax) { + log_dbg("Unknown protocol syntax."); + flow_dealloc(conn->flow_info.fd); + return -1; + } + + switch (id) { + case COMPID_DT: + notifier_event(NOTIFY_DT_CONN_ADD, conn); +#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR) + dir_wait_running(); +#endif + break; + case COMPID_MGMT: + notifier_event(NOTIFY_MGMT_CONN_ADD, conn); + break; + default: + break; + } + + return 0; +} + +int connmgr_dealloc(enum comp_id id, + struct conn * conn) +{ + switch (id) { + case COMPID_DT: + notifier_event(NOTIFY_DT_CONN_DEL, conn); + break; +#if defined(BUILD_IPCP_UNICAST) && defined(IPCP_CONN_WAIT_DIR) + case COMPID_MGMT: + notifier_event(NOTIFY_MGMT_CONN_DEL, conn); + break; +#endif + default: + break; + } + + return flow_dealloc(conn->flow_info.fd); +} + + +int connmgr_wait(enum comp_id id, + struct conn * conn) +{ + struct conn_el * el; + struct comp * comp; + + assert(id >= 0 && id < COMPID_MAX); + assert(conn); + + comp = connmgr.comps + id; + + pthread_mutex_lock(&comp->lock); + + pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, + (void *) &comp->lock); + + while (list_is_empty(&comp->pending)) + pthread_cond_wait(&comp->cond, &comp->lock); + + pthread_cleanup_pop(false); + + el = list_first_entry((&comp->pending), struct conn_el, next); + if (el == NULL) { + pthread_mutex_unlock(&comp->lock); + return -1; + } + + *conn = el->conn; + + list_del(&el->next); + list_add(&el->next, &connmgr.comps[id].conns); + + pthread_mutex_unlock(&comp->lock); + + return 0; +} diff --git a/src/ipcpd/unicast/connmgr.h b/src/ipcpd/common/connmgr.h index 92892a3d..5f7b557f 100644 --- a/src/ipcpd/unicast/connmgr.h +++ b/src/ipcpd/common/connmgr.h @@ -20,8 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_CONNMGR_H -#define OUROBOROS_IPCPD_UNICAST_CONNMGR_H +#ifndef OUROBOROS_IPCPD_COMMON_CONNMGR_H +#define OUROBOROS_IPCPD_COMMON_CONNMGR_H #include <ouroboros/cacep.h> #include <ouroboros/qos.h> @@ -71,4 +71,4 @@ int connmgr_dealloc(enum comp_id id, int connmgr_wait(enum comp_id id, struct conn * conn); -#endif /* OUROBOROS_IPCPD_UNICAST_CONNMGR_H */ +#endif /* OUROBOROS_IPCPD_COMMON_CONNMGR_H */ diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c new file mode 100644 index 00000000..090067d8 --- /dev/null +++ b/src/ipcpd/common/enroll.c @@ -0,0 +1,385 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2021 + * + * Enrollment Task + * + * 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 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/. + */ + +#if defined(__linux__) || defined(__CYGWIN__) +#define _DEFAULT_SOURCE +#else +#define _POSIX_C_SOURCE 199309L +#endif + +#define OUROBOROS_PREFIX "enrollment" + +#include <ouroboros/endian.h> +#include <ouroboros/errno.h> +#include <ouroboros/time_utils.h> +#include <ouroboros/dev.h> +#include <ouroboros/logs.h> +#include <ouroboros/errno.h> +#include <ouroboros/sockets.h> + +#include "common/connmgr.h" +#include "common/enroll.h" +#include "ipcp.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#include "ipcp_config.pb-c.h" +typedef EnrollMsg enroll_msg_t; + +#define ENROLL_COMP "Enrollment" +#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */ +#define ENROLL_WARN_TIME_OFFSET 20 +#define ENROLL_BUF_LEN 1024 + +enum enroll_state { + ENROLL_NULL = 0, + ENROLL_INIT, + ENROLL_RUNNING +}; + +struct { + struct ipcp_config conf; + enum enroll_state state; + pthread_t listener; +} enroll; + +static int send_rcv_enroll_msg(int fd) +{ + enroll_msg_t req = ENROLL_MSG__INIT; + enroll_msg_t * reply; + uint8_t buf[ENROLL_BUF_LEN]; + ssize_t len; + ssize_t delta_t; + struct timespec t0; + struct timespec rtt; + + req.code = ENROLL_CODE__ENROLL_REQ; + + len = enroll_msg__get_packed_size(&req); + if (len < 0) { + log_dbg("Failed pack request message."); + return -1; + } + + enroll_msg__pack(&req, buf); + + clock_gettime(CLOCK_REALTIME, &t0); + + if (flow_write(fd, buf, len) < 0) { + log_dbg("Failed to send request message."); + return -1; + } + + len = flow_read(fd, buf, ENROLL_BUF_LEN); + if (len < 0) { + log_dbg("No enrollment reply received."); + return -1; + } + + log_dbg("Received enrollment info (%zd bytes).", len); + + reply = enroll_msg__unpack(NULL, len, buf); + if (reply == NULL) { + log_dbg("No enrollment response."); + return -1; + } + + if (reply->code != ENROLL_CODE__ENROLL_BOOT) { + log_dbg("Failed to unpack enrollment response."); + enroll_msg__free_unpacked(reply, NULL); + return -1; + } + + if (!(reply->has_t_sec && reply->has_t_nsec)) { + log_dbg("No time in response message."); + enroll_msg__free_unpacked(reply, NULL); + return -1; + } + + clock_gettime(CLOCK_REALTIME, &rtt); + + delta_t = ts_diff_ms(&t0, &rtt); + + rtt.tv_sec = reply->t_sec; + rtt.tv_nsec = reply->t_nsec; + + if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) + log_warn("Clock offset above threshold."); + + strcpy(enroll.conf.layer_info.layer_name, + reply->conf->layer_info->layer_name); + enroll.conf.type = reply->conf->ipcp_type; +#ifdef BUILD_IPCP_UNICAST + enroll.conf.addr_size = reply->conf->addr_size; + enroll.conf.eid_size = reply->conf->eid_size; + enroll.conf.max_ttl = reply->conf->max_ttl; + enroll.conf.addr_auth_type = reply->conf->addr_auth_type; + enroll.conf.routing_type = reply->conf->routing_type; + enroll.conf.cong_avoid = reply->conf->cong_avoid; +#endif + enroll.conf.layer_info.dir_hash_algo + = reply->conf->layer_info->dir_hash_algo; + enroll_msg__free_unpacked(reply, NULL); + + return 0; +} + +static ssize_t enroll_pack(uint8_t ** buf) +{ + enroll_msg_t msg = ENROLL_MSG__INIT; + ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT; + layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT; + struct timespec now; + ssize_t len; + + clock_gettime(CLOCK_REALTIME, &now); + + msg.code = ENROLL_CODE__ENROLL_BOOT; + msg.has_t_sec = true; + msg.t_sec = now.tv_sec; + msg.has_t_nsec = true; + msg.t_nsec = now.tv_nsec; + msg.conf = &config; + + config.ipcp_type = enroll.conf.type; +#ifdef BUILD_IPCP_UNICAST + config.has_addr_size = true; + config.addr_size = enroll.conf.addr_size; + config.has_eid_size = true; + config.eid_size = enroll.conf.eid_size; + config.has_max_ttl = true; + config.max_ttl = enroll.conf.max_ttl; + config.has_addr_auth_type = true; + config.addr_auth_type = enroll.conf.addr_auth_type; + config.has_routing_type = true; + config.routing_type = enroll.conf.routing_type; + config.has_cong_avoid = true; + config.cong_avoid = enroll.conf.cong_avoid; +#endif + config.layer_info = &layer_info; + + layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name; + layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo; + + len = enroll_msg__get_packed_size(&msg); + + *buf = malloc(len); + if (*buf == NULL) + return -1; + + enroll_msg__pack(&msg, *buf); + + return len; +} + +static void * enroll_handle(void * o) +{ + struct conn conn; + uint8_t buf[ENROLL_BUF_LEN]; + uint8_t * reply; + ssize_t len; + enroll_msg_t * msg; + + (void) o; + + while (true) { + if (connmgr_wait(COMPID_ENROLL, &conn)) { + log_err("Failed to get next connection."); + continue; + } + + len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); + if (len < 0) { + log_err("Failed to read from flow."); + connmgr_dealloc(COMPID_ENROLL, &conn); + continue; + } + + msg = enroll_msg__unpack(NULL, len, buf); + if (msg == NULL) { + log_err("Failed to unpack message."); + connmgr_dealloc(COMPID_ENROLL, &conn); + continue; + } + + if (msg->code != ENROLL_CODE__ENROLL_REQ) { + log_err("Wrong message type."); + connmgr_dealloc(COMPID_ENROLL, &conn); + enroll_msg__free_unpacked(msg, NULL); + continue; + } + + log_dbg("Enrolling a new neighbor."); + + enroll_msg__free_unpacked(msg, NULL); + + len = enroll_pack(&reply); + if (reply == NULL) { + log_err("Failed to pack enrollment message."); + connmgr_dealloc(COMPID_ENROLL, &conn); + continue; + } + + log_dbg("Sending enrollment info (%zd bytes).", len); + + if (flow_write(conn.flow_info.fd, reply, len) < 0) { + log_err("Failed respond to enrollment request."); + connmgr_dealloc(COMPID_ENROLL, &conn); + free(reply); + continue; + } + + free(reply); + + len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); + if (len < 0) { + log_err("Failed to read from flow."); + connmgr_dealloc(COMPID_ENROLL, &conn); + continue; + } + + msg = enroll_msg__unpack(NULL, len, buf); + if (msg == NULL) { + log_err("Failed to unpack message."); + connmgr_dealloc(COMPID_ENROLL, &conn); + continue; + } + + if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) { + log_err("Wrong message type."); + enroll_msg__free_unpacked(msg, NULL); + connmgr_dealloc(COMPID_ENROLL, &conn); + continue; + } + + if (msg->result == 0) + log_dbg("Neighbor enrollment successful."); + else + log_dbg("Neigbor reported failed enrollment."); + + enroll_msg__free_unpacked(msg, NULL); + + connmgr_dealloc(COMPID_ENROLL, &conn); + } + + return 0; +} + +int enroll_boot(struct conn * conn) +{ + log_dbg("Getting boot information."); + + if (send_rcv_enroll_msg(conn->flow_info.fd)) { + log_err("Failed to enroll."); + return -1; + } + + return 0; +} + +int enroll_done(struct conn * conn, + int result) +{ + enroll_msg_t msg = ENROLL_MSG__INIT; + uint8_t buf[ENROLL_BUF_LEN]; + ssize_t len; + + msg.code = ENROLL_CODE__ENROLL_DONE; + msg.has_result = true; + msg.result = result; + + len = enroll_msg__get_packed_size(&msg); + if (len < 0) { + log_dbg("Failed pack request message."); + return -1; + } + + enroll_msg__pack(&msg, buf); + + if (flow_write(conn->flow_info.fd, buf, len) < 0) { + log_dbg("Failed to send acknowledgment."); + return -1; + } + + return 0; +} + +void enroll_bootstrap(const struct ipcp_config * conf) +{ + assert(conf); + + memcpy(&enroll.conf, conf, sizeof(enroll.conf)); +} + +struct ipcp_config * enroll_get_conf(void) +{ + return &enroll.conf; +} + +int enroll_init(void) +{ + struct conn_info info; + + memset(&info, 0, sizeof(info)); + + strcpy(info.comp_name, ENROLL_COMP); + strcpy(info.protocol, ENROLL_PROTO); + info.pref_version = 1; + info.pref_syntax = PROTO_GPB; + info.addr = 0; + + if (connmgr_comp_init(COMPID_ENROLL, &info)) { + log_err("Failed to register with connmgr."); + return -1; + } + + enroll.state = ENROLL_INIT; + + return 0; +} + +void enroll_fini(void) +{ + if (enroll.state == ENROLL_RUNNING) + pthread_join(enroll.listener, NULL); + + connmgr_comp_fini(COMPID_ENROLL); +} + +int enroll_start(void) +{ + if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL)) + return -1; + + enroll.state = ENROLL_RUNNING; + + return 0; +} + +void enroll_stop(void) +{ + if (enroll.state == ENROLL_RUNNING) + pthread_cancel(enroll.listener); +} diff --git a/src/ipcpd/unicast/enroll.h b/src/ipcpd/common/enroll.h index 18b31942..fb866416 100644 --- a/src/ipcpd/unicast/enroll.h +++ b/src/ipcpd/common/enroll.h @@ -20,8 +20,8 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#ifndef OUROBOROS_IPCPD_UNICAST_ENROLL_H -#define OUROBOROS_IPCPD_UNICAST_ENROLL_H +#ifndef OUROBOROS_IPCPD_COMMON_ENROLL_H +#define OUROBOROS_IPCPD_COMMON_ENROLL_H #include <ouroboros/ipcp.h> @@ -44,4 +44,4 @@ int enroll_done(struct conn * conn, struct ipcp_config * enroll_get_conf(void); -#endif /* OUROBOROS_IPCPD_UNICAST_ENROLL_H */ +#endif /* OUROBOROS_IPCPD_COMMON_ENROLL_H */ diff --git a/src/ipcpd/unicast/CMakeLists.txt b/src/ipcpd/unicast/CMakeLists.txt index 035ee5f4..07f12540 100644 --- a/src/ipcpd/unicast/CMakeLists.txt +++ b/src/ipcpd/unicast/CMakeLists.txt @@ -29,7 +29,6 @@ if (HAVE_FUSE) endif () endif () - set(SOURCE_FILES # Add source files here addr_auth.c diff --git a/src/ipcpd/unicast/connmgr.c b/src/ipcpd/unicast/connmgr.c index 51c4ce26..904deff8 100644 --- a/src/ipcpd/unicast/connmgr.c +++ b/src/ipcpd/unicast/connmgr.c @@ -20,505 +20,20 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ +#include "config.h" + #if defined(__linux__) || defined(__CYGWIN__) #define _DEFAULT_SOURCE #else #define _POSIX_C_SOURCE 200112L #endif -#define OUROBOROS_PREFIX "connection-manager" - -#include <ouroboros/dev.h> -#include <ouroboros/cacep.h> -#include <ouroboros/errno.h> -#include <ouroboros/list.h> -#include <ouroboros/logs.h> -#include <ouroboros/notifier.h> - -#include "comp.h" -#include "connmgr.h" -#include "dir.h" -#include "ipcp.h" - -#include <pthread.h> -#include <string.h> -#include <stdlib.h> -#include <assert.h> - -enum connmgr_state { - CONNMGR_NULL = 0, - CONNMGR_INIT, - CONNMGR_RUNNING -}; - -struct conn_el { - struct list_head next; - struct conn conn; -}; - -struct comp { - struct conn_info info; - - struct list_head conns; - struct list_head pending; - - pthread_cond_t cond; - pthread_mutex_t lock; -}; - -struct { - struct comp comps[COMPID_MAX]; - enum connmgr_state state; - - pthread_t acceptor; -} connmgr; - -static int get_id_by_name(const char * name) -{ - enum comp_id i; - - for (i = 0; i < COMPID_MAX; ++i) - if (strcmp(name, connmgr.comps[i].info.comp_name) == 0) - return i; - - return -1; -} - -static int get_conn_by_fd(int fd, - enum comp_id id, - struct conn * conn) -{ - struct list_head * p; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_for_each(p, &connmgr.comps[id].conns) { - struct conn_el * c = - list_entry(p, struct conn_el, next); - if (c->conn.flow_info.fd == fd) { - *conn = c->conn; - pthread_mutex_unlock(&connmgr.comps[id].lock); - return 0; - } - } - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return -1; -} - -static int add_comp_conn(enum comp_id id, - int fd, - qosspec_t qs, - struct conn_info * rcv_info) -{ - struct conn_el * el; - - el = malloc(sizeof(*el)); - if (el == NULL) { - log_err("Not enough memory."); - return -1; - } - - el->conn.conn_info = *rcv_info; - el->conn.flow_info.fd = fd; - el->conn.flow_info.qs = qs; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_add(&el->next, &connmgr.comps[id].pending); - pthread_cond_signal(&connmgr.comps[id].cond); - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -static void * flow_acceptor(void * o) -{ - int fd; - qosspec_t qs; - struct conn_info rcv_info; - struct conn_info fail_info; - - (void) o; - - memset(&fail_info, 0, sizeof(fail_info)); - - while (true) { - int id; - - fd = flow_accept(&qs, NULL); - if (fd < 0) { - if (fd != -EIRMD) - log_warn("Flow accept failed: %d", fd); - continue; - } - - if (cacep_rcv(fd, &rcv_info)) { - log_dbg("Error establishing application connection."); - flow_dealloc(fd); - continue; - } - - id = get_id_by_name(rcv_info.comp_name); - if (id < 0) { - log_dbg("Connection request for unknown component %s.", - rcv_info.comp_name); - cacep_snd(fd, &fail_info); - flow_dealloc(fd); - continue; - } - - assert(id < COMPID_MAX); - - if (cacep_snd(fd, &connmgr.comps[id].info)) { - log_dbg("Failed to respond to request."); - flow_dealloc(fd); - continue; - } - - if (add_comp_conn(id, fd, qs, &rcv_info)) { - log_dbg("Failed to add new connection."); - flow_dealloc(fd); - continue; - } - } - - return (void *) 0; -} - -static void handle_event(void * self, - int event, - const void * o) -{ - struct conn conn; - - (void) self; - - if (!(event == NOTIFY_DT_FLOW_UP || - event == NOTIFY_DT_FLOW_DOWN || - event == NOTIFY_DT_FLOW_DEALLOC)) - return; - - if (get_conn_by_fd(*((int *) o), COMPID_DT, &conn)) - return; - - switch (event) { - case NOTIFY_DT_FLOW_UP: - notifier_event(NOTIFY_DT_CONN_UP, &conn); - break; - case NOTIFY_DT_FLOW_DOWN: - notifier_event(NOTIFY_DT_CONN_DOWN, &conn); - break; - case NOTIFY_DT_FLOW_DEALLOC: - notifier_event(NOTIFY_DT_CONN_DEL, &conn); - break; - default: - break; - } -} - -int connmgr_init(void) -{ - connmgr.state = CONNMGR_INIT; - - if (notifier_reg(handle_event, NULL)) - return -1; - - return 0; -} - -void connmgr_fini(void) -{ - int i; - - notifier_unreg(handle_event); - - if (connmgr.state == CONNMGR_RUNNING) - pthread_join(connmgr.acceptor, NULL); - - for (i = 0; i < COMPID_MAX; ++i) - connmgr_comp_fini(i); -} - -int connmgr_start(void) -{ - if (pthread_create(&connmgr.acceptor, NULL, flow_acceptor, NULL)) - return -1; - - connmgr.state = CONNMGR_RUNNING; - - return 0; -} - -void connmgr_stop(void) -{ - if (connmgr.state == CONNMGR_RUNNING) - pthread_cancel(connmgr.acceptor); -} - -int connmgr_comp_init(enum comp_id id, - const struct conn_info * info) -{ - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - - comp = connmgr.comps + id; +#include <ouroboros/ipcp.h> - if (pthread_mutex_init(&comp->lock, NULL)) - return -1; +#define BUILD_IPCP_UNICAST - if (pthread_cond_init(&comp->cond, NULL)) { - pthread_mutex_destroy(&comp->lock); - return -1; - } - - list_head_init(&comp->conns); - list_head_init(&comp->pending); - - memcpy(&connmgr.comps[id].info, info, sizeof(connmgr.comps[id].info)); - - return 0; -} - -void connmgr_comp_fini(enum comp_id id) -{ - struct list_head * p; - struct list_head * h; - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - - if (strlen(connmgr.comps[id].info.comp_name) == 0) - return; - - comp = connmgr.comps + id; - - pthread_mutex_lock(&comp->lock); - - list_for_each_safe(p, h, &comp->conns) { - struct conn_el * e = list_entry(p, struct conn_el, next); - list_del(&e->next); - free(e); - } - - list_for_each_safe(p, h, &comp->pending) { - struct conn_el * e = list_entry(p, struct conn_el, next); - list_del(&e->next); - free(e); - } - - pthread_mutex_unlock(&comp->lock); - - pthread_cond_destroy(&comp->cond); - pthread_mutex_destroy(&comp->lock); - - memset(&connmgr.comps[id].info, 0, sizeof(connmgr.comps[id].info)); -} - -int connmgr_ipcp_connect(const char * dst, - const char * component, - qosspec_t qs) -{ - struct conn_el * ce; - int id; - - assert(dst); - assert(component); - - ce = malloc(sizeof(*ce)); - if (ce == NULL) { - log_dbg("Out of memory."); - return -1; - } - - id = get_id_by_name(component); - if (id < 0) { - log_dbg("No such component: %s", component); - free(ce); - return -1; - } - - if (connmgr_alloc(id, dst, &qs, &ce->conn)) { - free(ce); - return -1; - } - - if (strlen(dst) > DST_MAX_STRLEN) { - log_warn("Truncating dst length for connection."); - memcpy(ce->conn.flow_info.dst, dst, DST_MAX_STRLEN); - ce->conn.flow_info.dst[DST_MAX_STRLEN] = '\0'; - } else { - strcpy(ce->conn.flow_info.dst, dst); - } - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_add(&ce->next, &connmgr.comps[id].conns); - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -int connmgr_ipcp_disconnect(const char * dst, - const char * component) -{ - struct list_head * p; - struct list_head * h; - int id; - - assert(dst); - assert(component); - - id = get_id_by_name(component); - if (id < 0) - return -1; - - pthread_mutex_lock(&connmgr.comps[id].lock); - - list_for_each_safe(p,h, &connmgr.comps[id].conns) { - struct conn_el * el = list_entry(p, struct conn_el, next); - if (strcmp(el->conn.flow_info.dst, dst) == 0) { - int ret; - pthread_mutex_unlock(&connmgr.comps[id].lock); - list_del(&el->next); - ret = connmgr_dealloc(id, &el->conn); - free(el); - return ret; - } - } - - pthread_mutex_unlock(&connmgr.comps[id].lock); - - return 0; -} - -int connmgr_alloc(enum comp_id id, - const char * dst, - qosspec_t * qs, - struct conn * conn) -{ - assert(id >= 0 && id < COMPID_MAX); - assert(dst); - - conn->flow_info.fd = flow_alloc(dst, qs, NULL); - if (conn->flow_info.fd < 0) { - log_dbg("Failed to allocate flow to %s.", dst); - return -1; - } - - if (qs != NULL) - conn->flow_info.qs = *qs; - else - memset(&conn->flow_info.qs, 0, sizeof(conn->flow_info.qs)); - - log_dbg("Sending cacep info for protocol %s to fd %d.", - connmgr.comps[id].info.protocol, conn->flow_info.fd); - - if (cacep_snd(conn->flow_info.fd, &connmgr.comps[id].info)) { - log_dbg("Failed to create application connection."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (cacep_rcv(conn->flow_info.fd, &conn->conn_info)) { - log_dbg("Failed to connect to application."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (strcmp(connmgr.comps[id].info.protocol, conn->conn_info.protocol)) { - log_dbg("Unknown protocol (requested %s, got %s).", - connmgr.comps[id].info.protocol, - conn->conn_info.protocol); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (connmgr.comps[id].info.pref_version != - conn->conn_info.pref_version) { - log_dbg("Unknown protocol version."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - if (connmgr.comps[id].info.pref_syntax != conn->conn_info.pref_syntax) { - log_dbg("Unknown protocol syntax."); - flow_dealloc(conn->flow_info.fd); - return -1; - } - - switch (id) { - case COMPID_DT: - notifier_event(NOTIFY_DT_CONN_ADD, conn); #ifdef IPCP_CONN_WAIT_DIR - dir_wait_running(); + #include "dir.h" #endif - break; - case COMPID_MGMT: - notifier_event(NOTIFY_MGMT_CONN_ADD, conn); - break; - default: - break; - } - - return 0; -} - -int connmgr_dealloc(enum comp_id id, - struct conn * conn) -{ - switch (id) { - case COMPID_DT: - notifier_event(NOTIFY_DT_CONN_DEL, conn); - break; - case COMPID_MGMT: - notifier_event(NOTIFY_MGMT_CONN_DEL, conn); - break; - default: - break; - } - - return flow_dealloc(conn->flow_info.fd); -} - - -int connmgr_wait(enum comp_id id, - struct conn * conn) -{ - struct conn_el * el; - struct comp * comp; - - assert(id >= 0 && id < COMPID_MAX); - assert(conn); - - comp = connmgr.comps + id; - - pthread_mutex_lock(&comp->lock); - - pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, - (void *) &comp->lock); - - while (list_is_empty(&comp->pending)) - pthread_cond_wait(&comp->cond, &comp->lock); - - pthread_cleanup_pop(false); - - el = list_first_entry((&comp->pending), struct conn_el, next); - if (el == NULL) { - pthread_mutex_unlock(&comp->lock); - return -1; - } - - *conn = el->conn; - - list_del(&el->next); - list_add(&el->next, &connmgr.comps[id].conns); - - pthread_mutex_unlock(&comp->lock); - return 0; -} +#include "common/connmgr.c" diff --git a/src/ipcpd/unicast/dht.c b/src/ipcpd/unicast/dht.c index 70c3408a..3dc592db 100644 --- a/src/ipcpd/unicast/dht.c +++ b/src/ipcpd/unicast/dht.c @@ -43,7 +43,7 @@ #include <ouroboros/tpm.h> #include <ouroboros/utils.h> -#include "connmgr.h" +#include "common/connmgr.h" #include "dht.h" #include "dt.h" diff --git a/src/ipcpd/unicast/dir.h b/src/ipcpd/unicast/dir.h index 32595749..8aa79638 100644 --- a/src/ipcpd/unicast/dir.h +++ b/src/ipcpd/unicast/dir.h @@ -23,6 +23,8 @@ #ifndef OUROBOROS_IPCPD_UNICAST_DIR_H #define OUROBOROS_IPCPD_UNICAST_DIR_H +#include <inttypes.h> + int dir_init(void); void dir_fini(void); diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c index 5d2bd9ce..92496e54 100644 --- a/src/ipcpd/unicast/dt.c +++ b/src/ipcpd/unicast/dt.c @@ -41,14 +41,14 @@ #include <ouroboros/fccntl.h> #endif +#include "common/comp.h" +#include "common/connmgr.h" #include "ca.h" -#include "connmgr.h" #include "ipcp.h" #include "dt.h" #include "pff.h" #include "routing.h" #include "psched.h" -#include "comp.h" #include "fa.h" #include <stdlib.h> diff --git a/src/ipcpd/unicast/enroll.c b/src/ipcpd/unicast/enroll.c index 3abe431e..500a3895 100644 --- a/src/ipcpd/unicast/enroll.c +++ b/src/ipcpd/unicast/enroll.c @@ -1,382 +1,3 @@ -/* - * Ouroboros - Copyright (C) 2016 - 2021 - * - * Enrollment Task - * - * 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 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 BUILD_IPCP_UNICAST -#if defined(__linux__) || defined(__CYGWIN__) -#define _DEFAULT_SOURCE -#else -#define _POSIX_C_SOURCE 199309L -#endif - -#define OUROBOROS_PREFIX "enrollment" - -#include <ouroboros/endian.h> -#include <ouroboros/errno.h> -#include <ouroboros/time_utils.h> -#include <ouroboros/dev.h> -#include <ouroboros/logs.h> -#include <ouroboros/errno.h> -#include <ouroboros/sockets.h> - -#include "connmgr.h" -#include "enroll.h" -#include "ipcp.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <pthread.h> - -#include "ipcp_config.pb-c.h" -typedef EnrollMsg enroll_msg_t; - -#define ENROLL_COMP "Enrollment" -#define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */ -#define ENROLL_WARN_TIME_OFFSET 20 -#define ENROLL_BUF_LEN 1024 - -enum enroll_state { - ENROLL_NULL = 0, - ENROLL_INIT, - ENROLL_RUNNING -}; - -struct { - struct ipcp_config conf; - enum enroll_state state; - pthread_t listener; -} enroll; - -static int send_rcv_enroll_msg(int fd) -{ - enroll_msg_t req = ENROLL_MSG__INIT; - enroll_msg_t * reply; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - ssize_t delta_t; - struct timespec t0; - struct timespec rtt; - - req.code = ENROLL_CODE__ENROLL_REQ; - - len = enroll_msg__get_packed_size(&req); - if (len < 0) { - log_dbg("Failed pack request message."); - return -1; - } - - enroll_msg__pack(&req, buf); - - clock_gettime(CLOCK_REALTIME, &t0); - - if (flow_write(fd, buf, len) < 0) { - log_dbg("Failed to send request message."); - return -1; - } - - len = flow_read(fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_dbg("No enrollment reply received."); - return -1; - } - - log_dbg("Received enrollment info (%zd bytes).", len); - - reply = enroll_msg__unpack(NULL, len, buf); - if (reply == NULL) { - log_dbg("No enrollment response."); - return -1; - } - - if (reply->code != ENROLL_CODE__ENROLL_BOOT) { - log_dbg("Failed to unpack enrollment response."); - enroll_msg__free_unpacked(reply, NULL); - return -1; - } - - if (!(reply->has_t_sec && reply->has_t_nsec)) { - log_dbg("No time in response message."); - enroll_msg__free_unpacked(reply, NULL); - return -1; - } - - clock_gettime(CLOCK_REALTIME, &rtt); - - delta_t = ts_diff_ms(&t0, &rtt); - - rtt.tv_sec = reply->t_sec; - rtt.tv_nsec = reply->t_nsec; - - if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) - log_warn("Clock offset above threshold."); - - strcpy(enroll.conf.layer_info.layer_name, - reply->conf->layer_info->layer_name); - enroll.conf.type = reply->conf->ipcp_type; - enroll.conf.addr_size = reply->conf->addr_size; - enroll.conf.eid_size = reply->conf->eid_size; - enroll.conf.max_ttl = reply->conf->max_ttl; - enroll.conf.addr_auth_type = reply->conf->addr_auth_type; - enroll.conf.routing_type = reply->conf->routing_type; - enroll.conf.cong_avoid = reply->conf->cong_avoid; - enroll.conf.layer_info.dir_hash_algo - = reply->conf->layer_info->dir_hash_algo; - - enroll_msg__free_unpacked(reply, NULL); - - return 0; -} - -static ssize_t enroll_pack(uint8_t ** buf) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT; - layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT; - struct timespec now; - ssize_t len; - - clock_gettime(CLOCK_REALTIME, &now); - - msg.code = ENROLL_CODE__ENROLL_BOOT; - msg.has_t_sec = true; - msg.t_sec = now.tv_sec; - msg.has_t_nsec = true; - msg.t_nsec = now.tv_nsec; - msg.conf = &config; - - config.ipcp_type = enroll.conf.type; - config.has_addr_size = true; - config.addr_size = enroll.conf.addr_size; - config.has_eid_size = true; - config.eid_size = enroll.conf.eid_size; - config.has_max_ttl = true; - config.max_ttl = enroll.conf.max_ttl; - config.has_addr_auth_type = true; - config.addr_auth_type = enroll.conf.addr_auth_type; - config.has_routing_type = true; - config.routing_type = enroll.conf.routing_type; - config.has_cong_avoid = true; - config.cong_avoid = enroll.conf.cong_avoid; - config.layer_info = &layer_info; - - layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name; - layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo; - - len = enroll_msg__get_packed_size(&msg); - - *buf = malloc(len); - if (*buf == NULL) - return -1; - - enroll_msg__pack(&msg, *buf); - - return len; -} - -static void * enroll_handle(void * o) -{ - struct conn conn; - uint8_t buf[ENROLL_BUF_LEN]; - uint8_t * reply; - ssize_t len; - enroll_msg_t * msg; - - (void) o; - - while (true) { - if (connmgr_wait(COMPID_ENROLL, &conn)) { - log_err("Failed to get next connection."); - continue; - } - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_err("Failed to read from flow."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->code != ENROLL_CODE__ENROLL_REQ) { - log_err("Wrong message type."); - connmgr_dealloc(COMPID_ENROLL, &conn); - enroll_msg__free_unpacked(msg, NULL); - continue; - } - - log_dbg("Enrolling a new neighbor."); - - enroll_msg__free_unpacked(msg, NULL); - - len = enroll_pack(&reply); - if (reply == NULL) { - log_err("Failed to pack enrollment message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - log_dbg("Sending enrollment info (%zd bytes).", len); - - if (flow_write(conn.flow_info.fd, reply, len) < 0) { - log_err("Failed respond to enrollment request."); - connmgr_dealloc(COMPID_ENROLL, &conn); - free(reply); - continue; - } - - free(reply); - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); - if (len < 0) { - log_err("Failed to read from flow."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) { - log_err("Wrong message type."); - enroll_msg__free_unpacked(msg, NULL); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } - - if (msg->result == 0) - log_dbg("Neighbor enrollment successful."); - else - log_dbg("Neigbor reported failed enrollment."); - - enroll_msg__free_unpacked(msg, NULL); - - connmgr_dealloc(COMPID_ENROLL, &conn); - } - - return 0; -} - -int enroll_boot(struct conn * conn) -{ - log_dbg("Getting boot information."); - - if (send_rcv_enroll_msg(conn->flow_info.fd)) { - log_err("Failed to enroll."); - return -1; - } - - return 0; -} - -int enroll_done(struct conn * conn, - int result) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - - msg.code = ENROLL_CODE__ENROLL_DONE; - msg.has_result = true; - msg.result = result; - - len = enroll_msg__get_packed_size(&msg); - if (len < 0) { - log_dbg("Failed pack request message."); - return -1; - } - - enroll_msg__pack(&msg, buf); - - if (flow_write(conn->flow_info.fd, buf, len) < 0) { - log_dbg("Failed to send acknowledgment."); - return -1; - } - - return 0; -} - -void enroll_bootstrap(const struct ipcp_config * conf) -{ - assert(conf); - - memcpy(&enroll.conf, conf, sizeof(enroll.conf)); -} - -struct ipcp_config * enroll_get_conf(void) -{ - return &enroll.conf; -} - -int enroll_init(void) -{ - struct conn_info info; - - memset(&info, 0, sizeof(info)); - - strcpy(info.comp_name, ENROLL_COMP); - strcpy(info.protocol, ENROLL_PROTO); - info.pref_version = 1; - info.pref_syntax = PROTO_GPB; - info.addr = 0; - - if (connmgr_comp_init(COMPID_ENROLL, &info)) { - log_err("Failed to register with connmgr."); - return -1; - } - - enroll.state = ENROLL_INIT; - - return 0; -} - -void enroll_fini(void) -{ - if (enroll.state == ENROLL_RUNNING) - pthread_join(enroll.listener, NULL); - - connmgr_comp_fini(COMPID_ENROLL); -} - -int enroll_start(void) -{ - if (pthread_create(&enroll.listener, NULL, enroll_handle, NULL)) - return -1; - - enroll.state = ENROLL_RUNNING; - - return 0; -} - -void enroll_stop(void) -{ - if (enroll.state == ENROLL_RUNNING) - pthread_cancel(enroll.listener); -} +#include "common/enroll.c" diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c index 050b9229..96df1664 100644 --- a/src/ipcpd/unicast/main.c +++ b/src/ipcpd/unicast/main.c @@ -29,6 +29,7 @@ #include "config.h" #define OUROBOROS_PREFIX "unicast-ipcp" +#define THIS_TYPE IPCP_UNICAST #include <ouroboros/errno.h> #include <ouroboros/hash.h> @@ -38,12 +39,12 @@ #include <ouroboros/rib.h> #include <ouroboros/time_utils.h> +#include "common/connmgr.h" +#include "common/enroll.h" #include "addr_auth.h" #include "ca.h" -#include "connmgr.h" #include "dir.h" #include "dt.h" -#include "enroll.h" #include "fa.h" #include "ipcp.h" @@ -54,8 +55,6 @@ #include <assert.h> #include <inttypes.h> -#define THIS_TYPE IPCP_UNICAST - struct ipcp ipcpi; static int initialize_components(const struct ipcp_config * conf) diff --git a/src/ipcpd/unicast/pol/link_state.c b/src/ipcpd/unicast/pol/link_state.c index 18729a7c..e8983ec6 100644 --- a/src/ipcpd/unicast/pol/link_state.c +++ b/src/ipcpd/unicast/pol/link_state.c @@ -41,8 +41,8 @@ #include <ouroboros/rib.h> #include <ouroboros/utils.h> -#include "comp.h" -#include "connmgr.h" +#include "common/comp.h" +#include "common/connmgr.h" #include "graph.h" #include "ipcp.h" #include "link_state.h" diff --git a/src/ipcpd/unicast/psched.c b/src/ipcpd/unicast/psched.c index facc495c..33ac5afe 100644 --- a/src/ipcpd/unicast/psched.c +++ b/src/ipcpd/unicast/psched.c @@ -31,9 +31,9 @@ #include <ouroboros/errno.h> #include <ouroboros/notifier.h> +#include "common/connmgr.h" #include "ipcp.h" #include "psched.h" -#include "connmgr.h" #include <assert.h> #include <sched.h> |