]> git.sur5r.net Git - openldap/blobdiff - libraries/liblutil/uuid.c
Sync with HEAD
[openldap] / libraries / liblutil / uuid.c
index 54595b39fcbd57f8152f7c17f3b5992f884de3a0..1627aa41fc519dc09b65f51d7cad5f0da84a3822 100644 (file)
@@ -1,15 +1,28 @@
-/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+/* uuid.c -- Universally Unique Identifier routines */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2000-2003 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.
+/* 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.
  */
-/* Adapted for incorporatation into OpenLDAP by Kurt Zeilenga */
+/* This work was initially developed by John E. Schimmel and adapted
+ * for inclusion in OpenLDAP Software by Kurt D. Zeilenga.
+ */
 
 /*
  * Sorry this file is so scary, but it needs to run on a wide range of
  */
 #include "portable.h"
 
+#include <limits.h>
 #include <stdio.h>
 #include <sys/types.h>
 
-#ifdef HAVE_SYS_UUID_H
+#include <ac/stdlib.h>
+#include <ac/string.h> /* get memcmp() */
+
+#ifdef HAVE_UUID_TO_STR
 #  include <sys/uuid.h>
+#elif defined( _WIN32 )
+#  include <rpc.h>
 #else
 #  include <ac/socket.h>
-#  include <net/if.h>
-#  include <sys/time.h>
+#  include <ac/time.h>
 #  ifdef HAVE_SYS_SYSCTL_H
+#    include <net/if.h>
 #    include <sys/sysctl.h>
 #    include <net/route.h>
 #  endif
 
 #include <lutil.h>
 
-/* 100 usec intervals from 10/10/1582 to 1/1/1970 */
-#define UUID_TPLUS     0x01B21DD2138140LL
-
-#ifndef HAVE_SYS_UUID_H
+/* not needed for Windows */
+#if !defined(HAVE_UUID_TO_STR) && !defined(_WIN32)
 static unsigned char *
 lutil_eaddr( void )
 {
@@ -93,7 +110,7 @@ lutil_eaddr( void )
        free(buf);
        return NULL;
 
-#elif defined (SIOCGIFADDR)
+#elif defined( SIOCGIFADDR ) && defined( AFLINK )
        char buf[sizeof(struct ifreq) * 32];
        struct ifconf ifc;
        struct ifreq *ifr;
@@ -152,14 +169,90 @@ lutil_eaddr( void )
        if (memcmp(eaddr, zero, sizeof(eaddr)) == 0) {
                /* XXX - who knows? */
                lutil_entropy( eaddr, sizeof(eaddr) );
-               eaddr[0] |= 0x80; /* turn it into a mutlicast address */
+               eaddr[0] |= 0x80; /* turn it into a multicast address */
        }
 
        return eaddr;
 #endif
 }
+
+#if (ULONG_MAX >> 31 >> 31) > 1 || defined HAVE_LONG_LONG
+
+#if (ULONG_MAX >> 31 >> 31) > 1
+    typedef unsigned long       UI64;
+       /* 100 usec intervals from 10/10/1582 to 1/1/1970 */
+#   define UUID_TPLUS           0x01B21DD2138140ul
+#else
+    typedef unsigned long long  UI64;
+#   define UUID_TPLUS           0x01B21DD2138140ull
 #endif
 
+#define high32(i)           ((unsigned long) ((i) >> 32))
+#define low32(i)            ((unsigned long) (i) & 0xFFFFFFFFul)
+#define set_add64(res, i)   ((res) += (i))
+#define set_add64l(res, i)  ((res) += (i))
+#define mul64ll(i1, i2)     ((UI64) (i1) * (i2))
+
+#else /* ! (ULONG_MAX >= 64 bits || HAVE_LONG_LONG) */
+
+typedef struct {
+       unsigned long high, low;
+} UI64;
+
+static const UI64 UUID_TPLUS = { 0x01B21Dul, 0xD2138140ul };
+
+#define high32(i)                       ((i).high)
+#define low32(i)                        ((i).low)
+
+/* res += ui64 */
+#define set_add64(res, ui64) \
+{ \
+       res.high += ui64.high; \
+       res.low  = (res.low + ui64.low) & 0xFFFFFFFFul; \
+       if (res.low < ui64.low) res.high++; \
+}
+
+/* res += ul32 */
+#define set_add64l(res, ul32) \
+{ \
+       res.low = (res.low + ul32) & 0xFFFFFFFFul; \
+       if (res.low < ul32) res.high++; \
+}
+
+/* compute i1 * i2 */
+static UI64
+mul64ll(unsigned long i1, unsigned long i2)
+{
+       const unsigned int high1 = (i1 >> 16), low1 = (i1 & 0xffff);
+       const unsigned int high2 = (i2 >> 16), low2 = (i2 & 0xffff);
+
+       UI64 res;
+       unsigned long tmp;
+
+       res.high = (unsigned long) high1 * high2;
+       res.low  = (unsigned long) low1  * low2;
+
+       tmp = (unsigned long) low1 * high2;
+       res.high += (tmp >> 16);
+       tmp = (tmp << 16) & 0xFFFFFFFFul;
+       res.low = (res.low + tmp) & 0xFFFFFFFFul;
+       if (res.low < tmp)
+               res.high++;
+
+       tmp = (unsigned long) low2 * high1;
+       res.high += (tmp >> 16);
+       tmp = (tmp << 16) & 0xFFFFFFFFul;
+       res.low = (res.low + tmp) & 0xFFFFFFFFul;
+       if (res.low < tmp)
+               res.high++;
+
+       return res;
+}
+
+#endif /* ULONG_MAX >= 64 bits || HAVE_LONG_LONG */
+
+#endif /* !HAVE_UUID_TO_STR && !_WIN32 */
+
 /*
 ** All we really care about is an ISO UUID string.  The format of a UUID is:
 **     field                   octet           note
@@ -175,10 +268,10 @@ lutil_eaddr( void )
 ** We use DCE version one, and the DCE variant.  Our unique identifier is
 ** the first ethernet address on the system.
 */
-int
+size_t
 lutil_uuidstr( char *buf, size_t len )
 {
-#ifdef HAVE_SYS_UUID_H
+#ifdef HAVE_UUID_TO_STR
        uuid_t uu = {0};
        unsigned rc;
        char *s;
@@ -200,17 +293,41 @@ lutil_uuidstr( char *buf, size_t len )
                return 0;
        }
 
-       strncpy( buf, s, l );
+       strncpy( buf, s, len );
        free( s );
 
        return l;
 
+#elif defined( _WIN32 )
+       UUID uuid;
+       unsigned char *uuidstr;
+       size_t uuidlen;
+
+       if( UuidCreate( &uuid ) != RPC_S_OK ) {
+               return 0;
+       }
+       if( UuidToString( &uuid, &uuidstr ) !=  RPC_S_OK ) {
+               return 0;
+       }
+
+       uuidlen = strlen( uuidstr );
+       if( uuidlen >= len ) {
+               return 0;
+       }
+
+       strncpy( buf, uuidstr, len );
+       RpcStringFree( &uuidstr );
+
+       return uuidlen;
 #else
        struct timeval tv;
-       unsigned long long tl;
+       UI64 tl;
        unsigned char *nl;
-       unsigned short t2, t3, s1, n1, n2, n3;
-       unsigned int t1;
+       unsigned short t2, t3, s1;
+       unsigned long t1, tl_high;
+       unsigned int rc;
 
        /*
         * Theoretically we should delay if seq wraps within 100usec but for now
@@ -231,22 +348,26 @@ lutil_uuidstr( char *buf, size_t len )
        tv.tv_usec = 0;
 #endif
 
-       tl = ( tv.tv_sec * 10000000LL ) + ( tv.tv_usec * 10LL ) + UUID_TPLUS;
+       tl = mul64ll(tv.tv_sec, 10000000UL);
+       set_add64l(tl, tv.tv_usec * 10UL);
+       set_add64(tl, UUID_TPLUS);
+
        nl = lutil_eaddr();
 
-       t1 = tl & 0xffffffff;                                   /* time_low */
-       t2 = ( tl >> 32 ) & 0xffff;                             /* time_mid */
-       t3 = ( ( tl >> 48 ) & 0x0fff ) | 0x1000;        /* time_hi_and_version */
+       t1 = low32(tl);                         /* time_low */
+       tl_high = high32(tl);
+       t2 = tl_high & 0xffff;          /* time_mid */
+       t3 = ((tl_high >> 16) & 0x0fff) | 0x1000;       /* time_hi_and_version */
        s1 = ( ++seq & 0x1fff ) | 0x8000;               /* clock_seq_and_reserved */
 
-       t1 = snprintf( buf, len,
-               "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
-           t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
+       rc = snprintf( buf, len,
+               "%08lx-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+               t1, (unsigned) t2, (unsigned) t3, (unsigned) s1,
                (unsigned) nl[0], (unsigned) nl[1],
                (unsigned) nl[2], (unsigned) nl[3],
                (unsigned) nl[4], (unsigned) nl[5] );
 
-       return (t1 < len) ? t1 : 0;
+       return rc < len ? rc : 0;
 #endif
 }
 
@@ -256,7 +377,7 @@ main(int argc, char **argv)
 {
        char buf1[8], buf2[64];
 
-#ifndef HAVE_SYS_UUID_H
+#ifndef HAVE_UUID_TO_STR
        unsigned char *p = lutil_eaddr();
 
        if( p ) {