1 //$Id: UUID.cpp 81541 2008-04-30 13:56:12Z shuston $
4 #include "ace/Guard_T.h"
6 #if !defined (__ACE_INLINE__)
7 #include "ace/UUID.inl"
8 #endif /* __ACE_INLINE__ */
10 #include "ace/Log_Msg.h"
11 #include "ace/OS_NS_stdio.h"
12 #include "ace/OS_NS_string.h"
13 #include "ace/OS_NS_sys_time.h"
14 #include "ace/OS_NS_netdb.h"
15 #include "ace/OS_NS_unistd.h"
20 "$Id: UUID.cpp 81541 2008-04-30 13:56:12Z shuston $")
23 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
27 UUID_Node::UUID_Node (void)
29 for (int i
= 0; i
< UUID_Node::NODE_ID_SIZE
; ++i
)
34 UUID_Node::node_ID (void)
40 UUID_Node::node_ID (Node_ID
& node_ID
)
42 for (int i
= 0; i
< UUID_Node::NODE_ID_SIZE
; ++i
)
43 node_ID_
[i
] = node_ID
[i
];
48 /// Construct a nil UUID. Such a UUID has every one of it's data
49 /// elements set to zero.
53 time_hi_and_version_ (0),
54 clock_seq_hi_and_reserved_ (0),
64 /// Construct a UUID from a string representation of an UUID.
65 UUID::UUID (const ACE_CString
& uuid_string
)
68 time_hi_and_version_ (0),
69 clock_seq_hi_and_reserved_ (0),
78 this->from_string_i (uuid_string
);
81 UUID::UUID (const UUID
&right
)
82 : time_low_ (right
.time_low_
),
83 time_mid_ (right
.time_mid_
),
84 time_hi_and_version_ (right
.time_hi_and_version_
),
85 clock_seq_hi_and_reserved_ (right
.clock_seq_hi_and_reserved_
),
86 clock_seq_low_ (right
.clock_seq_low_
),
90 UUID_Node (*right
.node_
));
103 UUID::to_string (void)
105 /// Only compute the string representation once.
108 // Get a buffer exactly the correct size. Use the nil UUID as a
109 // gauge. Don't forget the trailing nul.
110 size_t UUID_STRING_LENGTH
= 36 + thr_id_
.length () + pid_
.length ();
113 if ((thr_id_
.length () != 0) && (pid_
.length () != 0))
115 UUID_STRING_LENGTH
+= 2; //for '-'
117 char[UUID_STRING_LENGTH
+ 1],
120 ACE_OS::sprintf (buf
,
121 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x-%s-%s",
124 this->time_hi_and_version_
,
125 this->clock_seq_hi_and_reserved_
,
126 this->clock_seq_low_
,
127 (this->node_
->node_ID ()) [0],
128 (this->node_
->node_ID ()) [1],
129 (this->node_
->node_ID ()) [2],
130 (this->node_
->node_ID ()) [3],
131 (this->node_
->node_ID ()) [4],
132 (this->node_
->node_ID ()) [5],
140 char[UUID_STRING_LENGTH
+ 1],
143 ACE_OS::sprintf (buf
,
144 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
147 this->time_hi_and_version_
,
148 this->clock_seq_hi_and_reserved_
,
149 this->clock_seq_low_
,
150 (this->node_
->node_ID ()) [0],
151 (this->node_
->node_ID ()) [1],
152 (this->node_
->node_ID ()) [2],
153 (this->node_
->node_ID ()) [3],
154 (this->node_
->node_ID ()) [4],
155 (this->node_
->node_ID ()) [5]
159 // We allocated 'buf' above dynamically, so we shouldn't use
160 // ACE_NEW_RETURN here to avoid a possible memory leak.
161 ACE_NEW_NORETURN (this->as_string_
,
162 ACE_CString (buf
, UUID_STRING_LENGTH
));
164 // we first free the dynamically allocated 'buf'.
167 // then we test that ACE_NEW succeded for 'as_string_'
168 // if not, we return 0 (NULL) to indicate failure.
169 if (this->as_string_
== 0 )
177 UUID::from_string_i (const ACE_CString
& uuid_string
)
179 if (uuid_string
.length () < NIL_UUID
.to_string ()->length ())
181 ACE_ERROR ((LM_ERROR
,
182 "%N ACE_UUID::from_string_i - "
183 "IllegalArgument (incorrect string length)\n"));
187 /// Special case for the nil UUID.
188 if (uuid_string
== *NIL_UUID
.to_string ())
190 bool copy_constructor_not_supported
= false;
191 ACE_ASSERT (copy_constructor_not_supported
);
193 ACE_UNUSED_ARG (copy_constructor_not_supported
);
197 unsigned int time_low
;
198 unsigned int time_mid
;
199 unsigned int time_hi_and_version
;
200 unsigned int clock_seq_hi_and_reserved
;
201 unsigned int clock_seq_low
;
202 unsigned int node
[UUID_Node::NODE_ID_SIZE
];
203 char thr_pid_buf
[BUFSIZ
];
205 if (uuid_string
.length () == NIL_UUID
.to_string ()->length ())
207 // This might seem quite strange this being in ACE, but it
208 // seems to be a bit difficult to write a facade for ::sscanf
209 // because some compilers dont support vsscanf, including
210 // MSVC. It appears that most platforms support sscanf though
211 // so we need to use it directly.
213 #if defined (ACE_HAS_TR24731_2005_CRT)
217 #endif /* ACE_HAS_TR24731_2005_CRT */
218 uuid_string
.c_str (),
219 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x",
222 &time_hi_and_version
,
223 &clock_seq_hi_and_reserved
,
235 ACE_DEBUG ((LM_DEBUG
,
236 "UUID::from_string_i - "
237 "IllegalArgument (invalid string representation)\n"));
244 #if defined (ACE_HAS_TR24731_2005_CRT)
245 sscanf_s (uuid_string
.c_str (),
246 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
249 &time_hi_and_version
,
250 &clock_seq_hi_and_reserved
,
262 ::sscanf (uuid_string
.c_str (),
263 "%8x-%4x-%4x-%2x%2x-%2x%2x%2x%2x%2x%2x-%s",
266 &time_hi_and_version
,
267 &clock_seq_hi_and_reserved
,
277 #endif /* ACE_HAS_TR24731_2005_CRT */
281 ACE_DEBUG ((LM_DEBUG
,
282 "ACE_UUID::from_string_i - "
283 "IllegalArgument (invalid string representation)\n"));
288 this->time_low_
= static_cast<ACE_UINT32
> (time_low
);
289 this->time_mid_
= static_cast<ACE_UINT16
> (time_mid
);
290 this->time_hi_and_version_
= static_cast<ACE_UINT16
> (time_hi_and_version
);
291 this->clock_seq_hi_and_reserved_
= static_cast<u_char
> (clock_seq_hi_and_reserved
);
292 this->clock_seq_low_
= static_cast<u_char
> (clock_seq_low
);
294 UUID_Node::Node_ID node_id
;
295 for (int i
= 0; i
< UUID_Node::NODE_ID_SIZE
; ++i
)
296 node_id
[i
] = static_cast<u_char
> (node
[i
]);
298 this->node_
->node_ID (node_id
);
300 // Support varient 10- only
301 if ((this->clock_seq_hi_and_reserved_
& 0xc0) != 0x80 && (this->clock_seq_hi_and_reserved_
& 0xc0) != 0xc0)
303 ACE_DEBUG ((LM_DEBUG
,
304 "ACE_UUID::from_string_i - "
305 "IllegalArgument (unsupported variant)\n"));
309 /// Support versions 1, 3, and 4 only
310 ACE_UINT16 V1
= this->time_hi_and_version_
;
312 if ((V1
& 0xF000) != 0x1000 &&
313 (V1
& 0xF000) != 0x3000 &&
314 (V1
& 0xF000) != 0x4000)
316 ACE_DEBUG ((LM_DEBUG
,
317 "ACE_UUID::from_string_i - "
318 "IllegalArgument (unsupported version)\n"));
322 if ((this->clock_seq_hi_and_reserved_
& 0xc0) == 0xc0)
324 if (uuid_string
.length () == NIL_UUID
.to_string ()->length ())
326 ACE_DEBUG ((LM_DEBUG
,
327 "ACE_UUID::from_string_i - "
328 "IllegalArgument (Missing Thread and Process Id)\n"));
331 ACE_CString
thr_pid_str (thr_pid_buf
);
332 ssize_t pos
= static_cast<ssize_t
> (thr_pid_str
.find ('-'));
334 ACE_DEBUG ((LM_DEBUG
,
335 "ACE_UUID::from_string_i - "
336 "IllegalArgument (Thread and Process Id format incorrect)\n"));
338 this->thr_id_
= thr_pid_str
.substr (0, pos
);
339 this->pid_
= thr_pid_str
.substr (pos
+1, thr_pid_str
.length ()-pos
-1);
343 UUID_Generator::UUID_Generator ()
351 UUID_Generator::~UUID_Generator ()
358 UUID_Generator::init (void)
360 ACE_OS::macaddr_node_t macaddress
;
361 int result
= ACE_OS::getmacaddress (&macaddress
);
363 UUID_Node::Node_ID node_id
;
366 // ACE_DEBUG ((LM_DEBUG,
367 // "%02X-%02X-%02X-%02X-%02X-%02X\n",
368 // macaddress.node [0],
369 // macaddress.node [1],
370 // macaddress.node [2],
371 // macaddress.node [3],
372 // macaddress.node [4],
373 // macaddress.node [5]));
375 ACE_OS::memcpy (&node_id
,
381 node_id
[0] = static_cast<u_char
> (ACE_OS::rand ());
382 node_id
[1] = static_cast<u_char
> (ACE_OS::rand ());
383 node_id
[2] = static_cast<u_char
> (ACE_OS::rand ());
384 node_id
[3] = static_cast<u_char
> (ACE_OS::rand ());
385 node_id
[4] = static_cast<u_char
> (ACE_OS::rand ());
386 node_id
[5] = static_cast<u_char
> (ACE_OS::rand ());
389 this->get_timestamp (time_last_
);
392 ACE_GUARD (ACE_SYNCH_MUTEX
, ace_mon
, *lock_
);
393 uuid_state_
.timestamp
= time_last_
;
394 uuid_state_
.node
.node_ID (node_id
);
399 UUID_Generator::generate_UUID (UUID
& uuid
,ACE_UINT16 version
,
403 ACE_UINT16 clock_sequence
;
405 this->get_timestamp_and_clocksequence (timestamp
,
408 // Construct a Version 1 UUID with the information in the arguements.
409 uuid
.time_low (static_cast<ACE_UINT32
> (timestamp
& 0xFFFFFFFF));
410 uuid
.time_mid (static_cast<ACE_UINT16
> ((timestamp
>> 32) & 0xFFFF));
412 ACE_UINT16 tHAV
= static_cast<ACE_UINT16
> ((timestamp
>> 48) & 0xFFFF);
413 tHAV
|= (version
<< 12);
414 uuid
.time_hi_and_version (tHAV
);
417 uuid
.clock_seq_low (static_cast<u_char
> (clock_sequence
& 0xFF));
418 cseqHAV
= static_cast<u_char
> ((clock_sequence
& 0x3f00) >> 8);
419 uuid_state_
.timestamp
= timestamp
;
422 uuid
.clock_seq_hi_and_reserved (cseqHAV
);
423 uuid
.node (& (uuid_state_
.node
));
427 ACE_Thread_ID thread_id
;
429 thread_id
.to_string (buf
);
432 ACE_OS::sprintf (buf
,
434 static_cast<int> (ACE_OS::getpid ()));
440 UUID_Generator::generate_UUID (ACE_UINT16 version
, u_char variant
)
443 ACE_NEW_RETURN (uuid
,
447 this->generate_UUID (*uuid
, version
, variant
);
451 /// Obtain a new timestamp. If UUID's are being generated too quickly
452 /// the clock sequence will be incremented
454 UUID_Generator::get_timestamp (UUID_Time
& timestamp
)
456 ACE_GUARD (ACE_SYNCH_MUTEX
, mon
, *lock_
);
458 this->get_systemtime (timestamp
);
460 // Account for the clock being set back. Increment the clock /
462 if (timestamp
<= time_last_
)
464 uuid_state_
.clock_sequence
= static_cast<ACE_UINT16
>
465 ((uuid_state_
.clock_sequence
+ 1) & ACE_UUID_CLOCK_SEQ_MASK
);
467 // If the system time ticked since the last UUID was
468 // generated. Set / the clock sequence back.
469 else if (timestamp
> time_last_
)
471 uuid_state_
.clock_sequence
= 0;
474 time_last_
= timestamp
;
478 UUID_Generator::get_timestamp_and_clocksequence (UUID_Time
& timestamp
,
479 ACE_UINT16
& clock_sequence
)
481 ACE_GUARD (ACE_SYNCH_MUTEX
, mon
, *lock_
);
483 this->get_systemtime (timestamp
);
485 // Account for the clock being set back. Increment the clock /
487 if (timestamp
<= time_last_
)
488 uuid_state_
.clock_sequence
= static_cast<ACE_UINT16
> ((uuid_state_
.clock_sequence
+ 1) & ACE_UUID_CLOCK_SEQ_MASK
);
490 // If the system time ticked since the last UUID was
491 // generated. Set / the clock sequence back.
492 else if (timestamp
> time_last_
)
493 uuid_state_
.clock_sequence
= 0;
495 time_last_
= timestamp
;
496 clock_sequence
= uuid_state_
.clock_sequence
;
500 * ACE_Time_Value is in POSIX time, seconds since Jan 1, 1970. UUIDs use
501 * time in 100ns ticks since 15 October 1582. The difference is:
502 * 15 Oct 1582 - 1 Jan 1600: 17 days in Oct, 30 in Nov, 31 in Dec +
503 * 17 years and 4 leap days (1584, 88, 92 and 96)
504 * 1 Jan 1600 - 1 Jan 1900: 3 centuries + 73 leap days ( 25 in 17th cent.
505 * and 24 each in 18th and 19th centuries)
506 * 1 Jan 1900 - 1 Jan 1970: 70 years + 17 leap days.
507 * This adds up, in days: (17+30+31+365*17+4)+ (365*300+73)+ (365*70+17) or
508 * 122192928000000000U (0x1B21DD213814000) 100 ns ticks.
511 UUID_Generator::get_systemtime (UUID_Time
& timestamp
)
513 const UUID_Time timeOffset
=
514 #if defined (ACE_LACKS_UNSIGNEDLONGLONG_T)
515 ACE_U_LongLong (ACE_INT64_LITERAL (0x1B21DD213814000));
516 #elif defined (ACE_LACKS_LONGLONG_T)
517 ACE_U_LongLong (0x13814000u
, 0x1B21DD2u
);
519 ACE_UINT64_LITERAL (0x1B21DD213814000);
520 #endif /* ACE_LACKS_UNSIGNEDLONGLONG_T */
522 /// Get the time of day, convert to 100ns ticks then add the offset.
523 ACE_Time_Value now
= ACE_OS::gettimeofday ();
527 timestamp
= time
+ timeOffset
;
531 UUID_Generator::lock (void)
537 UUID_Generator::lock (ACE_SYNCH_MUTEX
* lock
,
540 if (this->destroy_lock_
)
544 this->destroy_lock_
= release_lock
;
549 #if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
550 template ACE_Singleton
<ACE_Utils::UUID_Generator
, ACE_SYNCH_MUTEX
> *
551 ACE_Singleton
<ACE_Utils::UUID_Generator
, ACE_SYNCH_MUTEX
>::singleton_
;
552 #endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
554 ACE_END_VERSIONED_NAMESPACE_DECL