diff options
author | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-06 16:22:02 +0300 |
---|---|---|
committer | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-07 13:52:44 +0300 |
commit | b4954701093739e7a4e54a0669f306922d0d4605 (patch) | |
tree | 73d71319a921234f6b507c9098fdc842f7fe06dc /src/foundation/windows/SocketImpl.h | |
parent | 8548a5f5579e3eee7e5ae6b1f6901dcc8bfee19e (diff) |
Long live the slayer!
Initial commit of OpenGL Runtime to repository.
Based on SHA1 61823aaccc6510699a54b34a2fe3f7523dab3b4e
of qt3dstudio repository.
Task-number: QT3DS-3600
Change-Id: Iaeb80237399f0e5656a19ebec9d1ab3a681d8832
Reviewed-by: Pasi Keränen <pasi.keranen@qt.io>
Diffstat (limited to 'src/foundation/windows/SocketImpl.h')
-rw-r--r-- | src/foundation/windows/SocketImpl.h | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/src/foundation/windows/SocketImpl.h b/src/foundation/windows/SocketImpl.h new file mode 100644 index 0000000..f72203b --- /dev/null +++ b/src/foundation/windows/SocketImpl.h @@ -0,0 +1,506 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +LuaSocket 3.0 license +Copyright � 2004-2013 Diego Nehab + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + +#ifndef FOUNDATION_WINDOWS_SOCKET_IMPL_H +#define FOUNDATION_WINDOWS_SOCKET_IMPL_H +#pragma once +#include <winsock.h> +#pragma warning(disable : 4127) +#pragma warning(disable : 4702) + +namespace qt3ds { +namespace foundation { + namespace socketimpl { + + // Functions take from lua socket implementation. Note that it has an MIT license. + + enum { + IO_DONE = 0, /* operation completed successfully */ + IO_TIMEOUT = -1, /* operation timed out */ + IO_CLOSED = -2, /* the connection has been closed */ + IO_UNKNOWN = -3 + }; + + /*-------------------------------------------------------------------------*\ + * I/O error strings + \*-------------------------------------------------------------------------*/ + const char *io_strerror(int err) + { + switch (err) { + case IO_DONE: + return NULL; + case IO_CLOSED: + return "closed"; + case IO_TIMEOUT: + return "timeout"; + default: + return "unknown error"; + } + } + + typedef int socklen_t; + typedef SOCKET t_socket; + typedef t_socket *p_socket; + typedef struct sockaddr SA; + +#define SOCKET_INVALID (INVALID_SOCKET) + + static const char *wstrerror(int err) + { + switch (err) { + case WSAEINTR: + return "Interrupted function call"; + case WSAEACCES: + return "Permission denied"; + case WSAEFAULT: + return "Bad address"; + case WSAEINVAL: + return "Invalid argument"; + case WSAEMFILE: + return "Too many open files"; + case WSAEWOULDBLOCK: + return "Resource temporarily unavailable"; + case WSAEINPROGRESS: + return "Operation now in progress"; + case WSAEALREADY: + return "Operation already in progress"; + case WSAENOTSOCK: + return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: + return "Destination address required"; + case WSAEMSGSIZE: + return "Message too long"; + case WSAEPROTOTYPE: + return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: + return "Bad protocol option"; + case WSAEPROTONOSUPPORT: + return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: + return "Socket type not supported"; + case WSAEOPNOTSUPP: + return "Operation not supported"; + case WSAEPFNOSUPPORT: + return "Protocol family not supported"; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case WSAEADDRINUSE: + return "Address already in use"; + case WSAEADDRNOTAVAIL: + return "Cannot assign requested address"; + case WSAENETDOWN: + return "Network is down"; + case WSAENETUNREACH: + return "Network is unreachable"; + case WSAENETRESET: + return "Network dropped connection on reset"; + case WSAECONNABORTED: + return "Software caused connection abort"; + case WSAECONNRESET: + return "Connection reset by peer"; + case WSAENOBUFS: + return "No buffer space available"; + case WSAEISCONN: + return "Socket is already connected"; + case WSAENOTCONN: + return "Socket is not connected"; + case WSAESHUTDOWN: + return "Cannot send after socket shutdown"; + case WSAETIMEDOUT: + return "Connection timed out"; + case WSAECONNREFUSED: + return "Connection refused"; + case WSAEHOSTDOWN: + return "Host is down"; + case WSAEHOSTUNREACH: + return "No route to host"; + case WSAEPROCLIM: + return "Too many processes"; + case WSASYSNOTREADY: + return "Network subsystem is unavailable"; + case WSAVERNOTSUPPORTED: + return "Winsock.dll version out of range"; + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performed"; + case WSAEDISCON: + return "Graceful shutdown in progress"; + case WSAHOST_NOT_FOUND: + return "Host not found"; + case WSATRY_AGAIN: + return "Nonauthoritative host not found"; + case WSANO_RECOVERY: + return "Nonrecoverable name lookup error"; + case WSANO_DATA: + return "Valid name, no data record of requested type"; + default: + return "Unknown error"; + } + } + + const char *socket_strerror(int err) + { + switch (err) { + case WSAEADDRINUSE: + return "address already in use"; + case WSAECONNREFUSED: + return "connection refused"; + case WSAEISCONN: + return "already connected"; + case WSAEACCES: + return "permission denied"; + case WSAECONNABORTED: + return "closed"; + case WSAECONNRESET: + return "closed"; + case WSAETIMEDOUT: + return "timeout"; + default: + return wstrerror(err); + } + } + + int socket_open(void) + { + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + int err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) + return 0; + if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) + && (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) { + WSACleanup(); + return 0; + } + return 1; + } + + /*-------------------------------------------------------------------------*\ + * Close module + \*-------------------------------------------------------------------------*/ + int socket_close(void) + { + WSACleanup(); + return 1; + } + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_E 4 +#define WAITFD_C (WAITFD_E | WAITFD_W) + + static int socket_waitfd(p_socket ps, int sw, QT3DSU32 timeoutMilliseconds) + { + int ret; + fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; + struct timeval tv, *tp = NULL; + if (timeoutMilliseconds == 0) + return IO_TIMEOUT; /* optimize timeout == 0 case */ + if (sw & WAITFD_R) { + FD_ZERO(&rfds); + FD_SET(*ps, &rfds); + rp = &rfds; + } + if (sw & WAITFD_W) { + FD_ZERO(&wfds); + FD_SET(*ps, &wfds); + wp = &wfds; + } + if (sw & WAITFD_C) { + FD_ZERO(&efds); + FD_SET(*ps, &efds); + ep = &efds; + } + if (timeoutMilliseconds >= 0.0) { + tv.tv_sec = (int)(timeoutMilliseconds / 1000); + QT3DSU32 leftover = timeoutMilliseconds % 1000; + tv.tv_usec = (int)(leftover * 100000); + tp = &tv; + } + ret = select(0, rp, wp, ep, tp); + if (ret == -1) + return WSAGetLastError(); + if (ret == 0) + return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) + return IO_CLOSED; + return IO_DONE; + } + + static int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, + QT3DSU32 timeoutMilliseconds) + { + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) + return IO_CLOSED; + /* loop until we send something or we give up on error */ + for (;;) { + /* try to send something */ + int put = send(*ps, data, (int)count, 0); + /* if we sent something, we are done */ + if (put > 0) { + *sent = put; + return IO_DONE; + } + /* deal with failure */ + err = WSAGetLastError(); + /* we can only proceed if there was no serious error */ + if (err != WSAEWOULDBLOCK) + return err; + /* avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_W, timeoutMilliseconds)) != IO_DONE) + return err; + } + /* can't reach here */ + return IO_UNKNOWN; + } + /*-------------------------------------------------------------------------*\ + * Receive with timeout + \*-------------------------------------------------------------------------*/ + static int socket_recv(p_socket ps, char *data, size_t count, size_t *got, + QT3DSU32 timeoutMilliseconds) + { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) + return IO_CLOSED; + for (;;) { + int taken = recv(*ps, data, (int)count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) + return IO_CLOSED; + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) + return err; + if ((err = socket_waitfd(ps, WAITFD_R, timeoutMilliseconds)) != IO_DONE) + return err; + } + return IO_UNKNOWN; + } + + void socket_setblocking(p_socket ps) + { + u_long argp = 0; + ioctlsocket(*ps, FIONBIO, &argp); + } + + /*-------------------------------------------------------------------------*\ + * Put socket into non-blocking mode + \*-------------------------------------------------------------------------*/ + void socket_setnonblocking(p_socket ps) + { + u_long argp = 1; + ioctlsocket(*ps, FIONBIO, &argp); + } + + int socket_listen(p_socket ps, int backlog) + { + int err = IO_DONE; + socket_setblocking(ps); + if (listen(*ps, backlog) < 0) + err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; + } + + /*-------------------------------------------------------------------------*\ + * Accept with timeout + \*-------------------------------------------------------------------------*/ + static int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, QT3DSU32 tm) + { + SA daddr; + socklen_t dlen = sizeof(daddr); + if (*ps == SOCKET_INVALID) + return IO_CLOSED; + if (!addr) + addr = &daddr; + if (!len) + len = &dlen; + for (;;) { + int err; + /* try to get client socket */ + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) + return IO_DONE; + /* find out why we failed */ + err = WSAGetLastError(); + /* if we failed because there was no connectoin, keep trying */ + if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) + return err; + /* call select to avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) + return err; + } + /* can't reach here */ + return IO_UNKNOWN; + } + + int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) + { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) + return IO_DONE; + else + return WSAGetLastError(); + } + + int socket_gethostbyname(const char *addr, struct hostent **hp) + { + *hp = gethostbyname(addr); + if (*hp) + return IO_DONE; + else + return WSAGetLastError(); + } + + /*-------------------------------------------------------------------------*\ + * Error translation functions + \*-------------------------------------------------------------------------*/ + const char *socket_hoststrerror(int err) + { + if (err <= 0) + return io_strerror(err); + switch (err) { + case WSAHOST_NOT_FOUND: + return "host not found"; + default: + return wstrerror(err); + } + } + /*-------------------------------------------------------------------------*\ + * Close and inutilize socket + \*-------------------------------------------------------------------------*/ + void socket_destroy(p_socket ps) + { + if (*ps != SOCKET_INVALID) { + socket_setblocking(ps); /* close can take a long time on WIN32 */ + closesocket(*ps); + *ps = SOCKET_INVALID; + } + } + + /*-------------------------------------------------------------------------*\ + * + \*-------------------------------------------------------------------------*/ + void socket_shutdown(p_socket ps, int how) + { + socket_setblocking(ps); + shutdown(*ps, how); + } + + int socket_create(p_socket ps, int domain, int type, int protocol) + { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) + return IO_DONE; + else + return WSAGetLastError(); + } + + /*-------------------------------------------------------------------------*\ + * Connects or returns error message + \*-------------------------------------------------------------------------*/ + int socket_connect(p_socket ps, SA *addr, socklen_t len, QT3DSU32 tm) + { + int err; + /* don't call on closed socket */ + if (*ps == SOCKET_INVALID) + return IO_CLOSED; + /* ask system to connect */ + if (connect(*ps, addr, len) == 0) + return IO_DONE; + /* make sure the system is trying to connect */ + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) + return err; + /* zero timeout case optimization */ + if (tm == 0) + return IO_TIMEOUT; + /* we wait until something happens */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + int len = sizeof(err); + /* give windows time to set the error (yes, disgusting) */ + Sleep(10); + /* find out why we failed */ + getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); + /* we KNOW there was an error. if 'why' is 0, we will return + * "unknown error", but it's not really our fault */ + return err > 0 ? err : IO_UNKNOWN; + } else + return err; + } + + /*-------------------------------------------------------------------------*\ + * Binds or returns error message + \*-------------------------------------------------------------------------*/ + int socket_bind(p_socket ps, SA *addr, socklen_t len) + { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) + err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; + } + } +} +} + +#endif
\ No newline at end of file |