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.2 2007/07/20 01:40:23 csoutheren
28 * Ignore spaces in GUID strings
30 * Revision 1.1 2006/09/20 05:03:41 csoutheren
31 * Migrated GUID functions to PWLib
33 * Revision 2.4 2004/02/19 10:47:06 rjongbloed
34 * Merged OpenH323 version 1.13.1 changes.
36 * Revision 2.3 2002/11/10 11:33:19 robertj
37 * Updated to OpenH323 v1.10.3
39 * Revision 2.2 2002/09/04 06:01:49 robertj
40 * Updated to OpenH323 v1.9.6
42 * Revision 2.1 2001/10/05 00:22:14 robertj
43 * Updated to PWLib 1.2.0 and OpenH323 1.7.0
45 * Revision 2.0 2001/07/27 15:48:25 robertj
46 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
48 * Revision 1.15 2003/04/15 03:04:08 robertj
49 * Fixed string constructor being able to build non null GUID.
51 * Revision 1.14 2002/10/10 05:33:18 robertj
52 * VxWorks port, thanks Martijn Roest
54 * Revision 1.13 2002/08/05 10:03:47 robertj
55 * Cosmetic changes to normalise the usage of pragma interface/implementation.
57 * Revision 1.12 2001/10/03 03:18:29 robertj
58 * Changed to only get (or fake) MAC address once.
60 * Revision 1.11 2001/04/05 01:45:13 robertj
63 * Revision 1.10 2001/04/04 07:46:13 robertj
64 * Fixed erros in rading GUID hex string.
66 * Revision 1.9 2001/04/04 06:46:39 robertj
67 * Fixed errors in time calculation used in GUID.
69 * Revision 1.8 2001/03/19 05:52:24 robertj
70 * Fixed problem with reading a GUID if there is leading white space.
71 * If get error reading GUID then set the stream fail bit.
73 * Revision 1.7 2001/03/15 00:25:12 robertj
74 * Fixed problem with hex output sign extending unsigned values.
76 * Revision 1.6 2001/03/14 05:03:37 robertj
77 * Fixed printing of GUID to have bytes as hex instead of characters.
79 * Revision 1.5 2001/03/03 00:54:48 yurik
80 * Proper fix for filetime routines used in guid calc done for WinCE
82 * Revision 1.4 2001/03/02 23:25:49 yurik
85 * Revision 1.3 2001/03/02 22:50:37 yurik
86 * Used PTime for WinCE port instead of non-portable function
88 * Revision 1.2 2001/03/02 07:17:41 robertj
89 * Compensated for stupid GNU compiler bug.
91 * Revision 1.1 2001/03/02 06:59:59 robertj
92 * Enhanced the globally unique identifier class.
99 #pragma implementation "guid.h"
102 #include <ptclib/guid.h>
104 #include <ptlib/sockets.h>
105 #include <ptclib/random.h>
106 #include <ptclib/asner.h>
114 ///////////////////////////////////////////////////////////////////////////////
116 PGloballyUniqueID::PGloballyUniqueID()
117 : PBYTEArray(GUID_SIZE
)
119 // Want time of UTC in 0.1 microseconds since 15 Oct 1582.
121 static PInt64 deltaTime
= PInt64(10000000)*24*60*60*
122 ( 16 // Days from 15th October
123 + 31 // Days in December 1583
124 + 30 // Days in November 1583
126 + (1601-1583)*365 // Whole years
127 + (1601-1583)/4); // Leap days
129 // Get nanoseconds since 1601
131 GetSystemTimeAsFileTime((LPFILETIME
)×tamp
);
133 SYSTEMTIME SystemTime
;
134 GetSystemTime(&SystemTime
);
135 SystemTimeToFileTime(&SystemTime
, (LPFILETIME
)×tamp
);
140 + (1970-1583)*365 // Days in years
141 + (1970-1583)/4 // Leap days
142 - 3); // Allow for 1700, 1800, 1900 not leap years
146 clock_gettime(0,&ts
);
147 timestamp
= (ts
.tv_sec
*(PInt64
)1000000 + ts
.tv_nsec
*1000)*10;
150 gettimeofday(&tv
, NULL
);
151 timestamp
= (tv
.tv_sec
*(PInt64
)1000000 + tv
.tv_usec
)*10;
155 timestamp
+= deltaTime
;
157 theArray
[0] = (BYTE
)(timestamp
&0xff);
158 theArray
[1] = (BYTE
)((timestamp
>>8)&0xff);
159 theArray
[2] = (BYTE
)((timestamp
>>16)&0xff);
160 theArray
[3] = (BYTE
)((timestamp
>>24)&0xff);
161 theArray
[4] = (BYTE
)((timestamp
>>32)&0xff);
162 theArray
[5] = (BYTE
)((timestamp
>>40)&0xff);
163 theArray
[6] = (BYTE
)((timestamp
>>48)&0xff);
164 theArray
[7] = (BYTE
)(((timestamp
>>56)&0x0f) + 0x10); // Version number is 1
166 static WORD clockSequence
= (WORD
)PRandom::Number();
167 static PInt64 lastTimestamp
= 0;
168 if (lastTimestamp
< timestamp
)
169 lastTimestamp
= timestamp
;
173 theArray
[8] = (BYTE
)(((clockSequence
>>8)&0x1f) | 0x80); // DCE compatible GUID
174 theArray
[9] = (BYTE
)clockSequence
;
176 static PEthSocket::Address macAddress
;
177 static BOOL needMacAddress
= TRUE
;
178 if (needMacAddress
) {
179 PIPSocket::InterfaceTable interfaces
;
180 if (PIPSocket::GetInterfaceTable(interfaces
)) {
181 for (PINDEX i
= 0; i
< interfaces
.GetSize(); i
++) {
182 PString macAddrStr
= interfaces
[i
].GetMACAddress();
183 if (!macAddrStr
&& macAddrStr
!= "44-45-53-54-00-00") { /* not Win32 PPP device */
184 macAddress
= macAddrStr
;
185 if (macAddress
!= NULL
) {
186 needMacAddress
= FALSE
;
193 if (needMacAddress
) {
195 macAddress
.ls
.l
= rand
;
196 macAddress
.ls
.s
= (WORD
)rand
;
197 macAddress
.b
[0] |= '\x80';
199 needMacAddress
= FALSE
;
203 memcpy(theArray
+10, macAddress
.b
, 6);
207 PGloballyUniqueID::PGloballyUniqueID(const char * cstr
)
208 : PBYTEArray(GUID_SIZE
)
210 if (cstr
!= NULL
&& *cstr
!= '\0') {
211 PStringStream
strm(cstr
);
217 PGloballyUniqueID::PGloballyUniqueID(const PString
& str
)
218 : PBYTEArray(GUID_SIZE
)
220 PStringStream
strm(str
);
225 PGloballyUniqueID::PGloballyUniqueID(const PASN_OctetString
& newId
)
228 PAssert(GetSize() == GUID_SIZE
, PInvalidParameter
);
233 PObject
* PGloballyUniqueID::Clone() const
235 PAssert(GetSize() == GUID_SIZE
, "PGloballyUniqueID is invalid size");
237 return new PGloballyUniqueID(*this);
241 PINDEX
PGloballyUniqueID::HashFunction() const
243 PAssert(GetSize() == GUID_SIZE
, "PGloballyUniqueID is invalid size");
245 DWORD
* words
= (DWORD
*)theArray
;
246 DWORD sum
= words
[0] + words
[1] + words
[2] + words
[3];
247 return ((sum
>> 25)+(sum
>> 15)+sum
)%23;
251 void PGloballyUniqueID::PrintOn(ostream
& strm
) const
253 PAssert(GetSize() == GUID_SIZE
, "PGloballyUniqueID is invalid size");
255 char fillchar
= strm
.fill();
256 strm
<< hex
<< setfill('0')
257 << setw(2) << (unsigned)(BYTE
)theArray
[0]
258 << setw(2) << (unsigned)(BYTE
)theArray
[1]
259 << setw(2) << (unsigned)(BYTE
)theArray
[2]
260 << setw(2) << (unsigned)(BYTE
)theArray
[3] << '-'
261 << setw(2) << (unsigned)(BYTE
)theArray
[4]
262 << setw(2) << (unsigned)(BYTE
)theArray
[5] << '-'
263 << setw(2) << (unsigned)(BYTE
)theArray
[6]
264 << setw(2) << (unsigned)(BYTE
)theArray
[7] << '-'
265 << setw(2) << (unsigned)(BYTE
)theArray
[8]
266 << setw(2) << (unsigned)(BYTE
)theArray
[9] << '-'
267 << setw(2) << (unsigned)(BYTE
)theArray
[10]
268 << setw(2) << (unsigned)(BYTE
)theArray
[11]
269 << setw(2) << (unsigned)(BYTE
)theArray
[12]
270 << setw(2) << (unsigned)(BYTE
)theArray
[13]
271 << setw(2) << (unsigned)(BYTE
)theArray
[14]
272 << setw(2) << (unsigned)(BYTE
)theArray
[15]
273 << dec
<< setfill(fillchar
);
277 void PGloballyUniqueID::ReadFrom(istream
& strm
)
279 PAssert(GetSize() == GUID_SIZE
, "PGloballyUniqueID is invalid size");
286 while (count
< 2*GUID_SIZE
) {
287 if (isxdigit(strm
.peek())) {
288 char digit
= (char)(strm
.get() - '0');
290 digit
-= 'A'-('9'+1);
294 theArray
[count
/2] = (BYTE
)((theArray
[count
/2] << 4) | digit
);
297 else if (strm
.peek() == '-') {
298 if (count
!= 8 && count
!= 12 && count
!= 16 && count
!= 20)
300 strm
.get(); // Ignore the dash if it was in the right place
302 else if (strm
.peek() == ' ')
303 strm
.get(); // Ignore spaces
308 if (count
< 2*GUID_SIZE
) {
309 memset(theArray
, 0, GUID_SIZE
);
310 strm
.clear(ios::failbit
);
315 PString
PGloballyUniqueID::AsString() const
323 BOOL
PGloballyUniqueID::IsNULL() const
325 PAssert(GetSize() == GUID_SIZE
, "PGloballyUniqueID is invalid size");
327 return memcmp(theArray
, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0;
331 /////////////////////////////////////////////////////////////////////////////