4 * Globally Unique Identifier
8 * Copyright (c) 1998-2001 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.15 2003/04/15 03:04:08 robertj
28 * Fixed string constructor being able to build non null GUID.
30 * Revision 1.14 2002/10/10 05:33:18 robertj
31 * VxWorks port, thanks Martijn Roest
33 * Revision 1.13 2002/08/05 10:03:47 robertj
34 * Cosmetic changes to normalise the usage of pragma interface/implementation.
36 * Revision 1.12 2001/10/03 03:18:29 robertj
37 * Changed to only get (or fake) MAC address once.
39 * Revision 1.11 2001/04/05 01:45:13 robertj
42 * Revision 1.10 2001/04/04 07:46:13 robertj
43 * Fixed erros in rading GUID hex string.
45 * Revision 1.9 2001/04/04 06:46:39 robertj
46 * Fixed errors in time calculation used in GUID.
48 * Revision 1.8 2001/03/19 05:52:24 robertj
49 * Fixed problem with reading a GUID if there is leading white space.
50 * If get error reading GUID then set the stream fail bit.
52 * Revision 1.7 2001/03/15 00:25:12 robertj
53 * Fixed problem with hex output sign extending unsigned values.
55 * Revision 1.6 2001/03/14 05:03:37 robertj
56 * Fixed printing of GUID to have bytes as hex instead of characters.
58 * Revision 1.5 2001/03/03 00:54:48 yurik
59 * Proper fix for filetime routines used in guid calc done for WinCE
61 * Revision 1.4 2001/03/02 23:25:49 yurik
64 * Revision 1.3 2001/03/02 22:50:37 yurik
65 * Used PTime for WinCE port instead of non-portable function
67 * Revision 1.2 2001/03/02 07:17:41 robertj
68 * Compensated for stupid GNU compiler bug.
70 * Revision 1.1 2001/03/02 06:59:59 robertj
71 * Enhanced the globally unique identifier class.
78 #pragma implementation "guid.h"
83 #include <ptlib/sockets.h>
84 #include <ptclib/random.h>
85 #include <ptclib/asner.h>
91 ///////////////////////////////////////////////////////////////////////////////
93 OpalGloballyUniqueID::OpalGloballyUniqueID()
94 : PBYTEArray(GUID_SIZE
)
96 // Want time of UTC in 0.1 microseconds since 15 Oct 1582.
98 static PInt64 deltaTime
= PInt64(10000000)*24*60*60*
99 ( 16 // Days from 15th October
100 + 31 // Days in December 1583
101 + 30 // Days in November 1583
103 + (1601-1583)*365 // Whole years
104 + (1601-1583)/4); // Leap days
106 // Get nanoseconds since 1601
108 GetSystemTimeAsFileTime((LPFILETIME
)×tamp
);
110 SYSTEMTIME SystemTime
;
111 GetSystemTime(&SystemTime
);
112 SystemTimeToFileTime(&SystemTime
, (LPFILETIME
)×tamp
);
117 + (1970-1583)*365 // Days in years
118 + (1970-1583)/4 // Leap days
119 - 3); // Allow for 1700, 1800, 1900 not leap years
123 clock_gettime(0,&ts
);
124 timestamp
= (ts
.tv_sec
*(PInt64
)1000000 + ts
.tv_nsec
*1000)*10;
127 gettimeofday(&tv
, NULL
);
128 timestamp
= (tv
.tv_sec
*(PInt64
)1000000 + tv
.tv_usec
)*10;
132 timestamp
+= deltaTime
;
134 theArray
[0] = (BYTE
)(timestamp
&0xff);
135 theArray
[1] = (BYTE
)((timestamp
>>8)&0xff);
136 theArray
[2] = (BYTE
)((timestamp
>>16)&0xff);
137 theArray
[3] = (BYTE
)((timestamp
>>24)&0xff);
138 theArray
[4] = (BYTE
)((timestamp
>>32)&0xff);
139 theArray
[5] = (BYTE
)((timestamp
>>40)&0xff);
140 theArray
[6] = (BYTE
)((timestamp
>>48)&0xff);
141 theArray
[7] = (BYTE
)(((timestamp
>>56)&0x0f) + 0x10); // Version number is 1
143 static WORD clockSequence
= (WORD
)PRandom::Number();
144 static PInt64 lastTimestamp
= 0;
145 if (lastTimestamp
< timestamp
)
146 lastTimestamp
= timestamp
;
150 theArray
[8] = (BYTE
)(((clockSequence
>>8)&0x1f) | 0x80); // DCE compatible GUID
151 theArray
[9] = (BYTE
)clockSequence
;
153 static PEthSocket::Address macAddress
;
154 static BOOL needMacAddress
= TRUE
;
155 if (needMacAddress
) {
156 PIPSocket::InterfaceTable interfaces
;
157 if (PIPSocket::GetInterfaceTable(interfaces
)) {
158 for (PINDEX i
= 0; i
< interfaces
.GetSize(); i
++) {
159 PString macAddrStr
= interfaces
[i
].GetMACAddress();
160 if (!macAddrStr
&& macAddrStr
!= "44-45-53-54-00-00") { /* not Win32 PPP device */
161 macAddress
= macAddrStr
;
162 if (macAddress
!= NULL
) {
163 needMacAddress
= FALSE
;
170 if (needMacAddress
) {
172 macAddress
.ls
.l
= rand
;
173 macAddress
.ls
.s
= (WORD
)rand
;
174 macAddress
.b
[0] |= '\x80';
176 needMacAddress
= FALSE
;
180 memcpy(theArray
+10, macAddress
.b
, 6);
184 OpalGloballyUniqueID::OpalGloballyUniqueID(const char * cstr
)
185 : PBYTEArray(GUID_SIZE
)
187 if (cstr
!= NULL
&& *cstr
!= '\0') {
188 PStringStream
strm(cstr
);
194 OpalGloballyUniqueID::OpalGloballyUniqueID(const PString
& str
)
195 : PBYTEArray(GUID_SIZE
)
197 PStringStream
strm(str
);
202 OpalGloballyUniqueID::OpalGloballyUniqueID(const PASN_OctetString
& newId
)
205 PAssert(GetSize() == GUID_SIZE
, PInvalidParameter
);
210 PObject
* OpalGloballyUniqueID::Clone() const
212 PAssert(GetSize() == GUID_SIZE
, "OpalGloballyUniqueID is invalid size");
214 return new OpalGloballyUniqueID(*this);
218 PINDEX
OpalGloballyUniqueID::HashFunction() const
220 PAssert(GetSize() == GUID_SIZE
, "OpalGloballyUniqueID is invalid size");
222 DWORD
* words
= (DWORD
*)theArray
;
223 DWORD sum
= words
[0] + words
[1] + words
[2] + words
[3];
224 return ((sum
>> 25)+(sum
>> 15)+sum
)%23;
228 void OpalGloballyUniqueID::PrintOn(ostream
& strm
) const
230 PAssert(GetSize() == GUID_SIZE
, "OpalGloballyUniqueID is invalid size");
232 char fillchar
= strm
.fill();
233 strm
<< hex
<< setfill('0')
234 << setw(2) << (unsigned)(BYTE
)theArray
[0]
235 << setw(2) << (unsigned)(BYTE
)theArray
[1]
236 << setw(2) << (unsigned)(BYTE
)theArray
[2]
237 << setw(2) << (unsigned)(BYTE
)theArray
[3] << '-'
238 << setw(2) << (unsigned)(BYTE
)theArray
[4]
239 << setw(2) << (unsigned)(BYTE
)theArray
[5] << '-'
240 << setw(2) << (unsigned)(BYTE
)theArray
[6]
241 << setw(2) << (unsigned)(BYTE
)theArray
[7] << '-'
242 << setw(2) << (unsigned)(BYTE
)theArray
[8]
243 << setw(2) << (unsigned)(BYTE
)theArray
[9] << '-'
244 << setw(2) << (unsigned)(BYTE
)theArray
[10]
245 << setw(2) << (unsigned)(BYTE
)theArray
[11]
246 << setw(2) << (unsigned)(BYTE
)theArray
[12]
247 << setw(2) << (unsigned)(BYTE
)theArray
[13]
248 << setw(2) << (unsigned)(BYTE
)theArray
[14]
249 << setw(2) << (unsigned)(BYTE
)theArray
[15]
250 << dec
<< setfill(fillchar
);
254 void OpalGloballyUniqueID::ReadFrom(istream
& strm
)
256 PAssert(GetSize() == GUID_SIZE
, "OpalGloballyUniqueID is invalid size");
263 while (count
< 2*GUID_SIZE
) {
264 if (isxdigit(strm
.peek())) {
265 char digit
= (char)(strm
.get() - '0');
267 digit
-= 'A'-('9'+1);
271 theArray
[count
/2] = (BYTE
)((theArray
[count
/2] << 4) | digit
);
274 else if (strm
.peek() == '-') {
275 if (count
!= 8 && count
!= 12 && count
!= 16 && count
!= 20)
277 strm
.get(); // Ignore the dash if it was in the right place
283 if (count
< 2*GUID_SIZE
) {
284 memset(theArray
, 0, GUID_SIZE
);
285 strm
.clear(ios::failbit
);
290 PString
OpalGloballyUniqueID::AsString() const
298 BOOL
OpalGloballyUniqueID::IsNULL() const
300 PAssert(GetSize() == GUID_SIZE
, "OpalGloballyUniqueID is invalid size");
302 return memcmp(theArray
, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0;
306 /////////////////////////////////////////////////////////////////////////////