]> pd.if.org Git - uuid/blob - internal.c
Fixed file descriptor leak getting linux mac addr.
[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         
131         /* TODO is this BSD specific? */
132         gettimeofday(&tv, 0);
133
134         now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL) + GREGORIAN;
135         return now;
136 }
137
138 static void random_bytes(void *buf, size_t n) {
139         unsigned char *s = buf;
140         int i = 0;
141
142         while (i < n) {
143                 i += pd_uuid_rng_get_bytes(s+i, n-i);
144         }
145 }
146
147 static uint64_t random_mc_mac(struct pd_uuid_state  *s) {
148         uint64_t node = 0;
149
150         if (s && s->random_bytes) {
151                 s->random_bytes(&node, sizeof node, s->rng_state);
152         } else {
153                 random_bytes(&node, sizeof node);
154         }
155         node |= 0x800000000000ULL; /* rfc 4.5 */
156         return node;
157 }
158
159 /*
160  * TODO would probably make more sense to use a destination array
161  * rather than returning an integer
162  */
163 static uint64_t current_node(struct pd_uuid_state *st) {
164         uint64_t node = 0;
165
166 #ifdef __linux__
167         struct ifconf   conf;
168         struct ifreq    *req;
169         struct ifreq    interfaces[4];
170         int s, i;
171         unsigned char *data;
172
173         s = socket(AF_INET, SOCK_DGRAM, 0);
174         if (s != -1) {
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) {
181                                         continue;
182                                 }
183                                 if (req->ifr_flags & IFF_LOOPBACK) {
184                                         continue;
185                                 }
186                                 if (req->ifr_flags & IFF_NOARP) {
187                                         continue;
188                                 }
189                                 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
190                                         data = (unsigned char *)req->ifr_hwaddr.sa_data;
191                                         node = data[0];
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];
197                                         close(s);
198                                         return node;
199                                 }
200                         }
201                 }
202                 close(s);
203         }
204 #endif
205
206         /* this is any BSD based system i think */
207 #ifdef __APPLE__
208         struct ifaddrs *addrs;
209         struct ifaddrs *a;
210         struct sockaddr_dl *dl;
211         unsigned char *data;
212         if (getifaddrs(&addrs) == 0) {
213                 for (a = addrs; a; a = a->ifa_next) {
214
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;
219
220                                 node = data[0];
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];
226                                 freeifaddrs(addrs);
227                                 return node;
228                         }
229                 }
230                 freeifaddrs(addrs);
231         }
232 #endif
233
234 #if defined(WIN32) || defined(__CYGWIN__)
235         IP_ADAPTER_INFO addrs[4];
236         DWORD size;
237         int rc;
238         unsigned char *data;
239
240         size = sizeof addrs;
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) {
246                                 continue;
247                         }
248                         data = info->Address;
249                         node = data[0];
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];
255                 }
256                 return node;
257         }
258 #endif
259
260         /* if we get here, use a random multicast address */
261         node = random_mc_mac(st);
262         return node;
263 }
264
265 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
266         uint16_t seq;
267
268         if (s && s->random_bytes) {
269                 s->random_bytes(&seq, sizeof seq, s->rng_state);
270         } else {
271                 random_bytes(&seq, sizeof seq);
272         }
273         return seq;
274 }
275
276 static int read_state(struct pd_uuid_state *s) {
277         s->available = 0;
278         s->node = 0LL;
279         s->clock_sequence = 0;
280         s->timestamp = 0LL;
281
282         return 0;
283 }
284
285 static int save_state(struct pd_uuid_state *s) {
286         /* no op */
287         return 0;
288 }
289
290 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
291         unsigned char *s = buf;
292         int i = 0;
293
294         while (i < n) {
295                 i += pd_uuid_rng_get_bytes(s+i, n-i);
296         }
297         return i;
298 }
299
300 int pd_uuid_init_state(struct pd_uuid_state *s) {
301         if (!s) return 0;
302
303         s->get_lock = obtain_global_lock;
304         s->release_lock = release_global_lock;
305         s->lock_data = 0;
306
307         s->read_state = read_state;
308         s->save_state = save_state;
309
310         s->random_bytes = get_bytes;
311         s->rng_state = 0;
312
313         s->available = 0;
314
315         return 1;
316 }
317
318 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
319         struct pd_uuid_state    ls;
320         uint64_t        now;
321         uint64_t        node;
322         int err;
323
324         if (!s) {
325                 s = &ls;
326                 pd_uuid_init_state(s);
327         }
328
329         if (s->get_lock) {
330                 if ((err = s->get_lock(s->lock_data)) != 0) {
331                         /* TODO set uuid to nil ? */
332                         /* be cute and have an "error" uuid? */
333                         return 0;
334                 }
335         }
336
337         if (s->read_state) {
338                 if ((err = s->read_state(s)) != 0) {
339                         return 0;
340                 }
341         }
342
343         now = current_time();
344         node = current_node(s);
345
346         if (!s->available || s->node != node) {
347                 s->clock_sequence = random_clock_sequence(s);
348         }
349
350         s->node = node;
351
352         if (s->available && s->timestamp > now) {
353                 s->clock_sequence++;
354         } else {
355                 s->timestamp = now;
356         }
357
358         if (s->save_state) {
359                 if ((err = s->save_state(s)) != 0) {
360                         return 0;
361                 }
362         }
363
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? */
368                         return 0;
369                 }
370         }
371
372         format_uuid(uuid, s, 1);
373
374         return 1;
375 }
376
377 int pd_uuid_make_v1mc(struct pd_uuid_state *s, pd_uuid_t *uuid) {
378         struct pd_uuid_state    ls;
379         uint64_t        now;
380         uint64_t        node;
381         int err;
382
383         if (!s) {
384                 s = &ls;
385                 pd_uuid_init_state(s);
386         }
387
388         if (s->get_lock) {
389                 if ((err = s->get_lock(s->lock_data)) != 0) {
390                         /* TODO set uuid to nil ? */
391                         /* be cute and have an "error" uuid? */
392                         return 0;
393                 }
394         }
395
396         if (s->read_state) {
397                 if ((err = s->read_state(s)) != 0) {
398                         return 0;
399                 }
400         }
401
402         now = current_time();
403         node = random_mc_mac(s);
404
405         if (!s->available || s->node != node) {
406                 s->clock_sequence = random_clock_sequence(s);
407         }
408         s->node = node;
409
410         if (s->available && s->timestamp > now) {
411                 s->clock_sequence++;
412         } else {
413                 s->timestamp = now;
414         }
415
416         if (s->save_state) {
417                 if ((err = s->save_state(s)) != 0) {
418                         return 0;
419                 }
420         }
421
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? */
426                         return 0;
427                 }
428         }
429
430         format_uuid(uuid, s, 1);
431
432         return 1;
433 }
434
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);
439         return 1;
440 }
441
442 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
443         int i;
444         unsigned char *h = hash;
445
446         for (i=0;i<16;i++) {
447                 s->data[i] = h[i];
448         }
449         set_version(s, version);
450         set_reserved(s, 0x2);
451         return 1;
452 }
453
454 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
455         hash_state hs;
456         unsigned char hash[16];
457
458         md5_init(&hs);
459         md5_process(&hs, ns->data, 16);
460         md5_process(&hs, data, len);
461         md5_done(&hs, hash);
462         pd_set_uuid_hash(uuid, hash, 3);
463         return 1;
464 }
465
466 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
467         hash_state hs;
468         unsigned char hash[20];
469
470         sha1_init(&hs);
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);
475         return 1;
476 }
477
478 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
479         unsigned int byte;
480         int i;
481
482         for (i=0;i<16;i++) {
483                 if (*s == 0) return 0;
484                 if (*s == '-') s++;
485
486                 if (sscanf(s, "%02x", &byte) != 1) {
487                         return 0;
488                 }
489                 s += 2;
490                 uuid->data[i] = byte & 0xff;
491         }
492         return 1;
493 }
494
495 /* pre-defined namespace uuids */
496
497 pd_uuid_t pd_uuid_ns_dns = {
498         {
499                 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
500                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
501         }
502 };
503
504 pd_uuid_t pd_uuid_ns_url = {
505         {
506                 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
507                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
508         }
509 };
510
511 pd_uuid_t pd_uuid_ns_oid = {
512         {
513                 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
514                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
515         }
516 };
517
518 pd_uuid_t pd_uuid_ns_x500 = {
519         {
520                 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
521                 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
522         }
523 };
524
525 int pd_uuid_copy(pd_uuid_t *src, pd_uuid_t *dst) {
526         if (src && dst) {
527                 memcpy(dst->data, src->data, 16);
528                 return 1;
529         }
530         return 0;
531 }
532
533 int pd_uuid_cmp(pd_uuid_t *a, pd_uuid_t *b) {
534         if (a && b) {
535                 return memcmp(a, b, 16);
536         }
537         return 1;
538 }