|
@@ -180,7 +180,7 @@ static int socket_error(void)
|
|
|
void qemu_socket_set_block(int fd)
|
|
|
{
|
|
|
unsigned long opt = 0;
|
|
|
- WSAEventSelect(fd, NULL, 0);
|
|
|
+ qemu_socket_unselect(fd, NULL);
|
|
|
ioctlsocket(fd, FIONBIO, &opt);
|
|
|
}
|
|
|
|
|
@@ -283,21 +283,155 @@ char *qemu_get_pid_name(pid_t pid)
|
|
|
}
|
|
|
|
|
|
|
|
|
-pid_t qemu_fork(Error **errp)
|
|
|
+bool qemu_socket_select(int sockfd, WSAEVENT hEventObject,
|
|
|
+ long lNetworkEvents, Error **errp)
|
|
|
{
|
|
|
- errno = ENOSYS;
|
|
|
- error_setg_errno(errp, errno,
|
|
|
- "cannot fork child process");
|
|
|
- return -1;
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (errp == NULL) {
|
|
|
+ errp = &error_warn;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ error_setg(errp, "invalid socket fd=%d", sockfd);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (WSAEventSelect(s, hEventObject, lNetworkEvents) != 0) {
|
|
|
+ error_setg_win32(errp, WSAGetLastError(), "failed to WSAEventSelect()");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
+bool qemu_socket_unselect(int sockfd, Error **errp)
|
|
|
+{
|
|
|
+ return qemu_socket_select(sockfd, NULL, 0, errp);
|
|
|
+}
|
|
|
+
|
|
|
+int qemu_socketpair(int domain, int type, int protocol, int sv[2])
|
|
|
+{
|
|
|
+ struct sockaddr_un addr = {
|
|
|
+ 0,
|
|
|
+ };
|
|
|
+ socklen_t socklen;
|
|
|
+ int listener = -1;
|
|
|
+ int client = -1;
|
|
|
+ int server = -1;
|
|
|
+ g_autofree char *path = NULL;
|
|
|
+ int tmpfd;
|
|
|
+ u_long arg;
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ g_return_val_if_fail(sv != NULL, -1);
|
|
|
+
|
|
|
+ addr.sun_family = AF_UNIX;
|
|
|
+ socklen = sizeof(addr);
|
|
|
+
|
|
|
+ tmpfd = g_file_open_tmp(NULL, &path, NULL);
|
|
|
+ if (tmpfd == -1 || !path) {
|
|
|
+ errno = EACCES;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ close(tmpfd);
|
|
|
+
|
|
|
+ if (strlen(path) >= sizeof(addr.sun_path)) {
|
|
|
+ errno = EINVAL;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
|
|
|
+
|
|
|
+ listener = socket(domain, type, protocol);
|
|
|
+ if (listener == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (DeleteFile(path) == 0 && GetLastError() != ERROR_FILE_NOT_FOUND) {
|
|
|
+ errno = EACCES;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ g_clear_pointer(&path, g_free);
|
|
|
+
|
|
|
+ if (bind(listener, (struct sockaddr *)&addr, socklen) == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (listen(listener, 1) == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ client = socket(domain, type, protocol);
|
|
|
+ if (client == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ arg = 1;
|
|
|
+ if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (connect(client, (struct sockaddr *)&addr, socklen) == -1 &&
|
|
|
+ WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ server = accept(listener, NULL, NULL);
|
|
|
+ if (server == -1) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ arg = 0;
|
|
|
+ if (ioctlsocket(client, FIONBIO, &arg) != NO_ERROR) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ arg = 0;
|
|
|
+ if (ioctlsocket(client, SIO_AF_UNIX_GETPEERPID, &arg) != NO_ERROR) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (arg != GetCurrentProcessId()) {
|
|
|
+ errno = EPERM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ sv[0] = server;
|
|
|
+ server = -1;
|
|
|
+ sv[1] = client;
|
|
|
+ client = -1;
|
|
|
+ ret = 0;
|
|
|
+
|
|
|
+out:
|
|
|
+ if (listener != -1) {
|
|
|
+ close(listener);
|
|
|
+ }
|
|
|
+ if (client != -1) {
|
|
|
+ close(client);
|
|
|
+ }
|
|
|
+ if (server != -1) {
|
|
|
+ close(server);
|
|
|
+ }
|
|
|
+ if (path) {
|
|
|
+ DeleteFile(path);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
#undef connect
|
|
|
int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
|
|
|
socklen_t addrlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = connect(sockfd, addr, addrlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = connect(s, addr, addrlen);
|
|
|
if (ret < 0) {
|
|
|
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
|
|
errno = EINPROGRESS;
|
|
@@ -313,7 +447,13 @@ int qemu_connect_wrap(int sockfd, const struct sockaddr *addr,
|
|
|
int qemu_listen_wrap(int sockfd, int backlog)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = listen(sockfd, backlog);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = listen(s, backlog);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -326,7 +466,13 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
|
|
|
socklen_t addrlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = bind(sockfd, addr, addrlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = bind(s, addr, addrlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -334,15 +480,82 @@ int qemu_bind_wrap(int sockfd, const struct sockaddr *addr,
|
|
|
}
|
|
|
|
|
|
|
|
|
+#undef close
|
|
|
+int qemu_close_wrap(int fd)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ DWORD flags = 0;
|
|
|
+ SOCKET s = INVALID_SOCKET;
|
|
|
+
|
|
|
+ if (fd_is_socket(fd)) {
|
|
|
+ s = _get_osfhandle(fd);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If we were to just call _close on the descriptor, it would close the
|
|
|
+ * HANDLE, but it wouldn't free any of the resources associated to the
|
|
|
+ * SOCKET, and we can't call _close after calling closesocket, because
|
|
|
+ * closesocket has already closed the HANDLE, and _close would attempt to
|
|
|
+ * close the HANDLE again, resulting in a double free. We can however
|
|
|
+ * protect the HANDLE from actually being closed long enough to close the
|
|
|
+ * file descriptor, then close the socket itself.
|
|
|
+ */
|
|
|
+ if (!GetHandleInformation((HANDLE)s, &flags)) {
|
|
|
+ errno = EACCES;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!SetHandleInformation((HANDLE)s, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE)) {
|
|
|
+ errno = EACCES;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = close(fd);
|
|
|
+
|
|
|
+ if (s != INVALID_SOCKET && !SetHandleInformation((HANDLE)s, flags, flags)) {
|
|
|
+ errno = EACCES;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * close() returns EBADF since we PROTECT_FROM_CLOSE the underlying handle,
|
|
|
+ * but the FD is actually freed
|
|
|
+ */
|
|
|
+ if (ret < 0 && (s == INVALID_SOCKET || errno != EBADF)) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (s != INVALID_SOCKET) {
|
|
|
+ ret = closesocket(s);
|
|
|
+ if (ret < 0) {
|
|
|
+ errno = socket_error();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
#undef socket
|
|
|
int qemu_socket_wrap(int domain, int type, int protocol)
|
|
|
{
|
|
|
- int ret;
|
|
|
- ret = socket(domain, type, protocol);
|
|
|
- if (ret < 0) {
|
|
|
+ SOCKET s;
|
|
|
+ int fd;
|
|
|
+
|
|
|
+ s = socket(domain, type, protocol);
|
|
|
+ if (s == -1) {
|
|
|
errno = socket_error();
|
|
|
+ return -1;
|
|
|
}
|
|
|
- return ret;
|
|
|
+
|
|
|
+ fd = _open_osfhandle(s, _O_BINARY);
|
|
|
+ if (fd < 0) {
|
|
|
+ closesocket(s);
|
|
|
+ /* _open_osfhandle may not set errno, and closesocket() may override it */
|
|
|
+ errno = ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return fd;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -350,12 +563,27 @@ int qemu_socket_wrap(int domain, int type, int protocol)
|
|
|
int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
|
|
|
socklen_t *addrlen)
|
|
|
{
|
|
|
- int ret;
|
|
|
- ret = accept(sockfd, addr, addrlen);
|
|
|
- if (ret < 0) {
|
|
|
+ int fd;
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ s = accept(s, addr, addrlen);
|
|
|
+ if (s == -1) {
|
|
|
errno = socket_error();
|
|
|
+ return -1;
|
|
|
}
|
|
|
- return ret;
|
|
|
+
|
|
|
+ fd = _open_osfhandle(s, _O_BINARY);
|
|
|
+ if (fd < 0) {
|
|
|
+ closesocket(s);
|
|
|
+ /* _open_osfhandle may not set errno, and closesocket() may override it */
|
|
|
+ errno = ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return fd;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -363,7 +591,13 @@ int qemu_accept_wrap(int sockfd, struct sockaddr *addr,
|
|
|
int qemu_shutdown_wrap(int sockfd, int how)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = shutdown(sockfd, how);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = shutdown(s, how);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -375,19 +609,13 @@ int qemu_shutdown_wrap(int sockfd, int how)
|
|
|
int qemu_ioctlsocket_wrap(int fd, int req, void *val)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = ioctlsocket(fd, req, val);
|
|
|
- if (ret < 0) {
|
|
|
- errno = socket_error();
|
|
|
- }
|
|
|
- return ret;
|
|
|
-}
|
|
|
+ SOCKET s = _get_osfhandle(fd);
|
|
|
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
-#undef closesocket
|
|
|
-int qemu_closesocket_wrap(int fd)
|
|
|
-{
|
|
|
- int ret;
|
|
|
- ret = closesocket(fd);
|
|
|
+ ret = ioctlsocket(s, req, val);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -400,7 +628,13 @@ int qemu_getsockopt_wrap(int sockfd, int level, int optname,
|
|
|
void *optval, socklen_t *optlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = getsockopt(sockfd, level, optname, optval, optlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = getsockopt(s, level, optname, optval, optlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -413,7 +647,13 @@ int qemu_setsockopt_wrap(int sockfd, int level, int optname,
|
|
|
const void *optval, socklen_t optlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = setsockopt(sockfd, level, optname, optval, optlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = setsockopt(s, level, optname, optval, optlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -426,7 +666,13 @@ int qemu_getpeername_wrap(int sockfd, struct sockaddr *addr,
|
|
|
socklen_t *addrlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = getpeername(sockfd, addr, addrlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = getpeername(s, addr, addrlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -439,7 +685,13 @@ int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
|
|
|
socklen_t *addrlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = getsockname(sockfd, addr, addrlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = getsockname(s, addr, addrlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -451,7 +703,13 @@ int qemu_getsockname_wrap(int sockfd, struct sockaddr *addr,
|
|
|
ssize_t qemu_send_wrap(int sockfd, const void *buf, size_t len, int flags)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = send(sockfd, buf, len, flags);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = send(s, buf, len, flags);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -464,7 +722,13 @@ ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
|
|
|
const struct sockaddr *addr, socklen_t addrlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = sendto(sockfd, buf, len, flags, addr, addrlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = sendto(s, buf, len, flags, addr, addrlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -476,7 +740,13 @@ ssize_t qemu_sendto_wrap(int sockfd, const void *buf, size_t len, int flags,
|
|
|
ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = recv(sockfd, buf, len, flags);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = recv(s, buf, len, flags);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|
|
@@ -489,7 +759,13 @@ ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
|
|
|
struct sockaddr *addr, socklen_t *addrlen)
|
|
|
{
|
|
|
int ret;
|
|
|
- ret = recvfrom(sockfd, buf, len, flags, addr, addrlen);
|
|
|
+ SOCKET s = _get_osfhandle(sockfd);
|
|
|
+
|
|
|
+ if (s == INVALID_SOCKET) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = recvfrom(s, buf, len, flags, addr, addrlen);
|
|
|
if (ret < 0) {
|
|
|
errno = socket_error();
|
|
|
}
|