From patchwork Thu Dec 3 10:04:30 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Molton X-Patchwork-Id: 40141 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 55D63B6F07 for ; Thu, 3 Dec 2009 21:06:02 +1100 (EST) Received: from localhost ([127.0.0.1]:53591 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NG8ZS-00036U-SG for incoming@patchwork.ozlabs.org; Thu, 03 Dec 2009 05:05:58 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NG8Yo-00036G-TG for qemu-devel@nongnu.org; Thu, 03 Dec 2009 05:05:18 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NG8Ym-00035k-GQ for qemu-devel@nongnu.org; Thu, 03 Dec 2009 05:05:18 -0500 Received: from [199.232.76.173] (port=42804 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NG8Ym-00035h-Av for qemu-devel@nongnu.org; Thu, 03 Dec 2009 05:05:16 -0500 Received: from bhuna.collabora.co.uk ([93.93.128.226]:34331) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NG8Yl-0004PU-KJ for qemu-devel@nongnu.org; Thu, 03 Dec 2009 05:05:16 -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 0866B60115A; Thu, 3 Dec 2009 10:05:11 +0000 (GMT) Message-ID: <4B178D2E.9090608@collabora.co.uk> Date: Thu, 03 Dec 2009 10:04:30 +0000 From: Ian Molton User-Agent: Mozilla-Thunderbird 2.0.0.22 (X11/20090707) MIME-Version: 1.0 To: "Krumme, Chris" Subject: Re: [Qemu-devel] 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> In-Reply-To: <58BD0469C48A7443A479A13D101685E30380C029@ala-mail09.corp.ad.wrs.com> X-Enigmail-Version: 0.96.0 X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: 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 Krumme, Chris wrote: > Hello Ian, Hello! > Qemu_malloc will never return 0, so sched function can return void. Gah! nasty. Check removed. > This is a mixture of tabs and spaces, for new code pick one. I've been sticking with spaces generally. I can't find 'CodingStyle' so I copied. I think spaces suck for this though. What is acceptable? linux kernel style ? > The if(prev) can just be this = prev; if prev is NULL you want NULL > anyway. Quite. Fixed. > Thanks Likewise. Fresh patch attached. Anthony, if this is ok, I can rebase this and its prerequisite. From 05581c5badd693b7537fe57f85a2ff5ddcb7972d 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 | 169 ++++++++++++++++++++++++++++++++++++++++++++------------- qemu-char.h | 2 + qemu-config.c | 3 + vl.c | 4 ++ 4 files changed, 139 insertions(+), 39 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index e202585..f20d697 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,61 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len) } #endif +struct reconnect_list { + TCPCharDriver *s; + uint64_t when; + struct reconnect_list *next; +}; + +static struct reconnect_list *rc_list; + +static void qemu_chr_sched_reconnect(TCPCharDriver *s) +{ + struct reconnect_list *new = qemu_malloc(sizeof(*new)); + struct timeval tv; + + gettimeofday(&tv, NULL); + new->s = s; + new->when = (s->reconnect + tv.tv_sec) * 1000000 + tv.tv_usec; + new->next = rc_list; + rc_list = new; +} + +static int qemu_chr_connect_socket(TCPCharDriver *s); + +void qemu_chr_reconnect(void) +{ + struct reconnect_list *this = rc_list, *prev = NULL; + struct timeval tv; + uint64_t now; + + if (!this) + return; + + gettimeofday(&tv, NULL); + now = tv.tv_sec * 1000000 + tv.tv_usec; + + while (this) { + if (this->when <= now) { + if (qemu_chr_connect_socket(this->s)) { + if (prev) + prev->next = this->next; + else + rc_list = NULL; + qemu_chr_event(this->s->chr, CHR_EVENT_RECONNECTED); + free(this); + this = prev; + } + else { + this->when += this->s->reconnect * 1000000; + } + } + prev = this; + if (this) + this = this->next; + } +} + static void tcp_chr_read(void *opaque) { CharDriverState *chr = opaque; @@ -2030,10 +2089,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); @@ -2137,7 +2202,6 @@ 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 +2209,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 +2256,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,22 +2272,56 @@ 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; } + +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 QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; 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;