A simple implementation of GUID/UUID


GUID, Globally Unique Identifier, aka UUID(Universally Unique Identifier), is very useful when you need a global identifier in you program.
GUID is a 128-bit integer number used to identify resources. The term GUID is generally used by developers working with Microsoft technologies, while UUID is used everywhere else.
For more information, you can visit:
1. IETF: RFC 4122 – http://www.ietf.org/rfc/rfc4122.txt (There’s a full implementation UUID in the Appendix A)
2. Wikipedia: Globally Unique Identifier – http://en.wikipedia.org/wiki/Globally_Unique_Identifier
3. Microsoft: GUID Structure – http://msdn2.microsoft.com/en-us/library/aa373931.aspx

Here is a simple/sample implementation of generating a GUID for yourself.

typedef struct
{
    unsigned char m_abyMacAddress[6];
    unsigned char m_abyTime[8];
    BOOL m_bClock_seq_change;
} uCID;

typedef struct
{
    u32        m_dwStartTime;
    u32        m_dwStartMilliTime;
    u32        m_dwOldMilliTime;
    u8        m_abyLastTime[8];
    BOOL    m_bNotStart;
    BOOL    m_bGenerated;
    uCID    m_tUCID;
    u8      m_abyCid[16];
    u8      m_abyOldCid[16];
    u16     m_wClock_seq;
} cidLocalStorage;

u32 timerGetTimeInMilliseconds(void)
{
#ifdef __VXWORKS__
    u32 dwTicks, dwTicksPerSec;
    u32 t;
    dwTicks = tickGet();
    dwTicksPerSec = sysClkRateGet();
    t = dwTicks / dwTicksPerSec * 1000 + (dwTicks % dwTicksPerSec) * 1000 / dwTicksPerSec;
    return (t==0xffffffff)?0:t;
#elif _UNIX_
    u32 t;
    static u32 sSeconds=0;
    struct timeval tv; /* timeval structure */
    gettimeofday(&tv, NULL);
    if (!sSeconds)
        sSeconds=(u32)tv.tv_sec;
    t=(u32)( (tv.tv_sec - sSeconds)*1000 + (tv.tv_usec/1000) );
    return (t==0xffffffff)?0:t;
    //modify by yj for CID [20120424]
#elif _LINUX_
    u32 t;
    static u32 sSeconds=0;
    struct timeval tv; /* timeval structure */
    gettimeofday(&tv, NULL);
    if (!sSeconds)
        sSeconds=(u32)tv.tv_sec;
    t=(u32)( (tv.tv_sec - sSeconds)*1000 + (tv.tv_usec/1000) );
    return (t==0xffffffff)?0:t;
    //end
#elif WIN32
    return GetTickCount();
#endif
}

u32 timerGetTimeInSeconds(void)
{
    //long only to 2036
    return (time(NULL))&0x7fffffff; /* force positive time */
}

u32 GetRandomNumber(void)
{
    s32 random;
    u32 result;
    
    /* for non windows systems, supply a permanant seed */
    static u32 seeded;
    if (!seeded)
    {
        srand(timerGetTimeInMilliseconds());
        seeded=TRUE;
    }
    random = rand();
    result = timerGetTimeInMilliseconds() * (random + 1);
    return result;
}

#define FROM1900TILL1970          (u32)0x83AA7E80//

cidLocalStorage *GetTime(u8 *theTime, BOOL32 *clockSeqChange)
{
    u32 milliTime;
    u32 secTime;
 
    static cidLocalStorage  cidTls = {0};
       
    if (!cidTls.m_dwStartTime)
    {
        cidTls.m_dwStartTime=timerGetTimeInSeconds()/3*5+0xb21dd213u;
        cidTls.m_dwStartMilliTime=timerGetTimeInMilliseconds();
    }
    if(!cidTls.m_wClock_seq)
    {
        cidTls.m_wClock_seq = (u16)GetRandomNumber();
    }
    
    milliTime = timerGetTimeInMilliseconds()-cidTls.m_dwStartMilliTime;
    
    *clockSeqChange  = (!cidTls.m_bNotStart) ||  /* first time */
                        ((s32)milliTime<0) || /* after reboot or overflow */
                        ((cidTls.m_dwOldMilliTime - milliTime) == 0); /* in the same millisec as before */
   
    cidTls.m_bNotStart = TRUE;
    cidTls.m_dwOldMilliTime = milliTime;
    
    secTime=milliTime/600+cidTls.m_dwStartTime;
    
    milliTime%=600;
    milliTime*=27777;
    
    theTime[0]=2;
    theTime[1]=(unsigned char)(secTime>>24);
    theTime[2]=(unsigned char)(secTime>>16);
    theTime[3]=(unsigned char)(secTime>>8);
    theTime[4]=(unsigned char)(secTime);
    theTime[5]=(unsigned char)(milliTime>>16);
    theTime[6]=(unsigned char)(milliTime>>8);
    theTime[7]=(unsigned char)(milliTime);
    
    return &cidTls;
}

//TODO to be implemented, hard code a MAC address
void GetMACaddress(unsigned char*theMAC)
{
    theMAC[0]=0x56;
    theMAC[1]=0x34;
    theMAC[2]=0x34;
    theMAC[3]=0x34;
    theMAC[4]=0x34;
    theMAC[5]=0xef;
}

//
u8* GenerateGUID(void)
{
    uCID u;
    /* set time_low , time_mid, time_hi_and_version fields - 0-7 octets of cid */
    cidLocalStorage * cidTls = GetTime(u.m_abyTime, &(u.m_bClock_seq_change));
    memcpy(cidTls->m_abyCid,u.m_abyTime,8);
    
    memcpy(cidTls->m_tUCID.m_abyTime ,u.m_abyTime, sizeof(u.m_abyTime));
    cidTls->m_tUCID.m_bClock_seq_change = u.m_bClock_seq_change;
    /* 4 most significant bits of 6-7 bytes set to version number - '0001' */
    //2007.02.05 LINUX_ARM
    //*((u16*)(cidTls->m_abyCid+6)) &= 0x1ffff;
    u16 wCID;
    memcpy(&wCID, cidTls->m_abyCid+6, sizeof(wCID));
    wCID &= 0x1ffff;
    memcpy(cidTls->m_abyCid+6, &wCID, sizeof(wCID));

    /* set clock_seq_hi_and_reserved and clock_seq_low  fields - 8,9 octets of cid */
    if (u.m_bClock_seq_change) {
        cidTls->m_wClock_seq++;
        cidTls->m_wClock_seq %= 16384; /* 16384 - '0100000000000000' */
    }
    
    cidTls->m_abyCid[9] = (u8) cidTls->m_wClock_seq; /* set clock_seq_low to the 8 LSBs*/
    cidTls->m_abyCid[8] = (u8) (cidTls->m_wClock_seq>>8); /* set clock_seq_hi */
    cidTls->m_abyCid[8] &= 0xbf; /* set 2 MSBs to '10' */
    /* set node  - 10 -15 octets of cid */
    if (!cidTls->m_bGenerated)
    {
        cidTls->m_bGenerated=TRUE;
        GetMACaddress(cidTls->m_tUCID.m_abyMacAddress);
    }
    
    memcpy(cidTls->m_abyCid+10,cidTls->m_tUCID.m_abyMacAddress,6);
    memcpy(cidTls->m_abyOldCid, cidTls->m_abyCid, 16);
    
    return cidTls->m_abyCid;
}

In fact, RFC4122 provided a full implementation of UUID in Appendix A – Sample Implementation. If you need to implement a strictly standard version of UUID/GUID, you can use that code directly.

Leave a comment

Your email address will not be published. Required fields are marked *