]> pd.if.org Git - uuid/blob - internal.c
Add support for gin indexes on uuid arrays.
[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
10 #include "hash.h"
11
12 #include "pduuid.h"
13
14 #ifdef __linux__
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <linux/if.h>
20 #include <unistd.h>
21 #endif
22
23 #ifdef __APPLE__
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <net/if_dl.h>
27 #include <ifaddrs.h>
28 #endif
29
30 #ifdef WIN32
31 #include <windows.h>
32 #include <iphlpapi.h>
33 #endif
34
35 #ifdef __CYGWIN__
36 #include <windows.h>
37 #include <iphlpapi.h>
38 #endif
39
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;
45 }
46
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;
50 }
51
52 static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
53         u->data[7] = hi & 0xff;
54         u->data[6] &= 0xf0;
55         u->data[6] |= (hi >> 8) & 0xf;
56 }
57
58 static void set_version(pd_uuid_t *u, uint8_t version) {
59         u->data[6] &= 0xf;
60         u->data[6] |= (version & 0xf) << 4;
61 }
62
63 static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
64         u->data[9] = low & 0xff;
65 }
66
67 static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
68         u->data[8] &= 0xc0;
69         u->data[8] |= hi & 0x3f;
70 }
71
72 static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
73         u->data[8] &= 0x3f;
74         u->data[8] |= (reserved & 0x3) << 6;
75 }
76
77 #if 0
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];
85 }
86 #endif
87
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;
95 }
96
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);
101 }
102
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);
106 }
107
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);
114 }
115
116 static int obtain_global_lock(void *data) {
117         /* no-op */
118         return 0;
119 }
120
121 static int release_global_lock(void *data) {
122         /* no-op */
123         return 0;
124 }
125
126 #define GREGORIAN 122192928000000000ULL
127 static uint64_t current_time(void) {
128         uint64_t now;
129         struct timeval tv;
130         static int seq = 0;
131         
132         /* TODO is this BSD specific? */
133         gettimeofday(&tv, 0);
134
135         now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL + seq++ % 10) + GREGORIAN;
136         return now;
137 }
138
139 static void random_bytes(void *buf, size_t n) {
140         unsigned char *s = buf;
141         int i = 0;
142
143         while (i < n) {
144                 i += pd_uuid_rng_get_bytes(s+i, n-i);
145         }
146 }
147
148 static uint64_t random_mc_mac(struct pd_uuid_state  *s) {
149         uint64_t node = 0;
150
151         if (s && s->random_bytes) {
152                 s->random_bytes(&node, sizeof node, s->rng_state);
153         } else {
154                 random_bytes(&node, sizeof node);
155         }
156         node |= 0x800000000000ULL; /* rfc 4.5 */
157         return node;
158 }
159
160 /*
161  * TODO would probably make more sense to use a destination array
162  * rather than returning an integer
163  */
164 static uint64_t current_node(struct pd_uuid_state *st) {
165         uint64_t node = 0;
166
167 #ifdef __linux__
168         struct ifconf   conf;
169         struct ifreq    *req;
170         struct ifreq    interfaces[4];
171         int s, i;
172         unsigned char *data;
173
174         s = socket(AF_INET, SOCK_DGRAM, 0);
175         if (s != -1) {
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) {
182                                         continue;
183                                 }
184                                 if (req->ifr_flags & IFF_LOOPBACK) {
185                                         continue;
186                                 }
187                                 if (req->ifr_flags & IFF_NOARP) {
188                                         continue;
189                                 }
190                                 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
191                                         data = (unsigned char *)req->ifr_hwaddr.sa_data;
192                                         node = data[0];
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];
198                                         close(s);
199                                         return node;
200                                 }
201                         }
202                 }
203                 close(s);
204         }
205 #endif
206
207         /* this is any BSD based system i think */
208 #ifdef __APPLE__
209         struct ifaddrs *addrs;
210         struct ifaddrs *a;
211         struct sockaddr_dl *dl;
212         unsigned char *data;
213         if (getifaddrs(&addrs) == 0) {
214                 for (a = addrs; a; a = a->ifa_next) {
215
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;
220
221                                 node = data[0];
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];
227                                 freeifaddrs(addrs);
228                                 return node;
229                         }
230                 }
231                 freeifaddrs(addrs);
232         }
233 #endif
234
235 #if defined(WIN32) || defined(__CYGWIN__)
236         IP_ADAPTER_INFO addrs[4];
237         DWORD size;
238         int rc;
239         unsigned char *data;
240
241         size = sizeof addrs;
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) {
247                                 continue;
248                         }
249                         data = info->Address;
250                         node = data[0];
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];
256                 }
257                 return node;
258         }
259 #endif
260
261         /* if we get here, use a random multicast address */
262         node = random_mc_mac(st);
263         return node;
264 }
265
266 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
267         uint16_t seq;
268
269         if (s && s->random_bytes) {
270                 s->random_bytes(&seq, sizeof seq, s->rng_state);
271         } else {
272                 random_bytes(&seq, sizeof seq);
273         }
274         return seq;
275 }
276
277 static int read_state(struct pd_uuid_state *s) {
278         uint64_t        node;
279
280         s->available = 0;
281         s->node = 0LL;
282         s->clock_sequence = 0;
283         s->timestamp = 0LL;
284
285         node = current_node(s);
286
287         if (!s->available || s->node != node) {
288                 s->clock_sequence = random_clock_sequence(s);
289         }
290
291         return 0;
292 }
293
294 static int save_state(struct pd_uuid_state *s) {
295         /* no op */
296         return 0;
297 }
298
299 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
300         unsigned char *s = buf;
301         int i = 0;
302
303         while (i < n) {
304                 i += pd_uuid_rng_get_bytes(s+i, n-i);
305         }
306         return i;
307 }
308
309 int pd_uuid_init(struct pd_uuid_state *s, int flags) {
310         if (!s) return 0;
311
312         s->get_lock = obtain_global_lock;
313         s->release_lock = release_global_lock;
314         s->lock_data = 0;
315
316         if (flags & 0x1) {
317                 s->read_state = 0;
318                 s->save_state = 0;
319                 s->node = current_node(s);
320         } else {
321                 s->read_state = read_state;
322                 s->save_state = 0;
323         }
324
325         s->random_bytes = get_bytes;
326         s->rng_state = 0;
327
328         s->available = 0;
329
330         return 1;
331 }
332
333 int pd_uuid_init_state(struct pd_uuid_state *s) {
334         if (!s) return 0;
335
336         s->get_lock = obtain_global_lock;
337         s->release_lock = release_global_lock;
338         s->lock_data = 0;
339
340         s->read_state = read_state;
341         s->save_state = save_state;
342
343         s->random_bytes = get_bytes;
344         s->rng_state = 0;
345
346         s->available = 0;
347
348         return 1;
349 }
350
351 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
352         struct pd_uuid_state    ls;
353         uint64_t        now;
354         int err;
355
356         if (!s) {
357                 s = &ls;
358                 pd_uuid_init_state(s);
359         }
360
361         if (s->get_lock) {
362                 if ((err = s->get_lock(s->lock_data)) != 0) {
363                         /* TODO set uuid to nil ? */
364                         /* be cute and have an "error" uuid? */
365                         return 0;
366                 }
367         }
368
369         if (s->read_state) {
370                 if ((err = s->read_state(s)) != 0) {
371                         return 0;
372                 }
373         }
374
375         now = current_time();
376
377         if (s->available && s->timestamp > now) {
378                 s->clock_sequence++;
379         } else {
380                 s->timestamp = now;
381         }
382
383         if (s->save_state) {
384                 if ((err = s->save_state(s)) != 0) {
385                         return 0;
386                 }
387         }
388
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? */
393                         return 0;
394                 }
395         }
396
397         format_uuid(uuid, s, 1);
398
399         return 1;
400 }
401
402 int pd_uuid_make_v1mc(struct pd_uuid_state *s, pd_uuid_t *uuid) {
403         struct pd_uuid_state    ls;
404         uint64_t        now;
405         uint64_t        node;
406         int err;
407
408         if (!s) {
409                 s = &ls;
410                 pd_uuid_init_state(s);
411         }
412
413         if (s->get_lock) {
414                 if ((err = s->get_lock(s->lock_data)) != 0) {
415                         /* TODO set uuid to nil ? */
416                         /* be cute and have an "error" uuid? */
417                         return 0;
418                 }
419         }
420
421         if (s->read_state) {
422                 if ((err = s->read_state(s)) != 0) {
423                         return 0;
424                 }
425         }
426
427         now = current_time();
428         node = random_mc_mac(s);
429
430         if (!s->available || s->node != node) {
431                 s->clock_sequence = random_clock_sequence(s);
432         }
433         s->node = node;
434
435         if (s->available && s->timestamp > now) {
436                 s->clock_sequence++;
437         } else {
438                 s->timestamp = now;
439         }
440
441         if (s->save_state) {
442                 if ((err = s->save_state(s)) != 0) {
443                         return 0;
444                 }
445         }
446
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? */
451                         return 0;
452                 }
453         }
454
455         format_uuid(uuid, s, 1);
456
457         return 1;
458 }
459
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);
464         return 1;
465 }
466
467 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
468         int i;
469         unsigned char *h = hash;
470
471         for (i=0;i<16;i++) {
472                 s->data[i] = h[i];
473         }
474         set_version(s, version);
475         set_reserved(s, 0x2);
476         return 1;
477 }
478
479 int pd_uuid_make_v3(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[16];
482
483         md5_init(&hs);
484         md5_process(&hs, ns->data, 16);
485         md5_process(&hs, data, len);
486         md5_done(&hs, hash);
487         pd_set_uuid_hash(uuid, hash, 3);
488         return 1;
489 }
490
491 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
492         hash_state hs;
493         unsigned char hash[20];
494
495         sha1_init(&hs);
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);
500         return 1;
501 }
502
503 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
504         unsigned int byte;
505         int i;
506
507         for (i=0;i<16;i++) {
508                 if (*s == 0) return 0;
509                 if (*s == '-') s++;
510
511                 if (sscanf(s, "%02x", &byte) != 1) {
512                         return 0;
513                 }
514                 s += 2;
515                 uuid->data[i] = byte & 0xff;
516         }
517         return 1;
518 }
519
520 /* pre-defined namespace uuids */
521
522 pd_uuid_t pd_uuid_ns_dns = {
523         {
524                 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
525                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
526         }
527 };
528
529 pd_uuid_t pd_uuid_ns_url = {
530         {
531                 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
532                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
533         }
534 };
535
536 pd_uuid_t pd_uuid_ns_oid = {
537         {
538                 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
539                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
540         }
541 };
542
543 pd_uuid_t pd_uuid_ns_x500 = {
544         {
545                 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
546                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
547         }
548 };
549
550 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
551         if (src && dst) {
552                 memcpy(dst->data, src->data, 16);
553                 return 1;
554         }
555         return 0;
556 }
557
558 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
559         if (a && b) {
560                 return memcmp(a, b, 16);
561         }
562         return 1;
563 }