From 66285249bb2b52306c3cfdd43c9515f0fae3ab21 Mon Sep 17 00:00:00 2001 From: Joseph Gooch Date: Mon, 17 Aug 2020 23:25:05 +0000 Subject: [PATCH] Refactor I/O and add SD_NOTIFY proxy support Refactored all the conn_sock functionality to be more generic. It can deal with different types of sockets, stream vs dgram, and reuses all the same callbacks, shutdown and async functionality. Conmon creates a notify socket which podman bind-mounts into the container, and passes in via the spec's environment variables. Conmon relays the READY=1 signal. This is similar to what runc and crun do, but doing it in conmon and NOT passing NOTIFY_SOCKET to the OCI runtime allows us to start up properly without runc and crun blocking on the "start" command. It would also be trivial to add more proxied sockets, i.e. the /dev/log proof of concept I did would now be super easy, if we wanted to revisit that. Signed-off-by: Joseph Gooch --- src/cli.c | 3 + src/cli.h | 1 + src/conmon.c | 5 + src/conn_sock.c | 338 ++++++++++++++++++++++++++++++++++++------------ src/conn_sock.h | 37 +++++- src/ctr_stdio.c | 14 +- src/globals.c | 2 - src/globals.h | 2 - 8 files changed, 300 insertions(+), 102 deletions(-) diff --git a/src/cli.c b/src/cli.c index 4173324a..d2294dce 100644 --- a/src/cli.c +++ b/src/cli.c @@ -48,6 +48,7 @@ char *opt_log_level = NULL; char *opt_log_tag = NULL; gboolean opt_sync = FALSE; gboolean opt_no_sync_log = FALSE; +char *opt_sdnotify_socket = NULL; GOptionEntry opt_entries[] = { {"terminal", 't', 0, G_OPTION_ARG_NONE, &opt_terminal, "Terminal", NULL}, {"stdin", 'i', 0, G_OPTION_ARG_NONE, &opt_stdin, "Stdin", NULL}, @@ -94,6 +95,8 @@ GOptionEntry opt_entries[] = { {"no-sync-log", 0, 0, G_OPTION_ARG_NONE, &opt_no_sync_log, "Do not manually call sync on logs after container shutdown", NULL}, {"sync", 0, 0, G_OPTION_ARG_NONE, &opt_sync, "Allowing caller to keep the main conmon process as its child by only forking once", NULL}, + {"sdnotify-socket", 0, 0, G_OPTION_ARG_STRING, &opt_sdnotify_socket, "Path to the host's sd-notify socket to relay messages to", + NULL}, {NULL, 0, 0, 0, NULL, NULL, NULL}}; diff --git a/src/cli.h b/src/cli.h index 351dbb3e..033daac9 100644 --- a/src/cli.h +++ b/src/cli.h @@ -42,6 +42,7 @@ extern char *opt_log_level; extern char *opt_log_tag; extern gboolean opt_no_sync_log; extern gboolean opt_sync; +extern char *opt_sdnotify_socket; extern GOptionEntry opt_entries[]; int initialize_cli(int argc, char *argv[]); diff --git a/src/conmon.c b/src/conmon.c index e43dc68f..6534f55f 100644 --- a/src/conmon.c +++ b/src/conmon.c @@ -89,6 +89,11 @@ int main(int argc, char *argv[]) /* before we fork, ensure our children will be reaped */ atexit(reap_children); + /* If we were passed a sd-notify socket to use, set it up now */ + if (opt_sdnotify_socket) { + setup_notify_socket(opt_sdnotify_socket); + } + /* Environment variables */ sync_pipe_fd = get_pipe_fd_from_env("_OCI_SYNCPIPE"); diff --git a/src/conn_sock.c b/src/conn_sock.c index 2237283c..c909c3ec 100644 --- a/src/conn_sock.c +++ b/src/conn_sock.c @@ -13,14 +13,64 @@ #include #include -static gboolean attach_cb(int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data); -static gboolean conn_sock_cb(int fd, GIOCondition condition, gpointer user_data); -static gboolean read_conn_sock(struct conn_sock_s *sock); -static gboolean terminate_conn_sock(struct conn_sock_s *sock); -void conn_sock_shutdown(struct conn_sock_s *sock, int how); -static void sock_try_write_to_mainfd_stdin(struct conn_sock_s *sock); -static gboolean mainfd_write_cb(G_GNUC_UNUSED int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data); - +static gboolean attach_cb(int fd, G_GNUC_UNUSED GIOCondition condition, gpointer user_data); +static gboolean remote_sock_cb(int fd, GIOCondition condition, gpointer user_data); +static void init_remote_sock(struct remote_sock_s *sock, struct remote_sock_s *src); +static gboolean read_remote_sock(struct remote_sock_s *sock); +static gboolean terminate_remote_sock(struct remote_sock_s *sock); +static void remote_sock_shutdown(struct remote_sock_s *sock, int how); +static void schedule_local_sock_write(struct local_sock_s *local_sock); +static void sock_try_write_to_local_sock(struct remote_sock_s *sock); +static gboolean local_sock_write_cb(G_GNUC_UNUSED int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data); +static char *bind_unix_socket(char *socket_relative_name, int sock_type, mode_t perms, struct remote_sock_s *remote_sock, + gboolean do_chdir); +/* + Since our socket handling is abstract now, handling is based on sock_type, so we can pass around a structure + that contains everything we need to handle I/O. Callbacks used to handle IO, for example, and whether this + can be read from or written to or both, and the buffers used for the communication. +*/ + +/* + This defines the Container STDIN, attaches it to the correct FD and sets the flags for handling I/O. + setup_attach_socket() is responsible for setting the correct remote FD and pushing it onto the queue. +*/ +static struct local_sock_s local_mainfd_stdin = {&mainfd_stdin, true, NULL, "container stdin", NULL}; +struct remote_sock_s remote_attach_sock = { + SOCK_TYPE_CONSOLE, /* sock_type */ + -1, /* fd */ + &local_mainfd_stdin, /* dest */ + true, /* listening */ + false, /* data_ready */ + true, /* readable */ + true, /* writable */ + 0, /* remaining */ + 0, /* off */ + {0} /* buf */ +}; +/* + This defines the Container SDNotify socket, attaches it to the correct FD and sets the flags for handling I/O. + setup_notify_socket() is responsible for initializing the unix sockets and pushing it onto the queue. + + If the local_notify_host_fd stays -1 (i.e. we have not requested SD-NOTIFY) then setup was never run and + this has no effect. +*/ +static int local_notify_host_fd = -1; +static struct sockaddr_un local_notify_host_addr = {0}; +static struct local_sock_s local_notify_host = {&local_notify_host_fd, false, NULL, "host notify socket", &local_notify_host_addr}; +struct remote_sock_s remote_notify_sock = { + SOCK_TYPE_NOTIFY, /* sock_type */ + -1, /* fd */ + &local_notify_host, /* dest */ + false, /* listening */ + false, /* data_ready */ + true, /* readable */ + false, /* writable */ + 0, /* remaining */ + 0, /* off */ + {0} /* buf */ +}; + +/* External */ char *setup_console_socket(void) { struct sockaddr_un addr = {0}; @@ -60,16 +110,48 @@ char *setup_console_socket(void) char *setup_attach_socket(void) { - struct sockaddr_un attach_addr = {0}; - attach_addr.sun_family = AF_UNIX; + char *symlink_dir_path = bind_unix_socket("attach", SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0700, &remote_attach_sock, 0); + + if (listen(remote_attach_sock.fd, 10) == -1) + pexitf("Failed to listen on attach socket: %s/%s", symlink_dir_path, "attach"); + + g_unix_fd_add(remote_attach_sock.fd, G_IO_IN, attach_cb, &remote_attach_sock); + + return symlink_dir_path; +} + +void setup_notify_socket(char *socket_path) +{ + /* Connect to Host socket */ + if (local_notify_host_fd < 0) { + local_notify_host_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + if (local_notify_host_fd == -1) { + pexit("Failed to create notify socket"); + } + local_notify_host_addr.sun_family = AF_UNIX; + strncpy(local_notify_host_addr.sun_path, socket_path, sizeof(local_notify_host_addr.sun_path) - 1); + } + + _cleanup_free_ char *symlink_dir_path = + bind_unix_socket("notify/notify.sock", SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0777, &remote_notify_sock, 1); + g_unix_fd_add(remote_notify_sock.fd, G_IO_IN | G_IO_HUP | G_IO_ERR, remote_sock_cb, &remote_notify_sock); +} + +/* REMEMBER to g_free() the return value! */ +static char *bind_unix_socket(char *socket_relative_name, int sock_type, mode_t perms, struct remote_sock_s *remote_sock, gboolean do_chdir) +{ + int socket_fd = -1; + struct sockaddr_un socket_addr = {0}; + socket_addr.sun_family = AF_UNIX; + _cleanup_free_ char *cwd = NULL; /* * Create a symlink so we don't exceed unix domain socket * path length limit. + * + * We do NOT free this because it's returned to the parent, who is responsible for freeing it! */ - char *attach_symlink_dir_path = g_build_filename(opt_socket_path, opt_cuuid, NULL); - if (unlink(attach_symlink_dir_path) == -1 && errno != ENOENT) - pexit("Failed to remove existing symlink for attach socket directory"); + char *base_path = g_build_filename(opt_socket_path, opt_cuuid, NULL); /* * This is to address a corner case where the symlink path length can end up being @@ -77,85 +159,123 @@ char *setup_attach_socket(void) * be created. This could still be a problem with other containers, but it is safe * to assume the CUUIDs don't change length in the same directory. As a workaround, * in such case, make the symlink one char shorter. + * + * If we're using do_chdir, this is unnecessary. */ - if (strlen(attach_symlink_dir_path) == (sizeof(attach_addr.sun_path) - 1)) - attach_symlink_dir_path[sizeof(attach_addr.sun_path) - 2] = '\0'; + if (!do_chdir && strlen(base_path) == (sizeof(socket_addr.sun_path) - 1)) + base_path[sizeof(socket_addr.sun_path) - 2] = '\0'; - if (symlink(opt_bundle_path, attach_symlink_dir_path) == -1) - pexit("Failed to create symlink for attach socket"); + /* + * Create a symlink so we don't exceed unix domain socket + * path length limit. We use the base path passed in from our parent. + */ + if (unlink(base_path) == -1 && errno != ENOENT) + pexitf("Failed to remove existing symlink for socket directory %s", base_path); - _cleanup_free_ char *attach_sock_path = g_build_filename(opt_socket_path, opt_cuuid, "attach", NULL); - ninfof("attach sock path: %s", attach_sock_path); + if (symlink(opt_bundle_path, base_path) == -1) + pexit("Failed to create symlink for notify socket"); - strncpy(attach_addr.sun_path, attach_sock_path, sizeof(attach_addr.sun_path) - 1); - ninfof("addr{sun_family=AF_UNIX, sun_path=%s}", attach_addr.sun_path); + _cleanup_free_ char *sock_fullpath = g_build_filename(base_path, socket_relative_name, NULL); + _cleanup_free_ char *sock_relpath = g_build_filename(opt_cuuid, socket_relative_name, NULL); + ninfof("socket path: %s", sock_fullpath); + + strncpy(socket_addr.sun_path, do_chdir ? sock_relpath : sock_fullpath, sizeof(socket_addr.sun_path) - 1); + ninfof("addr{sun_family=AF_UNIX, sun_path=%s}", socket_addr.sun_path); /* * We make the socket non-blocking to avoid a race where client aborts connection * before the server gets a chance to call accept. In that scenario, the server * accept blocks till a new client connection comes in. */ - attach_socket_fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); - if (attach_socket_fd == -1) - pexit("Failed to create attach socket"); + if (do_chdir && (cwd = getcwd(NULL, 0)) == NULL) + pexitf("Failed to get CWD for socket %s", sock_fullpath); + + socket_fd = socket(AF_UNIX, sock_type, 0); + if (socket_fd == -1) + pexitf("Failed to create socket %s", sock_fullpath); - if (fchmod(attach_socket_fd, 0700)) - pexit("Failed to change attach socket permissions"); + if (fchmod(socket_fd, perms)) + pexitf("Failed to change socket permissions %s", sock_fullpath); - if (unlink(attach_addr.sun_path) == -1 && errno != ENOENT) - pexitf("Failed to remove existing attach socket: %s", attach_addr.sun_path); + if (do_chdir && chdir(opt_socket_path) == -1) + pexitf("Could not chdir to %s", opt_socket_path); - if (bind(attach_socket_fd, (struct sockaddr *)&attach_addr, sizeof(struct sockaddr_un)) == -1) - pexitf("Failed to bind attach socket: %s", attach_sock_path); + if (unlink(sock_fullpath) == -1 && errno != ENOENT) + pexitf("Failed to remove existing socket: %s", sock_fullpath); - if (listen(attach_socket_fd, 10) == -1) - pexitf("Failed to listen on attach socket: %s", attach_sock_path); + if (bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) == -1) + pexitf("Failed to bind socket: %s", sock_fullpath); - g_unix_fd_add(attach_socket_fd, G_IO_IN, attach_cb, NULL); + if (chmod(sock_fullpath, perms)) + pexitf("Failed to change socket permissions %s", sock_fullpath); - return attach_symlink_dir_path; + if (do_chdir && chdir(cwd) == -1) + pexitf("Could not chdir to %s", cwd); + + remote_sock->fd = socket_fd; + + return base_path; } -static gboolean attach_cb(int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) + +void schedule_main_stdin_write() +{ + schedule_local_sock_write(&local_mainfd_stdin); +} + +void write_back_to_remote_consoles(char *buf, int len) { - int conn_fd = accept(fd, NULL, NULL); - if (conn_fd == -1) { + if (local_mainfd_stdin.readers == NULL) + return; + + for (int i = local_mainfd_stdin.readers->len; i > 0; i--) { + struct remote_sock_s *remote_sock = g_ptr_array_index(local_mainfd_stdin.readers, i - 1); + + if (remote_sock->writable && write_all(remote_sock->fd, buf, len) < 0) { + nwarn("Failed to write to remote console socket"); + remote_sock_shutdown(remote_sock, SHUT_WR); + } + } +} + +/* Internal */ +static gboolean attach_cb(int fd, G_GNUC_UNUSED GIOCondition condition, gpointer user_data) +{ + struct remote_sock_s *srcsock = (struct remote_sock_s *)user_data; + int new_fd = accept(fd, NULL, NULL); + if (new_fd == -1) { if (errno != EWOULDBLOCK) nwarn("Failed to accept client connection on attach socket"); } else { - struct conn_sock_s *conn_sock; - if (conn_socks == NULL) { - conn_socks = g_ptr_array_new_with_free_func(free); + struct remote_sock_s *remote_sock; + if (srcsock->dest->readers == NULL) { + srcsock->dest->readers = g_ptr_array_new_with_free_func(free); } - conn_sock = malloc(sizeof(*conn_sock)); - if (conn_sock == NULL) { + remote_sock = malloc(sizeof(*remote_sock)); + if (remote_sock == NULL) { pexit("Failed to allocate memory"); } - conn_sock->fd = conn_fd; - conn_sock->readable = true; - conn_sock->writable = true; - conn_sock->off = 0; - conn_sock->remaining = 0; - conn_sock->data_ready = false; - g_unix_fd_add(conn_sock->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, conn_sock_cb, conn_sock); - g_ptr_array_add(conn_socks, conn_sock); - ninfof("Accepted connection %d", conn_sock->fd); + init_remote_sock(remote_sock, srcsock); + remote_sock->fd = new_fd; + g_unix_fd_add(remote_sock->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, remote_sock_cb, remote_sock); + g_ptr_array_add(remote_sock->dest->readers, remote_sock); + ninfof("Accepted%s connection %d", SOCK_IS_CONSOLE(srcsock->sock_type) ? " console" : "", remote_sock->fd); } return G_SOURCE_CONTINUE; } -static gboolean conn_sock_cb(G_GNUC_UNUSED int fd, GIOCondition condition, gpointer user_data) +static gboolean remote_sock_cb(G_GNUC_UNUSED int fd, GIOCondition condition, gpointer user_data) { - struct conn_sock_s *sock = (struct conn_sock_s *)user_data; + struct remote_sock_s *sock = (struct remote_sock_s *)user_data; if (condition & G_IO_IN) - return read_conn_sock(sock); + return read_remote_sock(sock); - return terminate_conn_sock(sock); + return terminate_remote_sock(sock); } -static gboolean read_conn_sock(struct conn_sock_s *sock) +static gboolean read_remote_sock(struct remote_sock_s *sock) { ssize_t num_read; @@ -165,40 +285,63 @@ static gboolean read_conn_sock(struct conn_sock_s *sock) return G_SOURCE_REMOVE; } - num_read = read(sock->fd, sock->buf, CONN_SOCK_BUF_SIZE); + if (SOCK_IS_STREAM(sock->sock_type)) { + num_read = read(sock->fd, sock->buf, CONN_SOCK_BUF_SIZE); + } else { + num_read = recvfrom(sock->fd, sock->buf, CONN_SOCK_BUF_SIZE - 1, 0, NULL, NULL); + } + if (num_read < 0) return G_SOURCE_CONTINUE; if (num_read == 0) - return terminate_conn_sock(sock); + return terminate_remote_sock(sock); /* num_read > 0 */ sock->remaining = num_read; sock->off = 0; - sock_try_write_to_mainfd_stdin(sock); + if (SOCK_IS_NOTIFY(sock->sock_type)) { + /* Do what OCI runtime does - only pass READY=1 */ + sock->buf[num_read] = '\0'; + if (strstr(sock->buf, "READY=1")) { + strncpy(sock->buf, "READY=1", 8); + sock->remaining = 7; + } else { + sock->remaining = 0; + } + } + + if (sock->remaining) + sock_try_write_to_local_sock(sock); - /* Not everything was written to stdin, let's wait for the fd to be ready. */ + /* Not everything was written, let's wait for the fd to be ready. */ if (sock->remaining) - schedule_main_stdin_write(); + schedule_local_sock_write(sock->dest); return G_SOURCE_CONTINUE; } -static gboolean terminate_conn_sock(struct conn_sock_s *sock) +static gboolean terminate_remote_sock(struct remote_sock_s *sock) { - conn_sock_shutdown(sock, SHUT_RD); - if (mainfd_stdin >= 0 && opt_stdin) { - if (!opt_leave_stdin_open) { - close(mainfd_stdin); - mainfd_stdin = -1; + remote_sock_shutdown(sock, SHUT_RD); + if (SOCK_IS_CONSOLE(sock->sock_type)) { + if (sock->dest->readers == NULL || sock->dest->readers->len == 0) { + if (*(sock->dest->fd) >= 0 && opt_stdin) { + if (!opt_leave_stdin_open) { + close(*(sock->dest->fd)); + *(sock->dest->fd) = -1; + } else { + ninfo("Not closing input"); + } + } } else { - ninfo("Not closing input"); + ninfo("Not closing input - still have open sockets"); } } return G_SOURCE_REMOVE; } -void conn_sock_shutdown(struct conn_sock_s *sock, int how) +static void remote_sock_shutdown(struct remote_sock_s *sock, int how) { if (sock->fd == -1) return; @@ -216,55 +359,84 @@ void conn_sock_shutdown(struct conn_sock_s *sock, int how) break; } if (!sock->writable && !sock->readable) { + ndebugf("Closing %d", sock->fd); close(sock->fd); sock->fd = -1; - g_ptr_array_remove(conn_socks, sock); + if (sock->dest->readers != NULL) { + g_ptr_array_remove(sock->dest->readers, sock); + } } } -static void write_to_mainfd_stdin(gpointer data, gpointer user_data) +static void write_to_local_sock(gpointer data, gpointer user_data) { - struct conn_sock_s *sock = (struct conn_sock_s *)data; + struct remote_sock_s *sock = (struct remote_sock_s *)data; bool *has_data = user_data; - sock_try_write_to_mainfd_stdin(sock); + sock_try_write_to_local_sock(sock); if (sock->remaining) *has_data = true; else if (sock->data_ready) { sock->data_ready = false; - g_unix_fd_add(sock->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, conn_sock_cb, sock); + g_unix_fd_add(sock->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, remote_sock_cb, sock); } } -static void sock_try_write_to_mainfd_stdin(struct conn_sock_s *sock) +static void sock_try_write_to_local_sock(struct remote_sock_s *sock) { - if (!sock->remaining || mainfd_stdin < 0) + struct local_sock_s *local_sock = sock->dest; + ssize_t w = 0; + + if (!sock->remaining || *(local_sock->fd) < 0) return; - ssize_t w = write(mainfd_stdin, sock->buf + sock->off, sock->remaining); + if (local_sock->is_stream) { + w = write(*(local_sock->fd), sock->buf + sock->off, sock->remaining); + } else { + w = sendto(*(local_sock->fd), sock->buf + sock->off, sock->remaining, MSG_DONTWAIT | MSG_NOSIGNAL, + (struct sockaddr *)local_sock->addr, sizeof(*(local_sock->addr))); + } if (w < 0) { - nwarn("Failed to write to container stdin"); + nwarnf("Failed to write %s", local_sock->label); } else { sock->off += w; sock->remaining -= w; } } -static gboolean mainfd_write_cb(G_GNUC_UNUSED int fd, G_GNUC_UNUSED GIOCondition condition, G_GNUC_UNUSED gpointer user_data) +static gboolean local_sock_write_cb(G_GNUC_UNUSED int fd, G_GNUC_UNUSED GIOCondition condition, gpointer user_data) { + struct local_sock_s *local_sock = (struct local_sock_s *)user_data; bool has_data = FALSE; - if (mainfd_stdin < 0) + if (*(local_sock->fd) < 0) return G_SOURCE_REMOVE; - g_ptr_array_foreach(conn_socks, write_to_mainfd_stdin, &has_data); + g_ptr_array_foreach(local_sock->readers, write_to_local_sock, &has_data); if (has_data) return G_SOURCE_CONTINUE; return G_SOURCE_REMOVE; } -void schedule_main_stdin_write() +static void schedule_local_sock_write(struct local_sock_s *local_sock) { - g_unix_fd_add(mainfd_stdin, G_IO_OUT, mainfd_write_cb, NULL); + if (*(local_sock->fd) < 0) + return; + + g_unix_fd_add(*(local_sock->fd), G_IO_OUT, local_sock_write_cb, local_sock); +} + +static void init_remote_sock(struct remote_sock_s *sock, struct remote_sock_s *src) +{ + sock->off = 0; + sock->remaining = 0; + sock->data_ready = false; + sock->listening = false; + if (src) { + sock->readable = src->readable; + sock->writable = src->writable; + sock->dest = src->dest; + sock->sock_type = src->sock_type; + } } diff --git a/src/conn_sock.h b/src/conn_sock.h index 4af49c8a..32c1290b 100644 --- a/src/conn_sock.h +++ b/src/conn_sock.h @@ -4,9 +4,33 @@ #include /* gboolean */ #include "config.h" /* CONN_SOCK_BUF_SIZE */ +#define SOCK_TYPE_CONSOLE 1 +#define SOCK_TYPE_NOTIFY 2 +#define SOCK_IS_CONSOLE(sock_type) ((sock_type) == SOCK_TYPE_CONSOLE) +#define SOCK_IS_NOTIFY(sock_type) ((sock_type) == SOCK_TYPE_NOTIFY) +#define SOCK_IS_STREAM(sock_type) ((sock_type) == SOCK_TYPE_CONSOLE) +#define SOCK_IS_DGRAM(sock_type) ((sock_type) != SOCK_TYPE_CONSOLE) + /* Used for attach */ -struct conn_sock_s { +/* The nomenclature here is decided but may not be entirely intuitive. + in_sock and out_sock doesn't seem right, because ctr_stdio + breaks encapsulation and writes directly to the console + sockets. + In most cases in conn_sock.c, this struct is "INPUT" and + the next one is "OUTPUT". Really it's this struct is "one" + and the next is "many", but I don't want the same fd in + two different sockets. + + "remote" indicates "Remote User" i.e. attached console, or + "container's /dev/log" or "container's /run/notify" + "local" incidates "A socket we own, locally" i.e. mainfd_stdin + or "host /dev/log" or "host /run/systemd/notify" + */ +struct remote_sock_s { + int sock_type; int fd; + struct local_sock_s *dest; + gboolean listening; gboolean data_ready; gboolean readable; gboolean writable; @@ -15,9 +39,18 @@ struct conn_sock_s { char buf[CONN_SOCK_BUF_SIZE]; }; +struct local_sock_s { + int *fd; + gboolean is_stream; + GPtrArray *readers; + char *label; + struct sockaddr_un *addr; +}; + char *setup_console_socket(void); char *setup_attach_socket(void); -void conn_sock_shutdown(struct conn_sock_s *sock, int how); +void setup_notify_socket(char *); void schedule_main_stdin_write(); +void write_back_to_remote_consoles(char *buf, int len); #endif // CONN_SOCK_H diff --git a/src/ctr_stdio.c b/src/ctr_stdio.c index d0b1216a..ee7bee8e 100644 --- a/src/ctr_stdio.c +++ b/src/ctr_stdio.c @@ -107,7 +107,6 @@ static bool read_stdio(int fd, stdpipe_t pipe, gboolean *eof) char real_buf[STDIO_BUF_SIZE + 2]; char *buf = real_buf + 1; ssize_t num_read = 0; - size_t i; if (eof) *eof = false; @@ -128,19 +127,8 @@ static bool read_stdio(int fd, stdpipe_t pipe, gboolean *eof) if (!written) return written; - if (conn_socks == NULL) { - return true; - } - real_buf[0] = pipe; - for (i = conn_socks->len; i > 0; i--) { - struct conn_sock_s *conn_sock = g_ptr_array_index(conn_socks, i - 1); - - if (conn_sock->writable && write_all(conn_sock->fd, real_buf, num_read + 1) < 0) { - nwarn("Failed to write to socket"); - conn_sock_shutdown(conn_sock, SHUT_WR); - } - } + write_back_to_remote_consoles(real_buf, num_read + 1); return true; } } diff --git a/src/globals.c b/src/globals.c index e0271473..5a9be926 100644 --- a/src/globals.c +++ b/src/globals.c @@ -7,8 +7,6 @@ int mainfd_stdin = -1; int mainfd_stdout = -1; int mainfd_stderr = -1; -GPtrArray *conn_socks = NULL; - int attach_socket_fd = -1; int console_socket_fd = -1; int terminal_ctrl_fd = -1; diff --git a/src/globals.h b/src/globals.h index eb359f17..04e4b642 100644 --- a/src/globals.h +++ b/src/globals.h @@ -12,8 +12,6 @@ extern int mainfd_stdin; extern int mainfd_stdout; extern int mainfd_stderr; -extern GPtrArray *conn_socks; - extern int attach_socket_fd; extern int console_socket_fd; extern int terminal_ctrl_fd;