]> pd.if.org Git - uuid/blob - internal.c
Removed unused variable
[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 #endif
21
22 #ifdef __APPLE__
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <net/if_dl.h>
26 #include <ifaddrs.h>
27 #endif
28
29 #ifdef WIN32
30 #include <windows.h>
31 #include <iphlpapi.h>
32 #endif
33
34 #ifdef __CYGWIN__
35 #include <windows.h>
36 #include <iphlpapi.h>
37 #endif
38
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;
44 }
45
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;
49 }
50
51 static void set_time_hi(pd_uuid_t *u, uint16_t hi) {
52         u->data[7] = hi & 0xff;
53         u->data[6] &= 0xf0;
54         u->data[6] |= (hi >> 8) & 0xf;
55 }
56
57 static void set_version(pd_uuid_t *u, uint8_t version) {
58         u->data[6] &= 0xf;
59         u->data[6] |= (version & 0xf) << 4;
60 }
61
62 static void set_clock_seq_low(pd_uuid_t *u, uint8_t low) {
63         u->data[9] = low & 0xff;
64 }
65
66 static void set_clock_seq_hi(pd_uuid_t *u, uint8_t hi) {
67         u->data[8] &= 0xc0;
68         u->data[8] |= hi & 0x3f;
69 }
70
71 static void set_reserved(pd_uuid_t *u, uint8_t reserved) {
72         u->data[8] &= 0x3f;
73         u->data[8] |= (reserved & 0x3) << 6;
74 }
75
76 #if 0
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];
84 }
85 #endif
86
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;
94 }
95
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);
100 }
101
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);
105 }
106
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);
113 }
114
115 static int obtain_global_lock(void *data) {
116         /* no-op */
117         return 0;
118 }
119
120 static int release_global_lock(void *data) {
121         /* no-op */
122         return 0;
123 }
124
125 #define GREGORIAN 122192928000000000ULL
126 static uint64_t current_time(void) {
127         uint64_t now;
128         struct timeval tv;
129         
130         /* TODO is this BSD specific? */
131         gettimeofday(&tv, 0);
132
133         now = (tv.tv_sec * 10000000ULL + tv.tv_usec * 10ULL) + GREGORIAN;
134         return now;
135 }
136
137 static void random_bytes(void *buf, size_t n) {
138         unsigned char *s = buf;
139         int i = 0;
140
141         while (i < n) {
142                 i += pd_uuid_rng_get_bytes(s+i, n-i);
143         }
144 }
145
146 static uint64_t random_mc_mac(struct pd_uuid_state  *s) {
147         uint64_t node = 0;
148
149         if (s && s->random_bytes) {
150                 s->random_bytes(&node, sizeof node, s->rng_state);
151         } else {
152                 random_bytes(&node, sizeof node);
153         }
154         node |= 0x800000000000ULL; /* rfc 4.5 */
155         return node;
156 }
157
158 /*
159  * TODO would probably make more sense to use a destination array
160  * rather than returning an integer
161  */
162 static uint64_t current_node(struct pd_uuid_state *st) {
163         uint64_t node = 0;
164
165 #ifdef __linux__
166         struct ifconf   conf;
167         struct ifreq    *req;
168         struct ifreq    interfaces[4];
169         int s, i;
170         unsigned char *data;
171
172         s = socket(AF_INET, SOCK_DGRAM, 0);
173         if (s != -1) {
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) {
180                                         continue;
181                                 }
182                                 if (req->ifr_flags & IFF_LOOPBACK) {
183                                         continue;
184                                 }
185                                 if (req->ifr_flags & IFF_NOARP) {
186                                         continue;
187                                 }
188                                 if (ioctl(s, SIOCGIFHWADDR, req) == 0) {
189                                         data = (unsigned char *)req->ifr_hwaddr.sa_data;
190                                         node = data[0];
191                                         node = node << 8; node += data[1];
192                                         node = node << 8; node += data[2];
193                                         node = node << 8; node += data[3];
194                                         node = node << 8; node += data[4];
195                                         node = node << 8; node += data[5];
196                                         return node;
197                                 }
198                         }
199                 }
200         }
201 #endif
202
203         /* this is any BSD based system i think */
204 #ifdef __APPLE__
205         struct ifaddrs *addrs;
206         struct ifaddrs *a;
207         struct sockaddr_dl *dl;
208         unsigned char *data;
209         if (getifaddrs(&addrs) == 0) {
210                 for (a = addrs; a; a = a->ifa_next) {
211
212                         if (a->ifa_addr && a->ifa_addr->sa_family == AF_LINK) {
213                                 dl = (struct sockaddr_dl *)a->ifa_addr;
214                                 data = (unsigned char *)(dl->sdl_data + dl->sdl_nlen);
215                                 if (dl->sdl_alen != 6) continue;
216
217                                 node = data[0];
218                                 node = node << 8; node += data[1];
219                                 node = node << 8; node += data[2];
220                                 node = node << 8; node += data[3];
221                                 node = node << 8; node += data[4];
222                                 node = node << 8; node += data[5];
223                                 freeifaddrs(addrs);
224                                 return node;
225                         }
226                 }
227                 freeifaddrs(addrs);
228         }
229 #endif
230
231 #if defined(WIN32) || defined(__CYGWIN__)
232         IP_ADAPTER_INFO addrs[4];
233         DWORD size;
234         int rc;
235         unsigned char *data;
236
237         size = sizeof addrs;
238         rc = GetAdaptersInfo(addrs, &size);
239         if (rc == ERROR_SUCCESS) {
240                 PIP_ADAPTER_INFO info;
241                 for (info = addrs; info; info = info->Next) {
242                         if (info->Type != MIB_IF_TYPE_ETHERNET) {
243                                 continue;
244                         }
245                         data = info->Address;
246                         node = data[0];
247                         node = node << 8; node += data[1];
248                         node = node << 8; node += data[2];
249                         node = node << 8; node += data[3];
250                         node = node << 8; node += data[4];
251                         node = node << 8; node += data[5];
252                 }
253                 return node;
254         }
255 #endif
256
257         /* if we get here, use a random multicast address */
258         node = random_mc_mac(st);
259         return node;
260 }
261
262 static uint16_t random_clock_sequence(struct pd_uuid_state *s) {
263         uint16_t seq;
264
265         if (s && s->random_bytes) {
266                 s->random_bytes(&seq, sizeof seq, s->rng_state);
267         } else {
268                 random_bytes(&seq, sizeof seq);
269         }
270         return seq;
271 }
272
273 static int read_state(struct pd_uuid_state *s) {
274         s->available = 0;
275         s->node = 0LL;
276         s->clock_sequence = 0;
277         s->timestamp = 0LL;
278
279         return 0;
280 }
281
282 static int save_state(struct pd_uuid_state *s) {
283         /* no op */
284         return 0;
285 }
286
287 static unsigned long get_bytes(void *buf, unsigned long n, void *state) {
288         unsigned char *s = buf;
289         int i = 0;
290
291         while (i < n) {
292                 i += pd_uuid_rng_get_bytes(s+i, n-i);
293         }
294         return i;
295 }
296
297 int pd_uuid_init_state(struct pd_uuid_state *s) {
298         if (!s) return 0;
299
300         s->get_lock = obtain_global_lock;
301         s->release_lock = release_global_lock;
302         s->lock_data = 0;
303
304         s->read_state = read_state;
305         s->save_state = save_state;
306
307         s->random_bytes = get_bytes;
308         s->rng_state = 0;
309
310         s->available = 0;
311
312         return 1;
313 }
314
315 int pd_uuid_make_v1(struct pd_uuid_state *s, pd_uuid_t *uuid) {
316         struct pd_uuid_state    ls;
317         uint64_t        now;
318         uint64_t        node;
319         int err;
320
321         if (!s) {
322                 s = &ls;
323                 pd_uuid_init_state(s);
324         }
325
326         if (s->get_lock) {
327                 if ((err = s->get_lock(s->lock_data)) != 0) {
328                         /* TODO set uuid to nil ? */
329                         /* be cute and have an "error" uuid? */
330                         return 0;
331                 }
332         }
333
334         if (s->read_state) {
335                 if ((err = s->read_state(s)) != 0) {
336                         return 0;
337                 }
338         }
339
340         now = current_time();
341         node = current_node(s);
342
343         if (!s->available || s->node != node) {
344                 s->clock_sequence = random_clock_sequence(s);
345         }
346         s->node = node;
347
348         if (s->available && s->timestamp > now) {
349                 s->clock_sequence++;
350         } else {
351                 s->timestamp = now;
352         }
353
354         if (s->save_state) {
355                 if ((err = s->save_state(s)) != 0) {
356                         return 0;
357                 }
358         }
359
360         if (s->release_lock) {
361                 if ((err = s->release_lock(s->lock_data)) != 0) {
362                         /* TODO set uuid to nil ? */
363                         /* be cute and have an "error" uuid? */
364                         return 0;
365                 }
366         }
367
368         format_uuid(uuid, s, 1);
369
370         return 1;
371 }
372
373 int pd_uuid_make_v1mc(struct pd_uuid_state *ps, pd_uuid_t *uuid) {
374         struct pd_uuid_state    s;
375         uint64_t        now;
376         uint64_t        node;
377
378         obtain_global_lock(0);
379         read_state(&s);
380         now = current_time();
381         node = random_mc_mac(&s);
382         if (!s.available) {
383                 s.clock_sequence = random_clock_sequence(&s);
384         }
385
386         if (s.available && s.timestamp > now) {
387                 s.clock_sequence++;
388         } else {
389                 s.timestamp = now;
390         }
391
392         save_state(&s);
393         release_global_lock(0);
394         s.node = node;
395
396         format_uuid(uuid, &s, 1);
397
398         return 1;
399 }
400
401 int pd_uuid_make_v4(struct pd_uuid_state *s, pd_uuid_t *uuid) {
402         random_bytes(uuid, sizeof *uuid);
403         set_version(uuid, 4);
404         set_reserved(uuid, 0x2);
405         return 1;
406 }
407
408 int pd_set_uuid_hash(struct pd_uuid *s, void *hash, int version) {
409         int i;
410         unsigned char *h = hash;
411
412         for (i=0;i<16;i++) {
413                 s->data[i] = h[i];
414         }
415         set_version(s, version);
416         set_reserved(s, 0x2);
417         return 1;
418 }
419
420 int pd_uuid_make_v3(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
421         hash_state hs;
422         unsigned char hash[16];
423
424         md5_init(&hs);
425         md5_process(&hs, ns->data, 16);
426         md5_process(&hs, data, len);
427         md5_done(&hs, hash);
428         pd_set_uuid_hash(uuid, hash, 3);
429         return 1;
430 }
431
432 int pd_uuid_make_v5(struct pd_uuid_state *s, pd_uuid_t *uuid, pd_uuid_t *ns, void *data, int len) {
433         hash_state hs;
434         unsigned char hash[20];
435
436         sha1_init(&hs);
437         sha1_process(&hs, ns->data, sizeof *ns);
438         sha1_process(&hs, data, len);
439         sha1_done(&hs, hash);
440         pd_set_uuid_hash(uuid, hash, 5);
441         return 1;
442 }
443
444 int pd_uuid_set_string(pd_uuid_t *uuid, char *s) {
445         unsigned int byte;
446         int i;
447
448         for (i=0;i<16;i++) {
449                 if (*s == 0) return 0;
450                 if (*s == '-') s++;
451
452                 if (sscanf(s, "%02x", &byte) != 1) {
453                         return 0;
454                 }
455                 s += 2;
456                 uuid->data[i] = byte & 0xff;
457         }
458         return 1;
459 }