2 * internal functions for uuid library
4 * written by nathan wagner and placed in the public domain
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <net/if_dl.h>
44 static void pnode(uint64_t node) {
45 unsigned int bytes[6];
48 bytes[5-i] = node & 0xff;
52 fprintf(stderr, "%02x", bytes[0]);
55 fprintf(stderr, ":%02x", bytes[i]);
57 fprintf(stderr, "\n");
61 static void set_time_low(pd_uuid_t *u, uint32_t low) {
62 u->data[0] = (low >> 24) & 0xff;
63 u->data[1] = (low >> 16) & 0xff;
64 u->data[2] = (low >> 8) & 0xff;
65 u->data[3] = low & 0xff;
68 static void set_time_mid(pd_uuid_t *u, uint16_t mid) {
69 u->data[4] = (mid >> 8) & 0xff;
70 u->data[5] = mid & 0xff;
73 static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
74 u->data[7] = hi & 0xff;
76 u->data[6] |= (hi >> 8) & 0xf;
79 static void set_version(pd_uuid_t *u, uint8_t version) {
81 u->data[6] |= (version & 0xf) << 4;
84 static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
85 u->data[9] = low & 0xff;
88 static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
90 u->data[8] |= hi & 0x3f;
93 static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
95 u->data[8] |= (reserved & 0x3) << 6;
99 static void set_node(pd_uuid_t *u, uint8_t data[6]) {
100 u->data[10] = data[0];
101 u->data[11] = data[1];
102 u->data[12] = data[2];
103 u->data[13] = data[3];
104 u->data[14] = data[4];
105 u->data[15] = data[5];
109 static void set_node64(pd_uuid_t *u, uint64_t node) {
110 u->data[10] = (node >> 40) & 0xff;
111 u->data[11] = (node >> 32) & 0xff;
112 u->data[12] = (node >> 24) & 0xff;
113 u->data[13] = (node >> 16) & 0xff;
114 u->data[14] = (node >> 8) & 0xff;
115 u->data[15] = (node >> 0) & 0xff;
118 static void set_timestamp(pd_uuid_t *u, uint64_t ts) {
119 set_time_low(u, ts & 0xffffffff);
120 set_time_mid(u, (ts >> 32) & 0xffff);
121 set_time_hi(u, (ts >> 48) & 0xfff);
124 static void set_clockseq(pd_uuid_t *u, uint16_t seq) {
125 set_clock_seq_low(u, seq & 0xff);
126 set_clock_seq_hi(u, (seq >> 8) & 0xff);
129 static void format_uuid(pd_uuid_t *u, struct pd_uuid_state *s, int version) {
130 set_timestamp(u, s->timestamp);
131 set_version(u, version);
132 set_clockseq(u, s->clock_sequence);
133 set_reserved(u, 0x2);
134 set_node64(u, s->node);
137 static int obtain_global_lock(void *data) {
142 static int release_global_lock(void *data) {
147 #define GREGORIAN 122192928000000000ULL
148 static uint64_t current_time(void) {
153 /* TODO is this BSD specific? */
154 gettimeofday(&tv, 0);
156 now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL + seq++ % 10) + GREGORIAN;
160 static void random_bytes(void *buf, size_t n) {
161 unsigned char *s = buf;
165 i += pd_uuid_rng_get_bytes(s+i, n-i);
169 static uint64_t random_mc_mac(struct pd_uuid_state *s) {
172 if (s && s->random_bytes) {
173 s->random_bytes(&node, sizeof node, s->rng_state);
175 random_bytes(&node, sizeof node);
177 node |= 0x800000000000ULL; /* rfc 4.5 */
183 * TODO would probably make more sense to use a destination array
184 * rather than returning an integer
186 static uint64_t current_node(struct pd_uuid_state *st) {
192 struct ifreq interfaces[4];
196 s = socket(AF_INET, SOCK_DGRAM, 0);
198 conf.ifc_len = sizeof interfaces;
199 conf.ifc_req = interfaces;
200 if (ioctl(s, SIOCGIFCONF, &conf) == 0) {
201 for (i=0; i < 4; i++) {
202 req = &conf.ifc_req[i];
203 if (ioctl(s, SIOCGIFFLAGS, req) != 0) {
206 if (req->ifr_flags & IFF_LOOPBACK) {
209 if (req->ifr_flags & IFF_NOARP) {
214 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
215 data = (unsigned char *)req->ifr_hwaddr.sa_data;
217 node = node << 8; node += data[1];
218 node = node << 8; node += data[2];
219 node = node << 8; node += data[3];
220 node = node << 8; node += data[4];
221 node = node << 8; node += data[5];
226 fprintf(stderr, "ioctl to read address failed: %d\n", errno);
234 /* this is any BSD based system i think */
236 struct ifaddrs *addrs;
238 struct sockaddr_dl *dl;
240 if (getifaddrs(&addrs) == 0) {
241 for (a = addrs; a; a = a->ifa_next) {
243 if (a->ifa_addr && a->ifa_addr->sa_family == AF_LINK) {
244 dl = (struct sockaddr_dl *)a->ifa_addr;
245 data = (unsigned char *)(dl->sdl_data + dl->sdl_nlen);
246 if (dl->sdl_alen != 6) continue;
249 node = node << 8; node += data[1];
250 node = node << 8; node += data[2];
251 node = node << 8; node += data[3];
252 node = node << 8; node += data[4];
253 node = node << 8; node += data[5];
262 #if defined(WIN32) || defined(__CYGWIN__)
263 IP_ADAPTER_INFO addrs[4];
269 rc = GetAdaptersInfo(addrs, &size);
270 if (rc == ERROR_SUCCESS) {
271 PIP_ADAPTER_INFO info;
272 for (info = addrs; info; info = info->Next) {
273 if (info->Type != MIB_IF_TYPE_ETHERNET) {
276 data = info->Address;
278 node = node << 8; node += data[1];
279 node = node << 8; node += data[2];
280 node = node << 8; node += data[3];
281 node = node << 8; node += data[4];
282 node = node << 8; node += data[5];
288 /* if we get here, use a random multicast address */
289 node = random_mc_mac(st);
293 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
296 if (s && s->random_bytes) {
297 s->random_bytes(&seq, sizeof seq, s->rng_state);
299 random_bytes(&seq, sizeof seq);
304 static int read_state(struct pd_uuid_state *s) {
309 node = current_node(s);
311 if (!s->available || s->node != node) {
312 s->clock_sequence = random_clock_sequence(s);
319 static int save_state(struct pd_uuid_state *s) {
324 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
325 unsigned char *s = buf;
329 i += pd_uuid_rng_get_bytes(s+i, n-i);
334 int pd_uuid_init(struct pd_uuid_state *s, int flags) {
337 s->get_lock = obtain_global_lock;
338 s->release_lock = release_global_lock;
344 s->node = current_node(s);
346 s->read_state = read_state;
350 s->random_bytes = get_bytes;
358 int pd_uuid_init_state(struct pd_uuid_state *s) {
361 s->get_lock = obtain_global_lock;
362 s->release_lock = release_global_lock;
365 s->read_state = read_state;
366 s->save_state = save_state;
368 s->random_bytes = get_bytes;
376 static int pd_uuid_make_v1_any(struct pd_uuid_state *s, pd_uuid_t *uuid, int rmac);
378 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
379 return pd_uuid_make_v1_any(s, uuid, 0);
382 int pd_uuid_make_v1mc(struct pd_uuid_state *s, pd_uuid_t *uuid) {
383 return pd_uuid_make_v1_any(s, uuid, 1);
386 static int pd_uuid_make_v1_any(struct pd_uuid_state *s, pd_uuid_t *uuid, int rmac) {
387 struct pd_uuid_state ls;
394 pd_uuid_init_state(s);
398 if ((err = s->get_lock(s->lock_data)) != 0) {
399 /* TODO set uuid to nil ? */
400 /* be cute and have an "error" uuid? */
406 if ((err = s->read_state(s)) != 0) {
411 now = current_time();
413 node = random_mc_mac(s);
415 node = current_node(s);
418 if (!s->available || s->node != node) {
419 s->clock_sequence = random_clock_sequence(s);
423 if (s->available && s->timestamp > now) {
430 if ((err = s->save_state(s)) != 0) {
435 if (s->release_lock) {
436 if ((err = s->release_lock(s->lock_data)) != 0) {
437 /* TODO set uuid to nil ? */
438 /* be cute and have an "error" uuid? */
443 format_uuid(uuid, s, 1);
448 int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid) {
449 random_bytes(uuid, sizeof *uuid);
450 set_version(uuid, 4);
451 set_reserved(uuid, 0x2);
455 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
457 unsigned char *h = hash;
462 set_version(s, version);
463 set_reserved(s, 0x2);
467 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
469 unsigned char hash[16];
472 md5_process(&hs, ns->data, 16);
473 md5_process(&hs, data, len);
475 pd_set_uuid_hash(uuid, hash, 3);
479 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
481 unsigned char hash[20];
484 sha1_process(&hs, ns->data, sizeof *ns);
485 sha1_process(&hs, data, len);
486 sha1_done(&hs, hash);
487 pd_set_uuid_hash(uuid, hash, 5);
492 * s must point to enough space, i.e. at least 37 bytes.
493 * this is constrained enough that sprintf could
494 * probably be avoided
496 char *pd_uuid_get_string(pd_uuid_t *uuid, char *s) {
503 r += sprintf(r, "%.2x", (int)uuid->data[i]);
504 if (i == 3 || i == 5 || i == 7 || i == 9) {
514 * might be faster to sscanf in four bytes at a time
516 * A nybble loop might be faster yet.
518 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
523 if (*s == 0) return 0;
526 if (sscanf(s, "%02x", &byte) != 1) {
530 uuid->data[i] = byte & 0xff;
535 /* pre-defined namespace uuids */
537 pd_uuid_t pd_uuid_ns_dns = {
539 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
540 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
544 pd_uuid_t pd_uuid_ns_url = {
546 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
547 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
551 pd_uuid_t pd_uuid_ns_oid = {
553 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
554 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
558 pd_uuid_t pd_uuid_ns_x500 = {
560 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
561 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
565 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
567 memcpy(dst->data, src->data, 16);
573 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
575 return memcmp(a, b, 16);