diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am
index 23de4a6375..528c9f6cfe 100644
--- a/src/util/Makefile.inc.am
+++ b/src/util/Makefile.inc.am
@@ -188,6 +188,8 @@ UTIL_SOURCES = \
util/virseclabel.h \
util/virsecret.c \
util/virsecret.h \
+ util/virsocket.c \
+ util/virsocket.h \
util/virsocketaddr.c \
util/virsocketaddr.h \
util/virstorageencryption.c \
diff --git a/src/util/virsocket.c b/src/util/virsocket.c
new file mode 100644
index 0000000000..96b9ece2b7
--- /dev/null
+++ b/src/util/virsocket.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#include
+
+#include "virsocket.h"
+
+#ifdef WIN32
+
+# include
+
+# define FD2SK(fd) _get_osfhandle(fd)
+# define SK2FD(sk) (_open_osfhandle((intptr_t) (sk), O_RDWR | O_BINARY))
+
+# define GET_HANDLE(fd) \
+
+# define RETURN_ERROR(call) \
+ if ((call) < 0) { \
+ set_errno(); \
+ return -1; \
+ }
+
+# undef accept
+# undef bind
+# undef closesocket
+# undef connect
+# undef getpeername
+# undef getsockname
+# undef getsockopt
+# undef ioctlsocket
+# undef listen
+# undef setsockopt
+# undef socket
+
+static void
+set_errno(void)
+{
+ int err = WSAGetLastError();
+
+ /* Map some WSAE* errors to the runtime library's error codes. */
+ switch (err) {
+ case WSA_INVALID_HANDLE:
+ errno = EBADF;
+ break;
+ case WSA_NOT_ENOUGH_MEMORY:
+ errno = ENOMEM;
+ break;
+ case WSA_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+ case WSAENAMETOOLONG:
+ errno = ENAMETOOLONG;
+ break;
+ case WSAENOTEMPTY:
+ errno = ENOTEMPTY;
+ break;
+ case WSAEWOULDBLOCK:
+ errno = EWOULDBLOCK;
+ break;
+ case WSAEINPROGRESS:
+ errno = EINPROGRESS;
+ break;
+ case WSAEALREADY:
+ errno = EALREADY;
+ break;
+ case WSAENOTSOCK:
+ errno = ENOTSOCK;
+ break;
+ case WSAEDESTADDRREQ:
+ errno = EDESTADDRREQ;
+ break;
+ case WSAEMSGSIZE:
+ errno = EMSGSIZE;
+ break;
+ case WSAEPROTOTYPE:
+ errno = EPROTOTYPE;
+ break;
+ case WSAENOPROTOOPT:
+ errno = ENOPROTOOPT;
+ break;
+ case WSAEPROTONOSUPPORT:
+ errno = EPROTONOSUPPORT;
+ break;
+ case WSAEOPNOTSUPP:
+ errno = EOPNOTSUPP;
+ break;
+ case WSAEAFNOSUPPORT:
+ errno = EAFNOSUPPORT;
+ break;
+ case WSAEADDRINUSE:
+ errno = EADDRINUSE;
+ break;
+ case WSAEADDRNOTAVAIL:
+ errno = EADDRNOTAVAIL;
+ break;
+ case WSAENETDOWN:
+ errno = ENETDOWN;
+ break;
+ case WSAENETUNREACH:
+ errno = ENETUNREACH;
+ break;
+ case WSAENETRESET:
+ errno = ENETRESET;
+ break;
+ case WSAECONNABORTED:
+ errno = ECONNABORTED;
+ break;
+ case WSAECONNRESET:
+ errno = ECONNRESET;
+ break;
+ case WSAENOBUFS:
+ errno = ENOBUFS;
+ break;
+ case WSAEISCONN:
+ errno = EISCONN;
+ break;
+ case WSAENOTCONN:
+ errno = ENOTCONN;
+ break;
+ case WSAETIMEDOUT:
+ errno = ETIMEDOUT;
+ break;
+ case WSAECONNREFUSED:
+ errno = ECONNREFUSED;
+ break;
+ case WSAELOOP:
+ errno = ELOOP;
+ break;
+ case WSAEHOSTUNREACH:
+ errno = EHOSTUNREACH;
+ break;
+ default:
+ errno = (err > 10000 && err < 10025) ? err - 10000 : err;
+ break;
+ }
+}
+
+
+int
+vir_accept(int fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ SOCKET sk = FD2SK(fd);
+ SOCKET csk;
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ csk = accept(sk, addr, addrlen);
+
+ if (csk == INVALID_SOCKET) {
+ set_errno();
+ return -1;
+ }
+
+ return SK2FD(csk);
+}
+
+
+int
+vir_bind(int fd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (bind(sk, addr, addrlen) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_closesocket(int fd)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (closesocket(sk) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_connect(int fd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (connect(sk, addr, addrlen) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (getpeername(sk, addr, addrlen) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (getsockname(sk, addr, addrlen) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_listen(int fd, int backlog)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (listen(sk, backlog) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_ioctlsocket(int fd, int cmd, void *arg)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (ioctlsocket(sk, cmd, arg) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_getsockopt(int fd, int level, int optname,
+ void *optval, socklen_t *optlen)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (getsockopt(sk, level, optname, optval, optlen) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_setsockopt(int fd, int level, int optname,
+ const void *optval, socklen_t optlen)
+{
+ SOCKET sk = FD2SK(fd);
+
+ if (sk == INVALID_SOCKET) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (setsockopt(sk, level, optname, optval, optlen) < 0) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+vir_socket(int domain, int type, int protocol)
+{
+ SOCKET sk;
+
+ /* We have to use WSASocket() instead of socket(), to create
+ * non-overlapped IO sockets. Overlapped IO sockets cannot
+ * be used with read/write.
+ */
+ sk = WSASocket(domain, type, protocol, NULL, 0, 0);
+ if (sk == INVALID_SOCKET) {
+ set_errno();
+ return -1;
+ }
+
+ return SK2FD(sk);
+}
+
+#endif /* WIN32 */
diff --git a/src/util/virsocket.h b/src/util/virsocket.h
new file mode 100644
index 0000000000..33f237886f
--- /dev/null
+++ b/src/util/virsocket.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ */
+
+#pragma once
+
+#include "internal.h"
+
+#ifdef WIN32
+
+# define WIN32_LEAN_AND_MEAN
+# include
+# include
+# include
+# include
+
+int vir_accept(int fd, struct sockaddr *addr, socklen_t *addrlen);
+int vir_bind(int fd, const struct sockaddr *addr, socklen_t addrlen);
+int vir_closesocket(int fd);
+int vir_connect(int fd, const struct sockaddr *addr, socklen_t addrlen);
+int vir_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen);
+int vir_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen);
+int vir_listen(int fd, int backlog);
+int vir_ioctlsocket(int fd, int cmd, void *arg);
+int vir_getsockopt(int fd, int level, int optname,
+ void *optval, socklen_t *optlen);
+int vir_setsockopt(int fd, int level, int optname,
+ const void *optval, socklen_t optlen);
+int vir_socket(int domain, int type, int protocol);
+
+
+/* Get rid of GNULIB's replacements */
+# undef accept
+# undef bind
+# undef closesocket
+# undef connect
+# undef dup
+# undef dup2
+# undef getpeername
+# undef getsockname
+# undef getsockopt
+# undef ioctlsocket
+# undef listen
+# undef setsockopt
+# undef socket
+
+/* Provide our own replacements */
+# define accept vir_accept
+# define bind vir_bind
+# define closesocket vir_closesocket
+# define connect vir_connect
+# define dup _dup
+# define dup2 _dup2
+# define ioctlsocket vir_ioctlsocket
+# define getpeername vir_getpeername
+# define getsockname vir_getsockname
+# define getsockopt vir_getsockopt
+# define listen vir_listen
+# define setsockopt vir_setsockopt
+# define socket vir_socket
+
+#else
+
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+
+# define closesocket close
+# define ioctlsocket ioctl
+
+#endif
diff --git a/src/util/virutil.c b/src/util/virutil.c
index a0fd7618ee..9ea9e2946d 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -71,10 +71,10 @@
#include "verify.h"
#include "virfile.h"
#include "vircommand.h"
-#include "nonblocking.h"
#include "virprocess.h"
#include "virstring.h"
#include "virutil.h"
+#include "virsocket.h"
verify(sizeof(gid_t) <= sizeof(unsigned int) &&
sizeof(uid_t) <= sizeof(unsigned int));
@@ -99,6 +99,21 @@ int virSetInherit(int fd, bool inherit)
return 0;
}
+
+int virSetBlocking(int fd, bool block)
+{
+ int fflags;
+ if ((fflags = fcntl(fd, F_GETFL)) < 0)
+ return -1;
+ if (block)
+ fflags &= ~O_NONBLOCK;
+ else
+ fflags |= O_NONBLOCK;
+ if ((fcntl(fd, F_SETFL, fflags)) < 0)
+ return -1;
+ return 0;
+}
+
#else /* WIN32 */
int virSetInherit(int fd G_GNUC_UNUSED, bool inherit G_GNUC_UNUSED)
@@ -110,13 +125,19 @@ int virSetInherit(int fd G_GNUC_UNUSED, bool inherit G_GNUC_UNUSED)
return 0;
}
-#endif /* WIN32 */
-
int virSetBlocking(int fd, bool blocking)
{
- return set_nonblocking_flag(fd, !blocking);
+ unsigned long arg = blocking ? 0 : 1;
+
+ if (ioctlsocket(fd, FIONBIO, &arg) < 0)
+ return -1;
+
+ return 0;
}
+#endif /* WIN32 */
+
+
int virSetNonBlock(int fd)
{
return virSetBlocking(fd, false);