📄 compat.c
字号:
ent = gethostbyname(name);
#ifdef MS_WINDOWS
err = WSAGetLastError();
#else
err = h_errno;
#endif
#endif /* endif HAVE_GETHOSTBYNAME_R_6_ARG. */
if (ent) {
addr->family = ent->h_addrtype;
if (ent->h_addrtype == AF_INET) {
memcpy(&addr->addr.in_addr, ent->h_addr, sizeof(struct in_addr));
} else if (ent->h_addrtype == AF_INET6) {
memcpy(&addr->addr.in6_addr, ent->h_addr, sizeof(struct in6_addr));
} else {
tor_assert(0); /* gethostbyname() returned a bizarre addrtype */
}
return 0;
}
#ifdef MS_WINDOWS
return (err == WSATRY_AGAIN) ? 1 : -1;
#else
return (err == TRY_AGAIN) ? 1 : -1;
#endif
#endif
}
}
/** Hold the result of our call to <b>uname</b>. */
static char uname_result[256];
/** True iff uname_result is set. */
static int uname_result_is_set = 0;
/** Return a pointer to a description of our platform.
*/
const char *
get_uname(void)
{
#ifdef HAVE_UNAME
struct utsname u;
#endif
if (!uname_result_is_set) {
#ifdef HAVE_UNAME
if (uname(&u) != -1) {
/* (linux says 0 is success, solaris says 1 is success) */
tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
u.sysname, u.machine);
} else
#endif
{
#ifdef MS_WINDOWS
OSVERSIONINFOEX info;
int i;
unsigned int leftover_mask;
const char *plat = NULL;
const char *extra = NULL;
static struct {
unsigned major; unsigned minor; const char *version;
} win_version_table[] = {
{ 6, 0, "Windows \"Longhorn\"" },
{ 5, 2, "Windows Server 2003" },
{ 5, 1, "Windows XP" },
{ 5, 0, "Windows 2000" },
/* { 4, 0, "Windows NT 4.0" }, */
{ 4, 90, "Windows Me" },
{ 4, 10, "Windows 98" },
/* { 4, 0, "Windows 95" } */
{ 3, 51, "Windows NT 3.51" },
{ 0, 0, NULL }
};
#ifdef VER_SUITE_BACKOFFICE
static struct {
unsigned int mask; const char *str;
} win_mask_table[] = {
{ VER_SUITE_BACKOFFICE, " {backoffice}" },
{ VER_SUITE_BLADE, " {\"blade\" (2003, web edition)}" },
{ VER_SUITE_DATACENTER, " {datacenter}" },
{ VER_SUITE_ENTERPRISE, " {enterprise}" },
{ VER_SUITE_EMBEDDEDNT, " {embedded}" },
{ VER_SUITE_PERSONAL, " {personal}" },
{ VER_SUITE_SINGLEUSERTS,
" {terminal services, single user}" },
{ VER_SUITE_SMALLBUSINESS, " {small business}" },
{ VER_SUITE_SMALLBUSINESS_RESTRICTED,
" {small business, restricted}" },
{ VER_SUITE_TERMINAL, " {terminal services}" },
{ 0, NULL },
};
#endif
memset(&info, 0, sizeof(info));
info.dwOSVersionInfoSize = sizeof(info);
if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx"
" doesn't work.", sizeof(uname_result));
uname_result_is_set = 1;
return uname_result;
}
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
plat = "Windows NT 4.0";
else
plat = "Windows 95";
if (info.szCSDVersion[1] == 'B')
extra = "OSR2 (B)";
else if (info.szCSDVersion[1] == 'C')
extra = "OSR2 (C)";
} else {
for (i=0; win_version_table[i].major>0; ++i) {
if (win_version_table[i].major == info.dwMajorVersion &&
win_version_table[i].minor == info.dwMinorVersion) {
plat = win_version_table[i].version;
break;
}
}
}
if (plat && !strcmp(plat, "Windows 98")) {
if (info.szCSDVersion[1] == 'A')
extra = "SE (A)";
else if (info.szCSDVersion[1] == 'B')
extra = "SE (B)";
}
if (plat) {
if (!extra)
extra = info.szCSDVersion;
tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
plat, extra);
} else {
if (info.dwMajorVersion > 6 ||
(info.dwMajorVersion==6 && info.dwMinorVersion>0))
tor_snprintf(uname_result, sizeof(uname_result),
"Very recent version of Windows [major=%d,minor=%d] %s",
(int)info.dwMajorVersion,(int)info.dwMinorVersion,
info.szCSDVersion);
else
tor_snprintf(uname_result, sizeof(uname_result),
"Unrecognized version of Windows [major=%d,minor=%d] %s",
(int)info.dwMajorVersion,(int)info.dwMinorVersion,
info.szCSDVersion);
}
#ifdef VER_SUITE_BACKOFFICE
if (info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
strlcat(uname_result, " [domain controller]", sizeof(uname_result));
} else if (info.wProductType == VER_NT_SERVER) {
strlcat(uname_result, " [server]", sizeof(uname_result));
} else if (info.wProductType == VER_NT_WORKSTATION) {
strlcat(uname_result, " [workstation]", sizeof(uname_result));
}
leftover_mask = info.wSuiteMask;
for (i = 0; win_mask_table[i].mask; ++i) {
if (info.wSuiteMask & win_mask_table[i].mask) {
strlcat(uname_result, win_mask_table[i].str, sizeof(uname_result));
leftover_mask &= ~win_mask_table[i].mask;
}
}
if (leftover_mask) {
size_t len = strlen(uname_result);
tor_snprintf(uname_result+len, sizeof(uname_result)-len,
" {0x%x}", info.wSuiteMask);
}
#endif
#else
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
#endif
}
uname_result_is_set = 1;
}
return uname_result;
}
/*
* Process control
*/
#if defined(USE_PTHREADS)
/** Wraps a void (*)(void*) function and its argument so we can
* invoke them in a way pthreads would expect.
*/
typedef struct tor_pthread_data_t {
void (*func)(void *);
void *data;
} tor_pthread_data_t;
/** Given a tor_pthread_data_t <b>_data</b>, call _data->func(d->data)
* and free _data. Used to make sure we can call functions the way pthread
* expects. */
static void *
tor_pthread_helper_fn(void *_data)
{
tor_pthread_data_t *data = _data;
void (*func)(void*);
void *arg;
/* mask signals to worker threads to avoid SIGPIPE, etc */
sigset_t sigs;
/* We're in a subthread; don't handle any signals here. */
sigfillset(&sigs);
pthread_sigmask(SIG_SETMASK, &sigs, NULL);
func = data->func;
arg = data->data;
tor_free(_data);
func(arg);
return NULL;
}
#endif
/** Minimalist interface to run a void function in the background. On
* unix calls fork, on win32 calls beginthread. Returns -1 on failure.
* func should not return, but rather should call spawn_exit.
*
* NOTE: if <b>data</b> is used, it should not be allocated on the stack,
* since in a multithreaded environment, there is no way to be sure that
* the caller's stack will still be around when the called function is
* running.
*/
int
spawn_func(void (*func)(void *), void *data)
{
#if defined(USE_WIN32_THREADS)
int rv;
rv = (int)_beginthread(func, 0, data);
if (rv == (int)-1)
return -1;
return 0;
#elif defined(USE_PTHREADS)
pthread_t thread;
tor_pthread_data_t *d;
d = tor_malloc(sizeof(tor_pthread_data_t));
d->data = data;
d->func = func;
if (pthread_create(&thread,NULL,tor_pthread_helper_fn,d))
return -1;
if (pthread_detach(thread))
return -1;
return 0;
#else
pid_t pid;
pid = fork();
if (pid<0)
return -1;
if (pid==0) {
/* Child */
func(data);
tor_assert(0); /* Should never reach here. */
return 0; /* suppress "control-reaches-end-of-non-void" warning. */
} else {
/* Parent */
return 0;
}
#endif
}
/** End the current thread/process.
*/
void
spawn_exit(void)
{
#if defined(USE_WIN32_THREADS)
_endthread();
//we should never get here. my compiler thinks that _endthread returns, this
//is an attempt to fool it.
tor_assert(0);
_exit(0);
#elif defined(USE_PTHREADS)
pthread_exit(NULL);
#else
/* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should
* call _exit, not exit, from child processes. */
_exit(0);
#endif
}
/** Set *timeval to the current time of day. On error, log and terminate.
* (Same as gettimeofday(timeval,NULL), but never returns -1.)
*/
void
tor_gettimeofday(struct timeval *timeval)
{
#ifdef MS_WINDOWS
/* Epoch bias copied from perl: number of units between windows epoch and
* unix epoch. */
#define EPOCH_BIAS U64_LITERAL(116444736000000000)
#define UNITS_PER_SEC U64_LITERAL(10000000)
#define USEC_PER_SEC U64_LITERAL(1000000)
#define UNITS_PER_USEC U64_LITERAL(10)
union {
uint64_t ft_64;
FILETIME ft_ft;
} ft;
/* number of 100-nsec units since Jan 1, 1601 */
GetSystemTimeAsFileTime(&ft.ft_ft);
if (ft.ft_64 < EPOCH_BIAS) {
log_err(LD_GENERAL,"System time is before 1970; failing.");
exit(1);
}
ft.ft_64 -= EPOCH_BIAS;
timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC);
timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC);
#elif defined(HAVE_GETTIMEOFDAY)
if (gettimeofday(timeval, NULL)) {
log_err(LD_GENERAL,"gettimeofday failed.");
/* If gettimeofday dies, we have either given a bad timezone (we didn't),
or segfaulted.*/
exit(1);
}
#elif defined(HAVE_FTIME)
struct timeb tb;
ftime(&tb);
timeval->tv_sec = tb.time;
timeval->tv_usec = tb.millitm * 1000;
#else
#error "No way to get time."
#endif
return;
}
#if defined(TOR_IS_MULTITHREADED) && !defined(MS_WINDOWS)
/** Defined iff we need to add locks when defining fake versions of reentrant
* versions of time-related functions. */
#define TIME_FNS_NEED_LOCKS
#endif
#ifndef HAVE_LOCALTIME_R
#ifdef TIME_FNS_NEED_LOCKS
struct tm *
tor_localtime_r(const time_t *timep, struct tm *result)
{
struct tm *r;
static tor_mutex_t *m=NULL;
if (!m) { m=tor_mutex_new(); }
tor_assert(result);
tor_mutex_acquire(m);
r = localtime(timep);
memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
return result;
}
#else
struct tm *
tor_localtime_r(const time_t *timep, struct tm *result)
{
struct tm *r;
tor_assert(result);
r = localtime(timep);
memcpy(result, r, sizeof(struct tm));
return result;
}
#endif
#endif
#ifndef HAVE_GMTIME_R
#ifdef TIME_FNS_NEED_LOCKS
struct tm *
tor_gmtime_r(const time_t *timep, struct tm *result)
{
struct tm *r;
static tor_mutex_t *m=NULL;
if (!m) { m=tor_mutex_new(); }
tor_assert(result);
tor_mutex_acquire(m);
r = gmtime(timep);
memcpy(result, r, sizeof(struct tm));
tor_mutex_release(m);
return result;
}
#else
struct tm *
tor_gmtime_r(const time_t *timep, struct tm *result)
{
struct tm *r;
tor_assert(result);
r = gmtime(timep);
memcpy(result, r, sizeof(struct tm));
return result;
}
#endif
#endif
#if defined(USE_WIN32_THREADS) && 0
/** A generic lock structure for multithreaded builds. */
struct tor_mutex_t {
HANDLE handle;
};
tor_mutex_t *
tor_mutex_new(void)
{
tor_mutex_t *m;
m = tor_malloc_zero(sizeof(tor_mutex_t));
m->handle = CreateMutex(NULL, FALSE, NULL);
tor_assert(m->handle != NULL);
return m;
}
void
tor_mutex_free(tor_mutex_t *m)
{
CloseHandle(m->handle);
tor_free(m);
}
void
tor_mutex_acquire(tor_mutex_t *m)
{
DWORD r;
r = WaitForSingleObject(m->handle, INFINITE);
switch (r) {
case WAIT_ABANDONED: /* holding thread exited. */
case WAIT_OBJECT_0: /* we got the mutex normally. */
break;
case WAIT_TIMEOUT: /* Should never happen. */
tor_assert(0);
break;
case WAIT_FAILED:
log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError());
}
}
void
tor_mutex_release(tor_mutex_t *m)
{
BOOL r;
r = ReleaseMutex(m->handle);
if (!r) {
log_warn(LD_GENERAL, "Failed to release mutex: %d", (int) GetLastError());
}
}
unsigned long
tor_get_thread_id(void)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -