1 /* mswindows.c -- Windows-specific support
2 Copyright (C) 1996-2006 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
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.
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.
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.
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. */
39 #define INHIBIT_WRAP /* avoid wrapping of socket, bind, ... */
45 #ifndef ES_SYSTEM_REQUIRED
46 #define ES_SYSTEM_REQUIRED 0x00000001
50 #define ES_CONTINUOUS 0x80000000
54 /* Defined in log.c. */
55 void log_request_redirect_output (const char *);
57 /* Windows version of xsleep in utils.c. */
60 xsleep (double seconds)
65 /* Explained in utils.c. */
67 seconds -= (long) seconds;
69 usleep (seconds * 1000000);
70 #else /* not HAVE_USLEEP */
71 SleepEx ((DWORD) (seconds * 1000 + .5), FALSE);
72 #endif /* not HAVE_USLEEP */
76 windows_main (int *argc, char **argv, char **exec_name)
80 /* Remove .EXE from filename if it has one. */
81 *exec_name = xstrdup (*exec_name);
82 p = strrchr (*exec_name, '.');
93 #if defined(CTRLBREAK_BACKGND) || defined(CTRLC_BACKGND)
95 ws_hangup (const char *reason)
97 fprintf (stderr, _("Continuing in background.\n"));
98 log_request_redirect_output (reason);
100 /* Detach process from the current console. Under Windows 9x, if we
101 were launched from a 16-bit process (which is usually the case;
102 command.com is 16-bit) the parent process should resume right away.
103 Under NT or if launched from a 32-process under 9x, this is a futile
104 gesture as the parent will wait for us to terminate before resuming. */
109 /* Construct the name for a named section (a.k.a. `file mapping') object.
110 The returned string is dynamically allocated and needs to be xfree()'d. */
112 make_section_name (DWORD pid)
114 return aprintf ("gnu_wget_fake_fork_%lu", pid);
117 /* This structure is used to hold all the data that is exchanged between
119 struct fake_fork_info
122 bool logfile_changed;
123 char lfilename[MAX_PATH + 1];
126 /* Determines if we are the child and if so performs the child logic.
133 fake_fork_child (void)
135 HANDLE section, event;
136 struct fake_fork_info *info;
139 name = make_section_name (GetCurrentProcessId ());
140 section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name);
142 /* It seems that Windows 9x and NT set last-error inconsistently when
143 OpenFileMapping() fails; so we assume it failed because the section
144 object does not exist. */
146 return 0; /* We are the parent. */
148 info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
151 CloseHandle (section);
157 info->logfile_changed = false;
160 /* See utils:fork_to_background for explanation. */
161 FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename);
164 info->logfile_changed = true;
165 strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
166 info->lfilename[sizeof (info->lfilename) - 1] = '\0';
171 UnmapViewOfFile (info);
172 CloseHandle (section);
174 /* Inform the parent that we've done our part. */
175 if (!SetEvent (event))
179 return 1; /* We are the child. */
182 /* Windows doesn't support the fork() call; so we fake it by invoking
183 another copy of Wget with the same arguments with which we were
184 invoked. The child copy of Wget should perform the same initialization
185 sequence as the parent; so we should have two processes that are
186 essentially identical. We create a specially named section object that
187 allows the child to distinguish itself from the parent and is used to
188 exchange information between the two processes. We use an event object
189 for synchronization. */
193 char exe[MAX_PATH + 1];
195 SECURITY_ATTRIBUTES sa;
196 HANDLE section, event, h[2];
198 PROCESS_INFORMATION pi;
199 struct fake_fork_info *info;
203 section = pi.hProcess = pi.hThread = NULL;
205 /* Get the fully qualified name of our executable. This is more reliable
206 than using argv[0]. */
207 exe_len = GetModuleFileName (GetModuleHandle (NULL), exe, sizeof (exe));
208 if (!exe_len || (exe_len >= sizeof (exe)))
211 sa.nLength = sizeof (sa);
212 sa.lpSecurityDescriptor = NULL;
213 sa.bInheritHandle = TRUE;
215 /* Create an anonymous inheritable event object that starts out
217 event = CreateEvent (&sa, FALSE, FALSE, NULL);
221 /* Create the child process detached form the current console and in a
225 rv = CreateProcess (exe, GetCommandLine (), NULL, NULL, TRUE,
226 CREATE_SUSPENDED | DETACHED_PROCESS,
227 NULL, NULL, &si, &pi);
231 /* Create a named section object with a name based on the process id of
233 name = make_section_name (pi.dwProcessId);
235 CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
236 sizeof (struct fake_fork_info), name);
239 /* Fail if the section object already exists (should not happen). */
240 if (!section || (le == ERROR_ALREADY_EXISTS))
246 /* Copy the event handle into the section object. */
247 info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
256 UnmapViewOfFile (info);
258 /* Start the child process. */
259 rv = ResumeThread (pi.hThread);
262 TerminateProcess (pi.hProcess, (DWORD) -1);
266 /* Wait for the child to signal to us that it has done its part. If it
267 terminates before signaling us it's an error. */
271 rv = WAIT_OBJECT_0 == WaitForMultipleObjects (2, h, FALSE, 5 * 60 * 1000);
275 info = MapViewOfFile (section, FILE_MAP_READ, 0, 0, 0);
282 /* Ensure string is properly terminated. */
283 if (info->logfile_changed &&
284 !memchr (info->lfilename, '\0', sizeof (info->lfilename)))
290 printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
291 if (info->logfile_changed)
292 printf (_("Output will be written to `%s'.\n"), info->lfilename);
294 UnmapViewOfFile (info);
301 CloseHandle (section);
303 CloseHandle (pi.hThread);
305 CloseHandle (pi.hProcess);
307 /* We're the parent. If all is well, terminate. */
311 /* We failed, return. */
314 /* This is the corresponding Windows implementation of the
315 fork_to_background() function in utils.c. */
317 fork_to_background (void)
321 rv = fake_fork_child ();
324 fprintf (stderr, "fake_fork_child() failed\n");
329 /* We're the parent. */
331 /* If fake_fork() returns, it failed. */
332 fprintf (stderr, "fake_fork() failed\n");
335 /* If we get here, we're the child. */
339 ws_handler (DWORD dwEvent)
345 ws_hangup ("CTRL+C");
348 #ifdef CTRLBREAK_BACKGND
349 case CTRL_BREAK_EVENT:
350 ws_hangup ("CTRL+Break");
358 static char *title_buf = NULL;
359 static char *curr_url = NULL;
360 static int old_percentage = -1;
362 /* Updates the console title with the URL of the current file being
365 ws_changetitle (const char *url)
367 xfree_null (title_buf);
368 xfree_null (curr_url);
369 title_buf = xmalloc (strlen (url) + 20);
370 curr_url = xstrdup (url);
372 sprintf (title_buf, "Wget %s", curr_url);
373 SetConsoleTitle (title_buf);
376 /* Updates the console title with the percentage of the current file
379 ws_percenttitle (double percentage_float)
383 if (!title_buf || !curr_url)
386 percentage = (int) percentage_float;
388 /* Clamp percentage value. */
391 if (percentage > 100)
394 /* Only update the title when the percentage has changed. */
395 if (percentage == old_percentage)
398 old_percentage = percentage;
400 sprintf (title_buf, "Wget [%d%%] %s", percentage, curr_url);
401 SetConsoleTitle (title_buf);
404 /* Returns a pointer to the fully qualified name of the directory that
405 contains the Wget binary (wget.exe). The returned path does not have a
406 trailing path separator. Returns NULL on failure. */
410 static char *wspathsave = NULL;
414 char buf[MAX_PATH + 1];
418 len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
419 if (!len || (len >= sizeof (buf)))
422 p = strrchr (buf, PATH_SEPARATOR);
427 wspathsave = xstrdup (buf);
433 /* Prevent Windows entering sleep/hibernation-mode while Wget is doing
434 a lengthy transfer. Windows does not, by default, consider network
435 activity in console-programs as activity! Works on Win-98/ME/2K
438 set_sleep_mode (void)
440 typedef DWORD (WINAPI *func_t) (DWORD);
441 func_t set_exec_state;
444 (func_t) GetProcAddress (GetModuleHandle ("KERNEL32.DLL"),
445 "SetThreadExecutionState");
448 set_exec_state (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
451 /* Perform Windows specific initialization. */
456 WORD requested = MAKEWORD (1, 1);
457 int err = WSAStartup (requested, &data);
460 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
465 if (data.wVersion < requested)
467 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
475 SetConsoleCtrlHandler (ws_handler, TRUE);
478 /* run_with_timeout Windows implementation. */
480 /* Stack size 0 uses default thread stack-size (reserve+commit).
481 Determined by what's in the PE header. */
482 #define THREAD_STACK_SIZE 0
486 void (*fun) (void *);
491 /* The callback that runs FUN(ARG) in a separate thread. This
492 function exists for two reasons: a) to not require FUN to be
493 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
494 which are per-thread. The latter is useful when FUN calls Winsock
495 functions, which is how run_with_timeout is used in Wget.
497 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
498 the default (wcc386 -3r). */
501 thread_helper (void *arg)
503 struct thread_data *td = (struct thread_data *) arg;
505 /* Initialize Winsock error to what it was in the parent. That way
506 the subsequent call to WSAGetLastError will return the same value
507 if td->fun doesn't change Winsock error state. */
508 WSASetLastError (td->ws_error);
512 /* Return Winsock error to the caller, in case FUN ran Winsock
514 td->ws_error = WSAGetLastError ();
518 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
519 seconds. Returns true if the function was interrupted with a
520 timeout, false otherwise.
522 This works by running FUN in a separate thread and terminating the
523 thread if it doesn't finish in the specified time. */
526 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
529 struct thread_data thread_arg;
533 DEBUGP (("seconds %.2f, ", seconds));
542 thread_arg.fun = fun;
543 thread_arg.arg = arg;
544 thread_arg.ws_error = WSAGetLastError ();
545 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
546 &thread_arg, 0, &thread_id);
549 DEBUGP (("CreateThread() failed; [0x%x]\n", GetLastError ()));
550 goto blocking_fallback;
553 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
556 /* Propagate error state (which is per-thread) to this thread,
557 so the caller can inspect it. */
558 WSASetLastError (thread_arg.ws_error);
559 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
564 TerminateThread (thread_hnd, 1);
568 CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */
573 /* Wget expects network calls such as connect, recv, send, etc., to set
574 errno on failure. To achieve that, Winsock calls are wrapped with code
575 that, in case of error, sets errno to the value of WSAGetLastError().
576 In addition, we provide a wrapper around strerror, which recognizes
577 Winsock errors and prints the appropriate error message. */
579 /* Define a macro that creates a function definition that wraps FUN into
580 a function that sets errno the way the rest of the code expects. */
582 #define WRAP(fun, decl, call) int wrapped_##fun decl { \
583 int retval = fun call; \
585 errno = WSAGetLastError (); \
589 WRAP (socket, (int domain, int type, int protocol), (domain, type, protocol))
590 WRAP (bind, (int s, struct sockaddr *a, int alen), (s, a, alen))
591 WRAP (connect, (int s, const struct sockaddr *a, int alen), (s, a, alen))
592 WRAP (listen, (int s, int backlog), (s, backlog))
593 WRAP (accept, (int s, struct sockaddr *a, int *alen), (s, a, alen))
594 WRAP (recv, (int s, void *buf, int len, int flags), (s, buf, len, flags))
595 WRAP (send, (int s, const void *buf, int len, int flags), (s, buf, len, flags))
596 WRAP (select, (int n, fd_set *r, fd_set *w, fd_set *e, const struct timeval *tm),
598 WRAP (getsockname, (int s, struct sockaddr *n, int *nlen), (s, n, nlen))
599 WRAP (getpeername, (int s, struct sockaddr *n, int *nlen), (s, n, nlen))
600 WRAP (setsockopt, (int s, int level, int opt, const void *val, int len),
601 (s, level, opt, val, len))
602 WRAP (closesocket, (int s), (s))
604 /* Return the text of the error message for Winsock error WSERR. */
607 get_winsock_error (int wserr)
610 case WSAEINTR: return "Interrupted system call";
611 case WSAEBADF: return "Bad file number";
612 case WSAEACCES: return "Permission denied";
613 case WSAEFAULT: return "Bad address";
614 case WSAEINVAL: return "Invalid argument";
615 case WSAEMFILE: return "Too many open files";
616 case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
617 case WSAEINPROGRESS: return "Operation now in progress";
618 case WSAEALREADY: return "Operation already in progress";
619 case WSAENOTSOCK: return "Socket operation on nonsocket";
620 case WSAEDESTADDRREQ: return "Destination address required";
621 case WSAEMSGSIZE: return "Message too long";
622 case WSAEPROTOTYPE: return "Protocol wrong type for socket";
623 case WSAENOPROTOOPT: return "Bad protocol option";
624 case WSAEPROTONOSUPPORT: return "Protocol not supported";
625 case WSAESOCKTNOSUPPORT: return "Socket type not supported";
626 case WSAEOPNOTSUPP: return "Operation not supported";
627 case WSAEPFNOSUPPORT: return "Protocol family not supported";
628 case WSAEAFNOSUPPORT: return "Address family not supported by protocol family";
629 case WSAEADDRINUSE: return "Address already in use";
630 case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
631 case WSAENETDOWN: return "Network is down";
632 case WSAENETUNREACH: return "Network is unreachable";
633 case WSAENETRESET: return "Network dropped connection on reset";
634 case WSAECONNABORTED: return "Software caused connection abort";
635 case WSAECONNRESET: return "Connection reset by peer";
636 case WSAENOBUFS: return "No buffer space available";
637 case WSAEISCONN: return "Socket is already connected";
638 case WSAENOTCONN: return "Socket is not connected";
639 case WSAESHUTDOWN: return "Cannot send after socket shutdown";
640 case WSAETOOMANYREFS: return "Too many references";
641 case WSAETIMEDOUT: return "Connection timed out";
642 case WSAECONNREFUSED: return "Connection refused";
643 case WSAELOOP: return "Too many levels of symbolic links";
644 case WSAENAMETOOLONG: return "File name too long";
645 case WSAEHOSTDOWN: return "Host is down";
646 case WSAEHOSTUNREACH: return "No route to host";
647 case WSAENOTEMPTY: return "Not empty";
648 case WSAEPROCLIM: return "Too many processes";
649 case WSAEUSERS: return "Too many users";
650 case WSAEDQUOT: return "Bad quota";
651 case WSAESTALE: return "Something is stale";
652 case WSAEREMOTE: return "Remote error";
653 case WSAEDISCON: return "Disconnected";
655 /* Extended Winsock errors */
656 case WSASYSNOTREADY: return "Winsock library is not ready";
657 case WSANOTINITIALISED: return "Winsock library not initalised";
658 case WSAVERNOTSUPPORTED: return "Winsock version not supported";
660 case WSAHOST_NOT_FOUND: return "Host not found";
661 case WSATRY_AGAIN: return "Host not found, try again";
662 case WSANO_RECOVERY: return "Unrecoverable error in call to nameserver";
663 case WSANO_DATA: return "No data record of requested type";
670 /* Return the error message corresponding to ERR. This is different
671 from Windows libc strerror() in that it handles Winsock errors
675 windows_strerror (int err)
678 if (err >= 0 && err < sys_nerr)
679 return strerror (err);
680 else if ((p = get_winsock_error (err)) != NULL)
685 snprintf (buf, sizeof (buf), "Unknown error %d (%#x)", err, err);
691 /* An inet_ntop implementation that uses WSAAddressToString.
692 Prototype complies with POSIX 1003.1-2004. This is only used under
693 IPv6 because Wget prints IPv4 addresses using inet_ntoa. */
696 inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
698 /* struct sockaddr can't accomodate struct sockaddr_in6. */
700 struct sockaddr_in6 sin6;
701 struct sockaddr_in sin;
710 sa.sin.sin_family = AF_INET;
711 sa.sin.sin_addr = *(struct in_addr *) src;
712 srcsize = sizeof (sa.sin);
715 sa.sin6.sin6_family = AF_INET6;
716 sa.sin6.sin6_addr = *(struct in6_addr *) src;
717 srcsize = sizeof (sa.sin6);
723 if (WSAAddressToString ((struct sockaddr *) &sa, srcsize, NULL, dst, &dstlen) != 0)
725 errno = WSAGetLastError();
728 return (const char *) dst;