diff --git a/config/agent/agent.conf b/config/agent/agent.conf index b8dbd2ff8b..cd5b3e5a19 100644 --- a/config/agent/agent.conf +++ b/config/agent/agent.conf @@ -42,6 +42,20 @@ #LogIsQuiet=false # Enables or disables extended, reliable error message passing for the peer connection with the -# controller. For example, if set to true, the peer connection will be dropped instantly on -# Host unreachable errors. +# controller by setting the IP_RECVERR socket option. For example, if set to true, the peer connection +# will be dropped instantly on Host Unreachable errors. #IPReceiveErrors=true + +# +# Number of seconds the TCP connection with the controller needs to be idle before keepalive packets are sent. +# Value is set to socket option TCP_KEEPIDLE. +#TCPKeepAliveTime=1 + +# +# Number of seconds between each keepalive packet. Value is set to socket option TCP_KEEPINTVL. +#TCPKeepAliveInterval=1 + +# +# Number of keepalive packets without ACK from the controller till the connection is dropped. Value is +# set to socket option TCP_KEEPCNT. +#TCPKeepAliveCount=6 diff --git a/config/controller/controller.conf b/config/controller/controller.conf index 6da17f0d8b..29de5ee700 100644 --- a/config/controller/controller.conf +++ b/config/controller/controller.conf @@ -28,7 +28,21 @@ # If this flag is set to true, no logs are written by bluechi. #LogIsQuiet=false -# Enables or disables extended, reliable error message passing for the peer connection with -# the agent. For example, if set to true, the peer connection will be dropped instantly on -# Host unreachable errors. +# Enables or disables extended, reliable error message passing for the peer connection with the +# agent by setting the IP_RECVERR socket option. For example, if set to true, the peer connection +# will be dropped instantly on Host Unreachable errors. #IPReceiveErrors=true + +# +# Number of seconds the TCP connection with the agent needs to be idle before keepalive packets are sent. +# Value is set to socket option TCP_KEEPIDLE. +#TCPKeepAliveTime=1 + +# +# Number of seconds between each keepalive packet. Value is set to socket option TCP_KEEPINTVL. +#TCPKeepAliveInterval=1 + +# +# Number of keepalive packets without ACK from the agent till the peer connection is dropped. Value is +# set to socket option TCP_KEEPCNT. +#TCPKeepAliveCount=6 diff --git a/doc/man/bluechi-agent.conf.5.md b/doc/man/bluechi-agent.conf.5.md index 7118a7ceef..ff3c12982d 100644 --- a/doc/man/bluechi-agent.conf.5.md +++ b/doc/man/bluechi-agent.conf.5.md @@ -72,7 +72,27 @@ If this flag is set to `true`, it enables extended, reliable error message passi the peer connection with the controller. This results in BlueChi receiving errors such as host unreachable ICMP packets instantly and possibly dropping the connection. This is useful to detect disconnects faster, but should be used with care as this might cause -unnecessary disconnects in less robut networks. Default: true. +unnecessary disconnects in less robut networks. +Default: true. + +#### **TCPKeepAliveTime** (long) + +The number of seconds the TCP connection of the agent with the controller needs to be idle before +keepalive packets are sent. When `TCPKeepAliveTime` is set to 0, the system default will be used. +Default: 1s. + +#### **TCPKeepAliveInterval** (long) + +The number of seconds between each keepalive packet. When `TCPKeepAliveInterval` is set to 0, +the system default will be used. +Default: 1s. + +#### **TCPKeepAliveCount** (long) + +The number of keepalive packets without ACK from the controller till the connection is +dropped. When `TCPKeepAliveCount` is set to 0, the system default will be used. +Default: 6. + ## Example diff --git a/doc/man/bluechi-controller.conf.5.md b/doc/man/bluechi-controller.conf.5.md index 3146a12926..a24c80b5f2 100644 --- a/doc/man/bluechi-controller.conf.5.md +++ b/doc/man/bluechi-controller.conf.5.md @@ -58,8 +58,27 @@ If this flag is set to `true`, it enables extended, reliable error message passi the peer connection with all agents. This results in BlueChi receiving errors such as host unreachable ICMP packets instantly and possibly dropping the connection. This is useful to detect disconnects faster, but should be used with care as this might cause -unnecessary disconnects in less robut networks. Default: true. +unnecessary disconnects in less robut networks. +Default: true. +#### **TCPKeepAliveTime** (long) + +The number of seconds the individual TCP connection with an agent needs to be idle +before keepalive packets are sent. When `TCPKeepAliveTime` is set to 0, the system +default will be used. +Default: 1s. + +#### **TCPKeepAliveInterval** (long) + +The number of seconds between each keepalive packet. When `TCPKeepAliveInterval` is set to 0, +the system default will be used. +Default: 1s. + +#### **TCPKeepAliveCount** (long) + +The number of keepalive packets without ACK from an agent till the individual connection is dropped. +When `TCPKeepAliveCount` is set to 0, the system default will be used. +Default: 6. ## Example diff --git a/src/agent/agent.c b/src/agent/agent.c index 3acd6022e3..1b93e68097 100644 --- a/src/agent/agent.c +++ b/src/agent/agent.c @@ -390,10 +390,24 @@ Agent *agent_new(void) { return NULL; } + _cleanup_free_ SocketOptions *socket_opts = socket_options_new(); + if (socket_opts == NULL) { + bc_log_error("Out of memory"); + return NULL; + } + + struct hashmap *unit_infos = hashmap_new( + sizeof(AgentUnitInfo), 0, 0, 0, unit_info_hash, unit_info_compare, unit_info_clear, NULL); + if (unit_infos == NULL) { + return NULL; + } + _cleanup_agent_ Agent *agent = malloc0(sizeof(Agent)); agent->ref_count = 1; agent->event = steal_pointer(&event); agent->api_bus_service_name = steal_pointer(&service_name); + agent->peer_socket_options = steal_pointer(&socket_opts); + agent->unit_infos = unit_infos; LIST_HEAD_INIT(agent->outstanding_requests); LIST_HEAD_INIT(agent->tracked_jobs); LIST_HEAD_INIT(agent->proxy_services); @@ -408,7 +422,6 @@ Agent *agent_new(void) { agent->connection_retry_count = 0; agent->wildcard_subscription_active = false; agent->metrics_enabled = false; - agent->ip_receive_errors = false; agent->disconnect_timestamp = 0; return steal_pointer(&agent); @@ -624,7 +637,35 @@ bool agent_parse_config(Agent *agent, const char *configfile) { } } - agent->ip_receive_errors = cfg_get_bool_value(agent->config, CFG_IP_RECEIVE_ERRORS); + /* Set socket options used for peer connections with the agents */ + const char *keepidle = cfg_get_value(agent->config, CFG_TCP_KEEPALIVE_TIME); + if (keepidle) { + if (socket_options_set_tcp_keepidle(agent->peer_socket_options, keepidle) < 0) { + bc_log_error("Failed to set TCP KEEPIDLE"); + return false; + } + } + const char *keepintvl = cfg_get_value(agent->config, CFG_TCP_KEEPALIVE_INTERVAL); + if (keepintvl) { + if (socket_options_set_tcp_keepintvl(agent->peer_socket_options, keepintvl) < 0) { + bc_log_error("Failed to set TCP KEEPINTVL"); + return false; + } + } + const char *keepcnt = cfg_get_value(agent->config, CFG_TCP_KEEPALIVE_COUNT); + if (keepcnt) { + if (socket_options_set_tcp_keepcnt(agent->peer_socket_options, keepcnt) < 0) { + bc_log_error("Failed to set TCP KEEPCNT"); + return false; + } + } + if (socket_options_set_ip_recverr( + agent->peer_socket_options, + cfg_get_bool_value(agent->config, CFG_IP_RECEIVE_ERRORS)) < 0) { + bc_log_error("Failed to set IP RECVERR"); + return false; + } + _cleanup_free_ const char *dumped_cfg = cfg_dump(agent->config); bc_log_debug_with_data("Final configuration used", "\n%s", dumped_cfg); @@ -2394,23 +2435,9 @@ static bool agent_connect(Agent *agent) { return false; } - int r = bus_socket_set_no_delay(agent->peer_dbus); - if (r < 0) { - bc_log_warn("Failed to set NO_DELAY on socket"); - } - - r = bus_socket_set_keepalive(agent->peer_dbus); - if (r < 0) { - bc_log_warn("Failed to set KEEPALIVE on socket"); - } - if (agent->ip_receive_errors) { - r = bus_socket_enable_recv_err(agent->peer_dbus); - if (r < 0) { - bc_log_warnf("Failed to enable receiving errors on socket: %s", strerror(-r)); - } - } + bus_socket_set_options(agent->peer_dbus, agent->peer_socket_options); - r = sd_bus_add_object_vtable( + int r = sd_bus_add_object_vtable( agent->peer_dbus, NULL, INTERNAL_AGENT_OBJECT_PATH, diff --git a/src/agent/agent.h b/src/agent/agent.h index 4567f187eb..4d2bd4870b 100644 --- a/src/agent/agent.h +++ b/src/agent/agent.h @@ -9,6 +9,7 @@ #include "libbluechi/common/cfg.h" #include "libbluechi/common/common.h" +#include "libbluechi/socket.h" #include "types.h" @@ -65,7 +66,7 @@ struct Agent { bool metrics_enabled; - bool ip_receive_errors; + SocketOptions *peer_socket_options; sd_event *event; diff --git a/src/libbluechi/bus/utils.c b/src/libbluechi/bus/utils.c index 829c46aa7d..ad1248e6db 100644 --- a/src/libbluechi/bus/utils.c +++ b/src/libbluechi/bus/utils.c @@ -1,18 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include -#include #include -#include "utils.h" - #include "libbluechi/common/string-util.h" -/* Number of seconds idle before sending keepalive packets */ -#define AGENT_KEEPALIVE_SOCKET_KEEPIDLE_SECS 1 - -/* Number of seconds idle between each keepalive packet */ -#define AGENT_KEEPALIVE_SOCKET_KEEPINTVL_SECS 1 +#include "utils.h" int bus_parse_properties_foreach(sd_bus_message *m, bus_property_cb cb, void *userdata) { bool stop = false; @@ -280,82 +273,13 @@ char *bus_path_escape(const char *s) { return r; } -static bool is_socket_tcp(int fd) { - int type = 0; - socklen_t length = sizeof(int); - - getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &type, &length); - - return type == AF_INET || type == AF_INET6; -} - -int bus_socket_set_no_delay(sd_bus *bus) { - int fd = sd_bus_get_fd(bus); - if (fd < 0) { - return fd; - } - - if (!is_socket_tcp(fd)) { - return 0; - } - - int flag = 1; - int r = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); - if (r < 0) { - return -errno; - } - - return 0; -} - -int bus_socket_set_keepalive(sd_bus *bus) { +int bus_socket_set_options(sd_bus *bus, SocketOptions *opts) { int fd = sd_bus_get_fd(bus); if (fd < 0) { return fd; } - if (!is_socket_tcp(fd)) { - return 0; - } - - int flag = 1; - int r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)); - if (r < 0) { - return -errno; - } - - int keepidle = AGENT_KEEPALIVE_SOCKET_KEEPIDLE_SECS; - r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(int)); - if (r < 0) { - return -errno; - } - - int keepintvl = AGENT_KEEPALIVE_SOCKET_KEEPINTVL_SECS; - r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(int)); - if (r < 0) { - return -errno; - } - - return 0; -} - -int bus_socket_enable_recv_err(sd_bus *bus) { - int fd = sd_bus_get_fd(bus); - if (fd < 0) { - return fd; - } - - if (!is_socket_tcp(fd)) { - return -EINVAL; - } - - int flag = 1; - int r = setsockopt(fd, IPPROTO_IP, IP_RECVERR, &flag, sizeof(int)); - if (r < 0) { - return -errno; - } - - return 0; + return socket_set_options(fd, opts); } /* diff --git a/src/libbluechi/bus/utils.h b/src/libbluechi/bus/utils.h index dbb68fe1a1..55a76da5f1 100644 --- a/src/libbluechi/bus/utils.h +++ b/src/libbluechi/bus/utils.h @@ -5,6 +5,7 @@ #include #include "libbluechi/common/common.h" +#include "libbluechi/socket.h" /* return < 0 for error, 0 to continue, 1 to stop, 2 to continue and skip (if value was not consumed) */ typedef int (*bus_property_cb)(const char *key, const char *value_type, sd_bus_message *m, void *userdata); @@ -40,9 +41,7 @@ void unit_unref(UnitInfo *unit); int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); int bus_parse_unit_on_node_info(sd_bus_message *message, UnitInfo *u); -int bus_socket_set_no_delay(sd_bus *bus); -int bus_socket_set_keepalive(sd_bus *bus); -int bus_socket_enable_recv_err(sd_bus *bus); +int bus_socket_set_options(sd_bus *bus, SocketOptions *opts); bool bus_id_is_valid(const char *name); diff --git a/src/libbluechi/common/cfg.c b/src/libbluechi/common/cfg.c index 5be426580a..6924f9e4ee 100644 --- a/src/libbluechi/common/cfg.c +++ b/src/libbluechi/common/cfg.c @@ -417,6 +417,19 @@ static int cfg_def_conf(struct config *config) { return result; } + if ((result = cfg_set_value(config, CFG_TCP_KEEPALIVE_TIME, BC_DEFAULT_TCP_KEEPALIVE_TIME)) != 0) { + return result; + } + + if ((result = cfg_set_value(config, CFG_TCP_KEEPALIVE_INTERVAL, BC_DEFAULT_TCP_KEEPALIVE_INTERVAL)) != + 0) { + return result; + } + + if ((result = cfg_set_value(config, CFG_TCP_KEEPALIVE_COUNT, BC_DEFAULT_TCP_KEEPALIVE_COUNT)) != 0) { + return result; + } + return 0; } @@ -439,7 +452,8 @@ int cfg_agent_def_conf(struct config *config) { return result; } - if ((result = cfg_set_value(config, CFG_HEARTBEAT_INTERVAL, AGENT_HEARTBEAT_INTERVAL_MSEC)) != 0) { + if ((result = cfg_set_value(config, CFG_HEARTBEAT_INTERVAL, AGENT_DEFAULT_HEARTBEAT_INTERVAL_MSEC)) != + 0) { return result; } diff --git a/src/libbluechi/common/cfg.h b/src/libbluechi/common/cfg.h index 1dc399461f..78a8f3d190 100644 --- a/src/libbluechi/common/cfg.h +++ b/src/libbluechi/common/cfg.h @@ -18,6 +18,9 @@ #define CFG_ALLOWED_NODE_NAMES "AllowedNodeNames" #define CFG_HEARTBEAT_INTERVAL "HeartbeatInterval" #define CFG_IP_RECEIVE_ERRORS "IPReceiveErrors" +#define CFG_TCP_KEEPALIVE_TIME "TCPKeepAliveTime" +#define CFG_TCP_KEEPALIVE_INTERVAL "TCPKeepAliveInterval" +#define CFG_TCP_KEEPALIVE_COUNT "TCPKeepAliveCount" /* * Global section - this is used, when configuration options are specified in the configuration file diff --git a/src/libbluechi/common/protocol.h b/src/libbluechi/common/protocol.h index 5f78cc504e..ade259cc4a 100644 --- a/src/libbluechi/common/protocol.h +++ b/src/libbluechi/common/protocol.h @@ -3,14 +3,32 @@ #include +/* Time constants */ +#define USEC_PER_SEC 1000000 +#define USEC_PER_MSEC 1000 + +/* Configuration defaults */ #define BC_DEFAULT_PORT "842" #define BC_DEFAULT_HOST "127.0.0.1" -/* Enable extended reliable error message passing */ +/* Number of seconds idle before sending keepalive packets. Value is set to socket option TCP_KEEPIDLE. */ +#define BC_DEFAULT_TCP_KEEPALIVE_TIME "1" +/* Number of seconds idle between each keepalive packet. Value is set to socket option TCP_KEEPINTVL. */ +#define BC_DEFAULT_TCP_KEEPALIVE_INTERVAL "1" +/* Number of keepalive packets without ACK till connection is dropped. Value is set to socket option TCP_KEEPCNT. */ +#define BC_DEFAULT_TCP_KEEPALIVE_COUNT "6" +/* Enable extended reliable error message passing. Sets the socket option IP_RECVERR. */ #define BC_DEFAULT_IP_RECEIVE_ERROR "true" +/* High-level timeout for DBus calls */ +#define BC_DEFAULT_DBUS_TIMEOUT ((uint64_t) (USEC_PER_SEC * 30)) +/* Application-level heartbeat interval */ +#define AGENT_DEFAULT_HEARTBEAT_INTERVAL_MSEC "2000" + +/* BlueChi DBus service names */ #define BC_DBUS_NAME "org.eclipse.bluechi" #define BC_AGENT_DBUS_NAME "org.eclipse.bluechi.Agent" +/* Root object path */ #define BC_OBJECT_PATH "/org/eclipse/bluechi" /* Public objects */ @@ -48,18 +66,15 @@ #define BC_BUS_ERROR_ACTIVATION_FAILED "org.eclipse.bluechi.ActivationFailed" /* Systemd protocol */ - #define SYSTEMD_BUS_NAME "org.freedesktop.systemd1" #define SYSTEMD_OBJECT_PATH "/org/freedesktop/systemd1" #define SYSTEMD_MANAGER_IFACE "org.freedesktop.systemd1.Manager" #define SYSTEMD_UNIT_IFACE "org.freedesktop.systemd1.Unit" -#define USEC_PER_SEC 1000000 -#define USEC_PER_MSEC 1000 -#define BC_DEFAULT_DBUS_TIMEOUT ((uint64_t) (USEC_PER_SEC * 30)) +/* Signal names */ +#define AGENT_HEARTBEAT_SIGNAL_NAME "Heartbeat" /* Typestrings */ - #define UNIT_INFO_TYPESTRING "ssssssouso" #define UNIT_INFO_STRUCT_TYPESTRING "(" UNIT_INFO_TYPESTRING ")" #define UNIT_INFO_STRUCT_ARRAY_TYPESTRING "a" UNIT_INFO_STRUCT_TYPESTRING @@ -93,12 +108,6 @@ typedef enum UnitActiveState { const char *active_state_to_string(UnitActiveState s); UnitActiveState active_state_from_string(const char *s); -/* Agent to BlueChi heartbeat signals */ - -// Application-level heartbeat set at 2 seconds. -#define AGENT_HEARTBEAT_INTERVAL_MSEC "2000" -#define AGENT_HEARTBEAT_SIGNAL_NAME "Heartbeat" - /* Constants */ #define SYMBOL_WILDCARD "*" #define SYMBOL_GLOB_ALL '*' diff --git a/src/libbluechi/socket.c b/src/libbluechi/socket.c index 270709f01e..2e33953492 100644 --- a/src/libbluechi/socket.c +++ b/src/libbluechi/socket.c @@ -1,11 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include +#include #include #include #include #include "libbluechi/common/common.h" +#include "libbluechi/common/parse-util.h" +#include "libbluechi/log/log.h" #include "socket.h" int create_tcp_socket(uint16_t port) { @@ -82,3 +85,163 @@ int fd_check_peercred(int fd) { return 1; } + + +/* + * SocketOptions + */ +struct SocketOptions { + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; + bool ip_recv_err; +}; + +SocketOptions *socket_options_new() { + SocketOptions *opts = malloc0(sizeof(SocketOptions)); + if (opts == NULL) { + return NULL; + } + opts->tcp_keepidle = 0; + opts->tcp_keepintvl = 0; + opts->tcp_keepcnt = 0; + opts->ip_recv_err = false; + return opts; +} + +/* + * TCP max values for idle, interval and count based on + * https://github.com/torvalds/linux/blob/master/include/net/tcp.h + */ +#define MAX_TCP_KEEPIDLE 32767 +#define MAX_TCP_KEEPINTVL 32767 +#define MAX_TCP_KEEPCNT 127 + +int socket_options_set_tcp_keepidle(SocketOptions *opts, const char *keepidle_s) { + if (opts == NULL) { + return -EINVAL; + } + + long keepidle = 0; + if (!parse_long(keepidle_s, &keepidle)) { + return -EINVAL; + } + if (keepidle < 0 || keepidle > MAX_TCP_KEEPIDLE) { + return -EINVAL; + } + opts->tcp_keepidle = (int) keepidle; + + return 0; +} + +int socket_options_set_tcp_keepintvl(SocketOptions *opts, const char *keepintvl_s) { + if (opts == NULL) { + return -EINVAL; + } + + long keepintvl = 0; + if (!parse_long(keepintvl_s, &keepintvl)) { + return -EINVAL; + } + if (keepintvl < 0 || keepintvl > MAX_TCP_KEEPINTVL) { + return -EINVAL; + } + opts->tcp_keepintvl = (int) keepintvl; + + return 0; +} + +int socket_options_set_tcp_keepcnt(SocketOptions *opts, const char *keepcnt_s) { + if (opts == NULL) { + return -EINVAL; + } + + long keepcnt = 0; + if (!parse_long(keepcnt_s, &keepcnt)) { + return -EINVAL; + } + if (keepcnt < 0 || keepcnt > MAX_TCP_KEEPCNT) { + return -EINVAL; + } + opts->tcp_keepcnt = (int) keepcnt; + + return 0; +} + +int socket_options_set_ip_recverr(SocketOptions *opts, bool recverr) { + if (opts == NULL) { + return -EINVAL; + } + + opts->ip_recv_err = recverr; + return 0; +} + +static bool is_socket_tcp(int fd) { + int type = 0; + socklen_t length = sizeof(int); + + getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &type, &length); + + return type == AF_INET || type == AF_INET6; +} + +int socket_set_options(int fd, SocketOptions *opts) { + /* Just exit in case of a non-tcp socket. We could connect to a UNIX socket as well. */ + if (!is_socket_tcp(fd)) { + bc_log_debug("Socket options not set. FD is a TCP socket."); + return 0; + } + + if (opts == NULL) { + bc_log_error("Socket options are NULL."); + return -EINVAL; + } + + int r = 0; + int enable_flag = 1; + + if (opts->ip_recv_err) { + r = setsockopt(fd, IPPROTO_IP, IP_RECVERR, &enable_flag, sizeof(int)); + if (r < 0) { + bc_log_errorf("Failed to set IP_RECVERR: %s", strerror(errno)); + return -errno; + } + } + + r = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *) &enable_flag, sizeof(int)); + if (r < 0) { + bc_log_errorf("Failed to set TCP_NODELAY: %s", strerror(errno)); + return -errno; + } + + r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &enable_flag, sizeof(int)); + if (r < 0) { + bc_log_errorf("Failed to set SO_KEEPALIVE: %s", strerror(errno)); + return -errno; + } + + if (opts->tcp_keepidle != 0) { + r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &opts->tcp_keepidle, sizeof(int)); + if (r < 0) { + bc_log_errorf("Failed to set TCP_KEEPIDLE: %s", strerror(errno)); + return -errno; + } + } + if (opts->tcp_keepintvl != 0) { + r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &opts->tcp_keepintvl, sizeof(int)); + if (r < 0) { + bc_log_errorf("Failed to set TCP_KEEPINTVL: %s", strerror(errno)); + return -errno; + } + } + if (opts->tcp_keepcnt != 0) { + r = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &opts->tcp_keepcnt, sizeof(int)); + if (r < 0) { + bc_log_errorf("Failed to set TCP_KEEPCNT: %s", strerror(errno)); + return -errno; + } + } + + return 0; +} diff --git a/src/libbluechi/socket.h b/src/libbluechi/socket.h index c2d8de4489..1978fcc372 100644 --- a/src/libbluechi/socket.h +++ b/src/libbluechi/socket.h @@ -2,8 +2,20 @@ #pragma once #include +#include int create_tcp_socket(uint16_t port); int accept_tcp_connection_request(int fd); int fd_check_peercred(int fd); + + +typedef struct SocketOptions SocketOptions; + +SocketOptions *socket_options_new(); +int socket_options_set_tcp_keepidle(SocketOptions *opts, const char *keepidle_s); +int socket_options_set_tcp_keepintvl(SocketOptions *opts, const char *keepintvl_s); +int socket_options_set_tcp_keepcnt(SocketOptions *opts, const char *keepcnt_s); +int socket_options_set_ip_recverr(SocketOptions *opts, bool recverr); + +int socket_set_options(int fd, SocketOptions *opts); diff --git a/src/libbluechi/test/common/cfg/cfg_def_conf_test.c b/src/libbluechi/test/common/cfg/cfg_def_conf_test.c new file mode 100644 index 0000000000..52e172de5d --- /dev/null +++ b/src/libbluechi/test/common/cfg/cfg_def_conf_test.c @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include + +#include "libbluechi/common/cfg.h" +#include "libbluechi/common/protocol.h" +#include "libbluechi/common/string-util.h" +#include "libbluechi/log/log.h" + +bool test_cfg_agent_def_conf() { + struct config *config = NULL; + cfg_initialize(&config); + + int r = cfg_agent_def_conf(config); + if (r < 0) { + fprintf(stderr, "Unexpected error while setting agent default values: %s", strerror(-r)); + cfg_dispose(config); + return false; + } + + bool result = true; + const char *value = NULL; + + /* Common options */ + value = cfg_get_value(config, CFG_LOG_LEVEL); + if (!streq(value, log_level_to_string(LOG_LEVEL_INFO))) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_LOG_LEVEL, + log_level_to_string(LOG_LEVEL_INFO), + value); + result = false; + } + value = cfg_get_value(config, CFG_LOG_TARGET); + if (!streq(value, BC_LOG_TARGET_JOURNALD)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_LOG_TARGET, + BC_LOG_TARGET_JOURNALD, + value); + result = false; + } + value = cfg_get_value(config, CFG_LOG_IS_QUIET); + if (value != NULL) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_LOG_IS_QUIET, + "NULL", + value); + result = false; + } + value = cfg_get_value(config, CFG_IP_RECEIVE_ERRORS); + if (!streq(value, BC_DEFAULT_IP_RECEIVE_ERROR)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_IP_RECEIVE_ERRORS, + BC_DEFAULT_IP_RECEIVE_ERROR, + value); + result = false; + } + value = cfg_get_value(config, CFG_TCP_KEEPALIVE_TIME); + if (!streq(value, BC_DEFAULT_TCP_KEEPALIVE_TIME)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_TCP_KEEPALIVE_TIME, + BC_DEFAULT_TCP_KEEPALIVE_TIME, + value); + result = false; + } + value = cfg_get_value(config, CFG_TCP_KEEPALIVE_INTERVAL); + if (!streq(value, BC_DEFAULT_TCP_KEEPALIVE_INTERVAL)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_TCP_KEEPALIVE_INTERVAL, + BC_DEFAULT_TCP_KEEPALIVE_INTERVAL, + value); + result = false; + } + value = cfg_get_value(config, CFG_TCP_KEEPALIVE_COUNT); + if (!streq(value, BC_DEFAULT_TCP_KEEPALIVE_COUNT)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_TCP_KEEPALIVE_COUNT, + BC_DEFAULT_TCP_KEEPALIVE_COUNT, + value); + result = false; + } + + /* Agent specific options */ + value = cfg_get_value(config, CFG_NODE_NAME); + if (value == NULL) { + fprintf(stderr, + "Expected config option %s to have set a default value, but got 'NULL'\n", + CFG_NODE_NAME); + result = false; + } + value = cfg_get_value(config, CFG_MANAGER_HOST); + if (!streq(value, BC_DEFAULT_HOST)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_MANAGER_HOST, + BC_DEFAULT_HOST, + value); + result = false; + } + value = cfg_get_value(config, CFG_MANAGER_PORT); + if (!streq(value, BC_DEFAULT_PORT)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_MANAGER_PORT, + BC_DEFAULT_PORT, + value); + result = false; + } + value = cfg_get_value(config, CFG_HEARTBEAT_INTERVAL); + if (!streq(value, AGENT_DEFAULT_HEARTBEAT_INTERVAL_MSEC)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_HEARTBEAT_INTERVAL, + AGENT_DEFAULT_HEARTBEAT_INTERVAL_MSEC, + value); + result = false; + } + + cfg_dispose(config); + return result; +} + +bool test_cfg_manager_def_conf() { + struct config *config = NULL; + cfg_initialize(&config); + + int r = cfg_manager_def_conf(config); + if (r < 0) { + fprintf(stderr, "Unexpected error while setting agent default values: %s", strerror(-r)); + cfg_dispose(config); + return false; + } + + bool result = true; + const char *value = NULL; + + /* Common options */ + value = cfg_get_value(config, CFG_LOG_LEVEL); + if (!streq(value, log_level_to_string(LOG_LEVEL_INFO))) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_LOG_LEVEL, + log_level_to_string(LOG_LEVEL_INFO), + value); + result = false; + } + value = cfg_get_value(config, CFG_LOG_TARGET); + if (!streq(value, BC_LOG_TARGET_JOURNALD)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_LOG_TARGET, + BC_LOG_TARGET_JOURNALD, + value); + result = false; + } + value = cfg_get_value(config, CFG_LOG_IS_QUIET); + if (value != NULL) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_LOG_IS_QUIET, + "NULL", + value); + result = false; + } + value = cfg_get_value(config, CFG_IP_RECEIVE_ERRORS); + if (!streq(value, BC_DEFAULT_IP_RECEIVE_ERROR)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_IP_RECEIVE_ERRORS, + BC_DEFAULT_IP_RECEIVE_ERROR, + value); + result = false; + } + value = cfg_get_value(config, CFG_TCP_KEEPALIVE_TIME); + if (!streq(value, BC_DEFAULT_TCP_KEEPALIVE_TIME)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_TCP_KEEPALIVE_TIME, + BC_DEFAULT_TCP_KEEPALIVE_TIME, + value); + result = false; + } + value = cfg_get_value(config, CFG_TCP_KEEPALIVE_INTERVAL); + if (!streq(value, BC_DEFAULT_TCP_KEEPALIVE_INTERVAL)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_TCP_KEEPALIVE_INTERVAL, + BC_DEFAULT_TCP_KEEPALIVE_INTERVAL, + value); + result = false; + } + value = cfg_get_value(config, CFG_TCP_KEEPALIVE_COUNT); + if (!streq(value, BC_DEFAULT_TCP_KEEPALIVE_COUNT)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_TCP_KEEPALIVE_COUNT, + BC_DEFAULT_TCP_KEEPALIVE_COUNT, + value); + result = false; + } + + /* Manager specific options */ + value = cfg_get_value(config, CFG_MANAGER_PORT); + if (!streq(value, BC_DEFAULT_PORT)) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_MANAGER_PORT, + BC_DEFAULT_PORT, + value); + result = false; + } + value = cfg_get_value(config, CFG_ALLOWED_NODE_NAMES); + if (value != NULL) { + fprintf(stderr, + "Expected config option %s to have default value '%s', but got '%s'\n", + CFG_ALLOWED_NODE_NAMES, + "NULL", + value); + result = false; + } + + cfg_dispose(config); + return result; +} + +int main() { + bool result = true; + + result = result && test_cfg_agent_def_conf(); + result = result && test_cfg_manager_def_conf(); + + if (result) { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} diff --git a/src/libbluechi/test/common/cfg/meson.build b/src/libbluechi/test/common/cfg/meson.build index d83e5abc21..c44e1e4862 100644 --- a/src/libbluechi/test/common/cfg/meson.build +++ b/src/libbluechi/test/common/cfg/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later cfg_src = [ + 'cfg_def_conf_test', 'cfg_get_set_test', 'cfg_load_complete_configuration_test', 'cfg_load_from_env_test', diff --git a/src/libbluechi/test/meson.build b/src/libbluechi/test/meson.build index e1c9499289..ac97ac6f26 100644 --- a/src/libbluechi/test/meson.build +++ b/src/libbluechi/test/meson.build @@ -3,3 +3,4 @@ subdir('bus') subdir('common') subdir('log') +subdir('socket') diff --git a/src/libbluechi/test/socket/meson.build b/src/libbluechi/test/socket/meson.build new file mode 100644 index 0000000000..9ce84b4d1c --- /dev/null +++ b/src/libbluechi/test/socket/meson.build @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +socket_src = [ + 'socket_option_test', + 'socket_set_options_test', +] + +foreach src : socket_src + exec_test = executable(src, src + '.c', + link_with: [ + bluechi_lib, + ], + include_directories: include_directories('../../..'), + ) + test(src, exec_test) +endforeach diff --git a/src/libbluechi/test/socket/socket_option_test.c b/src/libbluechi/test/socket/socket_option_test.c new file mode 100644 index 0000000000..a3f5131047 --- /dev/null +++ b/src/libbluechi/test/socket/socket_option_test.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include + +#include "libbluechi/common/common.h" +#include "libbluechi/socket.h" + + +bool test_socket_options_set_tcp_keepidle(SocketOptions *opts, const char *input, int expected_ret) { + int r = socket_options_set_tcp_keepidle(opts, input); + if (r != expected_ret) { + fprintf(stderr, + "%s: Expected return value %d for input '%s', but got %d", + __func__, + expected_ret, + input, + r); + return false; + } + return true; +} + +bool test_socket_options_set_tcp_keepintvl(SocketOptions *opts, const char *input, int expected_ret) { + int r = socket_options_set_tcp_keepintvl(opts, input); + if (r != expected_ret) { + fprintf(stderr, + "%s: Expected return value %d for input '%s', but got %d", + __func__, + expected_ret, + input, + r); + return false; + } + return true; +} + +bool test_socket_options_set_tcp_keepcnt(SocketOptions *opts, const char *input, int expected_ret) { + int r = socket_options_set_tcp_keepcnt(opts, input); + if (r != expected_ret) { + fprintf(stderr, + "%s: Expected return value %d for input '%s', but got %d", + __func__, + expected_ret, + input, + r); + return false; + } + return true; +} + +bool test_socket_options_set_ip_recverr(SocketOptions *opts, bool input, int expected_ret) { + int r = socket_options_set_ip_recverr(opts, input); + if (r != expected_ret) { + fprintf(stderr, + "%s: Expected return value %d for input '%d', but got %d", + __func__, + expected_ret, + input, + r); + return false; + } + return true; +} + +int main() { + bool result = true; + + _cleanup_free_ SocketOptions *opts = socket_options_new(); + + result = result && test_socket_options_set_tcp_keepidle(NULL, "", -EINVAL); + result = result && test_socket_options_set_tcp_keepidle(opts, "abc123", -EINVAL); + result = result && test_socket_options_set_tcp_keepidle(opts, "-1", -EINVAL); + result = result && test_socket_options_set_tcp_keepidle(opts, "0", 0); + result = result && test_socket_options_set_tcp_keepidle(opts, "10", 0); + result = result && test_socket_options_set_tcp_keepidle(opts, "32767", 0); + result = result && test_socket_options_set_tcp_keepidle(opts, "32768", -EINVAL); + + result = result && test_socket_options_set_tcp_keepintvl(NULL, "", -EINVAL); + result = result && test_socket_options_set_tcp_keepintvl(opts, "abc123", -EINVAL); + result = result && test_socket_options_set_tcp_keepintvl(opts, "-1", -EINVAL); + result = result && test_socket_options_set_tcp_keepintvl(opts, "0", 0); + result = result && test_socket_options_set_tcp_keepintvl(opts, "10", 0); + result = result && test_socket_options_set_tcp_keepintvl(opts, "32767", 0); + result = result && test_socket_options_set_tcp_keepintvl(opts, "32768", -EINVAL); + + result = result && test_socket_options_set_tcp_keepcnt(NULL, "", -EINVAL); + result = result && test_socket_options_set_tcp_keepcnt(opts, "abc123", -EINVAL); + result = result && test_socket_options_set_tcp_keepcnt(opts, "-1", -EINVAL); + result = result && test_socket_options_set_tcp_keepcnt(opts, "0", 0); + result = result && test_socket_options_set_tcp_keepcnt(opts, "10", 0); + result = result && test_socket_options_set_tcp_keepcnt(opts, "127", 0); + result = result && test_socket_options_set_tcp_keepcnt(opts, "128", -EINVAL); + + result = result && test_socket_options_set_ip_recverr(NULL, true, -EINVAL); + result = result && test_socket_options_set_ip_recverr(opts, true, 0); + + if (result) { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} diff --git a/src/libbluechi/test/socket/socket_set_options_test.c b/src/libbluechi/test/socket/socket_set_options_test.c new file mode 100644 index 0000000000..7b95fba285 --- /dev/null +++ b/src/libbluechi/test/socket/socket_set_options_test.c @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include +#include +#include +#include + +#include "libbluechi/common/common.h" +#include "libbluechi/socket.h" + + +static int create_test_tcp_socket() { + int fd = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (fd < 0) { + int errsv = errno; + return -errsv; + } + return fd; +} + +bool test_socket_set_options_no_tcp_socket() { + _cleanup_fd_ int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + fprintf(stderr, "Unexpected error while opening socket: %s\n", strerror(-errno)); + return false; + } + + _cleanup_free_ SocketOptions *opts = socket_options_new(); + int r = socket_set_options(fd, opts); + if (r != 0) { + fprintf(stderr, "%s: Expected return code 0 for UNIX socket, but got %d\n", __func__, r); + return false; + } + + return true; +} + +bool test_socket_set_options_null() { + _cleanup_fd_ int fd = create_test_tcp_socket(); + if (fd < 0) { + fprintf(stderr, "Unexpected error while opening socket: %s", strerror(-errno)); + return false; + } + + int r = socket_set_options(fd, NULL); + if (r != -EINVAL) { + fprintf(stderr, "%s: Expected return code %d for UNIX socket, but got %d", __func__, -EINVAL, r); + return false; + } + + return true; +} + +bool test_socket_set_options_ip_recv_err(bool ip_recv_err, int expected_val) { + _cleanup_fd_ int fd = create_test_tcp_socket(); + if (fd < 0) { + fprintf(stderr, "Unexpected error while opening socket: %s\n", strerror(-errno)); + return false; + } + + _cleanup_free_ SocketOptions *opts = socket_options_new(); + socket_options_set_ip_recverr(opts, ip_recv_err); + int r = socket_set_options(fd, opts); + if (r != 0) { + fprintf(stderr, "%s: Expected return code 0, but got %d\n", __func__, r); + return false; + } + + int val = 0; + socklen_t len = sizeof(int); + getsockopt(fd, IPPROTO_IP, IP_RECVERR, &val, &len); + if (val != expected_val) { + fprintf(stderr, "%s: Expected IP_RECVERR to be %d, but got %d\n", __func__, expected_val, val); + return false; + } + + return true; +} + +bool test_socket_set_options_keepalive( + const char *keepidle, + const char *keepintvl, + const char *keepcnt, + int expected_keepalive, + int expected_keepidle, + int expected_keepintvl, + int expected_keepcnt) { + _cleanup_fd_ int fd = create_test_tcp_socket(); + if (fd < 0) { + fprintf(stderr, "Unexpected error while opening socket: %s\n", strerror(-errno)); + return false; + } + + _cleanup_free_ SocketOptions *opts = socket_options_new(); + socket_options_set_tcp_keepidle(opts, keepidle); + socket_options_set_tcp_keepintvl(opts, keepintvl); + socket_options_set_tcp_keepcnt(opts, keepcnt); + + int r = socket_set_options(fd, opts); + if (r != 0) { + fprintf(stderr, "%s: Expected return code 0, but got %d\n", __func__, r); + return false; + } + + bool result = true; + int val = 0; + socklen_t len = sizeof(int); + getsockopt(fd, SOL_TCP, TCP_NODELAY, &val, &len); + if (val != 1) { + fprintf(stderr, "%s: Expected TCP_NODELAY to be 1, but got %d\n", __func__, val); + result = false; + } + val = 0; + getsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, &len); + if (val != expected_keepalive) { + fprintf(stderr, + "%s: Expected SO_KEEPALIVE to be %d, but got %d\n", + __func__, + expected_keepalive, + val); + result = false; + } + val = 0; + getsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, &len); + /* system default is used when expected_keepidle == 0 */ + if (val != expected_keepidle && expected_keepidle != 0) { + fprintf(stderr, + "%s: Expected TCP_KEEPIDLE to be %d, but got %d\n", + __func__, + expected_keepidle, + val); + result = false; + } + val = 0; + /* system default is used when expected_keepintvl == 0 */ + getsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, &len); + if (val != expected_keepintvl && expected_keepintvl != 0) { + fprintf(stderr, + "%s: Expected TCP_KEEPINTVL to be %d, but got %d\n", + __func__, + expected_keepintvl, + val); + result = false; + } + val = 0; + getsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, &len); + /* system default is used when expected_keepcnt == 0 */ + if (val != expected_keepcnt && expected_keepcnt != 0) { + fprintf(stderr, + "%s: Expected TCP_KEEPCNT to be %d, but got %d\n", + __func__, + expected_keepcnt, + val); + result = false; + } + + return result; +} + + +int main() { + bool result = true; + + result = result && test_socket_set_options_no_tcp_socket(); + result = result && test_socket_set_options_null(); + + result = result && test_socket_set_options_ip_recv_err(false, 0); + result = result && test_socket_set_options_ip_recv_err(true, 1); + + result = result && test_socket_set_options_keepalive("0", "0", "0", 1, 0, 0, 0); + result = result && test_socket_set_options_keepalive("1", "0", "0", 1, 1, 0, 0); + result = result && test_socket_set_options_keepalive("0", "1", "0", 1, 0, 1, 0); + result = result && test_socket_set_options_keepalive("0", "0", "6", 1, 0, 0, 6); + result = result && test_socket_set_options_keepalive("10", "5", "8", 1, 10, 5, 8); + + if (result) { + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} diff --git a/src/manager/manager.c b/src/manager/manager.c index df0b387b83..d8a08b7e8e 100644 --- a/src/manager/manager.c +++ b/src/manager/manager.c @@ -10,7 +10,6 @@ #include "libbluechi/common/time-util.h" #include "libbluechi/log/log.h" #include "libbluechi/service/shutdown.h" -#include "libbluechi/socket.h" #include "job.h" #include "manager.h" @@ -35,13 +34,19 @@ Manager *manager_new(void) { return NULL; } + _cleanup_free_ SocketOptions *socket_opts = socket_options_new(); + if (socket_opts == NULL) { + bc_log_error("Out of memory"); + return NULL; + } + Manager *manager = malloc0(sizeof(Manager)); if (manager != NULL) { manager->ref_count = 1; manager->api_bus_service_name = steal_pointer(&service_name); manager->event = steal_pointer(&event); manager->metrics_enabled = false; - manager->ip_receive_errors = false; + manager->peer_socket_options = steal_pointer(&socket_opts); LIST_HEAD_INIT(manager->nodes); LIST_HEAD_INIT(manager->anonymous_nodes); LIST_HEAD_INIT(manager->jobs); @@ -100,6 +105,7 @@ void manager_unref(Manager *manager) { sd_event_unrefp(&manager->event); free_and_null(manager->api_bus_service_name); + free_and_null(manager->peer_socket_options); sd_event_source_unrefp(&manager->node_connection_source); @@ -346,7 +352,35 @@ bool manager_parse_config(Manager *manager, const char *configfile) { } } - manager->ip_receive_errors = cfg_get_bool_value(manager->config, CFG_IP_RECEIVE_ERRORS); + /* Set socket options used for peer connections with the agents */ + const char *keepidle = cfg_get_value(manager->config, CFG_TCP_KEEPALIVE_TIME); + if (keepidle) { + if (socket_options_set_tcp_keepidle(manager->peer_socket_options, keepidle) < 0) { + bc_log_error("Failed to set TCP KEEPIDLE"); + return false; + } + } + const char *keepintvl = cfg_get_value(manager->config, CFG_TCP_KEEPALIVE_INTERVAL); + if (keepintvl) { + if (socket_options_set_tcp_keepintvl(manager->peer_socket_options, keepintvl) < 0) { + bc_log_error("Failed to set TCP KEEPINTVL"); + return false; + } + } + const char *keepcnt = cfg_get_value(manager->config, CFG_TCP_KEEPALIVE_COUNT); + if (keepcnt) { + if (socket_options_set_tcp_keepcnt(manager->peer_socket_options, keepcnt) < 0) { + bc_log_error("Failed to set TCP KEEPCNT"); + return false; + } + } + if (socket_options_set_ip_recverr( + manager->peer_socket_options, + cfg_get_bool_value(manager->config, CFG_IP_RECEIVE_ERRORS)) < 0) { + bc_log_error("Failed to set IP RECVERR"); + return false; + } + _cleanup_free_ const char *dumped_cfg = cfg_dump(manager->config); bc_log_debug_with_data("Final configuration used", "\n%s", dumped_cfg); @@ -372,20 +406,7 @@ static int manager_accept_node_connection( return -1; } - int r = bus_socket_set_no_delay(dbus_server); - if (r < 0) { - bc_log_warnf("Failed to set NO_DELAY on socket: %s", strerror(-r)); - } - r = bus_socket_set_keepalive(dbus_server); - if (r < 0) { - bc_log_warnf("Failed to set KEEPALIVE on socket: %s", strerror(-r)); - } - if (manager->ip_receive_errors) { - r = bus_socket_enable_recv_err(dbus_server); - if (r < 0) { - bc_log_warnf("Failed to enable receiving errors on socket: %s", strerror(-r)); - } - } + bus_socket_set_options(dbus_server, manager->peer_socket_options); /* Add anonymous node */ node = manager_add_node(manager, NULL); diff --git a/src/manager/manager.h b/src/manager/manager.h index 0e72771079..f1677af726 100644 --- a/src/manager/manager.h +++ b/src/manager/manager.h @@ -6,6 +6,7 @@ #include "libbluechi/common/cfg.h" #include "libbluechi/common/common.h" +#include "libbluechi/socket.h" #include "types.h" @@ -26,7 +27,7 @@ struct Manager { bool metrics_enabled; - bool ip_receive_errors; + SocketOptions *peer_socket_options; int n_nodes; LIST_HEAD(Node, nodes);