From patchwork Thu Dec 3 18:37:15 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Molton X-Patchwork-Id: 40190 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 CEDDDB7BE9 for ; Fri, 4 Dec 2009 05:39:01 +1100 (EST) Received: from localhost ([127.0.0.1]:60748 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NGGZu-0004V7-Td for incoming@patchwork.ozlabs.org; Thu, 03 Dec 2009 13:38:58 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NGGYy-0004JG-Hk for qemu-devel@nongnu.org; Thu, 03 Dec 2009 13:38:00 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NGGYx-0004J0-UL for qemu-devel@nongnu.org; Thu, 03 Dec 2009 13:38:00 -0500 Received: from [199.232.76.173] (port=37476 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NGGYx-0004Ix-Mw for qemu-devel@nongnu.org; Thu, 03 Dec 2009 13:37:59 -0500 Received: from bhuna.collabora.co.uk ([93.93.128.226]:49290) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NGGYx-0005U8-69 for qemu-devel@nongnu.org; Thu, 03 Dec 2009 13:37:59 -0500 Received: from [192.168.1.164] (94-192-117-31.zone6.bethere.co.uk [94.192.117.31]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 53E4F601595; Thu, 3 Dec 2009 18:37:56 +0000 (GMT) Message-ID: <4B18055B.1030606@collabora.co.uk> Date: Thu, 03 Dec 2009 18:37:15 +0000 From: Ian Molton User-Agent: Mozilla-Thunderbird 2.0.0.22 (X11/20090707) MIME-Version: 1.0 To: Anthony Liguori Subject: Re: [Qemu-devel] [PATCH]Socket reconnection. References: <4B0DCC45.5080308@collabora.co.uk> <4B13FE66.2080401@codemonkey.ws> <4B1503EF.6090806@collabora.co.uk> <58BD0469C48A7443A479A13D101685E30380B88A@ala-mail09.corp.ad.wrs.com> <4B156672.1010008@codemonkey.ws> <4B16442E.3090706@collabora.co.uk> <58BD0469C48A7443A479A13D101685E30380C029@ala-mail09.corp.ad.wrs.com> <4B178D2E.9090608@collabora.co.uk> <4B17C98F.1060208@codemonkey.ws> In-Reply-To: <4B17C98F.1060208@codemonkey.ws> X-Enigmail-Version: 0.96.0 X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: "Krumme, Chris" , qemu-devel@nongnu.org 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 Anthony Liguori wrote: New patch attached, addressing the below. Thanks! > CODING_STYLE is off (as I mentioned before). Hopefully fixed now. >> + gettimeofday(&tv, NULL); >> > > This will break Win32 (use qemu_gettimeofday). Done > Don't open code a list, use one of the sys-queue types. I only wanted a singly linked list. However, changed to a QLIST >> +static int qemu_chr_connect_socket(TCPCharDriver *s); >> > > Forward declarations usually imply some form of code motion is required. Cant see any way around it here. I've reordered it so the new code needs the forward dec. rather than adding one for the old code. > Mixing tabs and spaces. fixed. From 8d12cabf09996eef9adcc121ea3cbec70d48b3b4 Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Tue, 1 Dec 2009 11:18:41 +0000 Subject: [PATCH 2/4] socket: Add a reconnect option. 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 e202585..45c9f3d 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1870,8 +1870,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); @@ -2011,6 +2015,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; @@ -2030,10 +2036,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); @@ -2133,11 +2145,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; @@ -2145,34 +2238,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; @@ -2186,19 +2285,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) { @@ -2215,19 +2301,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 9957db1..dc954e2 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -14,6 +14,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 @@ -73,6 +74,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 590fc05..ff8b06e 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -140,6 +140,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 44763af..5876c3e 100644 --- a/vl.c +++ b/vl.c @@ -3795,6 +3795,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; -- 1.6.5