2 * internal functions for uuid library
4 * written by nathan wagner and placed in the public domain
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <net/if_dl.h>
40 static void set_time_low(pd_uuid_t *u, uint32_t low) {
41 u->data[0] = (low >> 24) & 0xff;
42 u->data[1] = (low >> 16) & 0xff;
43 u->data[2] = (low >> 8) & 0xff;
44 u->data[3] = low & 0xff;
47 static void set_time_mid(pd_uuid_t *u, uint16_t mid) {
48 u->data[4] = (mid >> 8) & 0xff;
49 u->data[5] = mid & 0xff;
52 static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
53 u->data[7] = hi & 0xff;
55 u->data[6] |= (hi >> 8) & 0xf;
58 static void set_version(pd_uuid_t *u, uint8_t version) {
60 u->data[6] |= (version & 0xf) << 4;
63 static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
64 u->data[9] = low & 0xff;
67 static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
69 u->data[8] |= hi & 0x3f;
72 static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
74 u->data[8] |= (reserved & 0x3) << 6;
78 static void set_node(pd_uuid_t *u, uint8_t data[6]) {
79 u->data[10] = data[0];
80 u->data[11] = data[1];
81 u->data[12] = data[2];
82 u->data[13] = data[3];
83 u->data[14] = data[4];
84 u->data[15] = data[5];
88 static void set_node64(pd_uuid_t *u, uint64_t node) {
89 u->data[10] = (node >> 40) & 0xff;
90 u->data[11] = (node >> 32) & 0xff;
91 u->data[12] = (node >> 24) & 0xff;
92 u->data[13] = (node >> 16) & 0xff;
93 u->data[14] = (node >> 8) & 0xff;
94 u->data[15] = (node >> 0) & 0xff;
97 static void set_timestamp(pd_uuid_t *u, uint64_t ts) {
98 set_time_low(u, ts & 0xffffffff);
99 set_time_mid(u, (ts >> 32) & 0xffff);
100 set_time_hi(u, (ts >> 48) & 0xfff);
103 static void set_clockseq(pd_uuid_t *u, uint16_t seq) {
104 set_clock_seq_low(u, seq & 0xff);
105 set_clock_seq_hi(u, (seq >> 8) & 0xff);
108 static void format_uuid(pd_uuid_t *u, struct pd_uuid_state *s, int version) {
109 set_timestamp(u, s->timestamp);
110 set_version(u, version);
111 set_clockseq(u, s->clock_sequence);
112 set_reserved(u, 0x2);
113 set_node64(u, s->node);
116 static int obtain_global_lock(void *data) {
121 static int release_global_lock(void *data) {
126 #define GREGORIAN 122192928000000000ULL
127 static uint64_t current_time(void) {
132 /* TODO is this BSD specific? */
133 gettimeofday(&tv, 0);
135 now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL + seq++ % 10) + GREGORIAN;
139 static void random_bytes(void *buf, size_t n) {
140 unsigned char *s = buf;
144 i += pd_uuid_rng_get_bytes(s+i, n-i);
148 static uint64_t random_mc_mac(struct pd_uuid_state *s) {
151 if (s && s->random_bytes) {
152 s->random_bytes(&node, sizeof node, s->rng_state);
154 random_bytes(&node, sizeof node);
156 node |= 0x800000000000ULL; /* rfc 4.5 */
161 * TODO would probably make more sense to use a destination array
162 * rather than returning an integer
164 static uint64_t current_node(struct pd_uuid_state *st) {
170 struct ifreq interfaces[4];
174 s = socket(AF_INET, SOCK_DGRAM, 0);
176 conf.ifc_len = sizeof interfaces;
177 conf.ifc_req = interfaces;
178 if (ioctl(s, SIOCGIFCONF, &conf) == 0) {
179 for (i=0; i < 4; i++) {
180 req = &conf.ifc_req[i];
181 if (ioctl(s, SIOCGIFFLAGS, req) != 0) {
184 if (req->ifr_flags & IFF_LOOPBACK) {
187 if (req->ifr_flags & IFF_NOARP) {
190 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
191 data = (unsigned char *)req->ifr_hwaddr.sa_data;
193 node = node << 8; node += data[1];
194 node = node << 8; node += data[2];
195 node = node << 8; node += data[3];
196 node = node << 8; node += data[4];
197 node = node << 8; node += data[5];
207 /* this is any BSD based system i think */
209 struct ifaddrs *addrs;
211 struct sockaddr_dl *dl;
213 if (getifaddrs(&addrs) == 0) {
214 for (a = addrs; a; a = a->ifa_next) {
216 if (a->ifa_addr && a->ifa_addr->sa_family == AF_LINK) {
217 dl = (struct sockaddr_dl *)a->ifa_addr;
218 data = (unsigned char *)(dl->sdl_data + dl->sdl_nlen);
219 if (dl->sdl_alen != 6) continue;
222 node = node << 8; node += data[1];
223 node = node << 8; node += data[2];
224 node = node << 8; node += data[3];
225 node = node << 8; node += data[4];
226 node = node << 8; node += data[5];
235 #if defined(WIN32) || defined(__CYGWIN__)
236 IP_ADAPTER_INFO addrs[4];
242 rc = GetAdaptersInfo(addrs, &size);
243 if (rc == ERROR_SUCCESS) {
244 PIP_ADAPTER_INFO info;
245 for (info = addrs; info; info = info->Next) {
246 if (info->Type != MIB_IF_TYPE_ETHERNET) {
249 data = info->Address;
251 node = node << 8; node += data[1];
252 node = node << 8; node += data[2];
253 node = node << 8; node += data[3];
254 node = node << 8; node += data[4];
255 node = node << 8; node += data[5];
261 /* if we get here, use a random multicast address */
262 node = random_mc_mac(st);
266 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
269 if (s && s->random_bytes) {
270 s->random_bytes(&seq, sizeof seq, s->rng_state);
272 random_bytes(&seq, sizeof seq);
277 static int read_state(struct pd_uuid_state *s) {
282 s->clock_sequence = 0;
285 node = current_node(s);
287 if (!s->available || s->node != node) {
288 s->clock_sequence = random_clock_sequence(s);
294 static int save_state(struct pd_uuid_state *s) {
299 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
300 unsigned char *s = buf;
304 i += pd_uuid_rng_get_bytes(s+i, n-i);
309 int pd_uuid_init(struct pd_uuid_state *s, int flags) {
312 s->get_lock = obtain_global_lock;
313 s->release_lock = release_global_lock;
319 s->node = current_node(s);
321 s->read_state = read_state;
325 s->random_bytes = get_bytes;
333 int pd_uuid_init_state(struct pd_uuid_state *s) {
336 s->get_lock = obtain_global_lock;
337 s->release_lock = release_global_lock;
340 s->read_state = read_state;
341 s->save_state = save_state;
343 s->random_bytes = get_bytes;
351 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
352 struct pd_uuid_state ls;
358 pd_uuid_init_state(s);
362 if ((err = s->get_lock(s->lock_data)) != 0) {
363 /* TODO set uuid to nil ? */
364 /* be cute and have an "error" uuid? */
370 if ((err = s->read_state(s)) != 0) {
375 now = current_time();
377 if (s->available && s->timestamp > now) {
384 if ((err = s->save_state(s)) != 0) {
389 if (s->release_lock) {
390 if ((err = s->release_lock(s->lock_data)) != 0) {
391 /* TODO set uuid to nil ? */
392 /* be cute and have an "error" uuid? */
397 format_uuid(uuid, s, 1);
402 int pd_uuid_make_v1mc(struct pd_uuid_state *s, pd_uuid_t *uuid) {
403 struct pd_uuid_state ls;
410 pd_uuid_init_state(s);
414 if ((err = s->get_lock(s->lock_data)) != 0) {
415 /* TODO set uuid to nil ? */
416 /* be cute and have an "error" uuid? */
422 if ((err = s->read_state(s)) != 0) {
427 now = current_time();
428 node = random_mc_mac(s);
430 if (!s->available || s->node != node) {
431 s->clock_sequence = random_clock_sequence(s);
435 if (s->available && s->timestamp > now) {
442 if ((err = s->save_state(s)) != 0) {
447 if (s->release_lock) {
448 if ((err = s->release_lock(s->lock_data)) != 0) {
449 /* TODO set uuid to nil ? */
450 /* be cute and have an "error" uuid? */
455 format_uuid(uuid, s, 1);
460 int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid) {
461 random_bytes(uuid, sizeof *uuid);
462 set_version(uuid, 4);
463 set_reserved(uuid, 0x2);
467 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
469 unsigned char *h = hash;
474 set_version(s, version);
475 set_reserved(s, 0x2);
479 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
481 unsigned char hash[16];
484 md5_process(&hs, ns->data, 16);
485 md5_process(&hs, data, len);
487 pd_set_uuid_hash(uuid, hash, 3);
491 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
493 unsigned char hash[20];
496 sha1_process(&hs, ns->data, sizeof *ns);
497 sha1_process(&hs, data, len);
498 sha1_done(&hs, hash);
499 pd_set_uuid_hash(uuid, hash, 5);
503 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
508 if (*s == 0) return 0;
511 if (sscanf(s, "%02x", &byte) != 1) {
515 uuid->data[i] = byte & 0xff;
520 /* pre-defined namespace uuids */
522 pd_uuid_t pd_uuid_ns_dns = {
524 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
525 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
529 pd_uuid_t pd_uuid_ns_url = {
531 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
532 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
536 pd_uuid_t pd_uuid_ns_oid = {
538 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
539 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
543 pd_uuid_t pd_uuid_ns_x500 = {
545 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
546 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
550 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
552 memcpy(dst->data, src->data, 16);
558 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
560 return memcmp(a, b, 16);