]> pd.if.org Git - uuid/blob - internal.c
remove unused variable from makefile
[uuid] / internal.c
1 /*
2  * internal functions for uuid library
3  *
4  * written by nathan wagner and placed in the public domain
5  */
6 #include <stdint.h>
7 #include <sys/time.h>
8 #include <stdio.h>
9 #include <errno.h>
10
11 #include <inttypes.h>
12
13 #include "hash.h"
14
15 #include "pduuid.h"
16
17 #ifdef __linux__
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <linux/if.h>
23 #include <unistd.h>
24 #endif
25
26 #ifdef __APPLE__
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <net/if_dl.h>
30 #include <ifaddrs.h>
31 #endif
32
33 #ifdef WIN32
34 #include <windows.h>
35 #include <iphlpapi.h>
36 #endif
37
38 #ifdef __CYGWIN__
39 #include <windows.h>
40 #include <iphlpapi.h>
41 #endif
42
43 #if 0
44 static void pnode(uint64_t node) {
45         unsigned int bytes[6];
46         int i;
47         for (i=0;i<6;i++) {
48                 bytes[5-i] = node & 0xff;
49                 node >>= 8;
50         }
51
52         fprintf(stderr, "%02x", bytes[0]);
53
54         for (i=1;i<6;i++) {
55                 fprintf(stderr, ":%02x", bytes[i]);
56         }
57         fprintf(stderr, "\n");
58 }
59 #endif
60
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;
66 }
67
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;
71 }
72
73 static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
74         u->data[7] = hi & 0xff;
75         u->data[6] &= 0xf0;
76         u->data[6] |= (hi >> 8) & 0xf;
77 }
78
79 static void set_version(pd_uuid_t *u, uint8_t version) {
80         u->data[6] &= 0xf;
81         u->data[6] |= (version & 0xf) << 4;
82 }
83
84 static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
85         u->data[9] = low & 0xff;
86 }
87
88 static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
89         u->data[8] &= 0xc0;
90         u->data[8] |= hi & 0x3f;
91 }
92
93 static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
94         u->data[8] &= 0x3f;
95         u->data[8] |= (reserved & 0x3) << 6;
96 }
97
98 #if 0
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];
106 }
107 #endif
108
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;
116 }
117
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);
122 }
123
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);
127 }
128
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);
135 }
136
137 static int obtain_global_lock(void *data) {
138         /* no-op */
139         return 0;
140 }
141
142 static int release_global_lock(void *data) {
143         /* no-op */
144         return 0;
145 }
146
147 #define GREGORIAN 122192928000000000ULL
148 static uint64_t current_time(void) {
149         uint64_t now;
150         struct timeval tv;
151         static int seq = 0;
152         
153         /* TODO is this BSD specific? */
154         gettimeofday(&tv, 0);
155
156         now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL + seq++ % 10) + GREGORIAN;
157         return now;
158 }
159
160 static void random_bytes(void *buf, size_t n) {
161         unsigned char *s = buf;
162         int i = 0;
163
164         while (i < n) {
165                 i += pd_uuid_rng_get_bytes(s+i, n-i);
166         }
167 }
168
169 static uint64_t random_mc_mac(struct pd_uuid_state  *s) {
170         uint64_t node = 0;
171
172         if (s && s->random_bytes) {
173                 s->random_bytes(&node, sizeof node, s->rng_state);
174         } else {
175                 random_bytes(&node, sizeof node);
176         }
177         node |= 0x800000000000ULL; /* rfc 4.5 */
178         return node;
179 }
180
181
182 /*
183  * TODO would probably make more sense to use a destination array
184  * rather than returning an integer
185  */
186 static uint64_t current_node(struct pd_uuid_state *st) {
187         uint64_t node = 0;
188
189 #ifdef __linux__
190         struct ifconf   conf;
191         struct ifreq    *req;
192         struct ifreq    interfaces[4];
193         int s, i;
194         unsigned char *data;
195
196         s = socket(AF_INET, SOCK_DGRAM, 0);
197         if (s != -1) {
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) {
204                                         continue;
205                                 }
206                                 if (req->ifr_flags & IFF_LOOPBACK) {
207                                         continue;
208                                 }
209                                 if (req->ifr_flags & IFF_NOARP) {
210                                         continue;
211                                 }
212
213
214                                 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
215                                         data = (unsigned char *)req->ifr_hwaddr.sa_data;
216                                         node = data[0];
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];
222                                         close(s);
223
224                                         return node;
225                                 } else {
226                                         fprintf(stderr, "ioctl to read address failed: %d\n", errno);
227                                 }
228                         }
229                 }
230                 close(s);
231         }
232 #endif
233
234         /* this is any BSD based system i think */
235 #ifdef __APPLE__
236         struct ifaddrs *addrs;
237         struct ifaddrs *a;
238         struct sockaddr_dl *dl;
239         unsigned char *data;
240         if (getifaddrs(&addrs) == 0) {
241                 for (a = addrs; a; a = a->ifa_next) {
242
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;
247
248                                 node = data[0];
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];
254                                 freeifaddrs(addrs);
255                                 return node;
256                         }
257                 }
258                 freeifaddrs(addrs);
259         }
260 #endif
261
262 #if defined(WIN32) || defined(__CYGWIN__)
263         IP_ADAPTER_INFO addrs[4];
264         DWORD size;
265         int rc;
266         unsigned char *data;
267
268         size = sizeof addrs;
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) {
274                                 continue;
275                         }
276                         data = info->Address;
277                         node = data[0];
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];
283                 }
284                 return node;
285         }
286 #endif
287
288         /* if we get here, use a random multicast address */
289         node = random_mc_mac(st);
290         return node;
291 }
292
293 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
294         uint16_t seq;
295
296         if (s && s->random_bytes) {
297                 s->random_bytes(&seq, sizeof seq, s->rng_state);
298         } else {
299                 random_bytes(&seq, sizeof seq);
300         }
301         return seq;
302 }
303
304 static int read_state(struct pd_uuid_state *s) {
305         uint64_t        node;
306
307         s->available = 0;
308
309         node = current_node(s);
310
311         if (!s->available || s->node != node) {
312                 s->clock_sequence = random_clock_sequence(s);
313         }
314         s->node = node;
315
316         return 0;
317 }
318
319 static int save_state(struct pd_uuid_state *s) {
320         /* no op */
321         return 0;
322 }
323
324 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
325         unsigned char *s = buf;
326         int i = 0;
327
328         while (i < n) {
329                 i += pd_uuid_rng_get_bytes(s+i, n-i);
330         }
331         return i;
332 }
333
334 int pd_uuid_init(struct pd_uuid_state *s, int flags) {
335         if (!s) return 0;
336
337         s->get_lock = obtain_global_lock;
338         s->release_lock = release_global_lock;
339         s->lock_data = 0;
340
341         if (flags & 0x1) {
342                 s->read_state = 0;
343                 s->save_state = 0;
344                 s->node = current_node(s);
345         } else {
346                 s->read_state = read_state;
347                 s->save_state = 0;
348         }
349
350         s->random_bytes = get_bytes;
351         s->rng_state = 0;
352
353         s->available = 0;
354
355         return 1;
356 }
357
358 int pd_uuid_init_state(struct pd_uuid_state *s) {
359         if (!s) return 0;
360
361         s->get_lock = obtain_global_lock;
362         s->release_lock = release_global_lock;
363         s->lock_data = 0;
364
365         s->read_state = read_state;
366         s->save_state = save_state;
367
368         s->random_bytes = get_bytes;
369         s->rng_state = 0;
370         s->node = 0;
371
372         s->available = 0;
373
374         return 1;
375 }
376 static int pd_uuid_make_v1_any(struct pd_uuid_state *s, pd_uuid_t *uuid, int rmac);
377
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);
380 }
381
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);
384 }
385
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;
388         uint64_t        now;
389         uint64_t        node;
390         int err;
391
392         if (!s) {
393                 s = &ls;
394                 pd_uuid_init_state(s);
395         }
396
397         if (s->get_lock) {
398                 if ((err = s->get_lock(s->lock_data)) != 0) {
399                         /* TODO set uuid to nil ? */
400                         /* be cute and have an "error" uuid? */
401                         return 0;
402                 }
403         }
404
405         if (s->read_state) {
406                 if ((err = s->read_state(s)) != 0) {
407                         return 0;
408                 }
409         }
410
411         now = current_time();
412         if (rmac) {
413                 node = random_mc_mac(s);
414         } else {
415                 node = current_node(s);
416         }
417
418         if (!s->available || s->node != node) {
419                 s->clock_sequence = random_clock_sequence(s);
420         }
421         s->node = node;
422
423         if (s->available && s->timestamp > now) {
424                 s->clock_sequence++;
425         } else {
426                 s->timestamp = now;
427         }
428
429         if (s->save_state) {
430                 if ((err = s->save_state(s)) != 0) {
431                         return 0;
432                 }
433         }
434
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? */
439                         return 0;
440                 }
441         }
442
443         format_uuid(uuid, s, 1);
444
445         return 1;
446 }
447
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);
452         return 1;
453 }
454
455 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
456         int i;
457         unsigned char *h = hash;
458
459         for (i=0;i<16;i++) {
460                 s->data[i] = h[i];
461         }
462         set_version(s, version);
463         set_reserved(s, 0x2);
464         return 1;
465 }
466
467 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
468         hash_state hs;
469         unsigned char hash[16];
470
471         md5_init(&hs);
472         md5_process(&hs, ns->data, 16);
473         md5_process(&hs, data, len);
474         md5_done(&hs, hash);
475         pd_set_uuid_hash(uuid, hash, 3);
476         return 1;
477 }
478
479 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
480         hash_state hs;
481         unsigned char hash[20];
482
483         sha1_init(&hs);
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);
488         return 1;
489 }
490
491 /*
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
495  */
496 char *pd_uuid_get_string(pd_uuid_t *uuid, char *s) {
497         char *r;
498         int i;
499
500         r = s;
501
502         for (i=0;i<16;i++) {
503                 r += sprintf(r, "%.2x", (int)uuid->data[i]);
504                 if (i == 3 || i == 5 || i == 7 || i == 9) {
505                         *r++ = '-';
506                         *r = 0;
507                 }
508         }
509
510         return s;
511 }
512
513 /*
514  * might be faster to sscanf in four bytes at a time
515  * and using htonl()
516  * A nybble loop might be faster yet.
517  */
518 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
519         unsigned int byte;
520         int i;
521
522         for (i=0;i<16;i++) {
523                 if (*s == 0) return 0;
524                 if (*s == '-') s++;
525
526                 if (sscanf(s, "%02x", &byte) != 1) {
527                         return 0;
528                 }
529                 s += 2;
530                 uuid->data[i] = byte & 0xff;
531         }
532         return 1;
533 }
534
535 /* pre-defined namespace uuids */
536
537 pd_uuid_t pd_uuid_ns_dns = {
538         {
539                 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
540                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
541         }
542 };
543
544 pd_uuid_t pd_uuid_ns_url = {
545         {
546                 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
547                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
548         }
549 };
550
551 pd_uuid_t pd_uuid_ns_oid = {
552         {
553                 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
554                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
555         }
556 };
557
558 pd_uuid_t pd_uuid_ns_x500 = {
559         {
560                 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
561                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
562         }
563 };
564
565 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
566         if (src && dst) {
567                 memcpy(dst->data, src->data, 16);
568                 return 1;
569         }
570         return 0;
571 }
572
573 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
574         if (a && b) {
575                 return memcmp(a, b, 16);
576         }
577         return 1;
578 }