Home | History | Annotate | Download | only in src
      1 /* what follows is a somewhat stripped-down version of the sample
      2    implementation of UUID generation from RFC 4122.  */
      3 
      4 /*
      5 ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
      6 ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
      7 ** Digital Equipment Corporation, Maynard, Mass.
      8 ** Copyright (c) 1998 Microsoft.
      9 ** To anyone who acknowledges that this file is provided "AS IS"
     10 ** without any express or implied warranty: permission to use, copy,
     11 ** modify, and distribute this file for any purpose is hereby
     12 ** granted without fee, provided that the above copyright notices and
     13 ** this notice appears in all source code copies, and that none of
     14 ** the names of Open Software Foundation, Inc., Hewlett-Packard
     15 ** Company, Microsoft, or Digital Equipment Corporation be used in
     16 ** advertising or publicity pertaining to distribution of the software
     17 ** without specific, written prior permission. Neither Open Software
     18 ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
     19 ** Equipment Corporation makes any representations about the
     20 ** suitability of this software for any purpose.
     21 */
     22 
     23 #ifdef HAVE_CONFIG_H
     24 #include "config.h"
     25 #endif
     26 
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <fcntl.h>
     31 
     32 #if defined(HAVE_INTTYPES_H)
     33 #include <inttypes.h>
     34 #endif
     35 
     36 /* set the following to the number of 100ns ticks of the actual
     37    resolution of your system's clock */
     38 #define UUIDS_PER_TICK 1024
     39 
     40 #ifdef WIN32
     41 #include <windows.h>
     42 #include "missing\stdint.h"
     43 #define snprintf _snprintf
     44 #else
     45 
     46 #if HAVE_SYS_TYPES_H
     47 #include <sys/types.h>
     48 #else
     49 # if HAVE_STDINT_H
     50 #  include <stdint.h>
     51 # endif
     52 #endif
     53 
     54 #if HAVE_SYS_TIME_H
     55 #include <sys/time.h>
     56 #endif
     57 
     58 #if HAVE_SYS_SYSINFO_H
     59 #include <sys/sysinfo.h>
     60 #endif
     61 
     62 #endif
     63 
     64 /* system dependent call to get the current system time. Returned as
     65    100ns ticks since UUID epoch, but resolution may be less than
     66    100ns. */
     67 
     68 #ifdef WIN32
     69 #define I64(C) C
     70 #else
     71 #define I64(C) C##LL
     72 #endif
     73 
     74 typedef uint64_t uuid_time_t;
     75 
     76 typedef struct {
     77   char nodeID[6];
     78 } uuid_node_t;
     79 
     80 #undef uuid_t
     81 typedef struct {
     82   uint32_t  time_low;
     83   uint16_t  time_mid;
     84   uint16_t  time_hi_and_version;
     85   uint8_t   clock_seq_hi_and_reserved;
     86   uint8_t   clock_seq_low;
     87   uint8_t   node[6];
     88 } uuid_t;
     89 
     90 /* some forward declarations.  kind of wimpy to do that but heck, we
     91    are all friends here right?  raj 20081024 */
     92 static uint16_t true_random(void);
     93 
     94 
     95 
     96 #ifdef WIN32
     97 
     98 static void get_system_time(uuid_time_t *uuid_time)
     99 {
    100   ULARGE_INTEGER time;
    101 
    102   /* NT keeps time in FILETIME format which is 100ns ticks since
    103      Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
    104      The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
    105      + 18 years and 5 leap days. */
    106   GetSystemTimeAsFileTime((FILETIME *)&time);
    107   time.QuadPart +=
    108 
    109     (unsigned __int64) (1000*1000*10)       // seconds
    110     * (unsigned __int64) (60 * 60 * 24)       // days
    111     * (unsigned __int64) (17+30+31+365*18+5); // # of days
    112   *uuid_time = time.QuadPart;
    113 }
    114 
    115 /* Sample code, not for use in production; see RFC 1750 */
    116 static void get_random_info(char seed[16])
    117 {
    118   uint16_t myrand;
    119   int i;
    120 
    121   i = 0;
    122   do {
    123     myrand = true_random();
    124     seed[i++] = myrand & 0xff;
    125     seed[i++] = myrand >> 8;
    126   } while (i < 14);
    127 
    128 }
    129 
    130 #else
    131 
    132 static void get_system_time(uuid_time_t *uuid_time)
    133 {
    134   struct timeval tp;
    135 
    136   gettimeofday(&tp, (struct timezone *)0);
    137 
    138   /* Offset between UUID formatted times and Unix formatted times.
    139      UUID UTC base time is October 15, 1582.
    140      Unix base time is January 1, 1970.*/
    141   *uuid_time = ((uint64_t)tp.tv_sec * 10000000)
    142     + ((uint64_t)tp.tv_usec * 10)
    143     + I64(0x01B21DD213814000);
    144 }
    145 
    146 /* Sample code, not for use in production; see RFC 1750 */
    147 static void get_random_info(char seed[16])
    148 {
    149   int fd;
    150   uint16_t myrand;
    151   int i;
    152 
    153   /* we aren't all that picky, and we would rather not block so we
    154      will use urandom */
    155   fd = open("/dev/urandom", O_RDONLY);
    156 
    157   if (fd != -1) {
    158     read(fd, seed, 16);
    159     close(fd);
    160     return;
    161   }
    162 
    163   /* ok, now what? */
    164 
    165   i = 0;
    166   do {
    167     myrand = true_random();
    168     seed[i++] = myrand & 0xff;
    169     seed[i++] = myrand >> 8;
    170   } while (i < 14);
    171 
    172 }
    173 
    174 #endif
    175 
    176 
    177 /* true_random -- generate a crypto-quality random number.
    178 **This sample doesn't do that.** */
    179 static uint16_t true_random(void)
    180 {
    181   static int inited = 0;
    182   uuid_time_t time_now;
    183 
    184   if (!inited) {
    185     get_system_time(&time_now);
    186     time_now = time_now / UUIDS_PER_TICK;
    187     srand((unsigned int)
    188 	  (((time_now >> 32) ^ time_now) & 0xffffffff));
    189     inited = 1;
    190   }
    191 
    192   return (uint16_t)rand();
    193 }
    194 
    195 /* puid -- print a UUID */
    196 void puid(uuid_t u)
    197 {
    198   int i;
    199 
    200   printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
    201 	 u.time_hi_and_version, u.clock_seq_hi_and_reserved,
    202 	 u.clock_seq_low);
    203   for (i = 0; i < 6; i++)
    204     printf("%2.2x", u.node[i]);
    205   printf("\n");
    206 }
    207 
    208 /* snpuid -- print a UUID in the supplied buffer */
    209 void snpuid(char *str, size_t size, uuid_t u) {
    210   int i;
    211   char *tmp = str;
    212 
    213   if (size < 38) {
    214     snprintf(tmp,size,"%s","uuid string too small");
    215     return;
    216   }
    217 
    218   /* perhaps this is a trifle optimistic but what the heck */
    219   sprintf(tmp,
    220 	  "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-",
    221 	  u.time_low,
    222 	  u.time_mid,
    223 	  u.time_hi_and_version,
    224 	  u.clock_seq_hi_and_reserved,
    225 	  u.clock_seq_low);
    226   tmp += 24;
    227   for (i = 0; i < 6; i++) {
    228     sprintf(tmp,"%2.2x", u.node[i]);
    229     tmp += 2;
    230   }
    231   *tmp = 0;
    232 
    233 }
    234 
    235 /* get-current_time -- get time as 60-bit 100ns ticks since UUID epoch.
    236    Compensate for the fact that real clock resolution is
    237    less than 100ns. */
    238 static void get_current_time(uuid_time_t *timestamp)
    239 {
    240   static int inited = 0;
    241   static uuid_time_t time_last;
    242   static uint16_t uuids_this_tick;
    243   uuid_time_t time_now;
    244 
    245   if (!inited) {
    246     get_system_time(&time_now);
    247     uuids_this_tick = UUIDS_PER_TICK;
    248     inited = 1;
    249   }
    250 
    251   for ( ; ; ) {
    252     get_system_time(&time_now);
    253 
    254     /* if clock reading changed since last UUID generated, */
    255     if (time_last != time_now) {
    256       /* reset count of uuids gen'd with this clock reading */
    257       uuids_this_tick = 0;
    258       time_last = time_now;
    259       break;
    260     }
    261     if (uuids_this_tick < UUIDS_PER_TICK) {
    262       uuids_this_tick++;
    263       break;
    264     }
    265     /* going too fast for our clock; spin */
    266   }
    267   /* add the count of uuids to low order bits of the clock reading */
    268   *timestamp = time_now + uuids_this_tick;
    269 }
    270 
    271 
    272 /* system dependent call to get IEEE node ID.
    273    This sample implementation generates a random node ID. */
    274 /* netperf mod - don't bother trying to read or write the nodeid */
    275 static void get_ieee_node_identifier(uuid_node_t *node)
    276 {
    277   static int inited = 0;
    278   static uuid_node_t saved_node;
    279   char seed[16];
    280 
    281   if (!inited) {
    282     get_random_info(seed);
    283     seed[0] |= 0x01;
    284     memcpy(&saved_node, seed, sizeof saved_node);
    285   }
    286   inited = 1;
    287 
    288   *node = saved_node;
    289 }
    290 
    291 
    292 /* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
    293    and node ID */
    294 static void format_uuid_v1(uuid_t* uuid, uint16_t clock_seq,
    295                     uuid_time_t timestamp, uuid_node_t node)
    296 {
    297   /* Construct a version 1 uuid with the information we've gathered
    298      plus a few constants. */
    299   uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF);
    300   uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF);
    301   uuid->time_hi_and_version =
    302     (unsigned short)((timestamp >> 48) & 0x0FFF);
    303   uuid->time_hi_and_version |= (1 << 12);
    304   uuid->clock_seq_low = clock_seq & 0xFF;
    305   uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
    306   uuid->clock_seq_hi_and_reserved |= 0x80;
    307   memcpy(&uuid->node, &node, sizeof uuid->node);
    308 }
    309 
    310 /* uuid_create -- generator a UUID */
    311 int uuid_create(uuid_t *uuid)
    312 {
    313   uuid_time_t timestamp;
    314   uint16_t clockseq;
    315   uuid_node_t node;
    316 
    317   /* get time, node ID, saved state from non-volatile storage */
    318   get_current_time(&timestamp);
    319   get_ieee_node_identifier(&node);
    320 
    321   /* for us clockseq is always to be random as we have no state */
    322   clockseq = true_random();
    323 
    324   /* stuff fields into the UUID */
    325   format_uuid_v1(uuid, clockseq, timestamp, node);
    326   return 1;
    327 }
    328 
    329 void get_uuid_string(char *uuid_str, size_t size) {
    330   uuid_t u;
    331 
    332   uuid_create(&u);
    333   snpuid(uuid_str,size,u);
    334 
    335   return;
    336 }
    337 
    338 #ifdef NETPERF_STANDALONE_DEBUG
    339 
    340 int
    341 main(int argc, char *argv[])
    342 {
    343   uuid_t u;
    344   char  uuid_str[38];
    345 #if 0
    346   uuid_create(&u);
    347   printf("uuid_create(): "); puid(u);
    348   snpuid(uuid_str,sizeof(uuid_str),u);
    349   printf("\nas a string %s\n",uuid_str);
    350 #endif
    351   get_uuid_string(uuid_str,sizeof(uuid_str));
    352   printf("uuid_str is %s\n",uuid_str);
    353   return 0;
    354 }
    355 
    356 
    357 #endif
    358