su_uniqueid.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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. /**@defgroup su_uniqueid GloballyUniqueIDs
  25. *
  26. * Globally unique IDs and random integers.
  27. *
  28. * GloballyUniqueID or #su_guid_t is a 128-bit identifier based on current
  29. * time and MAC address of the node generating the ID. A new ID is generated
  30. * each time su_guid_generate() is called. Please note that such IDs are @b
  31. * not unique if multiple processes are run on the same node.
  32. *
  33. * Use su_guid_sprintf() to convert #su_guid_t to printable format.
  34. *
  35. * The random integers can be generated with functions
  36. * - su_randint(),
  37. * - su_randmem(), or
  38. * - su_random().
  39. */
  40. /**@ingroup su_uniqueid
  41. *
  42. * @CFILE su_uniqueid.c Construct a GloballyUniqueID as per H.225.0 v2.
  43. *
  44. * @author Pekka Pessi <pessi@research.nokia.com>
  45. *
  46. * @date Created: Tue Apr 15 06:31:41 1997 pessi
  47. */
  48. #include "config.h"
  49. #if defined(_WIN32)
  50. int _getpid(void);
  51. #define getpid _getpid
  52. #endif
  53. #include <string.h>
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <time.h>
  57. #if HAVE_SYS_TIME_H
  58. #include <sys/time.h>
  59. #endif
  60. #if HAVE_UNISTD_H
  61. #include <sys/types.h>
  62. #include <unistd.h>
  63. #endif
  64. #include "sofia-sip/su.h"
  65. #include "sofia-sip/su_time.h"
  66. #include "sofia-sip/su_uniqueid.h"
  67. /* For random number generator */
  68. static FILE *urandom;
  69. union state {
  70. uint64_t u64;
  71. };
  72. #if SU_HAVE_PTHREADS
  73. #include <pthread.h>
  74. #if __sun
  75. #undef PTHREAD_ONCE_INIT
  76. #define PTHREAD_ONCE_INIT {{ 0, 0, 0, PTHREAD_ONCE_NOTDONE }}
  77. #endif
  78. static pthread_once_t once = PTHREAD_ONCE_INIT;
  79. static int done_once = 0;
  80. static pthread_key_t state_key;
  81. static void
  82. init_once(void)
  83. {
  84. if (done_once)
  85. return;
  86. pthread_key_create(&state_key, free);
  87. #if HAVE_DEV_URANDOM
  88. urandom = fopen("/dev/urandom", "rb");
  89. #endif /* HAVE_DEV_URANDOM */
  90. done_once = 1;
  91. }
  92. #else
  93. static int initialized;
  94. #endif
  95. static union state *
  96. get_state(void)
  97. {
  98. static union state state0[1];
  99. union state *retval;
  100. #if SU_HAVE_PTHREADS
  101. pthread_once(&once, init_once);
  102. if (urandom)
  103. return NULL;
  104. retval = pthread_getspecific(state_key);
  105. if (retval) {
  106. return retval;
  107. }
  108. retval = calloc(1, sizeof *retval);
  109. if (retval != NULL)
  110. pthread_setspecific(state_key, retval);
  111. else
  112. retval = state0;
  113. #else /* !SU_HAVE_PTHREADS */
  114. if (urandom == NULL) {
  115. #if HAVE_DEV_URANDOM
  116. urandom = fopen("/dev/urandom", "rb");
  117. #endif /* HAVE_DEV_URANDOM */
  118. }
  119. if (urandom)
  120. return NULL;
  121. retval = state0;
  122. if (initialized)
  123. return retval;
  124. #endif
  125. {
  126. uint32_t seed[32];
  127. int i;
  128. union {
  129. uint32_t u32;
  130. pthread_t tid;
  131. } tid32 = { 0 };
  132. tid32.tid = pthread_self();
  133. memset(seed, 0, sizeof seed); /* Make valgrind happy */
  134. for (i = 0; i < 32; i += 2) {
  135. #if HAVE_CLOCK_GETTIME
  136. struct timespec ts;
  137. (void)clock_gettime(CLOCK_REALTIME, &ts);
  138. seed[i] ^= ts.tv_sec; seed[i + 1] ^= ts.tv_nsec;
  139. #else
  140. su_time_t now;
  141. su_time(&now);
  142. seed[i] ^= now.tv_sec; seed[i + 1] ^= now.tv_sec;
  143. #endif
  144. }
  145. seed[0] ^= getuid();
  146. seed[1] ^= getpid();
  147. seed[2] ^= tid32.u32;
  148. seed[3] ^= (uint32_t)(intptr_t)retval;
  149. for (i = 0; i < 32; i+= 4) {
  150. retval->u64 += ((uint64_t)seed[i] << 32) | seed[i + 1];
  151. retval->u64 *= ((uint64_t)seed[i + 3] << 32) | seed[i + 2];
  152. }
  153. retval->u64 += (uint64_t)su_nanotime(NULL);
  154. }
  155. return retval;
  156. }
  157. #if !defined(WIN32) && !defined(WIN64)
  158. void sofia_su_uniqueid_destructor(void)
  159. __attribute__((destructor));
  160. #endif
  161. void
  162. sofia_su_uniqueid_destructor(void)
  163. {
  164. #if HAVE_DEV_URANDOM
  165. if (urandom) {
  166. fclose(urandom);
  167. urandom=NULL;
  168. }
  169. #endif /* HAVE_DEV_URANDOM */
  170. #if SU_HAVE_PTHREADS
  171. if (done_once) {
  172. pthread_key_delete(state_key);
  173. done_once = 0;
  174. }
  175. #endif
  176. }
  177. #if HAVE_GETIFADDRS
  178. #include <ifaddrs.h>
  179. #if HAVE_NETPACKET_PACKET_H
  180. #define HAVE_SOCKADDR_LL 1
  181. #include <netpacket/packet.h>
  182. #include <net/if_arp.h>
  183. #endif
  184. #endif
  185. #define SIZEOF_NODE 6
  186. static
  187. void init_node(uint8_t node[SIZEOF_NODE])
  188. {
  189. #if HAVE_GETIFADDRS && HAVE_SOCKADDR_LL
  190. struct ifaddrs *ifa, *results;
  191. if (getifaddrs(&results) == 0) {
  192. for (ifa = results; ifa; ifa = ifa->ifa_next) {
  193. #if HAVE_SOCKADDR_LL
  194. struct sockaddr_ll const *sll = (void *)ifa->ifa_addr;
  195. if (sll == NULL || sll->sll_family != AF_PACKET)
  196. continue;
  197. switch (sll->sll_hatype) {
  198. case ARPHRD_ETHER:
  199. case ARPHRD_EETHER:
  200. case ARPHRD_IEEE802:
  201. break;
  202. default:
  203. continue;
  204. }
  205. memcpy(node, sll->sll_addr, SIZEOF_NODE);
  206. break;
  207. #endif
  208. }
  209. freeifaddrs(results);
  210. if (ifa)
  211. return; /* Success */
  212. }
  213. #endif
  214. su_randmem(node, SIZEOF_NODE);
  215. node[0] |= 1; /* "multicast" address */
  216. }
  217. static unsigned char node[SIZEOF_NODE];
  218. size_t su_node_identifier(void *address, size_t addrlen)
  219. {
  220. if (addrlen > SIZEOF_NODE)
  221. addrlen = SIZEOF_NODE;
  222. su_guid_generate(NULL);
  223. memcpy(address, node, addrlen);
  224. return addrlen;
  225. }
  226. void su_guid_generate(su_guid_t *v)
  227. {
  228. /* Constants */
  229. static const unsigned version = 1; /* Current version */
  230. static const unsigned reserved = 128; /* DCE variant */
  231. #define granularity (10000000UL)
  232. static const uint64_t mask60 = SU_U64_C(0xfffFFFFffffFFFF);
  233. #define MAGIC (16384)
  234. /* 100-nanosecond intervals between 15 October 1582 and 1 January 1900 */
  235. static const uint64_t ntp_epoch =
  236. (uint64_t)(141427) * (24 * 60 * 60L) * granularity;
  237. static uint64_t timestamp0 = 0;
  238. static unsigned clock_sequence = MAGIC;
  239. #if SU_HAVE_PTHREADS
  240. static pthread_mutex_t update = PTHREAD_MUTEX_INITIALIZER;
  241. #endif
  242. uint64_t tl = su_ntp_now();
  243. uint64_t hi = su_ntp_hi(tl), lo = su_ntp_lo(tl);
  244. lo *= granularity;
  245. hi *= granularity;
  246. tl = hi + (lo >> 32) + ntp_epoch;
  247. #ifdef TESTING
  248. printf("timestamp %08x-%08x\n", (unsigned)(tl >>32), (unsigned)tl);
  249. #endif
  250. tl &= mask60;
  251. if (tl == 0) tl++;
  252. #if SU_HAVE_PTHREADS
  253. pthread_mutex_lock(&update);
  254. #endif
  255. if (timestamp0 == 0) {
  256. clock_sequence = su_randint(0, MAGIC - 1);
  257. init_node(node);
  258. }
  259. else if (tl <= timestamp0) {
  260. clock_sequence = (clock_sequence + 1) & (MAGIC - 1);
  261. }
  262. timestamp0 = tl;
  263. #if SU_HAVE_PTHREADS
  264. pthread_mutex_unlock(&update);
  265. #endif
  266. if (v) {
  267. v->s.time_high_and_version =
  268. htons((unsigned short)(((tl >> 48) & 0x0fff) | (version << 12)));
  269. v->s.time_mid = htons((unsigned short)((tl >> 32) & 0xffff));
  270. v->s.time_low = htonl((unsigned long)(tl & 0xffffffffUL));
  271. v->s.clock_seq_low = clock_sequence & 0xff;
  272. v->s.clock_seq_hi_and_reserved = (clock_sequence >> 8) | reserved;
  273. memcpy(v->s.node, node, sizeof(v->s.node));
  274. }
  275. }
  276. /*
  277. * Human-readable form of GloballyUniqueID
  278. */
  279. isize_t su_guid_sprintf(char* buf, size_t len, su_guid_t const *v)
  280. {
  281. char mybuf[su_guid_strlen + 1];
  282. sprintf(mybuf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  283. (unsigned long)ntohl(v->s.time_low),
  284. ntohs(v->s.time_mid),
  285. ntohs(v->s.time_high_and_version),
  286. v->s.clock_seq_low,
  287. v->s.clock_seq_hi_and_reserved,
  288. v->s.node[0], v->s.node[1], v->s.node[2],
  289. v->s.node[3], v->s.node[4], v->s.node[5]);
  290. memcpy(buf, mybuf, len > sizeof(mybuf) ? sizeof(mybuf) : len);
  291. return su_guid_strlen;
  292. }
  293. uint64_t su_random64(void)
  294. {
  295. union state *state = get_state();
  296. if (state) {
  297. /* Simple rand64 from AoCP */
  298. return state->u64 = state->u64 * 0X5851F42D4C957F2DULL + 1ULL;
  299. }
  300. else {
  301. uint64_t retval;
  302. size_t len = fread(&retval, 1, sizeof retval, urandom); (void)len;
  303. return retval;
  304. }
  305. }
  306. void *su_randmem(void *mem, size_t siz)
  307. {
  308. union state *state = get_state();
  309. if (state) {
  310. size_t i;
  311. uint64_t r64;
  312. uint32_t r32;
  313. for (i = 0; i < siz; i += 4) {
  314. /* Simple rand64 from AoCP */
  315. state->u64 = r64 = state->u64 * 0X5851F42D4C957F2DULL + 1ULL;
  316. r32 = (uint32_t) (r64 >> 32) ^ (uint32_t)r64;
  317. if (siz - i >= 4)
  318. memcpy((char *)mem + i, &r32, 4);
  319. else
  320. memcpy((char *)mem + i, &r32, siz - i);
  321. }
  322. }
  323. else {
  324. size_t len = fread(mem, 1, siz, urandom); (void)len;
  325. }
  326. return mem;
  327. }
  328. /**
  329. * Generate random integer in range [lb, ub] (inclusive)
  330. */
  331. int su_randint(int lb, int ub)
  332. {
  333. uint64_t rnd;
  334. unsigned modulo = (unsigned)(ub - lb + 1);
  335. if (modulo != 0) {
  336. do {
  337. rnd = su_random64();
  338. } while (rnd / modulo == 0xffffFFFFffffFFFFULL / modulo);
  339. rnd %= modulo;
  340. }
  341. else {
  342. rnd = su_random64();
  343. }
  344. return (int)rnd + lb;
  345. }
  346. /** Get random 32-bit unsigned number.
  347. *
  348. */
  349. uint32_t su_random(void)
  350. {
  351. return (uint32_t)(su_random64() >> 16);
  352. }