From b878aa88eb8bb7ab74e24314e87c88586f15598d Mon Sep 17 00:00:00 2001 From: Chris Hall Date: Sun, 11 Apr 2010 11:17:37 +0100 Subject: Support gai_strerror() and tidy bgp_listener code. Added support for EAI_XXX error names and gai_strerror() error messages. Tidied up bgp_listener set up to remove #if skips around the "old" way -- so that the older code doesn't simply rot away. --- lib/pthread_safe.c | 249 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 199 insertions(+), 50 deletions(-) (limited to 'lib/pthread_safe.c') 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 #include #include +#include #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 '' + * 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 '' * - * where 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: * - * 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 + * + * 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 , 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 '' + * + * 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 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 '' + * This is similar to the above for errno. * - * where 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 '' + * 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: + * 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 + * + * 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 '' + * or: ENAME '' -- 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 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 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. -- cgit v1.2.3