aboutsummaryrefslogtreecommitdiff
path: root/util/qemu-sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/qemu-sockets.c')
-rw-r--r--util/qemu-sockets.c380
1 files changed, 260 insertions, 120 deletions
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8bd8bb64eb..60c44b2b56 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -30,6 +30,7 @@
#include "qapi/qobject-input-visitor.h"
#include "qapi/qobject-output-visitor.h"
#include "qemu/cutils.h"
+#include "trace.h"
#ifndef AI_ADDRCONFIG
# define AI_ADDRCONFIG 0
@@ -95,7 +96,7 @@ bool fd_is_socket(int fd)
{
int optval;
socklen_t optlen = sizeof(optval);
- return !qemu_getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
+ return !getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen);
}
@@ -183,8 +184,8 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e)
rebind:
if (e->ai_family == PF_INET6) {
- qemu_setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &v6only,
- sizeof(v6only));
+ setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &v6only,
+ sizeof(v6only));
}
stat = bind(socket, e->ai_addr, e->ai_addrlen);
@@ -206,9 +207,11 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e)
static int inet_listen_saddr(InetSocketAddress *saddr,
int port_offset,
+ int num,
Error **errp)
{
- struct addrinfo ai,*res,*e;
+ ERRP_GUARD();
+ struct addrinfo ai, *res, *e;
char port[33];
char uaddr[INET6_ADDRSTRLEN+1];
char uport[33];
@@ -216,18 +219,21 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
int slisten = -1;
int saved_errno = 0;
bool socket_created = false;
- Error *err = NULL;
+
+ if (saddr->keep_alive) {
+ error_setg(errp, "keep-alive option is not supported for passive "
+ "sockets");
+ return -1;
+ }
memset(&ai,0, sizeof(ai));
ai.ai_flags = AI_PASSIVE;
if (saddr->has_numeric && saddr->numeric) {
ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
}
- ai.ai_family = inet_ai_family_from_address(saddr, &err);
ai.ai_socktype = SOCK_STREAM;
-
- if (err) {
- error_propagate(errp, err);
+ ai.ai_family = inet_ai_family_from_address(saddr, errp);
+ if (*errp) {
return -1;
}
@@ -243,12 +249,12 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
/* lookup */
if (port_offset) {
- unsigned long long baseport;
+ uint64_t baseport;
if (strlen(port) == 0) {
error_setg(errp, "port not specified");
return -1;
}
- if (parse_uint_full(port, &baseport, 10) < 0) {
+ if (parse_uint_full(port, 10, &baseport) < 0) {
error_setg(errp, "can't convert to a number: %s", port);
return -1;
}
@@ -269,9 +275,14 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
/* create socket + bind/listen */
for (e = res; e != NULL; e = e->ai_next) {
+#ifdef HAVE_IPPROTO_MPTCP
+ if (saddr->has_mptcp && saddr->mptcp) {
+ e->ai_protocol = IPPROTO_MPTCP;
+ }
+#endif
getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
- uaddr,INET6_ADDRSTRLEN,uport,32,
- NI_NUMERICHOST | NI_NUMERICSERV);
+ uaddr,INET6_ADDRSTRLEN,uport,32,
+ NI_NUMERICHOST | NI_NUMERICSERV);
port_min = inet_getport(e);
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
@@ -302,7 +313,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
goto listen_failed;
}
} else {
- if (!listen(slisten, 1)) {
+ if (!listen(slisten, num)) {
goto listen_ok;
}
if (errno != EADDRINUSE) {
@@ -315,7 +326,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
* recover from this situation, so we need to recreate the
* socket to allow bind attempts for subsequent ports:
*/
- closesocket(slisten);
+ close(slisten);
slisten = -1;
}
}
@@ -326,7 +337,7 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
listen_failed:
saved_errno = errno;
if (slisten >= 0) {
- closesocket(slisten);
+ close(slisten);
}
freeaddrinfo(res);
errno = saved_errno;
@@ -345,15 +356,15 @@ listen_ok:
((rc) == -EINPROGRESS)
#endif
-static int inet_connect_addr(struct addrinfo *addr, Error **errp);
-
-static int inet_connect_addr(struct addrinfo *addr, Error **errp)
+static int inet_connect_addr(const InetSocketAddress *saddr,
+ struct addrinfo *addr, Error **errp)
{
int sock, rc;
sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sock < 0) {
- error_setg_errno(errp, errno, "Failed to create socket");
+ error_setg_errno(errp, errno, "Failed to create socket family %d",
+ addr->ai_family);
return -1;
}
socket_set_fast_reuse(sock);
@@ -367,8 +378,9 @@ static int inet_connect_addr(struct addrinfo *addr, Error **errp)
} while (rc == -EINTR);
if (rc < 0) {
- error_setg_errno(errp, errno, "Failed to connect socket");
- closesocket(sock);
+ error_setg_errno(errp, errno, "Failed to connect to '%s:%s'",
+ saddr->host, saddr->port);
+ close(sock);
return -1;
}
@@ -378,22 +390,20 @@ static int inet_connect_addr(struct addrinfo *addr, Error **errp)
static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
Error **errp)
{
+ ERRP_GUARD();
struct addrinfo ai, *res;
int rc;
- Error *err = NULL;
static int useV4Mapped = 1;
memset(&ai, 0, sizeof(ai));
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
- if (atomic_read(&useV4Mapped)) {
+ if (qatomic_read(&useV4Mapped)) {
ai.ai_flags |= AI_V4MAPPED;
}
- ai.ai_family = inet_ai_family_from_address(saddr, &err);
ai.ai_socktype = SOCK_STREAM;
-
- if (err) {
- error_propagate(errp, err);
+ ai.ai_family = inet_ai_family_from_address(saddr, errp);
+ if (*errp) {
return NULL;
}
@@ -407,12 +417,12 @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
/* At least FreeBSD and OS-X 10.6 declare AI_V4MAPPED but
* then don't implement it in their getaddrinfo(). Detect
- * this and retry without the flag since that's preferrable
+ * this and retry without the flag since that's preferable
* to a fatal error
*/
if (rc == EAI_BADFLAGS &&
(ai.ai_flags & AI_V4MAPPED)) {
- atomic_set(&useV4Mapped, 0);
+ qatomic_set(&useV4Mapped, 0);
ai.ai_flags &= ~AI_V4MAPPED;
rc = getaddrinfo(saddr->host, saddr->port, &ai, &res);
}
@@ -446,17 +456,38 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
for (e = res; e != NULL; e = e->ai_next) {
error_free(local_err);
local_err = NULL;
- sock = inet_connect_addr(e, &local_err);
+
+#ifdef HAVE_IPPROTO_MPTCP
+ if (saddr->has_mptcp && saddr->mptcp) {
+ e->ai_protocol = IPPROTO_MPTCP;
+ }
+#endif
+
+ sock = inet_connect_addr(saddr, e, &local_err);
if (sock >= 0) {
break;
}
}
+ freeaddrinfo(res);
+
if (sock < 0) {
error_propagate(errp, local_err);
+ return sock;
+ }
+
+ if (saddr->keep_alive) {
+ int val = 1;
+ int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+ &val, sizeof(val));
+
+ if (ret < 0) {
+ error_setg_errno(errp, errno, "Unable to set KEEPALIVE");
+ close(sock);
+ return -1;
+ }
}
- freeaddrinfo(res);
return sock;
}
@@ -464,20 +495,18 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr,
InetSocketAddress *sladdr,
Error **errp)
{
+ ERRP_GUARD();
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 = inet_ai_family_from_address(sraddr, &err);
ai.ai_socktype = SOCK_DGRAM;
-
- if (err) {
- error_propagate(errp, err);
+ ai.ai_family = inet_ai_family_from_address(sraddr, errp);
+ if (*errp) {
goto err;
}
@@ -526,7 +555,8 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr,
/* create socket */
sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
if (sock < 0) {
- error_setg_errno(errp, errno, "Failed to create socket");
+ error_setg_errno(errp, errno, "Failed to create socket family %d",
+ peer->ai_family);
goto err;
}
socket_set_fast_reuse(sock);
@@ -539,7 +569,8 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr,
/* connect to peer */
if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
- error_setg_errno(errp, errno, "Failed to connect socket");
+ error_setg_errno(errp, errno, "Failed to connect to '%s:%s'",
+ addr, port);
goto err;
}
@@ -549,7 +580,7 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr,
err:
if (sock != -1) {
- closesocket(sock);
+ close(sock);
}
if (local) {
freeaddrinfo(local);
@@ -652,6 +683,26 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
}
addr->has_ipv6 = true;
}
+ begin = strstr(optstr, ",keep-alive");
+ if (begin) {
+ if (inet_parse_flag("keep-alive", begin + strlen(",keep-alive"),
+ &addr->keep_alive, errp) < 0)
+ {
+ return -1;
+ }
+ addr->has_keep_alive = true;
+ }
+#ifdef HAVE_IPPROTO_MPTCP
+ begin = strstr(optstr, ",mptcp");
+ if (begin) {
+ if (inet_parse_flag("mptcp", begin + strlen(",mptcp"),
+ &addr->mptcp, errp) < 0)
+ {
+ return -1;
+ }
+ addr->has_mptcp = true;
+ }
+#endif
return 0;
}
@@ -681,19 +732,19 @@ static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr,
struct sockaddr_vm *svm,
Error **errp)
{
- unsigned long long val;
+ uint64_t val;
memset(svm, 0, sizeof(*svm));
svm->svm_family = AF_VSOCK;
- if (parse_uint_full(vaddr->cid, &val, 10) < 0 ||
+ if (parse_uint_full(vaddr->cid, 10, &val) < 0 ||
val > UINT32_MAX) {
error_setg(errp, "Failed to parse cid '%s'", vaddr->cid);
return false;
}
svm->svm_cid = val;
- if (parse_uint_full(vaddr->port, &val, 10) < 0 ||
+ if (parse_uint_full(vaddr->port, 10, &val) < 0 ||
val > UINT32_MAX) {
error_setg(errp, "Failed to parse port '%s'", vaddr->port);
return false;
@@ -703,13 +754,15 @@ static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr,
return true;
}
-static int vsock_connect_addr(const struct sockaddr_vm *svm, Error **errp)
+static int vsock_connect_addr(const VsockSocketAddress *vaddr,
+ const struct sockaddr_vm *svm, Error **errp)
{
int sock, rc;
sock = qemu_socket(AF_VSOCK, SOCK_STREAM, 0);
if (sock < 0) {
- error_setg_errno(errp, errno, "Failed to create socket");
+ error_setg_errno(errp, errno, "Failed to create socket family %d",
+ AF_VSOCK);
return -1;
}
@@ -722,8 +775,9 @@ static int vsock_connect_addr(const struct sockaddr_vm *svm, Error **errp)
} while (rc == -EINTR);
if (rc < 0) {
- error_setg_errno(errp, errno, "Failed to connect socket");
- closesocket(sock);
+ error_setg_errno(errp, errno, "Failed to connect to '%s:%s'",
+ vaddr->cid, vaddr->port);
+ close(sock);
return -1;
}
@@ -733,18 +787,16 @@ static int vsock_connect_addr(const struct sockaddr_vm *svm, Error **errp)
static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp)
{
struct sockaddr_vm svm;
- int sock = -1;
if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) {
return -1;
}
- sock = vsock_connect_addr(&svm, errp);
-
- return sock;
+ return vsock_connect_addr(vaddr, &svm, errp);
}
static int vsock_listen_saddr(VsockSocketAddress *vaddr,
+ int num,
Error **errp)
{
struct sockaddr_vm svm;
@@ -762,13 +814,13 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr,
if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) != 0) {
error_setg_errno(errp, errno, "Failed to bind socket");
- closesocket(slisten);
+ close(slisten);
return -1;
}
- if (listen(slisten, 1) != 0) {
+ if (listen(slisten, num) != 0) {
error_setg_errno(errp, errno, "Failed to listen on socket");
- closesocket(slisten);
+ close(slisten);
return -1;
}
return slisten;
@@ -807,6 +859,7 @@ static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp)
}
static int vsock_listen_saddr(VsockSocketAddress *vaddr,
+ int num,
Error **errp)
{
vsock_unsupported(errp);
@@ -821,15 +874,35 @@ static int vsock_parse(VsockSocketAddress *addr, const char *str,
}
#endif /* CONFIG_AF_VSOCK */
-#ifndef _WIN32
+static bool saddr_is_abstract(UnixSocketAddress *saddr)
+{
+#ifdef CONFIG_LINUX
+ return saddr->abstract;
+#else
+ return false;
+#endif
+}
+
+static bool saddr_is_tight(UnixSocketAddress *saddr)
+{
+#ifdef CONFIG_LINUX
+ return !saddr->has_tight || saddr->tight;
+#else
+ return false;
+#endif
+}
static int unix_listen_saddr(UnixSocketAddress *saddr,
+ int num,
Error **errp)
{
+ bool abstract = saddr_is_abstract(saddr);
struct sockaddr_un un;
int sock, fd;
char *pathbuf = NULL;
const char *path;
+ size_t pathlen;
+ size_t addrlen;
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
@@ -837,24 +910,26 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
return -1;
}
- if (saddr->path && saddr->path[0]) {
+ if (saddr->path[0] || abstract) {
path = saddr->path;
} else {
- const char *tmpdir = getenv("TMPDIR");
- tmpdir = tmpdir ? tmpdir : "/tmp";
- path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir);
+ path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX",
+ g_get_tmp_dir());
}
- if (strlen(path) > sizeof(un.sun_path)) {
+ pathlen = strlen(path);
+ if (pathlen > sizeof(un.sun_path) ||
+ (abstract && pathlen > (sizeof(un.sun_path) - 1))) {
error_setg(errp, "UNIX socket path '%s' is too long", path);
error_append_hint(errp, "Path must be less than %zu bytes\n",
+ abstract ? sizeof(un.sun_path) - 1 :
sizeof(un.sun_path));
goto err;
}
if (pathbuf != NULL) {
/*
- * This dummy fd usage silences the mktemp() unsecure warning.
+ * This dummy fd usage silences the mktemp() insecure warning.
* Using mkstemp() doesn't make things more secure here
* though. bind() complains about existing files, so we have
* to unlink first and thus re-open the race window. The
@@ -869,7 +944,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
close(fd);
}
- if (unlink(path) < 0 && errno != ENOENT) {
+ if (!abstract && unlink(path) < 0 && errno != ENOENT) {
error_setg_errno(errp, errno,
"Failed to unlink socket %s", path);
goto err;
@@ -877,13 +952,23 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
- strncpy(un.sun_path, path, sizeof(un.sun_path));
+ addrlen = sizeof(un);
+
+ if (abstract) {
+ un.sun_path[0] = '\0';
+ memcpy(&un.sun_path[1], path, pathlen);
+ if (saddr_is_tight(saddr)) {
+ addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen;
+ }
+ } else {
+ memcpy(un.sun_path, path, pathlen);
+ }
- if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
+ if (bind(sock, (struct sockaddr *) &un, addrlen) < 0) {
error_setg_errno(errp, errno, "Failed to bind socket to %s", path);
goto err;
}
- if (listen(sock, 1) < 0) {
+ if (listen(sock, num) < 0) {
error_setg_errno(errp, errno, "Failed to listen on socket");
goto err;
}
@@ -893,14 +978,17 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
err:
g_free(pathbuf);
- closesocket(sock);
+ close(sock);
return -1;
}
static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
{
+ bool abstract = saddr_is_abstract(saddr);
struct sockaddr_un un;
int sock, rc;
+ size_t pathlen;
+ size_t addrlen;
if (saddr->path == NULL) {
error_setg(errp, "unix connect: no path specified");
@@ -913,27 +1001,39 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
return -1;
}
- if (strlen(saddr->path) > sizeof(un.sun_path)) {
+ pathlen = strlen(saddr->path);
+ if (pathlen > sizeof(un.sun_path) ||
+ (abstract && pathlen > (sizeof(un.sun_path) - 1))) {
error_setg(errp, "UNIX socket path '%s' is too long", saddr->path);
error_append_hint(errp, "Path must be less than %zu bytes\n",
+ abstract ? sizeof(un.sun_path) - 1 :
sizeof(un.sun_path));
goto err;
}
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
- strncpy(un.sun_path, saddr->path, sizeof(un.sun_path));
+ addrlen = sizeof(un);
+ if (abstract) {
+ un.sun_path[0] = '\0';
+ memcpy(&un.sun_path[1], saddr->path, pathlen);
+ if (saddr_is_tight(saddr)) {
+ addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen;
+ }
+ } else {
+ memcpy(un.sun_path, saddr->path, pathlen);
+ }
/* connect to peer */
do {
rc = 0;
- if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
+ if (connect(sock, (struct sockaddr *) &un, addrlen) < 0) {
rc = -errno;
}
} while (rc == -EINTR);
if (rc < 0) {
- error_setg_errno(errp, -rc, "Failed to connect socket %s",
+ error_setg_errno(errp, -rc, "Failed to connect to '%s'",
saddr->path);
goto err;
}
@@ -945,47 +1045,15 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
return -1;
}
-#else
-
-static int unix_listen_saddr(UnixSocketAddress *saddr,
- Error **errp)
-{
- error_setg(errp, "unix sockets are not available on windows");
- errno = ENOTSUP;
- return -1;
-}
-
-static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp)
-{
- error_setg(errp, "unix sockets are not available on windows");
- errno = ENOTSUP;
- return -1;
-}
-#endif
-
/* compatibility wrapper */
int unix_listen(const char *str, Error **errp)
{
- char *path, *optstr;
- int sock, len;
UnixSocketAddress *saddr;
+ int sock;
saddr = g_new0(UnixSocketAddress, 1);
-
- optstr = strchr(str, ',');
- if (optstr) {
- len = optstr - str;
- if (len) {
- path = g_malloc(len+1);
- snprintf(path, len+1, "%.*s", len, str);
- saddr->path = path;
- }
- } else {
- saddr->path = g_strdup(str);
- }
-
- sock = unix_listen_saddr(saddr, errp);
-
+ saddr->path = g_strdup(str);
+ sock = unix_listen_saddr(saddr, 1, errp);
qapi_free_UnixSocketAddress(saddr);
return sock;
}
@@ -1002,6 +1070,26 @@ int unix_connect(const char *path, Error **errp)
return sock;
}
+char *socket_uri(SocketAddress *addr)
+{
+ switch (addr->type) {
+ case SOCKET_ADDRESS_TYPE_INET:
+ return g_strdup_printf("tcp:%s:%s",
+ addr->u.inet.host,
+ addr->u.inet.port);
+ case SOCKET_ADDRESS_TYPE_UNIX:
+ return g_strdup_printf("unix:%s",
+ addr->u.q_unix.path);
+ case SOCKET_ADDRESS_TYPE_FD:
+ return g_strdup_printf("fd:%s", addr->u.fd.str);
+ case SOCKET_ADDRESS_TYPE_VSOCK:
+ return g_strdup_printf("vsock:%s:%s",
+ addr->u.vsock.cid,
+ addr->u.vsock.port);
+ default:
+ return g_strdup("unknown address type");
+ }
+}
SocketAddress *socket_parse(const char *str, Error **errp)
{
@@ -1029,6 +1117,11 @@ SocketAddress *socket_parse(const char *str, Error **errp)
if (vsock_parse(&addr->u.vsock, str + strlen("vsock:"), errp)) {
goto fail;
}
+ } else if (strstart(str, "tcp:", NULL)) {
+ addr->type = SOCKET_ADDRESS_TYPE_INET;
+ if (inet_parse(&addr->u.inet, str + strlen("tcp:"), errp)) {
+ goto fail;
+ }
} else {
addr->type = SOCKET_ADDRESS_TYPE_INET;
if (inet_parse(&addr->u.inet, str, errp)) {
@@ -1044,6 +1137,7 @@ fail:
static int socket_get_fd(const char *fdstr, Error **errp)
{
+ Monitor *cur_mon = monitor_cur();
int fd;
if (cur_mon) {
fd = monitor_get_fd(cur_mon, fdstr, errp);
@@ -1066,6 +1160,25 @@ static int socket_get_fd(const char *fdstr, Error **errp)
return fd;
}
+int socket_address_parse_named_fd(SocketAddress *addr, Error **errp)
+{
+ int fd;
+
+ if (addr->type != SOCKET_ADDRESS_TYPE_FD) {
+ return 0;
+ }
+
+ fd = socket_get_fd(addr->u.fd.str, errp);
+ if (fd < 0) {
+ return fd;
+ }
+
+ g_free(addr->u.fd.str);
+ addr->u.fd.str = g_strdup_printf("%d", fd);
+
+ return 0;
+}
+
int socket_connect(SocketAddress *addr, Error **errp)
{
int fd;
@@ -1093,25 +1206,45 @@ int socket_connect(SocketAddress *addr, Error **errp)
return fd;
}
-int socket_listen(SocketAddress *addr, Error **errp)
+int socket_listen(SocketAddress *addr, int num, Error **errp)
{
int fd;
+ trace_socket_listen(num);
switch (addr->type) {
case SOCKET_ADDRESS_TYPE_INET:
- fd = inet_listen_saddr(&addr->u.inet, 0, errp);
+ fd = inet_listen_saddr(&addr->u.inet, 0, num, errp);
break;
case SOCKET_ADDRESS_TYPE_UNIX:
- fd = unix_listen_saddr(&addr->u.q_unix, errp);
+ fd = unix_listen_saddr(&addr->u.q_unix, num, errp);
break;
case SOCKET_ADDRESS_TYPE_FD:
fd = socket_get_fd(addr->u.fd.str, errp);
+ if (fd < 0) {
+ return -1;
+ }
+
+ /*
+ * If the socket is not yet in the listen state, then transition it to
+ * the listen state now.
+ *
+ * If it's already listening then this updates the backlog value as
+ * requested.
+ *
+ * If this socket cannot listen because it's already in another state
+ * (e.g. unbound or connected) then we'll catch the error here.
+ */
+ if (listen(fd, num) != 0) {
+ error_setg_errno(errp, errno, "Failed to listen on fd socket");
+ close(fd);
+ return -1;
+ }
break;
case SOCKET_ADDRESS_TYPE_VSOCK:
- fd = vsock_listen_saddr(&addr->u.vsock, errp);
+ fd = vsock_listen_saddr(&addr->u.vsock, num, errp);
break;
default:
@@ -1199,7 +1332,6 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa,
}
-#ifndef WIN32
static SocketAddress *
socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
socklen_t salen,
@@ -1210,13 +1342,22 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
addr = g_new0(SocketAddress, 1);
addr->type = SOCKET_ADDRESS_TYPE_UNIX;
- if (su->sun_path[0]) {
- addr->u.q_unix.path = g_strndup(su->sun_path, sizeof(su->sun_path));
+ salen -= offsetof(struct sockaddr_un, sun_path);
+#ifdef CONFIG_LINUX
+ if (salen > 0 && !su->sun_path[0]) {
+ /* Linux abstract socket */
+ addr->u.q_unix.path = g_strndup(su->sun_path + 1, salen - 1);
+ addr->u.q_unix.has_abstract = true;
+ addr->u.q_unix.abstract = true;
+ addr->u.q_unix.has_tight = true;
+ addr->u.q_unix.tight = salen < sizeof(su->sun_path);
+ return addr;
}
+#endif
+ addr->u.q_unix.path = g_strndup(su->sun_path, salen);
return addr;
}
-#endif /* WIN32 */
#ifdef CONFIG_AF_VSOCK
static SocketAddress *
@@ -1248,10 +1389,8 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa,
case AF_INET6:
return socket_sockaddr_to_address_inet(sa, salen, errp);
-#ifndef WIN32
case AF_UNIX:
return socket_sockaddr_to_address_unix(sa, salen, errp);
-#endif /* WIN32 */
#ifdef CONFIG_AF_VSOCK
case AF_VSOCK:
@@ -1308,24 +1447,25 @@ SocketAddress *socket_address_flatten(SocketAddressLegacy *addr_legacy)
addr = g_new(SocketAddress, 1);
switch (addr_legacy->type) {
- case SOCKET_ADDRESS_LEGACY_KIND_INET:
+ case SOCKET_ADDRESS_TYPE_INET:
addr->type = SOCKET_ADDRESS_TYPE_INET;
QAPI_CLONE_MEMBERS(InetSocketAddress, &addr->u.inet,
addr_legacy->u.inet.data);
break;
- case SOCKET_ADDRESS_LEGACY_KIND_UNIX:
+ case SOCKET_ADDRESS_TYPE_UNIX:
addr->type = SOCKET_ADDRESS_TYPE_UNIX;
QAPI_CLONE_MEMBERS(UnixSocketAddress, &addr->u.q_unix,
addr_legacy->u.q_unix.data);
break;
- case SOCKET_ADDRESS_LEGACY_KIND_VSOCK:
+ case SOCKET_ADDRESS_TYPE_VSOCK:
addr->type = SOCKET_ADDRESS_TYPE_VSOCK;
QAPI_CLONE_MEMBERS(VsockSocketAddress, &addr->u.vsock,
addr_legacy->u.vsock.data);
break;
- case SOCKET_ADDRESS_LEGACY_KIND_FD:
+ case SOCKET_ADDRESS_TYPE_FD:
addr->type = SOCKET_ADDRESS_TYPE_FD;
- QAPI_CLONE_MEMBERS(String, &addr->u.fd, addr_legacy->u.fd.data);
+ QAPI_CLONE_MEMBERS(FdSocketAddress, &addr->u.fd,
+ addr_legacy->u.fd.data);
break;
default:
abort();