diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/utils.c | 81 | ||||
-rw-r--r-- | src/libstrongswan/utils.h | 15 |
2 files changed, 92 insertions, 4 deletions
diff --git a/src/libstrongswan/utils.c b/src/libstrongswan/utils.c index f76245a19..f613b0c64 100644 --- a/src/libstrongswan/utils.c +++ b/src/libstrongswan/utils.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -25,6 +25,7 @@ #include <limits.h> #include <dirent.h> #include <time.h> +#include <pthread.h> #include "enum.h" #include "debug.h" @@ -194,6 +195,83 @@ bool mkdir_p(const char *path, mode_t mode) return TRUE; } + +/** + * The size of the thread-specific error buffer + */ +#define STRERROR_BUF_LEN 256 + +/** + * Key to store thread-specific error buffer + */ +static pthread_key_t strerror_buf_key; + +/** + * Only initialize the key above once + */ +static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT; + +/** + * Create the key used for the thread-specific error buffer + */ +static void create_strerror_buf_key() +{ + pthread_key_create(&strerror_buf_key, free); +} + +/** + * Retrieve the error buffer assigned to the current thread (or create it) + */ +static inline char *get_strerror_buf() +{ + char *buf; + + pthread_once(&strerror_buf_key_once, create_strerror_buf_key); + buf = pthread_getspecific(strerror_buf_key); + if (!buf) + { + buf = malloc(STRERROR_BUF_LEN); + pthread_setspecific(strerror_buf_key, buf); + } + return buf; +} + +#ifdef HAVE_STRERROR_R +/* + * Described in header. + */ +const char *safe_strerror(int errnum) +{ + char *buf = get_strerror_buf(), *msg; + +#ifdef STRERROR_R_CHAR_P + /* char* version which may or may not return the original buffer */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN); +#else + /* int version returns 0 on success */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf; +#endif + return msg; +} +#else /* HAVE_STRERROR_R */ +/* + * Described in header. + */ +const char *safe_strerror(int errnum) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + char *buf = get_strerror_buf(); + + /* use a mutex to ensure calling strerror(3) is thread-safe */ + pthread_mutex_lock(&mutex); + strncpy(buf, strerror(errnum), STRERROR_BUF_LEN); + pthread_mutex_unlock(&mutex); + buf[STRERROR_BUF_LEN - 1] = '\0'; + return buf; +} +#endif /* HAVE_STRERROR_R */ + + #ifndef HAVE_CLOSEFROM /** * Described in header. @@ -315,7 +393,6 @@ void nop() } #ifndef HAVE_GCC_ATOMIC_OPERATIONS -#include <pthread.h> /** * We use a single mutex for all refcount variables. diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index aeaa4e74b..954925dab 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -410,6 +410,18 @@ char *translate(char *str, const char *from, const char *to); */ bool mkdir_p(const char *path, mode_t mode); +/** + * Thread-safe wrapper around strerror and strerror_r. + * + * This is required because the first is not thread-safe (on some platforms) + * and the second uses two different signatures (POSIX/GNU) and is impractical + * to use anyway. + * + * @param errnum error code (i.e. errno) + * @return error message + */ +const char *safe_strerror(int errnum); + #ifndef HAVE_CLOSEFROM /** * Close open file descriptors greater than or equal to lowfd. @@ -628,7 +640,6 @@ bool cas_bool(bool *ptr, bool oldval, bool newval); */ bool cas_ptr(void **ptr, void *oldval, void *newval); - #endif /* HAVE_GCC_ATOMIC_OPERATIONS */ /** |