]> sjero.net Git - wget/blobdiff - src/mswindows.c
Fix build when libpsl is not available
[wget] / src / mswindows.c
index 09a3383a6c323d77336bbe16816d7677a3fd6cf6..179773e05fccfd99a9d566b6385540ca0ddbc9c5 100644 (file)
@@ -1,11 +1,13 @@
 /* mswindows.c -- Windows-specific support
-   Copyright (C) 1995, 1996, 1997, 1998  Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+   Inc.
 
 This file is part of GNU Wget.
 
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,49 +16,33 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
-In addition, as a special exception, the Free Software Foundation
-gives permission to link the code of its release of Wget with the
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables.  You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL".  If you
-modify this file, you may extend this exception to your version of the
-file, but you are not obligated to do so.  If you do not wish to do
-so, delete this exception statement from your version.  */
+Additional permission under GNU GPL version 3 section 7
 
-/* #### Someone please document what these functions do!  */
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work.  */
 
-#include <config.h>
+#define INHIBIT_WRAP /* avoid wrapping of socket, bind, ... */
+
+#include "wget.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <errno.h>
 #include <math.h>
 
-#ifdef HACK_BCC_UTIME_BUG
-# include <io.h>
-# include <fcntl.h>
-# ifdef HAVE_UTIME_H
-#  include <utime.h>
-# endif
-# ifdef HAVE_SYS_UTIME_H
-#  include <sys/utime.h>
-# endif
-#endif
 
-#include "wget.h"
 #include "utils.h"
 #include "url.h"
 
-#ifndef errno
-extern int errno;
-#endif
-
 #ifndef ES_SYSTEM_REQUIRED
 #define ES_SYSTEM_REQUIRED  0x00000001
 #endif
@@ -67,45 +53,28 @@ extern int errno;
 
 
 /* Defined in log.c.  */
-void log_request_redirect_output PARAMS ((const char *));
-
-static DWORD set_sleep_mode (DWORD mode);
-
-static DWORD pwr_mode = 0;
-static int windows_nt_p;
-
-#ifndef HAVE_SLEEP
-
-/* Emulation of Unix sleep.  */
+void log_request_redirect_output (const char *);
 
-unsigned int
-sleep (unsigned seconds)
-{
-  return SleepEx (1000 * seconds, TRUE) ? 0U : 1000 * seconds;
-}
-#endif
-
-#ifndef HAVE_USLEEP
-/* Emulation of Unix usleep().  This has a granularity of
-   milliseconds, but that's ok because:
-
-   a) Wget is only using it with milliseconds [not anymore, but b)
-      still applies];
+/* Windows version of xsleep in utils.c.  */
 
-   b) You can't rely on usleep's granularity anyway.  If a caller
-   expects usleep to respect every microsecond, he's in for a
-   surprise.  */
-
-int
-usleep (unsigned long usec)
+void
+xsleep (double seconds)
 {
-  SleepEx (usec / 1000, TRUE);
-  return 0;
+#if defined(HAVE_USLEEP) && defined(HAVE_SLEEP)
+  if (seconds > 1000)
+    {
+      /* Explained in utils.c. */
+      sleep (seconds);
+      seconds -= (long) seconds;
+    }
+  usleep (seconds * 1000000);
+#else  /* not HAVE_USLEEP */
+  SleepEx ((DWORD) (seconds * 1000 + .5), FALSE);
+#endif /* not HAVE_USLEEP */
 }
-#endif  /* HAVE_USLEEP */
 
 void
-windows_main_junk (int *argc, char **argv, char **exec_name)
+windows_main (char **exec_name)
 {
   char *p;
 
@@ -116,41 +85,256 @@ windows_main_junk (int *argc, char **argv, char **exec_name)
     *p = '\0';
 }
 \f
-/* Winsock stuff. */
-
 static void
 ws_cleanup (void)
 {
+  xfree ((char*)exec_name);
   WSACleanup ();
-  if (pwr_mode)
-     set_sleep_mode (pwr_mode);
-  pwr_mode = 0;
 }
 
+#if defined(CTRLBREAK_BACKGND) || defined(CTRLC_BACKGND)
+static void
+ws_hangup (const char *reason)
+{
+  fprintf (stderr, _("Continuing in background.\n"));
+  log_request_redirect_output (reason);
+
+  /* Detach process from the current console.  Under Windows 9x, if we
+     were launched from a 16-bit process (which is usually the case;
+     command.com is 16-bit) the parent process should resume right away.
+     Under NT or if launched from a 32-process under 9x, this is a futile
+     gesture as the parent will wait for us to terminate before resuming.  */
+  FreeConsole ();
+}
+#endif
+
+/* Construct the name for a named section (a.k.a. `file mapping') object.
+   The returned string is dynamically allocated and needs to be xfree()'d.  */
+static char *
+make_section_name (DWORD pid)
+{
+  return aprintf ("gnu_wget_fake_fork_%lu", pid);
+}
+
+/* This structure is used to hold all the data that is exchanged between
+   parent and child.  */
+struct fake_fork_info
+{
+  HANDLE event;
+  bool logfile_changed;
+  char lfilename[MAX_PATH + 1];
+};
+
+/* Determines if we are the child and if so performs the child logic.
+   Return values:
+     < 0  error
+       0  parent
+     > 0  child
+*/
+static int
+fake_fork_child (void)
+{
+  HANDLE section, event;
+  struct fake_fork_info *info;
+  char *name;
+
+  name = make_section_name (GetCurrentProcessId ());
+  section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name);
+  xfree (name);
+  /* It seems that Windows 9x and NT set last-error inconsistently when
+     OpenFileMapping() fails; so we assume it failed because the section
+     object does not exist.  */
+  if (!section)
+    return 0;                   /* We are the parent.  */
+
+  info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
+  if (!info)
+    {
+      CloseHandle (section);
+      return -1;
+    }
+
+  event = info->event;
+
+  info->logfile_changed = false;
+  if (!opt.lfilename && (!opt.quiet || opt.server_response))
+    {
+      /* See utils:fork_to_background for explanation. */
+      FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename);
+      if (new_log_fp)
+        {
+          info->logfile_changed = true;
+          strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
+          info->lfilename[sizeof (info->lfilename) - 1] = '\0';
+          fclose (new_log_fp);
+        }
+    }
+
+  UnmapViewOfFile (info);
+  CloseHandle (section);
+
+  /* Inform the parent that we've done our part.  */
+  if (!SetEvent (event))
+    return -1;
+
+  CloseHandle (event);
+  return 1;                     /* We are the child.  */
+}
+
+/* Windows doesn't support the fork() call; so we fake it by invoking
+   another copy of Wget with the same arguments with which we were
+   invoked.  The child copy of Wget should perform the same initialization
+   sequence as the parent; so we should have two processes that are
+   essentially identical.  We create a specially named section object that
+   allows the child to distinguish itself from the parent and is used to
+   exchange information between the two processes.  We use an event object
+   for synchronization.  */
 static void
-ws_hangup (void)
+fake_fork (void)
 {
-  log_request_redirect_output ("CTRL+Break");
+  char exe[MAX_PATH + 1];
+  DWORD exe_len, le;
+  SECURITY_ATTRIBUTES sa;
+  HANDLE section, event, h[2];
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+  struct fake_fork_info *info;
+  char *name;
+  BOOL rv;
+
+  section = pi.hProcess = pi.hThread = NULL;
+
+  /* Get the fully qualified name of our executable.  This is more reliable
+     than using argv[0].  */
+  exe_len = GetModuleFileName (GetModuleHandle (NULL), exe, sizeof (exe));
+  if (!exe_len || (exe_len >= sizeof (exe)))
+    return;
+
+  sa.nLength = sizeof (sa);
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = TRUE;
+
+  /* Create an anonymous inheritable event object that starts out
+     non-signaled.  */
+  event = CreateEvent (&sa, FALSE, FALSE, NULL);
+  if (!event)
+    return;
+
+  /* Create the child process detached form the current console and in a
+     suspended state.  */
+  xzero (si);
+  si.cb = sizeof (si);
+  rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
+                      CREATE_SUSPENDED | DETACHED_PROCESS,
+                      NULL, NULL, &si, &pi);
+  if (!rv)
+    goto cleanup;
+
+  /* Create a named section object with a name based on the process id of
+     the child.  */
+  name = make_section_name (pi.dwProcessId);
+  section =
+      CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+                         sizeof (struct fake_fork_info), name);
+  le = GetLastError();
+  xfree (name);
+  /* Fail if the section object already exists (should not happen).  */
+  if (!section || (le == ERROR_ALREADY_EXISTS))
+    {
+      rv = FALSE;
+      goto cleanup;
+    }
+
+  /* Copy the event handle into the section object.  */
+  info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
+  if (!info)
+    {
+      rv = FALSE;
+      goto cleanup;
+    }
+
+  info->event = event;
+
+  UnmapViewOfFile (info);
+
+  /* Start the child process.  */
+  rv = ResumeThread (pi.hThread);
+  if (!rv)
+    {
+      TerminateProcess (pi.hProcess, (DWORD) -1);
+      goto cleanup;
+    }
+
+  /* Wait for the child to signal to us that it has done its part.  If it
+     terminates before signaling us it's an error.  */
+
+  h[0] = event;
+  h[1] = pi.hProcess;
+  rv = WAIT_OBJECT_0 == WaitForMultipleObjects (2, h, FALSE, 5 * 60 * 1000);
+  if (!rv)
+    goto cleanup;
+
+  info = MapViewOfFile (section, FILE_MAP_READ, 0, 0, 0);
+  if (!info)
+    {
+      rv = FALSE;
+      goto cleanup;
+    }
+
+  /* Ensure string is properly terminated.  */
+  if (info->logfile_changed &&
+      !memchr (info->lfilename, '\0', sizeof (info->lfilename)))
+    {
+      rv = FALSE;
+      goto cleanup;
+    }
+
+  printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
+  if (info->logfile_changed)
+    printf (_("Output will be written to %s.\n"), quote (info->lfilename));
+
+  UnmapViewOfFile (info);
+
+cleanup:
+
+  if (event)
+    CloseHandle (event);
+  if (section)
+    CloseHandle (section);
+  if (pi.hThread)
+    CloseHandle (pi.hThread);
+  if (pi.hProcess)
+    CloseHandle (pi.hProcess);
+
+  /* We're the parent.  If all is well, terminate.  */
+  if (rv)
+    exit (0);
+
+  /* We failed, return.  */
 }
 
+/* This is the corresponding Windows implementation of the
+   fork_to_background() function in utils.c.  */
 void
 fork_to_background (void)
 {
-  /* Whether we arrange our own version of opt.lfilename here.  */
-  int changedp = 0;
+  int rv;
 
-  if (!opt.lfilename)
+  rv = fake_fork_child ();
+  if (rv < 0)
     {
-      opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
-      changedp = 1;
+      fprintf (stderr, _("fake_fork_child() failed\n"));
+      abort ();
     }
-  printf (_("Continuing in background.\n"));
-  if (changedp)
-    printf (_("Output will be written to `%s'.\n"), opt.lfilename);
-
-  ws_hangup ();
-  if (!windows_nt_p)
-    FreeConsole ();
+  else if (rv == 0)
+    {
+      /* We're the parent.  */
+      fake_fork ();
+      /* If fake_fork() returns, it failed.  */
+      fprintf (stderr, _("fake_fork() failed\n"));
+      abort ();
+    }
+  /* If we get here, we're the child.  */
 }
 
 static BOOL WINAPI
@@ -160,198 +344,150 @@ ws_handler (DWORD dwEvent)
     {
 #ifdef CTRLC_BACKGND
     case CTRL_C_EVENT:
+      ws_hangup ("CTRL+C");
+      return TRUE;
 #endif
 #ifdef CTRLBREAK_BACKGND
     case CTRL_BREAK_EVENT:
+      ws_hangup ("CTRL+Break");
+      return TRUE;
 #endif
-      fork_to_background ();
-      break;
-    case CTRL_SHUTDOWN_EVENT:
-    case CTRL_CLOSE_EVENT:
-    case CTRL_LOGOFF_EVENT:
     default:
-      ws_cleanup ();
       return FALSE;
     }
-  return TRUE;
 }
 
 static char *title_buf = NULL;
 static char *curr_url  = NULL;
-static int   num_urls  = 0;
+static int old_percentage = -1;
 
+/* Updates the console title with the URL of the current file being
+   transferred.  */
 void
-ws_changetitle (const char *url, int nurl)
+ws_changetitle (const char *url)
 {
-  if (!nurl)
-    return;
-
-  num_urls = nurl;
-  if (title_buf)
-     xfree(title_buf);
-  if (curr_url)
-     xfree(curr_url);
-  title_buf = (char *)xmalloc (strlen (url) + 20);
-  curr_url = xstrdup(url);
-  sprintf(title_buf, "Wget %s%s", url, nurl == 1 ? "" : " ...");
-  SetConsoleTitle(title_buf);
+  xfree_null (title_buf);
+  xfree_null (curr_url);
+  title_buf = xmalloc (strlen (url) + 20);
+  curr_url = xstrdup (url);
+  old_percentage = -1;
+  sprintf (title_buf, "Wget %s", curr_url);
+  SetConsoleTitle (title_buf);
 }
 
+/* Updates the console title with the percentage of the current file
+   transferred.  */
 void
-ws_percenttitle (double percent)
+ws_percenttitle (double percentage_float)
 {
-  if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
-    {
-      sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
-      SetConsoleTitle (title_buf);
-    }
+  int percentage;
+
+  if (!title_buf || !curr_url)
+    return;
+
+  percentage = (int) percentage_float;
+
+  /* Clamp percentage value.  */
+  if (percentage < 0)
+    percentage = 0;
+  if (percentage > 100)
+    percentage = 100;
+
+  /* Only update the title when the percentage has changed.  */
+  if (percentage == old_percentage)
+    return;
+
+  old_percentage = percentage;
+
+  sprintf (title_buf, "Wget [%d%%] %s", percentage, curr_url);
+  SetConsoleTitle (title_buf);
 }
 
+/* Returns a pointer to the fully qualified name of the directory that
+   contains the Wget binary (wget.exe).  The returned path does not have a
+   trailing path separator.  Returns NULL on failure.  */
 char *
 ws_mypath (void)
 {
   static char *wspathsave = NULL;
-  char buffer[MAX_PATH];
-  char *ptr;
 
-  if (wspathsave)
+  if (!wspathsave)
     {
-      return wspathsave;
-    }
+      char buf[MAX_PATH + 1];
+      char *p;
+      DWORD len;
 
-  if (GetModuleFileName (NULL, buffer, MAX_PATH) &&
-      (ptr = strrchr (buffer, PATH_SEPARATOR)) != NULL)
-    {
-      *(ptr + 1) = '\0';
-      wspathsave = xstrdup (buffer);
+      len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
+      if (!len || (len >= sizeof (buf)))
+        return NULL;
+
+      p = strrchr (buf, PATH_SEPARATOR);
+      if (!p)
+        return NULL;
+
+      *p = '\0';
+      wspathsave = xstrdup (buf);
     }
-  else
-    wspathsave = NULL;
+
   return wspathsave;
 }
 
-void
-ws_help (const char *name)
+/* Prevent Windows entering sleep/hibernation-mode while Wget is doing
+   a lengthy transfer.  Windows does not, by default, consider network
+   activity in console-programs as activity!  Works on Win-98/ME/2K
+   and up.  */
+static void
+set_sleep_mode (void)
 {
-  char *mypath = ws_mypath ();
+  typedef DWORD (WINAPI *func_t) (DWORD);
+  func_t set_exec_state;
 
-  if (mypath)
-    {
-      struct stat sbuf;
-      char *buf = (char *)alloca (strlen (mypath) + strlen (name) + 4 + 1);
-      sprintf (buf, "%s%s.HLP", mypath, name);
-      if (stat (buf, &sbuf) == 0) 
-       {
-          printf (_("Starting WinHelp %s\n"), buf);
-          WinHelp (NULL, buf, HELP_INDEX, 0);
-        }
-      else
-        {
-          printf ("%s: %s\n", buf, strerror (errno));
-        }
-    }
+  set_exec_state =
+      (func_t) GetProcAddress (GetModuleHandle ("KERNEL32.DLL"),
+                               "SetThreadExecutionState");
+
+  if (set_exec_state)
+    set_exec_state (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
 }
 
+/* Perform Windows specific initialization.  */
 void
 ws_startup (void)
 {
-  WORD requested;
   WSADATA data;
-  int err;
-  OSVERSIONINFO os;
-
-  if (GetVersionEx (&os) == TRUE
-      && os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
-    windows_nt_p = 1;
-
-  requested = MAKEWORD (1, 1);
-  err = WSAStartup (requested, &data);
-
+  WORD requested = MAKEWORD (1, 1);
+  int err = WSAStartup (requested, &data);
   if (err != 0)
     {
       fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
-              exec_name);
+               exec_name);
       exit (1);
     }
 
   if (data.wVersion < requested)
     {
       fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
-              exec_name);
+               exec_name);
       WSACleanup ();
       exit (1);
     }
+
   atexit (ws_cleanup);
-  pwr_mode = set_sleep_mode (0);
+  set_sleep_mode ();
   SetConsoleCtrlHandler (ws_handler, TRUE);
 }
-
-/* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
-   (The Borland utime function only works on Windows NT.)  */
-
-#ifdef HACK_BCC_UTIME_BUG
-int
-borland_utime (const char *path, const struct utimbuf *times)
-{
-  int fd;
-  int res;
-  struct ftime ft;
-  struct tm *ptr_tm;
-
-  if ((fd = open (path, O_RDWR)) < 0)
-    return -1;
-
-  ptr_tm = localtime (&times->modtime);
-  ft.ft_tsec = ptr_tm->tm_sec >> 1;
-  ft.ft_min = ptr_tm->tm_min;
-  ft.ft_hour = ptr_tm->tm_hour;
-  ft.ft_day = ptr_tm->tm_mday;
-  ft.ft_month = ptr_tm->tm_mon + 1;
-  ft.ft_year = ptr_tm->tm_year - 80;
-  res = setftime (fd, &ft);
-  close (fd);
-  return res;
-}
-#endif
-
-/*
- * Prevent Windows entering sleep/hibernation-mode while wget is doing a lengthy transfer.
- * Windows does by default not consider network activity in console-programs as activity !
- * Works on Win-98/ME/2K and up.
- */
-static DWORD
-set_sleep_mode (DWORD mode)
-{
-  HMODULE mod = LoadLibrary ("kernel32.dll");
-  DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
-  DWORD rc = (DWORD)-1;
-
-  if (mod)
-     (void*)_SetThreadExecutionState = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
-
-  if (_SetThreadExecutionState)
-    {
-      if (mode == 0)  /* first time */
-       mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
-      rc = (*_SetThreadExecutionState) (mode);
-    }
-  if (mod)
-    FreeLibrary (mod);
-  DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
-  return rc;
-}
 \f
-/* run_with_timeout Windows implementation. */
+/* run_with_timeout Windows implementation.  */
 
- /* Stack size 0 uses default thread stack-size (reserve+commit).
-  * Determined by what's in the PE header.
- */
+/* Stack size 0 uses default thread stack-size (reserve+commit).
+   Determined by what's in the PE header.  */
 #define THREAD_STACK_SIZE  0
 
-struct thread_data {
-   void (*fun) (void *);
-   void  *arg;
-   DWORD ws_error; 
+struct thread_data
+{
+  void (*fun) (void *);
+  void *arg;
+  DWORD ws_error;
 };
 
 /* The callback that runs FUN(ARG) in a separate thread.  This
@@ -363,7 +499,7 @@ struct thread_data {
    [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
    the default (wcc386 -3r).  */
 
-static DWORD WINAPI 
+static DWORD WINAPI
 thread_helper (void *arg)
 {
   struct thread_data *td = (struct thread_data *) arg;
@@ -377,62 +513,142 @@ thread_helper (void *arg)
 
   /* Return Winsock error to the caller, in case FUN ran Winsock
      code.  */
-  td->ws_error = WSAGetLastError();
-  return 0; 
+  td->ws_error = WSAGetLastError ();
+  return 0;
 }
 
-/*
- * Run FUN with timeout.  This is done by creating a thread for 'fun'
- * to run in and terminating the thread if it doesn't finish in
- * SECONDS time.
- */
+/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
+   seconds.  Returns true if the function was interrupted with a
+   timeout, false otherwise.
+
+   This works by running FUN in a separate thread and terminating the
+   thread if it doesn't finish in the specified time.  */
 
-int
+bool
 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
 {
-  static HANDLE thread_hnd = NULL;
+  HANDLE thread_hnd;
   struct thread_data thread_arg;
-  DWORD  thread_id;
-  int    rc = 0;
+  DWORD thread_id;
+  bool rc;
 
   DEBUGP (("seconds %.2f, ", seconds));
-  
+
   if (seconds == 0)
     {
     blocking_fallback:
       fun (arg);
-      return 0;
+      return false;
     }
 
-  /* Should never happen, but test for recursivety anyway */
-  assert (thread_hnd == NULL);  
-
   thread_arg.fun = fun;
   thread_arg.arg = arg;
   thread_arg.ws_error = WSAGetLastError ();
   thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
-                            &thread_arg, 0, &thread_id); 
+                             &thread_arg, 0, &thread_id);
   if (!thread_hnd)
     {
-      DEBUGP (("CreateThread() failed; %s\n", strerror(GetLastError())));
+      DEBUGP (("CreateThread() failed; [%#lx]\n",
+               (unsigned long) GetLastError ()));
       goto blocking_fallback;
     }
 
-  if (WaitForSingleObject(thread_hnd, (DWORD)(1000*seconds)) == WAIT_OBJECT_0)
+  if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
+      == WAIT_OBJECT_0)
     {
       /* Propagate error state (which is per-thread) to this thread,
-        so the caller can inspect it.  */
+         so the caller can inspect it.  */
       WSASetLastError (thread_arg.ws_error);
-      DEBUGP (("Winsock error: %d\n", WSAGetLastError()));
-      rc = 0;
+      DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
+      rc = false;
     }
   else
     {
       TerminateThread (thread_hnd, 1);
-      rc = 1;
+      rc = true;
     }
 
-  CloseHandle (thread_hnd); /* clear-up after TerminateThread() */
+  CloseHandle (thread_hnd);     /* Clear-up after TerminateThread().  */
   thread_hnd = NULL;
   return rc;
 }
+
+
+#ifdef ENABLE_IPV6
+/* An inet_ntop implementation that uses WSAAddressToString.
+   Prototype complies with POSIX 1003.1-2004.  This is only used under
+   IPv6 because Wget prints IPv4 addresses using inet_ntoa.  */
+
+const char *
+inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
+{
+  /* struct sockaddr can't accomodate struct sockaddr_in6. */
+  union {
+    struct sockaddr_in6 sin6;
+    struct sockaddr_in sin;
+  } sa;
+  DWORD dstlen = cnt;
+  size_t srcsize;
+
+  xzero (sa);
+  switch (af)
+    {
+    case AF_INET:
+      sa.sin.sin_family = AF_INET;
+      sa.sin.sin_addr = *(struct in_addr *) src;
+      srcsize = sizeof (sa.sin);
+      break;
+    case AF_INET6:
+      sa.sin6.sin6_family = AF_INET6;
+      sa.sin6.sin6_addr = *(struct in6_addr *) src;
+      srcsize = sizeof (sa.sin6);
+      break;
+    default:
+      abort ();
+    }
+
+  if (WSAAddressToString ((struct sockaddr *) &sa, srcsize, NULL, dst, &dstlen) != 0)
+    {
+      errno = WSAGetLastError();
+      return NULL;
+    }
+  return (const char *) dst;
+}
+#endif
+
+
+void
+set_windows_fd_as_blocking_socket (int fd)
+{
+    /* 04/2011
+     gnulib select() converts blocking sockets to nonblocking in windows
+     discussed here:
+     http://old.nabble.com/blocking-socket-is-nonblocking-after-calling-gnulib-
+     select%28%29-in-windows-td31432857.html
+
+     wget uses blocking sockets so we must convert them back to blocking.
+    */
+    int ret = 0;
+    int wsagle = 0;
+    const int zero = 0;
+
+    do
+    {
+        if(wsagle == WSAEINPROGRESS)
+          Sleep(1);  /* use windows sleep */
+
+        WSASetLastError (0);
+        ret = ioctl (fd, FIONBIO, &zero);
+        wsagle = WSAGetLastError ();
+    }
+  while (ret && (wsagle == WSAEINPROGRESS));
+
+  if(ret)
+    {
+      fprintf (stderr,
+               _("ioctl() failed.  The socket could not be set as blocking.\n") );
+      DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
+      abort ();
+    }
+  return;
+}