+\f
+/* run_with_timeout Windows implementation. */
+
+/* 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;
+};
+
+/* The callback that runs FUN(ARG) in a separate thread. This
+ function exists for two reasons: a) to not require FUN to be
+ declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
+ which are per-thread. The latter is useful when FUN calls Winsock
+ functions, which is how run_with_timeout is used in Wget.
+
+ [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
+ the default (wcc386 -3r). */
+
+static DWORD WINAPI
+thread_helper (void *arg)
+{
+ struct thread_data *td = (struct thread_data *) arg;
+
+ /* Initialize Winsock error to what it was in the parent. That way
+ the subsequent call to WSAGetLastError will return the same value
+ if td->fun doesn't change Winsock error state. */
+ WSASetLastError (td->ws_error);
+
+ td->fun (td->arg);
+
+ /* Return Winsock error to the caller, in case FUN ran Winsock
+ code. */
+ td->ws_error = WSAGetLastError ();
+ return 0;
+}
+
+/* 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. */
+
+bool
+run_with_timeout (double seconds, void (*fun) (void *), void *arg)
+{
+ HANDLE thread_hnd;
+ struct thread_data thread_arg;
+ DWORD thread_id;
+ bool rc;
+
+ DEBUGP (("seconds %.2f, ", seconds));
+
+ if (seconds == 0)
+ {
+ blocking_fallback:
+ fun (arg);
+ return false;
+ }
+
+ 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);
+ if (!thread_hnd)
+ {
+ DEBUGP (("CreateThread() failed; [%#lx]\n",
+ (unsigned long) GetLastError ()));
+ goto blocking_fallback;
+ }
+
+ 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. */
+ WSASetLastError (thread_arg.ws_error);
+ DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
+ rc = false;
+ }
+ else
+ {
+ TerminateThread (thread_hnd, 1);
+ rc = true;
+ }
+
+ 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;
+}