Index: boot/bootdata/hivesft.inf =================================================================== --- boot/bootdata/hivesft.inf (revision 72964) +++ boot/bootdata/hivesft.inf (working copy) @@ -1423,7 +1423,7 @@ ; SvcHost services HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost",,0x00000012 HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","DcomLaunch",0x00010000,"PlugPlay" -HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","netsvcs",0x00010000,"DHCP","BITS","lanmanserver","lanmanworkstation","Schedule","winmgmt" +HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost","netsvcs",0x00010000,"DHCP","BITS","lanmanserver","lanmanworkstation","Schedule","winmgmt","DNS" ; Win32 config HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows",,0x00000012 Index: dll/win32/dnsapi/CMakeLists.txt =================================================================== --- dll/win32/dnsapi/CMakeLists.txt (revision 72964) +++ dll/win32/dnsapi/CMakeLists.txt (working copy) @@ -9,11 +9,14 @@ list(APPEND SOURCE dnsapi/adns.c + dnsapi/cache.c dnsapi/context.c dnsapi/memory.c dnsapi/names.c dnsapi/query.c + dnsapi/pipe.c dnsapi/record.c + dnsapi/service.c dnsapi/stubs.c dnsapi/precomp.h) Index: dll/win32/dnsapi/dnsapi.spec =================================================================== --- dll/win32/dnsapi/dnsapi.spec (revision 72964) +++ dll/win32/dnsapi/dnsapi.spec (working copy) @@ -130,3 +130,4 @@ @ stdcall DnsWriteReverseNameStringForIpAddress() @ stdcall GetCurrentTimeInSeconds() @ stdcall DnsFree(ptr long) +@ stdcall ServiceMain(long ptr) Index: dll/win32/dnsapi/dnsapi/cache.c =================================================================== --- dll/win32/dnsapi/dnsapi/cache.c (revision 0) +++ dll/win32/dnsapi/dnsapi/cache.c (working copy) @@ -0,0 +1,151 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/dnsapi/dnsapi/cache.c + * PURPOSE: DNSAPI cache functions. + * PROGRAMER: Peter Hater + */ + +#include "precomp.h" +#include + +#define NDEBUG +#include + +static TCACHE DnsCache; +static BOOL DnsCacheInitialized = FALSE; + +#define DnsCacheLock() EnterCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock); +#define DnsCacheUnlock() LeaveCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock); + +VOID +DnsIntCacheInitialize(VOID) +{ + /* Check if we're initialized */ + if (DnsCacheInitialized) + return; + /* Initialize the catalog lock and namespace list */ + InitializeCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock); + InitializeListHead(&DnsCache.RecordList); + DnsCacheInitialized = TRUE; +} + +VOID +DnsIntCacheFree(VOID) +{ + /* Check if we're initialized */ + if (!DnsCacheInitialized) + return; + if (!DnsCache.RecordList.Flink) + return; + + DnsIntCacheFlush(); + + DeleteCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock); + DnsCacheInitialized = FALSE; +} + +VOID +DnsIntCacheRemoveEntryItem(PTCACHE_ENTRY CacheEntry) +{ + /* Remove the entry from the list */ + RemoveEntryList(&CacheEntry->CacheLink); + + /* Free record */ + DnsIntFreeRecordList((PDNS_RECORD)CacheEntry->Record); + + /* Delete us */ + RtlFreeHeap(RtlGetProcessHeap(), 0, CacheEntry); + + /* Decrease our count */ + DnsCache.ItemCount--; +} + +VOID +DnsIntCacheFlush(VOID) +{ + PLIST_ENTRY Entry; + PTCACHE_ENTRY CacheEntry; + + /* Acquire lock */ + DnsCacheLock(); + + /* Loop every entry */ + Entry = DnsCache.RecordList.Flink; + while (Entry != &DnsCache.RecordList) + { + /* Get this entry */ + CacheEntry = CONTAINING_RECORD(Entry, TCACHE_ENTRY, CacheLink); + + /* Remove it from list */ + DnsIntCacheRemoveEntryItem(CacheEntry); + + /* Move to the next entry */ + Entry = DnsCache.RecordList.Flink; + } + + /* Release and delete the lock */ + DnsCacheUnlock(); +} + +BOOL +DnsIntCacheGetEntryFromName(LPCWSTR Name, + PDNS_RECORDW *Record) +{ + BOOL Ret = FALSE; + PLIST_ENTRY NextEntry = DnsCache.RecordList.Flink; + PTCACHE_ENTRY Entry; + + /* Assume failure */ + *Record = NULL; + + /* Lock the cache */ + DnsCacheLock(); + + /* Match the Id with all the entries in the List */ + while (NextEntry != &DnsCache.RecordList) + { + /* Get the Current Entry */ + Entry = CONTAINING_RECORD(NextEntry, TCACHE_ENTRY, CacheLink); + NextEntry = NextEntry->Flink; + + /* Check if this is the Catalog Entry ID we want */ + if (_wcsnicmp(Entry->Record->pName, Name, NI_MAXHOST) == 0) + { + /* Copy the entry and return it */ + *Record = (PDNS_RECORDW)DnsRecordCopyEx((PDNS_RECORD)Entry->Record, DnsCharSetUnicode, DnsCharSetUnicode);; + Ret = TRUE; + break; + } + } + + /* Release the catalog */ + DnsCacheUnlock(); + + /* Return */ + return Ret; +} + +VOID +DnsIntCacheAddEntry(PDNS_RECORDW Record) +{ + PTCACHE_ENTRY Entry; + + /* Lock the cache */ + DnsCacheLock(); + + /* Match the Id with all the entries in the List */ + Entry = (PTCACHE_ENTRY)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(*Entry)); + if (!Entry) + return; + Entry->Record = Record; + + /* Insert it to our List */ + InsertTailList(&DnsCache.RecordList, &Entry->CacheLink); + + /* Increase our count */ + DnsCache.ItemCount++; + + /* Release the catalog */ + DnsCacheUnlock(); +} Index: dll/win32/dnsapi/dnsapi/pipe.c =================================================================== --- dll/win32/dnsapi/dnsapi/pipe.c (revision 0) +++ dll/win32/dnsapi/dnsapi/pipe.c (working copy) @@ -0,0 +1,109 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/dnsapi/dnsapi/pipe.c + * PURPOSE: DNS client pipe + * PROGRAMMER: Peter Hater + */ + +#include "precomp.h" + +#define NDEBUG +#include + +static HANDLE CommPipe = INVALID_HANDLE_VALUE, CommThread; +DWORD CommThrId; + +DWORD PipeSend(COMM_DNS_REPLY *Reply) +{ + DWORD Written = 0; + BOOL Success = WriteFile(CommPipe, + Reply, + sizeof(*Reply), + &Written, + NULL); + return Success ? Written : -1; +} + +DWORD WINAPI PipeThreadProc(LPVOID Parameter) +{ + DWORD BytesRead; + COMM_DNS_REQ Req; + COMM_DNS_REPLY Reply; + BOOL Result, Connected; + + while (TRUE) + { + Connected = ConnectNamedPipe(CommPipe, NULL) ? TRUE : GetLastError() == ERROR_PIPE_CONNECTED; + + if (!Connected) + { + DPRINT1("DNSAPI: Could not connect named pipe\n"); + CloseHandle(CommPipe); + CommPipe = INVALID_HANDLE_VALUE; + break; + } + + Result = ReadFile(CommPipe, &Req, sizeof(Req), &BytesRead, NULL); + if (Result) + { + switch (Req.Type) { + case DnsReqQueryRecord: + DnsPipedQueryRecord(PipeSend, &Req); + break; + + case DnsReqAddRecord: + DnsPipedAddRecord(PipeSend, &Req); + break; + + case DnsReqFlushAllRecords: + DnsPipedFlushAllRecords(PipeSend, &Req); + break; + + default: + DPRINT1("DNSAPI: Unrecognized request type %d\n", Req.Type); + ZeroMemory(&Reply, sizeof(COMM_DNS_REPLY)); + Reply.Reply = 0; + PipeSend(&Reply); + break; + } + } + DisconnectNamedPipe(CommPipe); + } + + return TRUE; +} + +HANDLE PipeInit(VOID) +{ + CommPipe = CreateNamedPipeW(DNS_PIPE_NAME, + PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + 1, + COMM_PIPE_OUTPUT_BUFFER, + COMM_PIPE_INPUT_BUFFER, + COMM_PIPE_DEFAULT_TIMEOUT, + NULL); + + if (CommPipe == INVALID_HANDLE_VALUE) + { + DPRINT("DNSAPI: Could not create named pipe\n"); + return CommPipe; + } + + CommThread = CreateThread(NULL, 0, PipeThreadProc, NULL, 0, &CommThrId); + + if (!CommThread) + { + CloseHandle(CommPipe); + CommPipe = INVALID_HANDLE_VALUE; + } + + return CommPipe; +} + +VOID PipeDestroy(VOID) +{ + CloseHandle(CommPipe); + CommPipe = INVALID_HANDLE_VALUE; +} Index: dll/win32/dnsapi/dnsapi/query.c =================================================================== --- dll/win32/dnsapi/dnsapi/query.c (revision 72964) +++ dll/win32/dnsapi/dnsapi/query.c (working copy) @@ -588,6 +588,8 @@ return Address; } +#define CNAME_LOOP_MAX 16 + DNS_STATUS WINAPI DnsQuery_W(LPCWSTR Name, WORD Type, @@ -601,16 +603,21 @@ int adns_error; adns_answer *answer; LPSTR CurrentName; - unsigned i, CNameLoop; + unsigned i, CNameLoop, NumAliases = 0; PFIXED_INFO network_info; ULONG network_info_blen = 0; - DWORD network_info_result; + DWORD error; PIP_ADDR_STRING pip; IP4_ADDRESS Address; + PDNS_RECORDW DnsRecord; struct in_addr addr; PCHAR HostWithDomainName; PCHAR AnsiName; + PCHAR Aliases[CNAME_LOOP_MAX]; size_t NameLen = 0; + DNS_STATUS Status; + DWORD DnsClientVersion; + PVOID hHeap; if (Name == NULL) return ERROR_INVALID_PARAMETER; @@ -620,6 +627,7 @@ return ERROR_INVALID_PARAMETER; *QueryResultSet = 0; + hHeap = RtlGetProcessHeap(); switch (Type) { @@ -633,7 +641,7 @@ 0, NULL, 0); - AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen); + AnsiName = RtlAllocateHeap(hHeap, 0, NameLen); if (NULL == AnsiName) { return ERROR_OUTOFMEMORY; @@ -650,8 +658,8 @@ /* Is it an IPv4 address? */ if (ParseV4Address(AnsiName, &Address)) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); + RtlFreeHeap(hHeap, 0, AnsiName); + *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORD)); if (NULL == *QueryResultSet) { @@ -674,7 +682,7 @@ if (AnsiName[0] == '-' || AnsiName[0] == '_' || AnsiName[NameLen - 1] == '-' || AnsiName[NameLen - 1] == '_' || strstr(AnsiName, "..") != NULL) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); + RtlFreeHeap(hHeap, 0, AnsiName); return ERROR_INVALID_NAME; } i = 0; @@ -685,7 +693,7 @@ (AnsiName[i] >= '0' && AnsiName[i] <= '9') || AnsiName[i] == '-' || AnsiName[i] == '_' || AnsiName[i] == '.')) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); + RtlFreeHeap(hHeap, 0, AnsiName); return ERROR_INVALID_NAME; } i++; @@ -695,8 +703,8 @@ { if ((Address = FindEntryInHosts(AnsiName)) != 0) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); + RtlFreeHeap(hHeap, 0, AnsiName); + *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORD)); if (NULL == *QueryResultSet) { @@ -714,29 +722,52 @@ } } - network_info_result = GetNetworkParams(NULL, &network_info_blen); - network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen); + if ((Options & DNS_QUERY_BYPASS_CACHE) == 0) + { + error = DnsCApiInitialize(&DnsClientVersion); + if (error == ERROR_SUCCESS) + { + DPRINT("Connected to DNS Client service v%ld\n", DnsClientVersion); + if (DnsCApiQueryRecord(Name, (PDNS_RECORDW *)QueryResultSet)) + { + DPRINT("Found entry for %ls in cache %lx\n", Name, (*QueryResultSet)->Data.A.IpAddress); + } + else + { + DPRINT("Entry for %ls not found in cache\n", Name); + } + DnsCApiCleanup(); + if (*QueryResultSet && (*QueryResultSet)->pName) + { + RtlFreeHeap(hHeap, 0, AnsiName); + return ERROR_SUCCESS; + } + } + } + + GetNetworkParams(NULL, &network_info_blen); + network_info = (PFIXED_INFO)RtlAllocateHeap(hHeap, 0, (size_t)network_info_blen); if (NULL == network_info) { return ERROR_OUTOFMEMORY; } - network_info_result = GetNetworkParams(network_info, &network_info_blen); - if (network_info_result != ERROR_SUCCESS) + error = GetNetworkParams(network_info, &network_info_blen); + if (error != ERROR_SUCCESS) { - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); - return network_info_result; + RtlFreeHeap(hHeap, 0, network_info); + return error; } if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0) { size_t TempLen = 2, StringLength = 0; - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); + RtlFreeHeap(hHeap, 0, AnsiName); StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength); TempLen += StringLength; StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength); TempLen += StringLength; - HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen); + HostWithDomainName = (PCHAR)RtlAllocateHeap(hHeap, 0, TempLen); StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName); if (network_info->DomainName) { @@ -743,12 +774,12 @@ StringCchCatA(HostWithDomainName, TempLen, "."); StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName); } - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); + RtlFreeHeap(hHeap, 0, network_info); + *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORD)); if (NULL == *QueryResultSet) { - RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName); + RtlFreeHeap(hHeap, 0, HostWithDomainName); return ERROR_OUTOFMEMORY; } @@ -759,14 +790,14 @@ (*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName); - RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName); + RtlFreeHeap(hHeap, 0, HostWithDomainName); return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; } if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); + RtlFreeHeap(hHeap, 0, AnsiName); + RtlFreeHeap(hHeap, 0, network_info); return ERROR_FILE_NOT_FOUND; } @@ -773,8 +804,8 @@ adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0); if (adns_error != adns_s_ok) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); + RtlFreeHeap(hHeap, 0, AnsiName); + RtlFreeHeap(hHeap, 0, network_info); return DnsIntTranslateAdnsToDNS_STATUS(adns_error); } for (pip = &(network_info->DnsServerList); pip; pip = pip->Next) @@ -787,7 +818,7 @@ { adns_ccf_search(astate, "LOCALDOMAIN", -1, network_info->DomainName); } - RtlFreeHeap(RtlGetProcessHeap(), 0, network_info); + RtlFreeHeap(hHeap, 0, network_info); if (Servers) { @@ -810,8 +841,6 @@ * CNAME loops. */ -#define CNAME_LOOP_MAX 16 - CurrentName = AnsiName; for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++) @@ -820,27 +849,18 @@ if (adns_error != adns_s_ok) { - adns_finish(astate); - - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - return DnsIntTranslateAdnsToDNS_STATUS(adns_error); + Status = DnsIntTranslateAdnsToDNS_STATUS(adns_error); + goto exit; } if (answer && answer->rrs.addr) { - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); + *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(hHeap, 0, sizeof(DNS_RECORD)); - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD)); - if (NULL == *QueryResultSet) { - adns_finish(astate); - return ERROR_OUTOFMEMORY; + Status = ERROR_OUTOFMEMORY; + goto exit; } (*QueryResultSet)->pNext = NULL; @@ -848,45 +868,64 @@ (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA); (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr; - adns_finish(astate); - + error = DnsCApiInitialize(&DnsClientVersion); + if (error == ERROR_SUCCESS) + { + DPRINT("Connected to DNS Client service v%ld\n", DnsClientVersion); + for (i = 0; i < NumAliases; i++) + { + DnsRecord = (PDNS_RECORDW)*QueryResultSet; + DnsRecord->pName = DnsCToW(Aliases[i]); + if (!DnsCApiAddRecord(DnsRecord)) + { + DPRINT("Failed to add entry for %ls to cache\n", DnsRecord->pName); + } + RtlFreeHeap(hHeap, 0, Aliases[i]); + RtlFreeHeap(hHeap, 0, DnsRecord->pName); + } + } (*QueryResultSet)->pName = (LPSTR)xstrsave(Name); - - return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + if (error == ERROR_SUCCESS) + { + if (!DnsCApiAddRecord((PDNS_RECORDW)*QueryResultSet)) + { + DPRINT("Failed to add entry for %ls to cache\n", Name); + } + DnsCApiCleanup(); + } + Status = (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY; + goto exit; } if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname) { - adns_finish(astate); - - if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - return ERROR_FILE_NOT_FOUND; + Status = ERROR_FILE_NOT_FOUND; + goto exit; } if (CurrentName != AnsiName) - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); + { + Aliases[NumAliases++] = CurrentName; + } CurrentName = (LPSTR)xstrsaveA(answer->cname); if (!CurrentName) { - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - adns_finish(astate); - return ERROR_OUTOFMEMORY; + Status = ERROR_OUTOFMEMORY; + goto exit; } } - adns_finish(astate); - RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName); - RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName); - return ERROR_FILE_NOT_FOUND; - default: return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */ } + +exit: + adns_finish(astate); + if (CurrentName && CurrentName != AnsiName) RtlFreeHeap(hHeap, 0, CurrentName); + if (AnsiName) RtlFreeHeap(hHeap, 0, AnsiName); + return Status; } DNS_STATUS WINAPI @@ -943,3 +982,19 @@ ToDelete = next; } } + +DNS_STATUS WINAPI +DnsFlushResolverCache() +{ + DWORD DnsClientVersion; + DWORD error = DnsCApiInitialize(&DnsClientVersion); + if (error != ERROR_SUCCESS) + return ERROR_PIPE_NOT_CONNECTED; + DPRINT("Connected to DNS Client service v%ld\n", DnsClientVersion); + if (!DnsCApiFlushAllRecords()) + { + DPRINT("DNS cache flushing error\n"); + } + DnsCApiCleanup(); + return ERROR_SUCCESS; +} Index: dll/win32/dnsapi/dnsapi/service.c =================================================================== --- dll/win32/dnsapi/dnsapi/service.c (revision 0) +++ dll/win32/dnsapi/dnsapi/service.c (working copy) @@ -0,0 +1,324 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/dnsapi/dnsapi/service.c + * PURPOSE: DNSAPI service functions. + * PROGRAMER: Peter Hater + */ + +#include "precomp.h" +#include +#include + +#define NDEBUG +#include + +static WCHAR ServiceName[] = L"DNS"; + +SERVICE_STATUS_HANDLE ServiceStatusHandle = 0; +SERVICE_STATUS ServiceStatus; + +static HANDLE PipeHandle = INVALID_HANDLE_VALUE; + +DWORD +DnsCApiInitialize(LPDWORD Version) +{ + DWORD PipeMode; + + /* Wait for the pipe to be available */ + if (!WaitNamedPipeW(DNS_PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT)) + { + /* No good, we failed */ + return GetLastError(); + } + + /* It's available, let's try to open it */ + PipeHandle = CreateFileW(DNS_PIPE_NAME, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + /* Check if we succeeded in opening the pipe */ + if (PipeHandle == INVALID_HANDLE_VALUE) + { + /* We didn't */ + return GetLastError(); + } + + /* Change the pipe into message mode */ + PipeMode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState(PipeHandle, &PipeMode, NULL, NULL)) + { + /* Mode change failed */ + CloseHandle(PipeHandle); + PipeHandle = INVALID_HANDLE_VALUE; + return GetLastError(); + } + else + { + /* We're good to go */ + *Version = 1; + return NO_ERROR; + } +} + +VOID +DnsCApiCleanup(VOID) +{ + CloseHandle(PipeHandle); + PipeHandle = INVALID_HANDLE_VALUE; +} + +BOOL +DnsCApiQueryRecord(LPCWSTR Name, PDNS_RECORDW* Record) +{ + COMM_DNS_REQ Req; + COMM_DNS_REPLY Reply; + DWORD BytesRead; + BOOL Result; + + ASSERT(PipeHandle != INVALID_HANDLE_VALUE); + + Req.Type = DnsReqQueryRecord; + /* Fix up pointers for sending */ + Req.Name = (LPWSTR)Req.Data; + StringCchCopy(Req.Name, NI_MAXHOST, Name); + + Result = TransactNamedPipe(PipeHandle, + &Req, sizeof(Req), + &Reply, sizeof(Reply), + &BytesRead, NULL); + if (!Result) + { + /* Pipe transaction failed */ + return FALSE; + } + + if (!Reply.Reply) + return FALSE; + + if (Record) + { + /* Fix up pointers after receive */ + Reply.Record.pName = (LPWSTR)Reply.Data; + *Record = (PDNS_RECORDW)DnsRecordCopyEx((PDNS_RECORD)&Reply.Record, DnsCharSetUnicode, DnsCharSetUnicode); + } + + return TRUE; +} + +BOOL +DnsCApiAddRecord(PDNS_RECORDW Record) +{ + COMM_DNS_REQ Req; + COMM_DNS_REPLY Reply; + DWORD BytesRead; + BOOL Result; + + ASSERT(PipeHandle != INVALID_HANDLE_VALUE); + ASSERT(Record != NULL); + + Req.Type = DnsReqAddRecord; + RtlCopyMemory(&Req.Record, Record, sizeof(DNS_RECORDW)); + /* FIXME: Currently only record without names in DNS_RECORD.Data */ + RtlCopyMemory(&Req.Record.Data, &Record->Data, Record->wDataLength); + /* Fix up pointers for sending */ + Req.Record.pName = (LPWSTR)Req.Data; + StringCchCopy(Req.Record.pName, NI_MAXHOST, Record->pName); + + Result = TransactNamedPipe(PipeHandle, + &Req, sizeof(Req), + &Reply, sizeof(Reply), + &BytesRead, NULL); + if (!Result) + { + /* Pipe transaction failed */ + return FALSE; + } + + if (!Reply.Reply) + return FALSE; + + return TRUE; +} + +BOOL +DnsCApiFlushAllRecords(VOID) +{ + COMM_DNS_REQ Req; + COMM_DNS_REPLY Reply; + DWORD BytesRead; + BOOL Result; + + ASSERT(PipeHandle != INVALID_HANDLE_VALUE); + + Req.Type = DnsReqFlushAllRecords; + + Result = TransactNamedPipe(PipeHandle, + &Req, sizeof(Req), + &Reply, sizeof(Reply), + &BytesRead, NULL); + if (!Result) + { + /* Pipe transaction failed */ + return FALSE; + } + + if (!Reply.Reply) + return FALSE; + + return TRUE; +} + +DWORD +DnsPipedQueryRecord(PipeSendFunc Send, COMM_DNS_REQ *Req) +{ + COMM_DNS_REPLY Reply; + PDNS_RECORDW TempDnsRecord; + + /* Fix up pointers after receive */ + Req->Name = (LPWSTR)Req->Data; + Reply.Reply = DnsIntCacheGetEntryFromName(Req->Name, &TempDnsRecord); // TRUE/FALSE ret + if (Reply.Reply) + { + /* FIXME: Fixup record names in DNS_RECORD.Data and add it the size */ + RtlCopyMemory(&Reply.Record, TempDnsRecord, sizeof(DNS_RECORDW)); + RtlCopyMemory(&Reply.Record.Data, &TempDnsRecord->Data, TempDnsRecord->wDataLength); + /* Fix up pointers for sending */ + Reply.Record.pName = (LPWSTR)Reply.Data; + StringCchCopy(Reply.Record.pName, NI_MAXHOST, TempDnsRecord->pName); + DnsIntFreeRecordList((PDNS_RECORD)TempDnsRecord); + } + return Send(&Reply); +} + +DWORD +DnsPipedAddRecord(PipeSendFunc Send, COMM_DNS_REQ *Req) +{ + COMM_DNS_REPLY Reply; + PDNS_RECORDW Record; + + /* Fix up pointers after receive */ + Req->Record.pName = (LPWSTR)Req->Data; + Record = (PDNS_RECORDW)DnsRecordCopyEx((PDNS_RECORD)&Req->Record, DnsCharSetUnicode, DnsCharSetUnicode); + DnsIntCacheAddEntry(Record); + Reply.Reply = 1; // TRUE/FALSE ret + + return Send(&Reply); +} + +DWORD +DnsPipedFlushAllRecords(PipeSendFunc Send, COMM_DNS_REQ *Req) +{ + COMM_DNS_REPLY Reply; + + DnsIntCacheFlush(); + Reply.Reply = 1; // TRUE/FALSE ret + + return Send(&Reply); +} + +static VOID +UpdateServiceStatus(DWORD dwState) +{ + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = dwState; + + ServiceStatus.dwControlsAccepted = 0; + + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + + if (dwState == SERVICE_START_PENDING || + dwState == SERVICE_STOP_PENDING || + dwState == SERVICE_PAUSE_PENDING || + dwState == SERVICE_CONTINUE_PENDING) + ServiceStatus.dwWaitHint = 10000; + else + ServiceStatus.dwWaitHint = 0; + + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); +} + +static DWORD WINAPI +ServiceControlHandler(DWORD dwControl, + DWORD dwEventType, + LPVOID lpEventData, + LPVOID lpContext) +{ + switch (dwControl) + { + case SERVICE_CONTROL_STOP: + UpdateServiceStatus(SERVICE_STOP_PENDING); + DPRINT("DNSAPISVC: DNS Client Service is shutting down\n"); + PipeDestroy(); + DnsIntCacheFree(); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_PAUSE: + UpdateServiceStatus(SERVICE_PAUSE_PENDING); + PipeDestroy(); + UpdateServiceStatus(SERVICE_PAUSED); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_CONTINUE: + UpdateServiceStatus(SERVICE_START_PENDING); + if (PipeInit() == INVALID_HANDLE_VALUE) + { + DPRINT1("DNSAPISVC: PipeInit() failed!\n"); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_PIPE_NOT_CONNECTED; // FALSE + } + UpdateServiceStatus(SERVICE_RUNNING); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_INTERROGATE: + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + return ERROR_SUCCESS; + + case SERVICE_CONTROL_SHUTDOWN: + UpdateServiceStatus(SERVICE_STOP_PENDING); + DPRINT("DNSAPISVC: DNS Client Service is shutting down\n"); + PipeDestroy(); + DnsIntCacheFree(); + UpdateServiceStatus(SERVICE_STOPPED); + return ERROR_SUCCESS; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; + } +} + +VOID WINAPI +ServiceMain(DWORD argc, LPWSTR* argv) +{ + ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName, + ServiceControlHandler, + NULL); + if (!ServiceStatusHandle) + { + DPRINT1("DNSAPISVC: Unable to register service control handler (%lx)\n", GetLastError()); + return; // FALSE + } + + UpdateServiceStatus(SERVICE_START_PENDING); + + DnsIntCacheInitialize(); + + if (PipeInit() == INVALID_HANDLE_VALUE) + { + DPRINT1("DNSAPISVC: PipeInit() failed!\n"); + DnsIntCacheFree(); + UpdateServiceStatus(SERVICE_STOPPED); + return; // FALSE + } + + DPRINT("DNSAPISVC: DNS Client Service Started\n"); + + UpdateServiceStatus(SERVICE_RUNNING); +} Index: dll/win32/dnsapi/dnsapi/stubs.c =================================================================== --- dll/win32/dnsapi/dnsapi/stubs.c (revision 72964) +++ dll/win32/dnsapi/dnsapi/stubs.c (working copy) @@ -216,13 +216,6 @@ return ERROR_OUTOFMEMORY; } -DNS_STATUS WINAPI -DnsFlushResolverCache() -{ - UNIMPLEMENTED; - return ERROR_OUTOFMEMORY; -} - BOOL WINAPI DnsFlushResolverCacheEntry_A(PCSTR entry) { Index: dll/win32/dnsapi/include/internal/windns.h =================================================================== --- dll/win32/dnsapi/include/internal/windns.h (revision 72964) +++ dll/win32/dnsapi/include/internal/windns.h (working copy) @@ -8,7 +8,79 @@ adns_state State; } WINDNS_CONTEXT, *PWINDNS_CONTEXT; +typedef struct _TCACHE_ENTRY +{ + LIST_ENTRY CacheLink; + PDNS_RECORDW Record; +} TCACHE_ENTRY, *PTCACHE_ENTRY; + +typedef struct _TCACHE +{ + LIST_ENTRY RecordList; + DWORD ItemCount; + RTL_CRITICAL_SECTION Lock; +} TCACHE, *PTCACHE; + DNS_STATUS DnsIntTranslateAdnsToDNS_STATUS(int Status); void DnsIntFreeRecordList(PDNS_RECORD ToFree); +VOID DnsIntCacheInitialize(VOID); +VOID DnsIntCacheRemoveEntryItem(PTCACHE_ENTRY CacheEntry); +VOID DnsIntCacheFree(VOID); +VOID DnsIntCacheFlush(VOID); +BOOL DnsIntCacheGetEntryFromName(LPCWSTR Name, + PDNS_RECORDW *Record); +VOID DnsIntCacheAddEntry(PDNS_RECORDW Record); + +/* pipe operations */ +enum +{ + DnsReqQueryRecord, + DnsReqAddRecord, + DnsReqFlushAllRecords, +}; + +/* pipe communication structures */ +typedef struct _COMM_DNS_REQ +{ + UINT Type; + LPWSTR Name; + DNS_RECORDW Record; + BYTE Data[NI_MAXHOST*sizeof(WCHAR)]; +} COMM_DNS_REQ; + +typedef struct _COMM_DNS_REPLY +{ + DWORD Reply; + DNS_RECORDW Record; + BYTE Data[NI_MAXHOST*sizeof(WCHAR)]; +} COMM_DNS_REPLY; + +/* pipe name */ +#define DNS_PIPE_NAME L"\\\\.\\pipe\\dnsclient" + +#define COMM_PIPE_OUTPUT_BUFFER sizeof(COMM_DNS_REQ) +#define COMM_PIPE_INPUT_BUFFER sizeof(COMM_DNS_REPLY) +#define COMM_PIPE_DEFAULT_TIMEOUT 1000 + +typedef DWORD(*PipeSendFunc)(COMM_DNS_REPLY *Reply); + +/* these do the real work */ +DWORD DnsPipedQueryRecord(PipeSendFunc Send, COMM_DNS_REQ *Req); +DWORD DnsPipedAddRecord(PipeSendFunc Send, COMM_DNS_REQ *Req); +DWORD DnsPipedFlushAllRecords(PipeSendFunc Send, COMM_DNS_REQ *Req); + +/* pipe internals */ +HANDLE PipeInit(VOID); +DWORD PipeSend(COMM_DNS_REPLY *Reply); +VOID PipeDestroy(VOID); + +/* Dns piped api */ +DWORD DnsCApiInitialize(LPDWORD Version); +VOID DnsCApiCleanup(VOID); + +BOOL DnsCApiQueryRecord(LPCWSTR Name, PDNS_RECORDW *Record); +BOOL DnsCApiAddRecord(PDNS_RECORDW Record); +BOOL DnsCApiFlushAllRecords(VOID); + #endif /* WINDNS_INTERNAL_H */ Index: media/inf/nettcpip.inf =================================================================== --- media/inf/nettcpip.inf (revision 72964) +++ media/inf/nettcpip.inf (working copy) @@ -235,6 +235,7 @@ [MS_TCPIP.PrimaryInstall.Services] AddService = Tcpip, , tcpip_Service_Inst AddService = DHCP, , dhcp_Service_Inst +AddService = DNS, , dns_Service_Inst [tcpip_Service_Inst] ServiceType = 1 @@ -269,6 +270,20 @@ HKR,,"ObjectName",0x00000000,"LocalSystem" HKR,"Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dhcpcsvc.dll" +[dns_Service_Inst] +DisplayName = "DNS Client" +Description = "Service that caches local DNS queries" +ServiceType = 0x20 +StartType = 2 +ErrorControl = 1 +ServiceBinary = "%11%\svchost.exe -k netsvcs" +LoadOrderGroup = TDI +AddReg=dns_AddReg + +[dns_AddReg] +HKR,,"ObjectName",0x00000000,"LocalSystem" +HKR,"Parameters","ServiceDll",0x00020000,"%SystemRoot%\system32\dnsapi.dll" + ;-------------------------------- STRINGS ------------------------------- [Strings]