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