rpcrt4: Implement UuidCreateSequential using the machine's MAC address, when available.

This commit is contained in:
Juan Lang 2010-03-03 14:37:40 -08:00 committed by Alexandre Julliard
parent b61c8f8b53
commit 86292d1dba
3 changed files with 132 additions and 4 deletions

View File

@ -6,7 +6,7 @@ VPATH = @srcdir@
MODULE = rpcrt4.dll MODULE = rpcrt4.dll
IMPORTLIB = rpcrt4 IMPORTLIB = rpcrt4
IMPORTS = uuid advapi32 kernel32 ntdll IMPORTS = uuid advapi32 kernel32 ntdll
DELAYIMPORTS = wininet secur32 user32 DELAYIMPORTS = iphlpapi wininet secur32 user32
EXTRALIBS = @SOCKETLIBS@ EXTRALIBS = @SOCKETLIBS@
C_SRCS = \ C_SRCS = \

View File

@ -44,6 +44,8 @@
#include "winnt.h" #include "winnt.h"
#include "winternl.h" #include "winternl.h"
#include "ntsecapi.h" #include "ntsecapi.h"
#include "iptypes.h"
#include "iphlpapi.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "rpc.h" #include "rpc.h"
@ -60,6 +62,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc);
static UUID uuid_nil; static UUID uuid_nil;
static CRITICAL_SECTION uuid_cs;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &uuid_cs,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": uuid_cs") }
};
static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
static CRITICAL_SECTION threaddata_cs; static CRITICAL_SECTION threaddata_cs;
static CRITICAL_SECTION_DEBUG threaddata_cs_debug = static CRITICAL_SECTION_DEBUG threaddata_cs_debug =
{ {
@ -305,6 +316,58 @@ RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
return RPC_S_OK; return RPC_S_OK;
} }
/* Number of 100ns ticks per clock tick. To be safe, assume that the clock
resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
#define TICKS_PER_CLOCK_TICK 1000
#define SECSPERDAY 86400
#define TICKSPERSEC 10000000
/* UUID system time starts at October 15, 1582 */
#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
static void RPC_UuidGetSystemTime(ULONGLONG *time)
{
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
*time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
*time += TICKS_15_OCT_1582_TO_1601;
}
/* Assume that a hardware address is at least 6 bytes long */
#define ADDRESS_BYTES_NEEDED 6
static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address)
{
int i;
DWORD status = RPC_S_OK;
ULONG buflen = sizeof(IP_ADAPTER_INFO);
PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen);
if (GetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) {
HeapFree(GetProcessHeap(), 0, adapter);
adapter = HeapAlloc(GetProcessHeap(), 0, buflen);
}
if (GetAdaptersInfo(adapter, &buflen) == NO_ERROR) {
for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) {
address[i] = adapter->Address[i];
}
}
/* We can't get a hardware address, just use random numbers.
Set the multicast bit to prevent conflicts with real cards. */
else {
RtlGenRandom(address, ADDRESS_BYTES_NEEDED);
address[0] |= 0x01;
status = RPC_S_UUID_LOCAL_ONLY;
}
HeapFree(GetProcessHeap(), 0, adapter);
return status;
}
/************************************************************************* /*************************************************************************
* UuidCreateSequential [RPCRT4.@] * UuidCreateSequential [RPCRT4.@]
* *
@ -315,10 +378,77 @@ RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
* RPC_S_OK if successful. * RPC_S_OK if successful.
* RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique.
* *
* FIXME: No compensation for changes across reloading
* this dll or across reboots (e.g. clock going
* backwards and swapped network cards). The RFC
* suggests using NVRAM for storing persistent
* values.
*/ */
RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid) RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid)
{ {
return UuidCreate(Uuid); static int initialised, count;
ULONGLONG time;
static ULONGLONG timelast;
static WORD sequence;
static DWORD status;
static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH];
EnterCriticalSection(&uuid_cs);
if (!initialised) {
RPC_UuidGetSystemTime(&timelast);
count = TICKS_PER_CLOCK_TICK;
sequence = ((rand() & 0xff) << 8) + (rand() & 0xff);
sequence &= 0x1fff;
status = RPC_UuidGetNodeAddress(address);
initialised = 1;
}
/* Generate time element of the UUID. Account for going faster
than our clock as well as the clock going backwards. */
while (1) {
RPC_UuidGetSystemTime(&time);
if (time > timelast) {
count = 0;
break;
}
if (time < timelast) {
sequence = (sequence + 1) & 0x1fff;
count = 0;
break;
}
if (count < TICKS_PER_CLOCK_TICK) {
count++;
break;
}
}
timelast = time;
time += count;
/* Pack the information into the UUID structure. */
Uuid->Data1 = (unsigned long)(time & 0xffffffff);
Uuid->Data2 = (unsigned short)((time >> 32) & 0xffff);
Uuid->Data3 = (unsigned short)((time >> 48) & 0x0fff);
/* This is a version 1 UUID */
Uuid->Data3 |= (1 << 12);
Uuid->Data4[0] = sequence & 0xff;
Uuid->Data4[1] = (sequence & 0x3f00) >> 8;
Uuid->Data4[1] |= 0x80;
memcpy(&Uuid->Data4[2], address, ADDRESS_BYTES_NEEDED);
LeaveCriticalSection(&uuid_cs);
TRACE("%s\n", debugstr_guid(Uuid));
return status;
} }

View File

@ -820,7 +820,6 @@ static void test_UuidCreateSequential(void)
ok(!ret || ret == RPC_S_UUID_LOCAL_ONLY, ok(!ret || ret == RPC_S_UUID_LOCAL_ONLY,
"expected RPC_S_OK or RPC_S_UUID_LOCAL_ONLY, got %08x\n", ret); "expected RPC_S_OK or RPC_S_UUID_LOCAL_ONLY, got %08x\n", ret);
version = (guid1.Data3 & 0xf000) >> 12; version = (guid1.Data3 & 0xf000) >> 12;
todo_wine
ok(version == 1, "unexpected version %d\n", version); ok(version == 1, "unexpected version %d\n", version);
if (version == 1) if (version == 1)
{ {
@ -849,7 +848,6 @@ static void test_UuidCreateSequential(void)
ok(!ret || ret == RPC_S_UUID_LOCAL_ONLY, ok(!ret || ret == RPC_S_UUID_LOCAL_ONLY,
"expected RPC_S_OK or RPC_S_UUID_LOCAL_ONLY, got %08x\n", ret); "expected RPC_S_OK or RPC_S_UUID_LOCAL_ONLY, got %08x\n", ret);
version = (guid2.Data3 & 0xf000) >> 12; version = (guid2.Data3 & 0xf000) >> 12;
todo_wine
ok(version == 1, "unexpected version %d\n", version); ok(version == 1, "unexpected version %d\n", version);
ok(!memcmp(guid1.Data4, guid2.Data4, sizeof(guid2.Data4)), ok(!memcmp(guid1.Data4, guid2.Data4, sizeof(guid2.Data4)),
"unexpected value in MAC address\n"); "unexpected value in MAC address\n");