1999-12-02 02:42:23 -05:00
|
|
|
|
/* mswindows.c -- Windows-specific support
|
|
|
|
|
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
|
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
|
This file is part of GNU Wget.
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
|
GNU Wget is free software; you can redistribute it and/or modify
|
1999-12-02 02:42:23 -05:00
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
|
GNU Wget is distributed in the hope that it will be useful,
|
1999-12-02 02:42:23 -05:00
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
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
|
2001-05-27 15:35:15 -04:00
|
|
|
|
along with Wget; if not, write to the Free Software
|
2002-05-17 22:16:36 -04:00
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
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. */
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2001-04-03 14:22:04 -04:00
|
|
|
|
/* #### Someone please document what these functions do! */
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <assert.h>
|
2000-12-17 13:12:02 -05:00
|
|
|
|
#include <errno.h>
|
2003-09-30 17:24:36 -04:00
|
|
|
|
#include <math.h>
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2002-04-09 14:29:54 -04:00
|
|
|
|
#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
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#include "wget.h"
|
2002-03-20 13:56:45 -05:00
|
|
|
|
#include "utils.h"
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#include "url.h"
|
|
|
|
|
|
2000-12-17 13:12:02 -05:00
|
|
|
|
#ifndef errno
|
|
|
|
|
extern int errno;
|
|
|
|
|
#endif
|
|
|
|
|
|
2003-09-26 20:35:31 -04:00
|
|
|
|
#ifndef ES_SYSTEM_REQUIRED
|
|
|
|
|
#define ES_SYSTEM_REQUIRED 0x00000001
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef ES_CONTINUOUS
|
|
|
|
|
#define ES_CONTINUOUS 0x80000000
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Defined in log.c. */
|
2001-12-10 00:31:45 -05:00
|
|
|
|
void log_request_redirect_output PARAMS ((const char *));
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2003-09-26 20:35:31 -04:00
|
|
|
|
static DWORD set_sleep_mode (DWORD mode);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2003-09-26 20:35:31 -04:00
|
|
|
|
static DWORD pwr_mode = 0;
|
|
|
|
|
static int windows_nt_p;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2003-09-25 18:39:37 -04:00
|
|
|
|
#ifndef HAVE_SLEEP
|
2003-09-26 20:35:31 -04:00
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Emulation of Unix sleep. */
|
2001-11-29 09:15:11 -05:00
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
unsigned int
|
|
|
|
|
sleep (unsigned seconds)
|
|
|
|
|
{
|
2001-04-03 14:22:04 -04:00
|
|
|
|
return SleepEx (1000 * seconds, TRUE) ? 0U : 1000 * seconds;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
2003-09-25 18:39:37 -04:00
|
|
|
|
#endif
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2003-09-25 18:39:37 -04:00
|
|
|
|
#ifndef HAVE_USLEEP
|
2001-11-29 09:15:11 -05:00
|
|
|
|
/* Emulation of Unix usleep(). This has a granularity of
|
|
|
|
|
milliseconds, but that's ok because:
|
|
|
|
|
|
2003-09-20 19:12:18 -04:00
|
|
|
|
a) Wget is only using it with milliseconds [not anymore, but b)
|
|
|
|
|
still applies];
|
2001-11-29 09:15:11 -05:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
SleepEx (usec / 1000, TRUE);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-09-25 18:39:37 -04:00
|
|
|
|
#endif /* HAVE_USLEEP */
|
2001-11-29 09:15:11 -05:00
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
void
|
|
|
|
|
windows_main_junk (int *argc, char **argv, char **exec_name)
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
|
|
/* Remove .EXE from filename if it has one. */
|
|
|
|
|
*exec_name = xstrdup (*exec_name);
|
|
|
|
|
p = strrchr (*exec_name, '.');
|
|
|
|
|
if (p)
|
|
|
|
|
*p = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Winsock stuff. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ws_cleanup (void)
|
|
|
|
|
{
|
|
|
|
|
WSACleanup ();
|
2003-09-26 20:35:31 -04:00
|
|
|
|
if (pwr_mode)
|
|
|
|
|
set_sleep_mode (pwr_mode);
|
|
|
|
|
pwr_mode = 0;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ws_hangup (void)
|
|
|
|
|
{
|
2001-12-10 00:31:45 -05:00
|
|
|
|
log_request_redirect_output ("CTRL+Break");
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fork_to_background (void)
|
|
|
|
|
{
|
|
|
|
|
/* Whether we arrange our own version of opt.lfilename here. */
|
|
|
|
|
int changedp = 0;
|
|
|
|
|
|
|
|
|
|
if (!opt.lfilename)
|
|
|
|
|
{
|
2003-09-16 17:47:49 -04:00
|
|
|
|
opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
changedp = 1;
|
|
|
|
|
}
|
|
|
|
|
printf (_("Continuing in background.\n"));
|
|
|
|
|
if (changedp)
|
|
|
|
|
printf (_("Output will be written to `%s'.\n"), opt.lfilename);
|
|
|
|
|
|
|
|
|
|
ws_hangup ();
|
|
|
|
|
if (!windows_nt_p)
|
|
|
|
|
FreeConsole ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL WINAPI
|
|
|
|
|
ws_handler (DWORD dwEvent)
|
|
|
|
|
{
|
|
|
|
|
switch (dwEvent)
|
|
|
|
|
{
|
|
|
|
|
#ifdef CTRLC_BACKGND
|
|
|
|
|
case CTRL_C_EVENT:
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef CTRLBREAK_BACKGND
|
|
|
|
|
case CTRL_BREAK_EVENT:
|
|
|
|
|
#endif
|
|
|
|
|
fork_to_background ();
|
|
|
|
|
break;
|
|
|
|
|
case CTRL_SHUTDOWN_EVENT:
|
|
|
|
|
case CTRL_CLOSE_EVENT:
|
|
|
|
|
case CTRL_LOGOFF_EVENT:
|
|
|
|
|
default:
|
2003-09-26 20:35:31 -04:00
|
|
|
|
ws_cleanup ();
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-30 17:24:36 -04:00
|
|
|
|
static char *title_buf = NULL;
|
|
|
|
|
static char *curr_url = NULL;
|
|
|
|
|
static int num_urls = 0;
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
void
|
2003-09-30 17:24:36 -04:00
|
|
|
|
ws_changetitle (const char *url, int nurl)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
if (!nurl)
|
|
|
|
|
return;
|
|
|
|
|
|
2003-09-30 17:24:36 -04:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ws_percenttitle (double percent)
|
|
|
|
|
{
|
|
|
|
|
if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
|
|
|
|
|
{
|
2003-10-04 17:54:12 -04:00
|
|
|
|
sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
|
2003-09-30 17:24:36 -04:00
|
|
|
|
SetConsoleTitle (title_buf);
|
|
|
|
|
}
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
ws_mypath (void)
|
|
|
|
|
{
|
2003-09-30 17:24:36 -04:00
|
|
|
|
static char *wspathsave = NULL;
|
2001-04-03 14:22:04 -04:00
|
|
|
|
char buffer[MAX_PATH];
|
1999-12-02 02:42:23 -05:00
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
|
|
if (wspathsave)
|
|
|
|
|
{
|
|
|
|
|
return wspathsave;
|
|
|
|
|
}
|
2001-04-03 14:22:04 -04:00
|
|
|
|
|
2003-09-30 17:24:36 -04:00
|
|
|
|
if (GetModuleFileName (NULL, buffer, MAX_PATH) &&
|
|
|
|
|
(ptr = strrchr (buffer, PATH_SEPARATOR)) != NULL)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
*(ptr + 1) = '\0';
|
2003-09-30 17:24:36 -04:00
|
|
|
|
wspathsave = xstrdup (buffer);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
2001-04-03 14:22:04 -04:00
|
|
|
|
else
|
|
|
|
|
wspathsave = NULL;
|
|
|
|
|
return wspathsave;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ws_help (const char *name)
|
|
|
|
|
{
|
|
|
|
|
char *mypath = ws_mypath ();
|
|
|
|
|
|
|
|
|
|
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);
|
2003-10-04 17:54:12 -04:00
|
|
|
|
WinHelp (NULL, buf, HELP_INDEX, 0);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf ("%s: %s\n", buf, strerror (errno));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (err != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
|
|
|
|
|
exec_name);
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-03 14:22:04 -04:00
|
|
|
|
if (data.wVersion < requested)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
|
|
|
|
|
exec_name);
|
|
|
|
|
WSACleanup ();
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
|
|
|
|
atexit (ws_cleanup);
|
2003-09-26 20:35:31 -04:00
|
|
|
|
pwr_mode = set_sleep_mode (0);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
SetConsoleCtrlHandler (ws_handler, TRUE);
|
|
|
|
|
}
|
2002-04-09 14:29:54 -04:00
|
|
|
|
|
|
|
|
|
/* 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
|
2003-10-05 17:12:36 -04:00
|
|
|
|
int
|
|
|
|
|
borland_utime (const char *path, const struct utimbuf *times)
|
2002-04-09 14:29:54 -04:00
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
int res;
|
|
|
|
|
struct ftime ft;
|
|
|
|
|
struct tm *ptr_tm;
|
|
|
|
|
|
|
|
|
|
if ((fd = open (path, O_RDWR)) < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
ptr_tm = localtime (×->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
|
2003-09-26 20:35:31 -04:00
|
|
|
|
|
|
|
|
|
/*
|
2003-10-07 20:09:56 -04:00
|
|
|
|
* 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.
|
2003-09-26 20:35:31 -04:00
|
|
|
|
*/
|
2003-10-05 17:12:36 -04:00
|
|
|
|
static DWORD
|
|
|
|
|
set_sleep_mode (DWORD mode)
|
2003-09-26 20:35:31 -04:00
|
|
|
|
{
|
|
|
|
|
HMODULE mod = LoadLibrary ("kernel32.dll");
|
2003-10-05 17:12:36 -04:00
|
|
|
|
DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
|
2003-09-26 20:35:31 -04:00
|
|
|
|
DWORD rc = (DWORD)-1;
|
|
|
|
|
|
|
|
|
|
if (mod)
|
2003-10-07 20:09:56 -04:00
|
|
|
|
(void *)_SetThreadExecutionState
|
|
|
|
|
= GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
|
2003-09-26 20:35:31 -04:00
|
|
|
|
|
|
|
|
|
if (_SetThreadExecutionState)
|
|
|
|
|
{
|
|
|
|
|
if (mode == 0) /* first time */
|
2003-10-05 17:12:36 -04:00
|
|
|
|
mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
|
2003-09-26 20:35:31 -04:00
|
|
|
|
rc = (*_SetThreadExecutionState) (mode);
|
|
|
|
|
}
|
|
|
|
|
if (mod)
|
2003-10-05 17:12:36 -04:00
|
|
|
|
FreeLibrary (mod);
|
2003-09-26 20:35:31 -04:00
|
|
|
|
DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
|
2003-10-05 17:12:36 -04:00
|
|
|
|
return rc;
|
2003-09-26 20:35:31 -04:00
|
|
|
|
}
|
2003-10-02 19:28:49 -04:00
|
|
|
|
|
|
|
|
|
/* run_with_timeout Windows implementation. */
|
|
|
|
|
|
2003-10-04 17:54:12 -04:00
|
|
|
|
/* Stack size 0 uses default thread stack-size (reserve+commit).
|
|
|
|
|
* Determined by what's in the PE header.
|
2003-10-02 19:28:49 -04:00
|
|
|
|
*/
|
2003-10-04 17:54:12 -04:00
|
|
|
|
#define THREAD_STACK_SIZE 0
|
2003-10-02 19:28:49 -04:00
|
|
|
|
|
|
|
|
|
struct thread_data {
|
|
|
|
|
void (*fun) (void *);
|
|
|
|
|
void *arg;
|
|
|
|
|
DWORD ws_error;
|
|
|
|
|
};
|
|
|
|
|
|
2003-10-04 17:54:12 -04:00
|
|
|
|
/* 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). */
|
|
|
|
|
|
2003-10-02 19:28:49 -04:00
|
|
|
|
static DWORD WINAPI
|
|
|
|
|
thread_helper (void *arg)
|
|
|
|
|
{
|
|
|
|
|
struct thread_data *td = (struct thread_data *) arg;
|
2003-10-04 17:54:12 -04:00
|
|
|
|
|
|
|
|
|
/* 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. */
|
2003-10-07 20:09:56 -04:00
|
|
|
|
td->ws_error = WSAGetLastError ();
|
2003-10-04 17:54:12 -04:00
|
|
|
|
return 0;
|
2003-10-02 19:28:49 -04:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-07 20:16:43 -04:00
|
|
|
|
/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
|
|
|
|
|
seconds. Returns non-zero if the function was interrupted with a
|
|
|
|
|
timeout, zero otherwise.
|
|
|
|
|
|
|
|
|
|
This works by running FUN in a separate thread and terminating the
|
|
|
|
|
thread if it doesn't finish in the specified time. */
|
2003-10-02 19:28:49 -04:00
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
run_with_timeout (double seconds, void (*fun) (void *), void *arg)
|
|
|
|
|
{
|
|
|
|
|
static HANDLE thread_hnd = NULL;
|
|
|
|
|
struct thread_data thread_arg;
|
2003-10-04 17:54:12 -04:00
|
|
|
|
DWORD thread_id;
|
|
|
|
|
int rc = 0;
|
2003-10-02 19:28:49 -04:00
|
|
|
|
|
2003-10-04 17:54:12 -04:00
|
|
|
|
DEBUGP (("seconds %.2f, ", seconds));
|
2003-10-02 19:28:49 -04:00
|
|
|
|
|
|
|
|
|
if (seconds == 0)
|
|
|
|
|
{
|
|
|
|
|
blocking_fallback:
|
|
|
|
|
fun (arg);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-09-26 20:35:31 -04:00
|
|
|
|
|
2003-10-02 19:28:49 -04:00
|
|
|
|
/* Should never happen, but test for recursivety anyway */
|
|
|
|
|
assert (thread_hnd == NULL);
|
2003-10-04 17:54:12 -04:00
|
|
|
|
|
2003-10-02 19:28:49 -04:00
|
|
|
|
thread_arg.fun = fun;
|
2003-10-04 17:54:12 -04:00
|
|
|
|
thread_arg.arg = arg;
|
|
|
|
|
thread_arg.ws_error = WSAGetLastError ();
|
|
|
|
|
thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
|
|
|
|
|
&thread_arg, 0, &thread_id);
|
2003-10-02 19:28:49 -04:00
|
|
|
|
if (!thread_hnd)
|
|
|
|
|
{
|
2003-10-07 20:09:56 -04:00
|
|
|
|
DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
|
2003-10-02 19:28:49 -04:00
|
|
|
|
goto blocking_fallback;
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-07 20:09:56 -04:00
|
|
|
|
if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
|
|
|
|
|
== WAIT_OBJECT_0)
|
2003-10-02 19:28:49 -04:00
|
|
|
|
{
|
|
|
|
|
/* Propagate error state (which is per-thread) to this thread,
|
|
|
|
|
so the caller can inspect it. */
|
|
|
|
|
WSASetLastError (thread_arg.ws_error);
|
2003-10-07 20:09:56 -04:00
|
|
|
|
DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
|
2003-10-04 17:54:12 -04:00
|
|
|
|
rc = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TerminateThread (thread_hnd, 1);
|
|
|
|
|
rc = 1;
|
2003-10-02 19:28:49 -04:00
|
|
|
|
}
|
2003-10-04 17:54:12 -04:00
|
|
|
|
|
|
|
|
|
CloseHandle (thread_hnd); /* clear-up after TerminateThread() */
|
2003-10-02 19:28:49 -04:00
|
|
|
|
thread_hnd = NULL;
|
2003-10-04 17:54:12 -04:00
|
|
|
|
return rc;
|
2003-10-02 19:28:49 -04:00
|
|
|
|
}
|