From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH 09/10] chardev: add socket chardev support to chardev-add (qmp)
Date: Wed, 16 Jan 2013 11:21:12 +0100 [thread overview]
Message-ID: <1358331673-6159-10-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1358331673-6159-1-git-send-email-kraxel@redhat.com>
qemu_chr_open_socket is split into two functions. All initialization
after creating the socket file handler is split 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 | 28 ++++++++-
qemu-char.c | 166 +++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 138 insertions(+), 56 deletions(-)
diff --git a/qapi-schema.json b/qapi-schema.json
index 320fa6b..5c3e3eb 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3049,6 +3049,27 @@
'type' : 'ChardevPortKind'} }
##
+# @ChardevSocket:
+#
+# Configuration info for socket chardevs.
+#
+# @addr: socket address to listen on (server=true)
+# or connect to (server=false)
+# @server: #optional create server socket (default: true)
+# @wait: #optional wait for connect (not used for server
+# sockets, default: false)
+# @nodelay: #optional set TCP_NODELAY socket option (default: false)
+# @telnet: #optional enable telnet protocol (default: false)
+#
+# Since: 1.4
+##
+{ 'type': 'ChardevSocket', 'data': { 'addr' : 'SocketAddress',
+ '*server' : 'bool',
+ '*wait' : 'bool',
+ '*nodelay' : 'bool',
+ '*telnet' : 'bool' } }
+
+##
# @ChardevBackend:
#
# Configuration info for the new chardev backend.
@@ -3057,9 +3078,10 @@
##
{ 'type': 'ChardevDummy', 'data': { } }
-{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
- 'port' : 'ChardevPort',
- 'null' : 'ChardevDummy' } }
+{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
+ 'port' : 'ChardevPort',
+ 'socket' : 'ChardevSocket',
+ 'null' : 'ChardevDummy' } }
##
# @ChardevReturn:
diff --git a/qemu-char.c b/qemu-char.c
index 7091e05..36d7e29 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2438,10 +2438,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, bool do_nodelay,
+ bool is_listen, bool is_telnet,
+ bool 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;
@@ -2458,9 +2536,6 @@ 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_listen) {
fd = unix_listen_opts(opts, &local_err);
@@ -2481,56 +2556,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);
@@ -2539,8 +2572,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;
}
@@ -3124,6 +3159,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_nodelay ? sock->nodelay : false;
+ 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);
+}
+
ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
Error **errp)
{
@@ -3144,6 +3201,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
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.9.7
next prev parent reply other threads:[~2013-01-16 10:21 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-16 10:21 [Qemu-devel] [PULL 00/10] chardev hotplug support Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 01/10] chardev: add error reporting for qemu_chr_new_from_opts Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 02/10] chardev: fix QemuOpts lifecycle Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 03/10] chardev: reduce chardev ifdef mess a bit Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 04/10] chardev: add qmp hotplug commands, with null chardev support Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 05/10] chardev: add hmp hotplug commands Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 06/10] chardev: add file chardev support to chardev-add (qmp) Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 07/10] chardev: add serial " Gerd Hoffmann
2013-01-16 10:21 ` [Qemu-devel] [PATCH 08/10] chardev: add parallel " Gerd Hoffmann
2013-01-16 10:21 ` Gerd Hoffmann [this message]
2013-01-16 10:21 ` [Qemu-devel] [PATCH 10/10] chardev: add pty " Gerd Hoffmann
2013-01-16 13:23 ` [Qemu-devel] [PULL 00/10] chardev hotplug support Eric Blake
2013-01-17 1:22 ` Anthony Liguori
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=1358331673-6159-10-git-send-email-kraxel@redhat.com \
--to=kraxel@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).