]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxccontainer: extend lxccontainer API with set_timeout
authorAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Tue, 17 Jan 2023 16:27:40 +0000 (17:27 +0100)
committerAlexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Fri, 21 Apr 2023 18:15:15 +0000 (20:15 +0200)
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 <aleksandr.mikhalitsyn@canonical.com>
src/lxc/commands.c
src/lxc/commands_utils.c
src/lxc/commands_utils.h
src/lxc/lxccontainer.c
src/lxc/lxccontainer.h

index a9c2909692595b3cf3b06dbb5ddf7756a6f2fc42..a6f476045bfbcc1e558f8e3f06b7eba146f41351 100644 (file)
@@ -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;
index 3558ff7e2fd4b173ab2adc6cc10ff299a184d6f0..22490700eb0dae5077d25ba08226669557ca3384 100644 (file)
@@ -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,
index 28ce4907ae0e6025f26a58ab3486d4553c2c7429..0779f747d6875b8aeb28cc60a6b5073fd437918e 100644 (file)
@@ -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,
index 8df60595a88df9971dae036ff600f94382cec8c0..61a3a7ee022cd112059fb81766a063dc57c8cac9 100644 (file)
@@ -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;
 
index 3386bfff6d20c1b97ad7fa38d9f082b3343799e2..a87941d5270894d4b1a2a580ed1ebabfd803cc46 100644 (file)
@@ -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.
         *