aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/lluuid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon/lluuid.cpp')
-rw-r--r--linden/indra/llcommon/lluuid.cpp923
1 files changed, 923 insertions, 0 deletions
diff --git a/linden/indra/llcommon/lluuid.cpp b/linden/indra/llcommon/lluuid.cpp
new file mode 100644
index 0000000..7e4eb50
--- /dev/null
+++ b/linden/indra/llcommon/lluuid.cpp
@@ -0,0 +1,923 @@
1/**
2 * @file lluuid.cpp
3 *
4 * $LicenseInfo:firstyear=2000&license=viewergpl$
5 *
6 * Copyright (c) 2000-2008, Linden Research, Inc.
7 *
8 * Second Life Viewer Source Code
9 * The source code in this file ("Source Code") is provided by Linden Lab
10 * to you under the terms of the GNU General Public License, version 2.0
11 * ("GPL"), unless you have obtained a separate licensing agreement
12 * ("Other License"), formally executed by you and Linden Lab. Terms of
13 * the GPL can be found in doc/GPL-license.txt in this distribution, or
14 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
15 *
16 * There are special exceptions to the terms and conditions of the GPL as
17 * it is applied to this Source Code. View the full text of the exception
18 * in the file doc/FLOSS-exception.txt in this software distribution, or
19 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
20 *
21 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above,
23 * and agree to abide by those obligations.
24 *
25 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
26 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
27 * COMPLETENESS OR PERFORMANCE.
28 * $/LicenseInfo$
29 */
30
31#include "linden_common.h"
32
33// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
34#if LL_WINDOWS
35# undef WIN32_LEAN_AND_MEAN
36# include <winsock2.h>
37# include <windows.h>
38#endif
39
40#include "lldefs.h"
41#include "llerror.h"
42
43#include "lluuid.h"
44#include "llerror.h"
45#include "llrand.h"
46#include "llmd5.h"
47#include "llstring.h"
48#include "lltimer.h"
49
50const LLUUID LLUUID::null;
51const LLTransactionID LLTransactionID::tnull;
52
53/*
54
55NOT DONE YET!!!
56
57static char BASE85_TABLE[] = {
58 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
59 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
60 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
61 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
62 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
63 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
64 'y', 'z', '!', '#', '$', '%', '&', '(', ')', '*',
65 '+', '-', ';', '[', '=', '>', '?', '@', '^', '_',
66 '`', '{', '|', '}', '~', '\0'
67};
68
69
70void encode( char * fiveChars, unsigned int word ) throw( )
71{
72for( int ix = 0; ix < 5; ++ix ) {
73fiveChars[4-ix] = encodeTable[ word % 85];
74word /= 85;
75}
76}
77
78To decode:
79unsigned int decode( char const * fiveChars ) throw( bad_input_data )
80{
81unsigned int ret = 0;
82for( int ix = 0; ix < 5; ++ix ) {
83char * s = strchr( encodeTable, fiveChars[ ix ] );
84if( s == 0 ) throw bad_input_data();
85ret = ret * 85 + (s-encodeTable);
86}
87return ret;
88}
89
90void LLUUID::toBase85(char* out)
91{
92 U32* me = (U32*)&(mData[0]);
93 for(S32 i = 0; i < 4; ++i)
94 {
95 char* o = &out[i*i];
96 for(S32 j = 0; j < 5; ++j)
97 {
98 o[4-j] = BASE85_TABLE[ me[i] % 85];
99 word /= 85;
100 }
101 }
102}
103
104unsigned int decode( char const * fiveChars ) throw( bad_input_data )
105{
106 unsigned int ret = 0;
107 for( S32 ix = 0; ix < 5; ++ix )
108 {
109 char * s = strchr( encodeTable, fiveChars[ ix ] );
110 ret = ret * 85 + (s-encodeTable);
111 }
112 return ret;
113}
114*/
115
116#define LL_USE_JANKY_RANDOM_NUMBER_GENERATOR 0
117#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
118/**
119 * @brief a global for
120 */
121static U64 sJankyRandomSeed(LLUUID::getRandomSeed());
122
123/**
124 * @brief generate a random U32.
125 */
126U32 janky_fast_random_bytes()
127{
128 sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223);
129 return (U32)sJankyRandomSeed;
130}
131
132/**
133 * @brief generate a random U32 from [0, val)
134 */
135U32 janky_fast_random_byes_range(U32 val)
136{
137 sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223);
138 return (U32)(sJankyRandomSeed) % val;
139}
140
141/**
142 * @brief generate a random U32 from [0, val)
143 */
144U32 janky_fast_random_seeded_bytes(U32 seed, U32 val)
145{
146 seed = U64L(1664525) * (U64)(seed) + U64L(1013904223);
147 return (U32)(seed) % val;
148}
149#endif
150
151// Common to all UUID implementations
152void LLUUID::toString(std::string& out) const
153{
154 out = llformat(
155 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
156 (U8)(mData[0]),
157 (U8)(mData[1]),
158 (U8)(mData[2]),
159 (U8)(mData[3]),
160 (U8)(mData[4]),
161 (U8)(mData[5]),
162 (U8)(mData[6]),
163 (U8)(mData[7]),
164 (U8)(mData[8]),
165 (U8)(mData[9]),
166 (U8)(mData[10]),
167 (U8)(mData[11]),
168 (U8)(mData[12]),
169 (U8)(mData[13]),
170 (U8)(mData[14]),
171 (U8)(mData[15]));
172}
173
174// *TODO: deprecate
175void LLUUID::toString(char *out) const
176{
177 std::string buffer;
178 toString(buffer);
179 strcpy(out,buffer.c_str()); /* Flawfinder: ignore */
180}
181
182void LLUUID::toCompressedString(std::string& out) const
183{
184 char bytes[UUID_BYTES+1];
185 memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */
186 bytes[UUID_BYTES] = '\0';
187 out.assign(bytes, UUID_BYTES);
188}
189
190// *TODO: deprecate
191void LLUUID::toCompressedString(char *out) const
192{
193 memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */
194 out[UUID_BYTES] = '\0';
195}
196
197std::string LLUUID::getString() const
198{
199 return asString();
200}
201
202std::string LLUUID::asString() const
203{
204 std::string str;
205 toString(str);
206 return str;
207}
208
209BOOL LLUUID::set(const char* in_string, BOOL emit)
210{
211 return set(ll_safe_string(in_string));
212}
213
214BOOL LLUUID::set(const std::string& in_string, BOOL emit)
215{
216 BOOL broken_format = FALSE;
217
218 // empty strings should make NULL uuid
219 if (in_string.empty())
220 {
221 setNull();
222 return TRUE;
223 }
224
225 if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */
226 {
227 // I'm a moron. First implementation didn't have the right UUID format.
228 // Shouldn't see any of these any more
229 if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
230 {
231 if(emit)
232 {
233 llinfos << "Warning! Using broken UUID string format" << llendl;
234 }
235 broken_format = TRUE;
236 }
237 else
238 {
239 // Bad UUID string. Spam as INFO, as most cases we don't care.
240 if(emit)
241 {
242 llinfos << "Bad UUID string: " << in_string << llendl;
243 }
244 setNull();
245 return FALSE;
246 }
247 }
248
249 U8 cur_pos = 0;
250 S32 i;
251 for (i = 0; i < UUID_BYTES; i++)
252 {
253 if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
254 {
255 cur_pos++;
256 if (broken_format && (i==10))
257 {
258 // Missing - in the broken format
259 cur_pos--;
260 }
261 }
262
263 mData[i] = 0;
264
265 if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
266 {
267 mData[i] += (U8)(in_string[cur_pos] - '0');
268 }
269 else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
270 {
271 mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
272 }
273 else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
274 {
275 mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
276 }
277 else
278 {
279 if(emit)
280 {
281 llwarns << "Invalid UUID string character" << llendl;
282 }
283 setNull();
284 return FALSE;
285 }
286
287 mData[i] = mData[i] << 4;
288 cur_pos++;
289
290 if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
291 {
292 mData[i] += (U8)(in_string[cur_pos] - '0');
293 }
294 else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
295 {
296 mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
297 }
298 else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
299 {
300 mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
301 }
302 else
303 {
304 if(emit)
305 {
306 llwarns << "Invalid UUID string character" << llendl;
307 }
308 setNull();
309 return FALSE;
310 }
311 cur_pos++;
312 }
313
314 return TRUE;
315}
316
317BOOL LLUUID::validate(const std::string& in_string)
318{
319 BOOL broken_format = FALSE;
320 if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */
321 {
322 // I'm a moron. First implementation didn't have the right UUID format.
323 if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
324 {
325 broken_format = TRUE;
326 }
327 else
328 {
329 return FALSE;
330 }
331 }
332
333 U8 cur_pos = 0;
334 for (U32 i = 0; i < 16; i++)
335 {
336 if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
337 {
338 cur_pos++;
339 if (broken_format && (i==10))
340 {
341 // Missing - in the broken format
342 cur_pos--;
343 }
344 }
345
346 if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
347 {
348 }
349 else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
350 {
351 }
352 else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
353 {
354 }
355 else
356 {
357 return FALSE;
358 }
359
360 cur_pos++;
361
362 if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
363 {
364 }
365 else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
366 {
367 }
368 else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
369 {
370 }
371 else
372 {
373 return FALSE;
374 }
375 cur_pos++;
376 }
377 return TRUE;
378}
379
380const LLUUID& LLUUID::operator^=(const LLUUID& rhs)
381{
382 U32* me = (U32*)&(mData[0]);
383 const U32* other = (U32*)&(rhs.mData[0]);
384 for(S32 i = 0; i < 4; ++i)
385 {
386 me[i] = me[i] ^ other[i];
387 }
388 return *this;
389}
390
391LLUUID LLUUID::operator^(const LLUUID& rhs) const
392{
393 LLUUID id(*this);
394 id ^= rhs;
395 return id;
396}
397
398void LLUUID::combine(const LLUUID& other, LLUUID& result) const
399{
400 LLMD5 md5_uuid;
401 md5_uuid.update((unsigned char*)mData, 16);
402 md5_uuid.update((unsigned char*)other.mData, 16);
403 md5_uuid.finalize();
404 md5_uuid.raw_digest(result.mData);
405}
406
407LLUUID LLUUID::combine(const LLUUID &other) const
408{
409 LLUUID combination;
410 combine(other, combination);
411 return combination;
412}
413
414std::ostream& operator<<(std::ostream& s, const LLUUID &uuid)
415{
416 std::string uuid_str;
417 uuid.toString(uuid_str);
418 s << uuid_str;
419 return s;
420}
421
422std::istream& operator>>(std::istream &s, LLUUID &uuid)
423{
424 U32 i;
425 char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */
426 for (i = 0; i < UUID_STR_LENGTH-1; i++)
427 {
428 s >> uuid_str[i];
429 }
430 uuid_str[i] = '\0';
431 uuid.set(std::string(uuid_str));
432 return s;
433}
434
435static void get_random_bytes(void *buf, int nbytes)
436{
437 int i;
438 char *cp = (char *) buf;
439
440 // *NOTE: If we are not using the janky generator ll_rand()
441 // generates at least 3 good bytes of data since it is 0 to
442 // RAND_MAX. This could be made more efficient by copying all the
443 // bytes.
444 for (i=0; i < nbytes; i++)
445#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
446 *cp++ = janky_fast_random_bytes() & 0xFF;
447#else
448 *cp++ = ll_rand() & 0xFF;
449#endif
450 return;
451}
452
453#if LL_WINDOWS
454typedef struct _ASTAT_
455{
456 ADAPTER_STATUS adapt;
457 NAME_BUFFER NameBuff [30];
458}ASTAT, * PASTAT;
459
460// static
461S32 LLUUID::getNodeID(unsigned char * node_id)
462{
463 ASTAT Adapter;
464 NCB Ncb;
465 UCHAR uRetCode;
466 LANA_ENUM lenum;
467 int i;
468 int retval = 0;
469
470 memset( &Ncb, 0, sizeof(Ncb) );
471 Ncb.ncb_command = NCBENUM;
472 Ncb.ncb_buffer = (UCHAR *)&lenum;
473 Ncb.ncb_length = sizeof(lenum);
474 uRetCode = Netbios( &Ncb );
475 // printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
476
477 for(i=0; i < lenum.length ;i++)
478 {
479 memset( &Ncb, 0, sizeof(Ncb) );
480 Ncb.ncb_command = NCBRESET;
481 Ncb.ncb_lana_num = lenum.lana[i];
482
483 uRetCode = Netbios( &Ncb );
484 // printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
485 // lenum.lana[i], uRetCode );
486
487 memset( &Ncb, 0, sizeof (Ncb) );
488 Ncb.ncb_command = NCBASTAT;
489 Ncb.ncb_lana_num = lenum.lana[i];
490
491 strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
492 Ncb.ncb_buffer = (unsigned char *)&Adapter;
493 Ncb.ncb_length = sizeof(Adapter);
494
495 uRetCode = Netbios( &Ncb );
496// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
497// lenum.lana[i], uRetCode );
498 if ( uRetCode == 0 )
499 {
500// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n",
501// lenum.lana[i],
502// Adapter.adapt.adapter_address[0],
503// Adapter.adapt.adapter_address[1],
504// Adapter.adapt.adapter_address[2],
505// Adapter.adapt.adapter_address[3],
506// Adapter.adapt.adapter_address[4],
507// Adapter.adapt.adapter_address[5] );
508 memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
509 retval = 1;
510
511 }
512 }
513 return retval;
514}
515
516#elif LL_DARWIN
517// Mac OS X version of the UUID generation code...
518/*
519 * Get an ethernet hardware address, if we can find it...
520 */
521#include <unistd.h>
522#include <sys/types.h>
523#include <sys/time.h>
524#include <sys/socket.h>
525#include <sys/ioctl.h>
526#include <net/if.h>
527#include <net/if_types.h>
528#include <net/if_dl.h>
529#include <net/route.h>
530#include <ifaddrs.h>
531
532// static
533S32 LLUUID::getNodeID(unsigned char *node_id)
534{
535 int i;
536 unsigned char *a = NULL;
537 struct ifaddrs *ifap, *ifa;
538 int rv;
539 S32 result = 0;
540
541 if ((rv=getifaddrs(&ifap))==-1)
542 {
543 return -1;
544 }
545 if (ifap == NULL)
546 {
547 return -1;
548 }
549
550 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
551 {
552// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family);
553 for(i=0; i< ifa->ifa_addr->sa_len; i++)
554 {
555// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]);
556 }
557// printf("\n");
558
559 if(ifa->ifa_addr->sa_family == AF_LINK)
560 {
561 // This is a link-level address
562 struct sockaddr_dl *lla = (struct sockaddr_dl *)ifa->ifa_addr;
563
564// printf("\tLink level address, type %02X\n", lla->sdl_type);
565
566 if(lla->sdl_type == IFT_ETHER)
567 {
568 // Use the first ethernet MAC in the list.
569 // For some reason, the macro LLADDR() defined in net/if_dl.h doesn't expand correctly. This is what it would do.
570 a = (unsigned char *)&((lla)->sdl_data);
571 a += (lla)->sdl_nlen;
572
573 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
574 {
575 continue;
576 }
577
578 if (node_id)
579 {
580 memcpy(node_id, a, 6);
581 result = 1;
582 }
583
584 // We found one.
585 break;
586 }
587 }
588 }
589 freeifaddrs(ifap);
590
591 return result;
592}
593
594#else
595
596// Linux version of the UUID generation code...
597/*
598 * Get the ethernet hardware address, if we can find it...
599 */
600#include <unistd.h>
601#include <fcntl.h>
602#include <errno.h>
603#include <sys/types.h>
604#include <sys/time.h>
605#include <sys/stat.h>
606#include <sys/file.h>
607#include <sys/ioctl.h>
608#include <sys/socket.h>
609#include <net/if.h>
610#define HAVE_NETINET_IN_H
611#ifdef HAVE_NETINET_IN_H
612#include <netinet/in.h>
613#if LL_SOLARIS
614#include <sys/sockio.h>
615#elif !LL_DARWIN
616#include <linux/sockios.h>
617#endif
618#endif
619
620// static
621S32 LLUUID::getNodeID(unsigned char *node_id)
622{
623 int sd;
624 struct ifreq ifr, *ifrp;
625 struct ifconf ifc;
626 char buf[1024];
627 int n, i;
628 unsigned char *a;
629
630/*
631 * BSD 4.4 defines the size of an ifreq to be
632 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
633 * However, under earlier systems, sa_len isn't present, so the size is
634 * just sizeof(struct ifreq)
635 */
636#ifdef HAVE_SA_LEN
637#ifndef max
638#define max(a,b) ((a) > (b) ? (a) : (b))
639#endif
640#define ifreq_size(i) max(sizeof(struct ifreq),\
641 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
642#else
643#define ifreq_size(i) sizeof(struct ifreq)
644#endif /* HAVE_SA_LEN*/
645
646 sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
647 if (sd < 0) {
648 return -1;
649 }
650 memset(buf, 0, sizeof(buf));
651 ifc.ifc_len = sizeof(buf);
652 ifc.ifc_buf = buf;
653 if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
654 close(sd);
655 return -1;
656 }
657 n = ifc.ifc_len;
658 for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
659 ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
660 strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */
661#ifdef SIOCGIFHWADDR
662 if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
663 continue;
664 a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
665#else
666#ifdef SIOCGENADDR
667 if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
668 continue;
669 a = (unsigned char *) ifr.ifr_enaddr;
670#else
671 /*
672 * XXX we don't have a way of getting the hardware
673 * address
674 */
675 close(sd);
676 return 0;
677#endif /* SIOCGENADDR */
678#endif /* SIOCGIFHWADDR */
679 if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
680 continue;
681 if (node_id) {
682 memcpy(node_id, a, 6); /* Flawfinder: ignore */
683 close(sd);
684 return 1;
685 }
686 }
687 close(sd);
688 return 0;
689}
690
691#endif
692
693S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2)
694{
695 // Compare two time values.
696
697 if (t1->high < t2->high) return -1;
698 if (t1->high > t2->high) return 1;
699 if (t1->low < t2->low) return -1;
700 if (t1->low > t2->low) return 1;
701 return 0;
702}
703
704void LLUUID::getSystemTime(uuid_time_t *timestamp)
705{
706 // Get system time with 100ns precision. Time is since Oct 15, 1582.
707#if LL_WINDOWS
708 ULARGE_INTEGER time;
709 GetSystemTimeAsFileTime((FILETIME *)&time);
710 // NT keeps time in FILETIME format which is 100ns ticks since
711 // Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
712 // The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
713 // + 18 years and 5 leap days.
714 time.QuadPart +=
715 (unsigned __int64) (1000*1000*10) // seconds
716 * (unsigned __int64) (60 * 60 * 24) // days
717 * (unsigned __int64) (17+30+31+365*18+5); // # of days
718
719 timestamp->high = time.HighPart;
720 timestamp->low = time.LowPart;
721#else
722 struct timeval tp;
723 gettimeofday(&tp, 0);
724
725 // Offset between UUID formatted times and Unix formatted times.
726 // UUID UTC base time is October 15, 1582.
727 // Unix base time is January 1, 1970.
728 U64 uuid_time = ((U64)tp.tv_sec * 10000000) + (tp.tv_usec * 10) +
729 U64L(0x01B21DD213814000);
730 timestamp->high = (U32) (uuid_time >> 32);
731 timestamp->low = (U32) (uuid_time & 0xFFFFFFFF);
732#endif
733}
734
735void LLUUID::getCurrentTime(uuid_time_t *timestamp)
736{
737 // Get current time as 60 bit 100ns ticks since whenever.
738 // Compensate for the fact that real clock resolution is less
739 // than 100ns.
740
741 const U32 uuids_per_tick = 1024;
742
743 static uuid_time_t time_last;
744 static U32 uuids_this_tick;
745 static BOOL init = FALSE;
746
747 if (!init) {
748 getSystemTime(&time_last);
749 uuids_this_tick = uuids_per_tick;
750 init = TRUE;
751 }
752
753 uuid_time_t time_now = {0,0};
754
755 while (1) {
756 getSystemTime(&time_now);
757
758 // if clock reading changed since last UUID generated
759 if (cmpTime(&time_last, &time_now)) {
760 // reset count of uuid's generated with this clock reading
761 uuids_this_tick = 0;
762 break;
763 }
764 if (uuids_this_tick < uuids_per_tick) {
765 uuids_this_tick++;
766 break;
767 }
768 // going too fast for our clock; spin
769 }
770
771 time_last = time_now;
772
773 if (uuids_this_tick != 0) {
774 if (time_now.low & 0x80000000) {
775 time_now.low += uuids_this_tick;
776 if (!(time_now.low & 0x80000000))
777 time_now.high++;
778 } else
779 time_now.low += uuids_this_tick;
780 }
781
782 timestamp->high = time_now.high;
783 timestamp->low = time_now.low;
784}
785
786void LLUUID::generate()
787{
788 // Create a UUID.
789 uuid_time_t timestamp;
790
791 static unsigned char node_id[6]; /* Flawfinder: ignore */
792 static int has_init = 0;
793
794 // Create a UUID.
795 static uuid_time_t time_last = {0,0};
796 static U16 clock_seq = 0;
797#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
798 static U32 seed = 0L; // dummy seed. reset it below
799#endif
800 if (!has_init)
801 {
802 if (getNodeID(node_id) <= 0)
803 {
804 get_random_bytes(node_id, 6);
805 /*
806 * Set multicast bit, to prevent conflicts
807 * with IEEE 802 addresses obtained from
808 * network cards
809 */
810 node_id[0] |= 0x80;
811 }
812
813 getCurrentTime(&time_last);
814#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
815 seed = time_last.low;
816#endif
817
818#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
819 clock_seq = (U16)janky_fast_random_seeded_bytes(seed, 65536);
820#else
821 clock_seq = (U16)ll_rand(65536);
822#endif
823 has_init = 1;
824 }
825
826 // get current time
827 getCurrentTime(&timestamp);
828
829 // if clock went backward change clockseq
830 if (cmpTime(&timestamp, &time_last) == -1) {
831 clock_seq = (clock_seq + 1) & 0x3FFF;
832 if (clock_seq == 0) clock_seq++;
833 }
834
835 memcpy(mData+10, node_id, 6); /* Flawfinder: ignore */
836 U32 tmp;
837 tmp = timestamp.low;
838 mData[3] = (unsigned char) tmp;
839 tmp >>= 8;
840 mData[2] = (unsigned char) tmp;
841 tmp >>= 8;
842 mData[1] = (unsigned char) tmp;
843 tmp >>= 8;
844 mData[0] = (unsigned char) tmp;
845
846 tmp = (U16) timestamp.high;
847 mData[5] = (unsigned char) tmp;
848 tmp >>= 8;
849 mData[4] = (unsigned char) tmp;
850
851 tmp = (timestamp.high >> 16) | 0x1000;
852 mData[7] = (unsigned char) tmp;
853 tmp >>= 8;
854 mData[6] = (unsigned char) tmp;
855
856 tmp = clock_seq;
857 mData[9] = (unsigned char) tmp;
858 tmp >>= 8;
859 mData[8] = (unsigned char) tmp;
860
861 LLMD5 md5_uuid;
862
863 md5_uuid.update(mData,16);
864 md5_uuid.finalize();
865 md5_uuid.raw_digest(mData);
866
867 time_last = timestamp;
868}
869
870void LLUUID::generate(const std::string& hash_string)
871{
872 LLMD5 md5_uuid((U8*)hash_string.c_str());
873 md5_uuid.raw_digest(mData);
874}
875
876U32 LLUUID::getRandomSeed()
877{
878 static unsigned char seed[16]; /* Flawfinder: ignore */
879
880 getNodeID(&seed[0]);
881 seed[6]='\0';
882 seed[7]='\0';
883 getSystemTime((uuid_time_t *)(&seed[8]));
884
885 LLMD5 md5_seed;
886
887 md5_seed.update(seed,16);
888 md5_seed.finalize();
889 md5_seed.raw_digest(seed);
890
891 return(*(U32 *)seed);
892}
893
894BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value)
895{
896 if( buf.empty() || value == NULL)
897 {
898 return FALSE;
899 }
900
901 std::string temp( buf );
902 LLStringUtil::trim(temp);
903 if( LLUUID::validate( temp ) )
904 {
905 value->set( temp );
906 return TRUE;
907 }
908 return FALSE;
909}
910
911LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const
912{
913 LLAssetID result;
914 if (isNull())
915 {
916 result.setNull();
917 }
918 else
919 {
920 combine(session, result);
921 }
922 return result;
923}