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>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <net/if_dl.h>
39 static void set_time_low(pd_uuid_t *u, uint32_t low) {
40 u->data[0] = (low >> 24) & 0xff;
41 u->data[1] = (low >> 16) & 0xff;
42 u->data[2] = (low >> 8) & 0xff;
43 u->data[3] = low & 0xff;
46 static void set_time_mid(pd_uuid_t *u, uint16_t mid) {
47 u->data[4] = (mid >> 8) & 0xff;
48 u->data[5] = mid & 0xff;
51 static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
52 u->data[7] = hi & 0xff;
54 u->data[6] |= (hi >> 8) & 0xf;
57 static void set_version(pd_uuid_t *u, uint8_t version) {
59 u->data[6] |= (version & 0xf) << 4;
62 static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
63 u->data[9] = low & 0xff;
66 static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
68 u->data[8] |= hi & 0x3f;
71 static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
73 u->data[8] |= (reserved & 0x3) << 6;
77 static void set_node(pd_uuid_t *u, uint8_t data[6]) {
78 u->data[10] = data[0];
79 u->data[11] = data[1];
80 u->data[12] = data[2];
81 u->data[13] = data[3];
82 u->data[14] = data[4];
83 u->data[15] = data[5];
87 static void set_node64(pd_uuid_t *u, uint64_t node) {
88 u->data[10] = (node >> 40) & 0xff;
89 u->data[11] = (node >> 32) & 0xff;
90 u->data[12] = (node >> 24) & 0xff;
91 u->data[13] = (node >> 16) & 0xff;
92 u->data[14] = (node >> 8) & 0xff;
93 u->data[15] = (node >> 0) & 0xff;
96 static void set_timestamp(pd_uuid_t *u, uint64_t ts) {
97 set_time_low(u, ts & 0xffffffff);
98 set_time_mid(u, (ts >> 32) & 0xffff);
99 set_time_hi(u, (ts >> 48) & 0xfff);
102 static void set_clockseq(pd_uuid_t *u, uint16_t seq) {
103 set_clock_seq_low(u, seq & 0xff);
104 set_clock_seq_hi(u, (seq >> 8) & 0xff);
107 static void format_uuid(pd_uuid_t *u, struct pd_uuid_state *s, int version) {
108 set_timestamp(u, s->timestamp);
109 set_version(u, version);
110 set_clockseq(u, s->clock_sequence);
111 set_reserved(u, 0x2);
112 set_node64(u, s->node);
115 static int obtain_global_lock(void *data) {
120 static int release_global_lock(void *data) {
125 #define GREGORIAN 122192928000000000ULL
126 static uint64_t current_time(void) {
130 /* TODO is this BSD specific? */
131 gettimeofday(&tv, 0);
133 now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL) + GREGORIAN;
137 static void random_bytes(void *buf, size_t n) {
138 unsigned char *s = buf;
142 i += pd_uuid_rng_get_bytes(s+i, n-i);
146 static uint64_t random_mc_mac(struct pd_uuid_state *s) {
149 if (s && s->random_bytes) {
150 s->random_bytes(&node, sizeof node, s->rng_state);
152 random_bytes(&node, sizeof node);
154 node |= 0x800000000000ULL; /* rfc 4.5 */
159 * TODO would probably make more sense to use a destination array
160 * rather than returning an integer
162 static uint64_t current_node(struct pd_uuid_state *st) {
168 struct ifreq interfaces[4];
172 s = socket(AF_INET, SOCK_DGRAM, 0);
174 conf.ifc_len = sizeof interfaces;
175 conf.ifc_req = interfaces;
176 if (ioctl(s, SIOCGIFCONF, &conf) == 0) {
177 for (i=0; i < 4; i++) {
178 req = &conf.ifc_req[i];
179 if (ioctl(s, SIOCGIFFLAGS, req) != 0) {
182 if (req->ifr_flags & IFF_LOOPBACK) {
185 if (req->ifr_flags & IFF_NOARP) {
188 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];
204 /* this is any BSD based system i think */
206 struct ifaddrs *addrs;
208 struct sockaddr_dl *dl;
210 if (getifaddrs(&addrs) == 0) {
211 for (a = addrs; a; a = a->ifa_next) {
213 if (a->ifa_addr && a->ifa_addr->sa_family == AF_LINK) {
214 dl = (struct sockaddr_dl *)a->ifa_addr;
215 data = (unsigned char *)(dl->sdl_data + dl->sdl_nlen);
216 if (dl->sdl_alen != 6) continue;
219 node = node << 8; node += data[1];
220 node = node << 8; node += data[2];
221 node = node << 8; node += data[3];
222 node = node << 8; node += data[4];
223 node = node << 8; node += data[5];
232 #if defined(WIN32) || defined(__CYGWIN__)
233 IP_ADAPTER_INFO addrs[4];
239 rc = GetAdaptersInfo(addrs, &size);
240 if (rc == ERROR_SUCCESS) {
241 PIP_ADAPTER_INFO info;
242 for (info = addrs; info; info = info->Next) {
243 if (info->Type != MIB_IF_TYPE_ETHERNET) {
246 data = info->Address;
248 node = node << 8; node += data[1];
249 node = node << 8; node += data[2];
250 node = node << 8; node += data[3];
251 node = node << 8; node += data[4];
252 node = node << 8; node += data[5];
258 /* if we get here, use a random multicast address */
259 node = random_mc_mac(st);
263 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
266 if (s && s->random_bytes) {
267 s->random_bytes(&seq, sizeof seq, s->rng_state);
269 random_bytes(&seq, sizeof seq);
274 static int read_state(struct pd_uuid_state *s) {
277 s->clock_sequence = 0;
283 static int save_state(struct pd_uuid_state *s) {
288 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
289 unsigned char *s = buf;
293 i += pd_uuid_rng_get_bytes(s+i, n-i);
298 int pd_uuid_init_state(struct pd_uuid_state *s) {
301 s->get_lock = obtain_global_lock;
302 s->release_lock = release_global_lock;
305 s->read_state = read_state;
306 s->save_state = save_state;
308 s->random_bytes = get_bytes;
316 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
317 struct pd_uuid_state ls;
324 pd_uuid_init_state(s);
328 if ((err = s->get_lock(s->lock_data)) != 0) {
329 /* TODO set uuid to nil ? */
330 /* be cute and have an "error" uuid? */
336 if ((err = s->read_state(s)) != 0) {
341 now = current_time();
342 node = current_node(s);
344 if (!s->available || s->node != node) {
345 s->clock_sequence = random_clock_sequence(s);
349 if (s->available && s->timestamp > now) {
356 if ((err = s->save_state(s)) != 0) {
361 if (s->release_lock) {
362 if ((err = s->release_lock(s->lock_data)) != 0) {
363 /* TODO set uuid to nil ? */
364 /* be cute and have an "error" uuid? */
369 format_uuid(uuid, s, 1);
374 int pd_uuid_make_v1mc(struct pd_uuid_state *ps, pd_uuid_t *uuid) {
375 struct pd_uuid_state s;
379 obtain_global_lock(0);
381 now = current_time();
382 node = random_mc_mac(&s);
384 s.clock_sequence = random_clock_sequence(&s);
387 if (s.available && s.timestamp > now) {
394 release_global_lock(0);
397 format_uuid(uuid, &s, 1);
402 int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid) {
403 random_bytes(uuid, sizeof *uuid);
404 set_version(uuid, 4);
405 set_reserved(uuid, 0x2);
409 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
411 unsigned char *h = hash;
416 set_version(s, version);
417 set_reserved(s, 0x2);
421 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
423 unsigned char hash[16];
426 md5_process(&hs, ns->data, 16);
427 md5_process(&hs, data, len);
429 pd_set_uuid_hash(uuid, hash, 3);
433 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
435 unsigned char hash[20];
438 sha1_process(&hs, ns->data, sizeof *ns);
439 sha1_process(&hs, data, len);
440 sha1_done(&hs, hash);
441 pd_set_uuid_hash(uuid, hash, 5);
445 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
450 if (*s == 0) return 0;
453 if (sscanf(s, "%02x", &byte) != 1) {
457 uuid->data[i] = byte & 0xff;
462 /* pre-defined namespace uuids */
464 pd_uuid_t pd_uuid_ns_dns = {
466 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
467 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
471 pd_uuid_t pd_uuid_ns_url = {
473 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
474 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
478 pd_uuid_t pd_uuid_ns_oid = {
480 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
481 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
485 pd_uuid_t pd_uuid_ns_x500 = {
487 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
488 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
492 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
494 memcpy(dst->data, src->data, 16);
500 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
502 return memcmp(a, b, 16);