aboutsummaryrefslogtreecommitdiff
path: root/src/platform/w32functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/w32functions.c')
-rw-r--r--src/platform/w32functions.c704
1 files changed, 704 insertions, 0 deletions
diff --git a/src/platform/w32functions.c b/src/platform/w32functions.c
new file mode 100644
index 00000000..bc42fef4
--- /dev/null
+++ b/src/platform/w32functions.c
@@ -0,0 +1,704 @@
+/*
+ This file is part of libmicrohttpd
+ Copyright (C) 2014 Karlson2k (Evgeny Grin)
+
+ 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/>.
+*/
+
+/**
+ * @file platform/w32functions.h
+ * @brief internal functions for W32 systems
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "w32functions.h"
+#include <errno.h>
+#include <winsock2.h>
+#include <string.h>
+#include <stdint.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+
+/**
+ * Return errno equivalent of last winsock error
+ * @return errno equivalent of last winsock error
+ */
+int MHD_W32_errno_from_winsock_(void)
+{
+ switch(WSAGetLastError())
+ {
+ case 0: return 0;
+ case WSA_INVALID_HANDLE: return EBADF;
+ case WSA_NOT_ENOUGH_MEMORY: return ENOMEM;
+ case WSA_INVALID_PARAMETER: return EINVAL;
+ case WSAEINTR: return EINTR;
+ case WSAEWOULDBLOCK: return EWOULDBLOCK;
+ case WSAEINPROGRESS: return EINPROGRESS;
+ case WSAEALREADY: return EALREADY;
+ case WSAENOTSOCK: return ENOTSOCK;
+ case WSAEDESTADDRREQ: return EDESTADDRREQ;
+ case WSAEMSGSIZE: return EMSGSIZE;
+ case WSAEPROTOTYPE: return EPROTOTYPE;
+ case WSAENOPROTOOPT: return ENOPROTOOPT;
+ case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
+ case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT;
+ case WSAEOPNOTSUPP: return EOPNOTSUPP;
+ case WSAEPFNOSUPPORT: return EPFNOSUPPORT;
+ case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
+ case WSAEADDRINUSE: return EADDRINUSE;
+ case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
+ case WSAENETDOWN: return ENETDOWN;
+ case WSAENETUNREACH: return ENETUNREACH;
+ case WSAENETRESET: return ENETRESET;
+ case WSAECONNABORTED: return ECONNABORTED;
+ case WSAECONNRESET: return ECONNRESET;
+ case WSAENOBUFS: return ENOBUFS;
+ case WSAEISCONN: return EISCONN;
+ case WSAENOTCONN: return ENOTCONN;
+ case WSAESHUTDOWN: return ESHUTDOWN;
+ case WSAETOOMANYREFS: return ETOOMANYREFS;
+ case WSAETIMEDOUT: return ETIMEDOUT;
+ case WSAECONNREFUSED: return ECONNREFUSED;
+ case WSAELOOP: return ELOOP;
+ case WSAENAMETOOLONG: return ENAMETOOLONG;
+ case WSAEHOSTDOWN: return EHOSTDOWN;
+ case WSAEHOSTUNREACH: return EHOSTUNREACH;
+ case WSAENOTEMPTY: return ENOTEMPTY;
+ case WSAEPROCLIM: return EPROCLIM;
+ case WSAEUSERS: return EUSERS;
+ case WSAEDQUOT: return EDQUOT;
+ case WSAESTALE: return ESTALE;
+ case WSAEREMOTE: return EREMOTE;
+ case WSAEINVAL: return EINVAL;
+ case WSAEFAULT: return EFAULT;
+ case WSANO_DATA: return ENODATA;
+ /* Rough equivalents */
+ case WSAEDISCON: return ECONNRESET;
+ case WSAEINVALIDPROCTABLE: return EFAULT;
+ case WSASYSNOTREADY:
+ case WSANOTINITIALISED:
+ case WSASYSCALLFAILURE: return ENOBUFS;
+ case WSAVERNOTSUPPORTED: return EOPNOTSUPP;
+ case WSAEREFUSED: return EIO;
+ }
+ return EINVAL;
+}
+
+/**
+ * Return pointer to string description of errnum error
+ * Works fine with both standard errno errnums
+ * and errnums from MHD_W32_errno_from_winsock_
+ * @param errnum the errno or value from MHD_W32_errno_from_winsock_()
+ * @return pointer to string description of error
+ */
+const char* MHD_W32_strerror_(int errnum)
+{
+ switch(errnum)
+ {
+ case 0:
+ return "No error";
+ case EWOULDBLOCK:
+ return "Operation would block";
+ case EINPROGRESS:
+ return "Connection already in progress";
+ case EALREADY:
+ return "Socket already connected";
+ case ENOTSOCK:
+ return "Socket operation on non-socket";
+ case EDESTADDRREQ:
+ return "Destination address required";
+ case EMSGSIZE:
+ return "Message too long";
+ case EPROTOTYPE:
+ return "Protocol wrong type for socket";
+ case ENOPROTOOPT:
+ return "Protocol not available";
+ case EPROTONOSUPPORT:
+ return "Unknown protocol";
+ case ESOCKTNOSUPPORT:
+ return "Socket type not supported";
+ case EOPNOTSUPP:
+ return "Operation not supported on socket";
+ case EPFNOSUPPORT:
+ return "Protocol family not supported";
+ case EAFNOSUPPORT:
+ return "Address family not supported by protocol family";
+ case EADDRINUSE:
+ return "Address already in use";
+ case EADDRNOTAVAIL:
+ return "Cannot assign requested address";
+ case ENETDOWN:
+ return "Network is down";
+ case ENETUNREACH:
+ return "Network is unreachable";
+ case ENETRESET:
+ return "Network dropped connection on reset";
+ case ECONNABORTED:
+ return "Software caused connection abort";
+ case ECONNRESET:
+ return "Connection reset by peer";
+ case ENOBUFS:
+ return "No system resources available";
+ case EISCONN:
+ return "Socket is already connected";
+ case ENOTCONN:
+ return "Socket is not connected";
+ case ESHUTDOWN:
+ return "Can't send after socket shutdown";
+ case ETOOMANYREFS:
+ return "Too many references: cannot splice";
+ case ETIMEDOUT:
+ return "Connection timed out";
+ case ECONNREFUSED:
+ return "Connection refused";
+ case ELOOP:
+ return "Cannot translate name";
+ case EHOSTDOWN:
+ return "Host is down";
+ case EHOSTUNREACH:
+ return "Host is unreachable";
+ case EPROCLIM:
+ return "Too many processes";
+ case EUSERS:
+ return "Too many users";
+ case EDQUOT:
+ return "Disk quota exceeded";
+ case ESTALE:
+ return "Stale file handle reference";
+ case EREMOTE:
+ return "Resource is remote";
+ case ENODATA:
+ return "No data available";
+ }
+ return strerror(errnum);
+}
+
+/**
+ * Return pointer to string description of last winsock error
+ * @return pointer to string description of last winsock error
+ */
+const char* MHD_W32_strerror_last_winsock_(void)
+{
+ switch (WSAGetLastError())
+ {
+ case 0:
+ return "No error";
+ case WSA_INVALID_HANDLE:
+ return "Specified event object handle is invalid";
+ case WSA_NOT_ENOUGH_MEMORY:
+ return "Insufficient memory available";
+ case WSA_INVALID_PARAMETER:
+ return "One or more parameters are invalid";
+ case WSA_OPERATION_ABORTED:
+ return "Overlapped operation aborted";
+ case WSA_IO_INCOMPLETE:
+ return "Overlapped I/O event object not in signaled state";
+ case WSA_IO_PENDING:
+ return "Overlapped operations will complete later";
+ case WSAEINTR:
+ return "Interrupted function call";
+ case WSAEBADF:
+ return "File handle is not valid";
+ 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 WSAETOOMANYREFS:
+ return "Too many references";
+ case WSAETIMEDOUT:
+ return "Connection timed out";
+ case WSAECONNREFUSED:
+ return "Connection refused";
+ case WSAELOOP:
+ return "Cannot translate name";
+ case WSAENAMETOOLONG:
+ return "Name too long";
+ case WSAEHOSTDOWN:
+ return "Host is down";
+ case WSAEHOSTUNREACH:
+ return "No route to host";
+ case WSAENOTEMPTY:
+ return "Directory not empty";
+ case WSAEPROCLIM:
+ return "Too many processes";
+ case WSAEUSERS:
+ return "User quota exceeded";
+ case WSAEDQUOT:
+ return "Disk quota exceeded";
+ case WSAESTALE:
+ return "Stale file handle reference";
+ case WSAEREMOTE:
+ return "Item is remote";
+ 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 WSAENOMORE:
+ return "No more results";
+ case WSAECANCELLED:
+ return "Call has been canceled";
+ case WSAEINVALIDPROCTABLE:
+ return "Procedure call table is invalid";
+ case WSAEINVALIDPROVIDER:
+ return "Service provider is invalid";
+ case WSAEPROVIDERFAILEDINIT:
+ return "Service provider failed to initialize";
+ case WSASYSCALLFAILURE:
+ return "System call failure";
+ case WSASERVICE_NOT_FOUND:
+ return "Service not found";
+ case WSATYPE_NOT_FOUND:
+ return "Class type not found";
+ case WSA_E_NO_MORE:
+ return "No more results";
+ case WSA_E_CANCELLED:
+ return "Call was canceled";
+ case WSAEREFUSED:
+ return "Database query was refused";
+ case WSAHOST_NOT_FOUND:
+ return "Host not found";
+ case WSATRY_AGAIN:
+ return "Nonauthoritative host not found";
+ case WSANO_RECOVERY:
+ return "This is a nonrecoverable error";
+ case WSANO_DATA:
+ return "Valid name, no data record of requested type";
+ case WSA_QOS_RECEIVERS:
+ return "QoS receivers";
+ case WSA_QOS_SENDERS:
+ return "QoS senders";
+ case WSA_QOS_NO_SENDERS:
+ return "No QoS senders";
+ case WSA_QOS_NO_RECEIVERS:
+ return "QoS no receivers";
+ case WSA_QOS_REQUEST_CONFIRMED:
+ return "QoS request confirmed";
+ case WSA_QOS_ADMISSION_FAILURE:
+ return "QoS admission error";
+ case WSA_QOS_POLICY_FAILURE:
+ return "QoS policy failure";
+ case WSA_QOS_BAD_STYLE:
+ return "QoS bad style";
+ case WSA_QOS_BAD_OBJECT:
+ return "QoS bad object";
+ case WSA_QOS_TRAFFIC_CTRL_ERROR:
+ return "QoS traffic control error";
+ case WSA_QOS_GENERIC_ERROR:
+ return "QoS generic error";
+ case WSA_QOS_ESERVICETYPE:
+ return "QoS service type error";
+ case WSA_QOS_EFLOWSPEC:
+ return "QoS flowspec error";
+ case WSA_QOS_EPROVSPECBUF:
+ return "Invalid QoS provider buffer";
+ case WSA_QOS_EFILTERSTYLE:
+ return "Invalid QoS filter style";
+ case WSA_QOS_EFILTERTYPE:
+ return "Invalid QoS filter type";
+ case WSA_QOS_EFILTERCOUNT:
+ return "Incorrect QoS filter count";
+ case WSA_QOS_EOBJLENGTH:
+ return "Invalid QoS object length";
+ case WSA_QOS_EFLOWCOUNT:
+ return "Incorrect QoS flow count";
+ case WSA_QOS_EUNKOWNPSOBJ:
+ return "Unrecognized QoS object";
+ case WSA_QOS_EPOLICYOBJ:
+ return "Invalid QoS policy object";
+ case WSA_QOS_EFLOWDESC:
+ return "Invalid QoS flow descriptor";
+ case WSA_QOS_EPSFLOWSPEC:
+ return "Invalid QoS provider-specific flowspec";
+ case WSA_QOS_EPSFILTERSPEC:
+ return "Invalid QoS provider-specific filterspec";
+ case WSA_QOS_ESDMODEOBJ:
+ return "Invalid QoS shape discard mode object";
+ case WSA_QOS_ESHAPERATEOBJ:
+ return "Invalid QoS shaping rate object";
+ case WSA_QOS_RESERVED_PETYPE:
+ return "Reserved policy QoS element type";
+ }
+ return "Unknown winsock error";
+}
+
+/**
+ * Set last winsock error to equivalent of given errno value
+ * @param errnum the errno value to set
+ */
+void MHD_W32_set_last_winsock_error_(int errnum)
+{
+ switch (errnum)
+ {
+ case 0:
+ WSASetLastError(0);
+ break;
+ case EBADF:
+ WSASetLastError(WSA_INVALID_HANDLE);
+ break;
+ case ENOMEM:
+ WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
+ break;
+ case EINVAL:
+ WSASetLastError(WSA_INVALID_PARAMETER);
+ break;
+ case EINTR:
+ WSASetLastError(WSAEINTR);
+ break;
+ case EWOULDBLOCK:
+ WSASetLastError(WSAEWOULDBLOCK);
+ break;
+ case EINPROGRESS:
+ WSASetLastError(WSAEINPROGRESS);
+ break;
+ case EALREADY:
+ WSASetLastError(WSAEALREADY);
+ break;
+ case ENOTSOCK:
+ WSASetLastError(WSAENOTSOCK);
+ break;
+ case EDESTADDRREQ:
+ WSASetLastError(WSAEDESTADDRREQ);
+ break;
+ case EMSGSIZE:
+ WSASetLastError(WSAEMSGSIZE);
+ break;
+ case EPROTOTYPE:
+ WSASetLastError(WSAEPROTOTYPE);
+ break;
+ case ENOPROTOOPT:
+ WSASetLastError(WSAENOPROTOOPT);
+ break;
+ case EPROTONOSUPPORT:
+ WSASetLastError(WSAEPROTONOSUPPORT);
+ break;
+ case ESOCKTNOSUPPORT:
+ WSASetLastError(WSAESOCKTNOSUPPORT);
+ break;
+ case EOPNOTSUPP:
+ WSASetLastError(WSAEOPNOTSUPP);
+ break;
+ case EPFNOSUPPORT:
+ WSASetLastError(WSAEPFNOSUPPORT);
+ break;
+ case EAFNOSUPPORT:
+ WSASetLastError(WSAEAFNOSUPPORT);
+ break;
+ case EADDRINUSE:
+ WSASetLastError(WSAEADDRINUSE);
+ break;
+ case EADDRNOTAVAIL:
+ WSASetLastError(WSAEADDRNOTAVAIL);
+ break;
+ case ENETDOWN:
+ WSASetLastError(WSAENETDOWN);
+ break;
+ case ENETUNREACH:
+ WSASetLastError(WSAENETUNREACH);
+ break;
+ case ENETRESET:
+ WSASetLastError(WSAENETRESET);
+ break;
+ case ECONNABORTED:
+ WSASetLastError(WSAECONNABORTED);
+ break;
+ case ECONNRESET:
+ WSASetLastError(WSAECONNRESET);
+ break;
+ case ENOBUFS:
+ WSASetLastError(WSAENOBUFS);
+ break;
+ case EISCONN:
+ WSASetLastError(WSAEISCONN);
+ break;
+ case ENOTCONN:
+ WSASetLastError(WSAENOTCONN);
+ break;
+ case ESHUTDOWN:
+ WSASetLastError(WSAESHUTDOWN);
+ break;
+ case ETOOMANYREFS:
+ WSASetLastError(WSAETOOMANYREFS);
+ break;
+ case ETIMEDOUT:
+ WSASetLastError(WSAETIMEDOUT);
+ break;
+ case ECONNREFUSED:
+ WSASetLastError(WSAECONNREFUSED);
+ break;
+ case ELOOP:
+ WSASetLastError(WSAELOOP);
+ break;
+ case ENAMETOOLONG:
+ WSASetLastError(WSAENAMETOOLONG);
+ break;
+ case EHOSTDOWN:
+ WSASetLastError(WSAEHOSTDOWN);
+ break;
+ case EHOSTUNREACH:
+ WSASetLastError(WSAEHOSTUNREACH);
+ break;
+ case ENOTEMPTY:
+ WSASetLastError(WSAENOTEMPTY);
+ break;
+ case EPROCLIM:
+ WSASetLastError(WSAEPROCLIM);
+ break;
+ case EUSERS:
+ WSASetLastError(WSAEUSERS);
+ break;
+ case EDQUOT:
+ WSASetLastError(WSAEDQUOT);
+ break;
+ case ESTALE:
+ WSASetLastError(WSAESTALE);
+ break;
+ case EREMOTE:
+ WSASetLastError(WSAEREMOTE);
+ break;
+ case EFAULT:
+ WSASetLastError(WSAEFAULT);
+ break;
+ case ENODATA:
+ WSASetLastError(WSANO_DATA);
+ break;
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN:
+ WSASetLastError(WSAEWOULDBLOCK);
+ break;
+#endif
+ /* Rough equivalent */
+ case EIO:
+ WSASetLastError(WSAEREFUSED);
+ break;
+
+ default: /* Unmapped errors */
+ WSASetLastError(WSAENOBUFS);
+ break;
+ }
+}
+
+/**
+ * Create pair of mutually connected TCP/IP sockets on loopback address
+ * @param sockets_pair array to receive resulted sockets
+ * @return zero on success, -1 otherwise
+ */
+int MHD_W32_pair_of_sockets_(SOCKET sockets_pair[2])
+{
+ int i;
+ if (!sockets_pair)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+#define PAIRMAXTRYIES 800
+ for (i = 0; i < PAIRMAXTRYIES; i++)
+ {
+ struct sockaddr_in listen_addr;
+ SOCKET listen_s;
+ static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */
+ int addr_len = c_addinlen;
+ int opt = 1;
+
+ listen_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (INVALID_SOCKET == listen_s)
+ break; /* can't create even single socket */
+
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_port = htons(0);
+ listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (0 == bind(listen_s, (struct sockaddr*) &listen_addr, c_addinlen)
+ && 0 == listen(listen_s, 1)
+ && 0 == getsockname(listen_s, (struct sockaddr*) &listen_addr,
+ &addr_len))
+ {
+ SOCKET client_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (INVALID_SOCKET != client_s)
+ {
+ if (0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt)
+ && (0 == connect(client_s, (struct sockaddr*) &listen_addr, c_addinlen)
+ || WSAGetLastError() == WSAEWOULDBLOCK))
+ {
+ struct sockaddr_in accepted_from_addr;
+ addr_len = c_addinlen;
+ SOCKET server_s = accept(listen_s,
+ (struct sockaddr*) &accepted_from_addr, &addr_len);
+ if (INVALID_SOCKET != server_s)
+ {
+ struct sockaddr_in client_addr;
+ addr_len = c_addinlen;
+ opt = 0;
+ if (0 == getsockname(client_s, (struct sockaddr*) &client_addr, &addr_len)
+ && accepted_from_addr.sin_family == client_addr.sin_family
+ && accepted_from_addr.sin_port == client_addr.sin_port
+ && accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr
+ && 0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt)
+ && 0 == ioctlsocket(server_s, FIONBIO, (u_long*) &opt))
+ {
+ closesocket(listen_s);
+ sockets_pair[0] = client_s;
+ sockets_pair[1] = server_s;
+ return 0;
+ }
+ closesocket(server_s);
+ }
+ }
+ closesocket(client_s);
+ }
+ }
+ closesocket(listen_s);
+ }
+
+ sockets_pair[0] = INVALID_SOCKET;
+ sockets_pair[1] = INVALID_SOCKET;
+ return -1;
+}
+
+/**
+ * Static variable used by pseudo random number generator
+ */
+static int32_t rnd_val = 0;
+/**
+ * Generate 31-bit pseudo random number.
+ * Function initialize itself at first call to current time.
+ * @return 31-bit pseudo random number.
+ */
+int MHD_W32_random_(void)
+{
+ if (0 == rnd_val)
+ rnd_val = (int32_t)time(NULL);
+ /* stolen from winsup\cygwin\random.cc */
+ rnd_val = (16807 * (rnd_val % 127773) - 2836 * (rnd_val / 127773))
+ & 0x7fffffff;
+ return (int)rnd_val;
+}
+
+/* Emulate snprintf function on W32 */
+int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...)
+{
+ int ret;
+ va_list args;
+ if (0 != n && NULL != s )
+ {
+ va_start(args, format);
+ ret = _vsnprintf(s, n, format, args);
+ va_end(args);
+ if (n == ret)
+ s[n - 1] = 0;
+ if (ret >= 0)
+ return ret;
+ }
+ va_start(args, format);
+ ret = _vscprintf(format, args);
+ va_end(args);
+ if (0 <= ret && 0 != n && NULL == s)
+ return -1;
+
+ return ret;
+}
+
+#ifdef _MSC_FULL_VER
+/**
+ * Set thread name
+ * @param thread_id ID of thread, -1 for current thread
+ * @param thread_name name to set
+ */
+void W32_SetThreadName(const DWORD thread_id, const char *thread_name)
+{
+ static const DWORD VC_SETNAME_EXC = 0x406D1388;
+#pragma pack(push,8)
+ struct thread_info_struct
+ {
+ DWORD type; // Must be 0x1000.
+ LPCSTR name; // Pointer to name (in user address space).
+ DWORD ID; // Thread ID (-1=caller thread).
+ DWORD flags; // Reserved for future use, must be zero.
+ } thread_info;
+#pragma pack(pop)
+
+ if (NULL == thread_name)
+ return;
+
+ thread_info.type = 0x1000;
+ thread_info.name = thread_name;
+ thread_info.ID = thread_id;
+ thread_info.flags = 0;
+
+ __try
+ { /* This exception is intercepted by debugger */
+ RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {}
+}
+#endif /* _MSC_FULL_VER */