From: Alexander Mikhalitsyn Date: Tue, 17 Jan 2023 16:27:40 +0000 (+0100) Subject: lxccontainer: extend lxccontainer API with set_timeout X-Git-Tag: v6.0.0~48^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0fed82b2679139babb14579ab3a4acda150f093b;p=thirdparty%2Flxc.git lxccontainer: extend lxccontainer API with set_timeout lxccontainer set_timeout method allows to set LXC client timeout for waiting monitor response. Right now, it's implemented using the SO_RCVTIMEO client socket option. (But it's the implementation detail that can be changed in the future.) This commit doesn't change behavior, because it's just adds a new option and setter, but not changes any existing LXC commands implementation. It's also extends internal API function lxc_cmd with lxc_cmd_timeout. Issue #4257 Signed-off-by: Alexander Mikhalitsyn --- diff --git a/src/lxc/commands.c b/src/lxc/commands.c index a9c290969..a6f476045 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -441,12 +441,12 @@ __access_r(3, 2) static int rsp_many_fds_reap(int fd, __u32 fds_len, } static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd, - const char *lxcpath, const char *hashed_sock_name) + const char *lxcpath, const char *hashed_sock_name, int rcv_timeout) { __do_close int client_fd = -EBADF; ssize_t ret = -1; - client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, "command"); + client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, "command", rcv_timeout); if (client_fd < 0) return -1; @@ -475,13 +475,15 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd, } /* - * lxc_cmd: Connect to the specified running container, send it a command - * request and collect the response + * lxc_cmd_timeout: Connect to the specified running container, send it a command + * request and collect the response with timeout * - * @name : name of container to connect to - * @cmd : command with initialized request to send - * @stopped : output indicator if the container was not running - * @lxcpath : the lxcpath in which the container is running + * @name : name of container to connect to + * @cmd : command with initialized request to send + * @stopped : output indicator if the container was not running + * @lxcpath : the lxcpath in which the container is running + * @hashed_sock_name : the hashed name of the socket (optional, can be NULL) + * @rcv_timeout : SO_RCVTIMEO for LXC client_fd socket * * Returns the size of the response message on success, < 0 on failure * @@ -493,8 +495,8 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd, * the slot with lxc_cmd_fd_cleanup(). The socket fd will be returned in the * cmd response structure. */ -static ssize_t lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, bool *stopped, - const char *lxcpath, const char *hashed_sock_name) +static ssize_t lxc_cmd_timeout(const char *name, struct lxc_cmd_rr *cmd, bool *stopped, + const char *lxcpath, const char *hashed_sock_name, int rcv_timeout) { __do_close int client_fd = -EBADF; bool stay_connected = false; @@ -506,7 +508,16 @@ static ssize_t lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, bool *stopped, *stopped = 0; - client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name); + /* + * We don't want to change anything for the case when the client + * socket fd lifetime is longer than the lxc_cmd_timeout() execution. + * So it's better not to set SO_RCVTIMEO for client_fd, + * because it'll have an affect on the entire socket lifetime. + */ + if (stay_connected) + rcv_timeout = 0; + + client_fd = lxc_cmd_send(name, cmd, lxcpath, hashed_sock_name, rcv_timeout); if (client_fd < 0) { if (errno == ECONNREFUSED || errno == EPIPE) *stopped = 1; @@ -527,6 +538,12 @@ static ssize_t lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, bool *stopped, return ret; } +static ssize_t lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, bool *stopped, + const char *lxcpath, const char *hashed_sock_name) +{ + return lxc_cmd_timeout(name, cmd, stopped, lxcpath, hashed_sock_name, 0); +} + int lxc_try_cmd(const char *name, const char *lxcpath) { bool stopped = false; diff --git a/src/lxc/commands_utils.c b/src/lxc/commands_utils.c index 3558ff7e2..22490700e 100644 --- a/src/lxc/commands_utils.c +++ b/src/lxc/commands_utils.c @@ -144,9 +144,10 @@ int lxc_make_abstract_socket_name(char *path, size_t pathlen, } int lxc_cmd_connect(const char *name, const char *lxcpath, - const char *hashed_sock_name, const char *suffix) + const char *hashed_sock_name, const char *suffix, int rcv_timeout) { - int ret, client_fd; + int ret; + __do_close int client_fd = -EBADF; char path[LXC_AUDS_ADDR_LEN] = {0}; ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, @@ -159,7 +160,10 @@ int lxc_cmd_connect(const char *name, const char *lxcpath, if (client_fd < 0) return -1; - return client_fd; + if (lxc_socket_set_timeout(client_fd, rcv_timeout, 0)) + return log_trace(-1, "Failed to set socket timeout"); + + return move_fd(client_fd); } int lxc_add_state_client(int state_client_fd, struct lxc_handler *handler, diff --git a/src/lxc/commands_utils.h b/src/lxc/commands_utils.h index 28ce4907a..0779f747d 100644 --- a/src/lxc/commands_utils.h +++ b/src/lxc/commands_utils.h @@ -62,7 +62,7 @@ __hidden extern int lxc_add_state_client(int state_client_fd, struct lxc_handler * >= 0 client fd */ __hidden extern int lxc_cmd_connect(const char *name, const char *lxcpath, - const char *hashed_sock_name, const char *suffix); + const char *hashed_sock_name, const char *suffix, int rcv_timeout); __hidden extern void lxc_cmd_notify_state_listeners(const char *name, const char *lxcpath, diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 8df60595a..61a3a7ee0 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -5257,6 +5257,21 @@ static int do_lxcapi_seccomp_notify_fd_active(struct lxc_container *c) WRAP_API(int, lxcapi_seccomp_notify_fd_active) +static bool do_lxcapi_set_timeout(struct lxc_container *c, int timeout) +{ + if (!c) + return false; + + if (!(timeout > 0 || timeout == -1)) + return ret_set_errno(-1, -EINVAL); + + c->rcv_timeout = (timeout == -1) ? 0 : timeout; + + return true; +} + +WRAP_API_1(bool, lxcapi_set_timeout, int) + struct lxc_container *lxc_container_new(const char *name, const char *configpath) { struct lxc_container *c; @@ -5400,6 +5415,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->umount = lxcapi_umount; c->seccomp_notify_fd = lxcapi_seccomp_notify_fd; c->seccomp_notify_fd_active = lxcapi_seccomp_notify_fd_active; + c->set_timeout = lxcapi_set_timeout; return c; diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 3386bfff6..a87941d52 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -94,6 +94,12 @@ struct lxc_container { */ struct lxc_conf *lxc_conf; + /*! + * \private + * SO_RCVTIMEO for LXC client_fd socket. + */ + int rcv_timeout; + /* public fields */ /*! Human-readable string representing last error */ char *error_string; @@ -867,6 +873,17 @@ struct lxc_container { */ int (*seccomp_notify_fd_active)(struct lxc_container *c); + /*! + * \brief Set response receive timeout for LXC commands + * + * \param c Container + * \param timeout Seconds to wait before returning false. + * (-1 to wait forever). + * + * \return \c true on success, else \c false. + */ + bool (*set_timeout)(struct lxc_container *c, int timeout); + /*! * \brief Retrieve a pidfd for the container's init process. *