[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