00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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
00090
00091
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
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
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
00142
00143
00144
00145
00146
00147
00148
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
00163
00164
00165
00166
00167
00168
00169
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
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
00195
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
00219
00220
00221 for (cp = buf, i = 0; i < nbytes; i++)
00222 *cp++ ^= (rand() >> 7) & 0xFF;
00223 return;
00224 }
00225
00226
00227
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
00241
00242
00243
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
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
00282
00283
00284 close(sd);
00285 return 0;
00286 #endif
00287 #endif
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
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
00358
00359
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
00388
00389
00390
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
00403
00404
00405
00406
00407
00408
00409
00410
00411
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
00425
00426
00427
00428
00429
00430
00431
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
00467
00468
00469
00470
00471
00472
00473
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
00517
00518
00519
00520
00521
00522
00523
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
00553
00554
00555
00556
00557
00558
00559
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
00576
00577
00578
00579
00580
00581
00582
00583
00584
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.