diff options
Diffstat (limited to 'util/qemu-sockets.c')
-rw-r--r-- | util/qemu-sockets.c | 380 |
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(); |