diff options
Diffstat (limited to 'src/irmd/ipcp.c')
-rw-r--r-- | src/irmd/ipcp.c | 468 |
1 files changed, 224 insertions, 244 deletions
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c index ae5325c5..5a9a79d3 100644 --- a/src/irmd/ipcp.c +++ b/src/irmd/ipcp.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2021 + * Ouroboros - Copyright (C) 2016 - 2024 * * The API to instruct IPCPs * @@ -20,195 +20,182 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#define _POSIX_C_SOURCE 199309L +#define _POSIX_C_SOURCE 200112L #include "config.h" #define OUROBOROS_PREFIX "irmd/ipcp" -#include <ouroboros/logs.h> #include <ouroboros/errno.h> -#include <ouroboros/utils.h> +#include <ouroboros/flow.h> +#include <ouroboros/logs.h> #include <ouroboros/sockets.h> +#include <ouroboros/time.h> +#include <ouroboros/utils.h> #include "ipcp.h" -#include <stdlib.h> -#include <string.h> +#include <fcntl.h> +#include <pthread.h> #include <signal.h> +#include <spawn.h> #include <stdbool.h> -#include <pthread.h> +#include <stdlib.h> +#include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/socket.h> #include <sys/time.h> -#include <spawn.h> -ipcp_msg_t * send_recv_ipcp_msg(pid_t pid, - ipcp_msg_t * msg) +static char * str_ipcp_cmd(int code) { - int sockfd = 0; - uint8_t buf[SOCK_BUF_SIZE]; - char * sock_path = NULL; - ssize_t len; - ipcp_msg_t * recv_msg = NULL; - struct timeval tv; - - if (kill(pid, 0) < 0) - return NULL; - - sock_path = ipcp_sock_path(pid); - if (sock_path == NULL) - return NULL; - - sockfd = client_socket_open(sock_path); - if (sockfd < 0) { - free(sock_path); - return NULL; - } - - free(sock_path); - - len = ipcp_msg__get_packed_size(msg); - if (len == 0) { - close(sockfd); - return NULL; - } - - switch (msg->code) { - case IPCP_MSG_CODE__IPCP_BOOTSTRAP: - tv.tv_sec = BOOTSTRAP_TIMEOUT / 1000; - tv.tv_usec = (BOOTSTRAP_TIMEOUT % 1000) * 1000; - break; - case IPCP_MSG_CODE__IPCP_ENROLL: - tv.tv_sec = ENROLL_TIMEOUT / 1000; - tv.tv_usec = (ENROLL_TIMEOUT % 1000) * 1000; - break; - case IPCP_MSG_CODE__IPCP_REG: - tv.tv_sec = REG_TIMEOUT / 1000; - tv.tv_usec = (REG_TIMEOUT % 1000) * 1000; - break; - case IPCP_MSG_CODE__IPCP_QUERY: - tv.tv_sec = QUERY_TIMEOUT / 1000; - tv.tv_usec = (QUERY_TIMEOUT % 1000) * 1000; - break; - case IPCP_MSG_CODE__IPCP_CONNECT: - tv.tv_sec = CONNECT_TIMEOUT / 1000; - tv.tv_usec = (CONNECT_TIMEOUT % 1000) * 1000; - break; - default: - tv.tv_sec = SOCKET_TIMEOUT / 1000; - tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000; - break; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, - (void *) &tv, sizeof(tv))) - log_warn("Failed to set timeout on socket."); - - pthread_cleanup_push(__cleanup_close_ptr, (void *) &sockfd); - - ipcp_msg__pack(msg, buf); - - if (write(sockfd, buf, len) != -1) - len = read(sockfd, buf, SOCK_BUF_SIZE); - - if (len > 0) - recv_msg = ipcp_msg__unpack(NULL, len, buf); - - pthread_cleanup_pop(true); - - return recv_msg; + switch (code) { + case IPCP_MSG_CODE__IPCP_BOOTSTRAP: + return "bootstrap"; + case IPCP_MSG_CODE__IPCP_ENROLL: + return "enroll"; + case IPCP_MSG_CODE__IPCP_CONNECT: + return "connect"; + case IPCP_MSG_CODE__IPCP_DISCONNECT: + return "disconnect"; + case IPCP_MSG_CODE__IPCP_REG: + return "reg"; + case IPCP_MSG_CODE__IPCP_UNREG: + return "unreg"; + case IPCP_MSG_CODE__IPCP_QUERY: + return "query"; + case IPCP_MSG_CODE__IPCP_FLOW_JOIN: + return "join"; + case IPCP_MSG_CODE__IPCP_FLOW_ALLOC: + return "alloc"; + case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP: + return "alloc_resp"; + case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC: + return "dealloc"; + default: + assert(false); + return "unknown"; + } } -pid_t ipcp_create(const char * name, - enum ipcp_type ipcp_type) +ipcp_msg_t * send_recv_ipcp_msg(pid_t pid, + ipcp_msg_t * msg) { - pid_t pid = -1; - char * ipcp_dir = "/sbin/"; - char * exec_name = NULL; - char irmd_pid[10]; - char full_name[256]; - char * argv[5]; - - switch(ipcp_type) { - case IPCP_UNICAST: - exec_name = IPCP_UNICAST_EXEC; + int sockfd; + uint8_t buf[SOCK_BUF_SIZE]; + char * sock_path; + ssize_t len; + ipcp_msg_t * recv_msg; + struct timeval tv; + struct timespec tic; + struct timespec toc; + bool dealloc = false; + + if (kill(pid, 0) < 0) + return NULL; + + sock_path = ipcp_sock_path(pid); + if (sock_path == NULL) + return NULL; + + sockfd = client_socket_open(sock_path); + if (sockfd < 0) { + free(sock_path); + return NULL; + } + + free(sock_path); + + len = ipcp_msg__get_packed_size(msg); + if (len == 0 || len >= SOCK_BUF_SIZE) { + log_warn("IPCP message has invalid size: %zd.", len); + close(sockfd); + return NULL; + } + + switch (msg->code) { + case IPCP_MSG_CODE__IPCP_BOOTSTRAP: + tv.tv_sec = BOOTSTRAP_TIMEOUT / 1000; + tv.tv_usec = (BOOTSTRAP_TIMEOUT % 1000) * 1000; + break; + case IPCP_MSG_CODE__IPCP_ENROLL: + tv.tv_sec = ENROLL_TIMEOUT / 1000; + tv.tv_usec = (ENROLL_TIMEOUT % 1000) * 1000; break; - case IPCP_BROADCAST: - exec_name = IPCP_BROADCAST_EXEC; + case IPCP_MSG_CODE__IPCP_REG: + tv.tv_sec = REG_TIMEOUT / 1000; + tv.tv_usec = (REG_TIMEOUT % 1000) * 1000; break; - case IPCP_UDP: - exec_name = IPCP_UDP_EXEC; + case IPCP_MSG_CODE__IPCP_QUERY: + tv.tv_sec = QUERY_TIMEOUT / 1000; + tv.tv_usec = (QUERY_TIMEOUT % 1000) * 1000; break; - case IPCP_ETH_LLC: - exec_name = IPCP_ETH_LLC_EXEC; + case IPCP_MSG_CODE__IPCP_CONNECT: + tv.tv_sec = CONNECT_TIMEOUT / 1000; + tv.tv_usec = (CONNECT_TIMEOUT % 1000) * 1000; break; - case IPCP_ETH_DIX: - exec_name = IPCP_ETH_DIX_EXEC; + case IPCP_MSG_CODE__IPCP_FLOW_ALLOC: + tv.tv_sec = FLOW_ALLOC_TIMEOUT / 1000; + tv.tv_usec = (FLOW_ALLOC_TIMEOUT % 1000) * 1000; break; - case IPCP_LOCAL: - exec_name = IPCP_LOCAL_EXEC; + case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC: + dealloc = true; + tv.tv_sec = 0; /* FIX DEALLOC: don't wait for dealloc */ + tv.tv_usec = 500; break; default: - return -1; + tv.tv_sec = SOCKET_TIMEOUT / 1000; + tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000; + break; } - if (strlen(exec_name) == 0) { - log_err("IPCP type not installed."); - return -1; - } + if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, + (void *) &tv, sizeof(tv))) + log_warn("Failed to set timeout on socket."); - sprintf(irmd_pid, "%u", getpid()); + pthread_cleanup_push(__cleanup_close_ptr, (void *) &sockfd); - strcpy(full_name, INSTALL_PREFIX); - strcat(full_name, ipcp_dir); - strcat(full_name, exec_name); + ipcp_msg__pack(msg, buf); - /* log_file to be placed at the end */ - argv[0] = full_name; - argv[1] = irmd_pid; - argv[2] = (char *) name; - if (log_syslog) - argv[3] = "1"; - else - argv[3] = NULL; + clock_gettime(CLOCK_REALTIME, &tic); - argv[4] = NULL; + if (write(sockfd, buf, len) != -1) + len = read(sockfd, buf, SOCK_BUF_SIZE); - if (posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL)) { - log_err("Failed to spawn new process"); - return -1; - } + clock_gettime(CLOCK_REALTIME, &toc); - return pid; -} + pthread_cleanup_pop(true); /* close socket */ -int ipcp_destroy(pid_t pid) -{ - if (kill(pid, SIGTERM)) { - log_err("Failed to destroy IPCP"); - return -1; + if (len > 0) + recv_msg = ipcp_msg__unpack(NULL, len, buf); + else { + if (errno == EAGAIN && !dealloc) { + int diff = ts_diff_ms(&tic, &toc); + log_warn("IPCP %s timed out after %d ms.", + str_ipcp_cmd(msg->code), diff); + } + return NULL; } - return 0; + return recv_msg; } -int ipcp_bootstrap(pid_t pid, - ipcp_config_msg_t * conf, - struct layer_info * info) +int ipcp_bootstrap(pid_t pid, + struct ipcp_config * conf, + struct layer_info * info) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; if (conf == NULL) return -EINVAL; msg.code = IPCP_MSG_CODE__IPCP_BOOTSTRAP; - msg.conf = conf; + msg.conf = ipcp_config_s_to_msg(conf); recv_msg = send_recv_ipcp_msg(pid, &msg); + ipcp_config_msg__free_unpacked(msg.conf, NULL); if (recv_msg == NULL) return -EIPCP; @@ -229,7 +216,7 @@ int ipcp_bootstrap(pid_t pid, } info->dir_hash_algo = recv_msg->layer_info->dir_hash_algo; - strcpy(info->layer_name, recv_msg->layer_info->layer_name); + strcpy(info->name, recv_msg->layer_info->name); ret = recv_msg->result; ipcp_msg__free_unpacked(recv_msg, NULL); @@ -241,9 +228,9 @@ int ipcp_enroll(pid_t pid, const char * dst, struct layer_info * info) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; if (dst == NULL) return -EINVAL; @@ -272,7 +259,7 @@ int ipcp_enroll(pid_t pid, } info->dir_hash_algo = recv_msg->layer_info->dir_hash_algo; - strcpy(info->layer_name, recv_msg->layer_info->layer_name); + strcpy(info->name, recv_msg->layer_info->name); ipcp_msg__free_unpacked(recv_msg, NULL); @@ -284,20 +271,19 @@ int ipcp_connect(pid_t pid, const char * component, qosspec_t qs) { - ipcp_msg_t msg = IPCP_MSG__INIT; - qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_CONNECT; msg.dst = (char *) dst; msg.comp = (char *) component; msg.has_pid = true; msg.pid = pid; - qs_msg = spec_to_msg(&qs); - msg.qosspec = &qs_msg; + msg.qosspec = qos_spec_s_to_msg(&qs); recv_msg = send_recv_ipcp_msg(pid, &msg); + free(msg.qosspec); if (recv_msg == NULL) return -EIPCP; @@ -316,9 +302,9 @@ int ipcp_disconnect(pid_t pid, const char * dst, const char * component) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_DISCONNECT; msg.dst = (char *) dst; @@ -341,20 +327,17 @@ int ipcp_disconnect(pid_t pid, return ret; } -int ipcp_reg(pid_t pid, - const uint8_t * hash, - size_t len) +int ipcp_reg(pid_t pid, + const buffer_t hash) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; - - assert(hash); + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_REG; msg.has_hash = true; - msg.hash.len = len; - msg.hash.data = (uint8_t *)hash; + msg.hash.data = (uint8_t *) hash.data; + msg.hash.len = hash.len; recv_msg = send_recv_ipcp_msg(pid, &msg); if (recv_msg == NULL) @@ -371,18 +354,17 @@ int ipcp_reg(pid_t pid, return ret; } -int ipcp_unreg(pid_t pid, - const uint8_t * hash, - size_t len) +int ipcp_unreg(pid_t pid, + const buffer_t hash) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_UNREG; msg.has_hash = true; - msg.hash.len = len; - msg.hash.data = (uint8_t *) hash; + msg.hash.data = (uint8_t *) hash.data; + msg.hash.len = hash.len; recv_msg = send_recv_ipcp_msg(pid, &msg); if (recv_msg == NULL) @@ -399,18 +381,17 @@ int ipcp_unreg(pid_t pid, return ret; } -int ipcp_query(pid_t pid, - const uint8_t * hash, - size_t len) +int ipcp_query(pid_t pid, + const buffer_t dst) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_QUERY; msg.has_hash = true; - msg.hash.len = len; - msg.hash.data = (uint8_t *) hash; + msg.hash.data = (uint8_t *) dst.data; + msg.hash.len = dst.len; recv_msg = send_recv_ipcp_msg(pid, &msg); if (recv_msg == NULL) @@ -427,39 +408,25 @@ int ipcp_query(pid_t pid, return ret; } -static int __ipcp_flow_alloc(pid_t pid, - int flow_id, - pid_t n_pid, - const uint8_t * dst, - size_t len, - qosspec_t qs, - bool join, - const void * data, - size_t dlen) +int ipcp_flow_join(const struct flow_info * flow, + const buffer_t dst) { - ipcp_msg_t msg = IPCP_MSG__INIT; - qosspec_msg_t qs_msg; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; - assert(dst); - - msg.code = join ? IPCP_MSG_CODE__IPCP_FLOW_JOIN - : IPCP_MSG_CODE__IPCP_FLOW_ALLOC; + msg.code = IPCP_MSG_CODE__IPCP_FLOW_JOIN; msg.has_flow_id = true; - msg.flow_id = flow_id; + msg.flow_id = flow->id; msg.has_pid = true; - msg.pid = n_pid; + msg.pid = flow->n_pid; msg.has_hash = true; - msg.hash.len = len; - msg.hash.data = (uint8_t *) dst; - qs_msg = spec_to_msg(&qs); - msg.qosspec = &qs_msg; - msg.has_pk = true; - msg.pk.data = (uint8_t *) data; - msg.pk.len = (uint32_t) dlen; + msg.hash.data = (uint8_t *) dst.data; + msg.hash.len = dst.len; + msg.has_pk = false; - recv_msg = send_recv_ipcp_msg(pid, &msg); + recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg); + free(msg.qosspec); if (recv_msg == NULL) return -EIPCP; @@ -474,53 +441,66 @@ static int __ipcp_flow_alloc(pid_t pid, return ret; } -int ipcp_flow_alloc(pid_t pid, - int flow_id, - pid_t n_pid, - const uint8_t * dst, - size_t len, - qosspec_t qs, - const void * data, - size_t dlen) +int ipcp_flow_alloc(const struct flow_info * flow, + const buffer_t dst, + const buffer_t data) { - return __ipcp_flow_alloc(pid, flow_id, n_pid, dst, len, qs, false, - data, dlen); -} + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; -int ipcp_flow_join(pid_t pid, - int flow_id, - pid_t n_pid, - const uint8_t * dst, - size_t len, - qosspec_t qs) -{ - return __ipcp_flow_alloc(pid, flow_id, n_pid, dst, len, qs, true, - NULL, 0); + msg.code = IPCP_MSG_CODE__IPCP_FLOW_ALLOC; + msg.has_flow_id = true; + msg.flow_id = flow->id; + msg.has_pid = true; + msg.pid = flow->n_pid; + msg.qosspec = qos_spec_s_to_msg(&flow->qs); + msg.has_hash = true; + msg.hash.data = (uint8_t *) dst.data; + msg.hash.len = dst.len; + msg.has_pk = true; + msg.pk.data = data.data; + msg.pk.len = data.len; + + recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg); + free(msg.qosspec); + if (recv_msg == NULL) { + log_err("Did not receive message."); + return -EIPCP; + } + + if (!recv_msg->has_result) { + log_err("Message has no result"); + ipcp_msg__free_unpacked(recv_msg, NULL); + return -EIPCP; + } + + ret = recv_msg->result; + ipcp_msg__free_unpacked(recv_msg, NULL); + + return ret; } -int ipcp_flow_alloc_resp(pid_t pid, - int flow_id, - pid_t n_pid, - int response, - const void * data, - size_t len) +int ipcp_flow_alloc_resp(const struct flow_info * flow, + int response, + const buffer_t data) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP; msg.has_flow_id = true; - msg.flow_id = flow_id; + msg.flow_id = flow->id; msg.has_pid = true; - msg.pid = n_pid; + msg.pid = flow->n_pid; msg.has_response = true; msg.response = response; msg.has_pk = true; - msg.pk.data = (uint8_t *) data; - msg.pk.len = (uint32_t) len; + msg.pk.data = data.data; + msg.pk.len = data.len; - recv_msg = send_recv_ipcp_msg(pid, &msg); + recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg); if (recv_msg == NULL) return -EIPCP; @@ -539,9 +519,9 @@ int ipcp_flow_dealloc(pid_t pid, int flow_id, time_t timeo) { - ipcp_msg_t msg = IPCP_MSG__INIT; - ipcp_msg_t * recv_msg = NULL; - int ret = -1; + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; msg.code = IPCP_MSG_CODE__IPCP_FLOW_DEALLOC; msg.has_flow_id = true; |