uuid.c
来自「原来由英特尔制定的UPnP SDK的」· C语言 代码 · 共 389 行
C
389 行
/* ** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. ** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & ** Digital Equipment Corporation, Maynard, Mass. ** Copyright (c) 1998 Microsoft. ** To anyone who acknowledges that this file is provided "AS IS" ** without any express or implied warranty: permission to use, copy, ** modify, and distribute this file for any purpose is hereby ** granted without fee, provided that the above copyright notices and ** this notice appears in all source code copies, and that none of ** the names of Open Software Foundation, Inc., Hewlett-Packard ** Company, or Digital Equipment Corporation be used in advertising ** or publicity pertaining to distribution of the software without ** specific, written prior permission. Neither Open Software ** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment ** Corporation makes any representations about the suitability of ** this software for any purpose. */#include "config.h"#include <string.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#ifndef WIN32 #include <netinet/in.h>#else #include <winsock2.h>#endif#include "sysdep.h"#include "uuid.h"/* various forward declarations */static int read_state( unsigned16 * clockseq, uuid_time_t * timestamp, uuid_node_t * node );static void write_state( unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node );static void format_uuid_v1( uuid_upnp * uid, unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node );static void format_uuid_v3( uuid_upnp * uid, unsigned char hash[16] );static void get_current_time( uuid_time_t * timestamp );static unsigned16 true_random( void );/*-----------------------------------------------------------------------------*//* uuid_create -- generator a UUID */intuuid_create(uuid_upnp *uid){ uuid_time_t timestamp; uuid_time_t last_time; unsigned16 clockseq; uuid_node_t node; uuid_node_t last_node; int f; /* acquire system wide lock so we're alone */ UUIDLock(); /* get current time */ get_current_time(×tamp); /* get node ID */ get_ieee_node_identifier(&node); /* get saved state from NV storage */ f = read_state(&clockseq, &last_time, &last_node); /* if no NV state, or if clock went backwards, or node ID changed (e.g., net card swap) change clockseq */ if (!f || memcmp(&node, &last_node, sizeof(uuid_node_t))) { clockseq = true_random(); } else if (timestamp < last_time) { clockseq++; } /* stuff fields into the UUID */ format_uuid_v1(uid, clockseq, timestamp, node); /* save the state for next time */ write_state(clockseq, timestamp, node); UUIDUnlock(); return 1;};/*-----------------------------------------------------------------------------*/voiduuid_unpack(uuid_upnp *u, char *out){ sprintf(out, "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x", (unsigned int)u->time_low, u->time_mid, u->time_hi_and_version, u->clock_seq_hi_and_reserved, u->clock_seq_low, u->node[0], u->node[1], u->node[2], u->node[3], u->node[4], u->node[5]);};/*-----------------------------------------------------------------------------*//* format_uuid_v1 -- make a UUID from the timestamp, clockseq, and node ID */voidformat_uuid_v1( uuid_upnp * uid, unsigned16 clock_seq, uuid_time_t timestamp, uuid_node_t node ){ /* Construct a version 1 uuid with the information we've gathered * plus a few constants. */ uid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); uid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); uid->time_hi_and_version = (unsigned short)((timestamp >> 48) & 0x0FFF); uid->time_hi_and_version |= (1 << 12); uid->clock_seq_low = clock_seq & 0xFF; uid->clock_seq_hi_and_reserved = ( clock_seq & 0x3F00 ) >> 8; uid->clock_seq_hi_and_reserved |= 0x80; memcpy( &uid->node, &node, sizeof uid->node );};/*-----------------------------------------------------------------------------*//* data type for UUID generator persistent state */typedef struct { uuid_time_t ts; /* saved timestamp */ uuid_node_t node; /* saved node ID */ unsigned16 cs; /* saved clock sequence */} uuid_state;static uuid_state st;static int stateInited = 0;/*-----------------------------------------------------------------------------*//* read_state -- read UUID generator state from non-volatile store */intread_state( unsigned16 * clockseq, uuid_time_t * timestamp, uuid_node_t * node ){ if( !stateInited ) { return 0; }; *clockseq = st.cs; *timestamp = st.ts; *node = st.node; return 1;};/*-----------------------------------------------------------------------------*//* write_state -- save UUID generator state back to non-volatile storage */voidwrite_state( unsigned16 clockseq, uuid_time_t timestamp, uuid_node_t node ){ static uuid_time_t next_save; if( !stateInited ) { next_save = timestamp; stateInited = 1; }; /* always save state to volatile shared state */ st.cs = clockseq; st.ts = timestamp; st.node = node; if( timestamp >= next_save ) { /* schedule next save for 10 seconds from now */ next_save = timestamp + ( 10 * 10 * 1000 * 1000 ); };};/*-----------------------------------------------------------------------------*//* get-current_time -- get time as 60 bit 100ns ticks since whenever. Compensate for the fact that real clock resolution is less than 100ns. */voidget_current_time( uuid_time_t * timestamp ){ uuid_time_t time_now; static uuid_time_t time_last; static unsigned16 uuids_this_tick; static int inited = 0; if( !inited ) { uuids_this_tick = UUIDS_PER_TICK; inited = 1; }; while( 1 ) { get_system_time( &time_now ); /* if clock reading changed since last UUID generated... */ if( time_last != time_now ) { /* reset count of uuids gen'd with this clock reading */ uuids_this_tick = 0; break; }; if( uuids_this_tick < UUIDS_PER_TICK ) { uuids_this_tick++; break; }; /* going too fast for our clock; spin */ }; /* add the count of uuids to low order bits of the clock reading */ *timestamp = time_now + uuids_this_tick; time_last = *timestamp;};/*-----------------------------------------------------------------------------*//* true_random -- generate a crypto-quality random number. This sample doesn't do that. */static unsigned16true_random( void ){ static int inited = 0; uuid_time_t time_now; if( !inited ) { get_system_time( &time_now ); time_now = time_now / UUIDS_PER_TICK; srand( ( unsigned int )( ( ( time_now >> 32 ) ^ time_now ) & 0xffffffff ) ); inited = 1; }; return ( rand() );}/*-----------------------------------------------------------------------------*//* uuid_create_from_name -- create a UUID using a "name" from a "name space" */voiduuid_create_from_name( uuid_upnp * uid, /* resulting UUID */ uuid_upnp nsid, /* UUID to serve as context, so identical names from different name spaces generate different UUIDs */ void *name, /* the name from which to generate a UUID */ int namelen /* the length of the name */ ){ MD5_CTX c; unsigned char hash[16]; uuid_upnp net_nsid; /* context UUID in network byte order */ /* put name space ID in network byte order so it hashes the same no matter what endian machine we're on */ net_nsid = nsid; net_nsid.time_low=htonl( net_nsid.time_low ); net_nsid.time_mid=htons( net_nsid.time_mid ); net_nsid.time_hi_and_version=htons( net_nsid.time_hi_and_version ); MD5Init( &c ); MD5Update( &c, &net_nsid, sizeof( uuid_upnp ) ); MD5Update( &c, name, namelen ); MD5Final( hash, &c ); /* the hash is in network byte order at this point */ format_uuid_v3( uid, hash );};/*-----------------------------------------------------------------------------*//* format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number */voidformat_uuid_v3( uuid_upnp * uid, unsigned char hash[16] ){ /* Construct a version 3 uuid with the (pseudo-)random number * plus a few constants. */ memcpy( uid, hash, sizeof( uuid_upnp ) ); /* convert UUID to local byte order */ uid->time_low=ntohl( uid->time_low ); uid->time_mid=ntohs( uid->time_mid ); uid->time_hi_and_version=ntohs( uid->time_hi_and_version ); /* put in the variant and version bits */ uid->time_hi_and_version &= 0x0FFF; uid->time_hi_and_version |= ( 3 << 12 ); uid->clock_seq_hi_and_reserved &= 0x3F; uid->clock_seq_hi_and_reserved |= 0x80;};/*-----------------------------------------------------------------------------*//* uuid_compare -- Compare two UUID's "lexically" and return -1 u1 is lexically before u2 0 u1 is equal to u2 1 u1 is lexically after u2 Note: lexical ordering is not temporal ordering! */intuuid_compare( uuid_upnp * u1, uuid_upnp * u2 ){ int i;#define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1; CHECK( u1->time_low, u2->time_low ); CHECK( u1->time_mid, u2->time_mid ); CHECK( u1->time_hi_and_version, u2->time_hi_and_version ); CHECK( u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved ); CHECK( u1->clock_seq_low, u2->clock_seq_low ) for( i = 0; i < 6; i++ ) { if( u1->node[i] < u2->node[i] ) return -1; if( u1->node[i] > u2->node[i] ) return 1; } return 0;};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?