From 81781310c5125e8784c1113e8306aef8f4e3c6d4 Mon Sep 17 00:00:00 2001 From: Kevin Wasserman Date: Thu, 30 Jun 2011 09:48:10 -0400 Subject: [PATCH] Consolidate thread-local data. Also add windows versions of MUTEX macros. Together, these changes eliminate dependency on pthread for windows and centralize the platform-specific code to deal with thread-local storage. --- moonshot/mech_eap/display_status.c | 66 +++++++-------- moonshot/mech_eap/util.h | 51 +++++++++--- moonshot/mech_eap/util_krb.c | 35 +++----- moonshot/mech_eap/util_tld.c | 160 +++++++++++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 74 deletions(-) create mode 100644 moonshot/mech_eap/util_tld.c diff --git a/moonshot/mech_eap/display_status.c b/moonshot/mech_eap/display_status.c index 2b41f18..89d8628 100644 --- a/moonshot/mech_eap/display_status.c +++ b/moonshot/mech_eap/display_status.c @@ -36,33 +36,24 @@ #include "gssapiP_eap.h" -static GSSEAP_THREAD_ONCE gssEapStatusInfoKeyOnce = GSSEAP_ONCE_INITIALIZER; -static GSSEAP_THREAD_KEY gssEapStatusInfoKey; - struct gss_eap_status_info { OM_uint32 code; char *message; struct gss_eap_status_info *next; }; -static void -destroyStatusInfo(void *arg) +void +gssEapDestroyStatusInfo(struct gss_eap_status_info* p) { - struct gss_eap_status_info *p = arg, *next; + struct gss_eap_status_info *next; - for (p = arg; p != NULL; p = next) { + for (; p != NULL; p = next) { next = p->next; GSSEAP_FREE(p->message); GSSEAP_FREE(p); } } -static void -createStatusInfoKey(void) -{ - GSSEAP_KEY_CREATE(&gssEapStatusInfoKey, destroyStatusInfo); -} - /* * Associate a message with a mechanism (minor) status code. This function * takes ownership of the message regardless of success. The message must @@ -73,23 +64,23 @@ createStatusInfoKey(void) static void saveStatusInfoNoCopy(OM_uint32 minor, char *message) { - struct gss_eap_status_info **next = NULL, *p; - - GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey); - - p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey); - for (; p != NULL; p = p->next) { - if (p->code == minor) { - /* Set message in-place */ - if (p->message != NULL) - GSSEAP_FREE(p->message); - p->message = message; - return; + struct gss_eap_status_info **next = NULL, *p=NULL; + + struct gss_eap_thread_local_data* tld = gssEapGetThreadLocalData(); + if (tld != NULL) { + for (p = tld->status_info; p != NULL; p = p->next) { + if (p->code == minor) { + /* Set message in-place */ + if (p->message != NULL) + GSSEAP_FREE(p->message); + p->message = message; + return; + } + next = &p->next; } - next = &p->next; - } - p = GSSEAP_CALLOC(1, sizeof(*p)); + p = GSSEAP_CALLOC(1, sizeof(*p)); + } if (p == NULL) { if (message != NULL) GSSEAP_FREE(message); @@ -102,23 +93,22 @@ saveStatusInfoNoCopy(OM_uint32 minor, char *message) if (next != NULL) *next = p; else - GSSEAP_SETSPECIFIC(gssEapStatusInfoKey, p); + tld->status_info = p; } static const char * getStatusInfo(OM_uint32 minor) { struct gss_eap_status_info *p; - - GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey); - - for (p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey); - p != NULL; - p = p->next) { - if (p->code == minor) - return p->message; + struct gss_eap_thread_local_data *tld=gssEapGetThreadLocalData(); + if (tld != NULL) { + for (p = tld->status_info; + p != NULL; + p = p->next) { + if (p->code == minor) + return p->message; + } } - return NULL; } diff --git a/moonshot/mech_eap/util.h b/moonshot/mech_eap/util.h index 89c9574..6e35fd4 100644 --- a/moonshot/mech_eap/util.h +++ b/moonshot/mech_eap/util.h @@ -64,26 +64,18 @@ #if defined(HAVE_SYS_PARAM_H) #include #endif +#if defined(HAVE_STDINT_H) +#include +#endif #include #include #include -///#if defined(HAVE_STDINT_H) -///#include -///#endif - -///#if defined(WIN32) -///#define INLINE __inline -///#else -///#define INLINE inline -///#endif - #if defined(WIN32) #define inline __inline #endif - #ifdef __cplusplus extern "C" { #endif @@ -99,13 +91,31 @@ extern "C" { #endif #if !defined(WIN32) -#define GSSEAP_CONSTRUCTOR __attribute__((constructor) +#define GSSEAP_CONSTRUCTOR __attribute__((constructor)) #define GSSEAP_DESTRUCTOR __attribute__((destructor)) #else #define GSSEAP_CONSTRUCTOR #define GSSEAP_DESTRUCTOR #endif +/* thread local storage */ +struct gss_eap_status_info; + +struct gss_eap_thread_local_data +{ + krb5_context context; + struct gss_eap_status_info* status_info; +}; + +struct gss_eap_thread_local_data* +gssEapGetThreadLocalData(); + +void +gssEapDestroyStatusInfo(struct gss_eap_status_info* status); + +void +gssEapDestroyKrbContext(krb5_context context); + /* util_buffer.c */ OM_uint32 makeStringBuffer(OM_uint32 *minor, @@ -704,6 +714,22 @@ verifyTokenHeader(OM_uint32 *minor, return GSS_S_FAILURE; \ } while (0) +#ifdef WIN32 +#include +#define GSSEAP_MUTEX CRITICAL_SECTION +// wrapper for EnterCriticalSection() to provide return value +inline int win32_mutex_init(CRITICAL_SECTION* m) +{ + EnterCriticalSection(m); + return 0; +} + +#define GSSEAP_MUTEX_INIT(m) win32_mutex_init((m)) +#define GSSEAP_MUTEX_DESTROY(m) DeleteCriticalSection((m)) +#define GSSEAP_MUTEX_LOCK(m) EnterCriticalSection((m)) +#define GSSEAP_MUTEX_UNLOCK(m) LeaveCriticalSection((m)) + +#else #include #define GSSEAP_MUTEX pthread_mutex_t @@ -722,6 +748,7 @@ verifyTokenHeader(OM_uint32 *minor, #define GSSEAP_THREAD_ONCE pthread_once_t #define GSSEAP_ONCE(o, i) pthread_once((o), (i)) #define GSSEAP_ONCE_INITIALIZER PTHREAD_ONCE_INIT +#endif /* Helper functions */ static inline void diff --git a/moonshot/mech_eap/util_krb.c b/moonshot/mech_eap/util_krb.c index 88ad6dd..73cf108 100644 --- a/moonshot/mech_eap/util_krb.c +++ b/moonshot/mech_eap/util_krb.c @@ -36,24 +36,13 @@ #include "gssapiP_eap.h" -static GSSEAP_THREAD_ONCE krbContextKeyOnce = GSSEAP_ONCE_INITIALIZER; -static GSSEAP_THREAD_KEY krbContextKey; - -static void -destroyKrbContext(void *arg) +void +gssEapDestroyKrbContext(krb5_context context) { - krb5_context context = (krb5_context)arg; - if (context != NULL) krb5_free_context(context); } -static void -createKrbContextKey(void) -{ - GSSEAP_KEY_CREATE(&krbContextKey, destroyKrbContext); -} - static krb5_error_code initKrbContext(krb5_context *pKrbContext) { @@ -91,22 +80,20 @@ cleanup: OM_uint32 gssEapKerberosInit(OM_uint32 *minor, krb5_context *context) { + struct gss_eap_thread_local_data* tld; *minor = 0; - GSSEAP_ONCE(&krbContextKeyOnce, createKrbContextKey); - - *context = GSSEAP_GETSPECIFIC(krbContextKey); - if (*context == NULL) { - *minor = initKrbContext(context); - if (*minor == 0) { - if (GSSEAP_SETSPECIFIC(krbContextKey, *context) != 0) { - *minor = errno; - krb5_free_context(*context); - *context = NULL; + tld = gssEapGetThreadLocalData(); + if (tld) + { + *context = tld->context; + if (*context == NULL) { + *minor = initKrbContext(context); + if (*minor == 0) { + tld->context = *context; } } } - return *minor == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE; } diff --git a/moonshot/mech_eap/util_tld.c b/moonshot/mech_eap/util_tld.c new file mode 100644 index 0000000..7679233 --- /dev/null +++ b/moonshot/mech_eap/util_tld.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Access all thread-local data through these methods which + * use pthreads to manage thread-local memory on Unix and TlsFoo() on Windows. + * This would be more flexible, scalable, and extensible + * if implemented through a callback interface, but given that + * there are currently only two 'clients', hard-coding seems more + * straightforward + */ +#include "gssapiP_eap.h" + +/* Clean up thread-local data; called on thread detach */ +static void +destroyThreadLocalData(struct gss_eap_thread_local_data* tld) +{ + if (tld->status_info) + gssEapDestroyStatusInfo(tld->status_info); + if (tld->context) + gssEapDestroyKrbContext(tld->context); + GSSEAP_FREE(tld); +} + +#ifdef WIN32 + +/* This is the tls index returned by TlsAlloc() on process init. + * Each thread, on thread attach in DllMain(), allocates its thread-local data and uses this index with TlsSetValue() to store it. + * It can then subsequently be retrieved with TlsGetValue() + */ +static DWORD tlsIndex; + +/* Access thread-local data */ +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData() +{ + return TlsGetValue(tlsIndex); +} + +/* DllMain() is the entry-point function for this DLL. */ +BOOL WINAPI DllMain(HINSTANCE hDLL, /* DLL module handle */ + DWORD reason, /* reason called */ + LPVOID reserved) /* reserved */ +{ + struct gss_eap_thread_local_data *tlsData; + + switch (reason) + { + // The DLL is loading due to process + // initialization or a call to LoadLibrary. + case DLL_PROCESS_ATTACH: + /* Allocate a TLS index. */ + if ((tlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return FALSE; + /* No break: Initialize the index for first thread.*/ + + /* The attached process creates a new thread. */ + case DLL_THREAD_ATTACH: + /* Initialize the TLS index for this thread. */ + tlsData = GSSEAP_CALLOC(1, sizeof(*tlsData)); + if (tlsData != NULL) + TlsSetValue(tlsIndex, tlsData); + + break; + + /* The thread of the attached process terminates. */ + case DLL_THREAD_DETACH: + /* Release the allocated memory for this thread. */ + tlsData = TlsGetValue(tlsIndex); + if (tlsData != NULL) + { + destroyThreadLocalData(tlsData); + TlsSetValue(tlsIndex, NULL); + } + + break; + + /* DLL unload due to process termination or FreeLibrary. */ + case DLL_PROCESS_DETACH: + /* Release the allocated memory for this thread. */ + tlsData = TlsGetValue(tlsIndex); + if (tlsData != NULL) + destroyThreadLocalData(tlsData); + /* Release the TLS index. */ + TlsFree(tlsIndex); + break; + + default: + break; + } + + return TRUE; + UNREFERENCED_PARAMETER(hDLL); + UNREFERENCED_PARAMETER(reserved); +} + +#else /* WIN32 */ + +/* PTHREAD implementation */ +static GSSEAP_THREAD_ONCE tldKeyOnce = GSSEAP_ONCE_INITIALIZER; +static GSSEAP_THREAD_KEY tldKey; +static void +pthreadDestroyThreadLocalData(void* arg) +{ + struct gss_eap_thread_local_data* tld = arg; + if (tld) + { + destroyThreadLocalData(tld); + } +} + +static void +createThreadLocalDataKey(void) +{ + GSSEAP_KEY_CREATE(&tldKey, pthreadDestroyThreadLocalData); +} + +struct gss_eap_thread_local_data * +gssEapGetThreadLocalData() +{ + struct gss_eap_thread_local_data *tld; + GSSEAP_ONCE(&tldKeyOnce, createThreadLocalDataKey); + tld = GSSEAP_GETSPECIFIC(tldKey); + if (!tld) + { + tld = GSSEAP_CALLOC(1, sizeof(*tld)); + GSSEAP_SETSPECIFIC(tldKey, tld); + } + return tld; +} + +#endif /* WIN32 */ -- 2.1.4