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) {
131 /* TODO is this BSD specific? */
132 gettimeofday(&tv, 0);
134 now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL) + GREGORIAN;
138 static void random_bytes(void *buf, size_t n) {
139 unsigned char *s = buf;
143 i += pd_uuid_rng_get_bytes(s+i, n-i);
147 static uint64_t random_mc_mac(struct pd_uuid_state *s) {
150 if (s && s->random_bytes) {
151 s->random_bytes(&node, sizeof node, s->rng_state);
153 random_bytes(&node, sizeof node);
155 node |= 0x800000000000ULL; /* rfc 4.5 */
160 * TODO would probably make more sense to use a destination array
161 * rather than returning an integer
163 static uint64_t current_node(struct pd_uuid_state *st) {
169 struct ifreq interfaces[4];
173 s = socket(AF_INET, SOCK_DGRAM, 0);
175 conf.ifc_len = sizeof interfaces;
176 conf.ifc_req = interfaces;
177 if (ioctl(s, SIOCGIFCONF, &conf) == 0) {
178 for (i=0; i < 4; i++) {
179 req = &conf.ifc_req[i];
180 if (ioctl(s, SIOCGIFFLAGS, req) != 0) {
183 if (req->ifr_flags & IFF_LOOPBACK) {
186 if (req->ifr_flags & IFF_NOARP) {
189 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
190 data = (unsigned char *)req->ifr_hwaddr.sa_data;
192 node = node << 8; node += data[1];
193 node = node << 8; node += data[2];
194 node = node << 8; node += data[3];
195 node = node << 8; node += data[4];
196 node = node << 8; node += data[5];
206 /* this is any BSD based system i think */
208 struct ifaddrs *addrs;
210 struct sockaddr_dl *dl;
212 if (getifaddrs(&addrs) == 0) {
213 for (a = addrs; a; a = a->ifa_next) {
215 if (a->ifa_addr && a->ifa_addr->sa_family == AF_LINK) {
216 dl = (struct sockaddr_dl *)a->ifa_addr;
217 data = (unsigned char *)(dl->sdl_data + dl->sdl_nlen);
218 if (dl->sdl_alen != 6) continue;
221 node = node << 8; node += data[1];
222 node = node << 8; node += data[2];
223 node = node << 8; node += data[3];
224 node = node << 8; node += data[4];
225 node = node << 8; node += data[5];
234 #if defined(WIN32) || defined(__CYGWIN__)
235 IP_ADAPTER_INFO addrs[4];
241 rc = GetAdaptersInfo(addrs, &size);
242 if (rc == ERROR_SUCCESS) {
243 PIP_ADAPTER_INFO info;
244 for (info = addrs; info; info = info->Next) {
245 if (info->Type != MIB_IF_TYPE_ETHERNET) {
248 data = info->Address;
250 node = node << 8; node += data[1];
251 node = node << 8; node += data[2];
252 node = node << 8; node += data[3];
253 node = node << 8; node += data[4];
254 node = node << 8; node += data[5];
260 /* if we get here, use a random multicast address */
261 node = random_mc_mac(st);
265 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
268 if (s && s->random_bytes) {
269 s->random_bytes(&seq, sizeof seq, s->rng_state);
271 random_bytes(&seq, sizeof seq);
276 static int read_state(struct pd_uuid_state *s) {
279 s->clock_sequence = 0;
285 static int save_state(struct pd_uuid_state *s) {
290 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
291 unsigned char *s = buf;
295 i += pd_uuid_rng_get_bytes(s+i, n-i);
300 int pd_uuid_init_state(struct pd_uuid_state *s) {
303 s->get_lock = obtain_global_lock;
304 s->release_lock = release_global_lock;
307 s->read_state = read_state;
308 s->save_state = save_state;
310 s->random_bytes = get_bytes;
318 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
319 struct pd_uuid_state ls;
326 pd_uuid_init_state(s);
330 if ((err = s->get_lock(s->lock_data)) != 0) {
331 /* TODO set uuid to nil ? */
332 /* be cute and have an "error" uuid? */
338 if ((err = s->read_state(s)) != 0) {
343 now = current_time();
344 node = current_node(s);
346 if (!s->available || s->node != node) {
347 s->clock_sequence = random_clock_sequence(s);
352 if (s->available && s->timestamp > now) {
359 if ((err = s->save_state(s)) != 0) {
364 if (s->release_lock) {
365 if ((err = s->release_lock(s->lock_data)) != 0) {
366 /* TODO set uuid to nil ? */
367 /* be cute and have an "error" uuid? */
372 format_uuid(uuid, s, 1);
377 int pd_uuid_make_v1mc(struct pd_uuid_state *s, pd_uuid_t *uuid) {
378 struct pd_uuid_state ls;
385 pd_uuid_init_state(s);
389 if ((err = s->get_lock(s->lock_data)) != 0) {
390 /* TODO set uuid to nil ? */
391 /* be cute and have an "error" uuid? */
397 if ((err = s->read_state(s)) != 0) {
402 now = current_time();
403 node = random_mc_mac(s);
405 if (!s->available || s->node != node) {
406 s->clock_sequence = random_clock_sequence(s);
410 if (s->available && s->timestamp > now) {
417 if ((err = s->save_state(s)) != 0) {
422 if (s->release_lock) {
423 if ((err = s->release_lock(s->lock_data)) != 0) {
424 /* TODO set uuid to nil ? */
425 /* be cute and have an "error" uuid? */
430 format_uuid(uuid, s, 1);
435 int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid) {
436 random_bytes(uuid, sizeof *uuid);
437 set_version(uuid, 4);
438 set_reserved(uuid, 0x2);
442 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
444 unsigned char *h = hash;
449 set_version(s, version);
450 set_reserved(s, 0x2);
454 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
456 unsigned char hash[16];
459 md5_process(&hs, ns->data, 16);
460 md5_process(&hs, data, len);
462 pd_set_uuid_hash(uuid, hash, 3);
466 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
468 unsigned char hash[20];
471 sha1_process(&hs, ns->data, sizeof *ns);
472 sha1_process(&hs, data, len);
473 sha1_done(&hs, hash);
474 pd_set_uuid_hash(uuid, hash, 5);
478 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
483 if (*s == 0) return 0;
486 if (sscanf(s, "%02x", &byte) != 1) {
490 uuid->data[i] = byte & 0xff;
495 /* pre-defined namespace uuids */
497 pd_uuid_t pd_uuid_ns_dns = {
499 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
500 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
504 pd_uuid_t pd_uuid_ns_url = {
506 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
507 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
511 pd_uuid_t pd_uuid_ns_oid = {
513 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
514 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
518 pd_uuid_t pd_uuid_ns_x500 = {
520 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
521 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
525 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
527 memcpy(dst->data, src->data, 16);
533 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
535 return memcmp(a, b, 16);