diff -U4 --new-file -r 7.5.orig/lib/modules/Stdio.pmod/module.pmod 7.5/lib/modules/Stdio.pmod/module.pmod --- 7.5.orig/lib/modules/Stdio.pmod/module.pmod 2003-04-23 13:17:00.000000000 +0200 +++ 7.5/lib/modules/Stdio.pmod/module.pmod 2003-04-23 13:59:57.000000000 +0200 @@ -228,9 +228,9 @@ //! //! @seealso //! @[connect()], @[set_nonblocking()], @[set_blocking()] //! - int open_socket(int|string|void port, string|void address) + int open_socket(int|void port, string|void address, int|void family) { _fd=Fd(); is_file = 0; #ifdef __STDIO_DEBUG @@ -238,14 +238,16 @@ #endif debug_file="socket"; debug_mode=0; debug_bits=0; switch(query_num_arg()) { - case 0: - return ::open_socket(); - case 1: - return ::open_socket(port); - default: - return ::open_socket(port, address); + case 0: + return ::open_socket(); + case 1: + return ::open_socket(port); + case 2: + return ::open_socket(port, address); + default: + return ::open_socket(port, address, family); } } //! This function connects a socket previously created with @@ -1090,34 +1092,43 @@ //! @decl void create() //! @decl void create(int|string port) //! @decl void create(int|string port, function accept_callback) //! @decl void create(int|string port, function accept_callback, string ip) + //! @decl void create(int|string port, function accept_callback, string ip, int family) //! @decl void create("stdin") //! @decl void create("stdin", function accept_callback) //! //! If the first argument is other than @expr{"stdin"@} the arguments will //! be passed to @[bind()]. //! //! When create is called with @expr{"stdin"@} as the first argument, a //! socket is created out of the file descriptor @expr{0@}. This is only - //! useful if that actually is a socket to begin with. + //! useful if that actually is a socket to begin with. The @tt{family@} + //! parameter specifies the protocol family to create the port in - + //! either @{AF_INET@} or @{AF_INET6@} //! //! @seealso //! @[bind] void create( string|int|void p, void|mixed cb, - string|void ip ) + string|void ip, + int|void family ) { debug_ip = (ip||"ANY"); debug_port = p; - if( cb ) - if( ip ) - ::create( p, cb, ip ); - else + if( cb ) { + if( ip ) { + if (family) + ::create( p, cb, ip, family ); + else + ::create( p, cb, ip ); + } else ::create( p, cb ); - else + } else if (p) { ::create( p ); + } else + ::create(); } //! This function completes a connection made from a remote machine to //! this port. It returns a two-way stream in the form of a clone of @@ -2517,8 +2528,68 @@ callback(i,@extra); } } +//! @decl int get_default_af() +//! +//! Return the current default protocol (address) family. +//! +//! @seealso +//! @[set_default_af()] +//! +int get_default_af() +{ + return _global_inet_config->_default_af; +} + +//! @decl void set_default_af(int af) +//! +//! Set the default protocol (address) family to be used from that point +//! onwards. +//! +//! @param af +//! The family to be made the default. Either @tt{AF_INET@} or +//! @tt{AF_INET6@}. +//! +//! @seealso +//! @[get_default_af()] +//! +void set_default_af(int af) +{ + _global_inet_config->_default_af = af; +} + +//! @decl int get_auto_switch_af() +//! +//! Check whether the family auto-switch feature is in effect. +//! +//! @seealso +//! @[set_auto_switch_af()] +//! +int get_auto_switch_af() +{ + return _global_inet_config->_auto_switch_af; +} + +//! @decl void set_auto_switch_af(int asa) +//! +//! Control the address family auto-switch feature. If set to a value != 0 +//! the default family will be switched whenever the user creates a port +//! bound to an IPv4 or IPv6 adddress. The default family will thereafter +//! be set to the one corresponding to the address just created. +//! +//! @param asa +//! @tt{0@} if the auto-switch should be turned off, @tt{!=0@} +//! otherwise. +//! +//! @seealso +//! @[get_auto_switch_af()] +//! +void set_auto_switch_af(int asa) +{ + _global_inet_config->_auto_switch_af = asa; +} + //! @decl void werror(string s) //! //! Write a message to stderr. Stderr is normally the console, even if //! the process output has been redirected to a file or pipe. diff -U4 --new-file -r 7.5.orig/src/acconfig.h 7.5/src/acconfig.h --- 7.5.orig/src/acconfig.h 2003-04-04 18:39:02.000000000 +0200 +++ 7.5/src/acconfig.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,628 +0,0 @@ -/* -|| This file is part of Pike. For copyright information see COPYRIGHT. -|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING -|| for more information. -|| $Id: acconfig.h,v 1.123 2003/04/01 19:41:13 mast Exp $ -*/ - -#ifndef MACHINE_H -#define MACHINE_H - -/* We must define this *always* */ -#ifndef POSIX_SOURCE -#define POSIX_SOURCE -#endif - -/* Get more declarations in GNU libc. */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -/* Get more declarations from AIX libc. */ -#ifndef _ALL_SOURCE -#define _ALL_SOURCE -#endif - -/* Where's the master.pike file installed? */ -#define DEFAULT_MASTER "@prefix@/lib/pike/master.pike" - -/* Define this if you want run time self tests */ -#undef PIKE_DEBUG - -/* Define this if you want pike to interact with valgrind. */ -#undef USE_VALGRIND - -/* Define this if you are going to use a memory access checker (like Purify) */ -#undef __CHECKER__ - -/* Define this if you want malloc debugging */ -#undef DEBUG_MALLOC - -/* Define this if you want checkpoints */ -#undef DMALLOC_TRACE - -/* With this, dmalloc will trace malloc(3) calls */ -#undef ENCAPSULATE_MALLOC - -/* With this, dmalloc will report leaks made by malloc(3) calls */ -#undef REPORT_ENCAPSULATED_MALLOC - -/* Define this to enable the internal Pike security system */ -#undef PIKE_SECURITY - -/* Define this to enable the internal bignum conversion */ -#undef AUTO_BIGNUM - -/* Define this to enable experimental code for multicpu machines */ -#undef PIKE_RUN_UNLOCKED - -/* Define this if you want to enable the shared nodes mode of the optimizer. */ -#undef SHARED_NODES - -/* Define this to use the new keypair loop. */ -#undef PIKE_MAPPING_KEYPAIR_LOOP - -/* Define this to use the new multiset implementation. */ -#undef PIKE_NEW_MULTISETS - -/* Enable profiling */ -#undef PROFILING - -/* Enable internal profiling */ -#undef INTERNAL_PROFILING - -/* The following USE_* are used by smartlink */ -/* Define this if your ld sets the run path with -rpath */ -#undef USE_RPATH - -/* Define this if your ld sets the run path with -R */ -#undef USE_R - -/* Define this if your ld sets the run path with -YP, */ -#undef USE_YP_ - -/* Define this if your ld sets the run path with +b */ -#undef USE_PLUS_b - -/* Define this if your ld uses -rpath, but your cc wants -Wl,-rpath, */ -#undef USE_Wl - -/* Define this if your ld uses -R, but your cc wants -Wl,-R */ -#undef USE_Wl_R - -/* Define this if your ld uses -rpath, but your cc -Qoption,ld,-rpath (icc) */ -#undef USE_Qoption - -/* Define this if your ld uses -YP, , but your cc wants -Xlinker -YP, */ -#undef USE_XLINKER_YP_ - -/* Define this if your ld doesn't have an option to set the run path */ -#undef USE_LD_LIBRARY_PATH - -/* Define if your tcc supports #pragma TenDRA longlong type allow. */ -#undef HAVE_PRAGMA_TENDRA_LONGLONG - -/* Define if your tcc supports #pragma TenDRA set longlong type : long long. */ -#undef HAVE_PRAGMA_TENDRA_SET_LONGLONG_TYPE - -/* The worlds most stringent C compiler? */ -#ifdef __TenDRA__ -/* We want to be able to use 64bit arithmetic */ -#ifdef HAVE_PRAGMA_TENDRA_LONGLONG -#pragma TenDRA longlong type allow -#endif /* HAVE_PRAGMA_TENDRA_LONGLONG */ -#ifdef HAVE_PRAGMA_TENDRA_SET_LONGLONG_TYPE -#pragma TenDRA set longlong type : long long -#endif /* HAVE_PRAGMA_TENDRA_SET_LONGLONG_TYPE */ - -#ifdef _NO_LONGLONG -#undef _NO_LONGLONG -#endif /* _NO_LONGLONG */ -#endif /* __TenDRA__ */ - -@TOP@ - -/* Define this if your compiler attempts to use _chkstk, but libc contains - * __chkstk. */ -#undef HAVE_BROKEN_CHKSTK - -/* Define for solaris */ -#undef SOLARIS - -/* Define if the closedir function returns void instead of int. */ -#undef VOID_CLOSEDIR - -/* Define to 'int' if doesn't */ -#undef time_t - -/* Define to 'short' if doesn't */ -#undef pri_t - -/* Define to 'int' if doesn't */ -#undef uid_t - -/* Define to 'int' if doesn't */ -#undef gid_t - -/* Define to 'int' if doesn't */ -#undef pid_t - -/* Define to 'unsigned long' if or doesn't */ -#undef size_t - -/* Define to 'long' if of doesn't */ -#undef ptrdiff_t - -/* Define to 'long' if doesn't */ -#undef off_t - -/* Define to 'int' if doesn't */ -#undef sig_atomic_t - -/* Define as the return type of signal handlers (int or void). */ -#undef RETSIGTYPE - -/* define this if igonoring SIGFPE helps with core dumps */ -#undef IGNORE_SIGFPE - -/* define if you want to use double precision floats instead of single */ -#undef WITH_DOUBLE_PRECISION_SVALUE - -/* define if you want to use long double precision floats */ -#undef WITH_LONG_DOUBLE_PRECISION_SVALUE - -/* define to the type of pike floats */ -#undef FLOAT_TYPE - -/* define to the size of pike floats */ -#undef SIZEOF_FLOAT_TYPE - -/* force this type upon ints */ -#undef WITH_LONG_INT -#undef WITH_LONG_LONG_INT -#undef WITH_SHORT_INT -#undef WITH_INT_INT -#undef WITH_UNSIGNED_LONG_INT -#undef WITH_UNSIGNED_LONG_LONG_INT - -/* define to the type of pike primitive ints */ -#undef INT_TYPE - -/* define to the size of pike primitive ints */ -#undef SIZEOF_INT_TYPE - -/* If using the C implementation of alloca, define if you know the - * direction of stack growth for your system; otherwise it will be - * automatically deduced at run-time. - * STACK_DIRECTION > 0 => grows toward higher addresses - * STACK_DIRECTION < 0 => grows toward lower addresses - * STACK_DIRECTION = 0 => direction of growth unknown - * - * Also used by Pike's runtime C-stack checker. - */ -#undef STACK_DIRECTION - -/* Define this to the number of KB in the initial stack, - * currently this is 1 Mb on FreeBSD, 2Mb on Linux and - * unlimited (undefined) everywhere else - */ -#undef Pike_INITIAL_STACK_SIZE - -/* If so, is it restricted to user and system time? */ -#undef GETRUSAGE_RESTRICTED - -/* Solaris has rusage as an ioctl on procfs */ -#undef GETRUSAGE_THROUGH_PROCFS - -/* So has True64, but no useful information in prstatus_t */ -#undef GETRUSAGE_THROUGH_PROCFS_PRS - -/* Define if you have infnan */ -#undef HAVE_INFNAN - -/* Define if you have _isnan */ -#undef HAVE__ISNAN - -/* Define if you have fork */ -#undef HAVE_FORK - -/* Define if you have isspace */ -#undef HAVE_ISSPACE - -/* Define if you have fpsetmask */ -#undef HAVE_FPSETMASK - -/* Define if you have fpsetround */ -#undef HAVE_FPSETROUND - -/* Define if you have isless */ -#undef HAVE_ISLESS - -/* Define if you have crypt. */ -#undef HAVE_CRYPT - -/* Define if you have ualarm. */ -#undef HAVE_UALARM - -/* Define if your ualarm takes two args. */ -#undef UALARM_TAKES_TWO_ARGS - -/* Define if your ptrace takes four args. */ -#undef PTRACE_TAKES_FOUR_ARGS - -/* Define if argument 3 to ptrace is a pointer type. */ -#undef PTRACE_ADDR_TYPE_IS_POINTER - -/* Define if gettimeofday takes to arguments */ -#undef GETTIMEOFDAY_TAKES_TWO_ARGS - -/* Define if realloc(NULL, SZ) works. */ -#undef HAVE_WORKING_REALLOC_NULL - -/* Define if gethrvtime works (i.e. even without ptime). */ -#undef HAVE_WORKING_GETHRVTIME - -/* Define if you have gethrtime */ -#undef HAVE_GETHRTIME - -/* Can we make our own gethrtime? */ -#undef OWN_GETHRTIME - -/* ... by using the RDTSC instruction? */ -#undef OWN_GETHRTIME_RDTSC - -/* Define if you have a working, 8-bit-clean memcmp */ -#undef HAVE_MEMCMP - -/* Define if you have gethostname */ -#undef HAVE_GETHOSTNAME - -/* Define if you have memmove. */ -#ifndef __CHECKER__ -#undef HAVE_MEMMOVE -#endif - -/* Define if you have memmem. */ -#undef HAVE_MEMMEM - -/* Define if you have memset. */ -#undef HAVE_MEMSET - -/* Define if you have memcpy. */ -#undef HAVE_MEMCPY - -/* Define if you have strcoll */ -#undef HAVE_STRCOLL - -/* Define this if you have dlopen */ -#undef HAVE_DLOPEN - -/* Define if you have ldexp. */ -#undef HAVE_LDEXP - -/* Define if you have rint. */ -#undef HAVE_RINT - -/* Define if you have frexp. */ -#undef HAVE_FREXP - -/* Define if your signals are one-shot */ -#undef SIGNAL_ONESHOT - -/* Define if you have gcc-style computed goto, and want to use them. */ -#undef HAVE_COMPUTED_GOTO - -/* Define this to use machine code */ -#undef PIKE_USE_MACHINE_CODE - -/* Define this to one of the available bytecode methods. */ -#undef PIKE_BYTECODE_METHOD - -/* You have gcc-type function attributes? */ -#undef HAVE_FUNCTION_ATTRIBUTES - -/* You have cl-type __declspec? */ -#undef HAVE_DECLSPEC - -/* Do your compiler grock 'volatile' */ -#define VOLATILE volatile - -/* Define this if your compiler doesn't allow cast of void * to function pointer */ -#undef NO_CAST_TO_FUN - -/* How to extract a char and an unsigned char from a char * */ -#undef EXTRACT_CHAR_BY_CAST -#undef EXTRACT_UCHAR_BY_CAST - -/* Do you have IEEE floats and/or doubles (either big or little endian) ? */ -#undef FLOAT_IS_IEEE_BIG -#undef FLOAT_IS_IEEE_LITTLE -#undef DOUBLE_IS_IEEE_BIG -#undef DOUBLE_IS_IEEE_LITTLE - -/* Define this if strtol exists, and doesn't cut at 0x7fffffff */ -#undef HAVE_WORKING_STRTOL - -/* The rest of this file is just to eliminate warnings */ - -/* define if declaration of strchr is missing */ -#undef STRCHR_DECL_MISSING - -/* define if declaration of malloc is missing */ -#undef MALLOC_DECL_MISSING - -/* define if declaration of getpeername is missing */ -#undef GETPEERNAME_DECL_MISSING - -/* define if declaration of gethostname is missing */ -#undef GETHOSTNAME_DECL_MISSING - -/* define if declaration of popen is missing */ -#undef POPEN_DECL_MISSING - -/* define if declaration of getenv is missing */ -#undef GETENV_DECL_MISSING - -/* define if you are using crypt.c. */ -#undef USE_CRYPT_C - -/* Define if we can declare 'extern char **environ' */ -#undef DECLARE_ENVIRON - -/* The byteorder your machine use, most use 4321, PC use 1234 */ -#define PIKE_BYTEORDER 0 - -/* What alignment do 32-bit integers need */ -#define PIKE_INT32_ALIGNMENT 4 - -/* Assembler prefix for general purpose registers */ -#undef PIKE_CPU_REG_PREFIX - -/* Number of possible filedesriptors */ -#define MAX_OPEN_FILEDESCRIPTORS 1024 - -/* define this if #include provides an external int timezone */ -#undef HAVE_EXTERNAL_TIMEZONE - -/* define this if your struct tm has a tm_gmtoff */ -#undef STRUCT_TM_HAS_GMTOFF - -/* define this if your struct tm has a __tm_gmtoff */ -#undef STRUCT_TM_HAS___TM_GMTOFF - -/* Define if you have struct timeval */ -#undef HAVE_STRUCT_TIMEVAL - -/* Define this to the max value of an unsigned short unles does.. */ -#undef USHRT_MAX - -/* Define these if you are going to use threads */ -#undef PIKE_THREADS -#undef _REENTRANT -#undef _THREAD_SAFE - -/* Define this if you want the UNIX taste of threads */ -#undef _UNIX_THREADS - -/* Define this if you want the POSIX taste of threads */ -#undef _MIT_POSIX_THREADS - -/* Define this if you want the SGI sproc taste of threads */ -#undef _SGI_SPROC_THREADS -#undef _SGI_MP_SOURCE - -/* Define this if you have Windows NT threads */ -#undef NT_THREADS - -/* Define this if your THREAD_T type is a pointer type. */ -#undef PIKE_THREAD_T_IS_POINTER - -/* Define to the flag to get an error checking mutex, if supported. */ -#undef PIKE_MUTEX_ERRORCHECK - -/* Define to the flag to get a recursive mutex, if supported. */ -#undef PIKE_MUTEX_RECURSIVE - -/* Define this if your pthreads have pthread_condattr_default */ -#undef HAVE_PTHREAD_CONDATTR_DEFAULT - -/* Define this if you need to use &pthread_condattr_default in cond_init() */ -#undef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX - -/* Define if you have the pthread_attr_setstacksize function. */ -#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE - -/* Define if you have the pthread_atfork function. */ -#undef HAVE_PTHREAD_ATFORK - -/* Define if you have the pthread_cond_init function. */ -#undef HAVE_PTHREAD_COND_INIT - -/* Define if you have the pthread_yield function. */ -#undef HAVE_PTHREAD_YIELD - -/* Hack for stupid glibc linuxthreads */ -#undef HAVE_PTHREAD_INITIAL_THREAD_BOS - -/* Define if your OS has the union wait. */ -#undef HAVE_UNION_WAIT - -/* Define if you have isgraph */ -#undef HAVE_ISGRAPH - -/* Define if your cpp supports the ANSI concatenation operator ## */ -#undef HAVE_ANSI_CONCAT - -/* Define if you don't have F_SETFD, or it doesn't work */ -#undef HAVE_BROKEN_F_SETFD - -/* Define if your thread implementation doesn't propagate euid & egid. */ -#undef HAVE_BROKEN_LINUX_THREAD_EUID - -/* Define if your cpp supports K&R-style concatenation */ -#undef HAVE_KR_CONCAT - -/* Use poll() instead of select() ? */ -#undef HAVE_AND_USE_POLL - -/* This works on Solaris or any UNIX where - * waitpid can report ECHILD when running more than one at once - * (or any UNIX where waitpid actually works) - */ -#undef USE_WAIT_THREAD - -/* This works on Linux or any UNIX where - * waitpid works or where threads and signals bugs in - * less annoying ways than Solaris. - */ -#undef USE_SIGCHILD - -/* Enable code to handle Out-Of-Band data */ -#undef WITH_OOB - -/* Enable tracing of the compiler */ -#undef YYDEBUG - -/* Define if your compiler has a symbol __func__ */ -#undef HAVE_WORKING___FUNC__ - -/* Define if your compiler has a symbol __FUNCTION__ */ -#undef HAVE_WORKING___FUNCTION__ - -/* The last argument to accept() is an ACCEPT_SIZE_T * */ -#define ACCEPT_SIZE_T int - -/* Can we compile in MMX support? */ -#undef TRY_USE_MMX - -/* Define if you have the header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* set this to the modifier type string to print size_t, like "" or "l" */ -#undef PRINTSIZET - -/* set this to the modifier type string to print ptrdiff_t, like "" or "l" */ -#undef PRINTPTRDIFFT - -/* set this to the modifier type string to print INT64 if that type exists */ -#undef PRINTINT64 - -/* Define if the compiler understand union initializations. */ -#undef HAVE_UNION_INIT - -/* Define when binary --disable-binary is used. */ -#undef DISABLE_BINARY - -/* Define to the size of the overhead for a malloc'ed block. (Slightly - * too much is better than slightly too little.) */ -#undef PIKE_MALLOC_OVERHEAD - -/* Define to the page size (handled efficiently by malloc). */ -#undef PIKE_MALLOC_PAGE_SIZE - -/* PIKE_YES if the number reported by get_cpu_time (rusage.c) is - * thread local, PIKE_NO if it isn't, PIKE_UNKNOWN if it couldn't be - * established. */ -#undef CPU_TIME_IS_THREAD_LOCAL - -@BOTTOM@ - -/* NT stuff */ -#undef HAVE_GETSYSTEMTIMEASFILETIME -#undef HAVE_LOADLIBRARY -#undef HAVE_FREELIBRARY -#undef HAVE_GETPROCADDRESS -#undef DL_EXPORT -#undef USE_MY_WIN32_DLOPEN - -/* CygWin kludge. */ -#if defined(HAVE_UNISTD_H) && defined(HAVE_WINDOWS_H) -#undef HAVE_WINDOWS_H -#undef HAVE_WINBASE_H -#undef HAVE_WINSOCK_H -#undef HAVE_WINSOCK2_H -#undef HAVE_FD_FLOCK -#endif /* HAVE_SYS_UNISTD_H && HAVE_WINDOWS_H */ - -/* How to set a socket non-blocking */ -#undef USE_IOCTL_FIONBIO -#undef USE_IOCTLSOCKET_FIONBIO -#undef USE_FCNTL_O_NDELAY -#undef USE_FCNTL_FNDELAY -#undef USE_FCNTL_O_NONBLOCK - -/* How well is OOB TCP working? - * -1 = unknown - * 0 = doesn't seem to be working at all - * 1 = very limited functionality - * 2 = should be working as long as you are cautious - * 3 = works excellently - */ -#define PIKE_OOB_WORKS -1 - -/* We want to use errno later */ -#ifdef _SGI_SPROC_THREADS -/* Magic define of _SGI_MP_SOURCE above might redefine errno below */ -#include -#if defined(HAVE_OSERROR) && !defined(errno) -#define errno (oserror()) -#endif /* HAVE_OSERROR && !errno */ -#endif /* _SGI_SPROC_THREADS */ - -/* This macro is only provided for compatibility with - * Windows PreRelease. Use ALIGNOF() instead! - * (Needed for va_arg().) - */ -#ifndef __alignof -#define __alignof(X) ((size_t)&(((struct { char ignored_ ; X fooo_; } *)0)->fooo_)) -#endif /* __alignof */ - -#ifdef HAVE_FUNCTION_ATTRIBUTES -#define ATTRIBUTE(X) __attribute__ (X) -#else -#define ATTRIBUTE(X) -#endif - -#ifdef HAVE_DECLSPEC -#define DECLSPEC(X) __declspec(X) -#else /* !HAVE_DECLSPEC */ -#define DECLSPEC(X) -#endif /* HAVE_DECLSPEC */ - -#ifndef HAVE_WORKING___FUNC__ -#ifdef HAVE_WORKING___FUNCTION__ -#define __func__ __FUNCTION__ -#else /* !HAVE_WORKING___FUNCTION__ */ -#define __func__ "unknown" -#endif /* HAVE_WORKING___FUNCTION__ */ -#endif /* !HAVE_WORKING___FUNC__ */ - -#ifndef HAVE_WORKING_REALLOC_NULL -#define realloc(PTR, SZ) pike_realloc((PTR),(SZ)) -#endif - -/* NOTE: - * PIKE_CONCAT doesn't get defined if there isn't any way to - * concatenate symbols - */ -#ifdef HAVE_ANSI_CONCAT -#define PIKE_CONCAT(X,Y) X##Y -#define PIKE_CONCAT3(X,Y,Z) X##Y##Z -#define PIKE_CONCAT4(X,Y,Z,Q) X##Y##Z##Q -#else -#ifdef HAVE_KR_CONCAT -#define PIKE_CONCAT(X,Y) X/**/Y -#define PIKE_CONCAT3(X,Y,Z) X/**/Y/**/Z -#define PIKE_CONCAT4(X,Y,Z,Q) X/**/Y/**/Z/**/Q -#endif /* HAVE_KR_CONCAT */ -#endif /* HAVE_ANSI_CONCAT */ - -#define TOSTR(X) #X -#define DEFINETOSTR(X) TOSTR(X) - -/* Some identifiers used as flags in the defines above. */ -#define PIKE_YES 1 -#define PIKE_NO 2 -#define PIKE_UNKNOWN 3 - -#endif /* MACHINE_H */ diff -U4 --new-file -r 7.5.orig/src/configure.in 7.5/src/configure.in --- 7.5.orig/src/configure.in 2003-04-08 13:26:36.000000000 +0200 +++ 7.5/src/configure.in 2003-04-23 14:08:53.000000000 +0200 @@ -3205,8 +3205,13 @@ usleep \ nanosleep \ thr_yield \ prctl \ + getaddrinfo \ + inet_aton \ + inet_ntoa \ + inet_pton \ + inet_ntop \ ) # SunOS 4 realloc() returns NULL when reallocing NULL. AC_MSG_CHECKING([if realloc(NULL, SZ) works]) @@ -3231,8 +3236,102 @@ else AC_MSG_RESULT(no) fi + +AC_MSG_CHECKING(if struct sockaddr_storage is defined) +AC_CACHE_VAL(pike_cv_struct_sockaddr_storage, [ + AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif /* HAVE_SYS_SOCKET_H */ + ],[ + struct sockaddr_storage sas; + + sas.ss_family = 0; + ], [ pike_cv_struct_sockaddr_storage=yes ], [ pike_cv_struct_sockaddr_storage=no ]) +]) +if test "$pike_cv_struct_sockaddr_storage" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_STRUCT_SOCKADDR_STORAGE) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for AF_INET6) +AC_CACHE_VAL(pike_cv_have_af_inet6, [ + AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif /* HAVE_SYS_SOCKET_H */ +#ifdef HAVE_NETINET_IN_H +#include +#endif /* HAVE_NETINET_IN_H */ + ],[ + int tst = AF_INET6; + ], [ pike_cv_have_af_inet6=yes ], [ pike_cv_have_af_inet6=no ]) +]) +if test "$pike_cv_have_af_inet6" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_AF_INET6) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(for struct sockaddr_in6) +AC_CACHE_VAL(pike_cv_struct_sockaddr_in6, [ + AC_TRY_COMPILE([ +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ +#include +#ifdef HAVE_SYS_SOCKET_H +#include +#endif /* HAVE_SYS_SOCKET_H */ +#ifdef HAVE_NETINET_IN_H +#include +#endif /* HAVE_NETINET_IN_H */ + ],[ + struct sockaddr_in6 sin6; + + sin6.sin6_family = 0; + sin6.sin6_port = 0; + sin6.sin6_flowinfo = 0; + sin6.sin6_scope_id = 0; + ], [ pike_cv_struct_sockaddr_in6=yes ], [ pike_cv_struct_sockaddr_in6=no ]) +]) +if test "$pike_cv_struct_sockaddr_in6" = "yes"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(whether IPv6 is supported by the system libraries) +if test "$pike_cv_have_af_inet6" = "yes" -a "$pike_cv_struct_sockaddr_in6" = "yes"; then + case "$pike_cv_sys_os" in + Linux*) AC_DEFINE(HAVE_IPV6_LINUX) + IPV6_FLAVOR=Linux ;; + FreeBSD*|OpenBSD*|NetBSD*) AC_DEFINE(HAVE_IPV6_KAME) + IPV6_FLAVOR=KAME ;; + *) AC_DEFINE(HAVE_IPV6_UNKNOWN) + IPV6_FLAVOR=Unknown + esac + + AC_MSG_RESULT([yes ($IPV6_FLAVOR)]) + AC_DEFINE(HAVE_IPV6) +else + AC_MSG_RESULT(no) +fi + AC_MSG_CHECKING(for the type of the last argument to accept) AC_CACHE_VAL(pike_cv_accept_size_t, [ for t in socklen_t size_t int; do AC_TRY_COMPILE([ diff -U4 --new-file -r 7.5.orig/src/modules/files/file.c 7.5/src/modules/files/file.c --- 7.5.orig/src/modules/files/file.c 2003-04-23 13:17:15.000000000 +0200 +++ 7.5/src/modules/files/file.c 2003-04-23 19:04:41.000000000 +0200 @@ -22,8 +22,9 @@ #include "operators.h" #include "security.h" #include "bignum.h" #include "builtin_functions.h" +#include "mapping.h" #include "file_machine.h" #include "file.h" #include "pike_error.h" @@ -31,8 +32,10 @@ #include "pike_types.h" #include "threads.h" #include "program_id.h" +#include "inet_config.h" + #ifdef HAVE_SYS_TYPE_H #include #endif /* HAVE_SYS_TYPE_H */ @@ -84,8 +87,12 @@ #ifdef HAVE_SYS_SOCKETVAR_H #include #endif +#ifdef HAVE_NETINET_IN_H +#include +#endif + /* Fix warning on OSF/1 * * NOERROR is defined by both sys/stream.h (-1), and arpa/nameser.h (0), * the latter is included by netdb.h. @@ -226,8 +233,13 @@ } static void init_fd(int fd, int open_mode) { + struct inet_config_storage *gics; + + gics = (struct inet_config_storage*)get_storage(global_inet_config, + inet_config_program); + FD=fd; ERRNO=0; REMOVE_INTERNAL_REFERENCE(THIS); THIS->flags=0; @@ -244,8 +256,11 @@ #endif /* WITH_OOB */ #if defined(HAVE_FD_FLOCK) || defined(HAVE_FD_LOCKF) THIS->key=0; #endif + THIS->default_af = gics->default_af; + THIS->curr_af = gics->default_af; + THIS->auto_switch_af = gics->auto_switch_af; } void reset_variables(void) @@ -536,8 +551,15 @@ }else{ /* For some reason, 8k seems to work faster than 64k. * (4k seems to be about 2% faster than 8k when using linux though) * /Hubbe (Per pointed it out to me..) + * + * Probably the best chunk size is the host system's VM page size + * (i.e. 4k on ia32, 8k on Alpha) - many systems (including Linux) do + * buffer reads/writes using page-aligned transfers. getpagesize() or + * sysconf(_SC_PAGESIZE) might be used to determine the page size on + * runtime. + * /Grendel */ #define CHUNK ( 1024 * 8 ) INT32 try_read; dynamic_buffer b; @@ -2077,11 +2099,22 @@ struct object *file_make_object_from_fd(int fd, int mode, int guess) { struct object *o=low_clone(file_program); + struct inet_config_storage *gics = NULL; + + if (global_inet_config) + gics = (struct inet_config_storage*)get_storage(global_inet_config, + inet_config_program); call_c_initializers(o); ((struct my_file *)(o->storage))->fd=fd; ((struct my_file *)(o->storage))->open_mode=mode | fd_query_properties(fd, guess); + if (gics) { + ((struct my_file *)(o->storage))->default_af = gics->default_af; + ((struct my_file *)(o->storage))->curr_af = gics->default_af; + ((struct my_file *)(o->storage))->auto_switch_af = gics->auto_switch_af; + } + return o; } /*! @decl void set_buffer(int bufsize, string mode) @@ -2181,20 +2214,20 @@ #endif /* !errno */ static int socketpair_fd = -1; int my_socketpair(int family, int type, int protocol, int sv[2]) { - static struct sockaddr_in my_addr; - struct sockaddr_in addr,addr2; + static SOCKADDR my_addr; + SOCKADDR addr,addr2; int retries=0; /* Solaris and AIX think this variable should be a size_t, everybody else * thinks it should be an int. * * FIXME: Configure-test? */ ACCEPT_SIZE_T len; - MEMSET((char *)&addr,0,sizeof(struct sockaddr_in)); - + MEMSET((char *)&addr,0,sizeof(SOCKADDR)); + /* We lie, we actually create an AF_INET socket... */ if(family != AF_UNIX || type != SOCK_STREAM) { errno=EINVAL; @@ -2204,39 +2237,38 @@ if(socketpair_fd==-1) { if((socketpair_fd=fd_socket(AF_INET, SOCK_STREAM, 0)) < 0) { SP_DEBUG((stderr, "my_socketpair:fd_socket() failed, errno:%d\n", - errno)); + errno)); return -1; } /* I wonder what is most common a loopback on ip# 127.0.0.1 or * a loopback with the name "localhost"? * Let's hope those few people who don't have socketpair have * a loopback on 127.0.0.1 */ - MEMSET((char *)&my_addr,0,sizeof(struct sockaddr_in)); - my_addr.sin_family=AF_INET; - my_addr.sin_addr.s_addr=htonl(INADDR_ANY); - my_addr.sin_port=htons(0); - + MEMSET((char *)&my_addr,0,sizeof(SOCKADDR)); + SOCKADDR_IN(my_addr).sin_family=AF_INET; + SOCKADDR_IN(my_addr).sin_addr.s_addr=htonl(INADDR_ANY); + SOCKADDR_IN(my_addr).sin_port=htons(0); /* Bind our sockets on any port */ - if(fd_bind(socketpair_fd, (struct sockaddr *)&my_addr, sizeof(addr)) < 0) + if(fd_bind(socketpair_fd, (struct sockaddr *)&my_addr, sizeof(SOCKADDR_IN(addr))) < 0) { SP_DEBUG((stderr, "my_socketpair:fd_bind() failed, errno:%d\n", - errno)); + errno)); fd_close(socketpair_fd); socketpair_fd=-1; return -1; } /* Check what ports we got.. */ - len = sizeof(my_addr); + len = sizeof(SOCKADDR_IN(my_addr)); if(fd_getsockname(socketpair_fd,(struct sockaddr *)&my_addr,&len) < 0) { SP_DEBUG((stderr, "my_socketpair:fd_getsockname() failed, errno:%d\n", - errno)); + errno)); fd_close(socketpair_fd); socketpair_fd=-1; return -1; } @@ -2244,9 +2276,9 @@ /* Listen to connections on our new socket */ if(fd_listen(socketpair_fd, 5) < 0) { SP_DEBUG((stderr, "my_socketpair:fd_listen() failed, errno:%d\n", - errno)); + errno)); fd_close(socketpair_fd); socketpair_fd=-1; return -1; } @@ -2254,49 +2286,57 @@ set_close_on_exec(socketpair_fd, 1); set_nonblocking(socketpair_fd, 1); - my_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); + SOCKADDR_IN(my_addr).sin_addr.s_addr=inet_addr("127.0.0.1"); + } else { + len = sizeof(SOCKADDR_IN(my_addr)); + if(fd_getsockname(socketpair_fd,(struct sockaddr *)&my_addr,&len) < 0) { + SP_DEBUG((stderr, "my_socketpair:fd_getsockname() failed, errno:%d\n", + errno)); + fd_close(socketpair_fd); + socketpair_fd=-1; + return -1; + } } - if((sv[1]=fd_socket(AF_INET, SOCK_STREAM, 0)) <0) { SP_DEBUG((stderr, "my_socketpair:fd_socket() failed, errno:%d (2)\n", - errno)); + errno)); return -1; } /* set_nonblocking(sv[1],1); */ -retry_connect: + retry_connect: retries++; - if(fd_connect(sv[1], (struct sockaddr *)&my_addr, sizeof(addr)) < 0) + if(fd_connect(sv[1], (struct sockaddr *)&my_addr, sizeof(SOCKADDR_IN(addr))) < 0) { /* fprintf(stderr,"errno=%d (%d)\n",errno,EWOULDBLOCK); */ SP_DEBUG((stderr, "my_socketpair:fd_connect() failed, errno:%d (%d)\n", - errno, EWOULDBLOCK)); + errno, EWOULDBLOCK)); if((errno != EWOULDBLOCK) #ifdef WSAEWOULDBLOCK && (errno != WSAEWOULDBLOCK) #endif /* WSAEWOULDBLOCK */ - ) + ) { int tmp2; for(tmp2=0;tmp2<20;tmp2++) { - int tmp; - ACCEPT_SIZE_T len2; + int tmp; + ACCEPT_SIZE_T len2; - len2=sizeof(addr); - tmp=fd_accept(socketpair_fd,(struct sockaddr *)&addr,&len2); + len2=sizeof(SOCKADDR_IN(addr)); + tmp=fd_accept(socketpair_fd,(struct sockaddr *)&addr,&len2); - if(tmp!=-1) { - SP_DEBUG((stderr, "my_socketpair:fd_accept() failed, errno:%d\n", - errno)); - fd_close(tmp); - } - else - break; + if(tmp!=-1) { + SP_DEBUG((stderr, "my_socketpair:fd_accept() failed, errno:%d\n", + errno)); + fd_close(tmp); + } + else + break; } if(retries > 20) return -1; goto retry_connect; } @@ -2313,15 +2353,15 @@ do { ACCEPT_SIZE_T len3; - len3=sizeof(addr); - retry_accept: + len3=sizeof(SOCKADDR_IN(addr)); + retry_accept: sv[0]=fd_accept(socketpair_fd,(struct sockaddr *)&addr,&len3); if(sv[0] < 0) { SP_DEBUG((stderr, "my_socketpair:fd_accept() failed, errno:%d (2)\n", - errno)); + errno)); if(errno==EINTR) goto retry_accept; fd_close(sv[1]); return -1; } @@ -2331,25 +2371,26 @@ /* We do not trust accept */ len=sizeof(addr); if(fd_getpeername(sv[0], (struct sockaddr *)&addr,&len)) { SP_DEBUG((stderr, "my_socketpair:fd_getpeername() failed, errno:%d\n", - errno)); + errno)); return -1; } - len=sizeof(addr); + + len=sizeof(SOCKADDR_IN(addr)); if(fd_getsockname(sv[1],(struct sockaddr *)&addr2,&len) < 0) { SP_DEBUG((stderr, "my_socketpair:fd_getsockname() failed, errno:%d\n", - errno)); + errno)); return -1; } - }while(len < (int)sizeof(addr) || - addr2.sin_addr.s_addr != addr.sin_addr.s_addr || - addr2.sin_port != addr.sin_port); - + } while(len < (int)sizeof(SOCKADDR_IN(addr)) || + SOCKADDR_IN(addr2).sin_addr.s_addr != SOCKADDR_IN(addr).sin_addr.s_addr || + SOCKADDR_IN(addr2).sin_port != SOCKADDR_IN(addr).sin_port) + ; /* set_nonblocking(sv[1],0); */ SP_DEBUG((stderr, "my_socketpair: succeeded\n", - errno)); + errno)); return 0; } @@ -2548,8 +2589,12 @@ }else{ set_write_oob_callback(to->fd, file_write_oob_callback, to); } #endif /* WITH_OOB */ + to->default_af = from->default_af; + to->curr_af = from->curr_af; + to->auto_switch_af = from->auto_switch_af; + check_internal_reference(to); } /*! @decl int dup2(Stdio.File to) @@ -2633,17 +2678,29 @@ low_dup(o, fd, THIS); push_object(o); } -/*! @decl int(0..1) open_socket(int|void port, string|void addr) +/*! @decl int(0..1) open_socket(int|void port, string|void addr, int|void family) */ static void file_open_socket(INT32 args) { int fd; - + int family; + close_fd(); FD=-1; - fd=fd_socket(AF_INET, SOCK_STREAM, 0); + + if (args > 2) { + if (Pike_sp[2-args].type != PIKE_T_INT) + Pike_error("Bad argument 3 to port port->bind()\n"); + family = Pike_sp[2-args].u.integer; + if (family == AF_UNSPEC) + family = THIS->auto_switch_af ? THIS->curr_af : THIS->default_af; + } else { + family = THIS->auto_switch_af ? THIS->curr_af : THIS->default_af; + } + + fd=fd_socket(family, SOCK_STREAM, 0); if(fd < 0) { ERRNO=errno; pop_n_elems(args); @@ -2651,35 +2708,34 @@ return; } if (args) { - struct sockaddr_in addr; + SOCKADDR addr; char *name; int o; if (Pike_sp[-args].type != PIKE_T_INT && - (Pike_sp[-args].type != PIKE_T_STRING || - Pike_sp[-args].u.string->size_shift)) { + (Pike_sp[-args].type != PIKE_T_STRING || + Pike_sp[-args].u.string->size_shift)) { fd_close(fd); SIMPLE_BAD_ARG_ERROR("Stdio.File->open_socket", 1, "int|string (8bit)"); } if (args > 1) { if (Pike_sp[1-args].type != PIKE_T_STRING) { - fd_close(fd); - SIMPLE_BAD_ARG_ERROR("Stdio.File->open_socket", 1, "string"); + fd_close(fd); + SIMPLE_BAD_ARG_ERROR("Stdio.File->open_socket", 1, "string"); } name = Pike_sp[1-args].u.string->str; } else { name = NULL; } get_inet_addr(&addr, name, - (Pike_sp[-args].type == PIKE_T_STRING? - Pike_sp[-args].u.string->str : NULL), - (Pike_sp[-args].type == PIKE_T_INT? - Pike_sp[-args].u.integer : -1), 0); + (Pike_sp[-args].type == PIKE_T_STRING? + Pike_sp[-args].u.string->str : NULL), + (Pike_sp[-args].type == PIKE_T_INT? + Pike_sp[-args].u.integer : -1), 0, AF_UNSPEC); - o=1; if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0) { ERRNO=errno; fd_close(fd); pop_n_elems(args); @@ -2693,9 +2749,12 @@ push_int(0); return; } } - + + if (THIS->auto_switch_af) + THIS->curr_af = family; + init_fd(fd, FILE_READ | FILE_WRITE | fd_query_properties(fd, SOCKET_CAPABILITIES)); my_set_close_on_exec(fd,1); FD = fd; ERRNO=0; @@ -2826,9 +2885,9 @@ *! as a connection failure. */ static void file_connect(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; struct pike_string *dest_addr = NULL; struct pike_string *src_addr = NULL; struct svalue *dest_port = NULL; struct svalue *src_port = NULL; @@ -2856,9 +2915,10 @@ file_open_socket(0); } else { push_svalue(src_port); ref_push_string(src_addr); - file_open_socket(2); + push_int(SOCKADDR_IN(addr).sin_family); + file_open_socket(3); } if(UNSAFE_IS_ZERO(Pike_sp-1) || FD < 0) Pike_error("Stdio.File->connect(): Failed to open socket.\n"); pop_stack(); @@ -2867,9 +2927,9 @@ get_inet_addr(&addr, dest_addr->str, (dest_port->type == PIKE_T_STRING? dest_port->u.string->str : NULL), (dest_port->type == PIKE_T_INT? - dest_port->u.integer : -1), 0); + dest_port->u.integer : -1), 0, AF_UNSPEC); tmp=FD; THREADS_ALLOW(); tmp=fd_connect(tmp, (struct sockaddr *)&addr, sizeof(addr)); @@ -2892,14 +2952,101 @@ pop_n_elems(args); push_int(0); }else{ + if (THIS->auto_switch_af) + THIS->curr_af = SOCKADDR_IN(addr).sin_family; + ERRNO=0; pop_n_elems(args); push_int(1); } } +//! @decl void set_inet_options(mapping opts) +//! +//! Sets various options for the internet-related functions. The following +//! options are recognized in the mapping passed to the function: +//! +//! @mapping +//! @member int "default_af" +//! The internet address family that should be the default one. +//! +//! @member int "curr_af" +//! The family that should be considered the one in effect at this +//! moment. +//! +//! @member int "auto_switch_af" +//! Set to @tt{!=0@} if the address family should be switched +//! automatically whenever an internet address is bound. If this +//! feature is in effect the family will always match the most recent +//! address used. +//! @endmapping +//! +//! @param opts +//! Mapping with parameters. +//! +//! @seealso +//! @[get_inet_options()] +//! +static void file_set_inet_options(INT32 args) +{ + struct mapping *opts; + struct svalue *sv; + + get_all_args("File->set_inet_options", args, "%m", &opts); + + sv = simple_mapping_string_lookup(opts, "default_af"); + if (sv && sv->type == PIKE_T_INT) + THIS->default_af = sv->u.integer; + + sv = simple_mapping_string_lookup(opts, "curr_af"); + if (sv && sv->type == PIKE_T_INT) + THIS->curr_af = sv->u.integer; + + sv = simple_mapping_string_lookup(opts, "auto_switch_af"); + if (sv && sv->type == PIKE_T_INT) + THIS->auto_switch_af = sv->u.integer != 0; + + pop_n_elems(args); +} + +//! @decl mapping get_inet_options() +//! +//! Retrieve the information about the current internet options. For the +//! description of the returned mapping, see @[set_inet_options()]. +//! +//! @returns +//! A mapping filled with the internet options information. +//! +//! @seealso +//! @[set_inet_options()] +//! +static void file_get_inet_options(INT32 args) +{ + struct mapping *opts; + static struct pike_string *default_af = NULL; + static struct pike_string *curr_af = NULL; + static struct pike_string *auto_switch_af = NULL; + + pop_n_elems(args); + + if (!default_af) { + default_af = make_shared_string("default_af"); + curr_af = make_shared_string("curr_af"); + auto_switch_af = make_shared_string("auto_switch_af"); + } + + push_string(default_af); + push_int(THIS->default_af); + push_string(curr_af); + push_int(THIS->curr_af); + push_string(auto_switch_af); + push_int(THIS->auto_switch_af); + + f_aggregate_mapping(6); +} + static int isipnr(char *s) { int e,i; for(e=0;e<3;e++) @@ -2919,8 +3066,106 @@ if(*s) return 0; return 1; } +#define SOCKETINFO_PEER 0x01 +#define SOCKETINFO_LOCAL 0x02 + +typedef struct +{ + char *peer_addr; + int peer_port; + int peer_family; + char *local_addr; + int local_port; + int local_family; +} SOCKET_INFO; + +static INLINE void fill_socket_info(SOCKADDR *addr, + char **address, + int *port, + int *family) +{ + char *tmp = NULL; +#ifdef HAVE_INET_NTOP + size_t buflen = 0; + void *src = NULL; + + switch(SOCKADDR_IN(*addr).sin_family) { + case AF_INET: + buflen = INET_ADDRSTRLEN * sizeof(char); + src = (void*)&(SOCKADDR_IN(*addr).sin_addr); + *port = ntohs(SOCKADDR_IN(*addr).sin_port); + break; + +#ifdef HAVE_IPV6 + case AF_INET6: + buflen = INET6_ADDRSTRLEN * sizeof(char); + src = (void*)&(SOCKADDR_IN6(*addr).sin6_addr); + *port = ntohs(SOCKADDR_IN6(*addr).sin6_port); + break; +#endif /* HAVE_IPV6 */ + } + + *address = (char*)malloc(buflen); + if (!*address) + Pike_error("Out of memory.\n"); + + tmp = (char*)inet_ntop(SOCKADDR_IN(*addr).sin_family, + src, *address, buflen); + if (!tmp) { + free(*address); + Pike_error("Error converting IP number to string.\n"); + } + + *family = SOCKADDR_IN(*addr).sin_family; +#else /* HAVE_INET_NTOP */ + tmp = inet_ntoa(SOCKADDR_IN(*addr).sin_addr); + *port = ntohs(SOCKADDR_IN(*addr).sin_port); + *family = SOCKADDR_IN(*addr).sin_family; + *address = strdup(tmp); + if (!*address) + Pike_error("Out of memory.\n"); +#endif /* HAVE_INET_NTOP */ +} + +static int get_socket_info(SOCKET_INFO *si, int flags) +{ + SOCKADDR addr; + ACCEPT_SIZE_T len; + int ret; + + if (!flags || !si) + return 1; + + MEMSET(si, 0, sizeof(*si)); + len = sizeof(addr); + ret = 1; + if (flags && SOCKETINFO_PEER) { + ret = fd_getpeername(FD, (struct sockaddr*)&addr, &len); + if (ret < 0) { + ERRNO=errno; + return -1; + } + + fill_socket_info(&addr, &si->peer_addr, &si->peer_port, &si->peer_family); + ret = 0; + } + + if (flags && SOCKETINFO_LOCAL) { + ret = fd_getsockname(FD, (struct sockaddr*)&addr, &len); + if (ret < 0) { + ERRNO=errno; + return -1; + } + + fill_socket_info(&addr, &si->local_addr, &si->local_port, &si->local_family); + ret = 0; + } + + return ret; +} + /*! @decl string query_address() *! @decl string query_address(int(0..1) local) *! *! Get address and port of a socket end-point. @@ -2942,16 +3187,22 @@ *! @[connect()] */ static void file_query_address(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; int i; char buffer[496],*q; /* XOPEN GROUP thinks this variable should be a size_t. * BSD thinks it should be an int. */ ACCEPT_SIZE_T len; - + int port = 0; +#ifdef HAVE_INET_NTOP + size_t buflen = 0; + void *src = NULL; + char *tmp = NULL; +#endif + if(FD <0) Pike_error("Stdio.File->query_address(): Connection not open.\n"); len=sizeof(addr); @@ -2961,26 +3212,150 @@ }else{ i=fd_getpeername(FD,(struct sockaddr *)&addr,&len); } pop_n_elems(args); - if(i < 0 || len < (int)sizeof(addr)) + if(i < 0) { ERRNO=errno; push_int(0); return; } -#ifdef HAVE_INET_NTOP - inet_ntop(addr.sin_family, &addr.sin_addr, buffer, sizeof(buffer)-20); + +#ifdef HAVE_INET_NTOP + switch(SOCKADDR_IN(addr).sin_family) { + case AF_INET: + buflen = INET_ADDRSTRLEN * sizeof(char*); + src = (void*)&SOCKADDR_IN(addr).sin_addr; + port = SOCKADDR_IN(addr).sin_port; + break; + +#ifdef HAVE_IPV6 + case AF_INET6: + buflen = INET6_ADDRSTRLEN * sizeof(char*); + src = (void*)&SOCKADDR_IN6(addr).sin6_addr; + port = SOCKADDR_IN6(addr).sin6_port; + break; +#endif + } + + /* should use alloca if available */ + tmp = (char*)malloc(buflen); + if (!tmp) + Pike_error("Out of memory.\n"); + + q = (char*)inet_ntop(SOCKADDR_IN(addr).sin_family, + src, tmp, buflen); + + if (!q) + Pike_error("Error converting IP number to string.\n"); #else q=inet_ntoa(addr.sin_addr); - strncpy(buffer,q,sizeof(buffer)-20); - buffer[sizeof(buffer)-20]=0; + port = SOCKADDR_IN(addr).sin_port; #endif - sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(addr.sin_port))); + sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(port))); +#ifdef HAVE_INET_NTOP + free(q); +#endif + push_string(make_shared_string(buffer)); } +/*! @decl mapping query_socket_info() + *! + *! Get information about the socket this object corresponds to. + *! + *! This function is an extension to the @[query_addres()] function. + *! It returns in one call more information about the socket than + *! the above function. The returned mapping looks as follows: + *! + *! @mapping + *! @member string "local_ip" + *! The IP number of the local socket endpoint. + *! @member int "local_port" + *! The port number of the local socket endpoint. + *! @member int "local_family" + *! The address family of the local endpoint + *! @member string "remote_ip" + *! The IP number of the remote socket endpoint. + *! @member int "remote_port" + *! The port number of the remote socket endpoint. + *! @member int "remote_family" + *! The address family of the remote endpoint. + *! @endmapping + *! + *! If the file is not a socket, not connected, or some other error + *! occurrs, @tt{0@} (zero) will be returned. + *! + *! @seealso + *! @[query_address()] + */ +static void file_query_socket_info(INT32 args) +{ + SOCKADDR addr; + SOCKET_INFO si; + int ret; + static struct pike_string *ps_raddr = NULL; + static struct pike_string *ps_laddr = NULL; + static struct pike_string *ps_rport = NULL; + static struct pike_string *ps_lport = NULL; + static struct pike_string *ps_rfamily = NULL; + static struct pike_string *ps_lfamily = NULL; + + ret = get_socket_info(&si, SOCKETINFO_PEER | SOCKETINFO_LOCAL); + + if (ret > 0) + Pike_error("File->query_socket_info: INTERNAL ERROR.\n"); + + if (ret < 0) { + ERRNO=errno; + push_int(0); + return; + } + + pop_n_elems(args); + + if (!ps_raddr) { + ps_raddr = make_shared_string("remote_addr"); + add_ref(ps_raddr); + ps_laddr = make_shared_string("local_addr"); + add_ref(ps_laddr); + ps_rport = make_shared_string("remote_port"); + add_ref(ps_rport); + ps_lport = make_shared_string("local_port"); + add_ref(ps_lport); + ps_rfamily = make_shared_string("remote_family"); + add_ref(ps_rfamily); + ps_lfamily = make_shared_string("local_family"); + add_ref(ps_lfamily); + } + + push_string(ps_raddr); + push_string(make_shared_string(si.peer_addr)); + + push_string(ps_rport); + push_int(si.peer_port); + + push_string(ps_rfamily); + push_int(si.peer_family); + + push_string(ps_laddr); + push_string(make_shared_string(si.local_addr)); + + push_string(ps_lport); + push_int(si.local_port); + + push_string(ps_lfamily); + push_int(si.local_family); + + f_aggregate_mapping(12); + + if (si.peer_addr) + free(si.peer_addr); + if (si.local_addr) + free(si.local_addr); +} + /*! @decl Stdio.File `<<(string data) *! @decl Stdio.File `<<(mixed data) *! *! Write some data to a file. @@ -3029,8 +3404,17 @@ *! @[open()] */ static void file_create(INT32 args) { + struct inet_config_storage *gics; + + gics = (struct inet_config_storage*)get_storage(global_inet_config, + inet_config_program); + + THIS->default_af = gics->default_af; + THIS->curr_af = gics->default_af; + THIS->auto_switch_af = gics->auto_switch_af; + if(!args) return; if(Pike_sp[-args].type != PIKE_T_STRING && Pike_sp[-args].type != PIKE_T_INT) SIMPLE_BAD_ARG_ERROR("Stdio.File->create", 1, "int|string"); @@ -3682,8 +4066,10 @@ file_ref_program=end_program(); add_program_constant("Fd_ref",file_ref_program,0); port_setup_program(); + inet_config_setup_program(); + add_object_constant("_global_inet_config", global_inet_config, 0); init_sendfile(); init_udp(); add_integer_constant("PROP_IPC",fd_INTERPROCESSABLE,0); diff -U4 --new-file -r 7.5.orig/src/modules/files/file.h 7.5/src/modules/files/file.h --- 7.5.orig/src/modules/files/file.h 2003-04-23 13:17:15.000000000 +0200 +++ 7.5/src/modules/files/file.h 2003-04-23 18:57:53.000000000 +0200 @@ -41,8 +41,12 @@ #if defined(HAVE_FD_FLOCK) || defined(HAVE_FD_LOCKF) struct object *key; #endif struct object *myself; + + int default_af; + int curr_af; + int auto_switch_af; }; #ifdef _REENTRANT @@ -93,9 +97,9 @@ extern struct program *file_program; extern struct program *file_ref_program; -extern void get_inet_addr(struct sockaddr_in *addr,char *name,char *service, INT_TYPE port, int udp); +extern void get_inet_addr(SOCKADDR *addr,char *name,char *service, INT_TYPE port, int udp, int family); #define CBFUNCS(X) \ static void PIKE_CONCAT(file_,X) (int fd, void *data); \ static void PIKE_CONCAT(file_set_,X) (INT32 args); \ diff -U4 --new-file -r 7.5.orig/src/modules/files/inet_config.c 7.5/src/modules/files/inet_config.c --- 7.5.orig/src/modules/files/inet_config.c 1970-01-01 01:00:00.000000000 +0100 +++ 7.5/src/modules/files/inet_config.c 2003-04-23 18:57:53.000000000 +0200 @@ -0,0 +1,71 @@ +/*\ +||| This file a part of Pike, and is copyright by Fredrik Hubinette +||| Pike is distributed as GPL (General Public License) +||| See the files COPYING and DISCLAIMER for more information. +\*/ +/**/ +#define NO_PIKE_SHORTHAND +#include "global.h" +RCSID("$Id$"); +#include "interpret.h" +#include "svalue.h" +#include "stralloc.h" +#include "array.h" +#include "object.h" +#include "pike_macros.h" +#include "module_support.h" +#include "pike_error.h" +#include "pike_types.h" +#include "threads.h" +#include "program_id.h" + +#include "inet_config.h" + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +struct program *inet_config_program = NULL; +struct object *global_inet_config = NULL; + +#define THIS ((struct inet_config_storage*)(Pike_fp->current_storage)) + +static void init_config(struct object *o) +{ + THIS->default_af = AF_INET; + THIS->auto_switch_af = 1; +} + +static void make_global_inet_config() +{ + global_inet_config = low_clone(inet_config_program); + call_c_initializers(global_inet_config); +} + +void inet_config_setup_program(void) +{ + ptrdiff_t offset; + + start_new_program(); + + offset = ADD_STORAGE(struct inet_config_storage); + + map_variable("_default_af", "int", 0, + offset + OFFSETOF(inet_config_storage, default_af), + PIKE_T_INT); + + map_variable("_auto_switch_af", "int", 0, + offset + OFFSETOF(inet_config_storage, auto_switch_af), + PIKE_T_INT); + + set_init_callback(init_config); + inet_config_program = end_program(); + add_program_constant("InetConfig", inet_config_program, 0); + + make_global_inet_config(); +} + diff -U4 --new-file -r 7.5.orig/src/modules/files/inet_config.h 7.5/src/modules/files/inet_config.h --- 7.5.orig/src/modules/files/inet_config.h 1970-01-01 01:00:00.000000000 +0100 +++ 7.5/src/modules/files/inet_config.h 2003-04-23 18:57:53.000000000 +0200 @@ -0,0 +1,26 @@ +/*\ +||| This file a part of Pike, and is copyright by Fredrik Hubinette +||| Pike is distributed as GPL (General Public License) +||| See the files COPYING and DISCLAIMER for more information. +\*/ + +/* + * $Id$ + */ + +#ifndef INET_CONFIG_H +#define INET_CONFIG_H + +struct inet_config_storage +{ + int default_af; + int auto_switch_af; +}; + +void inet_config_setup_program(void); + +extern struct program *inet_config_program; +extern struct object *global_inet_config; + +#endif /* INET_CONFIG_H */ + diff -U4 --new-file -r 7.5.orig/src/modules/files/Makefile.in 7.5/src/modules/files/Makefile.in --- 7.5.orig/src/modules/files/Makefile.in 2000-08-27 20:29:27.000000000 +0200 +++ 7.5/src/modules/files/Makefile.in 2003-04-23 18:57:53.000000000 +0200 @@ -1,8 +1,8 @@ # $Id: Makefile.in,v 1.12 2000/08/27 18:29:27 mirar Exp $ @make_variables@ VPATH=@srcdir@:@srcdir@/../..:../.. -OBJS=file.o efuns.o socket.o termios.o sendfile.o udp.o stat.o +OBJS=file.o efuns.o inet_config.o socket.o termios.o sendfile.o udp.o stat.o MODULE_LDFLAGS=@LIBS@ MODULE_TESTS=local_tests CONFIG_HEADERS=@CONFIG_HEADERS@ diff -U4 --new-file -r 7.5.orig/src/modules/files/socket.c 7.5/src/modules/files/socket.c --- 7.5.orig/src/modules/files/socket.c 2003-04-23 13:17:15.000000000 +0200 +++ 7.5/src/modules/files/socket.c 2003-04-23 19:17:19.000000000 +0200 @@ -22,8 +22,10 @@ #include "file_machine.h" #include "file.h" +#include "inet_config.h" + RCSID("$Id: socket.c,v 1.69 2003/04/22 16:06:07 marcus Exp $"); #ifdef HAVE_SYS_TYPE_H #include @@ -63,8 +65,12 @@ #ifdef HAVE_SYS_SOCKETVAR_H #include #endif +#ifdef HAVE_NETINET_IN_H +#include +#endif + #include "dmalloc.h" /*! @module Stdio */ @@ -78,8 +84,11 @@ int xref; int my_errno; struct svalue accept_callback; struct svalue id; + int default_af; + int curr_af; + int auto_switch_af; }; #undef THIS #define THIS ((struct port *)(Pike_fp->current_storage)) @@ -244,11 +253,12 @@ *! @[accept] */ static void port_bind(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; int fd,tmp; - + int family; + do_close(THIS,Pike_fp->current_object); if(args < 1) SIMPLE_TOO_FEW_ARGS_ERROR("Port->bind", 1); @@ -257,10 +267,39 @@ (Pike_sp[-args].type != PIKE_T_STRING || Pike_sp[-args].u.string->size_shift)) SIMPLE_BAD_ARG_ERROR("Port->bind", 1, "int|string (8bit)"); - fd=fd_socket(AF_INET, SOCK_STREAM, 0); - + if (args > 3) { + if (Pike_sp[3-args].type != PIKE_T_INT) + Pike_error("Bad argument 4 to port port->bind()\n"); + family = Pike_sp[3-args].u.integer; + if (family == AF_UNSPEC) + family = THIS->auto_switch_af ? THIS->curr_af : THIS->default_af; + } else + family = THIS->auto_switch_af ? THIS->curr_af : THIS->default_af; + + if (args > 2 && Pike_sp[2-args].type==PIKE_T_STRING) { + get_inet_addr(&addr, Pike_sp[2-args].u.string->str, NULL, -1, 0, AF_UNSPEC); + if (THIS->auto_switch_af) + THIS->curr_af = SOCKADDR_IN(addr).sin_family; + family = SOCKADDR_IN(addr).sin_family; + } else { + switch(family) { + case AF_INET: + SOCKADDR_IN(addr).sin_addr.s_addr = htonl(INADDR_ANY); + break; + +#ifdef HAVE_IPV6 + case AF_INET6: + MEMCPY(SOCKADDR_IN6(addr).sin6_addr.s6_addr, + &in6addr_any, sizeof(in6addr_any)); + break; +#endif + } + } + + fd=fd_socket(family, SOCK_STREAM, 0); + if(fd < 0) { THIS->my_errno=errno; pop_n_elems(args); @@ -288,9 +327,9 @@ Pike_sp[2-args].u.string->str : NULL), (Pike_sp[-args].type == PIKE_T_STRING? Pike_sp[-args].u.string->str : NULL), (Pike_sp[-args].type == PIKE_T_INT? - Pike_sp[-args].u.integer : -1), 0); + Pike_sp[-args].u.integer : -1), 0, AF_UNSPEC); THREADS_ALLOW_UID(); tmp=fd_bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 || fd_listen(fd, 16384) < 0; THREADS_DISALLOW_UID(); @@ -333,8 +372,17 @@ * with the same arguments. */ static void port_create(INT32 args) { + struct inet_config_storage *gics; + + gics = (struct inet_config_storage*)get_storage(global_inet_config, + inet_config_program); + + THIS->default_af = gics->default_af; + THIS->curr_af = gics->default_af; + THIS->auto_switch_af = gics->auto_switch_af; + if(args) { if(Pike_sp[-args].type == PIKE_T_INT || (Pike_sp[-args].type == PIKE_T_STRING && @@ -379,14 +427,15 @@ */ static void port_accept(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; struct port *this=THIS; int fd; struct object *o; ACCEPT_SIZE_T len=0; - + struct my_file *nf; + if(THIS->fd < 0) Pike_error("port->accept(): Port not open.\n"); THREADS_ALLOW(); @@ -403,9 +452,13 @@ } my_set_close_on_exec(fd,1); o=file_make_object_from_fd(fd,FILE_READ | FILE_WRITE, SOCKET_CAPABILITIES); - + nf = (struct my_file*)o->storage; + nf->default_af = this->default_af; + nf->curr_af = this->curr_af; + nf->auto_switch_af = this->auto_switch_af; + pop_n_elems(args); push_object(o); } @@ -415,38 +468,156 @@ *! Document this function. */ static void socket_query_address(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; int i; char buffer[496],*q; ACCEPT_SIZE_T len; - + int port = 0; +#ifdef HAVE_INET_NTOP + size_t buflen = 0; + void *src = NULL; + char *tmp = NULL; +#endif + if(THIS->fd <0) Pike_error("socket->query_address(): Socket not bound yet.\n"); len=sizeof(addr); i=fd_getsockname(THIS->fd,(struct sockaddr *)&addr,&len); pop_n_elems(args); - if(i < 0 || len < (int)sizeof(addr)) + if(i < 0) { THIS->my_errno=errno; push_int(0); return; } #ifdef HAVE_INET_NTOP - inet_ntop(addr.sin_family, &addr.sin_addr, buffer, sizeof(buffer)-20); + switch(SOCKADDR_IN(addr).sin_family) { + case AF_INET: + buflen = INET_ADDRSTRLEN * sizeof(char*); + src = (void*)&SOCKADDR_IN(addr).sin_addr; + port = SOCKADDR_IN(addr).sin_port; + break; + +#ifdef HAVE_IPV6 + case AF_INET6: + buflen = INET6_ADDRSTRLEN * sizeof(char*); + src = (void*)&SOCKADDR_IN6(addr).sin6_addr; + port = SOCKADDR_IN6(addr).sin6_port; + break; +#endif + } + + /* TODO: should use alloca whenever possible */ + tmp = (char*)malloc(buflen); + if (!tmp) + Pike_error("Out of memory.\n"); + + q = (char*)inet_ntop(SOCKADDR_IN(addr).sin_family, + src, tmp, buflen); + + if (!q) + Pike_error("Error converting IP number to string.\n"); #else q=inet_ntoa(addr.sin_addr); strncpy(buffer,q,sizeof(buffer)-20); buffer[sizeof(buffer)-20]=0; #endif - sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(addr.sin_port))); + sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(port))); +#ifdef HAVE_INET_NTOP + free(q); +#endif + push_string(make_shared_string(buffer)); } +//! @decl void set_inet_options(mapping opts) +//! +//! Sets various options for the internet-related functions. The following +//! options are recognized in the mapping passed to the function: +//! +//! @mapping +//! @member int "default_af" +//! The internet address family that should be the default one. +//! +//! @member int "curr_af" +//! The family that should be considered the one in effect at this +//! moment. +//! +//! @member int "auto_switch_af" +//! Set to @tt{!=0@} if the address family should be switched +//! automatically whenever an internet address is bound. If this +//! feature is in effect the family will always match the most recent +//! address used. +//! @endmapping +//! +//! @param opts +//! Mapping with parameters. +//! +//! @seealso +//! @[get_inet_options()] +//! +static void port_set_inet_options(INT32 args) +{ + struct mapping *opts; + struct svalue *sv; + + get_all_args("port->set_inet_options", args, "%m", &opts); + + sv = simple_mapping_string_lookup(opts, "default_af"); + if (sv && sv->type == PIKE_T_INT) + THIS->default_af = sv->u.integer; + + sv = simple_mapping_string_lookup(opts, "curr_af"); + if (sv && sv->type == PIKE_T_INT) + THIS->curr_af = sv->u.integer; + + sv = simple_mapping_string_lookup(opts, "auto_switch_af"); + if (sv && sv->type == PIKE_T_INT) + THIS->auto_switch_af = sv->u.integer != 0; + + pop_n_elems(args); +} + +//! @decl mapping get_inet_options() +//! +//! Retrieve the information about the current internet options. For the +//! description of the returned mapping, see @[set_inet_options()]. +//! +//! @returns +//! A mapping filled with the internet options information. +//! +//! @seealso +//! @[set_inet_options()] +//! +static void port_get_inet_options(INT32 args) +{ + struct mapping *opts; + static struct pike_string *default_af = NULL; + static struct pike_string *curr_af = NULL; + static struct pike_string *auto_switch_af = NULL; + + pop_n_elems(args); + + if (!default_af) { + default_af = make_shared_string("default_af"); + curr_af = make_shared_string("curr_af"); + auto_switch_af = make_shared_string("auto_switch_af"); + } + + push_string(default_af); + push_int(THIS->default_af); + push_string(curr_af); + push_int(THIS->curr_af); + push_string(auto_switch_af); + push_int(THIS->auto_switch_af); + + f_aggregate_mapping(6); +} static void init_port_struct(struct object *o) { THIS->fd=-1; @@ -457,8 +628,11 @@ #endif THIS->id.u.integer=0; THIS->accept_callback.type=PIKE_T_INT; THIS->my_errno=0; + THIS->default_af = AF_INET; + THIS->curr_af = AF_INET; + THIS->auto_switch_af = 0; } static void exit_port_struct(struct object *o) { @@ -491,9 +665,9 @@ offset=ADD_STORAGE(struct port); map_variable("_accept_callback","mixed",0,offset+OFFSETOF(port,accept_callback),PIKE_T_MIXED); map_variable("_id","mixed",0,offset+OFFSETOF(port,id),PIKE_T_MIXED); /* function(int|string,void|mixed,void|string:int) */ - ADD_FUNCTION("bind",port_bind,tFunc(tOr(tInt,tStr) tOr(tVoid,tMix) tOr(tVoid,tStr),tInt),0); + ADD_FUNCTION("bind",port_bind,tFunc(tOr(tInt,tStr) tOr(tVoid,tMix) tOr(tVoid,tStr) tOr(tVoid,tInt),tInt),0); /* function(int,void|mixed:int) */ ADD_FUNCTION("listen_fd",port_listen_fd,tFunc(tInt tOr(tVoid,tMix),tInt),0); /* function(mixed:mixed) */ ADD_FUNCTION("set_id",port_set_id,tFunc(tMix,tMix),0); @@ -506,9 +680,13 @@ /* function(:object) */ ADD_FUNCTION("accept",port_accept,tFunc(tNone,tObjIs_STDIO_FD),0); /* function(void|string|int,void|mixed,void|string:void) */ ADD_FUNCTION("create",port_create,tFunc(tOr3(tVoid,tStr,tInt) tOr(tVoid,tMix) tOr(tVoid,tStr),tVoid),0); - + /* function(mapping:void) */ + ADD_FUNCTION("set_inet_options",port_set_inet_options,tFunc(tMapping,tVoid),0); + /* function(:mapping) */ + ADD_FUNCTION("get_inet_options",port_get_inet_options,tFunc(tVoid,tMapping),0); + set_init_callback(init_port_struct); set_exit_callback(exit_port_struct); port_program = end_program(); diff -U4 --new-file -r 7.5.orig/src/modules/files/udp.c 7.5/src/modules/files/udp.c --- 7.5.orig/src/modules/files/udp.c 2003-04-23 13:17:15.000000000 +0200 +++ 7.5/src/modules/files/udp.c 2003-04-23 18:57:53.000000000 +0200 @@ -161,11 +161,12 @@ *! Binds a port for recieving or transmitting UDP. */ static void udp_bind(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; int o; int fd,tmp; + int family; #if !defined(SOL_IP) && defined(HAVE_GETPROTOBYNAME) static int ip_proto_num = -1; #endif /* !SOL_IP && HAVE_GETPROTOBYNAME */ @@ -183,9 +184,18 @@ fd_close(FD); FD = -1; } - fd = fd_socket(AF_INET, THIS->type, THIS->protocol); + if (args > 2) { + if (Pike_sp[2-args].type != PIKE_T_INT) + Pike_error("Bad argument 4 to port port->bind()\n"); + family = Pike_sp[2-args].u.integer; + if (family == AF_UNSPEC) + family = AF_INET; + } else + family = AF_INET; + + fd = fd_socket(family, THIS->type, THIS->protocol); if(fd < 0) { pop_n_elems(args); THIS->my_errno=errno; @@ -224,9 +234,9 @@ #ifdef IP_HDRINCL /* From mtr-0.28:net.c: FreeBSD wants this to avoid sending out packets with protocol type RAW to the network. */ - if (THIS->type==SOCK_RAW && THIS->protocol==255 /* raw */) + if (family == AF_INET && THIS->type==SOCK_RAW && THIS->protocol==255 /* raw */) if(fd_setsockopt(fd, SOL_IP, IP_HDRINCL, (char *)&o, sizeof(int))) Pike_error("UDP->bind: setsockopt IP_HDRINCL failed\n"); #endif /* IP_HDRINCL */ @@ -234,9 +244,9 @@ Pike_sp[1-args].u.string->str : NULL), (Pike_sp[-args].type == PIKE_T_STRING? Pike_sp[-args].u.string->str : NULL), (Pike_sp[-args].type == PIKE_T_INT? - Pike_sp[-args].u.integer : -1), 1); + Pike_sp[-args].u.integer : -1), 1, AF_UNSPEC); THREADS_ALLOW_UID(); tmp=fd_bind(fd, (struct sockaddr *)&addr, sizeof(addr))<0; @@ -392,11 +402,17 @@ */ void udp_read(INT32 args) { int flags = 0, res=0, fd, e; - struct sockaddr_in from; + SOCKADDR from; char buffer[UDP_BUFFSIZE]; - ACCEPT_SIZE_T fromlen = sizeof(struct sockaddr_in); + ACCEPT_SIZE_T fromlen = sizeof(SOCKADDR); + int port = 0; +#ifdef HAVE_INET_NTOP + size_t buflen = 0; + void *src = NULL; + char *tmp, *q; +#endif if(args) { if(Pike_sp[-args].u.integer & 1) { @@ -469,16 +485,16 @@ push_string( make_shared_binary_string(buffer, res) ); push_text("ip"); #ifdef HAVE_INET_NTOP - push_text( inet_ntop( from.sin_family, &from.sin_addr, + push_text( inet_ntop( SOCKADDR_IN(from).sin_family, &SOCKADDR_IN(from).sin_addr, buffer, sizeof(buffer) ) ); #else push_text( inet_ntoa( from.sin_addr ) ); #endif push_text("port"); - push_int(ntohs(from.sin_port)); + push_int(ntohs(SOCKADDR_IN(from).sin_port)); f_aggregate_mapping( 6 ); } /*! @decl int send(string to, int|string port, string message) @@ -496,9 +512,9 @@ void udp_sendto(INT32 args) { int flags = 0, fd, e; ptrdiff_t res = 0; - struct sockaddr_in to; + SOCKADDR to; char *str; ptrdiff_t len; if(FD < 0) @@ -528,17 +544,17 @@ get_inet_addr(&to, Pike_sp[-args].u.string->str, (Pike_sp[1-args].type == PIKE_T_STRING? Pike_sp[1-args].u.string->str : NULL), (Pike_sp[1-args].type == PIKE_T_INT? - Pike_sp[1-args].u.integer : -1), 1); + Pike_sp[1-args].u.integer : -1), 1, AF_UNSPEC); fd = FD; str = Pike_sp[2-args].u.string->str; len = Pike_sp[2-args].u.string->len; do { THREADS_ALLOW(); - res = fd_sendto( fd, str, len, flags, (struct sockaddr *)&to, sizeof(to)); + res = fd_sendto( fd, str, len, flags, (struct sockaddr *)&to, sizeof(SOCKADDR)); e = errno; THREADS_DISALLOW(); check_threads_etc(); @@ -680,9 +696,9 @@ *! @[bind()], @[query_address()] */ static void udp_connect(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; struct pike_string *dest_addr = NULL; struct svalue *dest_port = NULL; int tmp; @@ -707,9 +723,9 @@ get_inet_addr(&addr, dest_addr->str, (dest_port->type == PIKE_T_STRING? dest_port->u.string->str : NULL), (dest_port->type == PIKE_T_INT? - dest_port->u.integer : -1), 0); + dest_port->u.integer : -1), 0, AF_UNSPEC); tmp=FD; THREADS_ALLOW(); tmp=fd_connect(tmp, (struct sockaddr *)&addr, sizeof(addr)); @@ -733,14 +749,20 @@ *! zero is returned. */ static void udp_query_address(INT32 args) { - struct sockaddr_in addr; + SOCKADDR addr; int i; int fd = THIS->fd; char buffer[496],*q; ACCEPT_SIZE_T len; - + int port = 0; +#ifdef HAVE_INET_NTOP + size_t buflen = 0; + void *src = NULL; + char *tmp; +#endif + if(fd <0) Pike_error("UDP->query_address(): Port not bound yet.\n"); THREADS_ALLOW(); @@ -757,15 +779,15 @@ return; } #ifdef HAVE_INET_NTOP - inet_ntop(addr.sin_family, &addr.sin_addr, buffer, sizeof(buffer)-20); + inet_ntop(SOCKADDR_IN(addr).sin_family, &SOCKADDR_IN(addr).sin_addr, buffer, sizeof(buffer)-20); #else q=inet_ntoa(addr.sin_addr); strncpy(buffer,q,sizeof(buffer)-20); buffer[sizeof(buffer)-20]=0; #endif - sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(addr.sin_port))); + sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(SOCKADDR_IN(addr).sin_port))); push_string(make_shared_string(buffer)); } diff -U4 --new-file -r 7.5.orig/src/modules/system/configure.in 7.5/src/modules/system/configure.in --- 7.5.orig/src/modules/system/configure.in 2003-04-23 13:17:16.000000000 +0200 +++ 7.5/src/modules/system/configure.in 2003-04-23 18:28:04.000000000 +0200 @@ -6,8 +6,9 @@ AC_CHECK_LIB(bind, __inet_ntoa) AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(nsl, gethostbyname) +AC_CHECK_LIB(nsl, gethostbyname2) dnl For Cygwin AC_CHECK_LIB(cygipc, shmget) @@ -19,11 +20,11 @@ AC_HAVE_HEADERS(syslog.h sys/syslog.h sys/types.h errno.h unistd.h pwd.h \ sys/conf.h sys/socket.h netinet/in.h arpa/inet.h netdb.h stdarg.h \ sys/utsname.h pwd.h passwd.h shadow.h grp.h sys/stat.h winsock.h \ - sys/systeminfo.h windows.h sys/param.h utime.h sys/utime.h sys/id.h \ + sys/systeminfo.h windows.h sys/param.h utime.h sys/utime.h sys/id.h \ sys/time.h sys/shm.h sys/mman.h fcntl.h sys/fcntl.h netinfo/ni.h \ - sys/prctl.h cygwin/ipc.h cygwin/sem.h cygwin/shm.h) + sys/prctl.h cygwin/ipc.h cygwin/sem.h cygwin/shm.h net/if.h) # some Linux systems have a broken resource.h that compiles anyway /Mirar AC_MSG_CHECKING([for working sys/resource.h]) AC_CACHE_VAL(pike_cv_sys_resource_h, @@ -66,9 +67,11 @@ getpwnam_r getpwent_r getpwuid_r \ getspnam_r innetgr utime sleep usleep nanosleep \ getrlimit setrlimit \ setitimer getitimer mmap munmap \ - gettimeofday settimeofday prctl inet_ntoa inet_ntop) + gettimeofday settimeofday prctl inet_ntoa inet_ntop \ + gethostbyname2 getaddrinfo freeaddrinfo gai_strerror \ + if_nametoindex if_indextoname if_nameindex if_freenameindex) if test "x$ac_cv_func_setpgrp" = "xyes"; then AC_MSG_CHECKING([if setpgrp takes two arguments (BSD)]) diff -U4 --new-file -r 7.5.orig/src/modules/system/system.c 7.5/src/modules/system/system.c --- 7.5.orig/src/modules/system/system.c 2003-04-23 13:17:16.000000000 +0200 +++ 7.5/src/modules/system/system.c 2003-04-23 19:27:03.000000000 +0200 @@ -112,8 +112,12 @@ #ifdef HAVE_NETINFO_NI_H #include #endif +#ifdef HAVE_NET_IF_H +#include +#endif + #include "dmalloc.h" #define sp Pike_sp @@ -131,8 +135,10 @@ #else /* !HAVE_IN_ADDR_T */ #define IN_ADDR_T unsigned int #endif /* HAVE_IN_ADDR_T */ +/* #define GETADDR_DEBUG */ + /* * Functions */ @@ -1677,45 +1683,152 @@ #endif #endif /* REENTRANT */ +#ifdef HAVE_GETADDRINFO +static int my_getaddrinfo(SOCKADDR *addr, int family, char *name, int flags) +{ + struct addrinfo *ainf = NULL, *tmp; + struct addrinfo hints; + int ret; + int pref_family; + + MEMSET((char*)&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_flags = flags; + + ret = getaddrinfo(name, NULL, &hints, &ainf); + + if (ret) { + if (ret == EAI_SYSTEM) + Pike_error("System error while getting address info: %d\n", errno); + +#ifdef HAVE_GAI_STRERROR + Pike_error("Error getting address info: %s\n", gai_strerror(ret)); +#else + Pike_error("Error getting address info: %d\n", ret); +#endif + } + + if (family == AF_UNSPEC) + pref_family = AF_INET; + else + pref_family = family; + + tmp = ainf; + while (tmp) { + if (tmp->ai_family == pref_family) { + switch (pref_family) { + case AF_INET: + MEMCPY(&((struct sockaddr_in*)addr)->sin_addr, + tmp->ai_addr, tmp->ai_addrlen); + ((struct sockaddr_in*)addr)->sin_family = AF_INET; + freeaddrinfo(ainf); + return 0; + +#ifdef HAVE_IPV6 + case AF_INET6: + MEMCPY(&((struct sockaddr_in6*)addr)->sin6_addr, + tmp->ai_addr, tmp->ai_addrlen); + ((struct sockaddr_in6*)addr)->sin6_family = AF_INET6; + freeaddrinfo(ainf); + return 0; +#endif + } + } + + tmp = tmp->ai_next; + } + freeaddrinfo(ainf); + + return 1; +} +#endif + /* this is used from modules/file, and modules/spider! */ -void get_inet_addr(struct sockaddr_in *addr,char *name,char *service, INT_TYPE port, int udp) +/* TODO: this is not working for IPv6 yet! */ +void get_inet_addr(SOCKADDR *addr,char *name,char *service, INT_TYPE port, int udp, int family) { - MEMSET((char *)addr,0,sizeof(struct sockaddr_in)); + MEMSET((char *)addr,0,sizeof(SOCKADDR)); - addr->sin_family = AF_INET; + ((struct sockaddr_in*)addr)->sin_family = family; if(!name || !strcmp(name,"*")) { - addr->sin_addr.s_addr=htonl(INADDR_ANY); + switch (family) { + case AF_INET: + ((struct sockaddr_in*)addr)->sin_addr.s_addr=htonl(INADDR_ANY); + return; + +#ifdef HAVE_IPV6 + case AF_INET6: + MEMCPY(((struct sockaddr_in6*)addr)->sin6_addr.s6_addr, + &in6addr_any, sizeof(in6addr_any)); + return; +#endif + case AF_UNSPEC: + Pike_error("Cannot use wildcard addresses with unspecified address family.\n"); + + default: + Pike_error("Unsupported address family.\n"); + } } +#ifndef HAVE_INET_PTON else if(my_isipnr(name)) /* I do not entirely trust inet_addr */ { if (((IN_ADDR_T)inet_addr(name)) == ((IN_ADDR_T)-1)) - Pike_error("Malformed ip number.\n"); + Pike_error("Malformed IPv4 number.\n"); - addr->sin_addr.s_addr = inet_addr(name); + ((struct sockaddr_in*)addr)->sin_addr.s_addr = inet_addr(name); + ((struct sockaddr_in*)addr)->sin_family = AF_INET; + return; } - else +#else /* HAVE_INET_PTON */ { -#ifdef GETHOST_DECLARE - GETHOST_DECLARE; - CALL_GETHOSTBYNAME(name); + int ret; - if(!ret) { - if (strlen(name) < 1024) { - Pike_error("Invalid address '%s'\n",name); - } else { - Pike_error("Invalid address\n"); - } + ret = inet_pton(AF_INET, name, &((struct sockaddr_in*)addr)->sin_addr); + if (ret < 0 && errno == EAFNOSUPPORT) + Pike_error("Address family %s (%d) is not supported.\n", "AF_INET", AF_INET); + + if (!ret) { +#ifdef HAVE_IPV6 + ret = inet_pton(AF_INET6, name, &((struct sockaddr_in6*)addr)->sin6_addr); + if (ret < 0 && errno == EAFNOSUPPORT) + Pike_error("Address family %s (%d) is not supported.\n", "AF_INET6", AF_INET6); + + if (ret) { + ((struct sockaddr_in6*)addr)->sin6_family = AF_INET6; + return; + } +#endif /* HAVE_IPV6 */ + } else { + ((struct sockaddr_in*)addr)->sin_family = AF_INET; + return; } + } +#endif /* HAVE_INET_PTON */ + +#ifdef HAVE_GETADDRINFO + if (my_getaddrinfo(addr, family, name, 0)) + Pike_error("Couldn't convert address '%s' to a valid IP number.\n", name); +#elif defined(GETHOST_DECLARE) + GETHOST_DECLARE; + CALL_GETHOSTBYNAME(name); + + if(!ret) { + if (strlen(name) < 1024) { + Pike_error("Invalid address '%s'\n",name); + } else { + Pike_error("Invalid address\n"); + } + } #ifdef HAVE_H_ADDR_LIST - MEMCPY((char *)&(addr->sin_addr), + MEMCPY((char *)&(SOCKADDR_IN(addr)->sin_addr), (char *)ret->h_addr_list[0], ret->h_length); #else - MEMCPY((char *)&(addr->sin_addr), + MEMCPY((char *)&(SOCKADDR_IN(addr)->sin_addr), (char *)ret->h_addr, ret->h_length); #endif #else @@ -1724,35 +1837,34 @@ } else { Pike_error("Invalid address\n"); } #endif - } if(service) { #ifdef GETSERV_DECLARE GETSERV_DECLARE; CALL_GETSERVBYNAME(service, (udp? "udp":"tcp")); if(!ret) { if (strlen(service) < 1024) { - Pike_error("Invalid service '%s'\n",service); + Pike_error("Invalid service '%s'\n",service); } else { - Pike_error("Invalid service\n"); + Pike_error("Invalid service\n"); } } - addr->sin_port = ret->s_port; + SOCKADDR_IN(*addr).sin_port = ret->s_port; #else if (strlen(service) < 1024) { Pike_error("Invalid service '%s'\n",service); } else { Pike_error("Invalid service\n"); } #endif } else if(port >= 0) - addr->sin_port = htons((u_short)port); + SOCKADDR_IN(*addr).sin_port = htons((u_short)port); else - addr->sin_port = 0; + SOCKADDR_IN(*addr).sin_port = 0; } #ifdef GETHOST_DECLARE @@ -1899,12 +2011,144 @@ #endif } #endif +#ifdef HAVE_IF_NAMETOINDEX +/*! @decl int if_nametoindex(string ifname) + *! + *! Returns an index of the specified network interface. + *! + *! @returns + *! The returned integer is an arbitrarily assigned integer index of the + *! device in the operating system network tables. If the value returned + *! is 0 then no interface of that name exists. + *! + *! @note + *! This is a SUSv2 (POSIX) call available on the compliant Unix or + *! Unix-like systems + *! + *! @seealso + *! @[if_indextoname()], @[if_nameindex()] + */ +void f_if_nametoindex(INT32 args) +{ + char *ifname; + + get_all_args("if_nametoindex", args, "%s", &ifname); + + pop_n_elems(args); + push_int(if_nametoindex(ifname)); +} +#endif /* HAVE_IF_NAMETOINDEX */ + +#ifdef HAVE_IF_INDEXTONAME +/*! @decl string if_indextoname(int ifidx) + *! + *! Returns a name associated with the interface of the specified index. + *! + *! @returns + *! The returned string is a name of the interface selected by the given + *! index in the operating system network tables. If the value returned + *! is 0 then no interface of that index exists. + *! + *! @note + *! This is a SUSv2 (POSIX) call available on the compliant Unix or + *! Unix-like systems + *! + *! @seealso + *! @[if_nametoindex()], @[if_nameindex()] + */ +void f_if_indextoname(INT32 args) +{ + unsigned int ifidx; + char *buf; + + get_all_args("if_nametoindex", args, "%i", &ifidx); + + buf = (char*)malloc(IFNAMSIZ * sizeof(char)); + if (!buf) + Pike_error("if_indextoname: Out of memory.\n"); + + pop_n_elems(args); + + MEMSET(buf, 0, IFNAMSIZ); + push_string(make_shared_string(if_indextoname(ifidx,buf))); + free(buf); +} +#endif /* HAVE_IF_INDEXTONAME */ + +#ifdef HAVE_IF_NAMEINDEX +/*! @decl array(mapping(string:mixed)) if_nameindex(void) + *! + *! Returns an array of mappings that describe all the interfaces present + *! on the host machine. + *! + *! @returns + *! The returned array stores mappings of the following structure: + *! @mapping + *! @member int "index" + *! The index of the interface. + *! @member string "name" + *! The name of the interface. + *! @endmapping + *! + *! @note + *! This is a SUSv2 (POSIX) call available on the compliant Unix or + *! Unix-like systems + *! + *! @seealso + *! @[if_nametoindex()], @[if_indextoname()] + */ +void f_if_nameindex(INT32 args) +{ + static struct pike_string *ps_index = NULL; + static struct pike_string *ps_name = NULL; + struct if_nameindex *iar; + struct if_nameindex *tmp; + int cnt; + struct array *ret; + + iar = if_nameindex(); + if (!iar) { + push_int(0); + return; + } + + if (!ps_index) { + ps_index = make_shared_string("index"); + ps_name = make_shared_string("name"); + } + + pop_n_elems(args); + + tmp = iar; + cnt = 0; + while(tmp && (tmp->if_index && tmp->if_name)) { + push_string(ps_index); + push_int(tmp->if_index); + + push_string(ps_name); + push_string(make_shared_string(tmp->if_name)); + + f_aggregate_mapping(4); + + tmp++; + cnt++; + } + + ret = aggregate_array(cnt); + +#ifdef HAVE_IF_FREENAMEINDEX + if_freenameindex(iar); +#endif + + push_array(ret); +} +#endif /* HAVE_IF_NAMEINDEX */ + extern void init_passwd(void); extern void init_system_memory(void); - #ifdef HAVE_SLEEP /*! @decl int sleep(int seconds) *! @@ -3008,8 +3252,23 @@ ADD_FUNCTION2("gethostbyaddr", f_gethostbyaddr,tFunc(tStr,tArray), 0, OPT_TRY_OPTIMIZE); #endif /* GETHOST_DECLARE */ +#ifdef HAVE_IF_NAMETOINDEX + ADD_EFUN("if_nametoindex", f_if_nametoindex, tFunc(tStr,tInt), 0); + ADD_FUNCTION("if_nametoindex", f_if_nametoindex, tFunc(tStr,tInt), 0); +#endif /* HAVE_IF_NAMETOINDEX */ + +#ifdef HAVE_IF_INDEXTONAME + ADD_EFUN("if_indextoname", f_if_indextoname, tFunc(tInt,tStr), 0); + ADD_FUNCTION("if_indextoname", f_if_indextoname, tFunc(tInt,tStr), 0); +#endif /* HAVE_IF_INDEXTONAME */ + +#ifdef HAVE_IF_NAMEINDEX + ADD_EFUN("if_nameindex", f_if_nameindex, tFunc(tVoid,tArr(tMap(tString,tMixed))), 0); + ADD_FUNCTION("if_nameindex", f_if_nameindex, tFunc(tVoid,tArr(tMap(tString,tMixed))), 0); +#endif /* HAVE_IF_NAMEINDEX */ + /* * From syslog.c: */ #ifdef HAVE_SYSLOG @@ -3088,8 +3347,14 @@ ADD_FUNCTION("get_netinfo_property", f_get_netinfo_property, tFunc(tStr tStr tStr, tArray), 0); #endif /* NETINFO */ + ADD_INT_CONSTANT("AF_INET", AF_INET, 0); + +#ifdef HAVE_AF_INET6 + ADD_INT_CONSTANT("AF_INET6", AF_INET6, 0); +#endif + init_passwd(); init_system_memory(); #if defined(GETHOSTBYNAME_MUTEX_EXISTS) || defined(GETSERVBYNAME_MUTEX_EXISTS)