2004-11-01 21:41:47 +01:00
/* Copyright 2003-2004 Roger Dingledine; Copyright 2004 Nick Mathewson */
/* See LICENSE for licensing information */
/* $Id$ */
2004-11-29 23:25:31 +01:00
const char compat_c_id [ ] = " $Id$ " ;
2004-11-01 21:41:47 +01:00
/* This is required on rh7 to make strptime not complain.
*/
# define _GNU_SOURCE
# include "orconfig.h"
2004-11-04 05:01:19 +01:00
# include "compat.h"
2004-11-01 21:41:47 +01:00
# ifdef MS_WINDOWS
# include <process.h>
# endif
# ifdef HAVE_UNAME
# include <sys/utsname.h>
# endif
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
# ifdef HAVE_SYS_FCNTL_H
# include <sys/fcntl.h>
# endif
# ifdef HAVE_PWD_H
# include <pwd.h>
# endif
# ifdef HAVE_GRP_H
# include <grp.h>
# endif
# ifdef HAVE_FCNTL_H
# include <fcntl.h>
# endif
# ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
# endif
# ifdef HAVE_ERRNO_H
# include <errno.h>
# endif
# ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
# endif
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
# endif
# ifndef HAVE_GETTIMEOFDAY
# ifdef HAVE_FTIME
# include <sys/timeb.h>
# endif
# endif
# ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
# endif
2004-12-22 06:29:06 +01:00
# ifdef HAVE_NETDB_H
# include <netdb.h>
# endif
2004-11-01 21:41:47 +01:00
# ifdef HAVE_SYS_PARAM_H
# include <sys/param.h> /* FreeBSD needs this to know what version it is */
# endif
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2004-11-03 08:29:03 +01:00
# include <assert.h>
2005-01-27 23:34:48 +01:00
# ifdef HAVE_PTHREAD_H
# include <pthread.h>
# endif
2004-11-01 21:41:47 +01:00
# include "log.h"
# include "util.h"
2004-11-09 02:24:10 +01:00
/* Inline the strl functions if the platform doesn't have them. */
2004-11-02 20:25:52 +01:00
# ifndef HAVE_STRLCPY
# include "strlcpy.c"
# endif
# ifndef HAVE_STRLCAT
# include "strlcat.c"
# endif
2004-12-22 06:29:06 +01:00
/* used by inet_addr, not defined on solaris anywhere!? */
# ifndef INADDR_NONE
# define INADDR_NONE ((unsigned long) -1)
# endif
2004-11-01 21:41:47 +01:00
/** Replacement for snprintf. Differs from platform snprintf in two
* ways : First , always NUL - terminates its output . Second , always
* returns - 1 if the result is truncated . ( Note that this return
* behavior does < i > not < / i > conform to C99 ; it just happens to be the
* easiest to emulate " return -1 " with conformant implementations than
* it is to emulate " return number that would be written " with
* non - conformant implementations . ) */
int tor_snprintf ( char * str , size_t size , const char * format , . . . )
{
va_list ap ;
int r ;
va_start ( ap , format ) ;
r = tor_vsnprintf ( str , size , format , ap ) ;
va_end ( ap ) ;
return r ;
}
2004-11-29 07:49:04 +01:00
/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from
2004-11-01 21:41:47 +01:00
* snprintf .
*/
int tor_vsnprintf ( char * str , size_t size , const char * format , va_list args )
{
int r ;
2004-11-29 07:49:04 +01:00
if ( size = = 0 )
return - 1 ; /* no place for the NUL */
2004-12-02 05:33:01 +01:00
if ( size > SIZE_T_CEILING )
return - 1 ;
2004-11-01 21:41:47 +01:00
# ifdef MS_WINDOWS
r = _vsnprintf ( str , size , format , args ) ;
# else
r = vsnprintf ( str , size , format , args ) ;
# endif
str [ size - 1 ] = ' \0 ' ;
if ( r < 0 | | ( ( size_t ) r ) > = size )
return - 1 ;
return r ;
}
2004-12-22 03:32:26 +01:00
/** Take a filename and return a pointer to its final element. This
* function is called on __FILE__ to fix a MSVC nit where __FILE__
* contains the full path to the file . This is bad , because it
* confuses users to find the home directory of the person who
* compiled the binary in their warrning messages .
*/
const char *
_tor_fix_source_file ( const char * fname )
{
2004-12-22 03:46:28 +01:00
const char * cp1 , * cp2 , * r ;
2004-12-22 03:32:26 +01:00
cp1 = strrchr ( fname , ' / ' ) ;
cp2 = strrchr ( fname , ' \\ ' ) ;
if ( cp1 & & cp2 ) {
2004-12-22 03:46:28 +01:00
r = ( cp1 < cp2 ) ? ( cp2 + 1 ) : ( cp1 + 1 ) ;
2004-12-22 03:32:26 +01:00
} else if ( cp1 ) {
2004-12-22 03:46:28 +01:00
r = cp1 + 1 ;
2004-12-22 03:32:26 +01:00
} else if ( cp2 ) {
2004-12-22 03:46:28 +01:00
r = cp2 + 1 ;
2004-12-22 03:32:26 +01:00
} else {
2004-12-22 03:46:28 +01:00
r = fname ;
2004-12-22 03:32:26 +01:00
}
2004-12-22 03:46:28 +01:00
return r ;
2004-12-22 03:32:26 +01:00
}
2004-11-01 21:41:47 +01:00
# ifndef UNALIGNED_INT_ACCESS_OK
/**
2004-12-01 04:48:14 +01:00
* Read a 16 - bit value beginning at < b > cp < / b > . Equivalent to
2004-11-01 21:41:47 +01:00
* * ( uint16_t * ) ( cp ) , but will not cause segfaults on platforms that forbid
* unaligned memory access .
*/
uint16_t get_uint16 ( const char * cp )
{
uint16_t v ;
memcpy ( & v , cp , 2 ) ;
return v ;
}
/**
2004-12-01 04:48:14 +01:00
* Read a 32 - bit value beginning at < b > cp < / b > . Equivalent to
2004-11-01 21:41:47 +01:00
* * ( uint32_t * ) ( cp ) , but will not cause segfaults on platforms that forbid
* unaligned memory access .
*/
uint32_t get_uint32 ( const char * cp )
{
uint32_t v ;
memcpy ( & v , cp , 4 ) ;
return v ;
}
/**
* Set a 16 - bit value beginning at < b > cp < / b > to < b > v < / b > . Equivalent to
* * ( uint16_t ) ( cp ) = v , but will not cause segfaults on platforms that forbid
* unaligned memory access . */
void set_uint16 ( char * cp , uint16_t v )
{
memcpy ( cp , & v , 2 ) ;
}
/**
* Set a 32 - bit value beginning at < b > cp < / b > to < b > v < / b > . Equivalent to
* * ( uint32_t ) ( cp ) = v , but will not cause segfaults on platforms that forbid
* unaligned memory access . */
void set_uint32 ( char * cp , uint32_t v )
{
memcpy ( cp , & v , 4 ) ;
}
# endif
/**
* Rename the file ' from ' to the file ' to ' . On unix , this is the same as
* rename ( 2 ) . On windows , this removes ' to ' first if it already exists .
* Returns 0 on success . Returns - 1 and sets errno on failure .
*/
int replace_file ( const char * from , const char * to )
{
# ifndef MS_WINDOWS
return rename ( from , to ) ;
# else
2004-11-28 10:05:49 +01:00
switch ( file_status ( to ) )
2004-11-01 21:41:47 +01:00
{
case FN_NOENT :
break ;
case FN_FILE :
if ( unlink ( to ) ) return - 1 ;
break ;
case FN_ERROR :
return - 1 ;
case FN_DIR :
errno = EISDIR ;
return - 1 ;
}
return rename ( from , to ) ;
# endif
}
/** Turn <b>socket</b> into a nonblocking socket.
*/
void set_socket_nonblocking ( int socket )
{
# ifdef MS_WINDOWS
2004-11-28 06:57:18 +01:00
int nonblocking = 1 ;
2004-11-01 21:41:47 +01:00
ioctlsocket ( socket , FIONBIO , ( unsigned long * ) & nonblocking ) ;
# else
fcntl ( socket , F_SETFL , O_NONBLOCK ) ;
# endif
}
/**
* Allocate a pair of connected sockets . ( Like socketpair ( family ,
* type , protocol , fd ) , but works on systems that don ' t have
* socketpair . )
*
* Currently , only ( AF_UNIX , SOCK_STREAM , 0 ) sockets are supported .
*
* Note that on systems without socketpair , this call will fail if
* localhost is inaccessible ( for example , if the networking
* stack is down ) . And even if it succeeds , the socket pair will not
* be able to read while localhost is down later ( the socket pair may
* even close , depending on OS - specific timeouts ) .
* */
int
tor_socketpair ( int family , int type , int protocol , int fd [ 2 ] )
{
# ifdef HAVE_SOCKETPAIR
return socketpair ( family , type , protocol , fd ) ;
# else
/* This socketpair does not work when localhost is down. So
* it ' s really not the same thing at all . But it ' s close enough
* for now , and really , when localhost is down sometimes , we
* have other problems too .
*/
int listener = - 1 ;
int connector = - 1 ;
int acceptor = - 1 ;
struct sockaddr_in listen_addr ;
struct sockaddr_in connect_addr ;
int size ;
if ( protocol
# ifdef AF_UNIX
| | family ! = AF_UNIX
# endif
) {
# ifdef MS_WINDOWS
errno = WSAEAFNOSUPPORT ;
# else
errno = EAFNOSUPPORT ;
# endif
return - 1 ;
}
if ( ! fd ) {
errno = EINVAL ;
return - 1 ;
}
listener = socket ( AF_INET , type , 0 ) ;
if ( listener = = - 1 )
return - 1 ;
2004-12-01 04:15:59 +01:00
if ( ! SOCKET_IS_POLLABLE ( listener ) ) {
log_fn ( LOG_WARN , " Too many connections; can't open socketpair " ) ;
tor_close_socket ( listener ) ;
return - 1 ;
}
2004-11-23 00:28:26 +01:00
memset ( & listen_addr , 0 , sizeof ( listen_addr ) ) ;
2004-11-01 21:41:47 +01:00
listen_addr . sin_family = AF_INET ;
2004-11-23 00:28:26 +01:00
listen_addr . sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
2004-12-01 04:48:14 +01:00
listen_addr . sin_port = 0 ; /* kernel chooses port. */
2004-11-01 21:41:47 +01:00
if ( bind ( listener , ( struct sockaddr * ) & listen_addr , sizeof ( listen_addr ) )
= = - 1 )
goto tidy_up_and_fail ;
if ( listen ( listener , 1 ) = = - 1 )
goto tidy_up_and_fail ;
connector = socket ( AF_INET , type , 0 ) ;
if ( connector = = - 1 )
goto tidy_up_and_fail ;
2004-12-01 04:15:59 +01:00
if ( ! SOCKET_IS_POLLABLE ( connector ) ) {
log_fn ( LOG_WARN , " Too many connections; can't open socketpair " ) ;
goto tidy_up_and_fail ;
}
2004-11-01 21:41:47 +01:00
/* We want to find out the port number to connect to. */
2004-11-23 00:28:26 +01:00
size = sizeof ( connect_addr ) ;
2004-11-01 21:41:47 +01:00
if ( getsockname ( listener , ( struct sockaddr * ) & connect_addr , & size ) = = - 1 )
goto tidy_up_and_fail ;
if ( size ! = sizeof ( connect_addr ) )
goto abort_tidy_up_and_fail ;
if ( connect ( connector , ( struct sockaddr * ) & connect_addr ,
2004-11-23 00:28:26 +01:00
sizeof ( connect_addr ) ) = = - 1 )
2004-11-01 21:41:47 +01:00
goto tidy_up_and_fail ;
2004-11-23 00:28:26 +01:00
size = sizeof ( listen_addr ) ;
2004-11-01 21:41:47 +01:00
acceptor = accept ( listener , ( struct sockaddr * ) & listen_addr , & size ) ;
if ( acceptor = = - 1 )
goto tidy_up_and_fail ;
2004-12-01 04:15:59 +01:00
if ( ! SOCKET_IS_POLLABLE ( acceptor ) ) {
log_fn ( LOG_WARN , " Too many connections; can't open socketpair " ) ;
goto tidy_up_and_fail ;
}
2004-11-01 21:41:47 +01:00
if ( size ! = sizeof ( listen_addr ) )
goto abort_tidy_up_and_fail ;
tor_close_socket ( listener ) ;
/* Now check we are talking to ourself by matching port and host on the
two sockets . */
if ( getsockname ( connector , ( struct sockaddr * ) & connect_addr , & size ) = = - 1 )
goto tidy_up_and_fail ;
if ( size ! = sizeof ( connect_addr )
| | listen_addr . sin_family ! = connect_addr . sin_family
| | listen_addr . sin_addr . s_addr ! = connect_addr . sin_addr . s_addr
| | listen_addr . sin_port ! = connect_addr . sin_port ) {
goto abort_tidy_up_and_fail ;
}
fd [ 0 ] = connector ;
fd [ 1 ] = acceptor ;
2005-01-03 20:07:25 +01:00
2004-11-01 21:41:47 +01:00
return 0 ;
abort_tidy_up_and_fail :
# ifdef MS_WINDOWS
errno = WSAECONNABORTED ;
# else
errno = ECONNABORTED ; /* I hope this is portable and appropriate. */
# endif
tidy_up_and_fail :
{
int save_errno = errno ;
if ( listener ! = - 1 )
tor_close_socket ( listener ) ;
if ( connector ! = - 1 )
tor_close_socket ( connector ) ;
if ( acceptor ! = - 1 )
tor_close_socket ( acceptor ) ;
errno = save_errno ;
return - 1 ;
}
# endif
}
/** Get the maximum allowed number of file descriptors. (Some systems
* have a low soft limit . ) Make sure we set it to at least
* < b > required_min < / b > . Return 0 if we can , or - 1 if we fail . */
2004-11-01 23:41:32 +01:00
int set_max_file_descriptors ( unsigned int required_min ) {
2004-11-01 21:41:47 +01:00
# ifndef HAVE_GETRLIMIT
log_fn ( LOG_INFO , " This platform is missing getrlimit(). Proceeding. " ) ;
return 0 ; /* hope we'll be ok */
# else
struct rlimit rlim ;
if ( getrlimit ( RLIMIT_NOFILE , & rlim ) ! = 0 ) {
log_fn ( LOG_WARN , " Could not get maximum number of file descriptors: %s " ,
strerror ( errno ) ) ;
return - 1 ;
}
2004-11-28 10:05:49 +01:00
if ( required_min > rlim . rlim_max ) {
2004-11-10 10:09:15 +01:00
log_fn ( LOG_WARN , " We need %u file descriptors available, and we're limited to %lu. Please change your ulimit. " , required_min , ( unsigned long int ) rlim . rlim_max ) ;
2004-11-01 21:41:47 +01:00
return - 1 ;
}
2004-11-28 10:05:49 +01:00
if ( required_min > rlim . rlim_cur ) {
2004-11-10 10:09:15 +01:00
log_fn ( LOG_INFO , " Raising max file descriptors from %lu to %lu. " ,
( unsigned long int ) rlim . rlim_cur , ( unsigned long int ) rlim . rlim_max ) ;
2004-11-01 21:41:47 +01:00
}
rlim . rlim_cur = rlim . rlim_max ;
if ( setrlimit ( RLIMIT_NOFILE , & rlim ) ! = 0 ) {
log_fn ( LOG_WARN , " Could not set maximum number of file descriptors: %s " ,
strerror ( errno ) ) ;
return - 1 ;
}
return 0 ;
# endif
}
/** Call setuid and setgid to run as <b>user</b>:<b>group</b>. Return 0 on
* success . On failure , log and return - 1.
*/
int switch_id ( char * user , char * group ) {
# ifndef MS_WINDOWS
struct passwd * pw = NULL ;
struct group * gr = NULL ;
if ( user ) {
pw = getpwnam ( user ) ;
if ( pw = = NULL ) {
log_fn ( LOG_ERR , " User '%s' not found. " , user ) ;
return - 1 ;
}
}
/* switch the group first, while we still have the privileges to do so */
if ( group ) {
gr = getgrnam ( group ) ;
if ( gr = = NULL ) {
log_fn ( LOG_ERR , " Group '%s' not found. " , group ) ;
return - 1 ;
}
if ( setgid ( gr - > gr_gid ) ! = 0 ) {
log_fn ( LOG_ERR , " Error setting GID: %s " , strerror ( errno ) ) ;
return - 1 ;
}
} else if ( user ) {
if ( setgid ( pw - > pw_gid ) ! = 0 ) {
log_fn ( LOG_ERR , " Error setting GID: %s " , strerror ( errno ) ) ;
return - 1 ;
}
}
/* now that the group is switched, we can switch users and lose
privileges */
if ( user ) {
if ( setuid ( pw - > pw_uid ) ! = 0 ) {
log_fn ( LOG_ERR , " Error setting UID: %s " , strerror ( errno ) ) ;
return - 1 ;
}
}
return 0 ;
# endif
log_fn ( LOG_ERR ,
" User or group specified, but switching users is not supported. " ) ;
return - 1 ;
}
2004-11-10 15:23:31 +01:00
# ifdef HAVE_PWD_H
/** Allocate and return a string containing the home directory for the
* user < b > username < / b > . Only works on posix - like systems */
char *
get_user_homedir ( const char * username )
{
struct passwd * pw ;
tor_assert ( username ) ;
if ( ! ( pw = getpwnam ( username ) ) ) {
log_fn ( LOG_ERR , " User '%s' not found. " , username ) ;
return NULL ;
}
return tor_strdup ( pw - > pw_dir ) ;
}
# endif
2004-11-01 21:41:47 +01:00
/** Set *addr to the IP address (in dotted-quad notation) stored in c.
* Return 1 on success , 0 if c is badly formatted . ( Like inet_aton ( c , addr ) ,
* but works on Windows and Solaris . )
*/
int tor_inet_aton ( const char * c , struct in_addr * addr )
{
# ifdef HAVE_INET_ATON
return inet_aton ( c , addr ) ;
# else
uint32_t r ;
tor_assert ( c ) ;
tor_assert ( addr ) ;
if ( strcmp ( c , " 255.255.255.255 " ) = = 0 ) {
addr - > s_addr = 0xFFFFFFFFu ;
return 1 ;
}
r = inet_addr ( c ) ;
if ( r = = INADDR_NONE )
return 0 ;
addr - > s_addr = r ;
return 1 ;
# endif
}
2004-12-22 06:29:06 +01:00
/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set
* * addr to the proper IP address , in network byte order . Returns 0
* on success , - 1 on failure ; 1 on transient failure .
*
* ( This function exists because standard windows gethostbyname
* doesn ' t treat raw IP addresses properly . )
*/
int tor_lookup_hostname ( const char * name , uint32_t * addr )
{
/* Perhaps eventually this should be replaced by a tor_getaddrinfo or
* something .
*/
struct in_addr iaddr ;
struct hostent * ent ;
tor_assert ( addr ) ;
if ( ! * name ) {
/* Empty address is an error. */
return - 1 ;
} else if ( tor_inet_aton ( name , & iaddr ) ) {
/* It's an IP. */
memcpy ( addr , & iaddr . s_addr , 4 ) ;
return 0 ;
} else {
ent = gethostbyname ( name ) ;
if ( ent ) {
/* break to remind us if we move away from IPv4 */
tor_assert ( ent - > h_length = = 4 ) ;
memcpy ( addr , ent - > h_addr , 4 ) ;
return 0 ;
}
memset ( addr , 0 , 4 ) ;
# ifdef MS_WINDOWS
return ( WSAGetLastError ( ) = = WSATRY_AGAIN ) ? 1 : - 1 ;
# else
return ( h_errno = = TRY_AGAIN ) ? 1 : - 1 ;
# endif
}
}
2004-11-01 21:41:47 +01:00
/* 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 %s " ,
u . sysname , u . nodename , u . machine ) ;
} else
# endif
{
2005-01-20 00:10:16 +01:00
# ifdef MS_WINDOWS
OSVERSIONINFO info ;
int i ;
const char * plat = NULL ;
static struct {
int major ; int minor ; const char * version ;
} win_version_table [ ] = {
{ 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 " } ,
{ - 1 , - 1 , NULL }
} ;
info . dwOSVersionInfoSize = sizeof ( info ) ;
GetVersionEx ( & info ) ;
if ( info . dwMajorVersion = = 4 & & info . dwMinorVersion = = 0 ) {
if ( info . dwPlatformId = = VER_PLATFORM_WIN32_NT )
plat = " Windows NT 4.0 " ;
else
plat = " Windows 95 " ;
} else {
for ( i = 0 ; win_version_table [ i ] . major > = 0 ; + + i ) {
if ( win_version_table [ i ] . major = = info . dwMajorVersion & &
2005-01-20 20:03:09 +01:00
win_version_table [ i ] . minor = = info . dwMinorVersion ) {
2005-01-20 00:10:16 +01:00
plat = win_version_table [ i ] . version ;
break ;
}
}
}
if ( plat ) {
strlcpy ( uname_result , plat , sizeof ( uname_result ) ) ;
} else {
if ( info . dwMajorVersion > 5 | |
( info . dwMajorVersion = = 5 & & info . dwMinorVersion > 2 ) )
2005-01-20 20:03:09 +01:00
tor_snprintf ( uname_result , sizeof ( uname_result ) ,
" Very recent version of Windows [major=%d,minor=%d] " ,
2005-01-20 00:10:16 +01:00
( int ) info . dwMajorVersion , ( int ) info . dwMinorVersion ) ;
else
2005-01-20 20:03:09 +01:00
tor_snprintf ( uname_result , sizeof ( uname_result ) ,
" Unrecognized version of Windows [major=%d,minor=%d] " ,
2005-01-20 00:10:16 +01:00
( int ) info . dwMajorVersion , ( int ) info . dwMinorVersion ) ;
}
# else
2004-11-01 21:41:47 +01:00
strlcpy ( uname_result , " Unknown platform " , sizeof ( uname_result ) ) ;
2005-01-20 00:10:16 +01:00
# endif
2004-11-01 21:41:47 +01:00
}
uname_result_is_set = 1 ;
}
return uname_result ;
}
/*
* Process control
*/
2005-01-27 23:34:48 +01:00
# if defined(USE_PTHREADS)
struct tor_pthread_data_t {
int ( * func ) ( void * ) ;
void * data ;
} ;
static void *
tor_pthread_helper_fn ( void * _data )
{
struct tor_pthread_data_t * data = _data ;
int ( * func ) ( void * ) ;
void * arg ;
func = data - > func ;
arg = data - > data ;
tor_free ( _data ) ;
func ( arg ) ;
return NULL ;
}
# endif
2004-11-01 21:41:47 +01:00
/** 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 .
2005-01-03 20:07:25 +01:00
*
* 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 .
2004-11-01 21:41:47 +01:00
*/
2004-11-23 00:28:26 +01:00
int
spawn_func ( int ( * func ) ( void * ) , void * data )
2004-11-01 21:41:47 +01:00
{
2005-01-27 23:34:48 +01:00
# if defined(USE_WIN32_THREADS)
2004-11-01 21:41:47 +01:00
int rv ;
rv = _beginthread ( func , 0 , data ) ;
if ( rv = = ( unsigned long ) - 1 )
return - 1 ;
return 0 ;
2005-01-27 23:34:48 +01:00
# elif defined(USE_PTHREADS)
pthread_t thread ;
struct tor_pthread_data_t * d ;
d = tor_malloc ( sizeof ( struct 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 ;
2004-11-01 21:41:47 +01:00
# 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 ( )
{
2005-01-27 23:34:48 +01:00
# if defined(USE_WIN32_THREADS)
2004-11-01 21:41:47 +01:00
_endthread ( ) ;
2005-01-27 23:34:48 +01:00
# elif defined(USE_PTHREADS)
pthread_exit ( NULL ) ;
2004-11-01 21:41:47 +01:00
# else
2005-02-03 07:40:06 +01:00
/* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should
* call _exit , not exit , from child processes . */
_exit ( 0 ) ;
2004-11-01 21:41:47 +01:00
# 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 HAVE_GETTIMEOFDAY
if ( gettimeofday ( timeval , NULL ) ) {
log_fn ( LOG_ERR , " 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 ;
}
2005-01-27 23:34:48 +01:00
# ifdef USE_WIN32_THREADS
2004-11-01 21:41:47 +01:00
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_fn ( LOG_WARN , " Failed to acquire mutex: %d " , GetLastError ( ) ) ;
}
}
void tor_mutex_release ( tor_mutex_t * m )
{
BOOL r ;
r = ReleaseMutex ( m - > handle ) ;
if ( ! r ) {
log_fn ( LOG_WARN , " Failed to release mutex: %d " , GetLastError ( ) ) ;
}
}
2005-01-27 23:34:48 +01:00
# elif defined(USE_PTHREADS)
struct tor_mutex_t {
pthread_mutex_t mutex ;
} ;
tor_mutex_t * tor_mutex_new ( void )
{
tor_mutex_t * mutex = tor_malloc_zero ( sizeof ( tor_mutex_t ) ) ;
pthread_mutex_init ( & mutex - > mutex , NULL ) ;
return mutex ;
}
void tor_mutex_acquire ( tor_mutex_t * m )
{
tor_assert ( m ) ;
pthread_mutex_lock ( & m - > mutex ) ;
}
void tor_mutex_release ( tor_mutex_t * m )
{
tor_assert ( m ) ;
pthread_mutex_unlock ( & m - > mutex ) ;
}
void tor_mutex_free ( tor_mutex_t * m )
{
tor_assert ( m ) ;
pthread_mutex_destroy ( & m - > mutex ) ;
tor_free ( m ) ;
}
# else
struct tor_mutex_t {
2005-02-03 20:59:10 +01:00
int _unused ;
2005-01-27 23:34:48 +01:00
} ;
tor_mutex_t * tor_mutex_new ( void ) { return NULL ; }
void tor_mutex_acquire ( tor_mutex_t * m ) { }
void tor_mutex_release ( tor_mutex_t * m ) { }
void tor_mutex_free ( tor_mutex_t * m ) { }
2004-11-01 21:41:47 +01:00
# endif
/**
* On Windows , WSAEWOULDBLOCK is not always correct : when you see it ,
* you need to ask the socket for its actual errno . Also , you need to
* get your errors from WSAGetLastError , not errno . ( If you supply a
* socket of - 1 , we check WSAGetLastError , but don ' t correct
* WSAEWOULDBLOCKs . )
2004-11-28 06:48:02 +01:00
*
* The upshot of all of this is that when a socket call fails , you
* should call tor_socket_errno < em > at most once < / em > on the failing
* socket to get the error .
2004-11-01 21:41:47 +01:00
*/
# ifdef MS_WINDOWS
int tor_socket_errno ( int sock )
{
int optval , optvallen = sizeof ( optval ) ;
int err = WSAGetLastError ( ) ;
if ( err = = WSAEWOULDBLOCK & & sock > = 0 ) {
if ( getsockopt ( sock , SOL_SOCKET , SO_ERROR , ( void * ) & optval , & optvallen ) )
return err ;
if ( optval )
return optval ;
}
return err ;
}
# endif
# ifdef MS_WINDOWS
# define E(code, s) { code, (s " [" #code " ]") }
struct { int code ; const char * msg ; } windows_socket_errors [ ] = {
E ( WSAEINTR , " Interrupted function call " ) ,
E ( WSAEACCES , " Permission denied " ) ,
E ( WSAEFAULT , " Bad address " ) ,
E ( WSAEINVAL , " Invalid argument " ) ,
E ( WSAEMFILE , " Too many open files " ) ,
E ( WSAEWOULDBLOCK , " Resource temporarily unavailable " ) ,
E ( WSAEINPROGRESS , " Operation now in progress " ) ,
E ( WSAEALREADY , " Operation already in progress " ) ,
E ( WSAENOTSOCK , " Socket operation on nonsocket " ) ,
E ( WSAEDESTADDRREQ , " Destination address required " ) ,
E ( WSAEMSGSIZE , " Message too long " ) ,
E ( WSAEPROTOTYPE , " Protocol wrong for socket " ) ,
E ( WSAENOPROTOOPT , " Bad protocol option " ) ,
E ( WSAEPROTONOSUPPORT , " Protocol not supported " ) ,
E ( WSAESOCKTNOSUPPORT , " Socket type not supported " ) ,
/* What's the difference between NOTSUPP and NOSUPPORT? :) */
E ( WSAEOPNOTSUPP , " Operation not supported " ) ,
E ( WSAEPFNOSUPPORT , " Protocol family not supported " ) ,
E ( WSAEAFNOSUPPORT , " Address family not supported by protocol family " ) ,
E ( WSAEADDRINUSE , " Address already in use " ) ,
E ( WSAEADDRNOTAVAIL , " Cannot assign requested address " ) ,
E ( WSAENETDOWN , " Network is down " ) ,
E ( WSAENETUNREACH , " Network is unreachable " ) ,
E ( WSAENETRESET , " Network dropped connection on reset " ) ,
E ( WSAECONNABORTED , " Software caused connection abort " ) ,
E ( WSAECONNRESET , " Connection reset by peer " ) ,
2004-12-01 04:48:14 +01:00
E ( WSAENOBUFS , " No buffer space available " ) ,
2004-11-01 21:41:47 +01:00
E ( WSAEISCONN , " Socket is already connected " ) ,
E ( WSAENOTCONN , " Socket is not connected " ) ,
E ( WSAESHUTDOWN , " Cannot send after socket shutdown " ) ,
E ( WSAETIMEDOUT , " Connection timed out " ) ,
E ( WSAECONNREFUSED , " Connection refused " ) ,
E ( WSAEHOSTDOWN , " Host is down " ) ,
E ( WSAEHOSTUNREACH , " No route to host " ) ,
E ( WSAEPROCLIM , " Too many processes " ) ,
/* Yes, some of these start with WSA, not WSAE. No, I don't know why. */
E ( WSASYSNOTREADY , " Network subsystem is unavailable " ) ,
E ( WSAVERNOTSUPPORTED , " Winsock.dll out of range " ) ,
E ( WSANOTINITIALISED , " Successful WSAStartup not yet performed " ) ,
E ( WSAEDISCON , " Graceful shutdown now in progress " ) ,
# ifdef WSATYPE_NOT_FOUND
E ( WSATYPE_NOT_FOUND , " Class type not found " ) ,
# endif
E ( WSAHOST_NOT_FOUND , " Host not found " ) ,
E ( WSATRY_AGAIN , " Nonauthoritative host not found " ) ,
E ( WSANO_RECOVERY , " This is a nonrecoverable error " ) ,
E ( WSANO_DATA , " Valid name, no data record of requested type) " ) ,
/* There are some more error codes whose numeric values are marked
* < b > OS dependent < / b > . They start with WSA_ , apparently for the same
* reason that practitioners of some craft traditions deliberately
* introduce imperfections into their baskets and rugs " to allow the
* evil spirits to escape . " If we catch them, then our binaries
* might not report consistent results across versions of Windows .
* Thus , I ' m going to let them all fall through .
*/
{ - 1 , NULL } ,
} ;
/** There does not seem to be a strerror equivalent for winsock errors.
* Naturally , we have to roll our own .
*/
const char * tor_socket_strerror ( int e )
{
int i ;
for ( i = 0 ; windows_socket_errors [ i ] . code > = 0 ; + + i ) {
if ( e = = windows_socket_errors [ i ] . code )
return windows_socket_errors [ i ] . msg ;
}
return strerror ( e ) ;
}
# endif
2004-12-22 06:29:06 +01:00
/** Called before we make any calls to network-related functions.
* ( Some operating systems require their network libraries to be
* initialized . ) */
int network_init ( void )
{
# ifdef MS_WINDOWS
/* This silly exercise is necessary before windows will allow gethostbyname to work.
*/
WSADATA WSAData ;
int r ;
r = WSAStartup ( 0x101 , & WSAData ) ;
if ( r ) {
log_fn ( LOG_WARN , " Error initializing windows network layer: code was %d " , r ) ;
return - 1 ;
}
# endif
return 0 ;
}