From: Gerd Hoffmann <kraxel@redhat.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: Michal Privoznik <mprivozn@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH RfC 0/9] chardev hotplug
Date: Thu, 20 Dec 2012 14:02:51 +0100 [thread overview]
Message-ID: <50D30C7B.3030802@redhat.com> (raw)
In-Reply-To: <50D2FA5D.30602@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 208 bytes --]
Hi,
> /me wades through the socket code (unix+tcp) right now, which needs some
> refactoring to make it fly.
Sneak preview attached. Goes on top of the series.
Compile tested only so far.
enjoy,
Gerd
[-- Attachment #2: 0001-chardev-hotplug-qmp-socket.patch --]
[-- Type: text/plain, Size: 9258 bytes --]
From 2c5568c20d97d497b43c9af1c1c1388db089c1e9 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Thu, 20 Dec 2012 13:53:12 +0100
Subject: [PATCH] chardev: hotplug, qmp, socket
qemu_chr_open_socket is splitted into two functions. All initialization
after creating the socket file handler is splitted away into the new
qemu_chr_open_socket_fd function.
chr->filename doesn't get filled from QemuOpts any more. Qemu gathers
the information using getsockname and getnameinfo instead. This way it
will also work correctly for file handles passed via file descriptor
passing.
Finally qmp_chardev_open_socket() is the actual qmp hotplug
implementation which basically just calls socket_listen or
socket_connect and the new qemu_chr_open_socket_fd function.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
qapi-schema.json | 13 +++-
qemu-char.c | 168 ++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 124 insertions(+), 57 deletions(-)
diff --git a/qapi-schema.json b/qapi-schema.json
index 0922823..39e0ab4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3043,11 +3043,18 @@
{ 'type': 'ChardevPort', 'data': { 'device' : 'ChardevFileSource',
'type' : 'ChardevPortKind'} }
+{ 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress',
+ '*server' : 'bool',
+ '*wait' : 'bool',
+ '*delay' : 'bool',
+ '*telnet' : 'bool' } }
+
{ 'type': 'ChardevDummy', 'data': { } }
-{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
- 'port' : 'ChardevPort',
- 'null' : 'ChardevDummy' } }
+{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
+ 'port' : 'ChardevPort',
+ 'socket' : 'ChardevSocket',
+ 'null' : 'ChardevDummy' } }
{ 'command': 'chardev-add', 'data': {'id' : 'str',
'backend' : 'ChardevBackend' } }
diff --git a/qemu-char.c b/qemu-char.c
index 5a6d3c5..15f2ae2 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2427,10 +2427,88 @@ static void tcp_chr_close(CharDriverState *chr)
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
-static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_socket_fd(int fd, int do_nodelay,
+ int is_listen, int is_telnet,
+ int is_waitconnect,
+ Error **errp)
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
+ char host[NI_MAXHOST], serv[NI_MAXSERV];
+ const char *left = "", *right = "";
+ struct sockaddr_storage ss;
+ socklen_t ss_len = sizeof(ss);
+
+ memset(&ss, 0, ss_len);
+ if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) {
+ error_setg(errp, "getsockname: %s", strerror(errno));
+ return NULL;
+ }
+
+ chr = g_malloc0(sizeof(CharDriverState));
+ s = g_malloc0(sizeof(TCPCharDriver));
+
+ s->connected = 0;
+ s->fd = -1;
+ s->listen_fd = -1;
+ s->msgfd = -1;
+
+ chr->filename = g_malloc(256);
+ switch (ss.ss_family) {
+#ifndef _WIN32
+ case AF_UNIX:
+ s->is_unix = 1;
+ snprintf(chr->filename, 256, "unix:%s%s",
+ ((struct sockaddr_un *)(&ss))->sun_path,
+ is_listen ? ",server" : "");
+ break;
+#endif
+ case AF_INET6:
+ left = "[";
+ right = "]";
+ /* fall through */
+ case AF_INET:
+ s->do_nodelay = do_nodelay;
+ getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
+ serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
+ snprintf(chr->filename, 256, "%s:%s:%s%s%s%s",
+ is_telnet ? "telnet" : "tcp",
+ left, host, right, serv,
+ is_listen ? ",server" : "");
+ break;
+ }
+
+ chr->opaque = s;
+ chr->chr_write = tcp_chr_write;
+ chr->chr_close = tcp_chr_close;
+ chr->get_msgfd = tcp_get_msgfd;
+ chr->chr_add_client = tcp_chr_add_client;
+
+ if (is_listen) {
+ s->listen_fd = fd;
+ qemu_set_fd_handler2(s->listen_fd, NULL, 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);
+ }
+
+ 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;
+}
+
+static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+{
+ CharDriverState *chr = NULL;
Error *local_err = NULL;
int fd = -1;
int is_listen;
@@ -2447,10 +2525,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
if (!is_listen)
is_waitconnect = 0;
- chr = g_malloc0(sizeof(CharDriverState));
- s = g_malloc0(sizeof(TCPCharDriver));
-
- if (is_unix) {
+ if (is_unix) {
if (is_listen) {
fd = unix_listen_opts(opts, &local_err);
} else {
@@ -2470,56 +2545,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
if (!is_waitconnect)
socket_set_nonblock(fd);
- s->connected = 0;
- s->fd = -1;
- s->listen_fd = -1;
- s->msgfd = -1;
- s->is_unix = is_unix;
- s->do_nodelay = do_nodelay && !is_unix;
-
- chr->opaque = s;
- chr->chr_write = tcp_chr_write;
- chr->chr_close = tcp_chr_close;
- chr->get_msgfd = tcp_get_msgfd;
- chr->chr_add_client = tcp_chr_add_client;
-
- if (is_listen) {
- s->listen_fd = fd;
- qemu_set_fd_handler2(s->listen_fd, NULL, 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 = g_malloc(256);
- if (is_unix) {
- snprintf(chr->filename, 256, "unix:%s%s",
- qemu_opt_get(opts, "path"),
- qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
- } else if (is_telnet) {
- snprintf(chr->filename, 256, "telnet:%s:%s%s",
- qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
- qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
- } else {
- snprintf(chr->filename, 256, "tcp:%s:%s%s",
- qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
- 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);
+ chr = qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, is_telnet,
+ is_waitconnect, &local_err);
+ if (error_is_set(&local_err)) {
+ goto fail;
}
return chr;
+
fail:
if (local_err) {
qerror_report_err(local_err);
@@ -2528,8 +2561,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
if (fd >= 0) {
closesocket(fd);
}
- g_free(s);
- g_free(chr);
+ if (chr) {
+ g_free(chr->opaque);
+ g_free(chr);
+ }
return NULL;
}
@@ -3057,6 +3092,28 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
#endif /* WIN32 */
+static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock,
+ Error **errp)
+{
+ SocketAddress *addr = sock->addr;
+ bool do_nodelay = sock->has_delay ? !sock->delay : true;
+ bool is_listen = sock->has_server ? sock->server : true;
+ bool is_telnet = sock->has_telnet ? sock->telnet : false;
+ bool is_waitconnect = sock->has_wait ? sock->wait : false;
+ int fd;
+
+ if (is_listen) {
+ fd = socket_listen(addr, errp);
+ } else {
+ fd = socket_connect(addr, errp, NULL, NULL);
+ }
+ if (error_is_set(errp)) {
+ return NULL;
+ }
+ return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen,
+ is_telnet, is_waitconnect, errp);
+}
+
void qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp)
{
CharDriverState *chr;
@@ -3068,6 +3125,9 @@ void qmp_chardev_add(const char *id, ChardevBackend *backend, Error **errp)
case CHARDEV_BACKEND_KIND_PORT:
chr = qmp_chardev_open_port(backend->port, errp);
break;
+ case CHARDEV_BACKEND_KIND_SOCKET:
+ chr = qmp_chardev_open_socket(backend->socket, errp);
+ break;
case CHARDEV_BACKEND_KIND_NULL:
chr = qemu_chr_open_null(NULL);
break;
--
1.7.1
next prev parent reply other threads:[~2012-12-20 13:03 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-12-19 15:58 [Qemu-devel] [PATCH RfC 0/9] chardev hotplug Gerd Hoffmann
2012-12-19 15:58 ` [Qemu-devel] [PATCH 1/9] chardev: add error reporting for qemu_chr_new_from_opts Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 2/9] chardev: fix QemuOpts lifecycle Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 3/9] chardev: reduce chardev ifdef mess a bit Gerd Hoffmann
2012-12-19 20:04 ` Blue Swirl
2012-12-19 15:59 ` [Qemu-devel] [PATCH 4/9] chardev: hotplug, qmp, null Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 5/9] chardev: hotplug, hmp Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 6/9] chardev: hotplug, qmp, file Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 7/9] chardev: hotplug, qmp, tty Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 8/9] chardev: hotplug, qmp, serial Gerd Hoffmann
2012-12-19 16:21 ` Paolo Bonzini
2012-12-20 7:09 ` Gerd Hoffmann
2012-12-19 15:59 ` [Qemu-devel] [PATCH 9/9] chardev: hotplug, qmp, parallel Gerd Hoffmann
2012-12-20 10:49 ` [Qemu-devel] [PATCH RfC 0/9] chardev hotplug Michal Privoznik
2012-12-20 10:56 ` Daniel P. Berrange
2012-12-20 11:10 ` Paolo Bonzini
2012-12-20 11:45 ` Gerd Hoffmann
2012-12-20 13:02 ` Gerd Hoffmann [this message]
2012-12-21 11:45 ` Gerd Hoffmann
2012-12-21 11:53 ` Paolo Bonzini
2012-12-21 12:17 ` Gerd Hoffmann
2012-12-21 12:40 ` Paolo Bonzini
2012-12-21 14:21 ` Gerd Hoffmann
2012-12-20 16:44 ` Daniel P. Berrange
2012-12-21 9:01 ` Gerd Hoffmann
2012-12-21 9:28 ` Daniel P. Berrange
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=50D30C7B.3030802@redhat.com \
--to=kraxel@redhat.com \
--cc=mprivozn@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).