1 /*
2 This file is part of libmicrohttpd
3 Copyright (C) 2014 Karlson2k (Evgeny Grin)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /**
21 * @file platform/w32functions.h
22 * @brief internal functions for W32 systems
23 * @author Karlson2k (Evgeny Grin)
24 */
25
26 #include "w32functions.h"
27 #include <errno.h>
28 #include <winsock2.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <time.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34
35
36 /**
37 * Return errno equivalent of last winsock error
38 * @return errno equivalent of last winsock error
39 */
MHD_W32_errno_from_winsock_(void)40 int MHD_W32_errno_from_winsock_(void)
41 {
42 switch(WSAGetLastError())
43 {
44 case 0: return 0;
45 case WSA_INVALID_HANDLE: return EBADF;
46 case WSA_NOT_ENOUGH_MEMORY: return ENOMEM;
47 case WSA_INVALID_PARAMETER: return EINVAL;
48 case WSAEINTR: return EINTR;
49 case WSAEWOULDBLOCK: return EWOULDBLOCK;
50 case WSAEINPROGRESS: return EINPROGRESS;
51 case WSAEALREADY: return EALREADY;
52 case WSAENOTSOCK: return ENOTSOCK;
53 case WSAEDESTADDRREQ: return EDESTADDRREQ;
54 case WSAEMSGSIZE: return EMSGSIZE;
55 case WSAEPROTOTYPE: return EPROTOTYPE;
56 case WSAENOPROTOOPT: return ENOPROTOOPT;
57 case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
58 case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT;
59 case WSAEOPNOTSUPP: return EOPNOTSUPP;
60 case WSAEPFNOSUPPORT: return EPFNOSUPPORT;
61 case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
62 case WSAEADDRINUSE: return EADDRINUSE;
63 case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
64 case WSAENETDOWN: return ENETDOWN;
65 case WSAENETUNREACH: return ENETUNREACH;
66 case WSAENETRESET: return ENETRESET;
67 case WSAECONNABORTED: return ECONNABORTED;
68 case WSAECONNRESET: return ECONNRESET;
69 case WSAENOBUFS: return ENOBUFS;
70 case WSAEISCONN: return EISCONN;
71 case WSAENOTCONN: return ENOTCONN;
72 case WSAESHUTDOWN: return ESHUTDOWN;
73 case WSAETOOMANYREFS: return ETOOMANYREFS;
74 case WSAETIMEDOUT: return ETIMEDOUT;
75 case WSAECONNREFUSED: return ECONNREFUSED;
76 case WSAELOOP: return ELOOP;
77 case WSAENAMETOOLONG: return ENAMETOOLONG;
78 case WSAEHOSTDOWN: return EHOSTDOWN;
79 case WSAEHOSTUNREACH: return EHOSTUNREACH;
80 case WSAENOTEMPTY: return ENOTEMPTY;
81 case WSAEPROCLIM: return EPROCLIM;
82 case WSAEUSERS: return EUSERS;
83 case WSAEDQUOT: return EDQUOT;
84 case WSAESTALE: return ESTALE;
85 case WSAEREMOTE: return EREMOTE;
86 case WSAEINVAL: return EINVAL;
87 case WSAEFAULT: return EFAULT;
88 case WSANO_DATA: return ENODATA;
89 /* Rough equivalents */
90 case WSAEDISCON: return ECONNRESET;
91 case WSAEINVALIDPROCTABLE: return EFAULT;
92 case WSASYSNOTREADY:
93 case WSANOTINITIALISED:
94 case WSASYSCALLFAILURE: return ENOBUFS;
95 case WSAVERNOTSUPPORTED: return EOPNOTSUPP;
96 case WSAEREFUSED: return EIO;
97 }
98 return EINVAL;
99 }
100
101 /**
102 * Return pointer to string description of errnum error
103 * Works fine with both standard errno errnums
104 * and errnums from MHD_W32_errno_from_winsock_
105 * @param errnum the errno or value from MHD_W32_errno_from_winsock_()
106 * @return pointer to string description of error
107 */
MHD_W32_strerror_(int errnum)108 const char* MHD_W32_strerror_(int errnum)
109 {
110 switch(errnum)
111 {
112 case 0:
113 return "No error";
114 case EWOULDBLOCK:
115 return "Operation would block";
116 case EINPROGRESS:
117 return "Connection already in progress";
118 case EALREADY:
119 return "Socket already connected";
120 case ENOTSOCK:
121 return "Socket operation on non-socket";
122 case EDESTADDRREQ:
123 return "Destination address required";
124 case EMSGSIZE:
125 return "Message too long";
126 case EPROTOTYPE:
127 return "Protocol wrong type for socket";
128 case ENOPROTOOPT:
129 return "Protocol not available";
130 case EPROTONOSUPPORT:
131 return "Unknown protocol";
132 case ESOCKTNOSUPPORT:
133 return "Socket type not supported";
134 case EOPNOTSUPP:
135 return "Operation not supported on socket";
136 case EPFNOSUPPORT:
137 return "Protocol family not supported";
138 case EAFNOSUPPORT:
139 return "Address family not supported by protocol family";
140 case EADDRINUSE:
141 return "Address already in use";
142 case EADDRNOTAVAIL:
143 return "Cannot assign requested address";
144 case ENETDOWN:
145 return "Network is down";
146 case ENETUNREACH:
147 return "Network is unreachable";
148 case ENETRESET:
149 return "Network dropped connection on reset";
150 case ECONNABORTED:
151 return "Software caused connection abort";
152 case ECONNRESET:
153 return "Connection reset by peer";
154 case ENOBUFS:
155 return "No system resources available";
156 case EISCONN:
157 return "Socket is already connected";
158 case ENOTCONN:
159 return "Socket is not connected";
160 case ESHUTDOWN:
161 return "Can't send after socket shutdown";
162 case ETOOMANYREFS:
163 return "Too many references: cannot splice";
164 case ETIMEDOUT:
165 return "Connection timed out";
166 case ECONNREFUSED:
167 return "Connection refused";
168 case ELOOP:
169 return "Cannot translate name";
170 case EHOSTDOWN:
171 return "Host is down";
172 case EHOSTUNREACH:
173 return "Host is unreachable";
174 case EPROCLIM:
175 return "Too many processes";
176 case EUSERS:
177 return "Too many users";
178 case EDQUOT:
179 return "Disk quota exceeded";
180 case ESTALE:
181 return "Stale file handle reference";
182 case EREMOTE:
183 return "Resource is remote";
184 case ENODATA:
185 return "No data available";
186 }
187 return strerror(errnum);
188 }
189
190 /**
191 * Return pointer to string description of last winsock error
192 * @return pointer to string description of last winsock error
193 */
MHD_W32_strerror_last_winsock_(void)194 const char* MHD_W32_strerror_last_winsock_(void)
195 {
196 switch (WSAGetLastError())
197 {
198 case 0:
199 return "No error";
200 case WSA_INVALID_HANDLE:
201 return "Specified event object handle is invalid";
202 case WSA_NOT_ENOUGH_MEMORY:
203 return "Insufficient memory available";
204 case WSA_INVALID_PARAMETER:
205 return "One or more parameters are invalid";
206 case WSA_OPERATION_ABORTED:
207 return "Overlapped operation aborted";
208 case WSA_IO_INCOMPLETE:
209 return "Overlapped I/O event object not in signaled state";
210 case WSA_IO_PENDING:
211 return "Overlapped operations will complete later";
212 case WSAEINTR:
213 return "Interrupted function call";
214 case WSAEBADF:
215 return "File handle is not valid";
216 case WSAEACCES:
217 return "Permission denied";
218 case WSAEFAULT:
219 return "Bad address";
220 case WSAEINVAL:
221 return "Invalid argument";
222 case WSAEMFILE:
223 return "Too many open files";
224 case WSAEWOULDBLOCK:
225 return "Resource temporarily unavailable";
226 case WSAEINPROGRESS:
227 return "Operation now in progress";
228 case WSAEALREADY:
229 return "Operation already in progress";
230 case WSAENOTSOCK:
231 return "Socket operation on nonsocket";
232 case WSAEDESTADDRREQ:
233 return "Destination address required";
234 case WSAEMSGSIZE:
235 return "Message too long";
236 case WSAEPROTOTYPE:
237 return "Protocol wrong type for socket";
238 case WSAENOPROTOOPT:
239 return "Bad protocol option";
240 case WSAEPROTONOSUPPORT:
241 return "Protocol not supported";
242 case WSAESOCKTNOSUPPORT:
243 return "Socket type not supported";
244 case WSAEOPNOTSUPP:
245 return "Operation not supported";
246 case WSAEPFNOSUPPORT:
247 return "Protocol family not supported";
248 case WSAEAFNOSUPPORT:
249 return "Address family not supported by protocol family";
250 case WSAEADDRINUSE:
251 return "Address already in use";
252 case WSAEADDRNOTAVAIL:
253 return "Cannot assign requested address";
254 case WSAENETDOWN:
255 return "Network is down";
256 case WSAENETUNREACH:
257 return "Network is unreachable";
258 case WSAENETRESET:
259 return "Network dropped connection on reset";
260 case WSAECONNABORTED:
261 return "Software caused connection abort";
262 case WSAECONNRESET:
263 return "Connection reset by peer";
264 case WSAENOBUFS:
265 return "No buffer space available";
266 case WSAEISCONN:
267 return "Socket is already connected";
268 case WSAENOTCONN:
269 return "Socket is not connected";
270 case WSAESHUTDOWN:
271 return "Cannot send after socket shutdown";
272 case WSAETOOMANYREFS:
273 return "Too many references";
274 case WSAETIMEDOUT:
275 return "Connection timed out";
276 case WSAECONNREFUSED:
277 return "Connection refused";
278 case WSAELOOP:
279 return "Cannot translate name";
280 case WSAENAMETOOLONG:
281 return "Name too long";
282 case WSAEHOSTDOWN:
283 return "Host is down";
284 case WSAEHOSTUNREACH:
285 return "No route to host";
286 case WSAENOTEMPTY:
287 return "Directory not empty";
288 case WSAEPROCLIM:
289 return "Too many processes";
290 case WSAEUSERS:
291 return "User quota exceeded";
292 case WSAEDQUOT:
293 return "Disk quota exceeded";
294 case WSAESTALE:
295 return "Stale file handle reference";
296 case WSAEREMOTE:
297 return "Item is remote";
298 case WSASYSNOTREADY:
299 return "Network subsystem is unavailable";
300 case WSAVERNOTSUPPORTED:
301 return "Winsock.dll version out of range";
302 case WSANOTINITIALISED:
303 return "Successful WSAStartup not yet performed";
304 case WSAEDISCON:
305 return "Graceful shutdown in progress";
306 case WSAENOMORE:
307 return "No more results";
308 case WSAECANCELLED:
309 return "Call has been canceled";
310 case WSAEINVALIDPROCTABLE:
311 return "Procedure call table is invalid";
312 case WSAEINVALIDPROVIDER:
313 return "Service provider is invalid";
314 case WSAEPROVIDERFAILEDINIT:
315 return "Service provider failed to initialize";
316 case WSASYSCALLFAILURE:
317 return "System call failure";
318 case WSASERVICE_NOT_FOUND:
319 return "Service not found";
320 case WSATYPE_NOT_FOUND:
321 return "Class type not found";
322 case WSA_E_NO_MORE:
323 return "No more results";
324 case WSA_E_CANCELLED:
325 return "Call was canceled";
326 case WSAEREFUSED:
327 return "Database query was refused";
328 case WSAHOST_NOT_FOUND:
329 return "Host not found";
330 case WSATRY_AGAIN:
331 return "Nonauthoritative host not found";
332 case WSANO_RECOVERY:
333 return "This is a nonrecoverable error";
334 case WSANO_DATA:
335 return "Valid name, no data record of requested type";
336 case WSA_QOS_RECEIVERS:
337 return "QoS receivers";
338 case WSA_QOS_SENDERS:
339 return "QoS senders";
340 case WSA_QOS_NO_SENDERS:
341 return "No QoS senders";
342 case WSA_QOS_NO_RECEIVERS:
343 return "QoS no receivers";
344 case WSA_QOS_REQUEST_CONFIRMED:
345 return "QoS request confirmed";
346 case WSA_QOS_ADMISSION_FAILURE:
347 return "QoS admission error";
348 case WSA_QOS_POLICY_FAILURE:
349 return "QoS policy failure";
350 case WSA_QOS_BAD_STYLE:
351 return "QoS bad style";
352 case WSA_QOS_BAD_OBJECT:
353 return "QoS bad object";
354 case WSA_QOS_TRAFFIC_CTRL_ERROR:
355 return "QoS traffic control error";
356 case WSA_QOS_GENERIC_ERROR:
357 return "QoS generic error";
358 case WSA_QOS_ESERVICETYPE:
359 return "QoS service type error";
360 case WSA_QOS_EFLOWSPEC:
361 return "QoS flowspec error";
362 case WSA_QOS_EPROVSPECBUF:
363 return "Invalid QoS provider buffer";
364 case WSA_QOS_EFILTERSTYLE:
365 return "Invalid QoS filter style";
366 case WSA_QOS_EFILTERTYPE:
367 return "Invalid QoS filter type";
368 case WSA_QOS_EFILTERCOUNT:
369 return "Incorrect QoS filter count";
370 case WSA_QOS_EOBJLENGTH:
371 return "Invalid QoS object length";
372 case WSA_QOS_EFLOWCOUNT:
373 return "Incorrect QoS flow count";
374 case WSA_QOS_EUNKOWNPSOBJ:
375 return "Unrecognized QoS object";
376 case WSA_QOS_EPOLICYOBJ:
377 return "Invalid QoS policy object";
378 case WSA_QOS_EFLOWDESC:
379 return "Invalid QoS flow descriptor";
380 case WSA_QOS_EPSFLOWSPEC:
381 return "Invalid QoS provider-specific flowspec";
382 case WSA_QOS_EPSFILTERSPEC:
383 return "Invalid QoS provider-specific filterspec";
384 case WSA_QOS_ESDMODEOBJ:
385 return "Invalid QoS shape discard mode object";
386 case WSA_QOS_ESHAPERATEOBJ:
387 return "Invalid QoS shaping rate object";
388 case WSA_QOS_RESERVED_PETYPE:
389 return "Reserved policy QoS element type";
390 }
391 return "Unknown winsock error";
392 }
393
394 /**
395 * Set last winsock error to equivalent of given errno value
396 * @param errnum the errno value to set
397 */
MHD_W32_set_last_winsock_error_(int errnum)398 void MHD_W32_set_last_winsock_error_(int errnum)
399 {
400 switch (errnum)
401 {
402 case 0:
403 WSASetLastError(0);
404 break;
405 case EBADF:
406 WSASetLastError(WSA_INVALID_HANDLE);
407 break;
408 case ENOMEM:
409 WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
410 break;
411 case EINVAL:
412 WSASetLastError(WSA_INVALID_PARAMETER);
413 break;
414 case EINTR:
415 WSASetLastError(WSAEINTR);
416 break;
417 case EWOULDBLOCK:
418 WSASetLastError(WSAEWOULDBLOCK);
419 break;
420 case EINPROGRESS:
421 WSASetLastError(WSAEINPROGRESS);
422 break;
423 case EALREADY:
424 WSASetLastError(WSAEALREADY);
425 break;
426 case ENOTSOCK:
427 WSASetLastError(WSAENOTSOCK);
428 break;
429 case EDESTADDRREQ:
430 WSASetLastError(WSAEDESTADDRREQ);
431 break;
432 case EMSGSIZE:
433 WSASetLastError(WSAEMSGSIZE);
434 break;
435 case EPROTOTYPE:
436 WSASetLastError(WSAEPROTOTYPE);
437 break;
438 case ENOPROTOOPT:
439 WSASetLastError(WSAENOPROTOOPT);
440 break;
441 case EPROTONOSUPPORT:
442 WSASetLastError(WSAEPROTONOSUPPORT);
443 break;
444 case ESOCKTNOSUPPORT:
445 WSASetLastError(WSAESOCKTNOSUPPORT);
446 break;
447 case EOPNOTSUPP:
448 WSASetLastError(WSAEOPNOTSUPP);
449 break;
450 case EPFNOSUPPORT:
451 WSASetLastError(WSAEPFNOSUPPORT);
452 break;
453 case EAFNOSUPPORT:
454 WSASetLastError(WSAEAFNOSUPPORT);
455 break;
456 case EADDRINUSE:
457 WSASetLastError(WSAEADDRINUSE);
458 break;
459 case EADDRNOTAVAIL:
460 WSASetLastError(WSAEADDRNOTAVAIL);
461 break;
462 case ENETDOWN:
463 WSASetLastError(WSAENETDOWN);
464 break;
465 case ENETUNREACH:
466 WSASetLastError(WSAENETUNREACH);
467 break;
468 case ENETRESET:
469 WSASetLastError(WSAENETRESET);
470 break;
471 case ECONNABORTED:
472 WSASetLastError(WSAECONNABORTED);
473 break;
474 case ECONNRESET:
475 WSASetLastError(WSAECONNRESET);
476 break;
477 case ENOBUFS:
478 WSASetLastError(WSAENOBUFS);
479 break;
480 case EISCONN:
481 WSASetLastError(WSAEISCONN);
482 break;
483 case ENOTCONN:
484 WSASetLastError(WSAENOTCONN);
485 break;
486 case ESHUTDOWN:
487 WSASetLastError(WSAESHUTDOWN);
488 break;
489 case ETOOMANYREFS:
490 WSASetLastError(WSAETOOMANYREFS);
491 break;
492 case ETIMEDOUT:
493 WSASetLastError(WSAETIMEDOUT);
494 break;
495 case ECONNREFUSED:
496 WSASetLastError(WSAECONNREFUSED);
497 break;
498 case ELOOP:
499 WSASetLastError(WSAELOOP);
500 break;
501 case ENAMETOOLONG:
502 WSASetLastError(WSAENAMETOOLONG);
503 break;
504 case EHOSTDOWN:
505 WSASetLastError(WSAEHOSTDOWN);
506 break;
507 case EHOSTUNREACH:
508 WSASetLastError(WSAEHOSTUNREACH);
509 break;
510 case ENOTEMPTY:
511 WSASetLastError(WSAENOTEMPTY);
512 break;
513 case EPROCLIM:
514 WSASetLastError(WSAEPROCLIM);
515 break;
516 case EUSERS:
517 WSASetLastError(WSAEUSERS);
518 break;
519 case EDQUOT:
520 WSASetLastError(WSAEDQUOT);
521 break;
522 case ESTALE:
523 WSASetLastError(WSAESTALE);
524 break;
525 case EREMOTE:
526 WSASetLastError(WSAEREMOTE);
527 break;
528 case EFAULT:
529 WSASetLastError(WSAEFAULT);
530 break;
531 case ENODATA:
532 WSASetLastError(WSANO_DATA);
533 break;
534 #if EAGAIN != EWOULDBLOCK
535 case EAGAIN:
536 WSASetLastError(WSAEWOULDBLOCK);
537 break;
538 #endif
539 /* Rough equivalent */
540 case EIO:
541 WSASetLastError(WSAEREFUSED);
542 break;
543
544 default: /* Unmapped errors */
545 WSASetLastError(WSAENOBUFS);
546 break;
547 }
548 }
549
550 /**
551 * Create pair of mutually connected TCP/IP sockets on loopback address
552 * @param sockets_pair array to receive resulted sockets
553 * @return zero on success, -1 otherwise
554 */
MHD_W32_pair_of_sockets_(SOCKET sockets_pair[2])555 int MHD_W32_pair_of_sockets_(SOCKET sockets_pair[2])
556 {
557 int i;
558 if (!sockets_pair)
559 {
560 errno = EINVAL;
561 return -1;
562 }
563
564 #define PAIRMAXTRYIES 800
565 for (i = 0; i < PAIRMAXTRYIES; i++)
566 {
567 struct sockaddr_in listen_addr;
568 SOCKET listen_s;
569 static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */
570 int addr_len = c_addinlen;
571 int opt = 1;
572
573 listen_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
574 if (INVALID_SOCKET == listen_s)
575 break; /* can't create even single socket */
576
577 listen_addr.sin_family = AF_INET;
578 listen_addr.sin_port = htons(0);
579 listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
580 if (0 == bind(listen_s, (struct sockaddr*) &listen_addr, c_addinlen)
581 && 0 == listen(listen_s, 1)
582 && 0 == getsockname(listen_s, (struct sockaddr*) &listen_addr,
583 &addr_len))
584 {
585 SOCKET client_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
586 if (INVALID_SOCKET != client_s)
587 {
588 if (0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt)
589 && (0 == connect(client_s, (struct sockaddr*) &listen_addr, c_addinlen)
590 || WSAGetLastError() == WSAEWOULDBLOCK))
591 {
592 struct sockaddr_in accepted_from_addr;
593 addr_len = c_addinlen;
594 SOCKET server_s = accept(listen_s,
595 (struct sockaddr*) &accepted_from_addr, &addr_len);
596 if (INVALID_SOCKET != server_s)
597 {
598 struct sockaddr_in client_addr;
599 addr_len = c_addinlen;
600 opt = 0;
601 if (0 == getsockname(client_s, (struct sockaddr*) &client_addr, &addr_len)
602 && accepted_from_addr.sin_family == client_addr.sin_family
603 && accepted_from_addr.sin_port == client_addr.sin_port
604 && accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr
605 && 0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt)
606 && 0 == ioctlsocket(server_s, FIONBIO, (u_long*) &opt))
607 {
608 closesocket(listen_s);
609 sockets_pair[0] = client_s;
610 sockets_pair[1] = server_s;
611 return 0;
612 }
613 closesocket(server_s);
614 }
615 }
616 closesocket(client_s);
617 }
618 }
619 closesocket(listen_s);
620 }
621
622 sockets_pair[0] = INVALID_SOCKET;
623 sockets_pair[1] = INVALID_SOCKET;
624 return -1;
625 }
626
627 /**
628 * Static variable used by pseudo random number generator
629 */
630 static int32_t rnd_val = 0;
631 /**
632 * Generate 31-bit pseudo random number.
633 * Function initialize itself at first call to current time.
634 * @return 31-bit pseudo random number.
635 */
MHD_W32_random_(void)636 int MHD_W32_random_(void)
637 {
638 if (0 == rnd_val)
639 rnd_val = (int32_t)time(NULL);
640 /* stolen from winsup\cygwin\random.cc */
641 rnd_val = (16807 * (rnd_val % 127773) - 2836 * (rnd_val / 127773))
642 & 0x7fffffff;
643 return (int)rnd_val;
644 }
645
646 /* Emulate snprintf function on W32 */
W32_snprintf(char * __restrict s,size_t n,const char * __restrict format,...)647 int W32_snprintf(char *__restrict s, size_t n, const char *__restrict format, ...)
648 {
649 int ret;
650 va_list args;
651 if (0 != n && NULL != s )
652 {
653 va_start(args, format);
654 ret = _vsnprintf(s, n, format, args);
655 va_end(args);
656 if (n == ret)
657 s[n - 1] = 0;
658 if (ret >= 0)
659 return ret;
660 }
661 va_start(args, format);
662 ret = _vscprintf(format, args);
663 va_end(args);
664 if (0 <= ret && 0 != n && NULL == s)
665 return -1;
666
667 return ret;
668 }
669
670 #ifdef _MSC_FULL_VER
671 /**
672 * Set thread name
673 * @param thread_id ID of thread, -1 for current thread
674 * @param thread_name name to set
675 */
W32_SetThreadName(const DWORD thread_id,const char * thread_name)676 void W32_SetThreadName(const DWORD thread_id, const char *thread_name)
677 {
678 static const DWORD VC_SETNAME_EXC = 0x406D1388;
679 #pragma pack(push,8)
680 struct thread_info_struct
681 {
682 DWORD type; // Must be 0x1000.
683 LPCSTR name; // Pointer to name (in user address space).
684 DWORD ID; // Thread ID (-1=caller thread).
685 DWORD flags; // Reserved for future use, must be zero.
686 } thread_info;
687 #pragma pack(pop)
688
689 if (NULL == thread_name)
690 return;
691
692 thread_info.type = 0x1000;
693 thread_info.name = thread_name;
694 thread_info.ID = thread_id;
695 thread_info.flags = 0;
696
697 __try
698 { /* This exception is intercepted by debugger */
699 RaiseException(VC_SETNAME_EXC, 0, sizeof(thread_info) / sizeof(ULONG_PTR), (ULONG_PTR*)&thread_info);
700 }
701 __except (EXCEPTION_EXECUTE_HANDLER)
702 {}
703 }
704 #endif /* _MSC_FULL_VER */
705