]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/util-int.c
Merge remote branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[openldap] / libraries / libldap / util-int.c
index dbdc8b298c54cce5c61b5f1da6a11536e3e2e4da..3510aec93e45550513d96b9076c25c1274a7a35b 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2004 The OpenLDAP Foundation.
+ * Copyright 1998-2012 The OpenLDAP Foundation.
  * Portions Copyright 1998 A. Hartgers.
  * All rights reserved.
  *
 extern int h_errno;
 #endif
 
+#ifdef HAVE_HSTRERROR
+# define HSTRERROR(e)  hstrerror(e)
+#else
+# define HSTRERROR(e)  hp_strerror(e)
+#endif
+
 #ifndef LDAP_R_COMPILE
 # undef HAVE_REENTRANT_FUNCTIONS
 # undef HAVE_CTIME_R
@@ -52,14 +58,30 @@ extern int h_errno;
 #else
 # include <ldap_pvt_thread.h>
   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
+  ldap_pvt_thread_mutex_t ldap_int_hostname_mutex;
+  static ldap_pvt_thread_mutex_t ldap_int_gettime_mutex;
 
-#if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
-       && defined( CTIME_R_NARGS )
-# define USE_CTIME_R
+# if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
+        && defined( CTIME_R_NARGS )
+#   define USE_CTIME_R
 # else
        static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
 # endif
 
+/* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
+
+#ifdef LDAP_DEVEL
+       /* to be released with 2.5 */
+#if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
+       /* we use the same mutex for gmtime(3) and localtime(3)
+        * because implementations may use the same buffer
+        * for both functions */
+       static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
+#endif
+#else /* ! LDAP_DEVEL */
+       ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
+#endif /* ! LDAP_DEVEL */
+
 # if defined(HAVE_GETHOSTBYNAME_R) && \
        (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
        /* Don't know how to handle this version, pretend it's not there */
@@ -87,29 +109,222 @@ char *ldap_pvt_ctime( const time_t *tp, char *buf )
 
 #else
 
-# ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex );
-# endif
-
+       LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex );
        AC_MEMCPY( buf, ctime(tp), 26 );
-
-# ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex );
-# endif
+       LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex );
 
        return buf;
 #endif 
 }
 
+#if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
+int
+ldap_pvt_gmtime_lock( void )
+{
+# ifndef LDAP_R_COMPILE
+       return 0;
+# else /* LDAP_R_COMPILE */
+       return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
+# endif /* LDAP_R_COMPILE */
+}
+
+int
+ldap_pvt_gmtime_unlock( void )
+{
+# ifndef LDAP_R_COMPILE
+       return 0;
+# else /* LDAP_R_COMPILE */
+       return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
+# endif /* LDAP_R_COMPILE */
+}
+#endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
+
+#ifndef USE_GMTIME_R
+struct tm *
+ldap_pvt_gmtime( const time_t *timep, struct tm *result )
+{
+       struct tm *tm_ptr;
+
+       LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
+       tm_ptr = gmtime( timep );
+       if ( tm_ptr == NULL ) {
+               result = NULL;
+
+       } else {
+               *result = *tm_ptr;
+       }
+       LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
+
+       return result;
+}
+#endif /* !USE_GMTIME_R */
+
+#ifndef USE_LOCALTIME_R
+struct tm *
+ldap_pvt_localtime( const time_t *timep, struct tm *result )
+{
+       struct tm *tm_ptr;
+
+       LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
+       tm_ptr = localtime( timep );
+       if ( tm_ptr == NULL ) {
+               result = NULL;
+
+       } else {
+               *result = *tm_ptr;
+       }
+       LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
+
+       return result;
+}
+#endif /* !USE_LOCALTIME_R */
+
+/* return a broken out time, with microseconds
+ */
+#ifdef _WIN32
+/* Windows SYSTEMTIME only has 10 millisecond resolution, so we
+ * also need to use a high resolution timer to get microseconds.
+ * This is pretty clunky.
+ */
+void
+ldap_pvt_gettime( struct lutil_tm *tm )
+{
+       static LARGE_INTEGER cFreq;
+       static LARGE_INTEGER prevCount;
+       static int subs;
+       static int offset;
+       LARGE_INTEGER count;
+       SYSTEMTIME st;
+
+       GetSystemTime( &st );
+       QueryPerformanceCounter( &count );
+
+       /* It shouldn't ever go backwards, but multiple CPUs might
+        * be able to hit in the same tick.
+        */
+       LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
+       if ( count.QuadPart <= prevCount.QuadPart ) {
+               subs++;
+       } else {
+               subs = 0;
+               prevCount = count;
+       }
+       LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
+
+       /* We assume Windows has at least a vague idea of
+        * when a second begins. So we align our microsecond count
+        * with the Windows millisecond count using this offset.
+        * We retain the submillisecond portion of our own count.
+        *
+        * Note - this also assumes that the relationship between
+        * the PerformanceCouunter and SystemTime stays constant;
+        * that assumption breaks if the SystemTime is adjusted by
+        * an external action.
+        */
+       if ( !cFreq.QuadPart ) {
+               long long t;
+               int usec;
+               QueryPerformanceFrequency( &cFreq );
+
+               /* just get sub-second portion of counter */
+               t = count.QuadPart % cFreq.QuadPart;
+
+               /* convert to microseconds */
+               t *= 1000000;
+               usec = t / cFreq.QuadPart;
+
+               offset = usec - st.wMilliseconds * 1000;
+       }
+
+       tm->tm_usub = subs;
+
+       /* convert to microseconds */
+       count.QuadPart %= cFreq.QuadPart;
+       count.QuadPart *= 1000000;
+       count.QuadPart /= cFreq.QuadPart;
+       count.QuadPart -= offset;
+
+       tm->tm_usec = count.QuadPart % 1000000;
+       if ( tm->tm_usec < 0 )
+               tm->tm_usec += 1000000;
+
+       /* any difference larger than microseconds is
+        * already reflected in st
+        */
+
+       tm->tm_sec = st.wSecond;
+       tm->tm_min = st.wMinute;
+       tm->tm_hour = st.wHour;
+       tm->tm_mday = st.wDay;
+       tm->tm_mon = st.wMonth - 1;
+       tm->tm_year = st.wYear - 1900;
+}
+#else
+void
+ldap_pvt_gettime( struct lutil_tm *ltm )
+{
+       struct timeval tv;
+       static struct timeval prevTv;
+       static int subs;
+
+       struct tm tm;
+       time_t t;
+
+       gettimeofday( &tv, NULL );
+       t = tv.tv_sec;
+
+       LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
+       if ( tv.tv_sec < prevTv.tv_sec
+               || ( tv.tv_sec == prevTv.tv_sec && tv.tv_usec <= prevTv.tv_usec )) {
+               subs++;
+       } else {
+               subs = 0;
+               prevTv = tv;
+       }
+       LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
+
+       ltm->tm_usub = subs;
+
+       ldap_pvt_gmtime( &t, &tm );
+
+       ltm->tm_sec = tm.tm_sec;
+       ltm->tm_min = tm.tm_min;
+       ltm->tm_hour = tm.tm_hour;
+       ltm->tm_mday = tm.tm_mday;
+       ltm->tm_mon = tm.tm_mon;
+       ltm->tm_year = tm.tm_year;
+       ltm->tm_usec = tv.tv_usec;
+}
+#endif
+
+size_t
+ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
+{
+       struct lutil_tm tm;
+       int n;
+
+       ldap_pvt_gettime( &tm );
+
+       n = snprintf( buf, len,
+               "%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
+               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
+               tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_usub, replica, mod );
+
+       if( n < 0 ) return 0;
+       return ( (size_t) n < len ) ? n : 0;
+}
+
 #define BUFSTART (1024-32)
 #define BUFMAX (32*1024-32)
 
+#if defined(LDAP_R_COMPILE)
 static char *safe_realloc( char **buf, int len );
 
-#if !defined(HAVE_GETHOSTBYNAME_R) && defined(LDAP_R_COMPILE)
+#if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
 static int copy_hostent( struct hostent *res,
        char **buf, struct hostent * src );
 #endif
+#endif
 
 int ldap_pvt_gethostbyname_a(
        const char *name, 
@@ -157,7 +372,7 @@ int ldap_pvt_gethostbyname_a(
        int     retval;
        *buf = NULL;
        
-       ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
+       LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
        
        he = gethostbyname( name );
        
@@ -172,7 +387,7 @@ int ldap_pvt_gethostbyname_a(
                retval = 0;
        }
        
-       ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
+       LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
        
        return retval;
 #else  
@@ -189,7 +404,7 @@ int ldap_pvt_gethostbyname_a(
 #endif 
 }
 
-#ifndef GETNAMEINFO
+#if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
 static const char *
 hp_strerror( int err )
 {
@@ -216,13 +431,9 @@ int ldap_pvt_get_hname(
        int rc;
 #if defined( HAVE_GETNAMEINFO )
 
-#if defined( LDAP_R_COMPILE )
-       ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
        rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
-#if defined( LDAP_R_COMPILE )
-       ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
        if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
        return rc;
 
@@ -249,7 +460,7 @@ int ldap_pvt_get_hname(
                alen = sizeof(sin->sin_addr);
        } else {
                rc = NO_RECOVERY;
-               *err = (char *)hp_strerror( rc );
+               *err = (char *)HSTRERROR( rc );
                return rc;
        }
 #if defined( HAVE_GETHOSTBYADDR_R )
@@ -281,25 +492,21 @@ int ldap_pvt_get_hname(
        if (hp) {
                strncpy( name, hp->h_name, namelen );
        } else {
-               *err = (char *)hp_strerror( h_errno );
+               *err = (char *)HSTRERROR( h_errno );
        }
        LDAP_FREE(buf);
 #else /* HAVE_GETHOSTBYADDR_R */
 
-#if defined( LDAP_R_COMPILE )
-       ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
        hp = gethostbyaddr( addr, alen, sa->sa_family );
        if (hp) {
                strncpy( name, hp->h_name, namelen );
                rc = 0;
        } else {
                rc = h_errno;
-               *err = (char *)hp_strerror( h_errno );
+               *err = (char *)HSTRERROR( h_errno );
        }
-#if defined( LDAP_R_COMPILE )
-       ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
 
 #endif /* !HAVE_GETHOSTBYADDR_R */
        return rc;
@@ -354,8 +561,7 @@ int ldap_pvt_gethostbyaddr_a(
        int     retval;
        *buf = NULL;   
        
-       ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
-       
+       LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
        he = gethostbyaddr( addr, len, type );
        
        if (he==NULL) {
@@ -368,8 +574,7 @@ int ldap_pvt_gethostbyaddr_a(
                *result = resbuf;
                retval = 0;
        }
-       
-       ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
+       LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
        
        return retval;
 
@@ -397,8 +602,22 @@ void ldap_int_utils_init( void )
 #ifdef LDAP_R_COMPILE
 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
        ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
+#endif
+#if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
+       ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
 #endif
        ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
+
+       ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex );
+
+       ldap_pvt_thread_mutex_init( &ldap_int_gettime_mutex );
+
+#ifdef HAVE_CYRUS_SASL
+       ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex );
+#endif
+#ifdef HAVE_GSSAPI
+       ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
+#endif
 #endif
 
        /* call other module init functions here... */
@@ -453,7 +672,7 @@ static int copy_hostent(
        int     n_alias=0;
        int     total_alias_len=0;
        int     n_addr=0;
-       int     total_addr_len;
+       int     total_addr_len=0;
        int     total_len;
          
        /* calculate the size needed for the buffer */
@@ -563,7 +782,9 @@ char *ldap_pvt_gai_strerror (int code) {
                { EAI_NONAME, N_("Name or service not known") },
                { EAI_SERVICE, N_("Servname not supported for ai_socktype") },
                { EAI_SOCKTYPE, N_("ai_socktype not supported") },
+#ifdef EAI_SYSTEM
                { EAI_SYSTEM, N_("System error") },
+#endif
                { 0, NULL }
        };