From 86292d1dbacfd626452f79eccf04c0f0929c6450 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Wed, 3 Mar 2010 14:37:40 -0800 Subject: [PATCH] rpcrt4: Implement UuidCreateSequential using the machine's MAC address, when available. --- dlls/rpcrt4/Makefile.in | 2 +- dlls/rpcrt4/rpcrt4_main.c | 132 +++++++++++++++++++++++++++++++++++++++++++++- dlls/rpcrt4/tests/rpc.c | 2 - 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/dlls/rpcrt4/Makefile.in b/dlls/rpcrt4/Makefile.in index fda374c9435..ce50b36ac32 100644 --- a/dlls/rpcrt4/Makefile.in +++ b/dlls/rpcrt4/Makefile.in @@ -6,7 +6,7 @@ VPATH = @srcdir@ MODULE = rpcrt4.dll IMPORTLIB = rpcrt4 IMPORTS = uuid advapi32 kernel32 ntdll -DELAYIMPORTS = wininet secur32 user32 +DELAYIMPORTS = iphlpapi wininet secur32 user32 EXTRALIBS = @SOCKETLIBS@ C_SRCS = \ diff --git a/dlls/rpcrt4/rpcrt4_main.c b/dlls/rpcrt4/rpcrt4_main.c index a790ccbd568..344b6d08137 100644 --- a/dlls/rpcrt4/rpcrt4_main.c +++ b/dlls/rpcrt4/rpcrt4_main.c @@ -44,6 +44,8 @@ #include "winnt.h" #include "winternl.h" #include "ntsecapi.h" +#include "iptypes.h" +#include "iphlpapi.h" #include "wine/unicode.h" #include "rpc.h" @@ -60,6 +62,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(rpc); 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_DEBUG threaddata_cs_debug = { @@ -305,6 +316,58 @@ RPC_STATUS WINAPI UuidCreate(UUID *Uuid) 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.@] * @@ -315,10 +378,77 @@ RPC_STATUS WINAPI UuidCreate(UUID *Uuid) * RPC_S_OK if successful. * 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) { - 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; } diff --git a/dlls/rpcrt4/tests/rpc.c b/dlls/rpcrt4/tests/rpc.c index 7bd78bab467..bb480e1b865 100644 --- a/dlls/rpcrt4/tests/rpc.c +++ b/dlls/rpcrt4/tests/rpc.c @@ -820,7 +820,6 @@ static void test_UuidCreateSequential(void) ok(!ret || ret == RPC_S_UUID_LOCAL_ONLY, "expected RPC_S_OK or RPC_S_UUID_LOCAL_ONLY, got %08x\n", ret); version = (guid1.Data3 & 0xf000) >> 12; - todo_wine ok(version == 1, "unexpected version %d\n", version); if (version == 1) { @@ -849,7 +848,6 @@ static void test_UuidCreateSequential(void) ok(!ret || ret == RPC_S_UUID_LOCAL_ONLY, "expected RPC_S_OK or RPC_S_UUID_LOCAL_ONLY, got %08x\n", ret); version = (guid2.Data3 & 0xf000) >> 12; - todo_wine ok(version == 1, "unexpected version %d\n", version); ok(!memcmp(guid1.Data4, guid2.Data4, sizeof(guid2.Data4)), "unexpected value in MAC address\n"); -- 2.11.4.GIT