Imported existing code
This commit is contained in:
940
indra/llcommon/lluuid.cpp
Normal file
940
indra/llcommon/lluuid.cpp
Normal file
@@ -0,0 +1,940 @@
|
||||
/**
|
||||
* @file lluuid.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2000&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2000-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
|
||||
#if LL_WINDOWS
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "lldefs.h"
|
||||
#include "llerror.h"
|
||||
|
||||
#include "lluuid.h"
|
||||
#include "llerror.h"
|
||||
#include "llrand.h"
|
||||
#include "llmd5.h"
|
||||
#include "llstring.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
const LLUUID LLUUID::null;
|
||||
const LLTransactionID LLTransactionID::tnull;
|
||||
|
||||
/*
|
||||
|
||||
NOT DONE YET!!!
|
||||
|
||||
static char BASE85_TABLE[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z', '!', '#', '$', '%', '&', '(', ')', '*',
|
||||
'+', '-', ';', '[', '=', '>', '?', '@', '^', '_',
|
||||
'`', '{', '|', '}', '~', '\0'
|
||||
};
|
||||
|
||||
|
||||
void encode( char * fiveChars, unsigned int word ) throw( )
|
||||
{
|
||||
for( int ix = 0; ix < 5; ++ix ) {
|
||||
fiveChars[4-ix] = encodeTable[ word % 85];
|
||||
word /= 85;
|
||||
}
|
||||
}
|
||||
|
||||
To decode:
|
||||
unsigned int decode( char const * fiveChars ) throw( bad_input_data )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
for( int ix = 0; ix < 5; ++ix ) {
|
||||
char * s = strchr( encodeTable, fiveChars[ ix ] );
|
||||
if( s == 0 ) throw bad_input_data();
|
||||
ret = ret * 85 + (s-encodeTable);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLUUID::toBase85(char* out)
|
||||
{
|
||||
U32* me = (U32*)&(mData[0]);
|
||||
for(S32 i = 0; i < 4; ++i)
|
||||
{
|
||||
char* o = &out[i*i];
|
||||
for(S32 j = 0; j < 5; ++j)
|
||||
{
|
||||
o[4-j] = BASE85_TABLE[ me[i] % 85];
|
||||
word /= 85;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int decode( char const * fiveChars ) throw( bad_input_data )
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
for( S32 ix = 0; ix < 5; ++ix )
|
||||
{
|
||||
char * s = strchr( encodeTable, fiveChars[ ix ] );
|
||||
ret = ret * 85 + (s-encodeTable);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
#define LL_USE_JANKY_RANDOM_NUMBER_GENERATOR 0
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
/**
|
||||
* @brief a global for
|
||||
*/
|
||||
static U64 sJankyRandomSeed(LLUUID::getRandomSeed());
|
||||
|
||||
/**
|
||||
* @brief generate a random U32.
|
||||
*/
|
||||
U32 janky_fast_random_bytes()
|
||||
{
|
||||
sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223);
|
||||
return (U32)sJankyRandomSeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief generate a random U32 from [0, val)
|
||||
*/
|
||||
U32 janky_fast_random_byes_range(U32 val)
|
||||
{
|
||||
sJankyRandomSeed = U64L(1664525) * sJankyRandomSeed + U64L(1013904223);
|
||||
return (U32)(sJankyRandomSeed) % val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief generate a random U32 from [0, val)
|
||||
*/
|
||||
U32 janky_fast_random_seeded_bytes(U32 seed, U32 val)
|
||||
{
|
||||
seed = U64L(1664525) * (U64)(seed) + U64L(1013904223);
|
||||
return (U32)(seed) % val;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Common to all UUID implementations
|
||||
void LLUUID::toString(std::string& out) const
|
||||
{
|
||||
out = llformat(
|
||||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
(U8)(mData[0]),
|
||||
(U8)(mData[1]),
|
||||
(U8)(mData[2]),
|
||||
(U8)(mData[3]),
|
||||
(U8)(mData[4]),
|
||||
(U8)(mData[5]),
|
||||
(U8)(mData[6]),
|
||||
(U8)(mData[7]),
|
||||
(U8)(mData[8]),
|
||||
(U8)(mData[9]),
|
||||
(U8)(mData[10]),
|
||||
(U8)(mData[11]),
|
||||
(U8)(mData[12]),
|
||||
(U8)(mData[13]),
|
||||
(U8)(mData[14]),
|
||||
(U8)(mData[15]));
|
||||
}
|
||||
|
||||
// *TODO: deprecate
|
||||
void LLUUID::toString(char *out) const
|
||||
{
|
||||
std::string buffer;
|
||||
toString(buffer);
|
||||
strcpy(out,buffer.c_str()); /* Flawfinder: ignore */
|
||||
}
|
||||
|
||||
void LLUUID::toCompressedString(std::string& out) const
|
||||
{
|
||||
char bytes[UUID_BYTES+1];
|
||||
memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */
|
||||
bytes[UUID_BYTES] = '\0';
|
||||
out.assign(bytes, UUID_BYTES);
|
||||
}
|
||||
|
||||
// *TODO: deprecate
|
||||
void LLUUID::toCompressedString(char *out) const
|
||||
{
|
||||
memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */
|
||||
out[UUID_BYTES] = '\0';
|
||||
}
|
||||
|
||||
std::string LLUUID::getString() const
|
||||
{
|
||||
return asString();
|
||||
}
|
||||
|
||||
std::string LLUUID::asString() const
|
||||
{
|
||||
std::string str;
|
||||
toString(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
BOOL LLUUID::set(const char* in_string, BOOL emit)
|
||||
{
|
||||
return set(ll_safe_string(in_string),emit);
|
||||
}
|
||||
|
||||
BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
||||
{
|
||||
BOOL broken_format = FALSE;
|
||||
|
||||
// empty strings should make NULL uuid
|
||||
if (in_string.empty())
|
||||
{
|
||||
setNull();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */
|
||||
{
|
||||
// I'm a moron. First implementation didn't have the right UUID format.
|
||||
// Shouldn't see any of these any more
|
||||
if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
|
||||
{
|
||||
if(emit)
|
||||
{
|
||||
llwarns << "Warning! Using broken UUID string format" << llendl;
|
||||
}
|
||||
broken_format = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bad UUID string. Spam as INFO, as most cases we don't care.
|
||||
if(emit)
|
||||
{
|
||||
//don't spam the logs because a resident can't spell.
|
||||
llwarns << "Bad UUID string: " << in_string << llendl;
|
||||
}
|
||||
setNull();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U8 cur_pos = 0;
|
||||
S32 i;
|
||||
for (i = 0; i < UUID_BYTES; i++)
|
||||
{
|
||||
if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
|
||||
{
|
||||
cur_pos++;
|
||||
if (broken_format && (i==10))
|
||||
{
|
||||
// Missing - in the broken format
|
||||
cur_pos--;
|
||||
}
|
||||
}
|
||||
|
||||
mData[i] = 0;
|
||||
|
||||
if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
|
||||
{
|
||||
mData[i] += (U8)(in_string[cur_pos] - '0');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
|
||||
}
|
||||
else
|
||||
{
|
||||
if(emit)
|
||||
{
|
||||
llwarns << "Invalid UUID string character" << llendl;
|
||||
}
|
||||
setNull();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mData[i] = mData[i] << 4;
|
||||
cur_pos++;
|
||||
|
||||
if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
|
||||
{
|
||||
mData[i] += (U8)(in_string[cur_pos] - '0');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'a');
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
{
|
||||
mData[i] += (U8)(10 + in_string[cur_pos] - 'A');
|
||||
}
|
||||
else
|
||||
{
|
||||
if(emit)
|
||||
{
|
||||
llwarns << "Invalid UUID string character" << llendl;
|
||||
}
|
||||
setNull();
|
||||
return FALSE;
|
||||
}
|
||||
cur_pos++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLUUID::validate(const std::string& in_string)
|
||||
{
|
||||
BOOL broken_format = FALSE;
|
||||
if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */
|
||||
{
|
||||
// I'm a moron. First implementation didn't have the right UUID format.
|
||||
if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */
|
||||
{
|
||||
broken_format = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U8 cur_pos = 0;
|
||||
for (U32 i = 0; i < 16; i++)
|
||||
{
|
||||
if ((i == 4) || (i == 6) || (i == 8) || (i == 10))
|
||||
{
|
||||
cur_pos++;
|
||||
if (broken_format && (i==10))
|
||||
{
|
||||
// Missing - in the broken format
|
||||
cur_pos--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cur_pos++;
|
||||
|
||||
if ((in_string[cur_pos] >= '0') && (in_string[cur_pos] <= '9'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'a') && (in_string[cur_pos] <='f'))
|
||||
{
|
||||
}
|
||||
else if ((in_string[cur_pos] >= 'A') && (in_string[cur_pos] <='F'))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
cur_pos++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const LLUUID& LLUUID::operator^=(const LLUUID& rhs)
|
||||
{
|
||||
U32* me = (U32*)&(mData[0]);
|
||||
const U32* other = (U32*)&(rhs.mData[0]);
|
||||
for(S32 i = 0; i < 4; ++i)
|
||||
{
|
||||
me[i] = me[i] ^ other[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLUUID LLUUID::operator^(const LLUUID& rhs) const
|
||||
{
|
||||
LLUUID id(*this);
|
||||
id ^= rhs;
|
||||
return id;
|
||||
}
|
||||
|
||||
void LLUUID::combine(const LLUUID& other, LLUUID& result) const
|
||||
{
|
||||
LLMD5 md5_uuid;
|
||||
md5_uuid.update((unsigned char*)mData, 16);
|
||||
md5_uuid.update((unsigned char*)other.mData, 16);
|
||||
md5_uuid.finalize();
|
||||
md5_uuid.raw_digest(result.mData);
|
||||
}
|
||||
|
||||
LLUUID LLUUID::combine(const LLUUID &other) const
|
||||
{
|
||||
LLUUID combination;
|
||||
combine(other, combination);
|
||||
return combination;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const LLUUID &uuid)
|
||||
{
|
||||
std::string uuid_str;
|
||||
uuid.toString(uuid_str);
|
||||
s << uuid_str;
|
||||
return s;
|
||||
}
|
||||
|
||||
std::istream& operator>>(std::istream &s, LLUUID &uuid)
|
||||
{
|
||||
U32 i;
|
||||
char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */
|
||||
for (i = 0; i < UUID_STR_LENGTH-1; i++)
|
||||
{
|
||||
s >> uuid_str[i];
|
||||
}
|
||||
uuid_str[i] = '\0';
|
||||
uuid.set(std::string(uuid_str));
|
||||
return s;
|
||||
}
|
||||
|
||||
static void get_random_bytes(void *buf, int nbytes)
|
||||
{
|
||||
int i;
|
||||
char *cp = (char *) buf;
|
||||
|
||||
// *NOTE: If we are not using the janky generator ll_rand()
|
||||
// generates at least 3 good bytes of data since it is 0 to
|
||||
// RAND_MAX. This could be made more efficient by copying all the
|
||||
// bytes.
|
||||
for (i=0; i < nbytes; i++)
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
*cp++ = janky_fast_random_bytes() & 0xFF;
|
||||
#else
|
||||
*cp++ = ll_rand() & 0xFF;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
typedef struct _ASTAT_
|
||||
{
|
||||
ADAPTER_STATUS adapt;
|
||||
NAME_BUFFER NameBuff [30];
|
||||
}ASTAT, * PASTAT;
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char * node_id)
|
||||
{
|
||||
ASTAT Adapter;
|
||||
NCB Ncb;
|
||||
UCHAR uRetCode;
|
||||
LANA_ENUM lenum;
|
||||
int i;
|
||||
int retval = 0;
|
||||
|
||||
memset( &Ncb, 0, sizeof(Ncb) );
|
||||
Ncb.ncb_command = NCBENUM;
|
||||
Ncb.ncb_buffer = (UCHAR *)&lenum;
|
||||
Ncb.ncb_length = sizeof(lenum);
|
||||
uRetCode = Netbios( &Ncb );
|
||||
// printf( "The NCBENUM return code is: 0x%x \n", uRetCode );
|
||||
|
||||
for(i=0; i < lenum.length ;i++)
|
||||
{
|
||||
memset( &Ncb, 0, sizeof(Ncb) );
|
||||
Ncb.ncb_command = NCBRESET;
|
||||
Ncb.ncb_lana_num = lenum.lana[i];
|
||||
|
||||
uRetCode = Netbios( &Ncb );
|
||||
// printf( "The NCBRESET on LANA %d return code is: 0x%x \n",
|
||||
// lenum.lana[i], uRetCode );
|
||||
|
||||
memset( &Ncb, 0, sizeof (Ncb) );
|
||||
Ncb.ncb_command = NCBASTAT;
|
||||
Ncb.ncb_lana_num = lenum.lana[i];
|
||||
|
||||
strcpy( (char *)Ncb.ncb_callname, "* " ); /* Flawfinder: ignore */
|
||||
Ncb.ncb_buffer = (unsigned char *)&Adapter;
|
||||
Ncb.ncb_length = sizeof(Adapter);
|
||||
|
||||
uRetCode = Netbios( &Ncb );
|
||||
// printf( "The NCBASTAT on LANA %d return code is: 0x%x \n",
|
||||
// lenum.lana[i], uRetCode );
|
||||
if ( uRetCode == 0 )
|
||||
{
|
||||
// printf( "The Ethernet Number on LANA %d is: %02x%02x%02x%02x%02x%02x\n",
|
||||
// lenum.lana[i],
|
||||
// Adapter.adapt.adapter_address[0],
|
||||
// Adapter.adapt.adapter_address[1],
|
||||
// Adapter.adapt.adapter_address[2],
|
||||
// Adapter.adapt.adapter_address[3],
|
||||
// Adapter.adapt.adapter_address[4],
|
||||
// Adapter.adapt.adapter_address[5] );
|
||||
memcpy(node_id,Adapter.adapt.adapter_address,6); /* Flawfinder: ignore */
|
||||
retval = 1;
|
||||
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#elif LL_DARWIN
|
||||
// Mac OS X version of the UUID generation code...
|
||||
/*
|
||||
* Get an ethernet hardware address, if we can find it...
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/route.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char *node_id)
|
||||
{
|
||||
int i;
|
||||
unsigned char *a = NULL;
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
int rv;
|
||||
S32 result = 0;
|
||||
|
||||
if ((rv=getifaddrs(&ifap))==-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (ifap == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
|
||||
{
|
||||
// printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family);
|
||||
for(i=0; i< ifa->ifa_addr->sa_len; i++)
|
||||
{
|
||||
// printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]);
|
||||
}
|
||||
// printf("\n");
|
||||
|
||||
if(ifa->ifa_addr->sa_family == AF_LINK)
|
||||
{
|
||||
// This is a link-level address
|
||||
struct sockaddr_dl *lla = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||
|
||||
// printf("\tLink level address, type %02X\n", lla->sdl_type);
|
||||
|
||||
if(lla->sdl_type == IFT_ETHER)
|
||||
{
|
||||
// Use the first ethernet MAC in the list.
|
||||
// For some reason, the macro LLADDR() defined in net/if_dl.h doesn't expand correctly. This is what it would do.
|
||||
a = (unsigned char *)&((lla)->sdl_data);
|
||||
a += (lla)->sdl_nlen;
|
||||
|
||||
if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node_id)
|
||||
{
|
||||
memcpy(node_id, a, 6);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
// We found one.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Linux version of the UUID generation code...
|
||||
/*
|
||||
* Get the ethernet hardware address, if we can find it...
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#define HAVE_NETINET_IN_H
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#if LL_SOLARIS
|
||||
#include <sys/sockio.h>
|
||||
#elif !LL_DARWIN
|
||||
#include <linux/sockios.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// static
|
||||
S32 LLUUID::getNodeID(unsigned char *node_id)
|
||||
{
|
||||
int sd;
|
||||
struct ifreq ifr, *ifrp;
|
||||
struct ifconf ifc;
|
||||
char buf[1024];
|
||||
int n, i;
|
||||
unsigned char *a;
|
||||
|
||||
/*
|
||||
* BSD 4.4 defines the size of an ifreq to be
|
||||
* max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
|
||||
* However, under earlier systems, sa_len isn't present, so the size is
|
||||
* just sizeof(struct ifreq)
|
||||
*/
|
||||
#ifdef HAVE_SA_LEN
|
||||
#ifndef max
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
#define ifreq_size(i) max(sizeof(struct ifreq),\
|
||||
sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
|
||||
#else
|
||||
#define ifreq_size(i) sizeof(struct ifreq)
|
||||
#endif /* HAVE_SA_LEN*/
|
||||
|
||||
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (sd < 0) {
|
||||
return -1;
|
||||
}
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ifc.ifc_len = sizeof(buf);
|
||||
ifc.ifc_buf = buf;
|
||||
if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
n = ifc.ifc_len;
|
||||
for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
|
||||
ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
|
||||
strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */
|
||||
#ifdef SIOCGIFHWADDR
|
||||
if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
|
||||
continue;
|
||||
a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
|
||||
#else
|
||||
#ifdef SIOCGENADDR
|
||||
if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
|
||||
continue;
|
||||
a = (unsigned char *) ifr.ifr_enaddr;
|
||||
#else
|
||||
/*
|
||||
* XXX we don't have a way of getting the hardware
|
||||
* address
|
||||
*/
|
||||
close(sd);
|
||||
return 0;
|
||||
#endif /* SIOCGENADDR */
|
||||
#endif /* SIOCGIFHWADDR */
|
||||
if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
|
||||
continue;
|
||||
if (node_id) {
|
||||
memcpy(node_id, a, 6); /* Flawfinder: ignore */
|
||||
close(sd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
close(sd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
S32 LLUUID::cmpTime(uuid_time_t *t1, uuid_time_t *t2)
|
||||
{
|
||||
// Compare two time values.
|
||||
|
||||
if (t1->high < t2->high) return -1;
|
||||
if (t1->high > t2->high) return 1;
|
||||
if (t1->low < t2->low) return -1;
|
||||
if (t1->low > t2->low) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LLUUID::getSystemTime(uuid_time_t *timestamp)
|
||||
{
|
||||
// Get system time with 100ns precision. Time is since Oct 15, 1582.
|
||||
#if LL_WINDOWS
|
||||
ULARGE_INTEGER time;
|
||||
GetSystemTimeAsFileTime((FILETIME *)&time);
|
||||
// NT keeps time in FILETIME format which is 100ns ticks since
|
||||
// Jan 1, 1601. UUIDs use time in 100ns ticks since Oct 15, 1582.
|
||||
// The difference is 17 Days in Oct + 30 (Nov) + 31 (Dec)
|
||||
// + 18 years and 5 leap days.
|
||||
time.QuadPart +=
|
||||
(unsigned __int64) (1000*1000*10) // seconds
|
||||
* (unsigned __int64) (60 * 60 * 24) // days
|
||||
* (unsigned __int64) (17+30+31+365*18+5); // # of days
|
||||
|
||||
timestamp->high = time.HighPart;
|
||||
timestamp->low = time.LowPart;
|
||||
#else
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, 0);
|
||||
|
||||
// Offset between UUID formatted times and Unix formatted times.
|
||||
// UUID UTC base time is October 15, 1582.
|
||||
// Unix base time is January 1, 1970.
|
||||
U64 uuid_time = ((U64)tp.tv_sec * 10000000) + (tp.tv_usec * 10) +
|
||||
U64L(0x01B21DD213814000);
|
||||
timestamp->high = (U32) (uuid_time >> 32);
|
||||
timestamp->low = (U32) (uuid_time & 0xFFFFFFFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLUUID::getCurrentTime(uuid_time_t *timestamp)
|
||||
{
|
||||
// Get current time as 60 bit 100ns ticks since whenever.
|
||||
// Compensate for the fact that real clock resolution is less
|
||||
// than 100ns.
|
||||
|
||||
const U32 uuids_per_tick = 1024;
|
||||
|
||||
static uuid_time_t time_last;
|
||||
static U32 uuids_this_tick;
|
||||
static BOOL init = FALSE;
|
||||
|
||||
if (!init) {
|
||||
getSystemTime(&time_last);
|
||||
uuids_this_tick = uuids_per_tick;
|
||||
init = TRUE;
|
||||
}
|
||||
|
||||
uuid_time_t time_now = {0,0};
|
||||
|
||||
while (1) {
|
||||
getSystemTime(&time_now);
|
||||
|
||||
// if clock reading changed since last UUID generated
|
||||
if (cmpTime(&time_last, &time_now)) {
|
||||
// reset count of uuid's generated with this clock reading
|
||||
uuids_this_tick = 0;
|
||||
break;
|
||||
}
|
||||
if (uuids_this_tick < uuids_per_tick) {
|
||||
uuids_this_tick++;
|
||||
break;
|
||||
}
|
||||
// going too fast for our clock; spin
|
||||
}
|
||||
|
||||
time_last = time_now;
|
||||
|
||||
if (uuids_this_tick != 0) {
|
||||
if (time_now.low & 0x80000000) {
|
||||
time_now.low += uuids_this_tick;
|
||||
if (!(time_now.low & 0x80000000))
|
||||
time_now.high++;
|
||||
} else
|
||||
time_now.low += uuids_this_tick;
|
||||
}
|
||||
|
||||
timestamp->high = time_now.high;
|
||||
timestamp->low = time_now.low;
|
||||
}
|
||||
|
||||
void LLUUID::generate()
|
||||
{
|
||||
// Create a UUID.
|
||||
uuid_time_t timestamp;
|
||||
|
||||
static unsigned char node_id[6]; /* Flawfinder: ignore */
|
||||
static int has_init = 0;
|
||||
|
||||
// Create a UUID.
|
||||
static uuid_time_t time_last = {0,0};
|
||||
static U16 clock_seq = 0;
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
static U32 seed = 0L; // dummy seed. reset it below
|
||||
#endif
|
||||
if (!has_init)
|
||||
{
|
||||
if (getNodeID(node_id) <= 0)
|
||||
{
|
||||
get_random_bytes(node_id, 6);
|
||||
/*
|
||||
* Set multicast bit, to prevent conflicts
|
||||
* with IEEE 802 addresses obtained from
|
||||
* network cards
|
||||
*/
|
||||
node_id[0] |= 0x80;
|
||||
}
|
||||
|
||||
getCurrentTime(&time_last);
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
seed = time_last.low;
|
||||
#endif
|
||||
|
||||
#if LL_USE_JANKY_RANDOM_NUMBER_GENERATOR
|
||||
clock_seq = (U16)janky_fast_random_seeded_bytes(seed, 65536);
|
||||
#else
|
||||
clock_seq = (U16)ll_rand(65536);
|
||||
#endif
|
||||
has_init = 1;
|
||||
}
|
||||
|
||||
// get current time
|
||||
getCurrentTime(×tamp);
|
||||
|
||||
// if clock went backward change clockseq
|
||||
if (cmpTime(×tamp, &time_last) == -1) {
|
||||
clock_seq = (clock_seq + 1) & 0x3FFF;
|
||||
if (clock_seq == 0) clock_seq++;
|
||||
}
|
||||
|
||||
memcpy(mData+10, node_id, 6); /* Flawfinder: ignore */
|
||||
U32 tmp;
|
||||
tmp = timestamp.low;
|
||||
mData[3] = (unsigned char) tmp;
|
||||
tmp >>= 8;
|
||||
mData[2] = (unsigned char) tmp;
|
||||
tmp >>= 8;
|
||||
mData[1] = (unsigned char) tmp;
|
||||
tmp >>= 8;
|
||||
mData[0] = (unsigned char) tmp;
|
||||
|
||||
tmp = (U16) timestamp.high;
|
||||
mData[5] = (unsigned char) tmp;
|
||||
tmp >>= 8;
|
||||
mData[4] = (unsigned char) tmp;
|
||||
|
||||
tmp = (timestamp.high >> 16) | 0x1000;
|
||||
mData[7] = (unsigned char) tmp;
|
||||
tmp >>= 8;
|
||||
mData[6] = (unsigned char) tmp;
|
||||
|
||||
tmp = clock_seq;
|
||||
mData[9] = (unsigned char) tmp;
|
||||
tmp >>= 8;
|
||||
mData[8] = (unsigned char) tmp;
|
||||
|
||||
LLMD5 md5_uuid;
|
||||
|
||||
md5_uuid.update(mData,16);
|
||||
md5_uuid.finalize();
|
||||
md5_uuid.raw_digest(mData);
|
||||
|
||||
time_last = timestamp;
|
||||
}
|
||||
|
||||
void LLUUID::generate(const std::string& hash_string)
|
||||
{
|
||||
LLMD5 md5_uuid((U8*)hash_string.c_str());
|
||||
md5_uuid.raw_digest(mData);
|
||||
}
|
||||
|
||||
U32 LLUUID::getRandomSeed()
|
||||
{
|
||||
static unsigned char seed[16]; /* Flawfinder: ignore */
|
||||
|
||||
getNodeID(&seed[0]);
|
||||
seed[6]='\0';
|
||||
seed[7]='\0';
|
||||
getSystemTime((uuid_time_t *)(&seed[8]));
|
||||
|
||||
LLMD5 md5_seed;
|
||||
|
||||
md5_seed.update(seed,16);
|
||||
md5_seed.finalize();
|
||||
md5_seed.raw_digest(seed);
|
||||
|
||||
return(*(U32 *)seed);
|
||||
}
|
||||
|
||||
BOOL LLUUID::parseUUID(const std::string& buf, LLUUID* value)
|
||||
{
|
||||
if( buf.empty() || value == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
std::string temp( buf );
|
||||
LLStringUtil::trim(temp);
|
||||
if( LLUUID::validate( temp ) )
|
||||
{
|
||||
value->set( temp );
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//static
|
||||
LLUUID LLUUID::generateNewID(std::string hash_string)
|
||||
{
|
||||
LLUUID new_id;
|
||||
if (hash_string.empty())
|
||||
{
|
||||
new_id.generate();
|
||||
}
|
||||
else
|
||||
{
|
||||
new_id.generate(hash_string);
|
||||
}
|
||||
return new_id;
|
||||
}
|
||||
|
||||
LLAssetID LLTransactionID::makeAssetID(const LLUUID& session) const
|
||||
{
|
||||
LLAssetID result;
|
||||
if (isNull())
|
||||
{
|
||||
result.setNull();
|
||||
}
|
||||
else
|
||||
{
|
||||
combine(session, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user