xref: /reactos/base/services/dnsrslvr/cache.c (revision 019f21ee)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS system libraries
4  * FILE:        base/services/dnsrslvr/cache.c
5  * PURPOSE:     DNS cache functions
6  * PROGRAMMER:  Peter Hater
7  */
8 
9 #include "precomp.h"
10 
11 //#define NDEBUG
12 #include <debug.h>
13 
14 static RESOLVER_CACHE DnsCache;
15 static BOOL DnsCacheInitialized = FALSE;
16 
17 #define DnsCacheLock()          do { EnterCriticalSection(&DnsCache.Lock); } while (0)
18 #define DnsCacheUnlock()        do { LeaveCriticalSection(&DnsCache.Lock); } while (0)
19 
20 VOID
21 DnsIntCacheInitialize(VOID)
22 {
23     DPRINT("DnsIntCacheInitialize()\n");
24 
25     /* Check if we're initialized */
26     if (DnsCacheInitialized)
27         return;
28 
29     /* Initialize the cache lock and namespace list */
30     InitializeCriticalSection((LPCRITICAL_SECTION)&DnsCache.Lock);
31     InitializeListHead(&DnsCache.RecordList);
32     DnsCacheInitialized = TRUE;
33 }
34 
35 VOID
36 DnsIntCacheFree(VOID)
37 {
38     DPRINT("DnsIntCacheFree()\n");
39 
40     /* Check if we're initialized */
41     if (!DnsCacheInitialized)
42         return;
43 
44     if (!DnsCache.RecordList.Flink)
45         return;
46 
47     DnsIntCacheFlush(CACHE_FLUSH_ALL);
48 
49     DeleteCriticalSection(&DnsCache.Lock);
50     DnsCacheInitialized = FALSE;
51 }
52 
53 VOID
54 DnsIntCacheRemoveEntryItem(PRESOLVER_CACHE_ENTRY CacheEntry)
55 {
56     DPRINT("DnsIntCacheRemoveEntryItem(%p)\n", CacheEntry);
57 
58     /* Remove the entry from the list */
59     RemoveEntryList(&CacheEntry->CacheLink);
60 
61     /* Free record */
62     DnsRecordListFree(CacheEntry->Record, DnsFreeRecordList);
63 
64     /* Delete us */
65     HeapFree(GetProcessHeap(), 0, CacheEntry);
66 }
67 
68 DNS_STATUS
69 DnsIntCacheFlush(
70     _In_ ULONG ulFlags)
71 {
72     PLIST_ENTRY Entry, NextEntry;
73     PRESOLVER_CACHE_ENTRY CacheEntry;
74 
75     DPRINT("DnsIntCacheFlush(%lu)\n", ulFlags);
76 
77     /* Lock the cache */
78     DnsCacheLock();
79 
80     /* Loop every entry */
81     Entry = DnsCache.RecordList.Flink;
82     while (Entry != &DnsCache.RecordList)
83     {
84         NextEntry = Entry->Flink;
85 
86         /* Get this entry */
87         CacheEntry = CONTAINING_RECORD(Entry, RESOLVER_CACHE_ENTRY, CacheLink);
88 
89         /* Remove it from list */
90         if (((ulFlags & CACHE_FLUSH_HOSTS_FILE_ENTRIES) && (CacheEntry->bHostsFileEntry != FALSE)) ||
91             ((ulFlags & CACHE_FLUSH_NON_HOSTS_FILE_ENTRIES) && (CacheEntry->bHostsFileEntry == FALSE)))
92             DnsIntCacheRemoveEntryItem(CacheEntry);
93 
94         /* Move to the next entry */
95         Entry = NextEntry;
96     }
97 
98     /* Unlock the cache */
99     DnsCacheUnlock();
100 
101     return ERROR_SUCCESS;
102 }
103 
104 DNS_STATUS
105 DnsIntCacheGetEntryByName(
106     LPCWSTR Name,
107     WORD wType,
108     DWORD dwFlags,
109     PDNS_RECORDW *Record)
110 {
111     DNS_STATUS Status = DNS_INFO_NO_RECORDS;
112     PRESOLVER_CACHE_ENTRY CacheEntry;
113     PLIST_ENTRY NextEntry;
114 
115     DPRINT("DnsIntCacheGetEntryByName(%S %hu 0x%lx %p)\n",
116            Name, wType, dwFlags, Record);
117 
118     /* Assume failure */
119     *Record = NULL;
120 
121     /* Lock the cache */
122     DnsCacheLock();
123 
124     /* Match the Id with all the entries in the List */
125     NextEntry = DnsCache.RecordList.Flink;
126     while (NextEntry != &DnsCache.RecordList)
127     {
128         /* Get the Current Entry */
129         CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
130 
131         /* Check if this is the Catalog Entry ID we want */
132         if (_wcsicmp(CacheEntry->Record->pName, Name) == 0)
133         {
134             /* Copy the entry and return it */
135             *Record = DnsRecordSetCopyEx(CacheEntry->Record, DnsCharSetUnicode, DnsCharSetUnicode);
136             Status = ERROR_SUCCESS;
137             break;
138         }
139 
140         NextEntry = NextEntry->Flink;
141     }
142 
143     /* Release the cache */
144     DnsCacheUnlock();
145 
146     return Status;
147 }
148 
149 BOOL
150 DnsIntCacheRemoveEntryByName(LPCWSTR Name)
151 {
152     BOOL Ret = FALSE;
153     PRESOLVER_CACHE_ENTRY CacheEntry;
154     PLIST_ENTRY NextEntry;
155 
156     DPRINT("DnsIntCacheRemoveEntryByName(%S)\n", Name);
157 
158     /* Lock the cache */
159     DnsCacheLock();
160 
161     /* Match the Id with all the entries in the List */
162     NextEntry = DnsCache.RecordList.Flink;
163     while (NextEntry != &DnsCache.RecordList)
164     {
165         /* Get the Current Entry */
166         CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
167 
168         /* Check if this is the Catalog Entry ID we want */
169         if (_wcsicmp(CacheEntry->Record->pName, Name) == 0)
170         {
171             /* Remove the entry */
172             DnsIntCacheRemoveEntryItem(CacheEntry);
173             Ret = TRUE;
174             break;
175         }
176 
177         NextEntry = NextEntry->Flink;
178     }
179 
180     /* Release the cache */
181     DnsCacheUnlock();
182 
183     /* Return */
184     return Ret;
185 }
186 
187 VOID
188 DnsIntCacheAddEntry(
189     _In_ PDNS_RECORDW Record,
190     _In_ BOOL bHostsFileEntry)
191 {
192     PRESOLVER_CACHE_ENTRY Entry;
193 
194     DPRINT("DnsIntCacheAddEntry(%p %u)\n",
195            Record, bHostsFileEntry);
196 
197     DPRINT("Name: %S\n", Record->pName);
198     DPRINT("TTL: %lu\n", Record->dwTtl);
199 
200     /* Lock the cache */
201     DnsCacheLock();
202 
203     /* Match the Id with all the entries in the List */
204     Entry = (PRESOLVER_CACHE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(*Entry));
205     if (!Entry)
206         return;
207 
208     Entry->bHostsFileEntry = bHostsFileEntry;
209     Entry->Record = DnsRecordSetCopyEx(Record, DnsCharSetUnicode, DnsCharSetUnicode);
210 
211     /* Insert it to our List */
212     InsertTailList(&DnsCache.RecordList, &Entry->CacheLink);
213 
214     /* Release the cache */
215     DnsCacheUnlock();
216 }
217 
218 DNS_STATUS
219 DnsIntCacheGetEntries(
220     _Out_ DNS_CACHE_ENTRY **ppCacheEntries)
221 {
222     PRESOLVER_CACHE_ENTRY CacheEntry;
223     PLIST_ENTRY NextEntry;
224     PDNS_CACHE_ENTRY pLastEntry = NULL, pNewEntry;
225 
226     /* Lock the cache */
227     DnsCacheLock();
228 
229     *ppCacheEntries = NULL;
230 
231     NextEntry = DnsCache.RecordList.Flink;
232     while (NextEntry != &DnsCache.RecordList)
233     {
234         /* Get the Current Entry */
235         CacheEntry = CONTAINING_RECORD(NextEntry, RESOLVER_CACHE_ENTRY, CacheLink);
236 
237         DPRINT("1 %S %lu\n", CacheEntry->Record->pName, CacheEntry->Record->wType);
238         if (CacheEntry->Record->pNext)
239         {
240             DPRINT("2 %S %lu\n", CacheEntry->Record->pNext->pName, CacheEntry->Record->pNext->wType);
241         }
242 
243         pNewEntry = midl_user_allocate(sizeof(DNS_CACHE_ENTRY));
244         if (pNewEntry == NULL)
245         {
246             return ERROR_OUTOFMEMORY;
247         }
248 
249         pNewEntry->pszName = midl_user_allocate((wcslen(CacheEntry->Record->pName) + 1) * sizeof(WCHAR));
250         if (pNewEntry->pszName == NULL)
251         {
252             return ERROR_OUTOFMEMORY;
253         }
254 
255         wcscpy(pNewEntry->pszName, CacheEntry->Record->pName);
256         pNewEntry->wType1 = CacheEntry->Record->wType;
257         pNewEntry->wType2 = 0;
258         pNewEntry->wFlags = 0;
259 
260         if (pLastEntry == NULL)
261             *ppCacheEntries = pNewEntry;
262         else
263             pLastEntry->pNext = pNewEntry;
264         pLastEntry = pNewEntry;
265 
266         NextEntry = NextEntry->Flink;
267     }
268 
269     /* Release the cache */
270     DnsCacheUnlock();
271 
272     return ERROR_SUCCESS;
273 }
274