From patchwork Thu Dec 17 16:44:53 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Molton X-Patchwork-Id: 41333 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 8FDA4B6F05 for ; Fri, 18 Dec 2009 03:57:30 +1100 (EST) Received: from localhost ([127.0.0.1]:38761 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NLJfL-00056Q-Kj for incoming@patchwork.ozlabs.org; Thu, 17 Dec 2009 11:57:27 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NLJVi-0007S8-54 for qemu-devel@nongnu.org; Thu, 17 Dec 2009 11:47:30 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NLJVh-0007R0-Bu for qemu-devel@nongnu.org; Thu, 17 Dec 2009 11:47:29 -0500 Received: from [199.232.76.173] (port=45007 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NLJVh-0007Qc-1J for qemu-devel@nongnu.org; Thu, 17 Dec 2009 11:47:29 -0500 Received: from bhuna.collabora.co.uk ([93.93.128.226]:33985) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NLJVM-0000Fy-HQ for qemu-devel@nongnu.org; Thu, 17 Dec 2009 11:47:27 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: ian) with ESMTPSA id 06AC76017EE From: Ian Molton To: qemu-devel@nongnu.org Date: Thu, 17 Dec 2009 16:44:53 +0000 Message-Id: <1261068295-25831-3-git-send-email-ian.molton@collabora.co.uk> X-Mailer: git-send-email 1.6.5.4 In-Reply-To: <1261068295-25831-2-git-send-email-ian.molton@collabora.co.uk> References: <1261068295-25831-1-git-send-email-ian.molton@collabora.co.uk> <1261068295-25831-2-git-send-email-ian.molton@collabora.co.uk> X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: Ian Molton Subject: [Qemu-devel] [PATCH 2/4] socket: Add a reconnect option. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add a reconnect option that allows sockets to reconnect (after a specified delay) to the specified server. This makes the virtio-rng driver useful in production environments where the EGD server may need to be restarted. Signed-off-by: Ian Molton --- qemu-char.c | 159 +++++++++++++++++++++++++++++++++++++++++++-------------- qemu-char.h | 2 + qemu-config.c | 3 + vl.c | 4 ++ 4 files changed, 129 insertions(+), 39 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index b13f8d4..fabc96b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1871,8 +1871,12 @@ typedef struct { int max_size; int do_telnetopt; int do_nodelay; + int reconnect; int is_unix; int msgfd; + QemuOpts *opts; + CharDriverState *chr; + int (*setup)(QemuOpts *opts); } TCPCharDriver; static void tcp_chr_accept(void *opaque); @@ -2012,6 +2016,8 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) } #endif +static void qemu_chr_sched_reconnect(TCPCharDriver *s); + static void tcp_chr_read(void *opaque) { CharDriverState *chr = opaque; @@ -2031,10 +2037,16 @@ static void tcp_chr_read(void *opaque) if (s->listen_fd >= 0) { qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); } - qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + if (!s->reconnect) { + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + } closesocket(s->fd); s->fd = -1; - qemu_chr_event(chr, CHR_EVENT_CLOSED); + if (s->reconnect) { + qemu_chr_sched_reconnect(s); + } else { + qemu_chr_event(chr, CHR_EVENT_CLOSED); + } } else if (size > 0) { if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); @@ -2134,11 +2146,92 @@ static void tcp_chr_close(CharDriverState *chr) qemu_chr_event(chr, CHR_EVENT_CLOSED); } +static int qemu_chr_connect_socket(TCPCharDriver *s) +{ + QemuOpts *opts = s->opts; + int is_listen; + int fd; + int is_waitconnect; + int do_nodelay; + + is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); + is_listen = qemu_opt_get_bool(opts, "server", 0); + do_nodelay = !qemu_opt_get_bool(opts, "delay", 1); + + + fd = s->setup(s->opts); + if (fd < 0) + return 0; + + if (!is_waitconnect) + socket_set_nonblock(fd); + + if (is_listen) { + s->listen_fd = fd; + qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, s->chr); + if (is_waitconnect) { + printf("QEMU waiting for connection on: %s\n", + s->chr->filename); + tcp_chr_accept(s->chr); + socket_set_nonblock(s->listen_fd); + } + } else { + s->fd = fd; + socket_set_nodelay(fd); + tcp_chr_connect(s->chr); + } + + return 1; +} + +static QLIST_HEAD(reconnect_list_head, reconnect_list_entry) rcl_head; + +typedef struct reconnect_list_entry { + TCPCharDriver *s; + uint64_t when; + QLIST_ENTRY(reconnect_list_entry) entries; +} reconnect_list_entry; + +static void qemu_chr_sched_reconnect(TCPCharDriver *s) +{ + reconnect_list_entry *new = qemu_malloc(sizeof(*new)); + struct timeval tv; + + qemu_gettimeofday(&tv); + new->s = s; + new->when = (s->reconnect + tv.tv_sec) * 1000000 + tv.tv_usec; + QLIST_INSERT_HEAD(&rcl_head, new, entries); +} + +void qemu_chr_reconnect(void) +{ + struct timeval tv; + uint64_t now; + reconnect_list_entry *np; + + if (!rcl_head.lh_first) + return; + + gettimeofday(&tv, NULL); + now = tv.tv_sec * 1000000 + tv.tv_usec; + + for (np = rcl_head.lh_first; np != NULL; np = np->entries.le_next) { + if (np->when <= now) { + if (qemu_chr_connect_socket(np->s)) { + qemu_chr_event(np->s->chr, CHR_EVENT_RECONNECTED); + QLIST_REMOVE(np, entries); + } + else { + np->when += np->s->reconnect * 1000000; + } + } + } +} + static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) { CharDriverState *chr = NULL; TCPCharDriver *s = NULL; - int fd = -1; int is_listen; int is_waitconnect; int do_nodelay; @@ -2146,34 +2239,40 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) int is_telnet; is_listen = qemu_opt_get_bool(opts, "server", 0); + is_unix = qemu_opt_get(opts, "path") != NULL; + is_waitconnect = qemu_opt_get_bool(opts, "wait", 1); is_telnet = qemu_opt_get_bool(opts, "telnet", 0); do_nodelay = !qemu_opt_get_bool(opts, "delay", 1); - is_unix = qemu_opt_get(opts, "path") != NULL; - if (!is_listen) + + if (!is_listen) { is_waitconnect = 0; + } else { + if (is_telnet) + s->do_telnetopt = 1; + } + - chr = qemu_mallocz(sizeof(CharDriverState)); s = qemu_mallocz(sizeof(TCPCharDriver)); + chr = qemu_mallocz(sizeof(CharDriverState)); + s->opts = opts; + + if (!is_listen && !is_telnet) + s->reconnect = qemu_opt_get_number(opts, "reconnect", 0); if (is_unix) { if (is_listen) { - fd = unix_listen_opts(opts); + s->setup = unix_listen_opts; } else { - fd = unix_connect_opts(opts); + s->setup = unix_connect_opts; } } else { if (is_listen) { - fd = inet_listen_opts(opts, 0); + s->setup = inet_listen_opts; } else { - fd = inet_connect_opts(opts); + s->setup = inet_connect_opts; } } - if (fd < 0) - goto fail; - - if (!is_waitconnect) - socket_set_nonblock(fd); s->connected = 0; s->fd = -1; @@ -2187,19 +2286,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) chr->chr_close = tcp_chr_close; chr->get_msgfd = tcp_get_msgfd; - if (is_listen) { - s->listen_fd = fd; - qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); - if (is_telnet) - s->do_telnetopt = 1; - - } else { - s->connected = 1; - s->fd = fd; - socket_set_nodelay(fd); - tcp_chr_connect(chr); - } - /* for "info chardev" monitor command */ chr->filename = qemu_malloc(256); if (is_unix) { @@ -2216,19 +2302,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) qemu_opt_get_bool(opts, "server", 0) ? ",server" : ""); } - if (is_listen && is_waitconnect) { - printf("QEMU waiting for connection on: %s\n", - chr->filename); - tcp_chr_accept(chr); - socket_set_nonblock(s->listen_fd); - } - return chr; + s->chr = chr; + + if(qemu_chr_connect_socket(s)) + return chr; - fail: - if (fd >= 0) - closesocket(fd); - qemu_free(s); qemu_free(chr); + qemu_free(s); + return NULL; } diff --git a/qemu-char.h b/qemu-char.h index bcc0766..32bcfd7 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -15,6 +15,7 @@ #define CHR_EVENT_MUX_IN 3 /* mux-focus was set to this terminal */ #define CHR_EVENT_MUX_OUT 4 /* mux-focus will move on */ #define CHR_EVENT_CLOSED 5 /* connection closed */ +#define CHR_EVENT_RECONNECTED 6 /* reconnect event */ #define CHR_IOCTL_SERIAL_SET_PARAMS 1 @@ -75,6 +76,7 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)); CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)); void qemu_chr_close(CharDriverState *chr); +void qemu_chr_reconnect(void); void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); diff --git a/qemu-config.c b/qemu-config.c index c3203c8..a229350 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -144,6 +144,9 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "signal", .type = QEMU_OPT_BOOL, + },{ + .name = "reconnect", + .type = QEMU_OPT_NUMBER, }, { /* end if list */ } }, diff --git a/vl.c b/vl.c index c0d98f5..fa8d2ae 100644 --- a/vl.c +++ b/vl.c @@ -3917,6 +3917,10 @@ void main_loop_wait(int timeout) host_main_loop_wait(&timeout); + /* Reconnect any disconnected sockets, if necessary */ + + qemu_chr_reconnect(); + /* poll any events */ /* XXX: separate device handlers from system ones */ nfds = -1;