summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/errno_names.c60
-rw-r--r--lib/errno_names.h5
-rw-r--r--lib/pthread_safe.c249
-rw-r--r--lib/pthread_safe.h4
-rw-r--r--lib/sockunion.c15
-rw-r--r--lib/sockunion.h2
-rw-r--r--lib/vty_io.c2
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);
}