[Spice-devel] [PATCH spice-server v4 07/20] sys-socket: Introduce some utility to make sockets more portable
Marc-André Lureau
marcandre.lureau at gmail.com
Mon Mar 4 18:23:59 UTC 2019
Hi
On Wed, Feb 6, 2019 at 2:59 PM Frediano Ziglio <fziglio at redhat.com> wrote:
>
> Between Unix and Windows socket are quite different:
> - on Windows sockets have a different namespace from C file
> descriptors so you can't use read/write/close or similar functions;
> - errors are not stored in errno but you must be read/write the
> errors with specific function;
> - sometimes sockets are put in non-blocking mode automatically
> calling some functions;
> - SOCKET type is 64 bit on Windows 64 which does not fit technically
> in an int. Is however safe to assume them to fit in an int.
>
> So encapsulate the socket APIs in some definition to make easier
> and more safe to deal with them.
> Where the portability to Windows would make to code more offuscated a Unix
> style was preferred. For instance if errors are detected errno is set from
> Windows socket error instead of changing all code handling.
> Fortunately on Windows Qemu core interface accepts socket (but not
> other types like C file descriptors!).
>
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau at redhat.com>
> ---
> server/Makefile.am | 2 +
> server/sys-socket.c | 212 ++++++++++++++++++++++++++++++++++++++++++++
> server/sys-socket.h | 139 +++++++++++++++++++++++++++++
> 3 files changed, 353 insertions(+)
> create mode 100644 server/sys-socket.c
> create mode 100644 server/sys-socket.h
>
> diff --git a/server/Makefile.am b/server/Makefile.am
> index 34ec22ad..7f260612 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -166,6 +166,8 @@ libserver_la_SOURCES = \
> stat.h \
> stream-channel.c \
> stream-channel.h \
> + sys-socket.h \
> + sys-socket.c \
> red-stream-device.c \
> red-stream-device.h \
> sw-canvas.c \
> diff --git a/server/sys-socket.c b/server/sys-socket.c
> new file mode 100644
> index 00000000..7ce5dab1
> --- /dev/null
> +++ b/server/sys-socket.c
> @@ -0,0 +1,212 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> + Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
> +*/
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#ifndef _WIN32
> +#include <arpa/inet.h>
> +#include <netinet/in.h>
> +#include <netinet/ip.h>
> +#include <netinet/tcp.h>
> +#include <sys/socket.h>
> +#endif
> +
> +#include <common/log.h>
> +
> +#include "sys-socket.h"
> +
> +#ifdef _WIN32
> +// Map Windows socket errors to standard C ones
> +// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
> +void socket_win32_set_errno(void)
> +{
> + int err = EPIPE; // default
> + switch (WSAGetLastError()) {
> + case WSAEWOULDBLOCK:
> + case WSAEINPROGRESS:
> + err = EAGAIN;
> + break;
> + case WSAEINTR:
> + err = EINTR;
> + break;
> + case WSAEBADF:
> + err = EBADF;
> + break;
> + case WSA_INVALID_HANDLE:
> + case WSA_INVALID_PARAMETER:
> + case WSAEINVAL:
> + err = EINVAL;
> + break;
> + case WSAENOTSOCK:
> + err = ENOTSOCK;
> + break;
> + case WSA_NOT_ENOUGH_MEMORY:
> + err = ENOMEM;
> + break;
> + case WSAEPROTONOSUPPORT:
> + case WSAESOCKTNOSUPPORT:
> + case WSAEOPNOTSUPP:
> + case WSAEPFNOSUPPORT:
> + case WSAEAFNOSUPPORT:
> + case WSAVERNOTSUPPORTED:
> + err = ENOTSUP;
> + break;
> + case WSAEFAULT:
> + err = EFAULT;
> + break;
> + case WSAEACCES:
> + err = EACCES;
> + break;
> + case WSAEMFILE:
> + err = EMFILE;
> + break;
> + case WSAENAMETOOLONG:
> + err = ENAMETOOLONG;
> + break;
> + case WSAENOTEMPTY:
> + err = ENOTEMPTY;
> + break;
> + case WSA_OPERATION_ABORTED:
> + case WSAECANCELLED:
> + case WSA_E_CANCELLED:
> + err = ECANCELED;
> + break;
> + case WSAEADDRINUSE:
> + err = EADDRINUSE;
> + break;
> + case WSAENETDOWN:
> + err = ENETDOWN;
> + break;
> + case WSAENETUNREACH:
> + err = ENETUNREACH;
> + break;
> + case WSAENETRESET:
> + err = ENETRESET;
> + break;
> + case WSAECONNABORTED:
> + err = ECONNABORTED;
> + break;
> + case WSAECONNRESET:
> + err = ECONNRESET;
> + break;
> + case WSAEISCONN:
> + err = EISCONN;
> + break;
> + case WSAENOTCONN:
> + err = ENOTCONN;
> + break;
> + case WSAETIMEDOUT:
> + err = ETIMEDOUT;
> + break;
> + case WSAECONNREFUSED:
> + err = ECONNREFUSED;
> + break;
> + case WSAEHOSTUNREACH:
> + err = EHOSTUNREACH;
> + break;
> + case WSAEDESTADDRREQ:
> + err = EDESTADDRREQ;
> + break;
> + case WSAEMSGSIZE:
> + err = EMSGSIZE;
> + break;
> + case WSAEPROTOTYPE:
> + err = EPROTOTYPE;
> + break;
> + case WSAENOPROTOOPT:
> + err = ENOPROTOOPT;
> + break;
> + case WSAEADDRNOTAVAIL:
> + err = EADDRNOTAVAIL;
> + break;
> + case WSAENOBUFS:
> + err = ENOBUFS;
> + break;
> + // TODO
> + case WSAESTALE:
> + case WSAEDISCON:
> + case WSA_IO_INCOMPLETE:
> + case WSA_IO_PENDING:
> + case WSAEALREADY:
> + case WSAESHUTDOWN:
> + case WSAETOOMANYREFS:
> + case WSAELOOP:
> + case WSAEHOSTDOWN:
> + case WSAEPROCLIM:
> + case WSAEUSERS:
> + case WSAEDQUOT:
> + case WSAEREMOTE:
> + case WSASYSNOTREADY:
> + case WSANOTINITIALISED:
> + case WSAENOMORE:
> + case WSAEINVALIDPROCTABLE:
> + case WSAEINVALIDPROVIDER:
> + case WSAEPROVIDERFAILEDINIT:
> + case WSASYSCALLFAILURE:
> + case WSASERVICE_NOT_FOUND:
> + case WSATYPE_NOT_FOUND:
> + case WSA_E_NO_MORE:
> + case WSAEREFUSED:
> + case WSAHOST_NOT_FOUND:
> + case WSATRY_AGAIN:
> + case WSANO_RECOVERY:
> + case WSANO_DATA:
> + case WSA_QOS_RECEIVERS:
> + case WSA_QOS_SENDERS:
> + case WSA_QOS_NO_SENDERS:
> + case WSA_QOS_NO_RECEIVERS:
> + case WSA_QOS_REQUEST_CONFIRMED:
> + case WSA_QOS_ADMISSION_FAILURE:
> + case WSA_QOS_POLICY_FAILURE:
> + case WSA_QOS_BAD_STYLE:
> + case WSA_QOS_BAD_OBJECT:
> + case WSA_QOS_TRAFFIC_CTRL_ERROR:
> + case WSA_QOS_GENERIC_ERROR:
> + case WSA_QOS_ESERVICETYPE:
> + case WSA_QOS_EFLOWSPEC:
> + case WSA_QOS_EPROVSPECBUF:
> + case WSA_QOS_EFILTERSTYLE:
> + case WSA_QOS_EFILTERTYPE:
> + case WSA_QOS_EFILTERCOUNT:
> + case WSA_QOS_EOBJLENGTH:
> + case WSA_QOS_EFLOWCOUNT:
> + case WSA_QOS_EUNKOWNPSOBJ:
> + case WSA_QOS_EPOLICYOBJ:
> + case WSA_QOS_EFLOWDESC:
> + case WSA_QOS_EPSFLOWSPEC:
> + case WSA_QOS_EPSFILTERSPEC:
> + case WSA_QOS_ESDMODEOBJ:
> + case WSA_QOS_ESHAPERATEOBJ:
> + case WSA_QOS_RESERVED_PETYPE:
> + break;
> + }
> + errno = err;
> +}
> +
> +SPICE_CONSTRUCTOR_FUNC(socket_win32_init)
> +{
> + WSADATA wsaData;
> + WSAStartup(MAKEWORD(2, 2), &wsaData);
> +}
> +#endif
> diff --git a/server/sys-socket.h b/server/sys-socket.h
> new file mode 100644
> index 00000000..65062571
> --- /dev/null
> +++ b/server/sys-socket.h
> @@ -0,0 +1,139 @@
> +/*
> + Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
> +*/
> +
> +/* Small compatibility layer for sockets, mostly to make easier portability
> + * for Windows but without loosing performances under Unix, the most supported
> + * system */
> +#ifndef RED_SYS_SOCKET_H_
> +#define RED_SYS_SOCKET_H_
> +
> +#ifndef _WIN32
> +# include <sys/socket.h>
> +
> +#define socket_read(sock, buf, len) read(sock, buf, len)
> +#define socket_write(sock, buf, len) write(sock, buf, len)
> +#define socket_writev(sock, iov, n) writev(sock, iov, n)
> +#define socket_close(sock) close(sock)
> +
That's weird indentation, why not be consistent?
> +#else
> +# include <winsock2.h>
> +# include <windows.h>
> +typedef int socklen_t;
> +
> +// this definition is ABI compatible with WSABUF
> +struct iovec {
> + u_long iov_len;
> + void FAR *iov_base;
> +};
> +
> +void socket_win32_set_errno(void);
> +
> +static inline ssize_t socket_read(int sock, void *buf, size_t count)
> +{
> + ssize_t res = recv(sock, buf, count, 0);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +
> +static inline ssize_t socket_write(int sock, const void *buf, size_t count)
> +{
> + ssize_t res = send(sock, buf, count, 0);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +
> +static inline ssize_t socket_writev(int sock, const struct iovec *iov, int n_iov)
> +{
> + DWORD sent;
> + int res = WSASend(sock, (LPWSABUF) iov, n_iov, &sent, 0, NULL, NULL);
> + if (res) {
> + socket_win32_set_errno();
> + return -1;
> + }
> + return sent;
> +}
> +
> +#define socket_close(sock) closesocket(sock)
> +
> +#define SHUT_RDWR SD_BOTH
> +
> +static inline int
> +socket_getsockopt(int sock, int lvl, int type, void *value, socklen_t *len)
> +{
> + int res = getsockopt(sock, lvl, type, value, len);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +#undef getsockopt
> +#define getsockopt socket_getsockopt
> +
> +static inline int
> +socket_setsockopt(int sock, int lvl, int type, const void *value, socklen_t len)
> +{
> + int res = setsockopt(sock, lvl, type, value, len);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +#undef setsockopt
> +#define setsockopt socket_setsockopt
> +
> +static inline int
> +socket_listen(int sock, int backlog)
> +{
> + int res = listen(sock, backlog);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +#undef listen
> +#define listen socket_listen
> +
> +static inline int
> +socket_bind(int sock, const struct sockaddr *addr, int addrlen)
> +{
> + int res = bind(sock, addr, addrlen);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +#undef bind
> +#define bind socket_bind
> +
> +static inline int
> +socket_accept(int sock, struct sockaddr *addr, int *addrlen)
> +{
> + int res = accept(sock, addr, addrlen);
> + if (res < 0) {
> + socket_win32_set_errno();
> + }
> + return res;
> +}
> +#undef accept
> +#define accept socket_accept
> +#endif
> +
> +#endif // RED_SYS_SOCKET_H_
> --
> 2.20.1
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
--
Marc-André Lureau
More information about the Spice-devel
mailing list