Thread-safe wrapper around strerror(3)/strerror_r(3) added
authorTobias Brunner <tobias@strongswan.org>
Wed, 27 Jun 2012 16:42:25 +0000 (18:42 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 28 Jun 2012 11:14:52 +0000 (13:14 +0200)
configure.in
src/libstrongswan/utils.c
src/libstrongswan/utils.h

index 7c2342c..363a584 100644 (file)
@@ -301,6 +301,7 @@ dnl ===========================================
 
 AC_HEADER_STDBOOL
 AC_FUNC_ALLOCA
+AC_FUNC_STRERROR_R
 
 dnl libraries needed on some platforms but not on others
 dnl ====================================================
index f76245a..f613b0c 100644 (file)
@@ -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.
index aeaa4e7..954925d 100644 (file)
@@ -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 */
 
 /**