PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/uClinux-dist/lib/libupnp/upnp/src/uuid/uuid.c

https://bitbucket.org/__wp__/mb-linux-msli
C | 382 lines | 200 code | 47 blank | 135 comment | 17 complexity | 15f537cbf04ef6bec04ed073de82c74e MD5 | raw file
Possible License(s): AGPL-3.0, GPL-2.0, LGPL-2.0, MPL-2.0, ISC, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, 0BSD, CC-BY-SA-3.0, GPL-3.0, LGPL-3.0, AGPL-1.0, Unlicense
  1. /*
  2. ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
  3. ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
  4. ** Digital Equipment Corporation, Maynard, Mass.
  5. ** Copyright (c) 1998 Microsoft.
  6. ** To anyone who acknowledges that this file is provided "AS IS"
  7. ** without any express or implied warranty: permission to use, copy,
  8. ** modify, and distribute this file for any purpose is hereby
  9. ** granted without fee, provided that the above copyright notices and
  10. ** this notice appears in all source code copies, and that none of
  11. ** the names of Open Software Foundation, Inc., Hewlett-Packard
  12. ** Company, or Digital Equipment Corporation be used in advertising
  13. ** or publicity pertaining to distribution of the software without
  14. ** specific, written prior permission. Neither Open Software
  15. ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
  16. ** Corporation makes any representations about the suitability of
  17. ** this software for any purpose.
  18. */
  19. #include <string.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <time.h>
  23. #include <netinet/in.h>
  24. #include "sysdep.h"
  25. #include "uuid.h"
  26. /*
  27. various forward declarations
  28. */
  29. static int read_state( unsigned16 * clockseq,
  30. uuid_time_t * timestamp,
  31. uuid_node_t * node );
  32. static void write_state( unsigned16 clockseq,
  33. uuid_time_t timestamp,
  34. uuid_node_t node );
  35. static void format_uuid_v1( uuid_upnp * uid,
  36. unsigned16 clockseq,
  37. uuid_time_t timestamp,
  38. uuid_node_t node );
  39. static void format_uuid_v3( uuid_upnp * uid,
  40. unsigned char hash[16] );
  41. static void get_current_time( uuid_time_t * timestamp );
  42. static unsigned16 true_random( void );
  43. /*-----------------------------------------------------------------------------*/
  44. /*
  45. uuid_create -- generator a UUID
  46. */
  47. int
  48. uuid_create( uuid_upnp * uid )
  49. {
  50. uuid_time_t timestamp,
  51. last_time;
  52. unsigned16 clockseq;
  53. uuid_node_t node;
  54. uuid_node_t last_node;
  55. int f;
  56. /*
  57. acquire system wide lock so we're alone
  58. */
  59. UUIDLock( );
  60. /*
  61. get current time
  62. */
  63. get_current_time( &timestamp );
  64. /*
  65. get node ID
  66. */
  67. get_ieee_node_identifier( &node );
  68. /*
  69. get saved state from NV storage
  70. */
  71. f = read_state( &clockseq, &last_time, &last_node );
  72. /*
  73. if no NV state, or if clock went backwards, or node ID changed
  74. (e.g., net card swap) change clockseq
  75. */
  76. if( !f || memcmp( &node, &last_node, sizeof( uuid_node_t ) ) )
  77. clockseq = true_random( );
  78. else if( timestamp < last_time )
  79. clockseq++;
  80. /*
  81. stuff fields into the UUID
  82. */
  83. format_uuid_v1( uid, clockseq, timestamp, node );
  84. /*
  85. save the state for next time
  86. */
  87. write_state( clockseq, timestamp, node );
  88. UUIDUnlock( );
  89. return ( 1 );
  90. };
  91. /*-----------------------------------------------------------------------------*/
  92. void
  93. uuid_unpack( uuid_upnp * u,
  94. char *out )
  95. {
  96. sprintf( out,
  97. "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
  98. ( unsigned int )u->time_low, u->time_mid,
  99. u->time_hi_and_version, u->clock_seq_hi_and_reserved,
  100. u->clock_seq_low, u->node[0], u->node[1], u->node[2],
  101. u->node[3], u->node[4], u->node[5] );
  102. *( out + 36 ) = '\0';
  103. };
  104. /*-----------------------------------------------------------------------------*/
  105. /*
  106. format_uuid_v1 -- make a UUID from the timestamp, clockseq,
  107. and node ID
  108. */
  109. void
  110. format_uuid_v1( uuid_upnp * uid,
  111. unsigned16 clock_seq,
  112. uuid_time_t timestamp,
  113. uuid_node_t node )
  114. {
  115. /*
  116. Construct a version 1 uuid with the information we've gathered
  117. * plus a few constants.
  118. */
  119. uid->time_low = ( unsigned long )( timestamp & 0xFFFFFFFF );
  120. uid->time_mid = ( unsigned short )( ( timestamp >> 32 ) & 0xFFFF );
  121. uid->time_hi_and_version = ( unsigned short )( ( timestamp >> 48 ) &
  122. 0x0FFF );
  123. uid->time_hi_and_version |= ( 1 << 12 );
  124. uid->clock_seq_low = clock_seq & 0xFF;
  125. uid->clock_seq_hi_and_reserved = ( clock_seq & 0x3F00 ) >> 8;
  126. uid->clock_seq_hi_and_reserved |= 0x80;
  127. memcpy( &uid->node, &node, sizeof uid->node );
  128. };
  129. /*-----------------------------------------------------------------------------*/
  130. /*
  131. data type for UUID generator persistent state
  132. */
  133. typedef struct {
  134. uuid_time_t ts; /* saved timestamp */
  135. uuid_node_t node; /* saved node ID */
  136. unsigned16 cs; /* saved clock sequence */
  137. } uuid_state;
  138. static uuid_state st;
  139. static int stateInited = 0;
  140. /*-----------------------------------------------------------------------------*/
  141. /*
  142. read_state -- read UUID generator state from non-volatile store
  143. */
  144. int
  145. read_state( unsigned16 * clockseq,
  146. uuid_time_t * timestamp,
  147. uuid_node_t * node )
  148. {
  149. if( !stateInited ) {
  150. return 0;
  151. };
  152. *clockseq = st.cs;
  153. *timestamp = st.ts;
  154. *node = st.node;
  155. return 1;
  156. };
  157. /*-----------------------------------------------------------------------------*/
  158. /*
  159. write_state -- save UUID generator state back to non-volatile
  160. storage
  161. */
  162. void
  163. write_state( unsigned16 clockseq,
  164. uuid_time_t timestamp,
  165. uuid_node_t node )
  166. {
  167. static uuid_time_t next_save;
  168. if( !stateInited ) {
  169. next_save = timestamp;
  170. stateInited = 1;
  171. };
  172. /*
  173. always save state to volatile shared state
  174. */
  175. st.cs = clockseq;
  176. st.ts = timestamp;
  177. st.node = node;
  178. if( timestamp >= next_save ) {
  179. /*
  180. schedule next save for 10 seconds from now
  181. */
  182. next_save = timestamp + ( 10 * 10 * 1000 * 1000 );
  183. };
  184. };
  185. /*-----------------------------------------------------------------------------*/
  186. /*
  187. get-current_time -- get time as 60 bit 100ns ticks since whenever.
  188. Compensate for the fact that real clock resolution is
  189. less than 100ns.
  190. */
  191. void
  192. get_current_time( uuid_time_t * timestamp )
  193. {
  194. uuid_time_t time_now;
  195. static uuid_time_t time_last;
  196. static unsigned16 uuids_this_tick;
  197. static int inited = 0;
  198. if( !inited ) {
  199. get_system_time( &time_now );
  200. uuids_this_tick = UUIDS_PER_TICK;
  201. inited = 1;
  202. };
  203. while( 1 ) {
  204. get_system_time( &time_now );
  205. /*
  206. if clock reading changed since last UUID generated...
  207. */
  208. if( time_last != time_now ) {
  209. /*
  210. reset count of uuids gen'd with this clock reading
  211. */
  212. uuids_this_tick = 0;
  213. break;
  214. };
  215. if( uuids_this_tick < UUIDS_PER_TICK ) {
  216. uuids_this_tick++;
  217. break;
  218. };
  219. /*
  220. going too fast for our clock; spin
  221. */
  222. };
  223. /*
  224. add the count of uuids to low order bits of the clock reading
  225. */
  226. *timestamp = time_now + uuids_this_tick;
  227. time_last = *timestamp;
  228. };
  229. /*-----------------------------------------------------------------------------*/
  230. /*
  231. true_random -- generate a crypto-quality random number.
  232. This sample doesn't do that.
  233. */
  234. static unsigned16
  235. true_random( void )
  236. {
  237. static int inited = 0;
  238. uuid_time_t time_now;
  239. if( !inited ) {
  240. get_system_time( &time_now );
  241. time_now = time_now / UUIDS_PER_TICK;
  242. srand( ( unsigned int )( ( ( time_now >> 32 ) ^ time_now ) &
  243. 0xffffffff ) );
  244. inited = 1;
  245. };
  246. return ( rand( ) );
  247. }
  248. /*-----------------------------------------------------------------------------*/
  249. /*
  250. uuid_create_from_name -- create a UUID using a "name" from a "name space"
  251. */
  252. void
  253. uuid_create_from_name( uuid_upnp * uid, /* resulting UUID */
  254. uuid_upnp nsid, /* UUID to serve as context, so identical
  255. names from different name spaces generate
  256. different UUIDs */
  257. void *name, /* the name from which to generate a UUID */
  258. int namelen /* the length of the name */
  259. )
  260. {
  261. MD5_CTX c;
  262. unsigned char hash[16];
  263. uuid_upnp net_nsid; /* context UUID in network byte order */
  264. /*
  265. put name space ID in network byte order so it hashes the same
  266. no matter what endian machine we're on
  267. */
  268. net_nsid = nsid;
  269. htonl( net_nsid.time_low );
  270. htons( net_nsid.time_mid );
  271. htons( net_nsid.time_hi_and_version );
  272. MD5Init( &c );
  273. MD5Update( &c, &net_nsid, sizeof( uuid_upnp ) );
  274. MD5Update( &c, name, namelen );
  275. MD5Final( hash, &c );
  276. /*
  277. the hash is in network byte order at this point
  278. */
  279. format_uuid_v3( uid, hash );
  280. };
  281. /*-----------------------------------------------------------------------------*/
  282. /*
  283. format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number
  284. */
  285. void
  286. format_uuid_v3( uuid_upnp * uid,
  287. unsigned char hash[16] )
  288. {
  289. /*
  290. Construct a version 3 uuid with the (pseudo-)random number
  291. * plus a few constants.
  292. */
  293. memcpy( uid, hash, sizeof( uuid_upnp ) );
  294. /*
  295. convert UUID to local byte order
  296. */
  297. ntohl( uid->time_low );
  298. ntohs( uid->time_mid );
  299. ntohs( uid->time_hi_and_version );
  300. /*
  301. put in the variant and version bits
  302. */
  303. uid->time_hi_and_version &= 0x0FFF;
  304. uid->time_hi_and_version |= ( 3 << 12 );
  305. uid->clock_seq_hi_and_reserved &= 0x3F;
  306. uid->clock_seq_hi_and_reserved |= 0x80;
  307. };
  308. /*-----------------------------------------------------------------------------*/
  309. /*
  310. uuid_compare -- Compare two UUID's "lexically" and return
  311. -1 u1 is lexically before u2
  312. 0 u1 is equal to u2
  313. 1 u1 is lexically after u2
  314. Note: lexical ordering is not temporal ordering!
  315. */
  316. int
  317. uuid_compare( uuid_upnp * u1,
  318. uuid_upnp * u2 )
  319. {
  320. int i;
  321. #define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
  322. CHECK( u1->time_low, u2->time_low );
  323. CHECK( u1->time_mid, u2->time_mid );
  324. CHECK( u1->time_hi_and_version, u2->time_hi_and_version );
  325. CHECK( u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved );
  326. CHECK( u1->clock_seq_low, u2->clock_seq_low )
  327. for( i = 0; i < 6; i++ ) {
  328. if( u1->node[i] < u2->node[i] )
  329. return -1;
  330. if( u1->node[i] > u2->node[i] )
  331. return 1;
  332. }
  333. return 0;
  334. };