home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / openh323.tar.gz / openh323.tar / openh323 / src / guid.cxx < prev    next >
C/C++ Source or Header  |  2003-04-14  |  9KB  |  307 lines

  1. /*
  2.  * guid.cxx
  3.  *
  4.  * Globally Unique Identifier
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1998-2001 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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
  18.  * under the License.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Contributor(s): ______________________________________.
  25.  *
  26.  * $Log: guid.cxx,v $
  27.  * Revision 1.15  2003/04/15 03:04:08  robertj
  28.  * Fixed string constructor being able to build non null GUID.
  29.  *
  30.  * Revision 1.14  2002/10/10 05:33:18  robertj
  31.  * VxWorks port, thanks Martijn Roest
  32.  *
  33.  * Revision 1.13  2002/08/05 10:03:47  robertj
  34.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  35.  *
  36.  * Revision 1.12  2001/10/03 03:18:29  robertj
  37.  * Changed to only get (or fake) MAC address once.
  38.  *
  39.  * Revision 1.11  2001/04/05 01:45:13  robertj
  40.  * Fixed MSVC warning.
  41.  *
  42.  * Revision 1.10  2001/04/04 07:46:13  robertj
  43.  * Fixed erros in rading GUID hex string.
  44.  *
  45.  * Revision 1.9  2001/04/04 06:46:39  robertj
  46.  * Fixed errors in time calculation used in GUID.
  47.  *
  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.
  51.  *
  52.  * Revision 1.7  2001/03/15 00:25:12  robertj
  53.  * Fixed problem with hex output sign extending unsigned values.
  54.  *
  55.  * Revision 1.6  2001/03/14 05:03:37  robertj
  56.  * Fixed printing of GUID to have bytes as hex instead of characters.
  57.  *
  58.  * Revision 1.5  2001/03/03 00:54:48  yurik
  59.  * Proper fix for filetime routines used in guid calc done for WinCE
  60.  *
  61.  * Revision 1.4  2001/03/02 23:25:49  yurik
  62.  * fixed typo
  63.  *
  64.  * Revision 1.3  2001/03/02 22:50:37  yurik
  65.  * Used PTime for WinCE port instead of non-portable function
  66.  *
  67.  * Revision 1.2  2001/03/02 07:17:41  robertj
  68.  * Compensated for stupid GNU compiler bug.
  69.  *
  70.  * Revision 1.1  2001/03/02 06:59:59  robertj
  71.  * Enhanced the globally unique identifier class.
  72.  *
  73.  */
  74.  
  75. #include <ptlib.h>
  76.  
  77. #ifdef __GNUC__
  78. #pragma implementation "guid.h"
  79. #endif
  80.  
  81. #include "guid.h"
  82.  
  83. #include <ptlib/sockets.h>
  84. #include <ptclib/random.h>
  85. #include <ptclib/asner.h>
  86.  
  87.  
  88. #define GUID_SIZE 16
  89.  
  90.  
  91. ///////////////////////////////////////////////////////////////////////////////
  92.  
  93. OpalGloballyUniqueID::OpalGloballyUniqueID()
  94.   : PBYTEArray(GUID_SIZE)
  95. {
  96.   // Want time of UTC in 0.1 microseconds since 15 Oct 1582.
  97.   PInt64 timestamp;
  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
  102. #ifdef _WIN32
  103.                              + (1601-1583)*365   // Whole years
  104.                              + (1601-1583)/4);   // Leap days
  105.  
  106.   // Get nanoseconds since 1601
  107. #ifndef _WIN32_WCE
  108.   GetSystemTimeAsFileTime((LPFILETIME)×tamp);
  109. #else
  110.   SYSTEMTIME SystemTime;
  111.   GetSystemTime(&SystemTime);
  112.   SystemTimeToFileTime(&SystemTime, (LPFILETIME)×tamp);
  113. #endif // _WIN32_WCE
  114.  
  115.   timestamp /= 100;
  116. #else // _WIN32
  117.                              + (1970-1583)*365 // Days in years
  118.                              + (1970-1583)/4   // Leap days
  119.                              - 3);             // Allow for 1700, 1800, 1900 not leap years
  120.  
  121. #ifdef P_VXWORKS
  122.   struct timespec ts;
  123.   clock_gettime(0,&ts);
  124.   timestamp = (ts.tv_sec*(PInt64)1000000 + ts.tv_nsec*1000)*10;
  125. #else
  126.   struct timeval tv;
  127.   gettimeofday(&tv, NULL);
  128.   timestamp = (tv.tv_sec*(PInt64)1000000 + tv.tv_usec)*10;
  129. #endif // P_VXWORKS
  130. #endif // _WIN32
  131.  
  132.   timestamp += deltaTime;
  133.  
  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
  142.  
  143.   static WORD clockSequence = (WORD)PRandom::Number();
  144.   static PInt64 lastTimestamp = 0;
  145.   if (lastTimestamp < timestamp)
  146.     lastTimestamp = timestamp;
  147.   else
  148.     clockSequence++;
  149.  
  150.   theArray[8] = (BYTE)(((clockSequence>>8)&0x1f) | 0x80); // DCE compatible GUID
  151.   theArray[9] = (BYTE)clockSequence;
  152.  
  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;
  164.             break;
  165.           }
  166.         }
  167.       }
  168.     }
  169.  
  170.     if (needMacAddress) {
  171.       PRandom rand;
  172.       macAddress.ls.l = rand;
  173.       macAddress.ls.s = (WORD)rand;
  174.       macAddress.b[0] |= '\x80';
  175.  
  176.       needMacAddress = FALSE;
  177.     }
  178.   }
  179.  
  180.   memcpy(theArray+10, macAddress.b, 6);
  181. }
  182.  
  183.  
  184. OpalGloballyUniqueID::OpalGloballyUniqueID(const char * cstr)
  185.   : PBYTEArray(GUID_SIZE)
  186. {
  187.   if (cstr != NULL && *cstr != '\0') {
  188.     PStringStream strm(cstr);
  189.     ReadFrom(strm);
  190.   }
  191. }
  192.  
  193.  
  194. OpalGloballyUniqueID::OpalGloballyUniqueID(const PString & str)
  195.   : PBYTEArray(GUID_SIZE)
  196. {
  197.   PStringStream strm(str);
  198.   ReadFrom(strm);
  199. }
  200.  
  201.  
  202. OpalGloballyUniqueID::OpalGloballyUniqueID(const PASN_OctetString & newId)
  203.   : PBYTEArray(newId)
  204. {
  205.   PAssert(GetSize() == GUID_SIZE, PInvalidParameter);
  206.   SetSize(GUID_SIZE);
  207. }
  208.  
  209.  
  210. PObject * OpalGloballyUniqueID::Clone() const
  211. {
  212.   PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
  213.  
  214.   return new OpalGloballyUniqueID(*this);
  215. }
  216.  
  217.  
  218. PINDEX OpalGloballyUniqueID::HashFunction() const
  219. {
  220.   PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
  221.  
  222.   DWORD * words = (DWORD *)theArray;
  223.   DWORD sum = words[0] + words[1] + words[2] + words[3];
  224.   return ((sum >> 25)+(sum >> 15)+sum)%23;
  225. }
  226.  
  227.  
  228. void OpalGloballyUniqueID::PrintOn(ostream & strm) const
  229. {
  230.   PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
  231.  
  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);
  251. }
  252.  
  253.  
  254. void OpalGloballyUniqueID::ReadFrom(istream & strm)
  255. {
  256.   PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
  257.   SetSize(16);
  258.  
  259.   strm >> ws;
  260.  
  261.   PINDEX count = 0;
  262.  
  263.   while (count < 2*GUID_SIZE) {
  264.     if (isxdigit(strm.peek())) {
  265.       char digit = (char)(strm.get() - '0');
  266.       if (digit >= 10) {
  267.         digit -= 'A'-('9'+1);
  268.         if (digit >= 16)
  269.           digit -= 'a'-'A';
  270.       }
  271.       theArray[count/2] = (BYTE)((theArray[count/2] << 4) | digit);
  272.       count++;
  273.     }
  274.     else if (strm.peek() == '-') {
  275.       if (count != 8 && count != 12 && count != 16 && count != 20)
  276.         break;
  277.       strm.get(); // Ignore the dash if it was in the right place
  278.     }
  279.     else
  280.       break;
  281.   }
  282.  
  283.   if (count < 2*GUID_SIZE) {
  284.     memset(theArray, 0, GUID_SIZE);
  285.     strm.clear(ios::failbit);
  286.   }
  287. }
  288.  
  289.  
  290. PString OpalGloballyUniqueID::AsString() const
  291. {
  292.   PStringStream strm;
  293.   PrintOn(strm);
  294.   return strm;
  295. }
  296.  
  297.  
  298. BOOL OpalGloballyUniqueID::IsNULL() const
  299. {
  300.   PAssert(GetSize() == GUID_SIZE, "OpalGloballyUniqueID is invalid size");
  301.  
  302.   return memcmp(theArray, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) == 0;
  303. }
  304.  
  305.  
  306. /////////////////////////////////////////////////////////////////////////////
  307.