2 // Copyright (C) 2008 Francesco Salvestrini
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <stdlib.h> // XXX-FIXME to remove with rand/srand wraps in gnulib
31 #include <sys/time.h> // XXX-FIXME to remove with rand/srand wraps in gnulib
33 #include "libs/net/uuid.h"
38 static uint32_t myrand(uint32_t min
, uint32_t max
)
45 if (gettimeofday(&tv
, NULL
) == -1) {
50 fmax
= (max
!= 0xFFFFFFFF) ? (float) max
: (float)RAND_MAX
;
51 fmin
= min
? (float) min
: 0.0;
53 return (min
+ (uint32_t) (fmax
* (rand() / (RAND_MAX
+ 1.0))));
66 UUID::UUID(version_t version
)
68 memset(&uuid_
, 0, sizeof(uuid_
));
71 case IETF_RFC4122_TIMEBASED
: {
75 case DCE_SECURITY_POSIX_UID
: {
78 case IETF_RFC4122_NAMEBASED_MD5
: {
83 case IETF_RFC4122_NAMEBASED_SHA1
: {
88 case IETF_RFC4122_RANDOM
: {
93 throw invalid_version(version
,
94 "not supported in IETF RFC4122");
103 // NOTE (excerpt from wikipedia):
105 // In its canonical form, a UUID consists of 32 hexadecimal digits, displayed
106 // in 5 groups separated by hyphens, in the form 8-4-4-4-12 for a total of
107 // 36 characters. For example:
109 // 550e8400-e29b-41d4-a716-446655440000
112 bool UUID::grab_8hex(const std::string
& u
,
113 std::string::size_type s
,
114 std::string::size_type e
,
122 tmp
= u
.substr(s
, e
);
127 v
= strtoul(t
, 0, 16);
132 bool UUID::grab_4hex(const std::string
& u
,
133 std::string::size_type s
,
134 std::string::size_type e
,
142 tmp
= u
.substr(s
, e
);
147 v
= strtoul(t
, 0, 16);
152 bool UUID::grab_12hex(const std::string
& u
,
153 std::string::size_type s
,
154 std::string::size_type e
,
162 tmp
= u
.substr(s
, e
);
168 for (i
= 0; i
< 6; i
++) {
170 buf
[1] = tmp
[i
* 2 + 1];
171 v
[i
] = strtoul(buf
, 0, 16);
177 UUID::UUID(const std::string
& u
)
179 std::string::size_type s
, e
;
183 // Grab the time-low part
184 e
= u
.find_first_of('-', s
);
185 if (!grab_8hex(u
, s
, e
, uuid_
.time_low
)) {
186 throw invalid_hexfield(1, "Wrong field-1");
190 // Grab the time-mid part
191 e
= u
.find_first_of('-', s
);
192 if (!grab_4hex(u
, s
, e
, uuid_
.time_mid
)) {
193 throw invalid_hexfield(2, "Wrong field-2");
197 // Grab the time-high-and-version part
198 e
= u
.find_first_of('-', s
);
199 if (!grab_4hex(u
, s
, e
, uuid_
.time_hi_and_version
)) {
200 throw invalid_hexfield(3, "Wrong field-3");
204 // Grab clock-seq-and-reserverd clock-seq-low part
206 if (!grab_4hex(u
, s
, e
, uuid_
.clock_seq
)) {
207 throw invalid_hexfield(4, "Wrong field-4");
211 // Grab the node part
213 if (!grab_12hex(u
, s
, e
, uuid_
.node
)) {
214 throw invalid_hexfield(5, "Wrong field-5");
220 void UUID::clear(void)
222 memset(&uuid_
, 0, sizeof(struct uuid
));
225 Net::UUID
& UUID::operator =(const UUID
& rhs
)
227 memcpy(&uuid_
, &rhs
.uuid_
, sizeof(struct uuid
));
232 bool UUID::operator ==(const UUID
& rhs
)
234 if (!memcmp(&uuid_
, &rhs
.uuid_
, sizeof(struct uuid
))) {
241 UUID::operator std::string(void)
245 s
<< std::hex
<< std::setw(8) << std::setfill('0')
248 s
<< std::hex
<< std::setw(4) << std::setfill('0')
251 s
<< std::hex
<< std::setw(4) << std::setfill('0')
252 << uuid_
.time_hi_and_version
;
254 s
<< std::hex
<< std::setw(4) << std::setfill('0')
259 for (i
= 0; i
< 6; i
++) {
260 s
<< std::hex
<< std::setw(2) << std::setfill('0')
261 << static_cast<int>(uuid_
.node
[i
]);
267 std::ostream
& operator <<(std::ostream
& stream
,
273 std::istream
& operator >>(std::istream
& stream
,
279 void UUID::format_uuid_tb(void)
281 throw generic_problem("XXX TO BE IMPLEMENTED");
284 void UUID::format_uuid_nb(void)
286 throw generic_problem("XXX TO BE IMPLEMENTED");
289 void UUID::format_uuid_random(void)
291 uuid_
.time_low
= myrand(0, 0xFFFFFFFF);
292 uuid_
.time_mid
= (uint16_t) myrand(0, 0xFFFF);
293 uuid_
.time_hi_and_version
= (uint16_t) myrand(0, 0xFFFF);
294 uuid_
.time_hi_and_version
&= 0x0FFF;
295 uuid_
.time_hi_and_version
|= (IETF_RFC4122_RANDOM
<< 12);
296 uuid_
.clock_seq
= (uint16_t) myrand(0, 0xFFFF);
297 uuid_
.clock_seq
&= 0x3FFF;
298 uuid_
.clock_seq
|= (0x2 << 14); // variant
301 for (i
= 0; i
< 6; i
++) {
302 uuid_
.node
[i
] = (uint8_t) myrand(0, 0xFF);
308 // This bit is the unicast/multicast bit, which will never be set in
309 // IEEE 802 addresses obtained from network cards. Hence, there can
310 // never be a conflict between UUIDs generated by machines with and
311 // without network cards.
312 uuid_
.node
[0] |= (0x1 << 7);
315 void UUID::scramble_sha1(void)
317 throw generic_problem("XXX TO BE IMPLEMENTED");
320 void UUID::scramble_md5(void)
322 throw generic_problem("XXX TO BE IMPLEMENTED");
326 void UUID::check_uuid(void)
331 ver
= (version_t
) (uuid_
.time_hi_and_version
>> 12);
332 variant
= (uuid_
.clock_seq
& 0xC000) >> 14;
335 throw formatting_problem(ver
,
337 "UUID has a fake variant");
341 case IETF_RFC4122_TIMEBASED
: {
345 case DCE_SECURITY_POSIX_UID
: {
349 case IETF_RFC4122_NAMEBASED_MD5
: {
353 case IETF_RFC4122_NAMEBASED_SHA1
: {
357 case IETF_RFC4122_RANDOM
: {
358 if (!(uuid_
.node
[0] >> 7)) {
359 throw formatting_problem(ver
,
368 throw formatting_problem(ver
,
370 "UUID has a fake version");