Compare commits

...

6 Commits

Author SHA1 Message Date
Daniel P. Berrange
3f0230e926 vnc: distiguish between ipv4/ipv6 omitted vs set to off
The VNC code for interpreting QemuOpts does not currently
distinguish between ipv4/ipv6 being omitted, and being
set to 'off', because historically the 'ipv4' and 'ipv6'
options were just flags which did not accept a value.

The upshot is that if someone runs

  $QEMU -vnc localhost:1,ipv6=off

QEMU still uses PF_UNSPEC and thus may still bind to IPv6,
when it should use PF_INET.

This is another instance of the problem previously fixed
for chardevs in

  commit b77e7c8e99
  Author: Paolo Bonzini <pbonzini@redhat.com>
  Date:   Mon Oct 12 15:35:16 2015 +0200

    qemu-sockets: fix conversion of ipv4/ipv6 JSON to QemuOpts

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 1452518225-11751-6-git-send-email-berrange@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-01-19 15:41:01 +01:00
Daniel P. Berrange
8b39910e63 sockets: remove use of QemuOpts from socket_dgram
The socket_dgram method accepts a QAPI SocketAddress object
which it then turns into QemuOpts before calling the
inet_dgram_opts helper method. By converting the latter to
use QAPI SocketAddress directly, the QemuOpts conversion
step can be eliminated.

This removes the very last use of QemuOpts from the
sockets code, so the socket_optslist[] array is also
removed.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1452518225-11751-5-git-send-email-berrange@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-01-19 15:41:01 +01:00
Daniel P. Berrange
2942e420e0 sockets: remove use of QemuOpts from socket_connect
The socket_connect method accepts a QAPI SocketAddress object
which it then turns into QemuOpts before calling the
inet_connect_opts/unix_connect_opts helper methods. By
converting the latter to use QAPI SocketAddress directly,
the QemuOpts conversion step can be eliminated

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1452518225-11751-4-git-send-email-berrange@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-01-19 15:41:01 +01:00
Daniel P. Berrange
1856835d6d sockets: remove use of QemuOpts from socket_listen
The socket_listen method accepts a QAPI SocketAddress object
which it then turns into QemuOpts before calling the
inet_listen_opts/unix_listen_opts helper methods. By
converting the latter to use QAPI SocketAddress directly,
the QemuOpts conversion step can be eliminated

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1452518225-11751-3-git-send-email-berrange@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-01-19 15:41:01 +01:00
Daniel P. Berrange
505c4a1c5e sockets: remove use of QemuOpts from header file
There are no callers of the sockets methods which accept
QemuOpts any more. Make all the QemuOpts related functions
static to avoid new callers being added, in preparation
for removal of all QemuOpts usage, in favour of QAPI
SocketAddress.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 1452518225-11751-2-git-send-email-berrange@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2016-01-19 15:41:01 +01:00
Gerd Hoffmann
5614a283a8 add MAINTAINERS entry for qemu socket code
Cc: Daniel P. Berrange <berrange@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
Message-id: 1453129403-11357-1-git-send-email-kraxel@redhat.com
2016-01-19 15:39:06 +01:00
4 changed files with 178 additions and 204 deletions

View File

@@ -1260,6 +1260,14 @@ F: io/
F: include/io/
F: tests/test-io-*
Sockets
M: Daniel P. Berrange <berrange@redhat.com>
M: Gerd Hoffmann <kraxel@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
F: include/qemu/sockets.h
F: util/qemu-sockets.c
Usermode Emulation
------------------
Overall

View File

@@ -26,12 +26,9 @@ int inet_aton(const char *cp, struct in_addr *ia);
#endif /* !_WIN32 */
#include "qemu/option.h"
#include "qapi/error.h"
#include "qapi-types.h"
extern QemuOptsList socket_optslist;
/* misc helpers */
int qemu_socket(int domain, int type, int protocol);
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen);
@@ -54,23 +51,16 @@ int socket_set_fast_reuse(int fd);
typedef void NonBlockingConnectHandler(int fd, Error *err, void *opaque);
InetSocketAddress *inet_parse(const char *str, Error **errp);
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
int inet_listen(const char *str, char *ostr, int olen,
int socktype, int port_offset, Error **errp);
int inet_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque);
int inet_connect(const char *str, Error **errp);
int inet_nonblocking_connect(const char *str,
NonBlockingConnectHandler *callback,
void *opaque, Error **errp);
int inet_dgram_opts(QemuOpts *opts, Error **errp);
NetworkAddressFamily inet_netfamily(int family);
int unix_listen_opts(QemuOpts *opts, Error **errp);
int unix_listen(const char *path, char *ostr, int olen, Error **errp);
int unix_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque);
int unix_connect(const char *path, Error **errp);
int unix_nonblocking_connect(const char *str,
NonBlockingConnectHandler *callback,

View File

@@ -3501,8 +3501,10 @@ void vnc_display_open(const char *id, Error **errp)
const char *websocket = qemu_opt_get(opts, "websocket");
int to = qemu_opt_get_number(opts, "to", 0);
bool has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
bool has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
bool has_ipv4 = qemu_opt_get(opts, "ipv4");
bool has_ipv6 = qemu_opt_get(opts, "ipv6");
bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
saddr = g_new0(SocketAddress, 1);
if (websocket) {
@@ -3550,8 +3552,10 @@ void vnc_display_open(const char *id, Error **errp)
saddr->u.inet->has_to = true;
saddr->u.inet->to = to + 5900;
}
saddr->u.inet->ipv4 = saddr->u.inet->has_ipv4 = has_ipv4;
saddr->u.inet->ipv6 = saddr->u.inet->has_ipv6 = has_ipv6;
saddr->u.inet->ipv4 = ipv4;
saddr->u.inet->has_ipv4 = has_ipv4;
saddr->u.inet->ipv6 = ipv6;
saddr->u.inet->has_ipv6 = has_ipv6;
if (vs->ws_enabled) {
wsaddr->type = SOCKET_ADDRESS_KIND_INET;
@@ -3563,8 +3567,10 @@ void vnc_display_open(const char *id, Error **errp)
wsaddr->u.inet->has_to = true;
wsaddr->u.inet->to = to;
}
wsaddr->u.inet->ipv4 = wsaddr->u.inet->has_ipv4 = has_ipv4;
wsaddr->u.inet->ipv6 = wsaddr->u.inet->has_ipv6 = has_ipv6;
wsaddr->u.inet->ipv4 = ipv4;
wsaddr->u.inet->has_ipv4 = has_ipv4;
wsaddr->u.inet->ipv6 = ipv6;
wsaddr->u.inet->has_ipv6 = has_ipv6;
}
}
} else {

View File

@@ -36,39 +36,6 @@
# define AI_V4MAPPED 0
#endif
/* used temporarily until all users are converted to QemuOpts */
QemuOptsList socket_optslist = {
.name = "socket",
.head = QTAILQ_HEAD_INITIALIZER(socket_optslist.head),
.desc = {
{
.name = "path",
.type = QEMU_OPT_STRING,
},{
.name = "host",
.type = QEMU_OPT_STRING,
},{
.name = "port",
.type = QEMU_OPT_STRING,
},{
.name = "localaddr",
.type = QEMU_OPT_STRING,
},{
.name = "localport",
.type = QEMU_OPT_STRING,
},{
.name = "to",
.type = QEMU_OPT_NUMBER,
},{
.name = "ipv4",
.type = QEMU_OPT_BOOL,
},{
.name = "ipv6",
.type = QEMU_OPT_BOOL,
},
{ /* end if list */ }
},
};
static int inet_getport(struct addrinfo *e)
{
@@ -114,36 +81,78 @@ NetworkAddressFamily inet_netfamily(int family)
return NETWORK_ADDRESS_FAMILY_UNKNOWN;
}
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
/*
* Matrix we're trying to apply
*
* ipv4 ipv6 family
* - - PF_UNSPEC
* - f PF_INET
* - t PF_INET6
* f - PF_INET6
* f f <error>
* f t PF_INET6
* t - PF_INET
* t f PF_INET
* t t PF_INET6
*
* NB, this matrix is only about getting the neccessary results
* from getaddrinfo(). Some of the cases require further work
* after reading results from getaddrinfo in order to fully
* apply the logic the end user wants. eg with the last case
* ipv4=t + ipv6=t + PF_INET6, getaddrinfo alone can only
* guarantee the ipv6=t part of the request - we need more
* checks to provide ipv4=t part of the guarantee. This is
* outside scope of this method and not currently handled by
* callers at all.
*/
static int inet_ai_family_from_address(InetSocketAddress *addr,
Error **errp)
{
if (addr->has_ipv6 && addr->has_ipv4 &&
!addr->ipv6 && !addr->ipv4) {
error_setg(errp, "Cannot disable IPv4 and IPv6 at same time");
return PF_UNSPEC;
}
if ((addr->has_ipv6 && addr->ipv6) || (addr->has_ipv4 && !addr->ipv4)) {
return PF_INET6;
}
if ((addr->has_ipv4 && addr->ipv4) || (addr->has_ipv6 && !addr->ipv6)) {
return PF_INET;
}
return PF_UNSPEC;
}
static int inet_listen_saddr(InetSocketAddress *saddr,
int port_offset,
bool update_addr,
Error **errp)
{
struct addrinfo ai,*res,*e;
const char *addr;
char port[33];
char uaddr[INET6_ADDRSTRLEN+1];
char uport[33];
int slisten, rc, to, port_min, port_max, p;
int slisten, rc, port_min, port_max, p;
Error *err = NULL;
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_PASSIVE;
ai.ai_family = PF_UNSPEC;
ai.ai_family = inet_ai_family_from_address(saddr, &err);
ai.ai_socktype = SOCK_STREAM;
if ((qemu_opt_get(opts, "host") == NULL)) {
if (err) {
error_propagate(errp, err);
return -1;
}
if (saddr->host == NULL) {
error_setg(errp, "host not specified");
return -1;
}
if (qemu_opt_get(opts, "port") != NULL) {
pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
if (saddr->port != NULL) {
pstrcpy(port, sizeof(port), saddr->port);
} else {
port[0] = '\0';
}
addr = qemu_opt_get(opts, "host");
to = qemu_opt_get_number(opts, "to", 0);
if (qemu_opt_get_bool(opts, "ipv4", 0))
ai.ai_family = PF_INET;
if (qemu_opt_get_bool(opts, "ipv6", 0))
ai.ai_family = PF_INET6;
/* lookup */
if (port_offset) {
@@ -163,11 +172,11 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
}
snprintf(port, sizeof(port), "%d", (int)baseport + port_offset);
}
rc = getaddrinfo(strlen(addr) ? addr : NULL,
rc = getaddrinfo(strlen(saddr->host) ? saddr->host : NULL,
strlen(port) ? port : NULL, &ai, &res);
if (rc != 0) {
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
gai_strerror(rc));
error_setg(errp, "address resolution failed for %s:%s: %s",
saddr->host, port, gai_strerror(rc));
return -1;
}
@@ -195,7 +204,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
#endif
port_min = inet_getport(e);
port_max = to ? to + port_offset : port_min;
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
for (p = port_min; p <= port_max; p++) {
inet_setport(e, p);
if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
@@ -219,13 +228,15 @@ listen:
freeaddrinfo(res);
return -1;
}
qemu_opt_set(opts, "host", uaddr, &error_abort);
qemu_opt_set_number(opts, "port", inet_getport(e) - port_offset,
&error_abort);
qemu_opt_set_bool(opts, "ipv6", e->ai_family == PF_INET6,
&error_abort);
qemu_opt_set_bool(opts, "ipv4", e->ai_family != PF_INET6,
&error_abort);
if (update_addr) {
g_free(saddr->host);
saddr->host = g_strdup(uaddr);
g_free(saddr->port);
saddr->port = g_strdup_printf("%d",
inet_getport(e) - port_offset);
saddr->has_ipv6 = saddr->ipv6 = e->ai_family == PF_INET6;
saddr->has_ipv4 = saddr->ipv4 = e->ai_family != PF_INET6;
}
freeaddrinfo(res);
return slisten;
}
@@ -340,38 +351,34 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
return sock;
}
static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
Error **errp)
{
struct addrinfo ai, *res;
int rc;
const char *addr;
const char *port;
Error *err = NULL;
memset(&ai, 0, sizeof(ai));
ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG;
ai.ai_family = PF_UNSPEC;
ai.ai_family = inet_ai_family_from_address(saddr, &err);
ai.ai_socktype = SOCK_STREAM;
addr = qemu_opt_get(opts, "host");
port = qemu_opt_get(opts, "port");
if (addr == NULL || port == NULL) {
if (err) {
error_propagate(errp, err);
return NULL;
}
if (saddr->host == NULL || saddr->port == NULL) {
error_setg(errp, "host and/or port not specified");
return NULL;
}
if (qemu_opt_get_bool(opts, "ipv4", 0)) {
ai.ai_family = PF_INET;
}
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
ai.ai_family = PF_INET6;
}
/* lookup */
rc = getaddrinfo(addr, port, &ai, &res);
rc = getaddrinfo(saddr->host, saddr->port, &ai, &res);
if (rc != 0) {
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
gai_strerror(rc));
error_setg(errp, "address resolution failed for %s:%s: %s",
saddr->host, saddr->port, gai_strerror(rc));
return NULL;
}
return res;
@@ -380,8 +387,7 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
/**
* Create a socket and connect it to an address.
*
* @opts: QEMU options, recognized parameters strings "host" and "port",
* bools "ipv4" and "ipv6".
* @saddr: Inet socket address specification
* @errp: set on error
* @callback: callback function for non-blocking connect
* @opaque: opaque for callback function
@@ -392,8 +398,8 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
* function succeeds, callback will be called when the connection
* completes, with the file descriptor on success, or -1 on error.
*/
int inet_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
static int inet_connect_saddr(InetSocketAddress *saddr, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
Error *local_err = NULL;
struct addrinfo *res, *e;
@@ -401,7 +407,7 @@ int inet_connect_opts(QemuOpts *opts, Error **errp,
bool in_progress;
ConnectState *connect_state = NULL;
res = inet_parse_connect_opts(opts, errp);
res = inet_parse_connect_saddr(saddr, errp);
if (!res) {
return -1;
}
@@ -440,21 +446,29 @@ int inet_connect_opts(QemuOpts *opts, Error **errp,
return sock;
}
int inet_dgram_opts(QemuOpts *opts, Error **errp)
static int inet_dgram_saddr(InetSocketAddress *sraddr,
InetSocketAddress *sladdr,
Error **errp)
{
struct addrinfo ai, *peer = NULL, *local = NULL;
const char *addr;
const char *port;
int sock = -1, rc;
Error *err = NULL;
/* lookup peer addr */
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG;
ai.ai_family = PF_UNSPEC;
ai.ai_family = inet_ai_family_from_address(sraddr, &err);
ai.ai_socktype = SOCK_DGRAM;
addr = qemu_opt_get(opts, "host");
port = qemu_opt_get(opts, "port");
if (err) {
error_propagate(errp, err);
return -1;
}
addr = sraddr->host;
port = sraddr->port;
if (addr == NULL || strlen(addr) == 0) {
addr = "localhost";
}
@@ -463,11 +477,6 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp)
return -1;
}
if (qemu_opt_get_bool(opts, "ipv4", 0))
ai.ai_family = PF_INET;
if (qemu_opt_get_bool(opts, "ipv6", 0))
ai.ai_family = PF_INET6;
if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
gai_strerror(rc));
@@ -480,13 +489,19 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp)
ai.ai_family = peer->ai_family;
ai.ai_socktype = SOCK_DGRAM;
addr = qemu_opt_get(opts, "localaddr");
port = qemu_opt_get(opts, "localport");
if (addr == NULL || strlen(addr) == 0) {
if (sladdr) {
addr = sladdr->host;
port = sladdr->port;
if (addr == NULL || strlen(addr) == 0) {
addr = NULL;
}
if (!port || strlen(port) == 0) {
port = "0";
}
} else {
addr = NULL;
}
if (!port || strlen(port) == 0)
port = "0";
}
if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
@@ -595,54 +610,31 @@ fail:
return NULL;
}
static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr)
{
bool ipv4 = addr->has_ipv4 && addr->ipv4;
bool ipv6 = addr->has_ipv6 && addr->ipv6;
if (ipv4 || ipv6) {
qemu_opt_set_bool(opts, "ipv4", ipv4, &error_abort);
qemu_opt_set_bool(opts, "ipv6", ipv6, &error_abort);
} else if (addr->has_ipv4 || addr->has_ipv6) {
qemu_opt_set_bool(opts, "ipv4", !addr->has_ipv4, &error_abort);
qemu_opt_set_bool(opts, "ipv6", !addr->has_ipv6, &error_abort);
}
if (addr->has_to) {
qemu_opt_set_number(opts, "to", addr->to, &error_abort);
}
qemu_opt_set(opts, "host", addr->host, &error_abort);
qemu_opt_set(opts, "port", addr->port, &error_abort);
}
int inet_listen(const char *str, char *ostr, int olen,
int socktype, int port_offset, Error **errp)
{
QemuOpts *opts;
char *optstr;
int sock = -1;
InetSocketAddress *addr;
addr = inet_parse(str, errp);
if (addr != NULL) {
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
inet_addr_to_opts(opts, addr);
qapi_free_InetSocketAddress(addr);
sock = inet_listen_opts(opts, port_offset, errp);
sock = inet_listen_saddr(addr, port_offset, true, errp);
if (sock != -1 && ostr) {
optstr = strchr(str, ',');
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
if (addr->ipv6) {
snprintf(ostr, olen, "[%s]:%s%s",
qemu_opt_get(opts, "host"),
qemu_opt_get(opts, "port"),
addr->host,
addr->port,
optstr ? optstr : "");
} else {
snprintf(ostr, olen, "%s:%s%s",
qemu_opt_get(opts, "host"),
qemu_opt_get(opts, "port"),
addr->host,
addr->port,
optstr ? optstr : "");
}
}
qemu_opts_del(opts);
qapi_free_InetSocketAddress(addr);
}
return sock;
}
@@ -657,17 +649,13 @@ int inet_listen(const char *str, char *ostr, int olen,
**/
int inet_connect(const char *str, Error **errp)
{
QemuOpts *opts;
int sock = -1;
InetSocketAddress *addr;
addr = inet_parse(str, errp);
if (addr != NULL) {
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
inet_addr_to_opts(opts, addr);
sock = inet_connect_saddr(addr, errp, NULL, NULL);
qapi_free_InetSocketAddress(addr);
sock = inet_connect_opts(opts, errp, NULL, NULL);
qemu_opts_del(opts);
}
return sock;
}
@@ -689,7 +677,6 @@ int inet_nonblocking_connect(const char *str,
NonBlockingConnectHandler *callback,
void *opaque, Error **errp)
{
QemuOpts *opts;
int sock = -1;
InetSocketAddress *addr;
@@ -697,21 +684,19 @@ int inet_nonblocking_connect(const char *str,
addr = inet_parse(str, errp);
if (addr != NULL) {
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
inet_addr_to_opts(opts, addr);
sock = inet_connect_saddr(addr, errp, callback, opaque);
qapi_free_InetSocketAddress(addr);
sock = inet_connect_opts(opts, errp, callback, opaque);
qemu_opts_del(opts);
}
return sock;
}
#ifndef _WIN32
int unix_listen_opts(QemuOpts *opts, Error **errp)
static int unix_listen_saddr(UnixSocketAddress *saddr,
bool update_addr,
Error **errp)
{
struct sockaddr_un un;
const char *path = qemu_opt_get(opts, "path");
int sock, fd;
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
@@ -722,8 +707,8 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
if (path && strlen(path)) {
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
if (saddr->path && strlen(saddr->path)) {
snprintf(un.sun_path, sizeof(un.sun_path), "%s", saddr->path);
} else {
const char *tmpdir = getenv("TMPDIR");
tmpdir = tmpdir ? tmpdir : "/tmp";
@@ -748,7 +733,10 @@ int unix_listen_opts(QemuOpts *opts, Error **errp)
goto err;
}
close(fd);
qemu_opt_set(opts, "path", un.sun_path, &error_abort);
if (update_addr) {
g_free(saddr->path);
saddr->path = g_strdup(un.sun_path);
}
}
if (unlink(un.sun_path) < 0 && errno != ENOENT) {
@@ -772,15 +760,14 @@ err:
return -1;
}
int unix_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
struct sockaddr_un un;
const char *path = qemu_opt_get(opts, "path");
ConnectState *connect_state = NULL;
int sock, rc;
if (path == NULL) {
if (saddr->path == NULL) {
error_setg(errp, "unix connect: no path specified");
return -1;
}
@@ -799,7 +786,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp,
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
snprintf(un.sun_path, sizeof(un.sun_path), "%s", saddr->path);
/* connect to peer */
do {
@@ -832,15 +819,17 @@ int unix_connect_opts(QemuOpts *opts, Error **errp,
#else
int unix_listen_opts(QemuOpts *opts, Error **errp)
static int unix_listen_saddr(UnixSocketAddress *saddr,
bool update_addr,
Error **errp)
{
error_setg(errp, "unix sockets are not available on windows");
errno = ENOTSUP;
return -1;
}
int unix_connect_opts(QemuOpts *opts, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
error_setg(errp, "unix sockets are not available on windows");
errno = ENOTSUP;
@@ -851,11 +840,11 @@ int unix_connect_opts(QemuOpts *opts, Error **errp,
/* compatibility wrapper */
int unix_listen(const char *str, char *ostr, int olen, Error **errp)
{
QemuOpts *opts;
char *path, *optstr;
int sock, len;
UnixSocketAddress *saddr;
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
saddr = g_new0(UnixSocketAddress, 1);
optstr = strchr(str, ',');
if (optstr) {
@@ -863,30 +852,29 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp)
if (len) {
path = g_malloc(len+1);
snprintf(path, len+1, "%.*s", len, str);
qemu_opt_set(opts, "path", path, &error_abort);
g_free(path);
saddr->path = path;
}
} else {
qemu_opt_set(opts, "path", str, &error_abort);
saddr->path = g_strdup(str);
}
sock = unix_listen_opts(opts, errp);
sock = unix_listen_saddr(saddr, true, errp);
if (sock != -1 && ostr)
snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
qemu_opts_del(opts);
snprintf(ostr, olen, "%s%s", saddr->path, optstr ? optstr : "");
qapi_free_UnixSocketAddress(saddr);
return sock;
}
int unix_connect(const char *path, Error **errp)
{
QemuOpts *opts;
UnixSocketAddress *saddr;
int sock;
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
qemu_opt_set(opts, "path", path, &error_abort);
sock = unix_connect_opts(opts, errp, NULL, NULL);
qemu_opts_del(opts);
saddr = g_new0(UnixSocketAddress, 1);
saddr->path = g_strdup(path);
sock = unix_connect_saddr(saddr, errp, NULL, NULL);
qapi_free_UnixSocketAddress(saddr);
return sock;
}
@@ -895,15 +883,15 @@ int unix_nonblocking_connect(const char *path,
NonBlockingConnectHandler *callback,
void *opaque, Error **errp)
{
QemuOpts *opts;
UnixSocketAddress *saddr;
int sock = -1;
g_assert(callback != NULL);
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
qemu_opt_set(opts, "path", path, &error_abort);
sock = unix_connect_opts(opts, errp, callback, opaque);
qemu_opts_del(opts);
saddr = g_new0(UnixSocketAddress, 1);
saddr->path = g_strdup(path);
sock = unix_connect_saddr(saddr, errp, callback, opaque);
qapi_free_UnixSocketAddress(saddr);
return sock;
}
@@ -947,19 +935,15 @@ fail:
int socket_connect(SocketAddress *addr, Error **errp,
NonBlockingConnectHandler *callback, void *opaque)
{
QemuOpts *opts;
int fd;
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
switch (addr->type) {
case SOCKET_ADDRESS_KIND_INET:
inet_addr_to_opts(opts, addr->u.inet);
fd = inet_connect_opts(opts, errp, callback, opaque);
fd = inet_connect_saddr(addr->u.inet, errp, callback, opaque);
break;
case SOCKET_ADDRESS_KIND_UNIX:
qemu_opt_set(opts, "path", addr->u.q_unix->path, &error_abort);
fd = unix_connect_opts(opts, errp, callback, opaque);
fd = unix_connect_saddr(addr->u.q_unix, errp, callback, opaque);
break;
case SOCKET_ADDRESS_KIND_FD:
@@ -973,25 +957,20 @@ int socket_connect(SocketAddress *addr, Error **errp,
default:
abort();
}
qemu_opts_del(opts);
return fd;
}
int socket_listen(SocketAddress *addr, Error **errp)
{
QemuOpts *opts;
int fd;
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
switch (addr->type) {
case SOCKET_ADDRESS_KIND_INET:
inet_addr_to_opts(opts, addr->u.inet);
fd = inet_listen_opts(opts, 0, errp);
fd = inet_listen_saddr(addr->u.inet, 0, false, errp);
break;
case SOCKET_ADDRESS_KIND_UNIX:
qemu_opt_set(opts, "path", addr->u.q_unix->path, &error_abort);
fd = unix_listen_opts(opts, errp);
fd = unix_listen_saddr(addr->u.q_unix, false, errp);
break;
case SOCKET_ADDRESS_KIND_FD:
@@ -1001,31 +980,22 @@ int socket_listen(SocketAddress *addr, Error **errp)
default:
abort();
}
qemu_opts_del(opts);
return fd;
}
int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
{
QemuOpts *opts;
int fd;
opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort);
switch (remote->type) {
case SOCKET_ADDRESS_KIND_INET:
inet_addr_to_opts(opts, remote->u.inet);
if (local) {
qemu_opt_set(opts, "localaddr", local->u.inet->host, &error_abort);
qemu_opt_set(opts, "localport", local->u.inet->port, &error_abort);
}
fd = inet_dgram_opts(opts, errp);
fd = inet_dgram_saddr(remote->u.inet, local ? local->u.inet : NULL, errp);
break;
default:
error_setg(errp, "socket type unsupported for datagram");
fd = -1;
}
qemu_opts_del(opts);
return fd;
}