Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / UUID.cpp
blob9f57dbe0f8c4fe90970a04273bb5f43747e70f80
1 #include "ace/UUID.h"
2 #include "ace/Guard_T.h"
4 #if !defined (__ACE_INLINE__)
5 #include "ace/UUID.inl"
6 #endif /* __ACE_INLINE__ */
8 #include "ace/Log_Category.h"
9 #include "ace/OS_NS_stdio.h"
10 #include "ace/OS_NS_string.h"
11 #include "ace/OS_NS_sys_time.h"
12 #include "ace/OS_NS_netdb.h"
13 #include "ace/OS_NS_unistd.h"
14 #include "ace/ACE.h"
15 #include <memory>
17 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
19 namespace ACE_Utils
21 // NIL version of the UUID
22 const UUID UUID::NIL_UUID;
24 #ifndef ACE_LACKS_SSCANF
25 UUID::UUID (const ACE_CString& uuid_string)
27 this->init ();
28 this->from_string_i (uuid_string);
30 #endif /* ACE_LACKS_SSCANF */
32 ACE_ALLOC_HOOK_DEFINE(UUID);
34 const UUID &
35 UUID::operator = (const UUID & rhs)
37 if (this != &rhs)
39 // Reset the string version of the UUID a string version
40 // exist, and the UUID is not equal to the old UUID.
41 if (0 != this->as_string_.get ())
43 if (0 == rhs.as_string_.get () || *this != rhs)
44 this->as_string_.reset ();
47 // Copy the contents of the UUID.
48 ACE_OS::memcpy (&this->uuid_, &rhs.uuid_, BINARY_SIZE);
50 /// @todo We should create an UUID_Ex class for UUIDs that
51 /// contain the thread id and process id.
52 this->thr_id_ = rhs.thr_id_;
53 this->pid_ = rhs.pid_;
56 return *this;
59 const ACE_CString * UUID::to_string () const
61 // Compute the string representation only once.
62 if (0 != this->as_string_.get ())
63 return this->as_string_.get ();
65 // Get a buffer exactly the correct size. Use the nil UUID as a
66 // gauge. Don't forget the trailing nul.
67 std::unique_ptr <char[]> auto_clean;
68 size_t UUID_STRING_LENGTH = 36 + thr_id_.length () + pid_.length ();
69 char *buf = 0;
71 if (36 == UUID_STRING_LENGTH)
73 #if defined (ACE_HAS_ALLOC_HOOKS)
74 ACE_ALLOCATOR_RETURN (buf,
75 static_cast<char*> (ACE_Allocator::instance()->malloc(sizeof (char) * (UUID_STRING_LENGTH + 1))),
76 0);
77 #else
78 ACE_NEW_RETURN (buf,
79 char[UUID_STRING_LENGTH + 1],
80 0);
81 #endif /* ACE_HAS_ALLOC_HOOKS */
83 // Let the auto array pointer manage the buffer.
84 auto_clean.reset (buf);
86 ACE_OS::snprintf (buf, UUID_STRING_LENGTH + 1,
87 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
88 this->uuid_.time_low_,
89 this->uuid_.time_mid_,
90 this->uuid_.time_hi_and_version_,
91 this->uuid_.clock_seq_hi_and_reserved_,
92 this->uuid_.clock_seq_low_,
93 this->uuid_.node_.node_ID ()[0],
94 this->uuid_.node_.node_ID ()[1],
95 this->uuid_.node_.node_ID ()[2],
96 this->uuid_.node_.node_ID ()[3],
97 this->uuid_.node_.node_ID ()[4],
98 this->uuid_.node_.node_ID ()[5]);
100 else
102 UUID_STRING_LENGTH += 2; //for '-'
104 #if defined (ACE_HAS_ALLOC_HOOKS)
105 ACE_ALLOCATOR_RETURN (buf,
106 static_cast<char*> (ACE_Allocator::instance()->malloc(sizeof (char) * (UUID_STRING_LENGTH + 1))),
108 #else
109 ACE_NEW_RETURN (buf,
110 char[UUID_STRING_LENGTH + 1],
112 #endif /* ACE_HAS_ALLOC_HOOKS */
114 // Let the auto array pointer manage the buffer.
115 auto_clean.reset (buf);
117 ACE_OS::snprintf (buf, UUID_STRING_LENGTH + 1,
118 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x-%s-%s",
119 this->uuid_.time_low_,
120 this->uuid_.time_mid_,
121 this->uuid_.time_hi_and_version_,
122 this->uuid_.clock_seq_hi_and_reserved_,
123 this->uuid_.clock_seq_low_,
124 this->uuid_.node_.node_ID ()[0],
125 this->uuid_.node_.node_ID ()[1],
126 this->uuid_.node_.node_ID ()[2],
127 this->uuid_.node_.node_ID ()[3],
128 this->uuid_.node_.node_ID ()[4],
129 this->uuid_.node_.node_ID ()[5],
130 thr_id_.c_str (),
131 pid_.c_str ());
134 // Save the string.
135 ACE_CString * as_string = 0;
137 ACE_NEW_RETURN (as_string,
138 ACE_CString (buf, UUID_STRING_LENGTH),
141 this->as_string_.reset (as_string);
142 return this->as_string_.get ();
145 #ifndef ACE_LACKS_SSCANF
146 void
147 UUID::from_string_i (const ACE_CString& uuid_string)
149 if (uuid_string.length () < NIL_UUID.to_string ()->length ())
151 ACELIB_ERROR ((LM_ERROR,
152 "%N ACE_UUID::from_string_i - "
153 "IllegalArgument (incorrect string length)\n"));
154 return;
157 /// Special case for the nil UUID.
158 if (uuid_string == *NIL_UUID.to_string ())
160 *this = NIL_UUID;
161 return;
164 unsigned int time_low;
165 unsigned int time_mid;
166 unsigned int time_hi_and_version;
167 unsigned int clock_seq_hi_and_reserved;
168 unsigned int clock_seq_low;
169 unsigned int node [UUID_Node::NODE_ID_SIZE];
170 char thr_pid_buf [BUFSIZ];
172 if (uuid_string.length () == NIL_UUID.to_string ()->length ())
174 // This might seem quite strange this being in ACE, but it
175 // seems to be a bit difficult to write a facade for ::sscanf
176 // because some compilers dont support vsscanf, including
177 // MSVC. It appears that most platforms support sscanf though
178 // so we need to use it directly.
179 const int nScanned =
180 #if defined (ACE_HAS_TR24731_2005_CRT)
181 sscanf_s (
182 uuid_string.c_str (),
183 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
184 &time_low,
185 &time_mid,
186 &time_hi_and_version,
187 &clock_seq_hi_and_reserved,
188 &clock_seq_low,
189 &node[0],
190 &node[1],
191 &node[2],
192 &node[3],
193 &node[4],
194 &node[5]
196 #else
197 ::sscanf (
198 uuid_string.c_str (),
199 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
200 &time_low,
201 &time_mid,
202 &time_hi_and_version,
203 &clock_seq_hi_and_reserved,
204 &clock_seq_low,
205 &node[0],
206 &node[1],
207 &node[2],
208 &node[3],
209 &node[4],
210 &node[5]
212 #endif /* ACE_HAS_TR24731_2005_CRT */
214 if (nScanned != 11)
216 ACELIB_DEBUG ((LM_DEBUG,
217 "UUID::from_string_i - "
218 "IllegalArgument (invalid string representation)\n"));
219 return;
222 else
224 const int nScanned =
225 #if defined (ACE_HAS_TR24731_2005_CRT)
226 sscanf_s (uuid_string.c_str (),
227 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
228 &time_low,
229 &time_mid,
230 &time_hi_and_version,
231 &clock_seq_hi_and_reserved,
232 &clock_seq_low,
233 &node[0],
234 &node[1],
235 &node[2],
236 &node[3],
237 &node[4],
238 &node[5],
239 thr_pid_buf,
240 BUFSIZ
242 #else
243 ::sscanf (uuid_string.c_str (),
244 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
245 &time_low,
246 &time_mid,
247 &time_hi_and_version,
248 &clock_seq_hi_and_reserved,
249 &clock_seq_low,
250 &node[0],
251 &node[1],
252 &node[2],
253 &node[3],
254 &node[4],
255 &node[5],
256 thr_pid_buf
258 #endif /* ACE_HAS_TR24731_2005_CRT */
260 if (nScanned != 12)
262 ACELIB_DEBUG ((LM_DEBUG,
263 "ACE_UUID::from_string_i - "
264 "IllegalArgument (invalid string representation)\n"));
265 return;
269 this->uuid_.time_low_ = static_cast<ACE_UINT32> (time_low);
270 this->uuid_.time_mid_ = static_cast<ACE_UINT16> (time_mid);
271 this->uuid_.time_hi_and_version_ = static_cast<ACE_UINT16> (time_hi_and_version);
272 this->uuid_.clock_seq_hi_and_reserved_ = static_cast<u_char> (clock_seq_hi_and_reserved);
273 this->uuid_.clock_seq_low_ = static_cast<u_char> (clock_seq_low);
275 for (size_t i = 0; i < UUID_Node::NODE_ID_SIZE; ++ i)
276 this->uuid_.node_.node_ID ()[i] = static_cast <u_char> (node[i]);
278 // Support varient 10- only
279 if ((this->uuid_.clock_seq_hi_and_reserved_ & 0xc0) != 0x80 &&
280 (this->uuid_.clock_seq_hi_and_reserved_ & 0xc0) != 0xc0)
282 ACELIB_DEBUG ((LM_DEBUG,
283 "ACE_UUID::from_string_i - "
284 "IllegalArgument (unsupported variant)\n"));
285 return;
288 /// Support versions 1, 3, and 4 only
289 ACE_UINT16 V1 = this->uuid_.time_hi_and_version_;
291 if ((V1 & 0xF000) != 0x1000 &&
292 (V1 & 0xF000) != 0x3000 &&
293 (V1 & 0xF000) != 0x4000)
295 ACELIB_DEBUG ((LM_DEBUG,
296 "ACE_UUID::from_string_i - "
297 "IllegalArgument (unsupported version)\n"));
298 return;
301 if ((this->uuid_.clock_seq_hi_and_reserved_ & 0xc0) == 0xc0)
303 if (uuid_string.length () == NIL_UUID.to_string ()->length ())
305 ACELIB_DEBUG ((LM_DEBUG,
306 "ACE_UUID::from_string_i - "
307 "IllegalArgument (Missing Thread and Process Id)\n"));
308 return;
310 ACE_CString thr_pid_str (thr_pid_buf);
311 ssize_t pos = static_cast<ssize_t> (thr_pid_str.find ('-'));
312 if (pos == -1)
313 ACELIB_DEBUG ((LM_DEBUG,
314 "ACE_UUID::from_string_i - "
315 "IllegalArgument (Thread and Process Id format incorrect)\n"));
317 this->thr_id_ = thr_pid_str.substr (0, pos);
318 this->pid_ = thr_pid_str.substr (pos+1, thr_pid_str.length ()-pos-1);
321 #endif // ACE_LACKS_SSCANF
323 UUID_Generator::UUID_Generator ()
324 : time_last_ (0),
325 destroy_lock_ (true),
326 is_init_ (false)
328 ACE_NEW (lock_, ACE_SYNCH_MUTEX);
329 this->init ();
332 UUID_Generator::~UUID_Generator ()
334 if (destroy_lock_)
335 delete lock_;
338 void
339 UUID_Generator::init ()
341 if (this->is_init_)
342 return;
344 ACE_OS::macaddr_node_t macaddress;
345 int const result = ACE_OS::getmacaddress (&macaddress);
347 UUID_Node::Node_ID node_id;
349 if (-1 != result)
351 ACE_OS::memcpy (node_id,
352 macaddress.node,
353 UUID_Node::NODE_ID_SIZE);
355 else
357 node_id [0] = static_cast<u_char> (ACE_OS::rand ());
358 node_id [1] = static_cast<u_char> (ACE_OS::rand ());
359 node_id [2] = static_cast<u_char> (ACE_OS::rand ());
360 node_id [3] = static_cast<u_char> (ACE_OS::rand ());
361 node_id [4] = static_cast<u_char> (ACE_OS::rand ());
362 node_id [5] = static_cast<u_char> (ACE_OS::rand ());
365 this->get_timestamp (time_last_);
368 ACE_GUARD (ACE_SYNCH_MUTEX, ace_mon, *lock_);
369 uuid_state_.timestamp = time_last_;
371 ACE_OS::memcpy (uuid_state_.node.node_ID (),
372 node_id,
373 UUID_Node::NODE_ID_SIZE);
376 this->is_init_ = true;
379 void
380 UUID_Generator::
381 generate_UUID (UUID& uuid, ACE_UINT16 version, u_char variant)
383 UUID_Time timestamp = 0;
384 ACE_UINT16 clock_sequence = 0;
386 this->get_timestamp_and_clocksequence (timestamp,
387 clock_sequence);
389 // Construct a Version 1 UUID with the information in the arguements.
390 uuid.time_low (static_cast<ACE_UINT32> (timestamp & 0xFFFFFFFF));
391 uuid.time_mid (static_cast<ACE_UINT16> ((timestamp >> 32) & 0xFFFF));
393 ACE_UINT16 tHAV = static_cast<ACE_UINT16> ((timestamp >> 48) & 0xFFFF);
394 tHAV = static_cast<ACE_UINT16> (tHAV | (version << 12));
395 uuid.time_hi_and_version (tHAV);
397 u_char cseqHAV;
398 uuid.clock_seq_low (static_cast<u_char> (clock_sequence & 0xFF));
399 cseqHAV = static_cast<u_char> ((clock_sequence & 0x3f00) >> 8);
400 uuid_state_.timestamp = timestamp;
402 cseqHAV = static_cast<u_char> (cseqHAV | variant);
403 uuid.clock_seq_hi_and_reserved (cseqHAV);
404 uuid.node (uuid_state_.node);
406 if (variant == 0xc0)
408 ACE_Thread_ID thread_id;
409 char buf [BUFSIZ];
410 thread_id.to_string (buf, BUFSIZ);
411 uuid.thr_id (buf);
413 ACE_OS::snprintf (buf, BUFSIZ, "%d",
414 static_cast<int> (ACE_OS::getpid ()));
415 uuid.pid (buf);
419 UUID*
420 UUID_Generator::generate_UUID (ACE_UINT16 version, u_char variant)
422 UUID* uuid = 0;
423 ACE_NEW_RETURN (uuid,
424 UUID,
427 this->generate_UUID (*uuid, version, variant);
428 return uuid;
431 /// Obtain a new timestamp. If UUID's are being generated too quickly
432 /// the clock sequence will be incremented
433 void
434 UUID_Generator::get_timestamp (UUID_Time& timestamp)
436 ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
438 this->get_systemtime (timestamp);
440 // Account for the clock being set back. Increment the clock /
441 // sequence.
442 if (timestamp <= time_last_)
444 uuid_state_.clock_sequence = static_cast<ACE_UINT16>
445 ((uuid_state_.clock_sequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
447 // If the system time ticked since the last UUID was
448 // generated. Set / the clock sequence back.
449 else if (timestamp > time_last_)
451 uuid_state_.clock_sequence = 0;
454 time_last_ = timestamp;
457 void
458 UUID_Generator::get_timestamp_and_clocksequence (UUID_Time& timestamp,
459 ACE_UINT16& clock_sequence)
461 ACE_GUARD (ACE_SYNCH_MUTEX, mon, *lock_);
463 this->get_systemtime (timestamp);
465 // Account for the clock being set back. Increment the clock /
466 // sequence.
467 if (timestamp <= time_last_)
468 uuid_state_.clock_sequence = static_cast<ACE_UINT16> ((uuid_state_.clock_sequence + 1) & ACE_UUID_CLOCK_SEQ_MASK);
470 // If the system time ticked since the last UUID was
471 // generated. Set / the clock sequence back.
472 else if (timestamp > time_last_)
473 uuid_state_.clock_sequence = 0;
475 time_last_ = timestamp;
476 clock_sequence = uuid_state_.clock_sequence;
480 * ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use
481 * time in 100ns ticks since 15 October 1582. The difference is:
482 * 15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov, 31 in Dec +
483 * 17 years and 4 leap days (1584, 88, 92 and 96)
484 * 1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent.
485 * and 24 each in 18th and 19th centuries)
486 * 1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days.
487 * This adds up, in days: (17+30+31+365*17+4)+ (365*300+73)+ (365*70+17) or
488 * 122192928000000000U (0x1B21DD213814000) 100 ns ticks.
490 void
491 UUID_Generator::get_systemtime (UUID_Time & timestamp)
493 const UUID_Time timeOffset =
494 ACE_UINT64_LITERAL (0x1B21DD213814000);
496 /// Get the time of day, convert to 100ns ticks then add the offset.
497 ACE_Time_Value now = ACE_OS::gettimeofday ();
498 ACE_UINT64 time;
499 now.to_usec (time);
500 time = time * 10;
501 timestamp = time + timeOffset;
504 ACE_SYNCH_MUTEX*
505 UUID_Generator::lock ()
507 return this->lock_;
510 void
511 UUID_Generator::lock (ACE_SYNCH_MUTEX* lock, bool release_lock)
513 if (this->destroy_lock_)
514 delete this->lock_;
516 this->lock_ = lock;
517 this->destroy_lock_ = release_lock;
521 ACE_SINGLETON_TEMPLATE_INSTANTIATE(ACE_Singleton, ACE_Utils::UUID_Generator, ACE_SYNCH_MUTEX);
523 ACE_END_VERSIONED_NAMESPACE_DECL