diff options
81 files changed, 952 insertions, 334 deletions
diff --git a/Makefile.w32 b/Makefile.w32 index 1117ce7..ffa9b9a 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -15,7 +15,7 @@ remctl.exe: remctl.obj getopt.obj messages.obj asprintf.obj winsock.obj xmalloc. remctl.lib: remctl.dll -remctl.dll: api.obj client-v1.obj client-v2.obj error.obj open.obj network.obj asprintf.obj concat.obj gss-tokens.obj gss-errors.obj inet_aton.obj inet_ntop.obj strlcpy.obj strlcat.obj tokens.obj messages.obj winsock.obj xmalloc.obj libremctl.res +remctl.dll: api.obj client-v1.obj client-v2.obj error.obj open.obj network.obj fdflag.obj asprintf.obj concat.obj gss-tokens.obj gss-errors.obj inet_aton.obj inet_ntop.obj strlcpy.obj strlcat.obj tokens.obj messages.obj winsock.obj xmalloc.obj libremctl.res link $(ldebug) $(lflags) /LIBPATH:"$(KRB5SDK)"\lib\$(CPU) /dll /out:$@ /export:remctl /export:remctl_new /export:remctl_open /export:remctl_close /export:remctl_command /export:remctl_commandv /export:remctl_error /export:remctl_output $** $(GSSAPI_LIB) ws2_32.lib advapi32.lib {client\}.c{}.obj:: @@ -22,10 +22,23 @@ remctl 2.19 (unreleased) but the documentation said this was not allowed. Fix the documentation to match the implementation. + Use PATH_KRB5_CONFIG as the environment variable to set the path to + krb5-config rather than KRB5_CONFIG when running configure, since the + latter is used by the Kerberos libraries to specify an alternative + path to krb5.conf. + Update to rra-c-util 3.9: + * Prefer gssapi/gssapi.h to gssapi.h. + * Include strings.h if it exists for strncasecmp on some platforms. + * getaddrinfo replacement now portable to systems with bad netdb.h. + * Avoid krb5-config if --with-gssapi-{include,lib} are given. + * Add Windows implementation of fdflag_nonblocking. + * The network_connect utility functions now take an optional timeout. * Wait longer for remctld to start in remctl tests. * Use an atexit handler to clean up after Kerberos tests. + * Use typedef instead of #define for socklen_t and sig_atomic_t. + * Stop providing or using INADDR_LOOPBACK for portability reasons. Update to C TAP Harness 1.8: @@ -187,18 +187,21 @@ INSTALLATION (UNIX) You can also individually set the paths to the include directory and the library directory with --with-gssapi-include and --with-gssapi-lib. You may need to do this if Autoconf can't figure out whether to use lib, - lib32, or lib64 on your platform. Note that these settings aren't used - if a krb5-config script is found. + lib32, or lib64 on your platform. To specify a particular krb5-config script to use, either set the - KRB5_CONFIG environment variable or pass it to configure like: + PATH_KRB5_CONFIG environment variable or pass it to configure like: - ./configure KRB5_CONFIG=/path/to/krb5-config + ./configure PATH_KRB5_CONFIG=/path/to/krb5-config To not use krb5-config and force library probing even if there is a - krb5-config script on your path, set KRB5_CONFIG to a nonexistent path: + krb5-config script on your path, set PATH_KRB5_CONFIG to a nonexistent + path: - ./configure KRB5_CONFIG=/nonexistent + ./configure PATH_KRB5_CONFIG=/nonexistent + + krb5-config is not used and library probing is always done if either + --with-gssapi-include or --with-gssapi-lib are given. remctl will automatically build with PCRE support if pcre-config or the PCRE library are found. You can pass --with-pcre to configure to diff --git a/client/open.c b/client/open.c index 725cd00..9acd0a1 100644 --- a/client/open.c +++ b/client/open.c @@ -56,7 +56,7 @@ internal_connect(struct remctl *r, const char *host, unsigned short port) gai_strerror(status)); return INVALID_SOCKET; } - fd = network_connect(ai, r->source); + fd = network_connect(ai, r->source, 0); freeaddrinfo(ai); if (fd == INVALID_SOCKET) { internal_set_error(r, "cannot connect to %s (port %hu): %s", host, diff --git a/configure.ac b/configure.ac index f949261..96e55a1 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ RRA_LIB_GSSAPI AC_HEADER_STDBOOL AC_CHECK_HEADERS([sys/bitypes.h sys/filio.h sys/select.h sys/uio.h syslog.h]) AC_CHECK_DECLS([snprintf, vsnprintf]) +AC_CHECK_DECLS([h_errno], [], [], [#include <netdb.h>]) AC_CHECK_DECLS([inet_aton, inet_ntoa], [], [], [#include <sys/types.h> #include <netinet/in.h> @@ -39,14 +40,10 @@ AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include <sys/types.h> #include <sys/socket.h>]) AC_TYPE_LONG_LONG_INT -AC_CHECK_TYPE([sig_atomic_t], [], - [AC_DEFINE([sig_atomic_t], [int], - [Define to int if <signal.h> does not define.])], +AC_CHECK_TYPES([sig_atomic_t], [], [], [#include <sys/types.h> #include <signal.h>]) -AC_CHECK_TYPE([socklen_t], , - [AC_DEFINE([socklen_t], [int], - [Define to int if <sys/socket.h> does not define.])], +AC_CHECK_TYPES([socklen_t], [], [], [#include <sys/types.h> #include <sys/socket.h>]) AC_CHECK_TYPES([struct sockaddr_in6], diff --git a/m4/gssapi.m4 b/m4/gssapi.m4 index 6c8c9b6..deaa432 100644 --- a/m4/gssapi.m4 +++ b/m4/gssapi.m4 @@ -3,7 +3,8 @@ dnl dnl Finds the compiler and linker flags for linking with GSS-API libraries. dnl Provides the --with-gssapi, --with-gssapi-include, and --with-gssapi-lib dnl configure option to specify a non-standard path to the GSS-API libraries. -dnl Uses krb5-config where available unless reduced dependencies is requested. +dnl Uses krb5-config where available unless reduced dependencies is requested +dnl or --with-gssapi-include or --with-gssapi-lib are given. dnl dnl Provides the macro RRA_LIB_GSSAPI and sets the substitution variables dnl GSSAPI_CPPFLAGS, GSSAPI_LDFLAGS, and GSSAPI_LIBS. Also provides @@ -13,6 +14,9 @@ dnl to restore those settings to before the last RRA_LIB_GSSAPI_SWITCH. dnl dnl Depends on RRA_ENABLE_REDUCED_DEPENDS and RRA_SET_LDFLAGS. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Copyright 2005, 2006, 2007, 2008, 2009, 2011 dnl The Board of Trustees of the Leland Stanford Junior University @@ -118,6 +122,30 @@ AC_DEFUN([_RRA_LIB_GSSAPI_CHECK], _RRA_LIB_GSSAPI_PATHS _RRA_LIB_GSSAPI_MANUAL])]) +dnl Determine GSS-API compiler and linker flags from krb5-config. +AC_DEFUN([_RRA_LIB_GSSAPI_CONFIG], +[AC_ARG_VAR([PATH_KRB5_CONFIG], [Path to krb5-config]) + AS_IF([test x"$rra_gssapi_root" != x && test -z "$PATH_KRB5_CONFIG"], + [AS_IF([test -x "${rra_gssapi_root}/bin/krb5-config"], + [PATH_KRB5_CONFIG="${rra_gssapi_root}/bin/krb5-config"])], + [AC_PATH_PROG([PATH_KRB5_CONFIG], [krb5-config], [], + [${PATH}:/usr/kerberos/bin])]) + AS_IF([test x"$PATH_KRB5_CONFIG" != x && test -x "$PATH_KRB5_CONFIG"], + [AC_CACHE_CHECK([for gssapi support in krb5-config], + [rra_cv_lib_gssapi_config], + [AS_IF(["$PATH_KRB5_CONFIG" 2>&1 | grep gssapi >/dev/null 2>&1], + [rra_cv_lib_gssapi_config=yes], + [rra_cv_lib_gssapi_config=no])]) + AS_IF([test "$rra_cv_lib_gssapi_config" = yes], + [GSSAPI_CPPFLAGS=`"$PATH_KRB5_CONFIG" --cflags gssapi 2>/dev/null` + GSSAPI_LIBS=`"$PATH_KRB5_CONFIG" --libs gssapi 2>/dev/null`], + [GSSAPI_CPPFLAGS=`"$PATH_KRB5_CONFIG" --cflags 2>/dev/null` + GSSAPI_LIBS=`"$PATH_KRB5_CONFIG" --libs 2>/dev/null`]) + GSSAPI_CPPFLAGS=`echo "$GSSAPI_CPPFLAGS" | sed 's%-I/usr/include ?%%'` + _RRA_LIB_GSSAPI_CHECK], + [_RRA_LIB_GSSAPI_PATHS + _RRA_LIB_GSSAPI_MANUAL])]) + dnl The main macro. AC_DEFUN([RRA_LIB_GSSAPI], [AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) @@ -150,25 +178,8 @@ AC_DEFUN([RRA_LIB_GSSAPI], AS_IF([test x"$rra_reduced_depends" = xtrue], [_RRA_LIB_GSSAPI_PATHS _RRA_LIB_GSSAPI_REDUCED], - [AC_ARG_VAR([KRB5_CONFIG], [Path to krb5-config]) - AS_IF([test x"$rra_gssapi_root" != x && test -z "$KRB5_CONFIG"], - [AS_IF([test -x "${rra_gssapi_root}/bin/krb5-config"], - [KRB5_CONFIG="${rra_gssapi_root}/bin/krb5-config"])], - [AC_PATH_PROG([KRB5_CONFIG], [krb5-config], [], - [${PATH}:/usr/kerberos/bin])]) - AS_IF([test x"$KRB5_CONFIG" != x && test -x "$KRB5_CONFIG"], - [AC_CACHE_CHECK([for gssapi support in krb5-config], - [rra_cv_lib_gssapi_config], - [AS_IF(["$KRB5_CONFIG" 2>&1 | grep gssapi >/dev/null 2>&1], - [rra_cv_lib_gssapi_config=yes], - [rra_cv_lib_gssapi_config=no])]) - AS_IF([test "$rra_cv_lib_gssapi_config" = yes], - [GSSAPI_CPPFLAGS=`"$KRB5_CONFIG" --cflags gssapi 2>/dev/null` - GSSAPI_LIBS=`"$KRB5_CONFIG" --libs gssapi 2>/dev/null`], - [GSSAPI_CPPFLAGS=`"$KRB5_CONFIG" --cflags 2>/dev/null` - GSSAPI_LIBS=`"$KRB5_CONFIG" --libs 2>/dev/null`]) - GSSAPI_CPPFLAGS=`echo "$GSSAPI_CPPFLAGS" \ - | sed 's%-I/usr/include ?%%'` - _RRA_LIB_GSSAPI_CHECK], - [_RRA_LIB_GSSAPI_PATHS - _RRA_LIB_GSSAPI_MANUAL])])]) + [AS_IF([test x"$rra_gssapi_includedir" = x \ + && test x"$rra_gssapi_libdir" = x], + [_RRA_LIB_GSSAPI_CONFIG], + [_RRA_LIB_GSSAPI_PATHS + _RRA_LIB_GSSAPI_MANUAL])])]) diff --git a/m4/inet-ntoa.m4 b/m4/inet-ntoa.m4 index 5e68d9c..6cf46d3 100644 --- a/m4/inet-ntoa.m4 +++ b/m4/inet-ntoa.m4 @@ -6,6 +6,9 @@ dnl may still not function with gcc on some platforms (such as IRIX). dnl Provides RRA_FUNC_INET_NTOA and defines HAVE_INET_NTOA if inet_ntoa is dnl present and working. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Copyright 1999, 2000, 2001, 2003 Russ Allbery <rra@stanford.edu> dnl Copyright 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University diff --git a/m4/ld-version.m4 b/m4/ld-version.m4 index 97b731d..03d2436 100644 --- a/m4/ld-version.m4 +++ b/m4/ld-version.m4 @@ -4,6 +4,9 @@ dnl Probes whether the linker supports --version-script with a simple version dnl script that only defines a single version. Sets the Automake conditional dnl HAVE_LD_VERSION_SCRIPT based on whether it is supported. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Based on the gnulib ld-version-script macro from Simon Josefsson dnl Copyright 2010 diff --git a/m4/lib-depends.m4 b/m4/lib-depends.m4 index 0aa0d1e..b5185f3 100644 --- a/m4/lib-depends.m4 +++ b/m4/lib-depends.m4 @@ -9,6 +9,9 @@ dnl dnl This macro doesn't do much but is defined separately so that other macros dnl can require it with AC_REQUIRE. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Copyright 2005, 2006, 2007 dnl The Board of Trustees of the Leland Stanford Junior University diff --git a/m4/lib-pathname.m4 b/m4/lib-pathname.m4 index a639b17..fd5a5a1 100644 --- a/m4/lib-pathname.m4 +++ b/m4/lib-pathname.m4 @@ -12,6 +12,9 @@ dnl dnl This file also provides the Autoconf macro RRA_SET_LIBDIR, which sets the dnl libdir variable to PREFIX/lib{,32,64} as appropriate. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Copyright 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University @@ -15,6 +15,9 @@ dnl variables will be empty. dnl dnl Depends on RRA_SET_LDFLAGS. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Copyright 2010 dnl The Board of Trustees of the Leland Stanford Junior University diff --git a/m4/snprintf.m4 b/m4/snprintf.m4 index 51c9202..cd585ef 100644 --- a/m4/snprintf.m4 +++ b/m4/snprintf.m4 @@ -9,6 +9,9 @@ dnl dnl Provides RRA_FUNC_SNPRINTF, which adds snprintf.o to LIBOBJS unless a dnl fully working snprintf is found. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Copyright 2006, 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University diff --git a/m4/socket.m4 b/m4/socket.m4 index 3c9e8dc..338a4a4 100644 --- a/m4/socket.m4 +++ b/m4/socket.m4 @@ -9,6 +9,9 @@ dnl RRA_MACRO_SA_LEN dnl dnl They use a separate internal source macro to make the code easier to read. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Copyright 2008, 2009, 2011 dnl The Board of Trustees of the Leland Stanford Junior University dnl Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009 diff --git a/m4/vamacros.m4 b/m4/vamacros.m4 index 62cf28f..af98f6a 100644 --- a/m4/vamacros.m4 +++ b/m4/vamacros.m4 @@ -13,6 +13,9 @@ dnl #define macro(args...) fprintf(stderr, args) dnl dnl They set HAVE_C99_VAMACROS or HAVE_GNU_VAMACROS as appropriate. dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl dnl Written by Russ Allbery <rra@stanford.edu> dnl Copyright 2006, 2008, 2009 dnl The Board of Trustees of the Leland Stanford Junior University diff --git a/portable/asprintf.c b/portable/asprintf.c index d085b64..0093070 100644 --- a/portable/asprintf.c +++ b/portable/asprintf.c @@ -4,6 +4,9 @@ * Provides the same functionality as the standard GNU library routines * asprintf and vasprintf for those platforms that don't have them. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/daemon.c b/portable/daemon.c index 8e614e3..1a3e25f 100644 --- a/portable/daemon.c +++ b/portable/daemon.c @@ -4,6 +4,9 @@ * Provides the same functionality as the library function daemon for those * systems that don't have it. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/dummy.c b/portable/dummy.c index 94333a6..50052ec 100644 --- a/portable/dummy.c +++ b/portable/dummy.c @@ -5,6 +5,9 @@ * supply, Automake builds an empty library and then calls ar with nonsensical * arguments. Ensure that libportable always contains at least one symbol. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/getaddrinfo.c b/portable/getaddrinfo.c index a0f6ad3..2a5d430 100644 --- a/portable/getaddrinfo.c +++ b/portable/getaddrinfo.c @@ -16,6 +16,9 @@ * needed to date. Adding IPv6 support isn't worth it; systems with IPv6 * support should already support getaddrinfo natively. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -33,6 +36,26 @@ #include <errno.h> +/* We need access to h_errno to map errors from gethostbyname. */ +#if !HAVE_DECL_H_ERRNO +extern int h_errno; +#endif + +/* + * The netdb constants, which aren't always defined (particularly if h_errno + * isn't declared). We also make sure that a few of the less-used ones are + * defined so that we can deal with them in case statements. + */ +#ifndef HOST_NOT_FOUND +# define HOST_NOT_FOUND 1 +# define TRY_AGAIN 2 +# define NO_RECOVERY 3 +# define NO_DATA 4 +#endif +#ifndef NETDB_INTERNAL +# define NETDB_INTERNAL -1 +#endif + /* * If we're running the test suite, rename the functions to avoid conflicts * with the system version. Note that we don't rename the structures and @@ -46,11 +69,13 @@ const char *test_gai_strerror(int); void test_freeaddrinfo(struct addrinfo *); int test_getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); +#endif /* * If the native platform doesn't support AI_NUMERICSERV or AI_NUMERICHOST, * pick some other values for them. */ +#if TESTING # if AI_NUMERICSERV == 0 # undef AI_NUMERICSERV # define AI_NUMERICSERV 0x0080 @@ -61,20 +86,6 @@ int test_getaddrinfo(const char *, const char *, const struct addrinfo *, # endif #endif -/* Table of strings corresponding to the EAI_* error codes. */ -static const char * const gai_errors[] = { - "Host name lookup failure", /* 1 EAI_AGAIN */ - "Invalid flag value", /* 2 EAI_BADFLAGS */ - "Unknown server error", /* 3 EAI_FAIL */ - "Unsupported address family", /* 4 EAI_FAMILY */ - "Memory allocation failure", /* 5 EAI_MEMORY */ - "Host unknown or not given", /* 6 EAI_NONAME */ - "Service not supported for socket", /* 7 EAI_SERVICE */ - "Unsupported socket type", /* 8 EAI_SOCKTYPE */ - "System error", /* 9 EAI_SYSTEM */ - "Supplied buffer too small", /* 10 EAI_OVERFLOW */ -}; - /* * Value representing all of the hint flags set. Linux uses flags up to * 0x0400, so be sure not to break when testing on that platform. @@ -89,18 +100,32 @@ static const char * const gai_errors[] = { # define AI_INTERNAL_ALL 0x007f #endif +/* Table of strings corresponding to the EAI_* error codes. */ +static const char * const gai_errors[] = { + "Host name lookup failure", /* 1 EAI_AGAIN */ + "Invalid flag value", /* 2 EAI_BADFLAGS */ + "Unknown server error", /* 3 EAI_FAIL */ + "Unsupported address family", /* 4 EAI_FAMILY */ + "Memory allocation failure", /* 5 EAI_MEMORY */ + "Host unknown or not given", /* 6 EAI_NONAME */ + "Service not supported for socket", /* 7 EAI_SERVICE */ + "Unsupported socket type", /* 8 EAI_SOCKTYPE */ + "System error", /* 9 EAI_SYSTEM */ + "Supplied buffer too small", /* 10 EAI_OVERFLOW */ +}; + /* Macro to set the len attribute of sockaddr_in. */ #if HAVE_STRUCT_SOCKADDR_SA_LEN -# define sin_set_length(s) ((s)->sin_len = sizeof(struct sockaddr_in)) +# define sin_set_length(s) ((s)->sin_len = sizeof(struct sockaddr_in)) #else -# define sin_set_length(s) /* empty */ +# define sin_set_length(s) /* empty */ #endif /* * Used for iterating through arrays. ARRAY_SIZE returns the number of * elements in the array (useful for a < upper bound in a for loop). */ -#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) /* @@ -378,7 +403,10 @@ getaddrinfo(const char *nodename, const char *servname, else { if (servname == NULL) return EAI_NONAME; - addr.s_addr = (flags & AI_PASSIVE) ? INADDR_ANY : INADDR_LOOPBACK; + if ((flags & AI_PASSIVE) == AI_PASSIVE) + addr.s_addr = INADDR_ANY; + else + addr.s_addr = htonl(0x7f000001UL); ai = gai_addrinfo_new(socktype, NULL, addr, port); if (ai == NULL) return EAI_MEMORY; diff --git a/portable/getaddrinfo.h b/portable/getaddrinfo.h index 37e335b..5bd50d1 100644 --- a/portable/getaddrinfo.h +++ b/portable/getaddrinfo.h @@ -9,6 +9,9 @@ * This file should generally be included by way of portable/socket.h rather * than directly. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/getnameinfo.c b/portable/getnameinfo.c index bc422ae..8e06611 100644 --- a/portable/getnameinfo.c +++ b/portable/getnameinfo.c @@ -13,6 +13,9 @@ * needed so far. Adding IPv6 support isn't worth it; systems with IPv6 * support should already support getnameinfo natively. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -60,7 +63,7 @@ try_name(const char *name, char *node, socklen_t nodelen, int *status) { if (strchr(name, '.') == NULL) return 0; - if (strlen(name) > nodelen - 1) + if (strlen(name) + 1 > (size_t) nodelen) *status = EAI_OVERFLOW; else { strlcpy(node, name, nodelen); @@ -108,7 +111,7 @@ lookup_name(const struct in_addr *addr, char *node, socklen_t nodelen, /* Just convert the address to ASCII. */ name = inet_ntoa(*addr); - if (strlen(name) > nodelen - 1) + if (strlen(name) + 1 > (size_t) nodelen) return EAI_OVERFLOW; strlcpy(node, name, nodelen); return 0; @@ -131,7 +134,7 @@ lookup_service(unsigned short port, char *service, socklen_t servicelen, protocol = (flags & NI_DGRAM) ? "udp" : "tcp"; srv = getservbyport(htons(port), protocol); if (srv != NULL) { - if (strlen(srv->s_name) > servicelen - 1) + if (strlen(srv->s_name) + 1 > (size_t) servicelen) return EAI_OVERFLOW; strlcpy(service, srv->s_name, servicelen); return 0; diff --git a/portable/getnameinfo.h b/portable/getnameinfo.h index 3e71b8d..c6f8dd0 100644 --- a/portable/getnameinfo.h +++ b/portable/getnameinfo.h @@ -8,6 +8,9 @@ * This file should generally be included by way of portable/socket.h rather * than directly. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -53,11 +56,16 @@ BEGIN_DECLS +/* Default to a hidden visibility for all portability functions. */ +#pragma GCC visibility push(hidden) + /* Function prototypes. */ int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, socklen_t nodelen, - char *service, socklen_t servicelen, int flags) - __attribute__((__visibility__("hidden"))); + char *service, socklen_t servicelen, int flags); + +/* Undo default visibility change. */ +#pragma GCC visibility pop END_DECLS diff --git a/portable/getopt.c b/portable/getopt.c index 0ff49ca..06350ab 100644 --- a/portable/getopt.c +++ b/portable/getopt.c @@ -6,6 +6,9 @@ * since remctl doesn't use GNU long options, and the code has been rearranged * and reworked somewhat to fit with my coding style. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 1997, 2000, 2001, 2002 Benjamin Sittler * Copyright 2008 Russ Allbery <rra@stanford.edu> * diff --git a/portable/getopt.h b/portable/getopt.h index 160ff6f..d3b6f85 100644 --- a/portable/getopt.h +++ b/portable/getopt.h @@ -6,6 +6,9 @@ * since remctl doesn't use GNU long options, and the code has been rearranged * and reworked somewhat to fit with my coding style. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 1997, 2000, 2001, 2002 Benjamin Sittler * Copyright 2008 Russ Allbery <rra@stanford.edu> * @@ -39,9 +42,8 @@ BEGIN_DECLS -/* The primary interface. Call repeatedly to return each option. */ -int getopt(int argc, char *argv[], const char *opts) - __attribute__((__visibility__("hidden"))); +/* Default to a hidden visibility for all portability functions. */ +#pragma GCC visibility push(hidden) /* * The current element in the argv array or, if getopt returns -1, the index @@ -58,6 +60,12 @@ extern int optopt; /* The argument to an option. */ extern char *optarg; +/* The primary interface. Call repeatedly to return each option. */ +int getopt(int argc, char *argv[], const char *opts); + +/* Undo default visibility change. */ +#pragma GCC visibility pop + END_DECLS #endif /* !HAVE_GETOPT */ diff --git a/portable/gssapi-mech.c b/portable/gssapi-mech.c index a7facfc..938c94d 100644 --- a/portable/gssapi-mech.c +++ b/portable/gssapi-mech.c @@ -1,13 +1,26 @@ /* - * Define the Kerberos v5 GSS-API mechanism OID. + * Define the Kerberos GSS-API mechanism OID. * - * This short bit of code exposes the Kerberos v5 GSS-API mechanism OID has + * This short bit of code exposes the Kerberos GSS-API mechanism OID has * gss_mech_krb5 on platforms that don't have GSS_KRB5_MECHANISM or * gss_mech_krb5, such as Solaris 10. * * On Solaris 10, we could call gss_str_to_oid to convert "kerberos_v5" to an * OID or to parse the numeric form of an OID, but this doesn't rely on * configuration files and is just as portable in practice. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Written by Russ Allbery <rra@stanford.edu> + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work. */ #include <portable/gssapi.h> diff --git a/portable/gssapi.h b/portable/gssapi.h index 533a189..13a326e 100644 --- a/portable/gssapi.h +++ b/portable/gssapi.h @@ -4,6 +4,19 @@ * This header tries to encapsulate the differences between the MIT and * Heimdal GSS-API implementations and the differences between various * versions. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Written by Russ Allbery <rra@stanford.edu> + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work. */ #ifndef PORTABLE_GSSAPI_H diff --git a/portable/inet_aton.c b/portable/inet_aton.c index 2de0a61..0767d20 100644 --- a/portable/inet_aton.c +++ b/portable/inet_aton.c @@ -5,6 +5,9 @@ * inet_aton for those platforms that don't have it. inet_aton is * thread-safe. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/inet_ntoa.c b/portable/inet_ntoa.c index 68d02c5..dafdd70 100644 --- a/portable/inet_ntoa.c +++ b/portable/inet_ntoa.c @@ -6,6 +6,9 @@ * as on IRIX when using gcc to compile). inet_ntoa is not thread-safe since * it uses static storage (inet_ntop should be used instead when available). * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/inet_ntop.c b/portable/inet_ntop.c index 4408b39..9724ff8 100644 --- a/portable/inet_ntop.c +++ b/portable/inet_ntop.c @@ -7,6 +7,9 @@ * call inet_ntop unconditionally without needing to worry about whether the * host supports IPv6. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/macros.h b/portable/macros.h index 78fd495..eed772a 100644 --- a/portable/macros.h +++ b/portable/macros.h @@ -1,6 +1,9 @@ /* * Portability macros used in include files. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/setenv.c b/portable/setenv.c index 9a0044f..8a4302c 100644 --- a/portable/setenv.c +++ b/portable/setenv.c @@ -4,6 +4,9 @@ * Provides the same functionality as the standard library routine setenv for * those platforms that don't have it. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/snprintf.c b/portable/snprintf.c index ab3121c..91c8491 100644 --- a/portable/snprintf.c +++ b/portable/snprintf.c @@ -8,6 +8,9 @@ * Please do not reformat or otherwise change this file more than necessary so * that later merges with the original source are easy. Bug fixes and * improvements should be sent back to the original author. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. */ /* diff --git a/portable/socket.h b/portable/socket.h index cc15a33..89d3459 100644 --- a/portable/socket.h +++ b/portable/socket.h @@ -13,7 +13,10 @@ * Windows. It ensures that inet_aton, inet_ntoa, and inet_ntop are available * and properly prototyped. * - * Copyright 2008, 2009 + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2008, 2009, 2011 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006, 2007 * by Internet Systems Consortium, Inc. ("ISC") @@ -63,98 +66,45 @@ #include <portable/getaddrinfo.h> #include <portable/getnameinfo.h> -BEGIN_DECLS - -/* - * Provide prototypes for inet_aton and inet_ntoa if not prototyped in the - * system header files since they're occasionally available without proper - * prototypes. - */ -#if !HAVE_DECL_INET_ATON -extern int inet_aton(const char *, struct in_addr *); -#endif -#if !HAVE_DECL_INET_NTOA -extern const char * inet_ntoa(const struct in_addr); -#endif -#if !HAVE_INET_NTOP -# ifdef _WIN32 -extern const char * inet_ntop(int, const void *, char *, int); -# else -extern const char * inet_ntop(int, const void *, char *, socklen_t) - __attribute__((__visibility__("hidden"))); -# endif -#endif - -/* - * Used for portability to Windows, which requires different functions be - * called to close sockets, send data to or read from sockets, and get socket - * errors than the regular functions and variables. Windows also uses SOCKET - * to store socket descriptors instead of an int. - * - * socket_init must be called before socket functions are used and - * socket_shutdown at the end of the program. socket_init may return failure, - * but this interface doesn't have a way to retrieve the exact error. - * - * socket_close, socket_read, and socket_write must be used instead of the - * standard functions. On Windows, closesocket must be called instead of - * close for sockets and recv and send must always be used instead of read and - * write. - * - * When reporting errors from socket functions, use socket_errno and - * socket_strerror instead of errno and strerror. When setting errno to - * something for socket errors (to preserve errors through close, for - * example), use socket_set_errno instead of just assigning to errno. - * - * Socket file descriptors must be passed and stored in variables of type - * socket_type rather than an int. Use INVALID_SOCKET for invalid socket file - * descriptors rather than -1, and compare to INVALID_SOCKET when testing - * whether operations succeed. - */ -#ifdef _WIN32 -int socket_init(void); -# define socket_shutdown() WSACleanup() -# define socket_close(fd) closesocket(fd) -# define socket_read(fd, b, s) recv((fd), (b), (s), 0) -# define socket_write(fd, b, s) send((fd), (b), (s), 0) -# define socket_errno WSAGetLastError() -# define socket_set_errno(e) WSASetLastError(e) -const char *socket_strerror(int); -typedef SOCKET socket_type; -#else -# define socket_init() 1 -# define socket_shutdown() /* empty */ -# define socket_close(fd) close(fd) -# define socket_read(fd, b, s) read((fd), (b), (s)) -# define socket_write(fd, b, s) write((fd), (b), (s)) -# define socket_errno errno -# define socket_set_errno(e) errno = (e) -# define socket_strerror(e) strerror(e) -# define INVALID_SOCKET -1 -typedef int socket_type; -#endif - -/* Some systems don't define INADDR_LOOPBACK. */ -#ifndef INADDR_LOOPBACK -# define INADDR_LOOPBACK 0x7f000001UL +/* Define socklen_t if it's not available in sys/socket.h. */ +#ifndef HAVE_SOCKLEN_T +typedef socklen_t int; #endif /* - * Defined by RFC 3493, used to store a generic address. Note that this - * doesn't do the alignment mangling that RFC 3493 does; it's not clear if - * that needs be added. However, I've not gotten any complaints yet (probably - * because nearly everyone now has sockaddr_storage). + * Defined by RFC 3493, used to store a generic address. All of the extra + * goop here is to ensure that the structs are appropriately aligned on + * platforms that may require 64-bit alignment for the embedded addresses. */ #if !HAVE_STRUCT_SOCKADDR_STORAGE +# define SS_MAXSIZE_ 128 +# ifdef HAVE_LONG_LONG_INT +# define SS_ALIGNSIZE_ sizeof(long long) +# define SS_ALIGNTYPE_ long long +# else +# define SS_ALIGNSIZE_ sizeof(long) +# define SS_ALIGNTYPE_ long +# endif # if HAVE_STRUCT_SOCKADDR_SA_LEN +# define SS_PAD1SIZE_ (SS_ALIGNSIZE_ - 2 * sizeof(unsigned char)) +# define SS_PAD2SIZE_ \ + (SS_MAXSIZE_ - (2 * sizeof(unsigned char) + SS_PAD1SIZE_ + SS_ALIGNSIZE_)) struct sockaddr_storage { unsigned char ss_len; unsigned char ss_family; - unsigned char __padding[128 - 2]; + char __ss_pad1[SS_PAD1SIZE_]; + SS_ALIGNTYPE_ __ss_align; + char __ss_pad2[SS_PAD2SIZE_]; }; # else +# define SS_PAD1SIZE_ (SS_ALIGNSIZE_ - sizeof(unsigned char)) +# define SS_PAD2SIZE_ \ + (SS_MAXSIZE_ - (sizeof(unsigned char) + SS_PAD1SIZE_ + SS_ALIGNSIZE_)) struct sockaddr_storage { unsigned short ss_family; - unsigned char __padding[128 - 2]; + char __ss_pad1[SS_PAD1SIZE_]; + SS_ALIGNTYPE_ __ss_align; + char __ss_pad2[SS_PAD2SIZE_]; }; # endif #endif @@ -238,6 +188,82 @@ struct sockaddr_storage { # define EAFNOSUPPORT EDOM #endif +BEGIN_DECLS + +/* + * Provide prototypes for inet_aton and inet_ntoa if not prototyped in the + * system header files since they're occasionally available without proper + * prototypes. + */ +#if !HAVE_DECL_INET_ATON +extern int inet_aton(const char *, struct in_addr *); +#endif +#if !HAVE_DECL_INET_NTOA +extern const char *inet_ntoa(const struct in_addr); +#endif + +/* Default to a hidden visibility for all portability functions. */ +#pragma GCC visibility push(hidden) + +#if !HAVE_INET_NTOP +# ifdef _WIN32 +extern const char *inet_ntop(int, const void *, char *, int); +# else +extern const char *inet_ntop(int, const void *, char *, socklen_t); +# endif +#endif + +/* + * Used for portability to Windows, which requires different functions be + * called to close sockets, send data to or read from sockets, and get socket + * errors than the regular functions and variables. Windows also uses SOCKET + * to store socket descriptors instead of an int. + * + * socket_init must be called before socket functions are used and + * socket_shutdown at the end of the program. socket_init may return failure, + * but this interface doesn't have a way to retrieve the exact error. + * + * socket_close, socket_read, and socket_write must be used instead of the + * standard functions. On Windows, closesocket must be called instead of + * close for sockets and recv and send must always be used instead of read and + * write. + * + * When reporting errors from socket functions, use socket_errno and + * socket_strerror instead of errno and strerror. When setting errno to + * something for socket errors (to preserve errors through close, for + * example), use socket_set_errno instead of just assigning to errno. + * + * Socket file descriptors must be passed and stored in variables of type + * socket_type rather than an int. Use INVALID_SOCKET for invalid socket file + * descriptors rather than -1, and compare to INVALID_SOCKET when testing + * whether operations succeed. + */ +#ifdef _WIN32 +int socket_init(void); +# define socket_shutdown() WSACleanup() +# define socket_close(fd) closesocket(fd) +# define socket_read(fd, b, s) recv((fd), (b), (s), 0) +# define socket_write(fd, b, s) send((fd), (b), (s), 0) +# define socket_errno WSAGetLastError() +# define socket_set_errno(e) WSASetLastError(e) +const char *socket_strerror(int); +typedef SOCKET socket_type; +#else +# define socket_init() 1 +# define socket_shutdown() /* empty */ +# define socket_close(fd) close(fd) +# define socket_read(fd, b, s) read((fd), (b), (s)) +# define socket_write(fd, b, s) write((fd), (b), (s)) +# define socket_errno errno +# define socket_set_errno(e) errno = (e) +# define socket_strerror(e) strerror(e) +# define INVALID_SOCKET -1 +typedef int socket_type; +#endif + +/* Undo default visibility change. */ +#pragma GCC visibility pop + END_DECLS #endif /* !PORTABLE_SOCKET_H */ diff --git a/portable/stdbool.h b/portable/stdbool.h index 5632f16..6f2fc7e 100644 --- a/portable/stdbool.h +++ b/portable/stdbool.h @@ -5,6 +5,9 @@ * following the C99 specification, on hosts that don't have stdbool.h. This * logic is based heavily on the example in the Autoconf manual. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/strlcat.c b/portable/strlcat.c index 69fcb5e..3bee4ee 100644 --- a/portable/strlcat.c +++ b/portable/strlcat.c @@ -9,6 +9,9 @@ * space available in the destination buffer, not just the amount of space * remaining. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/strlcpy.c b/portable/strlcpy.c index b83c86e..df75fd8 100644 --- a/portable/strlcpy.c +++ b/portable/strlcpy.c @@ -8,6 +8,9 @@ * total space required is returned. The destination string is not nul-filled * like strncpy does, just nul-terminated. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/system.h b/portable/system.h index 6b04793..1fee43a 100644 --- a/portable/system.h +++ b/portable/system.h @@ -13,11 +13,15 @@ * #include <stddef.h> * #include <stdint.h> * #include <string.h> + * #include <strings.h> * #include <unistd.h> * * Missing functions are provided via #define or prototyped if available from * the portable helper library. Also provides some standard #defines. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -45,6 +49,9 @@ #include <stdlib.h> #include <sys/types.h> #include <string.h> +#if HAVE_STRINGS_H +# include <strings.h> +#endif #if HAVE_INTTYPES_H # include <inttypes.h> #endif @@ -63,6 +70,38 @@ /* Get the bool type. */ #include <portable/stdbool.h> +/* Windows provides snprintf under a different name. */ +#ifdef _WIN32 +# define snprintf _snprintf +#endif + +/* Define sig_atomic_t if it's not available in signal.h. */ +#ifndef HAVE_SIG_ATOMIC_T +typedef sig_atomic_t int; +#endif + +/* + * POSIX requires that these be defined in <unistd.h>. If one of them has + * been defined, all the rest almost certainly have. + */ +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +# define STDOUT_FILENO 1 +# define STDERR_FILENO 2 +#endif + +/* + * C99 requires va_copy. Older versions of GCC provide __va_copy. Per the + * Autoconf manual, memcpy is a generally portable fallback. + */ +#ifndef va_copy +# ifdef __va_copy +# define va_copy(d, s) __va_copy((d), (s)) +# else +# define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) +# endif +#endif + BEGIN_DECLS /* Default to a hidden visibility for all portability functions. */ @@ -103,31 +142,4 @@ extern size_t strlcpy(char *, const char *, size_t); END_DECLS -/* Windows provides snprintf under a different name. */ -#ifdef _WIN32 -# define snprintf _snprintf -#endif - -/* - * POSIX requires that these be defined in <unistd.h>. If one of them has - * been defined, all the rest almost certainly have. - */ -#ifndef STDIN_FILENO -# define STDIN_FILENO 0 -# define STDOUT_FILENO 1 -# define STDERR_FILENO 2 -#endif - -/* - * C99 requires va_copy. Older versions of GCC provide __va_copy. Per the - * Autoconf manual, memcpy is a generally portable fallback. - */ -#ifndef va_copy -# ifdef __va_copy -# define va_copy(d, s) __va_copy((d), (s)) -# else -# define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) -# endif -#endif - #endif /* !PORTABLE_SYSTEM_H */ diff --git a/portable/uio.h b/portable/uio.h index e9ef1a8..3bd1f96 100644 --- a/portable/uio.h +++ b/portable/uio.h @@ -5,6 +5,9 @@ * (primarily Windows). Currently, the corresponding readv and writev * functions are not provided or prototyped here. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/portable/winsock.c b/portable/winsock.c index 10032ca..fc65463 100644 --- a/portable/winsock.c +++ b/portable/winsock.c @@ -4,6 +4,9 @@ * Provides supporting functions and wrappers that help with portability to * the Windows socket API. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/asprintf-t.c b/tests/portable/asprintf-t.c index 79cdd76..4513a85 100644 --- a/tests/portable/asprintf-t.c +++ b/tests/portable/asprintf-t.c @@ -1,6 +1,9 @@ /* * asprintf and vasprintf test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/daemon-t.c b/tests/portable/daemon-t.c index 8451811..9f62732 100644 --- a/tests/portable/daemon-t.c +++ b/tests/portable/daemon-t.c @@ -1,6 +1,9 @@ /* * daemon test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/getaddrinfo-t.c b/tests/portable/getaddrinfo-t.c index 5f4d157..499f3b4 100644 --- a/tests/portable/getaddrinfo-t.c +++ b/tests/portable/getaddrinfo-t.c @@ -1,6 +1,9 @@ /* * getaddrinfo test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -65,7 +68,7 @@ main(void) is_int(sizeof(struct sockaddr_in), ai->ai_addrlen, "...right addrlen"); saddr = (struct sockaddr_in *) ai->ai_addr; is_int(htons(25), saddr->sin_port, "...right port"); - ok(saddr->sin_addr.s_addr == INADDR_LOOPBACK, "...right address"); + is_int(htonl(0x7f000001UL), saddr->sin_addr.s_addr, "...right address"); test_freeaddrinfo(ai); memset(&hints, 0, sizeof(hints)); @@ -75,7 +78,7 @@ main(void) is_int(SOCK_STREAM, ai->ai_socktype, "...right socktype"); saddr = (struct sockaddr_in *) ai->ai_addr; is_int(htons(25), saddr->sin_port, "...right port"); - ok(saddr->sin_addr.s_addr == INADDR_ANY, "...right address"); + is_int(INADDR_ANY, saddr->sin_addr.s_addr, "...right address"); test_freeaddrinfo(ai); service = getservbyname("smtp", "tcp"); @@ -88,7 +91,7 @@ main(void) is_int(SOCK_STREAM, ai->ai_socktype, "...right socktype"); saddr = (struct sockaddr_in *) ai->ai_addr; is_int(htons(25), saddr->sin_port, "...right port"); - ok(saddr->sin_addr.s_addr == INADDR_ANY, "...right address"); + is_int(INADDR_ANY, saddr->sin_addr.s_addr, "...right address"); test_freeaddrinfo(ai); } @@ -103,7 +106,7 @@ main(void) "valid AI_NUMERICSERV"); saddr = (struct sockaddr_in *) ai->ai_addr; is_int(htons(25), saddr->sin_port, "...right port"); - ok(saddr->sin_addr.s_addr == INADDR_LOOPBACK, "...right address"); + is_int(htonl(0x7f000001UL), saddr->sin_addr.s_addr, "...right address"); test_freeaddrinfo(ai); ok(test_getaddrinfo(NULL, NULL, NULL, &ai) == EAI_NONAME, "EAI_NONAME"); diff --git a/tests/portable/getnameinfo-t.c b/tests/portable/getnameinfo-t.c index b12d4d8..21c0533 100644 --- a/tests/portable/getnameinfo-t.c +++ b/tests/portable/getnameinfo-t.c @@ -1,6 +1,9 @@ /* * getnameinfo test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/getopt-t.c b/tests/portable/getopt-t.c index c399969..20e9636 100644 --- a/tests/portable/getopt-t.c +++ b/tests/portable/getopt-t.c @@ -1,6 +1,9 @@ /* * getopt test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2008, 2009 * The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/portable/inet_aton-t.c b/tests/portable/inet_aton-t.c index 185003a..048eca9 100644 --- a/tests/portable/inet_aton-t.c +++ b/tests/portable/inet_aton-t.c @@ -1,6 +1,9 @@ /* * inet_aton test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/inet_ntoa-t.c b/tests/portable/inet_ntoa-t.c index 3c1b019..95b9fc0 100644 --- a/tests/portable/inet_ntoa-t.c +++ b/tests/portable/inet_ntoa-t.c @@ -1,6 +1,9 @@ /* * inet_ntoa test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/inet_ntop-t.c b/tests/portable/inet_ntop-t.c index 8071d36..ee29039 100644 --- a/tests/portable/inet_ntop-t.c +++ b/tests/portable/inet_ntop-t.c @@ -1,6 +1,9 @@ /* * inet_ntop test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/setenv-t.c b/tests/portable/setenv-t.c index c21a0e2..a1aecb5 100644 --- a/tests/portable/setenv-t.c +++ b/tests/portable/setenv-t.c @@ -1,6 +1,9 @@ /* * setenv test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/snprintf-t.c b/tests/portable/snprintf-t.c index 1df0ba8..927de96 100644 --- a/tests/portable/snprintf-t.c +++ b/tests/portable/snprintf-t.c @@ -1,6 +1,9 @@ /* * snprintf test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 * Russ Allbery <rra@stanford.edu> diff --git a/tests/portable/strlcat-t.c b/tests/portable/strlcat-t.c index 3af91ca..54d0d40 100644 --- a/tests/portable/strlcat-t.c +++ b/tests/portable/strlcat-t.c @@ -1,6 +1,9 @@ /* * strlcat test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/portable/strlcpy-t.c b/tests/portable/strlcpy-t.c index 54dcbd5..26aa8f2 100644 --- a/tests/portable/strlcpy-t.c +++ b/tests/portable/strlcpy-t.c @@ -1,6 +1,9 @@ /* * strlcpy test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/tap/kerberos.sh b/tests/tap/kerberos.sh index 577598b..2dacc42 100644 --- a/tests/tap/kerberos.sh +++ b/tests/tap/kerberos.sh @@ -1,5 +1,8 @@ # Shell function library to initialize Kerberos credentials # +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +# # Written by Russ Allbery <rra@stanford.edu> # Copyright 2009, 2010 # The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/tap/messages.c b/tests/tap/messages.c index 9d17c0c..78a1fee 100644 --- a/tests/tap/messages.c +++ b/tests/tap/messages.c @@ -5,6 +5,9 @@ * into a buffer that can be inspected later, allowing testing of error * handling. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu> * Copyright 2006, 2007, 2009 * The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/tap/messages.h b/tests/tap/messages.h index 8f53aa2..5e59bff 100644 --- a/tests/tap/messages.h +++ b/tests/tap/messages.h @@ -1,6 +1,9 @@ /* * Utility functions to test message handling. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2002 Russ Allbery <rra@stanford.edu> * Copyright 2006, 2007, 2009 * The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/tap/process.c b/tests/tap/process.c index be364e4..fc94295 100644 --- a/tests/tap/process.c +++ b/tests/tap/process.c @@ -1,14 +1,18 @@ /* * Utility functions for tests that use subprocesses. * - * Provides utility functions for subprocess manipulation. Currently, only - * one utility function is provided: is_function_output, which runs a function - * in a subprocess and checks its output and exit status against expected - * values. + * Provides utility functions for subprocess manipulation. Specifically, + * provides a function, run_setup, which runs a command and bails if it fails, + * using its error message as the bail output, and is_function_output, which + * runs a function in a subprocess and checks its output and exit status + * against expected values. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu> - * Copyright 2009, 2010 + * Copyright 2009, 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a @@ -37,26 +41,23 @@ #include <tests/tap/basic.h> #include <tests/tap/process.h> -#include <util/xmalloc.h> /* * Given a function, an expected exit status, and expected output, runs that * function in a subprocess, capturing stdout and stderr via a pipe, and - * compare the combination of stdout and stderr with the expected output and - * the exit status with the expected status. Expects the function to always - * exit (not die from a signal). + * returns the function output in newly allocated memory. Also captures the + * process exit status. */ -void -is_function_output(test_function_type function, int status, const char *output, - const char *format, ...) +static void +run_child_function(test_function_type function, void *data, int *status, + char **output) { int fds[2]; pid_t child; - char *buf, *msg; + char *buf; ssize_t count, ret, buflen; int rval; - va_list args; /* Flush stdout before we start to avoid odd forking issues. */ fflush(stdout); @@ -76,7 +77,7 @@ is_function_output(test_function_type function, int status, const char *output, _exit(255); /* Now, run the function and exit successfully if it returns. */ - (*function)(); + (*function)(data); fflush(stdout); _exit(0); } else { @@ -86,7 +87,7 @@ is_function_output(test_function_type function, int status, const char *output, */ close(fds[1]); buflen = BUFSIZ; - buf = xmalloc(buflen); + buf = bmalloc(buflen); count = 0; do { ret = read(fds[0], buf + count, buflen - count - 1); @@ -94,7 +95,7 @@ is_function_output(test_function_type function, int status, const char *output, count += ret; if (count >= buflen - 1) { buflen += BUFSIZ; - buf = xrealloc(buf, buflen); + buf = brealloc(buf, buflen); } } while (ret > 0); buf[count < 0 ? 0 : count] = '\0'; @@ -102,9 +103,32 @@ is_function_output(test_function_type function, int status, const char *output, sysbail("waitpid failed"); } + /* Store the output and return. */ + *status = rval; + *output = buf; +} + + +/* + * Given a function, data to pass to that function, an expected exit status, + * and expected output, runs that function in a subprocess, capturing stdout + * and stderr via a pipe, and compare the combination of stdout and stderr + * with the expected output and the exit status with the expected status. + * Expects the function to always exit (not die from a signal). + */ +void +is_function_output(test_function_type function, void *data, int status, + const char *output, const char *format, ...) +{ + char *buf, *msg; + int rval; + va_list args; + + run_child_function(function, data, &rval, &buf); + /* Now, check the results against what we expected. */ va_start(args, format); - if (xvasprintf(&msg, format, args) < 0) + if (vasprintf(&msg, format, args) < 0) bail("cannot format test description"); va_end(args); ok(WIFEXITED(rval), "%s (exited)", msg); @@ -113,3 +137,39 @@ is_function_output(test_function_type function, int status, const char *output, free(buf); free(msg); } + + +/* + * A helper function for run_setup. This is a function to run an external + * command, suitable for passing into run_child_function. The expected + * argument must be an argv array, with argv[0] being the command to run. + */ +static void +exec_command(void *data) +{ + char *const *argv = data; + + execvp(argv[0], argv); +} + + +/* + * Given a command expressed as an argv struct, with argv[0] the name or path + * to the command, run that command. If it exits with a non-zero status, use + * the part of its output up to the first newline as the error message when + * calling bail. + */ +void +run_setup(const char *const argv[]) +{ + char *output, *p; + int status; + + run_child_function(exec_command, (void *) argv, &status, &output); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + p = strchr(output, '\n'); + if (p != NULL) + *p = '\0'; + bail("%s", output); + } +} diff --git a/tests/tap/process.h b/tests/tap/process.h index 40bdd56..cd4eadc 100644 --- a/tests/tap/process.h +++ b/tests/tap/process.h @@ -1,6 +1,9 @@ /* * Utility functions for tests that use subprocesses. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2009, 2010 * The Board of Trustees of the Leland Stanford Junior University @@ -35,16 +38,27 @@ BEGIN_DECLS /* * Run a function in a subprocess and check the exit status and expected * output (stdout and stderr combined) against the provided values. Expects - * the function to always exit (not die from a signal). + * the function to always exit (not die from a signal). data is optional data + * that's passed into the function as its only argument. * * This reports as three separate tests: whether the function exited rather * than was killed, whether the exit status was correct, and whether the * output was correct. */ -typedef void (*test_function_type)(void); -void is_function_output(test_function_type, int status, const char *output, - const char *format, ...) - __attribute__((__format__(printf, 4, 5))); +typedef void (*test_function_type)(void *); +void is_function_output(test_function_type, void *data, int status, + const char *output, const char *format, ...) + __attribute__((__format__(printf, 5, 6), __nonnull__(1))); + +/* + * Run a setup program. Takes the program to run and its arguments as an argv + * vector, where argv[0] must be either the full path to the program or the + * program name if the PATH should be searched. If the program does not exit + * successfully, call bail, with the error message being the output from the + * program. + */ +void run_setup(const char *const argv[]) + __attribute__((__nonnull__)); END_DECLS diff --git a/tests/tap/remctl.h b/tests/tap/remctl.h index e7e14ef..eda8d61 100644 --- a/tests/tap/remctl.h +++ b/tests/tap/remctl.h @@ -4,6 +4,9 @@ * Provides functions to start and stop a remctl daemon that uses the test * Kerberos environment and runs on port 14373 instead of the default 4373. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2006, 2007, 2009, 2011 * The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/tap/remctl.sh b/tests/tap/remctl.sh index afceb8b..07302f3 100644 --- a/tests/tap/remctl.sh +++ b/tests/tap/remctl.sh @@ -1,5 +1,8 @@ # Shell function library to start and stop remctld # +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +# # Written by Russ Allbery <rra@stanford.edu> # Copyright 2009 # The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/util/concat-t.c b/tests/util/concat-t.c index 8333c44..384af3a 100644 --- a/tests/util/concat-t.c +++ b/tests/util/concat-t.c @@ -1,6 +1,9 @@ /* * concat test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/util/fakewrite.c b/tests/util/fakewrite.c index 6c4390b..5f9a056 100644 --- a/tests/util/fakewrite.c +++ b/tests/util/fakewrite.c @@ -1,6 +1,9 @@ /* * Fake write and writev functions for testing xwrite and xwritev. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2000, 2001, 2002, 2004 Russ Allbery <rra@stanford.edu> * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/tests/util/fdflag-t.c b/tests/util/fdflag-t.c index b7334c1..adc5ebc 100644 --- a/tests/util/fdflag-t.c +++ b/tests/util/fdflag-t.c @@ -1,6 +1,9 @@ /* * fdflag test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2008, 2009 * The Board of Trustees of the Leland Stanford Junior University diff --git a/tests/util/messages-t.c b/tests/util/messages-t.c index bac53d2..aa895fa 100644 --- a/tests/util/messages-t.c +++ b/tests/util/messages-t.c @@ -1,9 +1,12 @@ /* * Test suite for error handling routines. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu> - * Copyright 2009, 2010 + * Copyright 2009, 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * * Permission is hereby granted, free of charge, to any person obtaining a @@ -36,6 +39,7 @@ #include <tests/tap/basic.h> #include <tests/tap/process.h> #include <util/concat.h> +#include <util/macros.h> #include <util/messages.h> #include <util/xmalloc.h> @@ -43,24 +47,27 @@ /* * Test functions. */ -static void test1(void) { warn("warning"); } -static void test2(void) { die("fatal"); } -static void test3(void) { errno = EPERM; syswarn("permissions"); } -static void test4(void) { errno = EACCES; sysdie("fatal access"); } -static void test5(void) { +static void test1(void *data UNUSED) { warn("warning"); } +static void test2(void *data UNUSED) { die("fatal"); } +static void test3(void *data UNUSED) { errno = EPERM; syswarn("permissions"); } +static void test4(void *data UNUSED) { + errno = EACCES; + sysdie("fatal access"); +} +static void test5(void *data UNUSED) { message_program_name = "test5"; warn("warning"); } -static void test6(void) { +static void test6(void *data UNUSED) { message_program_name = "test6"; die("fatal"); } -static void test7(void) { +static void test7(void *data UNUSED) { message_program_name = "test7"; errno = EPERM; syswarn("perms %d", 7); } -static void test8(void) { +static void test8(void *data UNUSED) { message_program_name = "test8"; errno = EACCES; sysdie("%st%s", "fa", "al"); @@ -68,17 +75,17 @@ static void test8(void) { static int return10(void) { return 10; } -static void test9(void) { +static void test9(void *data UNUSED) { message_fatal_cleanup = return10; die("fatal"); } -static void test10(void) { +static void test10(void *data UNUSED) { message_program_name = 0; message_fatal_cleanup = return10; errno = EPERM; sysdie("fatal perm"); } -static void test11(void) { +static void test11(void *data UNUSED) { message_program_name = "test11"; message_fatal_cleanup = return10; errno = EPERM; @@ -92,55 +99,55 @@ static void log_msg(int len, const char *format, va_list args, int error) { fprintf(stderr, "\n"); } -static void test12(void) { +static void test12(void *data UNUSED) { message_handlers_warn(1, log_msg); warn("warning"); } -static void test13(void) { +static void test13(void *data UNUSED) { message_handlers_die(1, log_msg); die("fatal"); } -static void test14(void) { +static void test14(void *data UNUSED) { message_handlers_warn(2, log_msg, log_msg); errno = EPERM; syswarn("warning"); } -static void test15(void) { +static void test15(void *data UNUSED) { message_handlers_die(2, log_msg, log_msg); message_fatal_cleanup = return10; errno = EPERM; sysdie("fatal"); } -static void test16(void) { +static void test16(void *data UNUSED) { message_handlers_warn(2, message_log_stderr, log_msg); message_program_name = "test16"; errno = EPERM; syswarn("warning"); } -static void test17(void) { notice("notice"); } -static void test18(void) { +static void test17(void *data UNUSED) { notice("notice"); } +static void test18(void *data UNUSED) { message_program_name = "test18"; notice("notice"); } -static void test19(void) { debug("debug"); } -static void test20(void) { +static void test19(void *data UNUSED) { debug("debug"); } +static void test20(void *data UNUSED) { message_handlers_notice(1, log_msg); notice("foo"); } -static void test21(void) { +static void test21(void *data UNUSED) { message_handlers_debug(1, message_log_stdout); message_program_name = "test23"; debug("baz"); } -static void test22(void) { +static void test22(void *data UNUSED) { message_handlers_die(0); die("hi mom!"); } -static void test23(void) { +static void test23(void *data UNUSED) { message_handlers_warn(0); warn("this is a test"); } -static void test24(void) { +static void test24(void *data UNUSED) { notice("first"); message_handlers_notice(0); notice("second"); @@ -161,7 +168,7 @@ test_strerror(int status, const char *output, int error, full_output = concat(output, ": ", strerror(error), "\n", (char *) NULL); xasprintf(&name, "strerror %lu", testnum / 3 + 1); - is_function_output(function, status, full_output, "%s", name); + is_function_output(function, NULL, status, full_output, "%s", name); free(full_output); free(name); } @@ -178,43 +185,43 @@ main(void) plan(24 * 3); - is_function_output(test1, 0, "warning\n", "test1"); - is_function_output(test2, 1, "fatal\n", "test2"); + is_function_output(test1, NULL, 0, "warning\n", "test1"); + is_function_output(test2, NULL, 1, "fatal\n", "test2"); test_strerror(0, "permissions", EPERM, test3); test_strerror(1, "fatal access", EACCES, test4); - is_function_output(test5, 0, "test5: warning\n", "test5"); - is_function_output(test6, 1, "test6: fatal\n", "test6"); + is_function_output(test5, NULL, 0, "test5: warning\n", "test5"); + is_function_output(test6, NULL, 1, "test6: fatal\n", "test6"); test_strerror(0, "test7: perms 7", EPERM, test7); test_strerror(1, "test8: fatal", EACCES, test8); - is_function_output(test9, 10, "fatal\n", "test9"); + is_function_output(test9, NULL, 10, "fatal\n", "test9"); test_strerror(10, "fatal perm", EPERM, test10); test_strerror(10, "1st test11: fatal", EPERM, test11); - is_function_output(test12, 0, "7 0 warning\n", "test12"); - is_function_output(test13, 1, "5 0 fatal\n", "test13"); + is_function_output(test12, NULL, 0, "7 0 warning\n", "test12"); + is_function_output(test13, NULL, 1, "5 0 fatal\n", "test13"); sprintf(buff, "%d", EPERM); xasprintf(&output, "7 %d warning\n7 %d warning\n", EPERM, EPERM); - is_function_output(test14, 0, output, "test14"); + is_function_output(test14, NULL, 0, output, "test14"); free(output); xasprintf(&output, "5 %d fatal\n5 %d fatal\n", EPERM, EPERM); - is_function_output(test15, 10, output, "test15"); + is_function_output(test15, NULL, 10, output, "test15"); free(output); xasprintf(&output, "test16: warning: %s\n7 %d warning\n", strerror(EPERM), EPERM); - is_function_output(test16, 0, output, "test16"); + is_function_output(test16, NULL, 0, output, "test16"); free(output); - is_function_output(test17, 0, "notice\n", "test17"); - is_function_output(test18, 0, "test18: notice\n", "test18"); - is_function_output(test19, 0, "", "test19"); - is_function_output(test20, 0, "3 0 foo\n", "test20"); - is_function_output(test21, 0, "test23: baz\n", "test21"); + is_function_output(test17, NULL, 0, "notice\n", "test17"); + is_function_output(test18, NULL, 0, "test18: notice\n", "test18"); + is_function_output(test19, NULL, 0, "", "test19"); + is_function_output(test20, NULL, 0, "3 0 foo\n", "test20"); + is_function_output(test21, NULL, 0, "test23: baz\n", "test21"); /* Make sure that it's possible to turn off a message type entirely. */ - is_function_output(test22, 1, "", "test22"); - is_function_output(test23, 0, "", "test23"); - is_function_output(test24, 0, "first\nthird\n", "test24"); + is_function_output(test22, NULL, 1, "", "test22"); + is_function_output(test23, NULL, 0, "", "test23"); + is_function_output(test24, NULL, 0, "first\nthird\n", "test24"); return 0; } diff --git a/tests/util/network-t.c b/tests/util/network-t.c index ac8ee8a..3e04b1d 100644 --- a/tests/util/network-t.c +++ b/tests/util/network-t.c @@ -1,6 +1,9 @@ /* * network test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2005 Russ Allbery <rra@stanford.edu> * Copyright 2009, 2010, 2011 @@ -88,15 +91,28 @@ listener(socket_type fd) * A varient version of the server portion of the test. Takes an array of * sockets and the size of the sockets and accepts a connection on any of * those sockets. + * + * saddr is allocated from the heap instead of using a local struct + * sockaddr_storage to work around a misdiagnosis of strict aliasing + * violations from gcc 4.4 (fixed in later versions). */ static void listener_any(socket_type fds[], unsigned int count) { socket_type client; unsigned int i; + struct sockaddr *saddr; + socklen_t slen; - client = network_accept_any(fds, count, NULL, NULL); + slen = sizeof(struct sockaddr_storage); + saddr = bmalloc(slen); + client = network_accept_any(fds, count, saddr, &slen); listener_handler(client); + is_int(AF_INET, saddr->sa_family, "...address family is IPv4"); + is_int(htonl(0x7f000001UL), + ((struct sockaddr_in *) saddr)->sin_addr.s_addr, + "...and client address is 127.0.0.1"); + free(saddr); for (i = 0; i < count; i++) close(fds[i]); } @@ -105,17 +121,23 @@ listener_any(socket_type fds[], unsigned int count) /* * Connect to the given host on port 11119 and send a constant string to a * socket, used to do the client side of the testing. Takes the source - * address as well to pass into network_connect_host. + * address as well to pass into network_connect_host. If the flag is true, + * expects to succeed in connecting; otherwise, fail the test if the + * connection is successful. */ static void -client(const char *host, const char *source) +client(const char *host, const char *source, bool succeed) { socket_type fd; FILE *out; - fd = network_connect_host(host, 11119, source); - if (fd == INVALID_SOCKET) - sysdie("connect failed"); + fd = network_connect_host(host, 11119, source, 0); + if (fd == INVALID_SOCKET) { + if (succeed) + _exit(1); + else + return; + } out = fdopen(fd, "w"); if (out == NULL) sysdie("fdopen failed"); @@ -149,7 +171,7 @@ test_ipv4(const char *source) sysbail("cannot fork"); else if (child == 0) { close(fd); - client("127.0.0.1", source); + client("127.0.0.1", source, true); } else { listener(fd); waitpid(child, NULL, 0); @@ -169,20 +191,21 @@ test_ipv6(const char *source) { socket_type fd; pid_t child; + int status; fd = network_bind_ipv6("::1", 11119); if (fd == INVALID_SOCKET) { if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT || errno == EADDRNOTAVAIL) { ipv6 = 0; - skip_block(3, "IPv6 not supported"); + skip_block(4, "IPv6 not supported"); return; } else sysbail("cannot create socket"); } if (listen(fd, 1) < 0) { sysdiag("cannot listen to socket"); - ok_block(3, 0, "IPv6 server test"); + ok_block(4, 0, "IPv6 server test"); } else { ok(1, "IPv6 server test"); child = fork(); @@ -190,10 +213,14 @@ test_ipv6(const char *source) sysbail("cannot fork"); else if (child == 0) { close(fd); - client("::1", source); +#ifdef IPV6_V6ONLY + client("127.0.0.1", NULL, false); +#endif + client("::1", source, true); } else { listener(fd); - waitpid(child, NULL, 0); + waitpid(child, &status, 0); + is_int(0, status, "client made correct connections"); } } } @@ -201,7 +228,7 @@ test_ipv6(const char *source) static void test_ipv6(const char *source UNUSED) { - skip_block(3, "IPv6 not supported"); + skip_block(4, "IPv6 not supported"); } #endif /* !HAVE_INET6 */ @@ -218,7 +245,8 @@ test_all(const char *source_ipv4, const char *source_ipv6 UNUSED) unsigned int count, i; pid_t child; struct sockaddr_storage saddr; - socklen_t size = sizeof(saddr); + socklen_t size; + int status; network_bind_all(11119, &fds, &count); if (count == 0) @@ -234,29 +262,35 @@ test_all(const char *source_ipv4, const char *source_ipv6 UNUSED) ok_block(3, 0, "all address server test"); } else { ok(1, "all address server test (part %d)", i); + size = sizeof(saddr); + if (getsockname(fd, (struct sockaddr *) &saddr, &size) < 0) + sysbail("cannot getsockname"); child = fork(); if (child < 0) sysbail("cannot fork"); else if (child == 0) { - if (getsockname(fd, (struct sockaddr *) &saddr, &size) < 0) - sysbail("cannot getsockname"); - if (saddr.ss_family == AF_INET) - client("127.0.0.1", source_ipv4); + if (saddr.ss_family == AF_INET) { + client("::1", source_ipv6, false); + client("127.0.0.1", source_ipv4, true); #ifdef HAVE_INET6 - else if (saddr.ss_family == AF_INET6) - client("::1", source_ipv6); + } else if (saddr.ss_family == AF_INET6) { +# ifdef IPV6_V6ONLY + client("127.0.0.1", source_ipv4, false); +# endif + client("::1", source_ipv6, true); #endif - else - skip_block(2, "unknown socket family %d", saddr.ss_family); - size = sizeof(saddr); + } + _exit(1); } else { listener(fd); - waitpid(child, NULL, 0); + waitpid(child, &status, 0); + is_int(0, status, "client made correct connections"); } } } if (count == 1) skip_block(3, "only one listening socket"); + network_bind_all_free(fds); } @@ -283,11 +317,12 @@ test_any(void) if (child < 0) sysbail("cannot fork"); else if (child == 0) - client("127.0.0.1", NULL); + client("127.0.0.1", NULL, true); else { listener_any(fds, count); waitpid(child, NULL, 0); } + network_bind_all_free(fds); } @@ -323,7 +358,7 @@ test_create_ipv4(const char *source) memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(11119); - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_addr.s_addr = htonl(0x7f000001UL); if (connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) _exit(1); out = fdopen(fd, "w"); @@ -341,6 +376,73 @@ test_create_ipv4(const char *source) /* + * Test connect timeouts using IPv4. Bring up a server on port 11119 on the + * loopback address and test connections to it. The server only accepts one + * connection at a time, so the second connection will time out. + */ +static void +test_timeout_ipv4(void) +{ + socket_type fd, c; + pid_t child; + + fd = network_bind_ipv4("127.0.0.1", 11119); + if (fd == INVALID_SOCKET) + sysbail("cannot create or bind socket"); + if (listen(fd, 1) < 0) { + sysdiag("cannot listen to socket"); + ok_block(3, 0, "IPv4 network client with timeout"); + close(fd); + return; + } + child = fork(); + if (child < 0) + sysbail("cannot fork"); + else if (child == 0) { + struct sockaddr_in sin; + socklen_t slen; + + alarm(10); + c = accept(fd, &sin, &slen); + if (c == INVALID_SOCKET) + _exit(1); + sleep(9); + _exit(0); + } else { + socket_type block[20]; + int i; + + close(fd); + c = network_connect_host("127.0.0.1", 11119, NULL, 1); + ok(c != INVALID_SOCKET, "Timeout: first connection worked"); + + /* + * For some reason, despite a listening queue of only 1, it can take + * up to seven connections on Linux before connections start actually + * timing out. + */ + alarm(10); + for (i = 0; i < (int) ARRAY_SIZE(block); i++) { + block[i] = network_connect_host("127.0.0.1", 11119, NULL, 1); + if (block[i] == INVALID_SOCKET) + break; + } + diag("Finally timed out on socket %d", i); + ok(block[i] == INVALID_SOCKET, "Timeout: later connection timed out"); + is_int(ETIMEDOUT, socket_errno, "...with correct error"); + alarm(0); + kill(child, SIGTERM); + waitpid(child, NULL, 0); + close(c); + for (; i >= 0; i--) + if (block[i] != INVALID_SOCKET) + close(block[i]); + } + close(fd); +} + + +/* * Tests network_addr_compare. Takes the expected result, the two addresses, * and the mask. */ @@ -369,7 +471,7 @@ main(void) static const char *ipv6_addr = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"; #endif - plan(89); + plan(100); /* * If IPv6 support appears to be available but doesn't work, we have to @@ -397,6 +499,9 @@ main(void) /* Test network_accept_any. */ test_any(); + /* Test network_connect with a timeout. */ + test_timeout_ipv4(); + /* * Now, test network_sockaddr_sprint, network_sockaddr_equal, and * network_sockaddr_port. @@ -439,6 +544,7 @@ main(void) "...and not equal to IPv4"); ok(!network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr), "...other way around"); + freeaddrinfo(ai6); /* Test IPv4 mapped addresses. */ status = getaddrinfo("::ffff:7f00:1", NULL, &hints, &ai6); @@ -459,6 +565,7 @@ main(void) #else skip_block(12, "IPv6 not supported"); #endif + freeaddrinfo(ai); /* Check the domains of functions and their error handling. */ ai4->ai_addr->sa_family = AF_UNIX; @@ -466,6 +573,7 @@ main(void) "equal not equal with address mismatches"); is_int(0, network_sockaddr_port(ai4->ai_addr), "port meaningless for AF_UNIX"); + freeaddrinfo(ai4); /* Tests for network_addr_compare. */ ok_addr(1, "127.0.0.1", "127.0.0.1", NULL); diff --git a/tests/util/vector-t.c b/tests/util/vector-t.c index 71c28c4..4848156 100644 --- a/tests/util/vector-t.c +++ b/tests/util/vector-t.c @@ -1,6 +1,9 @@ /* * vector test suite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/tests/util/xmalloc-t b/tests/util/xmalloc-t index 88145dd..4dadc65 100755 --- a/tests/util/xmalloc-t +++ b/tests/util/xmalloc-t @@ -2,6 +2,9 @@ # # Test suite for xmalloc and friends. # +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +# # Written by Russ Allbery <rra@stanford.edu> # Copyright 2000, 2001, 2006 Russ Allbery <rra@stanford.edu> # Copyright 2008, 2009, 2010 diff --git a/tests/util/xmalloc.c b/tests/util/xmalloc.c index 2364d1f..14e5fed 100644 --- a/tests/util/xmalloc.c +++ b/tests/util/xmalloc.c @@ -1,6 +1,9 @@ /* * Test suite for xmalloc and family. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2000, 2001, 2006 Russ Allbery <rra@stanford.edu> * Copyright 2008 * The Board of Trustees of the Leland Stanford Junior University @@ -76,9 +79,9 @@ test_malloc(size_t size) /* - * Allocate half the memory given, write to it, then reallocate to the desired - * size, writing to the rest and then checking it all. Returns true on - * success, false on any failure. + * Allocate 10 bytes of memory given, write to it, then reallocate to the + * desired size, writing to the rest and then checking it all. Returns true + * on success, false on any failure. */ static int test_realloc(size_t size) diff --git a/tests/util/xwrite-t.c b/tests/util/xwrite-t.c index 399a5da..f1cab22 100644 --- a/tests/util/xwrite-t.c +++ b/tests/util/xwrite-t.c @@ -1,6 +1,9 @@ /* * Test suite for xwrite, xwritev, and xpwrite. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2000, 2001, 2002, 2004 Russ Allbery <rra@stanford.edu> * Copyright 2009 * The Board of Trustees of the Leland Stanford Junior University diff --git a/util/concat.c b/util/concat.c index 0525ddb..fb4afa8 100644 --- a/util/concat.c +++ b/util/concat.c @@ -18,6 +18,9 @@ * together and returned. This is useful for building file names where names * that aren't fully qualified are qualified with some particular directory. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/util/concat.h b/util/concat.h index 9712d70..960f242 100644 --- a/util/concat.h +++ b/util/concat.h @@ -1,6 +1,9 @@ /* * Prototypes for string concatenation with dynamic memory allocation. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have diff --git a/util/fdflag.c b/util/fdflag.c index bf3125e..1be200c 100644 --- a/util/fdflag.c +++ b/util/fdflag.c @@ -4,7 +4,10 @@ * Simple functions (wrappers around fcntl) to set or clear file descriptor * flags like close-on-exec or nonblocking I/O. * - * Copyright 2008 + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2008, 2011 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006 * by Internet Systems Consortium, Inc. ("ISC") @@ -30,16 +33,21 @@ #include <config.h> #include <portable/system.h> -#include <errno.h> -#include <fcntl.h> -#ifndef O_NONBLOCK -# include <sys/ioctl.h> -# if HAVE_SYS_FILIO_H -# include <sys/filio.h> +#ifdef _WIN32 +# include <winsock2.h> +#else +# include <errno.h> +# include <fcntl.h> +# ifndef O_NONBLOCK +# include <sys/ioctl.h> +# if HAVE_SYS_FILIO_H +# include <sys/filio.h> +# endif # endif #endif #include <util/fdflag.h> +#include <util/macros.h> /* @@ -49,7 +57,17 @@ * One is supposed to retrieve the flags, add FD_CLOEXEC, and then set them, * although I've never seen a system with any flags other than close-on-exec. * Do it right anyway; it's not that expensive. -*/ + * + * Stub this out on Windows, where it's not supported (at least currently by + * this utility library). + */ +#ifdef _WIN32 +bool +fdflag_close_exec(int fd UNUSED, bool flag UNUSED) +{ + return false; +} +#else bool fdflag_close_exec(int fd, bool flag) { @@ -61,17 +79,23 @@ fdflag_close_exec(int fd, bool flag) mode = flag ? (oflag | FD_CLOEXEC) : (oflag & ~FD_CLOEXEC); return (fcntl(fd, F_SETFD, mode) == 0); } +#endif /* * Set a file descriptor to nonblocking (or clear the nonblocking flag if flag * is false), returning true on success and false on failure. * - * Always use O_NONBLOCK; O_NDELAY is not the same thing historically. The - * semantics of O_NDELAY are that if the read would block, it returns 0 - * instead. This is indistinguishable from an end of file condition. POSIX - * added O_NONBLOCK, which requires read to return -1 and set errno to EAGAIN, - * which is what we want. + * For Windows, be aware that this will only work for sockets. For UNIX, you + * can pass a non-socket in and it will do the right thing, since UNIX doesn't + * distinguish, but Windows will not allow that. Thankfully, there's rarely + * any need to set non-sockets non-blocking. + * + * For UNIX, always use O_NONBLOCK; O_NDELAY is not the same thing + * historically. The semantics of O_NDELAY are that if the read would block, + * it returns 0 instead. This is indistinguishable from an end of file + * condition. POSIX added O_NONBLOCK, which requires read to return -1 and + * set errno to EAGAIN, which is what we want. * * FNDELAY (4.3BSD) originally did the correct thing, although it has a * different incompatibility (affecting all users of a socket rather than just @@ -93,9 +117,18 @@ fdflag_close_exec(int fd, bool flag) * O_NONBLOCK). Accordingly, we currently unconditionally use O_NONBLOCK. If * this causes too many problems, an autoconf test may be required. */ -#ifdef O_NONBLOCK +#if defined(_WIN32) +bool +fdflag_nonblocking(socket_type fd, bool flag) +{ + u_long mode; + + mode = flag ? 1 : 0; + return (ioctlsocket(fd, FIONBIO, &mode) == 0); +} +#elif defined(O_NONBLOCK) bool -fdflag_nonblocking(int fd, bool flag) +fdflag_nonblocking(socket_type fd, bool flag) { int mode; @@ -106,8 +139,8 @@ fdflag_nonblocking(int fd, bool flag) return (fcntl(fd, F_SETFL, mode) == 0); } #else /* !O_NONBLOCK */ -int -nonblocking(int fd, bool flag) +bool +fdflag_nonblocking(socket_type fd, bool flag) { int state; diff --git a/util/fdflag.h b/util/fdflag.h index 6b8af60..bed45da 100644 --- a/util/fdflag.h +++ b/util/fdflag.h @@ -1,7 +1,10 @@ /* * Prototypes for setting or clearing file descriptor flags. * - * Copyright 2008, 2010 + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2008, 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006 * by Internet Systems Consortium, Inc. ("ISC") @@ -30,15 +33,22 @@ #include <config.h> #include <portable/macros.h> #include <portable/stdbool.h> +#include <portable/socket.h> BEGIN_DECLS /* Default to a hidden visibility for all util functions. */ #pragma GCC visibility push(hidden) -/* Set a file descriptor close-on-exec or nonblocking. */ +/* + * Set a file descriptor close-on-exec or nonblocking. fdflag_close_exec is + * not supported on Windows and will always return false. fdflag_nonblocking + * is defined to take a socket_type so that it can be supported on Windows. + * On UNIX systems, you can safely pass in a non-socket file descriptor, but + * be aware that this will fail to compile on Windows. + */ bool fdflag_close_exec(int fd, bool flag); -bool fdflag_nonblocking(int fd, bool flag); +bool fdflag_nonblocking(socket_type fd, bool flag); /* Undo default visibility change. */ #pragma GCC visibility pop diff --git a/util/macros.h b/util/macros.h index 084a5a2..54faee5 100644 --- a/util/macros.h +++ b/util/macros.h @@ -1,6 +1,9 @@ /* * Some standard helpful macros. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -17,6 +20,15 @@ #include <portable/macros.h> +/* + * Used for iterating through arrays. ARRAY_SIZE returns the number of + * elements in the array (useful for a < upper bound in a for loop) and + * ARRAY_END returns a pointer to the element past the end (ISO C99 makes it + * legal to refer to such a pointer as long as it's never dereferenced). + */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)]) + /* Used for unused parameters to silence gcc warnings. */ #define UNUSED __attribute__((__unused__)) diff --git a/util/messages.c b/util/messages.c index 01038d6..52fcfb7 100644 --- a/util/messages.c +++ b/util/messages.c @@ -50,6 +50,9 @@ * generates given the format and arguments), a format, an argument list as a * va_list, and the applicable errno value (if any). * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2008, 2009, 2010 * The Board of Trustees of the Leland Stanford Junior University @@ -204,8 +207,8 @@ message_log_syslog(int pri, size_t len, const char *fmt, va_list args, int err) buffer = malloc(len + 1); if (buffer == NULL) { - fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s", - len + 1, __FILE__, __LINE__, strerror(errno)); + fprintf(stderr, "failed to malloc %lu bytes at %s line %d: %s", + (unsigned long) len + 1, __FILE__, __LINE__, strerror(errno)); exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); } vsnprintf(buffer, len + 1, fmt, args); diff --git a/util/messages.h b/util/messages.h index 05dacac..0f8b5b6 100644 --- a/util/messages.h +++ b/util/messages.h @@ -1,6 +1,9 @@ /* * Prototypes for message and error reporting (possibly fatal). * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2008, 2010 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006 @@ -91,7 +94,7 @@ void message_log_syslog_crit(size_t, const char *, va_list, int) __attribute__((__nonnull__)); /* The type of a message handler. */ -typedef void (*message_handler_func)(size_t, const char *, va_list, int); +typedef void (*message_handler_func)(unsigned int, const char *, va_list, int); /* If non-NULL, called before exit and its return value passed to exit. */ extern int (*message_fatal_cleanup)(void); diff --git a/util/network.c b/util/network.c index 50d7f8d..b88f83b 100644 --- a/util/network.c +++ b/util/network.c @@ -10,6 +10,15 @@ * implementations for functions that aren't found on some pre-IPv6 systems. * No other part of the source tree should have to care about IPv4 vs. IPv6. * + * In this file, casts through void * or const void * of struct sockaddr * + * parameters are to silence gcc warnings with -Wcast-align. The specific + * address types often require stronger alignment than a struct sockaddr, and + * were originally allocated with that alignment. GCC doesn't have a good way + * of knowing that this code is correct. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2009, 2011 * The Board of Trustees of the Leland Stanford Junior University @@ -39,7 +48,14 @@ #include <portable/socket.h> #include <errno.h> +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#include <util/fdflag.h> #include <util/messages.h> #include <util/network.h> #include <util/xmalloc.h> @@ -218,7 +234,7 @@ network_bind_ipv6(const char *address, unsigned short port) */ #if HAVE_INET6 void -network_bind_all(unsigned short port, int **fds, unsigned int *count) +network_bind_all(unsigned short port, socket_type **fds, unsigned int *count) { struct addrinfo hints, *addrs, *addr; unsigned int size; @@ -245,7 +261,7 @@ network_bind_all(unsigned short port, int **fds, unsigned int *count) * assuming an IPv6 and IPv4 socket, and grow it by two when necessary. */ size = 2; - *fds = xmalloc(size * sizeof(int)); + *fds = xmalloc(size * sizeof(socket_type)); for (addr = addrs; addr != NULL; addr = addr->ai_next) { network_sockaddr_sprint(name, sizeof(name), addr->ai_addr); if (addr->ai_family == AF_INET) @@ -285,6 +301,18 @@ network_bind_all(unsigned short port, socket_type **fds, unsigned int *count) /* + * Free the array of file descriptors allocated by network_bind_all. This is + * a simple wrapper around free, needed on platforms where libraries allocate + * memory from a different memory domain than programs (such as Windows). + */ +void +network_bind_all_free(socket_type *fds) +{ + free(fds); +} + + +/* * Given an array of file descriptors and the length of that array (the same * data that's returned by network_bind_all), wait for an incoming connection * on any of those sockets, accept the connection with accept(), and return @@ -327,7 +355,10 @@ network_accept_any(socket_type fds[], unsigned int count, fd = fds[i]; break; } - return accept(fd, addr, addrlen); + if (fd == INVALID_SOCKET) + return INVALID_SOCKET; + else + return accept(fd, addr, addrlen); } @@ -336,18 +367,18 @@ network_accept_any(socket_type fds[], unsigned int count, * using the provided source address. Returns true on success and false on * failure. */ -static int +static bool network_source(socket_type fd, int family, const char *source) { if (source == NULL || strcmp(source, "all") == 0) - return 1; + return true; if (family == AF_INET) { struct sockaddr_in saddr; memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; if (!inet_aton(source, &saddr.sin_addr)) - return 0; + return false; return bind(fd, (struct sockaddr *) &saddr, sizeof(saddr)) == 0; } #ifdef HAVE_INET6 @@ -357,7 +388,7 @@ network_source(socket_type fd, int family, const char *source) memset(&saddr, 0, sizeof(saddr)); saddr.sin6_family = AF_INET6; if (inet_pton(AF_INET6, source, &saddr.sin6_addr) < 1) - return 0; + return false; return bind(fd, (struct sockaddr *) &saddr, sizeof(saddr)) == 0; } #endif @@ -367,7 +398,7 @@ network_source(socket_type fd, int family, const char *source) #else socket_set_errno(EINVAL); #endif - return 0; + return false; } } @@ -381,13 +412,15 @@ network_source(socket_type fd, int family, const char *source) * errno. */ socket_type -network_connect(struct addrinfo *ai, const char *source) +network_connect(struct addrinfo *ai, const char *source, time_t timeout) { socket_type fd = INVALID_SOCKET; - int oerrno; - int success; + int oerrno, status, err; + socklen_t len; + struct timeval tv; + fd_set set; - for (success = 0; ai != NULL; ai = ai->ai_next) { + for (status = -1; status != 0 && ai != NULL; ai = ai->ai_next) { if (fd != INVALID_SOCKET) socket_close(fd); fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); @@ -395,15 +428,34 @@ network_connect(struct addrinfo *ai, const char *source) continue; if (!network_source(fd, ai->ai_family, source)) continue; - if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0) { - success = 1; - break; + if (timeout == 0) + status = connect(fd, ai->ai_addr, ai->ai_addrlen); + else { + fdflag_nonblocking(fd, true); + status = connect(fd, ai->ai_addr, ai->ai_addrlen); + if (status < 0 && socket_errno == EINPROGRESS) { + tv.tv_sec = timeout; + tv.tv_usec = 0; + FD_ZERO(&set); + FD_SET(fd, &set); + status = select(fd + 1, NULL, &set, NULL, &tv); + if (status == 0 && !FD_ISSET(fd, &set)) { + status = -1; + socket_set_errno(ETIMEDOUT); + } else if (status > 0 && FD_ISSET(fd, &set)) { + len = sizeof(err); + status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len); + if (status == 0) + status = err; + } + } + fdflag_nonblocking(fd, false); } } - if (success) + if (status == 0) return fd; else { - if (fd >= 0) { + if (fd != INVALID_SOCKET) { oerrno = socket_errno; socket_close(fd); socket_set_errno(oerrno); @@ -421,7 +473,7 @@ network_connect(struct addrinfo *ai, const char *source) */ socket_type network_connect_host(const char *host, unsigned short port, - const char *source) + const char *source, time_t timeout) { struct addrinfo hints, *ai; char portbuf[16]; @@ -434,7 +486,7 @@ network_connect_host(const char *host, unsigned short port, snprintf(portbuf, sizeof(portbuf), "%d", port); if (getaddrinfo(host, portbuf, &hints, &ai) != 0) return INVALID_SOCKET; - fd = network_connect(ai, source); + fd = network_connect(ai, source, timeout); oerrno = socket_errno; freeaddrinfo(ai); socket_set_errno(oerrno); @@ -483,7 +535,7 @@ network_sockaddr_sprint(char *dst, size_t size, const struct sockaddr *addr) if (addr->sa_family == AF_INET6) { const struct sockaddr_in6 *sin6; - sin6 = (const struct sockaddr_in6 *) addr; + sin6 = (const struct sockaddr_in6 *) (const void *) addr; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { struct in_addr in; @@ -497,7 +549,7 @@ network_sockaddr_sprint(char *dst, size_t size, const struct sockaddr *addr) if (addr->sa_family == AF_INET) { const struct sockaddr_in *sin; - sin = (const struct sockaddr_in *) addr; + sin = (const struct sockaddr_in *) (const void *) addr; result = inet_ntop(AF_INET, &sin->sin_addr, dst, size); return (result != NULL); } else { @@ -515,20 +567,26 @@ network_sockaddr_sprint(char *dst, size_t size, const struct sockaddr *addr) bool network_sockaddr_equal(const struct sockaddr *a, const struct sockaddr *b) { - const struct sockaddr_in *a4 = (const struct sockaddr_in *) a; - const struct sockaddr_in *b4 = (const struct sockaddr_in *) b; - + const struct sockaddr_in *a4; + const struct sockaddr_in *b4; #ifdef HAVE_INET6 - const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) a; - const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *) b; + const struct sockaddr_in6 *a6; + const struct sockaddr_in6 *b6; const struct sockaddr *tmp; +#endif + + a4 = (const struct sockaddr_in *) (const void *) a; + b4 = (const struct sockaddr_in *) (const void *) b; +#ifdef HAVE_INET6 + a6 = (const struct sockaddr_in6 *) (const void *) a; + b6 = (const struct sockaddr_in6 *) (const void *) b; if (a->sa_family == AF_INET && b->sa_family == AF_INET6) { tmp = a; a = b; b = tmp; - a6 = (const struct sockaddr_in6 *) a; - b4 = (const struct sockaddr_in *) b; + a6 = (const struct sockaddr_in6 *) (const void *) a; + b4 = (const struct sockaddr_in *) (const void *) b; } if (a->sa_family == AF_INET6) { if (b->sa_family == AF_INET6) @@ -564,14 +622,14 @@ network_sockaddr_port(const struct sockaddr *sa) const struct sockaddr_in6 *sin6; if (sa->sa_family == AF_INET6) { - sin6 = (const struct sockaddr_in6 *) sa; + sin6 = (const struct sockaddr_in6 *) (const void *) sa; return htons(sin6->sin6_port); } #endif if (sa->sa_family != AF_INET) return 0; else { - sin = (const struct sockaddr_in *) sa; + sin = (const struct sockaddr_in *) (const void *) sa; return htons(sin->sin_port); } } diff --git a/util/network.h b/util/network.h index d528a1a..5c4d981 100644 --- a/util/network.h +++ b/util/network.h @@ -1,6 +1,9 @@ /* * Prototypes for network connection utility functions. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * Copyright 2009, 2010, 2011 * The Board of Trustees of the Leland Stanford Junior University @@ -56,11 +59,13 @@ socket_type network_bind_ipv6(const char *address, unsigned short port) * and one for IPv6, if IPv6 support is enabled). If IPv6 is not enabled, * just one socket will be created and bound to the IPv4 wildcard address. * fds will be set to an array containing the resulting file descriptors, with - * count holding the count returned. + * count holding the count returned. Use network_bind_all_free to free the + * array of file descriptors when no longer needed. */ void network_bind_all(unsigned short port, socket_type **fds, unsigned int *count) __attribute__((__nonnull__)); +void network_bind_all_free(socket_type *fds); /* * Accept an incoming connection from any file descriptor in an array. This @@ -78,9 +83,9 @@ socket_type network_accept_any(socket_type fds[], unsigned int count, * Create a socket and connect it to the remote service given by the linked * list of addrinfo structs. Returns the new file descriptor on success and * -1 on failure, with the error left in errno. Takes an optional source - * address. + * address and a timeout in seconds, which may be 0 for no timeout. */ -socket_type network_connect(struct addrinfo *, const char *source) +socket_type network_connect(struct addrinfo *, const char *source, time_t) __attribute__((__nonnull__(1))); /* @@ -88,7 +93,7 @@ socket_type network_connect(struct addrinfo *, const char *source) * fails, errno may not be set to anything useful. */ socket_type network_connect_host(const char *host, unsigned short port, - const char *source) + const char *source, time_t) __attribute__((__nonnull__(1))); /* diff --git a/util/vector.c b/util/vector.c index 5138438..285969c 100644 --- a/util/vector.c +++ b/util/vector.c @@ -20,6 +20,9 @@ * and perform the same operations, but I'm leery of doing that as I'm not * sure if it's a violation of the C type aliasing rules. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -345,7 +348,7 @@ vector_split_multi(const char *string, const char *seps, if (vector->allocated < count) vector_resize(vector, count); - for (start = string, p = string, i = 0; *p; p++) + for (start = string, p = string, i = 0; *p != '\0'; p++) if (strchr(seps, *p) != NULL) { if (start != p) vector->strings[i++] = xstrndup(start, p - start); @@ -378,7 +381,7 @@ cvector_split_multi(char *string, const char *seps, struct cvector *vector) if (vector->allocated < count) cvector_resize(vector, count); - for (start = string, p = string, i = 0; *p; p++) + for (start = string, p = string, i = 0; *p != '\0'; p++) if (strchr(seps, *p) != NULL) { if (start != p) { *p = '\0'; @@ -438,7 +441,7 @@ vector_split_space(const char *string, struct vector *vector) if (vector->allocated < count) vector_resize(vector, count); - for (start = string, p = string, i = 0; *p; p++) + for (start = string, p = string, i = 0; *p != '\0'; p++) if (*p == ' ' || *p == '\t') { if (start != p) vector->strings[i++] = xstrndup(start, p - start); @@ -470,7 +473,7 @@ cvector_split_space(char *string, struct cvector *vector) if (vector->allocated < count) cvector_resize(vector, count); - for (start = string, p = string, i = 0; *p; p++) + for (start = string, p = string, i = 0; *p != '\0'; p++) if (*p == ' ' || *p == '\t') { if (start != p) { *p = '\0'; diff --git a/util/vector.h b/util/vector.h index ac3bf18..6a872d3 100644 --- a/util/vector.h +++ b/util/vector.h @@ -8,6 +8,9 @@ * Vectors require list of strings, not arbitrary binary data, and cannot * handle data elements containing nul characters. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Written by Russ Allbery <rra@stanford.edu> * * The authors hereby relinquish any claim to any copyright that they may have @@ -97,7 +100,9 @@ void cvector_free(struct cvector *) * Empty strings will yield zero-length vectors. Adjacent delimiters are * treated as a single delimiter by *_split_space and *_split_multi, but *not* * by *_split, so callers of *_split should be prepared for zero-length - * strings in the vector. + * strings in the vector. *_split_space and *_split_multi ignore any leading + * or trailing delimiters, so those functions will never create zero-length + * strings (similar to the behavior of strtok). */ struct vector *vector_split(const char *string, char sep, struct vector *) __attribute__((__nonnull__(1))); diff --git a/util/xmalloc.c b/util/xmalloc.c index 0803999..839f5a0 100644 --- a/util/xmalloc.c +++ b/util/xmalloc.c @@ -55,6 +55,9 @@ * header file defines macros named xmalloc, etc. that pass the file name and * line number to these functions. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright (c) 2004, 2005, 2006 * by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, diff --git a/util/xmalloc.h b/util/xmalloc.h index 5447335..14d8831 100644 --- a/util/xmalloc.h +++ b/util/xmalloc.h @@ -1,6 +1,9 @@ /* * Prototypes for malloc routines with failure handling. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2010 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006 diff --git a/util/xwrite.c b/util/xwrite.c index 7e27654..8d472a7 100644 --- a/util/xwrite.c +++ b/util/xwrite.c @@ -21,6 +21,9 @@ * written, on the subsequent additional write; in that case, these functions * will return -1 and the number of bytes actually written will be lost. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2008 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006 diff --git a/util/xwrite.h b/util/xwrite.h index d79e801..2822727 100644 --- a/util/xwrite.h +++ b/util/xwrite.h @@ -1,6 +1,9 @@ /* * Prototypes for write and writev replacements to handle partial writes. * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * * Copyright 2008, 2010 * The Board of Trustees of the Leland Stanford Junior University * Copyright (c) 2004, 2005, 2006 |