]> sjero.net Git - wget/blob - src/mswindows.c
[svn] Use strtoll on Windows if available (as with DMC).
[wget] / src / mswindows.c
1 /* mswindows.c -- Windows-specific support
2    Copyright (C) 1996-2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <errno.h>
37 #include <math.h>
38
39 #define INHIBIT_WRAP /* avoid wrapping of socket, bind, ... */
40
41 #include "wget.h"
42 #include "utils.h"
43 #include "url.h"
44
45 #ifndef ES_SYSTEM_REQUIRED
46 #define ES_SYSTEM_REQUIRED  0x00000001
47 #endif
48
49 #ifndef ES_CONTINUOUS
50 #define ES_CONTINUOUS       0x80000000
51 #endif
52
53
54 /* Defined in log.c.  */
55 void log_request_redirect_output (const char *);
56
57 /* Windows version of xsleep in utils.c.  */
58
59 void
60 xsleep (double seconds)
61 {
62 #ifdef HAVE_USLEEP
63   if (seconds > 1000)
64     {
65       /* Explained in utils.c. */
66       sleep (seconds);
67       seconds -= (long) seconds;
68     }
69   usleep (seconds * 1000000);
70 #else  /* not HAVE_USLEEP */
71   SleepEx ((DWORD) (seconds * 1000 + .5), FALSE);
72 #endif /* not HAVE_USLEEP */
73 }
74
75 #if !defined(HAVE_STRTOLL) && !defined(HAVE__STRTOI64)
76
77 static inline int
78 char_value (char c, int base)
79 {
80   int value;
81   if (c < '0')
82     return -1;
83   if ('0' <= c && c <= '9')
84     value = c - '0';
85   else if ('a' <= c && c <= 'z')
86     value = c - 'a' + 10;
87   else if ('A' <= c && c <= 'Z')
88     value = c - 'A' + 10;
89   else
90     return -1;
91   if (value >= base)
92     return -1;
93   return value;
94 }
95
96 /* A fairly simple strtoll replacement for MS VC versions that don't
97    supply _strtoi64.  */
98
99 __int64
100 str_to_int64 (const char *nptr, char **endptr, int base)
101 {
102 #define INT64_OVERFLOW 9223372036854775807I64
103 #define INT64_UNDERFLOW (-INT64_OVERFLOW - 1)
104
105   __int64 result = 0;
106   bool negative;
107
108   if (base != 0 && (base < 2 || base > 36))
109     {
110       errno = EINVAL;
111       return 0;
112     }
113
114   while (*nptr == ' ' || *nptr == '\t')
115     ++nptr;
116   if (*nptr == '-')
117     {
118       negative = true;
119       ++nptr;
120     }
121   else if (*nptr == '+')
122     {
123       negative = false;
124       ++nptr;
125     }
126   else
127     negative = false;
128
129   /* If base is 0, determine the real base based on the beginning on
130      the number; octal numbers begin with "0", hexadecimal with "0x",
131      and the others are considered octal.  */
132   if (*nptr == '0')
133     {
134       if ((base == 0 || base == 16)
135           &&
136           (*(nptr + 1) == 'x' || *(nptr + 1) == 'X'))
137         {
138           base = 16;
139           nptr += 2;
140         }
141       else if (base == 0)
142         base = 8;
143     }
144   else if (base == 0)
145     base = 10;
146
147   if (!negative)
148     {
149       /* Parse positive number, checking for overflow. */
150       int val;
151       for (; (val = char_value (*nptr, base)) != -1; ++nptr)
152         {
153           __int64 newresult = base * result + val;
154           if (newresult < result)
155             {
156               result = INT64_OVERFLOW;
157               errno = ERANGE;
158               break;
159             }
160           result = newresult;
161         }
162     }
163   else
164     {
165       /* Parse negative number, checking for underflow. */
166       int val;
167       for (; (val = char_value (*nptr, base)) != -1; ++nptr)
168         {
169           __int64 newresult = base * result - val;
170           if (newresult > result)
171             {
172               result = INT64_UNDERFLOW;
173               errno = ERANGE;
174               break;
175             }
176           result = newresult;
177         }
178     }
179   if (endptr)
180     *endptr = (char *) nptr;
181   return result;
182 }
183 #endif
184
185 void
186 windows_main (int *argc, char **argv, char **exec_name)
187 {
188   char *p;
189
190   /* Remove .EXE from filename if it has one.  */
191   *exec_name = xstrdup (*exec_name);
192   p = strrchr (*exec_name, '.');
193   if (p)
194     *p = '\0';
195 }
196 \f
197 static void
198 ws_cleanup (void)
199 {
200   WSACleanup ();
201 }
202
203 static void
204 ws_hangup (const char *reason)
205 {
206   fprintf (stderr, _("Continuing in background.\n"));
207   log_request_redirect_output (reason);
208
209   /* Detach process from the current console.  Under Windows 9x, if we
210      were launched from a 16-bit process (which is usually the case;
211      command.com is 16-bit) the parent process should resume right away.
212      Under NT or if launched from a 32-process under 9x, this is a futile
213      gesture as the parent will wait for us to terminate before resuming.  */
214   FreeConsole ();
215 }
216
217 /* Construct the name for a named section (a.k.a. `file mapping') object.
218    The returned string is dynamically allocated and needs to be xfree()'d.  */
219 static char *
220 make_section_name (DWORD pid)
221 {
222   return aprintf ("gnu_wget_fake_fork_%lu", pid);
223 }
224
225 /* This structure is used to hold all the data that is exchanged between
226    parent and child.  */
227 struct fake_fork_info
228 {
229   HANDLE event;
230   bool logfile_changed;
231   char lfilename[MAX_PATH + 1];
232 };
233
234 /* Determines if we are the child and if so performs the child logic.
235    Return values:
236      < 0  error
237        0  parent
238      > 0  child
239 */
240 static int
241 fake_fork_child (void)
242 {
243   HANDLE section, event;
244   struct fake_fork_info *info;
245   char *name;
246
247   name = make_section_name (GetCurrentProcessId ());
248   section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name);
249   xfree (name);
250   /* It seems that Windows 9x and NT set last-error inconsistently when
251      OpenFileMapping() fails; so we assume it failed because the section
252      object does not exist.  */
253   if (!section)
254     return 0;                   /* We are the parent.  */
255
256   info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
257   if (!info)
258     {
259       CloseHandle (section);
260       return -1;
261     }
262
263   event = info->event;
264
265   info->logfile_changed = false;
266   if (!opt.lfilename)
267     {
268       /* See utils:fork_to_background for explanation. */
269       FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename);
270       if (new_log_fp)
271         {
272           info->logfile_changed = true;
273           strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
274           info->lfilename[sizeof (info->lfilename) - 1] = '\0';
275           fclose (new_log_fp);
276         }
277     }
278
279   UnmapViewOfFile (info);
280   CloseHandle (section);
281
282   /* Inform the parent that we've done our part.  */
283   if (!SetEvent (event))
284     return -1;
285
286   CloseHandle (event);
287   return 1;                     /* We are the child.  */
288 }
289
290 /* Windows doesn't support the fork() call; so we fake it by invoking
291    another copy of Wget with the same arguments with which we were
292    invoked.  The child copy of Wget should perform the same initialization
293    sequence as the parent; so we should have two processes that are
294    essentially identical.  We create a specially named section object that
295    allows the child to distinguish itself from the parent and is used to
296    exchange information between the two processes.  We use an event object
297    for synchronization.  */
298 static void
299 fake_fork (void)
300 {
301   char exe[MAX_PATH + 1];
302   DWORD exe_len, le;
303   SECURITY_ATTRIBUTES sa;
304   HANDLE section, event, h[2];
305   STARTUPINFO si;
306   PROCESS_INFORMATION pi;
307   struct fake_fork_info *info;
308   char *name;
309   BOOL rv;
310
311   section = pi.hProcess = pi.hThread = NULL;
312
313   /* Get the fully qualified name of our executable.  This is more reliable
314      than using argv[0].  */
315   exe_len = GetModuleFileName (GetModuleHandle (NULL), exe, sizeof (exe));
316   if (!exe_len || (exe_len >= sizeof (exe)))
317     return;
318
319   sa.nLength = sizeof (sa);
320   sa.lpSecurityDescriptor = NULL;
321   sa.bInheritHandle = TRUE;
322
323   /* Create an anonymous inheritable event object that starts out
324      non-signaled.  */
325   event = CreateEvent (&sa, FALSE, FALSE, NULL);
326   if (!event)
327     return;
328
329   /* Create the child process detached form the current console and in a
330      suspended state.  */
331   xzero (si);
332   si.cb = sizeof (si);
333   rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
334                       CREATE_SUSPENDED | DETACHED_PROCESS,
335                       NULL, NULL, &si, &pi);
336   if (!rv)
337     goto cleanup;
338
339   /* Create a named section object with a name based on the process id of
340      the child.  */
341   name = make_section_name (pi.dwProcessId);
342   section =
343       CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
344                          sizeof (struct fake_fork_info), name);
345   le = GetLastError();
346   xfree (name);
347   /* Fail if the section object already exists (should not happen).  */
348   if (!section || (le == ERROR_ALREADY_EXISTS))
349     {
350       rv = FALSE;
351       goto cleanup;
352     }
353
354   /* Copy the event handle into the section object.  */
355   info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
356   if (!info)
357     {
358       rv = FALSE;
359       goto cleanup;
360     }
361
362   info->event = event;
363
364   UnmapViewOfFile (info);
365
366   /* Start the child process.  */
367   rv = ResumeThread (pi.hThread);
368   if (!rv)
369     {
370       TerminateProcess (pi.hProcess, (DWORD) -1);
371       goto cleanup;
372     }
373
374   /* Wait for the child to signal to us that it has done its part.  If it
375      terminates before signaling us it's an error.  */
376
377   h[0] = event;
378   h[1] = pi.hProcess;
379   rv = WAIT_OBJECT_0 == WaitForMultipleObjects (2, h, FALSE, 5 * 60 * 1000);
380   if (!rv)
381     goto cleanup;
382
383   info = MapViewOfFile (section, FILE_MAP_READ, 0, 0, 0);
384   if (!info)
385     {
386       rv = FALSE;
387       goto cleanup;
388     }
389
390   /* Ensure string is properly terminated.  */
391   if (info->logfile_changed &&
392       !memchr (info->lfilename, '\0', sizeof (info->lfilename)))
393     {
394       rv = FALSE;
395       goto cleanup;
396     }
397
398   printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
399   if (info->logfile_changed)
400     printf (_("Output will be written to `%s'.\n"), info->lfilename);
401
402   UnmapViewOfFile (info);
403
404 cleanup:
405
406   if (event)
407     CloseHandle (event);
408   if (section)
409     CloseHandle (section);
410   if (pi.hThread)
411     CloseHandle (pi.hThread);
412   if (pi.hProcess)
413     CloseHandle (pi.hProcess);
414
415   /* We're the parent.  If all is well, terminate.  */
416   if (rv)
417     exit (0);
418
419   /* We failed, return.  */
420 }
421
422 /* This is the corresponding Windows implementation of the
423    fork_to_background() function in utils.c.  */
424 void
425 fork_to_background (void)
426 {
427   int rv;
428
429   rv = fake_fork_child ();
430   if (rv < 0)
431     {
432       fprintf (stderr, "fake_fork_child() failed\n");
433       abort ();
434     }
435   else if (rv == 0)
436     {
437       /* We're the parent.  */
438       fake_fork ();
439       /* If fake_fork() returns, it failed.  */
440       fprintf (stderr, "fake_fork() failed\n");
441       abort ();
442     }
443   /* If we get here, we're the child.  */
444 }
445
446 static BOOL WINAPI
447 ws_handler (DWORD dwEvent)
448 {
449   switch (dwEvent)
450     {
451 #ifdef CTRLC_BACKGND
452     case CTRL_C_EVENT:
453       ws_hangup ("CTRL+C");
454       return TRUE;
455 #endif
456 #ifdef CTRLBREAK_BACKGND
457     case CTRL_BREAK_EVENT:
458       ws_hangup ("CTRL+Break");
459       return TRUE;
460 #endif
461     default:
462       return FALSE;
463     }
464 }
465
466 static char *title_buf = NULL;
467 static char *curr_url  = NULL;
468 static int old_percentage = -1;
469
470 /* Updates the console title with the URL of the current file being
471    transferred.  */
472 void
473 ws_changetitle (const char *url)
474 {
475   xfree_null (title_buf);
476   xfree_null (curr_url);
477   title_buf = xmalloc (strlen (url) + 20);
478   curr_url = xstrdup (url);
479   old_percentage = -1;
480   sprintf (title_buf, "Wget %s", curr_url);
481   SetConsoleTitle (title_buf);
482 }
483
484 /* Updates the console title with the percentage of the current file
485    transferred.  */
486 void
487 ws_percenttitle (double percentage_float)
488 {
489   int percentage;
490
491   if (!title_buf || !curr_url)
492     return;
493
494   percentage = (int) percentage_float;
495
496   /* Clamp percentage value.  */
497   if (percentage < 0)
498     percentage = 0;
499   if (percentage > 100)
500     percentage = 100;
501
502   /* Only update the title when the percentage has changed.  */
503   if (percentage == old_percentage)
504     return;
505
506   old_percentage = percentage;
507
508   sprintf (title_buf, "Wget [%d%%] %s", percentage, curr_url);
509   SetConsoleTitle (title_buf);
510 }
511
512 /* Returns a pointer to the fully qualified name of the directory that
513    contains the Wget binary (wget.exe).  The returned path does not have a
514    trailing path separator.  Returns NULL on failure.  */
515 char *
516 ws_mypath (void)
517 {
518   static char *wspathsave = NULL;
519
520   if (!wspathsave)
521     {
522       char buf[MAX_PATH + 1];
523       char *p;
524       DWORD len;
525
526       len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
527       if (!len || (len >= sizeof (buf)))
528         return NULL;
529
530       p = strrchr (buf, PATH_SEPARATOR);
531       if (!p)
532         return NULL;
533
534       *p = '\0';
535       wspathsave = xstrdup (buf);
536     }
537
538   return wspathsave;
539 }
540
541 /* Prevent Windows entering sleep/hibernation-mode while Wget is doing
542    a lengthy transfer.  Windows does not, by default, consider network
543    activity in console-programs as activity!  Works on Win-98/ME/2K
544    and up.  */
545 static void
546 set_sleep_mode (void)
547 {
548   typedef DWORD (WINAPI *func_t) (DWORD);
549   func_t set_exec_state;
550
551   set_exec_state =
552       (func_t) GetProcAddress (GetModuleHandle ("KERNEL32.DLL"),
553                                "SetThreadExecutionState");
554
555   if (set_exec_state)
556     set_exec_state (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
557 }
558
559 /* Perform Windows specific initialization.  */
560 void
561 ws_startup (void)
562 {
563   WSADATA data;
564   WORD requested = MAKEWORD (1, 1);
565   int err = WSAStartup (requested, &data);
566   if (err != 0)
567     {
568       fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
569                exec_name);
570       exit (1);
571     }
572
573   if (data.wVersion < requested)
574     {
575       fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
576                exec_name);
577       WSACleanup ();
578       exit (1);
579     }
580
581   atexit (ws_cleanup);
582   set_sleep_mode ();
583   SetConsoleCtrlHandler (ws_handler, TRUE);
584 }
585 \f
586 /* run_with_timeout Windows implementation.  */
587
588 /* Stack size 0 uses default thread stack-size (reserve+commit).
589    Determined by what's in the PE header.  */
590 #define THREAD_STACK_SIZE  0
591
592 struct thread_data
593 {
594   void (*fun) (void *);
595   void *arg;
596   DWORD ws_error;
597 };
598
599 /* The callback that runs FUN(ARG) in a separate thread.  This
600    function exists for two reasons: a) to not require FUN to be
601    declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
602    which are per-thread.  The latter is useful when FUN calls Winsock
603    functions, which is how run_with_timeout is used in Wget.
604
605    [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
606    the default (wcc386 -3r).  */
607
608 static DWORD WINAPI
609 thread_helper (void *arg)
610 {
611   struct thread_data *td = (struct thread_data *) arg;
612
613   /* Initialize Winsock error to what it was in the parent.  That way
614      the subsequent call to WSAGetLastError will return the same value
615      if td->fun doesn't change Winsock error state.  */
616   WSASetLastError (td->ws_error);
617
618   td->fun (td->arg);
619
620   /* Return Winsock error to the caller, in case FUN ran Winsock
621      code.  */
622   td->ws_error = WSAGetLastError ();
623   return 0;
624 }
625
626 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
627    seconds.  Returns true if the function was interrupted with a
628    timeout, false otherwise.
629
630    This works by running FUN in a separate thread and terminating the
631    thread if it doesn't finish in the specified time.  */
632
633 bool
634 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
635 {
636   static HANDLE thread_hnd = NULL;
637   struct thread_data thread_arg;
638   DWORD thread_id;
639   bool rc;
640
641   DEBUGP (("seconds %.2f, ", seconds));
642
643   if (seconds == 0)
644     {
645     blocking_fallback:
646       fun (arg);
647       return false;
648     }
649
650   /* Should never happen, but test for recursivety anyway.  */
651   assert (thread_hnd == NULL);
652
653   thread_arg.fun = fun;
654   thread_arg.arg = arg;
655   thread_arg.ws_error = WSAGetLastError ();
656   thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
657                              &thread_arg, 0, &thread_id);
658   if (!thread_hnd)
659     {
660       DEBUGP (("CreateThread() failed; [0x%x]\n", GetLastError ()));
661       goto blocking_fallback;
662     }
663
664   if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
665       == WAIT_OBJECT_0)
666     {
667       /* Propagate error state (which is per-thread) to this thread,
668          so the caller can inspect it.  */
669       WSASetLastError (thread_arg.ws_error);
670       DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
671       rc = false;
672     }
673   else
674     {
675       TerminateThread (thread_hnd, 1);
676       rc = true;
677     }
678
679   CloseHandle (thread_hnd);     /* Clear-up after TerminateThread().  */
680   thread_hnd = NULL;
681   return rc;
682 }
683 \f
684 /* Wget expects network calls such as connect, recv, send, etc., to set
685    errno on failure.  To achieve that, Winsock calls are wrapped with code
686    that, in case of error, sets errno to the value of WSAGetLastError().
687    In addition, we provide a wrapper around strerror, which recognizes
688    Winsock errors and prints the appropriate error message. */
689
690 /* Define a macro that creates a function definition that wraps FUN into
691    a function that sets errno the way the rest of the code expects. */
692
693 #define WRAP(fun, decl, call) int wrapped_##fun decl {  \
694   int retval = fun call;                                \
695   if (retval < 0)                                       \
696     errno = WSAGetLastError ();                         \
697   return retval;                                        \
698 }
699
700 WRAP (socket, (int domain, int type, int protocol), (domain, type, protocol))
701 WRAP (bind, (int s, struct sockaddr *a, int alen), (s, a, alen))
702 WRAP (connect, (int s, const struct sockaddr *a, int alen), (s, a, alen))
703 WRAP (listen, (int s, int backlog), (s, backlog))
704 WRAP (accept, (int s, struct sockaddr *a, int *alen), (s, a, alen))
705 WRAP (recv, (int s, void *buf, int len, int flags), (s, buf, len, flags))
706 WRAP (send, (int s, const void *buf, int len, int flags), (s, buf, len, flags))
707 WRAP (select, (int n, fd_set *r, fd_set *w, fd_set *e, const struct timeval *tm),
708               (n, r, w, e, tm))
709 WRAP (getsockname, (int s, struct sockaddr *n, int *nlen), (s, n, nlen))
710 WRAP (getpeername, (int s, struct sockaddr *n, int *nlen), (s, n, nlen))
711 WRAP (setsockopt, (int s, int level, int opt, const void *val, int len),
712                   (s, level, opt, val, len))
713 WRAP (closesocket, (int s), (s))
714
715 /* Return the text of the error message for Winsock error WSERR. */
716
717 static const char *
718 get_winsock_error (int wserr)
719 {
720   switch (wserr) {
721   case WSAEINTR:           return "Interrupted system call";
722   case WSAEBADF:           return "Bad file number";
723   case WSAEACCES:          return "Permission denied";
724   case WSAEFAULT:          return "Bad address";
725   case WSAEINVAL:          return "Invalid argument";
726   case WSAEMFILE:          return "Too many open files";
727   case WSAEWOULDBLOCK:     return "Resource temporarily unavailable";
728   case WSAEINPROGRESS:     return "Operation now in progress";
729   case WSAEALREADY:        return "Operation already in progress";
730   case WSAENOTSOCK:        return "Socket operation on nonsocket";
731   case WSAEDESTADDRREQ:    return "Destination address required";
732   case WSAEMSGSIZE:        return "Message too long";
733   case WSAEPROTOTYPE:      return "Protocol wrong type for socket";
734   case WSAENOPROTOOPT:     return "Bad protocol option";
735   case WSAEPROTONOSUPPORT: return "Protocol not supported";
736   case WSAESOCKTNOSUPPORT: return "Socket type not supported";
737   case WSAEOPNOTSUPP:      return "Operation not supported";
738   case WSAEPFNOSUPPORT:    return "Protocol family not supported";
739   case WSAEAFNOSUPPORT:    return "Address family not supported by protocol family";
740   case WSAEADDRINUSE:      return "Address already in use";
741   case WSAEADDRNOTAVAIL:   return "Cannot assign requested address";
742   case WSAENETDOWN:        return "Network is down";
743   case WSAENETUNREACH:     return "Network is unreachable";
744   case WSAENETRESET:       return "Network dropped connection on reset";
745   case WSAECONNABORTED:    return "Software caused connection abort";
746   case WSAECONNRESET:      return "Connection reset by peer";
747   case WSAENOBUFS:         return "No buffer space available";
748   case WSAEISCONN:         return "Socket is already connected";
749   case WSAENOTCONN:        return "Socket is not connected";
750   case WSAESHUTDOWN:       return "Cannot send after socket shutdown";
751   case WSAETOOMANYREFS:    return "Too many references";
752   case WSAETIMEDOUT:       return "Connection timed out";
753   case WSAECONNREFUSED:    return "Connection refused";
754   case WSAELOOP:           return "Too many levels of symbolic links";
755   case WSAENAMETOOLONG:    return "File name too long";
756   case WSAEHOSTDOWN:       return "Host is down";
757   case WSAEHOSTUNREACH:    return "No route to host";
758   case WSAENOTEMPTY:       return "Not empty";
759   case WSAEPROCLIM:        return "Too many processes";
760   case WSAEUSERS:          return "Too many users";
761   case WSAEDQUOT:          return "Bad quota";
762   case WSAESTALE:          return "Something is stale";
763   case WSAEREMOTE:         return "Remote error";
764   case WSAEDISCON:         return "Disconnected";
765
766   /* Extended Winsock errors */
767   case WSASYSNOTREADY:     return "Winsock library is not ready";
768   case WSANOTINITIALISED:  return "Winsock library not initalised";
769   case WSAVERNOTSUPPORTED: return "Winsock version not supported";
770
771   case WSAHOST_NOT_FOUND: return "Host not found";
772   case WSATRY_AGAIN:      return "Host not found, try again";
773   case WSANO_RECOVERY:    return "Unrecoverable error in call to nameserver";
774   case WSANO_DATA:        return "No data record of requested type";
775
776   default:
777     return NULL;
778   }
779 }
780
781 /* Return the error message corresponding to ERR.  This is different
782    from Windows libc strerror() in that it handles Winsock errors
783    correctly.  */
784
785 const char *
786 windows_strerror (int err)
787 {
788   const char *p;
789   if (err >= 0 && err < sys_nerr)
790     return strerror (err);
791   else if ((p = get_winsock_error (err)) != NULL)
792     return p;
793   else
794     {
795       static char buf[32];
796       snprintf (buf, sizeof (buf), "Unknown error %d (%#x)", err, err);
797       return buf;
798     }
799 }
800 \f
801 #ifdef ENABLE_IPV6
802 /* An IPv6-only inet_ntop that prints with WSAAddressToString.  (Wget
803    uses inet_ntoa for IPv4 addresses -- see print_address.)  Prototype
804    complies with POSIX 1003.1-2004.  */
805
806 const char *
807 inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
808 {
809   struct sockaddr_in6 sin6;
810   DWORD dstlen = cnt;
811
812   assert (af == AF_INET6);
813   xzero (sin6);
814   sin6.sin6_family = AF_INET6;
815   sin6.sin6_addr = *(struct in6_addr *) src;
816   if (WSAAddressToString ((struct sockaddr *) &sin6, sizeof (sin6),
817                           NULL, dst, &dstlen) != 0)
818     {
819       errno = WSAGetLastError();
820       return NULL;
821     }
822   return (const char *) dst;
823 }
824 #endif