Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

gw_uuid.c

Go to the documentation of this file.
00001 /*
00002  * clear.c -- Clear a UUID
00003  * 
00004  * Copyright (C) 1996, 1997 Theodore Ts'o.
00005  *
00006  * %Begin-Header%
00007  * This file may be redistributed under the terms of the GNU 
00008  * Library General Public License.
00009  * %End-Header%
00010  */
00011 
00012 /*
00013  * Force inclusion of SVID stuff since we need it if we're compiling in
00014  * gcc-wall wall mode
00015  */
00016 #ifndef _SVID_SOURCE
00017 #define _SVID_SOURCE
00018 #endif
00019 
00020 #include "gw-config.h"
00021 
00022 #ifdef HAVE_UNISTD_H
00023 #include <unistd.h>
00024 #endif
00025 #ifdef HAVE_STDLIB_H
00026 #include <stdlib.h>
00027 #endif
00028 #include <string.h>
00029 #include <ctype.h>
00030 #include <fcntl.h>
00031 #include <errno.h>
00032 #include <sys/types.h>
00033 #include <sys/time.h>
00034 #include <sys/stat.h>
00035 #include <sys/file.h>
00036 #ifdef HAVE_SYS_IOCTL_H
00037 #include <sys/ioctl.h>
00038 #endif
00039 #ifdef HAVE_SYS_SOCKET_H
00040 #include <sys/socket.h>
00041 #endif
00042 #ifdef HAVE_SYS_SOCKIO_H
00043 #include <sys/sockio.h>
00044 #endif
00045 #ifdef HAVE_NET_IF_H
00046 #include <net/if.h>
00047 #endif
00048 #ifdef HAVE_NETINET_IN_H
00049 #include <netinet/in.h>
00050 #endif
00051 #include <stdio.h>
00052 
00053 #include "gwlib/gw_uuid_types.h"
00054 #include "gwlib/gw_uuid.h"
00055 
00056 /*
00057  * Offset between 15-Oct-1582 and 1-Jan-70
00058  */
00059 #define TIME_OFFSET_HIGH 0x01B21DD2
00060 #define TIME_OFFSET_LOW  0x13814000
00061 
00062 struct uuid {
00063         __u32   time_low;
00064         __u16   time_mid;
00065         __u16   time_hi_and_version;
00066         __u16   clock_seq;
00067         __u8    node[6];
00068 };
00069 
00070 
00071 /*
00072  * prototypes
00073  */
00074 static void uuid_pack(const struct uuid *uu, uuid_t ptr);
00075 static void uuid_unpack(const uuid_t in, struct uuid *uu);
00076 static int get_random_fd(void);
00077 
00078 
00079 #ifdef HAVE_SRANDOM
00080 #define srand(x)    srandom(x)
00081 #define rand()      random()
00082 #endif
00083 
00084 
00085 
00086 void uuid_init(void)
00087 {
00088     /* 
00089      * open random device if any.
00090      * We should do it here because otherwise it's
00091      * possible that we open device twice.
00092      */
00093     get_random_fd();
00094 }
00095 
00096 
00097 void uuid_shutdown(void)
00098 {
00099     int fd = get_random_fd();
00100 
00101     if (fd > 0)
00102         close(fd);
00103 }
00104 
00105 void uuid_clear(uuid_t uu)
00106 {
00107     memset(uu, 0, 16);
00108 }
00109 
00110 /*
00111  * compare.c --- compare whether or not two UUID's are the same
00112  *
00113  * Returns an integer less than, equal to, or greater than zero if
00114  * uu1 respectively, to be less than, to match, or be greater than
00115  * uu2.
00116  * 
00117  * Copyright (C) 1996, 1997 Theodore Ts'o.
00118  *
00119  * %Begin-Header%
00120  * This file may be redistributed under the terms of the GNU 
00121  * Library General Public License.
00122  * %End-Header%
00123  */
00124 #define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
00125 
00126 int uuid_compare(const uuid_t uu1, const uuid_t uu2)
00127 {
00128     struct uuid uuid1, uuid2;
00129 
00130     uuid_unpack(uu1, &uuid1);
00131     uuid_unpack(uu2, &uuid2);
00132 
00133     UUCMP(uuid1.time_low, uuid2.time_low);
00134     UUCMP(uuid1.time_mid, uuid2.time_mid);
00135     UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
00136     UUCMP(uuid1.clock_seq, uuid2.clock_seq);
00137     return memcmp(uuid1.node, uuid2.node, 6);
00138 }
00139 
00140 /*
00141  * copy.c --- copy UUIDs
00142  * 
00143  * Copyright (C) 1996, 1997 Theodore Ts'o.
00144  *
00145  * %Begin-Header%
00146  * This file may be redistributed under the terms of the GNU 
00147  * Library General Public License.
00148  * %End-Header%
00149  */
00150 void uuid_copy(uuid_t dst, const uuid_t src)
00151 {
00152     unsigned char       *cp1;
00153     const unsigned char *cp2;
00154     int         i;
00155 
00156     for (i=0, cp1 = dst, cp2 = src; i < 16; i++)
00157         *cp1++ = *cp2++;
00158 }
00159 
00160 
00161 /*
00162  * gen_uuid.c --- generate a DCE-compatible uuid
00163  *
00164  * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
00165  *
00166  * %Begin-Header%
00167  * This file may be redistributed under the terms of the GNU 
00168  * Library General Public License.
00169  * %End-Header%
00170  */
00171 static int get_random_fd(void)
00172 {
00173     struct timeval  tv;
00174     static int  fd = -2;
00175     int     i;
00176 
00177     if (fd == -2) {
00178         gettimeofday(&tv, 0);
00179         fd = open("/dev/urandom", O_RDONLY);
00180         if (fd == -1)
00181             fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
00182         srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
00183     }
00184     /* Crank the random number generator a few times */
00185     gettimeofday(&tv, 0);
00186     for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
00187         rand();
00188 
00189     return fd;
00190 }
00191 
00192 
00193 /*
00194  * Generate a series of random bytes.  Use /dev/urandom if possible,
00195  * and if not, use srandom/random.
00196  */
00197 static void get_random_bytes(void *buf, int nbytes)
00198 {
00199     int i, n = nbytes, fd = get_random_fd();
00200     int lose_counter = 0;
00201     unsigned char *cp = (unsigned char *) buf;
00202 
00203     if (fd >= 0) {
00204         while (n > 0) {
00205             i = read(fd, cp, n);
00206             if (i <= 0) {
00207                 if (lose_counter++ > 16)
00208                     break;
00209                 continue;
00210             }
00211             n -= i;
00212             cp += i;
00213             lose_counter = 0;
00214         }
00215     }
00216     
00217     /*
00218      * We do this all the time, but this is the only source of
00219      * randomness if /dev/random/urandom is out to lunch.
00220      */
00221     for (cp = buf, i = 0; i < nbytes; i++)
00222         *cp++ ^= (rand() >> 7) & 0xFF;
00223     return;
00224 }
00225 
00226 /*
00227  * Get the ethernet hardware address, if we can find it...
00228  */
00229 static int get_node_id(unsigned char *node_id)
00230 {
00231 #ifdef HAVE_NET_IF_H
00232     int         sd;
00233     struct ifreq    ifr, *ifrp;
00234     struct ifconf   ifc;
00235     char buf[1024];
00236     int     n, i;
00237     unsigned char   *a;
00238     
00239 /*
00240  * BSD 4.4 defines the size of an ifreq to be
00241  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
00242  * However, under earlier systems, sa_len isn't present, so the size is 
00243  * just sizeof(struct ifreq)
00244  */
00245 #ifdef HAVE_SA_LEN
00246 #ifndef max
00247 #define max(a,b) ((a) > (b) ? (a) : (b))
00248 #endif
00249 #define ifreq_size(i) max(sizeof(struct ifreq),\
00250      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
00251 #else
00252 #define ifreq_size(i) sizeof(struct ifreq)
00253 #endif /* HAVE_SA_LEN*/
00254 
00255     sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
00256     if (sd < 0) {
00257         return -1;
00258     }
00259     memset(buf, 0, sizeof(buf));
00260     ifc.ifc_len = sizeof(buf);
00261     ifc.ifc_buf = buf;
00262     if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
00263         close(sd);
00264         return -1;
00265     }
00266     n = ifc.ifc_len;
00267     for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
00268         ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
00269         strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
00270 #ifdef SIOCGIFHWADDR
00271         if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
00272             continue;
00273         a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
00274 #else
00275 #ifdef SIOCGENADDR
00276         if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
00277             continue;
00278         a = (unsigned char *) ifr.ifr_enaddr;
00279 #else
00280         /*
00281          * XXX we don't have a way of getting the hardware
00282          * address
00283          */
00284         close(sd);
00285         return 0;
00286 #endif /* SIOCGENADDR */
00287 #endif /* SIOCGIFHWADDR */
00288         if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
00289             continue;
00290         if (node_id) {
00291             memcpy(node_id, a, 6);
00292             close(sd);
00293             return 1;
00294         }
00295     }
00296     close(sd);
00297 #endif
00298     return 0;
00299 }
00300 
00301 /* Assume that the gettimeofday() has microsecond granularity */
00302 #define MAX_ADJUSTMENT 10
00303 
00304 static int get_clock(__u32 *clock_high, __u32 *clock_low, __u16 *ret_clock_seq)
00305 {
00306     static int          adjustment = 0;
00307     static struct timeval       last = {0, 0};
00308     static __u16            clock_seq;
00309     struct timeval          tv;
00310     unsigned long long      clock_reg;
00311     
00312 try_again:
00313     gettimeofday(&tv, 0);
00314     if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
00315         get_random_bytes(&clock_seq, sizeof(clock_seq));
00316         clock_seq &= 0x1FFF;
00317         last = tv;
00318         last.tv_sec--;
00319     }
00320     if ((tv.tv_sec < last.tv_sec) ||
00321         ((tv.tv_sec == last.tv_sec) &&
00322          (tv.tv_usec < last.tv_usec))) {
00323         clock_seq = (clock_seq+1) & 0x1FFF;
00324         adjustment = 0;
00325         last = tv;
00326     } else if ((tv.tv_sec == last.tv_sec) &&
00327         (tv.tv_usec == last.tv_usec)) {
00328         if (adjustment >= MAX_ADJUSTMENT)
00329             goto try_again;
00330         adjustment++;
00331     } else {
00332         adjustment = 0;
00333         last = tv;
00334     }
00335         
00336     clock_reg = tv.tv_usec*10 + adjustment;
00337     clock_reg += ((unsigned long long) tv.tv_sec)*10000000;
00338     clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
00339 
00340     *clock_high = clock_reg >> 32;
00341     *clock_low = clock_reg;
00342     *ret_clock_seq = clock_seq;
00343     return 0;
00344 }
00345 
00346 void uuid_generate_time(uuid_t out)
00347 {
00348     static unsigned char node_id[6];
00349     static int has_init = 0;
00350     struct uuid uu;
00351     __u32   clock_mid;
00352 
00353     if (!has_init) {
00354         if (get_node_id(node_id) <= 0) {
00355             get_random_bytes(node_id, 6);
00356             /*
00357              * Set multicast bit, to prevent conflicts
00358              * with IEEE 802 addresses obtained from
00359              * network cards
00360              */
00361             node_id[0] |= 0x80;
00362         }
00363         has_init = 1;
00364     }
00365     get_clock(&clock_mid, &uu.time_low, &uu.clock_seq);
00366     uu.clock_seq |= 0x8000;
00367     uu.time_mid = (__u16) clock_mid;
00368     uu.time_hi_and_version = (clock_mid >> 16) | 0x1000;
00369     memcpy(uu.node, node_id, 6);
00370     uuid_pack(&uu, out);
00371 }
00372 
00373 void uuid_generate_random(uuid_t out)
00374 {
00375     uuid_t  buf;
00376     struct uuid uu;
00377 
00378     get_random_bytes(buf, sizeof(buf));
00379     uuid_unpack(buf, &uu);
00380 
00381     uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
00382     uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000;
00383     uuid_pack(&uu, out);
00384 }
00385 
00386 /*
00387  * This is the generic front-end to uuid_generate_random and
00388  * uuid_generate_time.  It uses uuid_generate_random only if
00389  * /dev/urandom is available, since otherwise we won't have
00390  * high-quality randomness.
00391  */
00392 void uuid_generate(uuid_t out)
00393 {
00394     if (get_random_fd() >= 0) {
00395         uuid_generate_random(out);
00396     }
00397     else
00398         uuid_generate_time(out);
00399 }
00400 
00401 /*
00402  * isnull.c --- Check whether or not the UUID is null
00403  * 
00404  * Copyright (C) 1996, 1997 Theodore Ts'o.
00405  *
00406  * %Begin-Header%
00407  * This file may be redistributed under the terms of the GNU 
00408  * Library General Public License.
00409  * %End-Header%
00410  */
00411 /* Returns 1 if the uuid is the NULL uuid */
00412 int uuid_is_null(const uuid_t uu)
00413 {
00414     const unsigned char     *cp;
00415     int         i;
00416 
00417     for (i=0, cp = uu; i < 16; i++)
00418         if (*cp++)
00419             return 0;
00420     return 1;
00421 }
00422 
00423 /*
00424  * Internal routine for packing UUID's
00425  * 
00426  * Copyright (C) 1996, 1997 Theodore Ts'o.
00427  *
00428  * %Begin-Header%
00429  * This file may be redistributed under the terms of the GNU 
00430  * Library General Public License.
00431  * %End-Header%
00432  */
00433 void uuid_pack(const struct uuid *uu, uuid_t ptr)
00434 {
00435     __u32   tmp;
00436     unsigned char   *out = ptr;
00437 
00438     tmp = uu->time_low;
00439     out[3] = (unsigned char) tmp;
00440     tmp >>= 8;
00441     out[2] = (unsigned char) tmp;
00442     tmp >>= 8;
00443     out[1] = (unsigned char) tmp;
00444     tmp >>= 8;
00445     out[0] = (unsigned char) tmp;
00446     
00447     tmp = uu->time_mid;
00448     out[5] = (unsigned char) tmp;
00449     tmp >>= 8;
00450     out[4] = (unsigned char) tmp;
00451 
00452     tmp = uu->time_hi_and_version;
00453     out[7] = (unsigned char) tmp;
00454     tmp >>= 8;
00455     out[6] = (unsigned char) tmp;
00456 
00457     tmp = uu->clock_seq;
00458     out[9] = (unsigned char) tmp;
00459     tmp >>= 8;
00460     out[8] = (unsigned char) tmp;
00461 
00462     memcpy(out+10, uu->node, 6);
00463 }
00464 
00465 /*
00466  * parse.c --- UUID parsing
00467  * 
00468  * Copyright (C) 1996, 1997 Theodore Ts'o.
00469  *
00470  * %Begin-Header%
00471  * This file may be redistributed under the terms of the GNU 
00472  * Library General Public License.
00473  * %End-Header%
00474  */
00475 int uuid_parse(const char *in, uuid_t uu)
00476 {
00477     struct uuid uuid;
00478     int         i;
00479     const char  *cp;
00480     char        buf[3];
00481 
00482     if (strlen(in) != 36)
00483         return -1;
00484     for (i=0, cp = in; i <= 36; i++,cp++) {
00485         if ((i == 8) || (i == 13) || (i == 18) ||
00486             (i == 23)) {
00487             if (*cp == '-')
00488                 continue;
00489             else
00490                 return -1;
00491         }
00492         if (i== 36)
00493             if (*cp == 0)
00494                 continue;
00495         if (!isxdigit(*cp))
00496             return -1;
00497     }
00498     uuid.time_low = strtoul(in, NULL, 16);
00499     uuid.time_mid = strtoul(in+9, NULL, 16);
00500     uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
00501     uuid.clock_seq = strtoul(in+19, NULL, 16);
00502     cp = in+24;
00503     buf[2] = 0;
00504     for (i=0; i < 6; i++) {
00505         buf[0] = *cp++;
00506         buf[1] = *cp++;
00507         uuid.node[i] = strtoul(buf, NULL, 16);
00508     }
00509     
00510     uuid_pack(&uuid, uu);
00511     return 0;
00512 }
00513     
00514 
00515 /*
00516  * Internal routine for unpacking UUID
00517  * 
00518  * Copyright (C) 1996, 1997 Theodore Ts'o.
00519  *
00520  * %Begin-Header%
00521  * This file may be redistributed under the terms of the GNU 
00522  * Library General Public License.
00523  * %End-Header%
00524  */
00525 void uuid_unpack(const uuid_t in, struct uuid *uu)
00526 {
00527     const __u8  *ptr = in;
00528     __u32       tmp;
00529 
00530     tmp = *ptr++;
00531     tmp = (tmp << 8) | *ptr++;
00532     tmp = (tmp << 8) | *ptr++;
00533     tmp = (tmp << 8) | *ptr++;
00534     uu->time_low = tmp;
00535 
00536     tmp = *ptr++;
00537     tmp = (tmp << 8) | *ptr++;
00538     uu->time_mid = tmp;
00539     
00540     tmp = *ptr++;
00541     tmp = (tmp << 8) | *ptr++;
00542     uu->time_hi_and_version = tmp;
00543 
00544     tmp = *ptr++;
00545     tmp = (tmp << 8) | *ptr++;
00546     uu->clock_seq = tmp;
00547 
00548     memcpy(uu->node, ptr, 6);
00549 }
00550 
00551 /*
00552  * unparse.c -- convert a UUID to string
00553  * 
00554  * Copyright (C) 1996, 1997 Theodore Ts'o.
00555  *
00556  * %Begin-Header%
00557  * This file may be redistributed under the terms of the GNU 
00558  * Library General Public License.
00559  * %End-Header%
00560  */
00561 void uuid_unparse(const uuid_t uu, char *out)
00562 {
00563     struct uuid uuid;
00564 
00565     uuid_unpack(uu, &uuid);
00566     sprintf(out,
00567         "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
00568         uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
00569         uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
00570         uuid.node[0], uuid.node[1], uuid.node[2],
00571         uuid.node[3], uuid.node[4], uuid.node[5]);
00572 }
00573 
00574 /*
00575  * uuid_time.c --- Interpret the time field from a uuid.  This program
00576  *  violates the UUID abstraction barrier by reaching into the guts
00577  *  of a UUID and interpreting it.
00578  * 
00579  * Copyright (C) 1998, 1999 Theodore Ts'o.
00580  *
00581  * %Begin-Header%
00582  * This file may be redistributed under the terms of the GNU 
00583  * Library General Public License.
00584  * %End-Header%
00585  */
00586 time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
00587 {
00588     struct uuid     uuid;
00589     __u32           high;
00590     struct timeval      tv;
00591     unsigned long long  clock_reg;
00592 
00593     uuid_unpack(uu, &uuid);
00594     
00595     high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
00596     clock_reg = uuid.time_low | ((unsigned long long) high << 32);
00597 
00598     clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000;
00599     tv.tv_sec = clock_reg / 10000000;
00600     tv.tv_usec = (clock_reg % 10000000) / 10;
00601 
00602     if (ret_tv)
00603         *ret_tv = tv;
00604 
00605     return tv.tv_sec;
00606 }
00607 
00608 int uuid_type(const uuid_t uu)
00609 {
00610     struct uuid     uuid;
00611 
00612     uuid_unpack(uu, &uuid); 
00613     return ((uuid.time_hi_and_version >> 12) & 0xF);
00614 }
00615 
00616 int uuid_variant(const uuid_t uu)
00617 {
00618     struct uuid     uuid;
00619     int         var;
00620 
00621     uuid_unpack(uu, &uuid); 
00622     var = uuid.clock_seq;
00623 
00624     if ((var & 0x8000) == 0)
00625         return UUID_VARIANT_NCS;
00626     if ((var & 0x4000) == 0)
00627         return UUID_VARIANT_DCE;
00628     if ((var & 0x2000) == 0)
00629         return UUID_VARIANT_MICROSOFT;
00630     return UUID_VARIANT_OTHER;
00631 }
00632 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.