Commit f3cdcadf authored by Pierangelo Masarati's avatar Pierangelo Masarati
Browse files

wrap gmtime for reentrancy (ITS#6262)

parent 959fd984
...@@ -1859,6 +1859,7 @@ dnl ---------------------------------------------------------------- ...@@ -1859,6 +1859,7 @@ dnl ----------------------------------------------------------------
dnl Tests for reentrant functions necessary to build -lldap_r dnl Tests for reentrant functions necessary to build -lldap_r
AC_CHECK_FUNCS( \ AC_CHECK_FUNCS( \
ctime_r \ ctime_r \
gmtime_r localtime_r \
gethostbyname_r gethostbyaddr_r \ gethostbyname_r gethostbyaddr_r \
) )
......
...@@ -367,7 +367,7 @@ best_guess( Operation *op, ...@@ -367,7 +367,7 @@ best_guess( Operation *op,
struct berval *bv_modifiersName, struct berval *bv_nmodifiersName ) struct berval *bv_modifiersName, struct berval *bv_nmodifiersName )
{ {
if ( bv_entryCSN ) { if ( bv_entryCSN ) {
char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
struct berval entryCSN; struct berval entryCSN;
entryCSN.bv_val = csnbuf; entryCSN.bv_val = csnbuf;
...@@ -836,7 +836,7 @@ lastmod_db_open( ...@@ -836,7 +836,7 @@ lastmod_db_open(
char buf[ 8192 ]; char buf[ 8192 ];
static char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ]; static char tmbuf[ LDAP_LUTIL_GENTIME_BUFSIZE ];
char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
struct berval entryCSN; struct berval entryCSN;
struct berval timestamp; struct berval timestamp;
......
...@@ -91,6 +91,43 @@ ldap_pvt_ctime LDAP_P(( ...@@ -91,6 +91,43 @@ ldap_pvt_ctime LDAP_P((
const time_t *tp, const time_t *tp,
char *buf )); char *buf ));
# if defined( HAVE_GMTIME_R )
# define USE_GMTIME_R
# define ldap_pvt_gmtime_lock() (0)
# define ldap_pvt_gmtime_unlock() (0)
# define ldap_pvt_gmtime(timep, result) gmtime_r((timep), (result))
# else
LDAP_F( int )
ldap_pvt_gmtime_lock LDAP_P(( void ));
LDAP_F( int )
ldap_pvt_gmtime_unlock LDAP_P(( void ));
LDAP_F( struct tm * )
ldap_pvt_gmtime LDAP_P((
LDAP_CONST time_t *timep,
struct tm *result ));
#endif
# if defined( HAVE_LOCALTIME_R )
# define USE_LOCALTIME_R
# define ldap_pvt_localtime(timep, result) localtime_r((timep), (result))
# else
LDAP_F( struct tm * )
ldap_pvt_localtime LDAP_P((
LDAP_CONST time_t *timep,
struct tm *result ));
# endif
/* Get current time as a structured time */
LDAP_F( void )
ldap_pvt_gettime LDAP_P(( struct lutil_tm * ));
/* use this macro to allocate buffer for ldap_pvt_csnstr */
#define LDAP_PVT_CSNSTR_BUFSIZE 64
LDAP_F( size_t )
ldap_pvt_csnstr( char *buf, size_t len, unsigned int replica, unsigned int mod );
LDAP_F( char *) ldap_pvt_get_fqdn LDAP_P(( char * )); LDAP_F( char *) ldap_pvt_get_fqdn LDAP_P(( char * ));
struct hostent; /* avoid pulling in <netdb.h> */ struct hostent; /* avoid pulling in <netdb.h> */
......
...@@ -177,10 +177,6 @@ LDAP_LUTIL_F( int ) ...@@ -177,10 +177,6 @@ LDAP_LUTIL_F( int )
lutil_tm2time LDAP_P(( lutil_tm2time LDAP_P((
struct lutil_tm *, struct lutil_timet * )); struct lutil_tm *, struct lutil_timet * ));
/* Get current time as a structured time */
LDAP_LUTIL_F( void )
lutil_gettime LDAP_P(( struct lutil_tm * ));
#ifdef _WIN32 #ifdef _WIN32
LDAP_LUTIL_F( void ) LDAP_LUTIL_F( void )
lutil_slashpath LDAP_P(( char* path )); lutil_slashpath LDAP_P(( char* path ));
...@@ -229,12 +225,6 @@ lutil_uuidstr_from_normalized( ...@@ -229,12 +225,6 @@ lutil_uuidstr_from_normalized(
char *buf, char *buf,
size_t buflen ); size_t buflen );
/* csn.c */
/* use this macro to allocate buffer for lutil_csnstr */
#define LDAP_LUTIL_CSNSTR_BUFSIZE 64
LDAP_LUTIL_F( size_t )
lutil_csnstr( char *buf, size_t len, unsigned int replica, unsigned int mod );
/* /*
* Sometimes not all declarations in a header file are needed. * Sometimes not all declarations in a header file are needed.
* An indicator to this is whether or not the symbol's type has * An indicator to this is whether or not the symbol's type has
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#endif #endif
#include "../liblber/lber-int.h" #include "../liblber/lber-int.h"
#include "lutil.h"
#ifdef LDAP_R_COMPILE #ifdef LDAP_R_COMPILE
#include <ldap_pvt_thread.h> #include <ldap_pvt_thread.h>
......
...@@ -66,6 +66,15 @@ extern int h_errno; ...@@ -66,6 +66,15 @@ extern int h_errno;
static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex; static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
# endif # endif
/* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
#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
# if defined(HAVE_GETHOSTBYNAME_R) && \ # if defined(HAVE_GETHOSTBYNAME_R) && \
(GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS) (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
/* Don't know how to handle this version, pretend it's not there */ /* Don't know how to handle this version, pretend it's not there */
...@@ -107,6 +116,204 @@ char *ldap_pvt_ctime( const time_t *tp, char *buf ) ...@@ -107,6 +116,204 @@ char *ldap_pvt_ctime( const time_t *tp, char *buf )
#endif #endif
} }
#ifndef USE_GMTIME_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 */
}
struct tm *
ldap_pvt_gmtime( const time_t *timep, struct tm *result )
{
struct tm *tm_ptr;
# ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
# endif /* LDAP_R_COMPILE */
tm_ptr = gmtime( timep );
if ( tm_ptr != NULL ) {
*result = *tm_ptr;
}
# ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
# endif /* LDAP_R_COMPILE */
return tm_ptr;
}
#endif /* !USE_GMTIME_R */
#ifndef USE_LOCALTIME_R
struct tm *
ldap_pvt_localtime( const time_t *timep, struct tm *result )
{
struct tm *tm_ptr;
# ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
# endif /* LDAP_R_COMPILE */
tm_ptr = localtime( timep );
if ( tm_ptr != NULL ) {
*result = *tm_ptr;
}
# ifdef LDAP_R_COMPILE
ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
# endif /* LDAP_R_COMPILE */
return tm_ptr;
}
#endif /* !USE_LOCALTIME_R */
/* return a broken out time, with microseconds
* Must be mutex-protected.
*/
#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.
*/
if ( count.QuadPart <= prevCount.QuadPart ) {
subs++;
} else {
subs = 0;
prevCount = count;
}
/* 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;
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;
}
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 BUFSTART (1024-32)
#define BUFMAX (32*1024-32) #define BUFMAX (32*1024-32)
...@@ -405,6 +612,9 @@ void ldap_int_utils_init( void ) ...@@ -405,6 +612,9 @@ void ldap_int_utils_init( void )
#ifdef LDAP_R_COMPILE #ifdef LDAP_R_COMPILE
#if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS ) #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex ); 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 #endif
ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex ); ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
......
...@@ -27,14 +27,14 @@ UNIX_OBJS = detach.o ...@@ -27,14 +27,14 @@ UNIX_OBJS = detach.o
XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA) XLIBS = $(LIBRARY) $(LDAP_LIBLBER_LA)
SRCS = base64.c csn.c entropy.c sasl.c signal.c hash.c passfile.c \ SRCS = base64.c entropy.c sasl.c signal.c hash.c passfile.c \
md5.c passwd.c sha1.c getpass.c lockf.c utils.c uuid.c sockpair.c \ md5.c passwd.c sha1.c getpass.c lockf.c utils.c uuid.c sockpair.c \
avl.c tavl.c ldif.c fetch.c \ avl.c tavl.c ldif.c fetch.c \
testavl.c \ testavl.c \
meter.c \ meter.c \
@LIBSRCS@ $(@PLAT@_SRCS) @LIBSRCS@ $(@PLAT@_SRCS)
OBJS = base64.o csn.o entropy.o sasl.o signal.o hash.o passfile.o \ OBJS = base64.o entropy.o sasl.o signal.o hash.o passfile.o \
md5.o passwd.o sha1.o getpass.o lockf.o utils.o uuid.o sockpair.o \ md5.o passwd.o sha1.o getpass.o lockf.o utils.o uuid.o sockpair.o \
avl.o tavl.o ldif.o fetch.o \ avl.o tavl.o ldif.o fetch.o \
meter.o \ meter.o \
......
/* csn.c - Change Sequence Number routines */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2009 The OpenLDAP Foundation.
* Portions Copyright 2000-2003 Kurt D. Zeilenga.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* Portions Copyright 2000, John E. Schimmel, All rights reserved.
* This software is not subject to any license of Mirapoint, Inc.
*
* This is free software; you can redistribute and use it
* under the same terms as OpenLDAP itself.
*/
/* This work was developed by John E. Schimmel and adapted for
* inclusion in OpenLDAP Software by Kurt D. Zeilenga.
*/
/* This file contains routines to generate a change sequence number.
* Every add, delete, and modification is given a unique identifier
* for use in resolving conflicts during replication operations.
*
* These routines are (loosly) based upon draft-ietf-ldup-model-03.txt,
* A WORK IN PROGRESS. The format will likely change.
*
* The format of a CSN string is: yyyymmddhhmmssz#s#r#c
* where s is a counter of operations within a timeslice, r is
* the replica id (normally zero), and c is a counter of
* modifications within this operation. s, r, and c are
* represented in hex and zero padded to lengths of 6, 3, and
* 6, respectively. (In previous implementations r was only 2 digits.)
*
* Calls to this routine MUST be serialized with other calls
* to gmtime().
*/
#include "portable.h"
#include <stdio.h>
#include <ac/time.h>
#include <lutil.h>
/* Must be mutex-protected, because lutil_gettime needs mutex protection */
size_t
lutil_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
{
struct lutil_tm tm;
int n;
lutil_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;
}
#ifdef TEST
int
main(int argc, char **argv)
{
char buf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
if ( ! lutil_csnstr( buf, (size_t) 10, 0, 0 ) ) {
fprintf(stderr, "failed lutil_csnstr\n");
}
if ( ! lutil_csnstr( buf, sizeof(buf), 0, 0 ) ) {
fprintf(stderr, "failed lutil_csnstr\n");
}
}
#endif
...@@ -282,128 +282,6 @@ int lutil_parsetime( char *atm, struct lutil_tm *tm ) ...@@ -282,128 +282,6 @@ int lutil_parsetime( char *atm, struct lutil_tm *tm )
return -1; return -1;
} }
/* return a broken out time, with microseconds
* Must be mutex-protected.
*/
#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
lutil_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.
*/
if ( count.QuadPart <= prevCount.QuadPart ) {
subs++;
} else {
subs = 0;
prevCount = count;
}
/* 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
lutil_gettime( struct lutil_tm *ltm )
{
struct timeval tv;
static struct timeval prevTv;
static int subs;
#ifdef HAVE_GMTIME_R
struct tm tm_buf;
#endif
struct tm *tm;
time_t t;
gettimeofday( &tv, NULL );
t = tv.tv_sec;
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;
}
ltm->tm_usub = subs;
#ifdef HAVE_GMTIME_R
tm = gmtime_r( &t, &tm_buf );
#else
tm = gmtime( &t );
#endif
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
/* strcopy is like strcpy except it returns a pointer to the trailing NUL of /* strcopy is like strcpy except it returns a pointer to the trailing NUL of
* the result string. This allows fast construction of catenated strings * the result string. This allows fast construction of catenated strings
* without the overhead of strlen/strcat. * without the overhead of strlen/strcat.
...