1878dbb84cb14b5d61e6941841eea00e5737eb07aDaniel Dunbar/*
2878dbb84cb14b5d61e6941841eea00e5737eb07aDaniel Dunbar  This file is part of libmicrohttpd
33ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar  Copyright (C) 2014 Karlson2k (Evgeny Grin)
43ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
5878dbb84cb14b5d61e6941841eea00e5737eb07aDaniel Dunbar  This library is free software; you can redistribute it and/or
6878dbb84cb14b5d61e6941841eea00e5737eb07aDaniel Dunbar  modify it under the terms of the GNU Lesser General Public
7878dbb84cb14b5d61e6941841eea00e5737eb07aDaniel Dunbar  License as published by the Free Software Foundation; either
8878dbb84cb14b5d61e6941841eea00e5737eb07aDaniel Dunbar  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 */
40int 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 */
108const 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 */
194const 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 */
398void 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 */
555int 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 */
630static 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 */
636int 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 */
647int 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 */
676void 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