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/meson.build b/server/meson.build index 63191d79..34d8eef1 100644 --- a/server/meson.build +++ b/server/meson.build @@ -133,6 +133,8 @@ spice_server_sources = [ 'stat.h', 'stream-channel.c', 'stream-channel.h', + 'sys-socket.c', + 'sys-socket.h', '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..5ac627b4 --- /dev/null +++ b/server/sys-socket.c @@ -0,0 +1,210 @@ +/* -*- 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 . +*/ +#include + +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif + +#include + +#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 . +*/ + +/* 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 + +#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) + +#else +# include +# include +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_