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