UUID.cpp

Go to the documentation of this file.
00001 //$Id: UUID.cpp 78180 2007-04-25 07:05:02Z johnnyw $
00002 
00003 #include "ace/UUID.h"
00004 #include "ace/Guard_T.h"
00005 
00006 #if !defined (__ACE_INLINE__)
00007 #include "ace/UUID.inl"
00008 #endif /* __ACE_INLINE__ */
00009 
00010 #include "ace/Log_Msg.h"
00011 #include "ace/OS_NS_stdio.h"
00012 #include "ace/OS_NS_string.h"
00013 #include "ace/OS_NS_sys_time.h"
00014 #include "ace/OS_NS_netdb.h"
00015 #include "ace/OS_NS_unistd.h"
00016 #include "ace/ACE.h"
00017 
00018 ACE_RCSID (ace,
00019            UUID,
00020            "$Id: UUID.cpp 78180 2007-04-25 07:05:02Z johnnyw $")
00021 
00022 
00023 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00024 
00025 namespace ACE_Utils
00026 {
00027 
00028   UUID_node::UUID_node (void)
00029   {
00030     for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
00031       {
00032         nodeID_[i] = 0;
00033       }
00034   }
00035 
00036   UUID_node::NodeID&
00037   UUID_node::nodeID (void)
00038   {
00039     return nodeID_;
00040   }
00041 
00042   void
00043   UUID_node::nodeID (NodeID& nodeID)
00044   {
00045     for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
00046       {
00047         nodeID_[i] = nodeID[i];
00048       }
00049   }
00050 
00051   UUID UUID::NIL_UUID;
00052 
00053   /// Construct a nil UUID. Such a UUID has every one of it's data
00054   /// elements set to zero.
00055   UUID::UUID(void)
00056     : timeLow_ (0),
00057       timeMid_ (0),
00058       timeHiAndVersion_ (0),
00059       clockSeqHiAndReserved_ (0),
00060       clockSeqLow_ (0),
00061       node_ (0),
00062       node_release_ (true),
00063       as_string_ (0)
00064   {
00065     ACE_NEW (node_,
00066              UUID_node);
00067   }
00068 
00069   /// Construct a UUID from a string representation of an UUID.
00070   UUID::UUID (const ACE_CString& uuid_string)
00071     : timeLow_ (0),
00072       timeMid_ (0),
00073       timeHiAndVersion_ (0),
00074       clockSeqHiAndReserved_ (0),
00075       clockSeqLow_ (0),
00076       node_ (0),
00077       node_release_ (true),
00078       as_string_ (0)
00079   {
00080     ACE_NEW (node_,
00081              UUID_node);
00082 
00083     this->from_string_i (uuid_string);
00084   }
00085 
00086   UUID::UUID(const UUID &right)
00087     : timeLow_ (right.timeLow_),
00088       timeMid_ (right.timeMid_),
00089       timeHiAndVersion_ (right.timeHiAndVersion_),
00090       clockSeqHiAndReserved_ (right.clockSeqHiAndReserved_),
00091       clockSeqLow_ (right.clockSeqLow_),
00092       as_string_ (0)
00093   {
00094     ACE_NEW (node_,
00095              UUID_node (*right.node_));
00096   }
00097 
00098   UUID::~UUID (void)
00099   {
00100     if (node_release_)
00101       delete node_;
00102 
00103     if (as_string_ != 0)
00104       delete as_string_;
00105   }
00106 
00107   const ACE_CString*
00108   UUID::to_string (void)
00109   {
00110     /// Only compute the string representation once.
00111     if (as_string_ == 0)
00112       {
00113         // Get a buffer exactly the correct size. Use the nil UUID as a
00114         // gauge.  Don't forget the trailing nul.
00115         size_t UUID_STRING_LENGTH = 36 + thr_id_.length () + pid_.length ();
00116         char *buf = 0;
00117 
00118         if ((thr_id_.length () != 0) && (pid_.length () != 0))
00119           {
00120             UUID_STRING_LENGTH += 2; //for '-'
00121             ACE_NEW_RETURN (buf,
00122                             char[UUID_STRING_LENGTH + 1],
00123                             0);
00124 
00125             ACE_OS::sprintf(buf,
00126                             "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x-%s-%s",
00127                             this->timeLow_,
00128                             this->timeMid_,
00129                             this->timeHiAndVersion_,
00130                             this->clockSeqHiAndReserved_,
00131                             this->clockSeqLow_,
00132                             (this->node_->nodeID ()) [0],
00133                             (this->node_->nodeID ()) [1],
00134                             (this->node_->nodeID ()) [2],
00135                             (this->node_->nodeID ()) [3],
00136                             (this->node_->nodeID ()) [4],
00137                             (this->node_->nodeID ()) [5],
00138                             thr_id_.c_str (),
00139                             pid_.c_str ()
00140                             );
00141           }
00142         else
00143           {
00144             ACE_NEW_RETURN (buf,
00145                             char[UUID_STRING_LENGTH + 1],
00146                             0);
00147 
00148             ACE_OS::sprintf (buf,
00149                              "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
00150                              this->timeLow_,
00151                              this->timeMid_,
00152                              this->timeHiAndVersion_,
00153                              this->clockSeqHiAndReserved_,
00154                              this->clockSeqLow_,
00155                              (this->node_->nodeID ()) [0],
00156                              (this->node_->nodeID ()) [1],
00157                              (this->node_->nodeID ()) [2],
00158                              (this->node_->nodeID ()) [3],
00159                              (this->node_->nodeID ()) [4],
00160                              (this->node_->nodeID ()) [5]
00161                              );
00162           }
00163 
00164         // We allocated 'buf' above dynamically, so we shouldn't use
00165         // ACE_NEW_RETURN here to avoid a possible memory leak.
00166         ACE_NEW_NORETURN (this->as_string_,
00167                           ACE_CString (buf, UUID_STRING_LENGTH));
00168 
00169         // we first free the dynamically allocated 'buf'.
00170         delete [] buf;
00171 
00172         // then we test that ACE_NEW succeded for 'as_string_'
00173         // if not, we return 0 (NULL) to indicate failure.
00174         if( this->as_string_ == 0 )
00175         {
00176            return 0;
00177         }
00178       }
00179 
00180     return as_string_;
00181   }
00182 
00183   void
00184   UUID::from_string_i (const ACE_CString& uuid_string)
00185   {
00186     if (uuid_string.length() < NIL_UUID.to_string ()->length ())
00187       {
00188         ACE_ERROR ((LM_ERROR,
00189                     "%N ACE_UUID::from_string_i - "
00190                     "IllegalArgument(incorrect string length)\n"));
00191         return;
00192       }
00193 
00194     /// Special case for the nil UUID.
00195     if (uuid_string == *NIL_UUID.to_string ())
00196       {
00197         bool copy_constructor_not_supported = false;
00198         ACE_ASSERT (copy_constructor_not_supported);
00199         //*this = NIL_UUID;
00200         ACE_UNUSED_ARG (copy_constructor_not_supported);
00201         return;
00202       }
00203 
00204     unsigned int timeLow;
00205     unsigned int timeMid;
00206     unsigned int timeHiAndVersion;
00207     unsigned int clockSeqHiAndReserved;
00208     unsigned int clockSeqLow;
00209     unsigned int node [UUID_node::NODE_ID_SIZE];
00210     char thr_pid_buf [BUFSIZ];
00211 
00212     if (uuid_string.length() == NIL_UUID.to_string()->length())
00213       {
00214         // This might seem quite strange this being in ACE, but it
00215         // seems to be a bit difficult to write a facade for ::sscanf
00216         // because some compilers dont support vsscanf, including
00217         // MSVC. It appears that most platforms support sscanf though
00218         // so we need to use it directly.
00219         const int nScanned =
00220 #if defined (ACE_HAS_TR24731_2005_CRT)
00221           sscanf_s (
00222 #else
00223           ::sscanf(
00224 #endif
00225                    uuid_string.c_str(),
00226                    "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
00227                    &timeLow,
00228                    &timeMid,
00229                    &timeHiAndVersion,
00230                    &clockSeqHiAndReserved,
00231                    &clockSeqLow,
00232                    &node[0],
00233                    &node[1],
00234                    &node[2],
00235                    &node[3],
00236                    &node[4],
00237                    &node[5]
00238                    );
00239 
00240         if (nScanned != 11)
00241           {
00242             ACE_DEBUG ((LM_DEBUG,
00243                         "UUID::from_string_i - "
00244                         "IllegalArgument(invalid string representation)\n"));
00245             return;
00246           }
00247       }
00248     else
00249       {
00250         const int nScanned =
00251 #if defined (ACE_HAS_TR24731_2005_CRT)
00252           sscanf_s (uuid_string.c_str(),
00253                     "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
00254                     &timeLow,
00255                     &timeMid,
00256                     &timeHiAndVersion,
00257                     &clockSeqHiAndReserved,
00258                     &clockSeqLow,
00259                     &node[0],
00260                     &node[1],
00261                     &node[2],
00262                     &node[3],
00263                     &node[4],
00264                     &node[5],
00265                     thr_pid_buf,
00266                     BUFSIZ
00267                     );
00268 #else
00269           ::sscanf (uuid_string.c_str(),
00270                     "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
00271                     &timeLow,
00272                     &timeMid,
00273                     &timeHiAndVersion,
00274                     &clockSeqHiAndReserved,
00275                     &clockSeqLow,
00276                     &node[0],
00277                     &node[1],
00278                     &node[2],
00279                     &node[3],
00280                     &node[4],
00281                     &node[5],
00282                     thr_pid_buf
00283                     );
00284 #endif /* ACE_HAS_TR24731_2005_CRT */
00285 
00286         if (nScanned != 12)
00287           {
00288             ACE_DEBUG ((LM_DEBUG,
00289                         "ACE_UUID::from_string_i - "
00290                         "IllegalArgument(invalid string representation)\n"));
00291             return;
00292           }
00293       }
00294 
00295     this->timeLow_ = static_cast<ACE_UINT32> (timeLow);
00296     this->timeMid_ = static_cast<ACE_UINT16> (timeMid);
00297     this->timeHiAndVersion_ = static_cast<ACE_UINT16> (timeHiAndVersion);
00298     this->clockSeqHiAndReserved_ = static_cast<u_char> (clockSeqHiAndReserved);
00299     this->clockSeqLow_ = static_cast<u_char> (clockSeqLow);
00300 
00301     UUID_node::NodeID nodeID;
00302     for (int i = 0; i < UUID_node::NODE_ID_SIZE; ++i)
00303       nodeID [i] = static_cast<u_char> (node[i]);
00304 
00305     this->node_->nodeID (nodeID);
00306 
00307     // Support varient 10- only
00308     if ((this->clockSeqHiAndReserved_ & 0xc0) != 0x80 && (this->clockSeqHiAndReserved_ & 0xc0) != 0xc0)
00309       {
00310         ACE_DEBUG ((LM_DEBUG,
00311                     "ACE_UUID::from_string_i - "
00312                     "IllegalArgument(unsupported variant)\n"));
00313         return;
00314       }
00315 
00316     /// Support versions 1, 3, and 4 only
00317     ACE_UINT16 V1 = this->timeHiAndVersion_;
00318 
00319     if ((V1 & 0xF000) != 0x1000 &&
00320         (V1 & 0xF000) != 0x3000 &&
00321       (V1 & 0xF000) != 0x4000)
00322       {
00323         ACE_DEBUG ((LM_DEBUG,
00324                     "ACE_UUID::from_string_i - "
00325                     "IllegalArgument(unsupported version)\n"));
00326         return;
00327       }
00328     if ((this->clockSeqHiAndReserved_ & 0xc0) == 0xc0)
00329       {
00330         if (uuid_string.length() == NIL_UUID.to_string()->length())
00331           {
00332             ACE_DEBUG ((LM_DEBUG,
00333                       "ACE_UUID::from_string_i - "
00334                         "IllegalArgument (Missing Thread and Process Id)\n"));
00335             return;
00336           }
00337         ACE_CString thr_pid_str (thr_pid_buf);
00338         ssize_t pos = static_cast<ssize_t> (thr_pid_str.find ('-'));
00339         if (pos == -1)
00340           ACE_DEBUG ((LM_DEBUG,
00341                       "ACE_UUID::from_string_i - "
00342                       "IllegalArgument (Thread and Process Id format incorrect)\n"));
00343 
00344         this->thr_id_ = thr_pid_str.substr (0, pos);
00345       this->pid_ = thr_pid_str.substr (pos+1, thr_pid_str.length ()-pos-1);
00346       }
00347   }
00348 
00349   UUID_Generator::UUID_Generator ()
00350     : timeLast_ (0),
00351       destroy_lock_ (true)
00352   {
00353     ACE_NEW (lock_,
00354              ACE_SYNCH_MUTEX);
00355   }
00356 
00357   UUID_Generator::~UUID_Generator()
00358   {
00359     if (destroy_lock_)
00360       delete lock_;
00361   }
00362 
00363   void
00364   UUID_Generator::init (void)
00365   {
00366     ACE_OS::macaddr_node_t macaddress;
00367     int result = ACE_OS::getmacaddress (&macaddress);
00368 
00369     UUID_node::NodeID nodeID;
00370     if (result != -1)
00371       {
00372 //         ACE_DEBUG ((LM_DEBUG,
00373 //                     "%02X-%02X-%02X-%02X-%02X-%02X\n",
00374 //                     macaddress.node [0],
00375 //                     macaddress.node [1],
00376 //                     macaddress.node [2],
00377 //                     macaddress.node [3],
00378 //                     macaddress.node [4],
00379 //                     macaddress.node [5]));
00380 
00381         ACE_OS::memcpy (&nodeID,
00382                         macaddress.node,
00383                         sizeof (nodeID));
00384       }
00385     else
00386       {
00387         nodeID [0] = static_cast<u_char> (ACE_OS::rand());
00388         nodeID [1] = static_cast<u_char> (ACE_OS::rand());
00389         nodeID [2] = static_cast<u_char> (ACE_OS::rand());
00390         nodeID [3] = static_cast<u_char> (ACE_OS::rand());
00391         nodeID [4] = static_cast<u_char> (ACE_OS::rand());
00392         nodeID [5] = static_cast<u_char> (ACE_OS::rand());
00393       }
00394 
00395     this->get_timestamp (timeLast_);
00396 
00397     {
00398       ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, *lock_);
00399       uuid_state_.timestamp = timeLast_;
00400       uuid_state_.node.nodeID (nodeID);
00401     }
00402   }
00403 
00404 
00405   void
00406   UUID_Generator::generateUUID (UUID& uuid,ACE_UINT16 version, u_char variant)
00407   {
00408     UUID_time timestamp;
00409     this->get_timestamp (timestamp);
00410 
00411 
00412     // Construct a Version 1 UUID with the information in the arguements.
00413     uuid.timeLow (static_cast<ACE_UINT32> (timestamp & 0xFFFFFFFF));
00414     uuid.timeMid (static_cast<ACE_UINT16> ((timestamp >> 32) & 0xFFFF));
00415 
00416 
00417     ACE_UINT16 tHAV = static_cast<ACE_UINT16> ((timestamp >> 48) & 0xFFFF);
00418     tHAV |= (version << 12);
00419     uuid.timeHiAndVersion (tHAV);
00420 
00421     u_char cseqHAV;
00422     {
00423       ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
00424       uuid.clockSeqLow (static_cast<u_char> (uuid_state_.clockSequence & 0xFF));
00425       cseqHAV = static_cast<u_char> ((uuid_state_.clockSequence & 0x3f00) >> 8);
00426       uuid_state_.timestamp = timestamp;
00427     }
00428 
00429     cseqHAV |= variant;
00430     uuid.clockSeqHiAndReserved (cseqHAV);
00431     uuid.node (&(uuid_state_.node));
00432 
00433     if (variant == 0xc0)
00434     {
00435       ACE_Thread_ID thread_id;
00436       char buf [BUFSIZ];
00437       thread_id.to_string (buf);
00438       uuid.thr_id (buf);
00439 
00440       ACE_OS::sprintf (buf,
00441                        "%d",
00442                        static_cast<int> (ACE_OS::getpid ()));
00443       uuid.pid (buf);
00444     }
00445   }
00446 
00447   UUID*
00448   UUID_Generator::generateUUID (ACE_UINT16 version, u_char variant)
00449   {
00450     UUID* uuid;
00451     ACE_NEW_RETURN (uuid,
00452                     UUID,
00453                     0);
00454 
00455     this->generateUUID (*uuid, version, variant);
00456     return uuid;
00457   }
00458 
00459   /// Obtain a new timestamp. If UUID's are being generated too quickly
00460   /// the clock sequence will be incremented
00461   void
00462   UUID_Generator::get_timestamp (UUID_time& timestamp)
00463   {
00464     ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
00465 
00466     this->get_systemtime(timestamp);
00467 
00468     // Account for the clock being set back. Increment the clock /
00469     // sequence.
00470     if (timestamp <= timeLast_)
00471       uuid_state_.clockSequence = static_cast<u_char> ((uuid_state_.clockSequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
00472 
00473     // If the system time ticked since the last UUID was
00474     // generated. Set / the clock sequence back.
00475     else if (timestamp > timeLast_)
00476       uuid_state_.clockSequence = 0;
00477 
00478     timeLast_ = timestamp;
00479   }
00480 
00481   /**
00482    * ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use
00483    * time in 100ns ticks since 15 October 1582. The difference is:
00484    *   15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov,  31 in Dec +
00485    *       17 years and 4 leap days (1584, 88, 92 and 96)
00486    *   1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent.
00487    *       and 24 each in 18th and 19th centuries)
00488    *   1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days.
00489    * This adds up, in days: (17+30+31+365*17+4)+(365*300+73)+(365*70+17) or
00490    * 122192928000000000U (0x1B21DD213814000) 100 ns ticks.
00491    */
00492   void
00493   UUID_Generator::get_systemtime (UUID_time & timestamp)
00494   {
00495     const UUID_time timeOffset =
00496 #if defined (ACE_LACKS_UNSIGNEDLONGLONG_T)
00497       ACE_U_LongLong (ACE_INT64_LITERAL (0x1B21DD213814000));
00498 #elif defined (ACE_LACKS_LONGLONG_T)
00499       ACE_U_LongLong (0x13814000u, 0x1B21DD2u);
00500 #else
00501       ACE_UINT64_LITERAL (0x1B21DD213814000);
00502 #endif  /* ACE_LACKS_UNSIGNEDLONGLONG_T */
00503 
00504     /// Get the time of day, convert to 100ns ticks then add the offset.
00505     ACE_Time_Value now = ACE_OS::gettimeofday();
00506     ACE_UINT64 time;
00507     now.to_usec (time);
00508     time = time * 10;
00509     timestamp = time + timeOffset;
00510 }
00511 
00512   ACE_SYNCH_MUTEX*
00513   UUID_Generator::lock (void)
00514   {
00515     return this->lock_;
00516   }
00517 
00518   void
00519   UUID_Generator::lock (ACE_SYNCH_MUTEX* lock,
00520                         bool release_lock)
00521   {
00522     if (this->destroy_lock_)
00523       delete this->lock_;
00524 
00525     this->lock_ = lock;
00526     this->destroy_lock_ = release_lock;
00527   }
00528 
00529 }
00530 
00531 #if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
00532 template ACE_Singleton<ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX> *
00533   ACE_Singleton<ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX>::singleton_;
00534 #endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
00535 
00536 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Sun Jan 27 12:05:43 2008 for ACE by doxygen 1.3.6