| /* |
| 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 */ |