diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/errno_names.c | 60 | ||||
-rw-r--r-- | lib/errno_names.h | 5 | ||||
-rw-r--r-- | lib/pthread_safe.c | 249 | ||||
-rw-r--r-- | lib/pthread_safe.h | 4 | ||||
-rw-r--r-- | lib/sockunion.c | 15 | ||||
-rw-r--r-- | lib/sockunion.h | 2 | ||||
-rw-r--r-- | lib/vty_io.c | 2 |
7 files changed, 283 insertions, 54 deletions
diff --git a/lib/errno_names.c b/lib/errno_names.c index 51f430a9..791f8001 100644 --- a/lib/errno_names.c +++ b/lib/errno_names.c @@ -21,6 +21,8 @@ #include <stddef.h> #include <errno.h> +#include <netdb.h> + #include "errno_names.h" /*============================================================================== @@ -291,7 +293,7 @@ static const char* errno_name_table[] = enum { errno_last = (sizeof(errno_name_table) / sizeof(char*)) - 1 } ; -/*============================================================================== +/*------------------------------------------------------------------------------ * Lookup the name for given error number. * * Returns: address of string, or NULL if not known @@ -308,4 +310,60 @@ errno_name_lookup(int err) return errno_name_table[err] ; } ; +/*============================================================================== + * Table to map EAI error number to its name -- the errors generated by + * getaddrinfo() and getnameinfo(). + * + * At least one system uses -ve numbers for these... so the following will + * support either +ve or -ve values, provided that all have the same sign. + */ +#if EAI_AGAIN < 0 +enum { eai_sgn = -1 } ; +#else +enum { eai_sgn = +1 } ; +#endif + +#define EAINO(eai) [eai * eai_sgn] = #eai + +static const char* eaino_name_table[] = +{ + /* Error number for no error + * + * (123456789012345), /-- no name is more than 15 characters + */ + EAINO(EAI_OK), /* No error */ + /* POSIX Error Numbers -- taken Open Group Base Specifications Issue 7 + * IEEE Std 1003.1-2008 + */ + EAINO(EAI_AGAIN), /* Temporary failure in name resolution. */ + EAINO(EAI_BADFLAGS), /* Invalid value for 'ai_flags' field. */ + EAINO(EAI_FAIL), /* Non-recoverable failure in name res. */ + EAINO(EAI_FAMILY), /* 'ai_family' not supported. */ + EAINO(EAI_MEMORY), /* Memory allocation failure. */ + EAINO(EAI_NONAME), /* NAME or SERVICE is unknown. */ + EAINO(EAI_OVERFLOW), /* Argument buffer overflow. */ + EAINO(EAI_SERVICE), /* SERVICE not supported for 'ai_socktype'. */ + EAINO(EAI_SOCKTYPE), /* 'ai_socktype' not supported. */ + EAINO(EAI_SYSTEM), /* System error returned in 'errno'. */ +} ; + +enum { eaino_last = (sizeof(eaino_name_table) / sizeof(char*)) - 1 } ; + +/*------------------------------------------------------------------------------ + * Lookup the name for given error number. + * + * Returns: address of string, or NULL if not known + * + * NB: for 0 returns "EOK". + * + * NB: async-signal-safe and thread-safe ! + */ +extern const char* +eaino_name_lookup(int eai) +{ + eai *= eai_sgn ; + if ((eai < 0) || (eai > eaino_last)) + return NULL ; + return eaino_name_table[eai] ; +} ; diff --git a/lib/errno_names.h b/lib/errno_names.h index f095640d..a4f1f2e3 100644 --- a/lib/errno_names.h +++ b/lib/errno_names.h @@ -23,4 +23,9 @@ #define EOK 0 #endif +#ifndef EAI_OK +#define EAI_OK 0 +#endif + extern const char* errno_name_lookup(int err) ; +extern const char* eaino_name_lookup(int err) ; diff --git a/lib/pthread_safe.c b/lib/pthread_safe.c index b6c429e4..c4ab9679 100644 --- a/lib/pthread_safe.c +++ b/lib/pthread_safe.c @@ -36,6 +36,7 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> +#include <netdb.h> #include "qfstring.h" #include "errno_names.h" @@ -101,29 +102,94 @@ safe_strerror(int errnum) } } -/*------------------------------------------------------------------------------ - * Construct string to describe the given error of the form: +/*============================================================================== + * Alternative error number handling. * - * ENAME '<strerror>' + * The descriptive strings for error numbers are all very well, but for some + * purposes knowing the name for the error is more useful -- the name, not the + * number, as the number is system dependent. + * + * The following provides: + * + * * errtoa() -- which maps error number to: ENAME '<strerror>' * - * where <strerror> is given by strerror() or, if pthreads_enabled, strerror_r() + * * errtoname() -- which maps error number to: ENAME * - * Truncates the result to the given len (0 => no truncation). But silently - * imposes the maximum length allowed by the strerror_t. + * * errtostr() -- which maps error number to: <strerror> * - * If has to truncate, places "..." at the end of the message to show this has - * happened. + * where: * - * If a name is not known then (assuming strerror() won't know it either): + * * if name is not known gives: ERRNO=999 * - * ERRNO=999 *unknown error* + * * if strerror rejects the number gives: *unknown error* * - * For err==0 returns: + * * err == 0 gives: EOK -- for the name + * 'no error' -- for the <strerror> + * + * These functions take a 'len' argument, and truncates the result to the given + * len (0 => no truncation) -- silently imposing the maximum length allowed by + * the strerror_t. + * + * If has to truncate the <strerror>, places "..." at the end of the message + * to show this has happened. + */ + +static void errtox(strerror_t* st, int err, int len, int want) ; + +/*------------------------------------------------------------------------------ + * Construct string to describe the given error of the form: + * + * ENAME '<strerror>' + * + * Thread safe extension to strerror. Never returns NULL. + */ +extern strerror_t +errtoa(int err, int len) +{ + strerror_t st ; + + errtox(&st, err, len, 3) ; /* name and message */ + + return st ; +} ; + +/*------------------------------------------------------------------------------ + * Convert error number to its name * - * EOK 'no error' + * Thread-safe. Never returns NULL. + */ +extern strerror_t +errtoname(int err, int len) +{ + strerror_t st ; + + errtox(&st, err, len, 1) ; /* name */ + + return st ; +} ; + +/*------------------------------------------------------------------------------ + * Alternative thread-safe safe_strerror() * * Thread safe replacement for strerror. Never returns NULL. */ +extern strerror_t +errtostr(int err, int len) +{ + strerror_t st ; + + errtox(&st, err, len, 2) ; /* message */ + + return st ; +} ; + +/*----------------------------------------------------------------------------- + * Common code for errto<x> above. + * + * want == 1 -- return just name + * want == 2 -- return just the strerror() + * want == 3 -- return both, with the strerror() in single quotes. + */ static void errtox(strerror_t* st, int err, int len, int want) { @@ -241,86 +307,169 @@ errtox(strerror_t* st, int err, int len, int want) errno = errno_saved ; } ; -/*------------------------------------------------------------------------------ - * Construct string to describe the given error of the form: +/*============================================================================== + * getaddrinfo() and getnameinfo() "EAI_XXXX" error number handling. * - * ENAME '<strerror>' + * This is similar to the above for errno. * - * where <strerror> is given by strerror() or, if pthreads_enabled, strerror_r() + * The following provides: * - * Truncates the result to the given len (0 => no truncation). But silently - * imposes the maximum length allowed by the strerror_t. + * * eaitoa() -- which maps error number to: EAI_XXX '<gai_strerror>' + * or: as errtoa() * - * If has to truncate, places "..." at the end of the message to show this has - * happened. + * * eaitoname() -- which maps error number to: EAI_XXX + * or: as errtoname() * - * If a name is not known then (assuming strerror() won't know it either): + * * eaitostr() -- which maps error number to: <gai_strerror> + * or: as errtostr() * - * ERRNO=999 *unknown error* + * where: * - * For err==0 returns: + * * if given EAI_SYSTEM, and given a non-zero errno type error number, + * produce the errno string. * - * EOK 'no error' + * * if name is not known gives: EAI=999 * - * Thread safe replacement for strerror. Never returns NULL. + * * gai_strerror returns a string saying the error is not known if that is + * the case. + * + * * eai == 0 gives: EAI_OK -- for the name + * 'no error' -- for the <sgai_strerror> + * + * NB: EAI_SYSTEM is an invitation to look at errno to discover the true + * error. + */ + +static void eaitox(strerror_t* st, int eai, int err, int len, int want) ; + +/*------------------------------------------------------------------------------ + * Construct string to describe the given EAI_XXX error of the form: + * + * EAI_XXX '<gai_strerror>' + * or: ENAME '<strerror>' -- if EAI_SYSTEM and err != 0 + * + * Thread safe. Never returns NULL. */ extern strerror_t -errtoa(int err, int len) +eaitoa(int eai, int err, int len) { strerror_t st ; - errtox(&st, err, len, 3) ; /* name and message */ + eaitox(&st, eai, err, len, 3) ; /* name and message */ return st ; } ; /*------------------------------------------------------------------------------ - * Convert error number to its name - - * If a name is not known then: - * - * ERRNO=999 - * - * For err==0 returns: + * Convert EAI_XXX error number to its name... * - * EOK + * ...or, if EAI_SYSTEM and err != 0, convert err to its name. * - * Truncates the result to the given len (0 => no truncation). But silently - * imposes the maximum length allowed by the strerror_t. - * - * This is thread-safe. + * Thread-safe. Never returns NULL. */ extern strerror_t -errtoname(int err, int len) +eaitoname(int eai, int err, int len) { strerror_t st ; - errtox(&st, err, len, 1) ; /* name */ + eaitox(&st, eai, err, len, 1) ; /* name */ return st ; } ; /*------------------------------------------------------------------------------ - * Alternative thread-safe safe_strerror() + * Alternative to gai_strerror()... * - * Truncates the result to the given len (0 => no truncation). But silently - * imposes the maximum length allowed by the strerror_t. + * ...or, if EAI_SYSTEM and err != 0, do strerror(err) or strerror_r(err). * - * If the <strerror> will not fit in the strerror_t, it is truncated and - * '...' placed at the end to show this has happened. - * - * Thread safe replacement for strerror. Never returns NULL. + * Thread-safe. Never returns NULL. */ extern strerror_t -errtostr(int err, int len) +eaitostr(int eai, int err, int len) { strerror_t st ; - errtox(&st, err, len, 2) ; /* message */ + eaitox(&st, eai, err, len, 2) ; /* message */ return st ; } ; +/*----------------------------------------------------------------------------- + * Common code for eaito<x> above. + * + * want == 1 -- return just name + * want == 2 -- return just the gai_strerror() + * want == 3 -- return both, with the gai_strerror() in single quotes. + * + * err != 0 => if EAI_SYSTEM, return result for errno == err instead. + */ +static void +eaitox(strerror_t* st, int eai, int err, int len, int want) +{ + qf_str_t qfs ; + + const char* q ; + int ql ; + + /* Look out for mapping EAI_SYSTEM */ + if ((eai == EAI_SYSTEM) && (err != 0)) + return errtox(st, err, len, want) ; + + /* Prepare. */ + int errno_saved = errno ; + + if ((len <= 0) || (len >= (int)sizeof(st->str))) + len = sizeof(st->str) - 1 ; + qfs_init(&qfs, st->str, len + 1) ; + + q = "" ; + ql = 0 ; + + /* If want the error name, do that now. */ + if (want & 1) + { + const char* name = eaino_name_lookup(eai) ; + + if (name != NULL) + qfs_append(&qfs, name) ; + else + qfs_printf(&qfs, "EAI=%d", eai) ; + } ; + + /* name and string ? */ + if (want == 3) + { + qfs_append(&qfs, " ") ; + q = "'" ; + ql = 2 ; + } ; + + /* If want the error string, do that now */ + if (want & 2) + { + const char* eaim ; + + if (eai == 0) + eaim = "no error" ; + else + eaim = gai_strerror(eai) ; + + /* Add strerror to the result... looking out for overflow. */ + len = strlen(eaim) ; + + if ((len + ql) <= qfs_left(&qfs)) /* accounting for "quotes" */ + qfs_printf(&qfs, "%s%s%s", q, eaim, q) ; + else + qfs_printf(&qfs, "%s%.*s...%s", q, qfs_left(&qfs) - ql - 3, eaim, q) ; + /* -ve precision is ignored ! */ + } ; + + /* Put back errno */ + errno = errno_saved ; +} ; + +/*============================================================================*/ + /* Thread safe version of inet_ntoa. Never returns NULL. * Contents of result remains intact until another call of * a safe_ function. diff --git a/lib/pthread_safe.h b/lib/pthread_safe.h index 0b2d7cdf..9518f3d1 100644 --- a/lib/pthread_safe.h +++ b/lib/pthread_safe.h @@ -39,4 +39,8 @@ extern strerror_t errtoa(int err, int len) ; extern strerror_t errtoname(int err, int len) ; extern strerror_t errtostr(int err, int len) ; +extern strerror_t eaitoa(int eai, int err, int len) ; +extern strerror_t eaitoname(int eai, int err, int len) ; +extern strerror_t eaitostr(int eai, int err, int len) ; + #endif /* PTHREAD_SAFE_H_ */ diff --git a/lib/sockunion.c b/lib/sockunion.c index 23287cd2..9a063190 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -209,7 +209,7 @@ sockunion_set_addr_any(sockunion su) * * For good measure, set the size (if that's required) and return same. */ -static int +extern int sockunion_set_port(sockunion su, in_port_t port) { switch (su->sa.sa_family) @@ -234,6 +234,8 @@ sockunion_set_port(sockunion su, in_port_t port) * * Allocates a sockunion if required. * + * Result is set "any". + * * Advice is to zeroize sockaddr_in6, in particular. */ extern sockunion @@ -455,7 +457,7 @@ sockunion_socket(sa_family_t family, int type, int protocol) err = errno ; zlog (NULL, LOG_WARNING, - "Can't make socket family=%d, type=%d, protocol=%d: %s", + "Cannot make socket family=%d, type=%d, protocol=%d: %s", (int)family, type, protocol, errtoa(err, 0).str) ; errno = err ; return -1; @@ -908,6 +910,15 @@ sockunion_dup (union sockunion *su) } /*------------------------------------------------------------------------------ + * Copy one sockunion to another + */ +extern void +sockunion_copy (sockunion dst, sockunion src) +{ + memcpy (dst, src, sizeof(*dst)) ; +} ; + +/*------------------------------------------------------------------------------ * Free given sockunion (if any). */ void diff --git a/lib/sockunion.h b/lib/sockunion.h index 3823c522..0b23ae63 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -101,6 +101,7 @@ struct sockunion_string /* Prototypes. */ extern sockunion sockunion_init_new(sockunion su, sa_family_t family) ; +extern int sockunion_set_port(sockunion su, in_port_t port) ; extern int str2sockunion (const char *, union sockunion *); extern const char *sockunion2str (union sockunion *, char *, size_t); extern sockunion_string_t sutoa(sockunion su) ; @@ -128,6 +129,7 @@ extern void sockunion_unmap_ipv4 (union sockunion *su) ; extern void sockunion_map_ipv4 (union sockunion *su) ; extern union sockunion *sockunion_dup (union sockunion *); +extern void sockunion_copy (sockunion dst, sockunion src) ; extern void sockunion_free (union sockunion *); extern sockunion sockunion_new_prefix(sockunion su, prefix p) ; diff --git a/lib/vty_io.c b/lib/vty_io.c index af61e97c..c4b4f528 100644 --- a/lib/vty_io.c +++ b/lib/vty_io.c @@ -1983,7 +1983,7 @@ uty_serv_sock_addrinfo (const char *hostname, unsigned short port) if (ret != 0) { - fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret)); + fprintf (stderr, "getaddrinfo failed: %s\n", eaitoa(ret, errno, 0).str); exit (1); } |