1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@defgroup su_uniqueid GloballyUniqueIDs
26  *
27  * Globally unique IDs and random integers.
28  *
29  * GloballyUniqueID or #su_guid_t is a 128-bit identifier based on current
30  * time and MAC address of the node generating the ID. A new ID is generated
31  * each time su_guid_generate() is called. Please note that such IDs are @b
32  * not unique if multiple processes are run on the same node.
33  *
34  * Use su_guid_sprintf() to convert #su_guid_t to printable format.
35  *
36  * The random integers can be generated with functions
37  * - su_randint(),
38  * - su_randmem(), or
39  * - su_random().
40  */
41 
42 /**@ingroup su_uniqueid
43  *
44  * @CFILE su_uniqueid.c Construct a GloballyUniqueID as per H.225.0 v2.
45  *
46  * @author Pekka Pessi <pessi@research.nokia.com>
47  *
48  * @date Created: Tue Apr 15 06:31:41 1997 pessi
49  */
50 
51 #include "config.h"
52 
53 #if defined(_WIN32)
54 int _getpid(void);
55 #define getpid _getpid
56 #endif
57 
58 #include <string.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <time.h>
62 
63 #if HAVE_SYS_TIME_H
64 #include <sys/time.h>
65 #endif
66 
67 #if HAVE_UNISTD_H
68 #include <sys/types.h>
69 #include <unistd.h>
70 #endif
71 
72 #include "sofia-sip/su.h"
73 #include "sofia-sip/su_time.h"
74 #include "sofia-sip/su_uniqueid.h"
75 
76 /* For random number generator */
77 static FILE *urandom;
78 
79 union state {
80   uint64_t u64;
81 };
82 
83 #if SU_HAVE_PTHREADS
84 
85 #include <pthread.h>
86 
87 #if __sun
88 #undef PTHREAD_ONCE_INIT
89 #define PTHREAD_ONCE_INIT {{ 0, 0, 0, PTHREAD_ONCE_NOTDONE }}
90 #endif
91 
92 static pthread_once_t once = PTHREAD_ONCE_INIT;
93 static int done_once = 0;
94 static pthread_key_t state_key;
95 
96 static void
init_once(void)97 init_once(void)
98 {
99   if (done_once)
100     return;
101 
102   pthread_key_create(&state_key, free);
103 #if HAVE_DEV_URANDOM
104   urandom = fopen("/dev/urandom", "rb");
105 #endif	/* HAVE_DEV_URANDOM */
106   done_once = 1;
107 }
108 
109 #else
110 static int initialized;
111 #endif
112 
113 static union state *
get_state(void)114 get_state(void)
115 {
116   static union state state0[1];
117   union state *retval;
118 
119 #if SU_HAVE_PTHREADS
120 
121   pthread_once(&once, init_once);
122 
123   if (urandom)
124     return NULL;
125 
126   retval = pthread_getspecific(state_key);
127   if (retval) {
128     return retval;
129   }
130 
131   retval = calloc(1, sizeof *retval);
132   if (retval != NULL)
133     pthread_setspecific(state_key, retval);
134   else
135     retval = state0;
136 
137 #else  /* !SU_HAVE_PTHREADS */
138 
139   if (urandom == NULL) {
140 #if HAVE_DEV_URANDOM
141     urandom = fopen("/dev/urandom", "rb");
142 #endif	/* HAVE_DEV_URANDOM */
143   }
144 
145   if (urandom)
146     return NULL;
147 
148   retval = state0;
149 
150   if (initialized)
151     return retval;
152 #endif
153 
154   {
155     uint32_t seed[32];
156     int i;
157     union {
158       uint32_t u32;
159       pthread_t tid;
160     } tid32 = { 0 };
161 
162     tid32.tid = pthread_self();
163 
164     memset(seed, 0, sizeof seed); /* Make valgrind happy */
165 
166     for (i = 0; i < 32; i += 2) {
167 #if HAVE_CLOCK_GETTIME
168       struct timespec ts;
169       (void)clock_gettime(CLOCK_REALTIME, &ts);
170       seed[i] ^= ts.tv_sec; seed[i + 1] ^= ts.tv_nsec;
171 #else
172       su_time_t now;
173       su_time(&now);
174       seed[i] ^= now.tv_sec; seed[i + 1] ^= now.tv_sec;
175 #endif
176     }
177 
178     seed[0] ^= getuid();
179     seed[1] ^= getpid();
180     seed[2] ^= tid32.u32;
181     seed[3] ^= (uint32_t)(intptr_t)retval;
182 
183     for (i = 0; i < 32; i+= 4) {
184       retval->u64 += ((uint64_t)seed[i] << 32) | seed[i + 1];
185       retval->u64 *= ((uint64_t)seed[i + 3] << 32) | seed[i + 2];
186     }
187 
188     retval->u64 += (uint64_t)su_nanotime(NULL);
189   }
190 
191   return retval;
192 }
193 
194 #if !defined(WIN32) && !defined(WIN64)
195 void sofia_su_uniqueid_destructor(void)
196   __attribute__((destructor));
197 #endif
198 
199 void
sofia_su_uniqueid_destructor(void)200 sofia_su_uniqueid_destructor(void)
201 {
202 #if HAVE_DEV_URANDOM
203 	if (urandom) {
204 		fclose(urandom);
205 		urandom=NULL;
206 	}
207 #endif	/* HAVE_DEV_URANDOM */
208 
209 #if SU_HAVE_PTHREADS
210   if (done_once) {
211     pthread_key_delete(state_key);
212     done_once = 0;
213   }
214 #endif
215 }
216 
217 #if HAVE_GETIFADDRS
218 #include <ifaddrs.h>
219 #if HAVE_NETPACKET_PACKET_H
220 #define HAVE_SOCKADDR_LL 1
221 #include <netpacket/packet.h>
222 #include <net/if_arp.h>
223 #endif
224 #endif
225 
226 #define SIZEOF_NODE 6
227 static
init_node(uint8_t node[SIZEOF_NODE])228 void init_node(uint8_t node[SIZEOF_NODE])
229 {
230 #if HAVE_GETIFADDRS && HAVE_SOCKADDR_LL
231   struct ifaddrs *ifa, *results;
232 
233   if (getifaddrs(&results) == 0) {
234     for (ifa = results; ifa; ifa = ifa->ifa_next) {
235 #if HAVE_SOCKADDR_LL
236       struct sockaddr_ll const *sll = (void *)ifa->ifa_addr;
237 
238       if (sll == NULL || sll->sll_family != AF_PACKET)
239 	continue;
240       switch (sll->sll_hatype) {
241       case ARPHRD_ETHER:
242       case ARPHRD_EETHER:
243       case ARPHRD_IEEE802:
244 	break;
245       default:
246 	continue;
247       }
248 
249       memcpy(node, sll->sll_addr, SIZEOF_NODE);
250 
251       break;
252 #endif
253     }
254 
255     freeifaddrs(results);
256 
257     if (ifa)
258       return;			/* Success */
259   }
260 #endif
261 
262   su_randmem(node, SIZEOF_NODE);
263   node[0] |= 1;			/* "multicast" address */
264 }
265 
266 static unsigned char node[SIZEOF_NODE];
267 
su_node_identifier(void * address,size_t addrlen)268 size_t su_node_identifier(void *address, size_t addrlen)
269 {
270   if (addrlen > SIZEOF_NODE)
271     addrlen = SIZEOF_NODE;
272 
273   su_guid_generate(NULL);
274   memcpy(address, node, addrlen);
275 
276   return addrlen;
277 }
278 
su_guid_generate(su_guid_t * v)279 void su_guid_generate(su_guid_t *v)
280 {
281   /* Constants */
282   static const unsigned version = 1;	/* Current version */
283   static const unsigned reserved = 128;	/* DCE variant */
284 #define granularity (10000000UL)
285   static const uint64_t mask60 = SU_U64_C(0xfffFFFFffffFFFF);
286 #define MAGIC (16384)
287 
288   /* 100-nanosecond intervals between 15 October 1582 and 1 January 1900 */
289   static const uint64_t ntp_epoch =
290     (uint64_t)(141427) * (24 * 60 * 60L) * granularity;
291 
292   static uint64_t timestamp0 = 0;
293   static unsigned clock_sequence = MAGIC;
294 
295 #if SU_HAVE_PTHREADS
296   static pthread_mutex_t update = PTHREAD_MUTEX_INITIALIZER;
297 #endif
298 
299   uint64_t tl = su_ntp_now();
300   uint64_t hi = su_ntp_hi(tl), lo = su_ntp_lo(tl);
301 
302   lo *= granularity;
303   hi *= granularity;
304 
305   tl = hi + (lo >> 32) + ntp_epoch;
306 
307 #ifdef TESTING
308   printf("timestamp %08x-%08x\n", (unsigned)(tl >>32), (unsigned)tl);
309 #endif
310 
311   tl &= mask60;
312   if (tl == 0) tl++;
313 
314 #if SU_HAVE_PTHREADS
315   pthread_mutex_lock(&update);
316 #endif
317 
318   if (timestamp0 == 0) {
319     clock_sequence = su_randint(0, MAGIC - 1);
320     init_node(node);
321   }
322   else if (tl <= timestamp0) {
323     clock_sequence = (clock_sequence + 1) & (MAGIC - 1);
324   }
325 
326   timestamp0 = tl;
327 
328 #if SU_HAVE_PTHREADS
329   pthread_mutex_unlock(&update);
330 #endif
331 
332   if (v) {
333     v->s.time_high_and_version =
334       htons((unsigned short)(((tl >> 48) & 0x0fff) | (version << 12)));
335     v->s.time_mid = htons((unsigned short)((tl >> 32) & 0xffff));
336     v->s.time_low = htonl((unsigned long)(tl & 0xffffffffUL));
337     v->s.clock_seq_low = clock_sequence & 0xff;
338     v->s.clock_seq_hi_and_reserved = (clock_sequence >> 8) | reserved;
339     memcpy(v->s.node, node, sizeof(v->s.node));
340   }
341 }
342 
343 /*
344  * Human-readable form of GloballyUniqueID
345  */
su_guid_sprintf(char * buf,size_t len,su_guid_t const * v)346 isize_t su_guid_sprintf(char* buf, size_t len, su_guid_t const *v)
347 {
348   char mybuf[su_guid_strlen + 1];
349   sprintf(mybuf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
350 	  (unsigned long)ntohl(v->s.time_low),
351 	  ntohs(v->s.time_mid),
352 	  ntohs(v->s.time_high_and_version),
353 	  v->s.clock_seq_low,
354 	  v->s.clock_seq_hi_and_reserved,
355 	  v->s.node[0], v->s.node[1], v->s.node[2],
356 	  v->s.node[3], v->s.node[4], v->s.node[5]);
357   memcpy(buf, mybuf, len > sizeof(mybuf) ? sizeof(mybuf) : len);
358   return su_guid_strlen;
359 }
360 
su_random64(void)361 uint64_t su_random64(void)
362 {
363   union state *state = get_state();
364 
365   if (state) {
366     /* Simple rand64 from AoCP */
367     return state->u64 = state->u64 * 0X5851F42D4C957F2DULL + 1ULL;
368   }
369   else {
370     uint64_t retval;
371     size_t len = fread(&retval, 1, sizeof retval, urandom); (void)len;
372     return retval;
373   }
374 }
375 
su_randmem(void * mem,size_t siz)376 void *su_randmem(void *mem, size_t siz)
377 {
378   union state *state = get_state();
379 
380   if (state) {
381     size_t i;
382     uint64_t r64;
383     uint32_t r32;
384 
385     for (i = 0; i < siz; i += 4) {
386       /* Simple rand64 from AoCP */
387       state->u64 = r64 = state->u64 * 0X5851F42D4C957F2DULL + 1ULL;
388       r32 = (uint32_t) (r64 >> 32) ^ (uint32_t)r64;
389       if (siz - i >= 4)
390 	memcpy((char *)mem + i, &r32, 4);
391       else
392 	memcpy((char *)mem + i, &r32, siz - i);
393     }
394   }
395   else {
396     size_t len = fread(mem, 1, siz, urandom); (void)len;
397   }
398 
399   return mem;
400 }
401 
402 /**
403  * Generate random integer in range [lb, ub] (inclusive)
404  */
su_randint(int lb,int ub)405 int su_randint(int lb, int ub)
406 {
407   uint64_t rnd;
408   unsigned modulo = (unsigned)(ub - lb + 1);
409 
410   if (modulo != 0) {
411     do {
412       rnd = su_random64();
413     } while (rnd / modulo == 0xffffFFFFffffFFFFULL / modulo);
414 
415     rnd %= modulo;
416   }
417   else {
418     rnd = su_random64();
419   }
420 
421   return (int)rnd + lb;
422 }
423 
424 /** Get random 32-bit unsigned number.
425  *
426  */
su_random(void)427 uint32_t su_random(void)
428 {
429   return (uint32_t)(su_random64() >> 16);
430 }
431