pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / uuid / uuid.c
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
20 #include "config.h"
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #ifndef WIN32
26  #include <netinet/in.h>
27 #else
28  #include <winsock2.h>
29 #endif
30 #include "sysdep.h"
31 #include "uuid.h"
32
33 /*
34    various forward declarations 
35  */
36 static int read_state( unsigned16 * clockseq,
37                        uuid_time_t * timestamp,
38                        uuid_node_t * node );
39 static void write_state( unsigned16 clockseq,
40                          uuid_time_t timestamp,
41                          uuid_node_t node );
42 static void format_uuid_v1( uuid_upnp * uid,
43                             unsigned16 clockseq,
44                             uuid_time_t timestamp,
45                             uuid_node_t node );
46 static void format_uuid_v3( uuid_upnp * uid,
47                             unsigned char hash[16] );
48 static void get_current_time( uuid_time_t * timestamp );
49 static unsigned16 true_random( void );
50
51 /*-----------------------------------------------------------------------------*/
52 /*
53    uuid_create -- generator a UUID 
54  */
55 int
56 uuid_create(uuid_upnp *uid)
57 {
58     uuid_time_t timestamp;
59     uuid_time_t last_time;
60     unsigned16 clockseq;
61     uuid_node_t node;
62     uuid_node_t last_node;
63     int f;
64
65     /*
66        acquire system wide lock so we're alone 
67      */
68     UUIDLock();
69
70     /*
71        get current time 
72      */
73     get_current_time(&timestamp);
74
75     /*
76        get node ID 
77      */
78     get_ieee_node_identifier(&node);
79
80     /*
81        get saved state from NV storage 
82      */
83     f = read_state(&clockseq, &last_time, &last_node);
84
85     /*
86        if no NV state, or if clock went backwards, or node ID changed
87        (e.g., net card swap) change clockseq 
88      */
89     if (!f || memcmp(&node, &last_node, sizeof(uuid_node_t))) {
90         clockseq = true_random();
91     } else if (timestamp < last_time) {
92         clockseq++;
93     }
94
95     /*
96        stuff fields into the UUID 
97      */
98     format_uuid_v1(uid, clockseq, timestamp, node);
99
100     /*
101        save the state for next time 
102      */
103     write_state(clockseq, timestamp, node);
104
105     UUIDUnlock();
106     return 1;
107 };
108
109 /*-----------------------------------------------------------------------------*/
110 void
111 uuid_unpack(uuid_upnp *u, char *out)
112 {
113         sprintf(out,
114                 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
115                 (unsigned int)u->time_low,
116                 u->time_mid,
117                 u->time_hi_and_version,
118                 u->clock_seq_hi_and_reserved,
119                 u->clock_seq_low,
120                 u->node[0],
121                 u->node[1],
122                 u->node[2],
123                 u->node[3],
124                 u->node[4],
125                 u->node[5]);
126 };
127
128 /*-----------------------------------------------------------------------------*/
129 /*
130    format_uuid_v1 -- make a UUID from the timestamp, clockseq,
131    and node ID 
132  */
133 void
134 format_uuid_v1( uuid_upnp * uid,
135                 unsigned16 clock_seq,
136                 uuid_time_t timestamp,
137                 uuid_node_t node )
138 {
139     /*
140        Construct a version 1 uuid with the information we've gathered
141        * plus a few constants. 
142      */
143     uid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF);
144     uid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF);
145     uid->time_hi_and_version = (unsigned short)((timestamp >> 48) & 0x0FFF);
146     uid->time_hi_and_version |= (1 << 12);
147     uid->clock_seq_low = clock_seq & 0xFF;
148     uid->clock_seq_hi_and_reserved = ( clock_seq & 0x3F00 ) >> 8;
149     uid->clock_seq_hi_and_reserved |= 0x80;
150     memcpy( &uid->node, &node, sizeof uid->node );
151 };
152
153 /*-----------------------------------------------------------------------------*/
154 /*
155    data type for UUID generator persistent state 
156  */
157 typedef struct {
158     uuid_time_t ts;             /* saved timestamp */
159     uuid_node_t node;           /* saved node ID */
160     unsigned16 cs;              /* saved clock sequence */
161 } uuid_state;
162
163 static uuid_state st;
164 static int stateInited = 0;
165
166 /*-----------------------------------------------------------------------------*/
167 /*
168    read_state -- read UUID generator state from non-volatile store 
169  */
170 int
171 read_state( unsigned16 * clockseq,
172             uuid_time_t * timestamp,
173             uuid_node_t * node )
174 {
175
176     if( !stateInited ) {
177         return 0;
178     };
179
180     *clockseq = st.cs;
181     *timestamp = st.ts;
182     *node = st.node;
183     return 1;
184 };
185
186 /*-----------------------------------------------------------------------------*/
187 /*
188    write_state -- save UUID generator state back to non-volatile
189    storage 
190  */
191 void
192 write_state( unsigned16 clockseq,
193              uuid_time_t timestamp,
194              uuid_node_t node )
195 {
196     static uuid_time_t next_save;
197
198     if( !stateInited ) {
199         next_save = timestamp;
200         stateInited = 1;
201     };
202
203     /*
204        always save state to volatile shared state 
205      */
206     st.cs = clockseq;
207     st.ts = timestamp;
208     st.node = node;
209     if( timestamp >= next_save ) {
210         /*
211            schedule next save for 10 seconds from now 
212          */
213         next_save = timestamp + ( 10 * 10 * 1000 * 1000 );
214     };
215 };
216
217 /*-----------------------------------------------------------------------------*/
218 /*
219    get-current_time -- get time as 60 bit 100ns ticks since whenever.
220    Compensate for the fact that real clock resolution is
221    less than 100ns. 
222  */
223 void
224 get_current_time( uuid_time_t * timestamp )
225 {
226     uuid_time_t time_now;
227     static uuid_time_t time_last;
228     static unsigned16 uuids_this_tick;
229     static int inited = 0;
230
231     if( !inited ) {
232         uuids_this_tick = UUIDS_PER_TICK;
233         inited = 1;
234     };
235
236     while( 1 ) {
237         get_system_time( &time_now );
238
239         /*
240            if clock reading changed since last UUID generated... 
241          */
242         if( time_last != time_now ) {
243             /*
244                reset count of uuids gen'd with this clock reading 
245              */
246             uuids_this_tick = 0;
247             break;
248         };
249
250         if( uuids_this_tick < UUIDS_PER_TICK ) {
251             uuids_this_tick++;
252             break;
253         };
254         /*
255            going too fast for our clock; spin 
256          */
257     };
258
259     /*
260        add the count of uuids to low order bits of the clock reading 
261      */
262     *timestamp = time_now + uuids_this_tick;
263     time_last = *timestamp;
264 };
265
266 /*-----------------------------------------------------------------------------*/
267 /*
268    true_random -- generate a crypto-quality random number.
269    This sample doesn't do that. 
270  */
271 static unsigned16
272 true_random( void )
273 {
274     static int inited = 0;
275     uuid_time_t time_now;
276
277     if( !inited ) {
278         get_system_time( &time_now );
279         time_now = time_now / UUIDS_PER_TICK;
280         srand( ( unsigned int )( ( ( time_now >> 32 ) ^ time_now ) &
281                                  0xffffffff ) );
282         inited = 1;
283     };
284
285     return ( rand() );
286 }
287
288 /*-----------------------------------------------------------------------------*/
289 /*
290    uuid_create_from_name -- create a UUID using a "name" from a "name space" 
291  */
292 void
293 uuid_create_from_name( uuid_upnp * uid, /* resulting UUID */
294
295                        uuid_upnp nsid,  /* UUID to serve as context, so identical
296                                            names from different name spaces generate
297                                            different UUIDs */
298
299                        void *name,  /* the name from which to generate a UUID */
300
301                        int namelen  /* the length of the name */
302      )
303 {
304     MD5_CTX c;
305     unsigned char hash[16];
306     uuid_upnp net_nsid;         /* context UUID in network byte order */
307
308     /*
309        put name space ID in network byte order so it hashes the same
310        no matter what endian machine we're on 
311      */
312     net_nsid = nsid;
313     net_nsid.time_low=htonl( net_nsid.time_low );
314     net_nsid.time_mid=htons( net_nsid.time_mid );
315     net_nsid.time_hi_and_version=htons( net_nsid.time_hi_and_version );
316
317     MD5Init( &c );
318     MD5Update( &c, &net_nsid, sizeof( uuid_upnp ) );
319     MD5Update( &c, name, namelen );
320     MD5Final( hash, &c );
321
322     /*
323        the hash is in network byte order at this point 
324      */
325     format_uuid_v3( uid, hash );
326 };
327
328 /*-----------------------------------------------------------------------------*/
329 /*
330    format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number
331  */
332 void
333 format_uuid_v3( uuid_upnp * uid,
334                 unsigned char hash[16] )
335 {
336     /*
337        Construct a version 3 uuid with the (pseudo-)random number
338        * plus a few constants. 
339      */
340
341     memcpy( uid, hash, sizeof( uuid_upnp ) );
342
343     /*
344        convert UUID to local byte order 
345      */
346     uid->time_low=ntohl( uid->time_low );
347     uid->time_mid=ntohs( uid->time_mid );
348     uid->time_hi_and_version=ntohs( uid->time_hi_and_version );
349
350     /*
351        put in the variant and version bits 
352      */
353     uid->time_hi_and_version &= 0x0FFF;
354     uid->time_hi_and_version |= ( 3 << 12 );
355     uid->clock_seq_hi_and_reserved &= 0x3F;
356     uid->clock_seq_hi_and_reserved |= 0x80;
357 };
358
359 /*-----------------------------------------------------------------------------*/
360 /*
361    uuid_compare --  Compare two UUID's "lexically" and return
362    -1   u1 is lexically before u2
363    0   u1 is equal to u2
364    1   u1 is lexically after u2
365
366    Note:   lexical ordering is not temporal ordering!
367  */
368 int
369 uuid_compare( uuid_upnp * u1,
370               uuid_upnp * u2 )
371 {
372     int i;
373
374 #define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
375     CHECK( u1->time_low, u2->time_low );
376     CHECK( u1->time_mid, u2->time_mid );
377     CHECK( u1->time_hi_and_version, u2->time_hi_and_version );
378     CHECK( u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved );
379     CHECK( u1->clock_seq_low, u2->clock_seq_low )
380         for( i = 0; i < 6; i++ ) {
381         if( u1->node[i] < u2->node[i] )
382             return -1;
383         if( u1->node[i] > u2->node[i] )
384             return 1;
385     }
386
387     return 0;
388 };