[CMAKE]
[reactos.git] / dll / win32 / iphlpapi / resinfo_reactos.c
1 /*
2 * iphlpapi dll implementation -- Setting and storing route information
3 *
4 * These are stubs for functions that set routing information on the target
5 * operating system. They are grouped here because their implementation will
6 * vary widely by operating system.
7 *
8 * Copyright (C) 2004 Art Yerkes
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config.h"
25 #include "iphlpapi_private.h"
26
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
32 #endif
33 #ifdef HAVE_ARPA_INET_H
34 # include <arpa/inet.h>
35 #endif
36 #ifdef HAVE_ARPA_NAMESER_H
37 # include <arpa/nameser.h>
38 #endif
39 #ifdef HAVE_RESOLV_H
40 # include <resolv.h>
41 #endif
42
43 #include "windef.h"
44 #include "winbase.h"
45 #include "winreg.h"
46 #include "resinfo.h"
47 #include "iphlpapi.h"
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
51
52 typedef struct _NAME_SERVER_LIST_PRIVATE {
53 UINT NumServers;
54 IP_ADDR_STRING * pCurrent;
55 } NAME_SERVER_LIST_PRIVATE, *PNAME_SERVER_LIST_PRIVATE;
56
57 typedef VOID (*ENUM_INTERFACE_CALLBACK)(
58 HKEY ChildKeyHandle,
59 LPWSTR ChildKeyName,
60 PVOID CallbackContext);
61
62 LSTATUS
63 QueryNameServer(
64 IN HKEY hInterface,
65 IN LPCWSTR NameServerKey,
66 OUT LPWSTR * OutNameServer)
67 {
68 DWORD dwLength, dwType;
69 LPWSTR NameServer;
70 LSTATUS Status;
71
72 /* query ns */
73 dwLength = 0;
74 Status = RegQueryValueExW(hInterface, NameServerKey, NULL, &dwType, NULL, &dwLength);
75
76 if (Status != ERROR_SUCCESS)
77 {
78 /* failed to retrieve size */
79 TRACE("Status %x\n", Status);
80 return Status;
81 }
82
83 /* add terminating null */
84 dwLength += sizeof(WCHAR);
85
86 /* allocate name server */
87 NameServer = HeapAlloc(GetProcessHeap(), 0, dwLength);
88
89 if (!NameServer)
90 {
91 /* no memory */
92 return ERROR_OUTOFMEMORY;
93 }
94
95 /* query ns */
96 Status = RegQueryValueExW(hInterface, NameServerKey, NULL, &dwType, (LPBYTE)NameServer, &dwLength);
97
98 if (Status != ERROR_SUCCESS || dwType != REG_SZ)
99 {
100 /* failed to retrieve ns */
101 HeapFree(GetProcessHeap(), 0, NameServer);
102 return Status;
103 }
104
105 /* null terminate it */
106 NameServer[dwLength / sizeof(WCHAR)] = L'\0';
107
108 /* store result */
109 *OutNameServer = NameServer;
110
111 return STATUS_SUCCESS;
112 }
113
114
115 LSTATUS
116 EnumNameServers(
117 IN HKEY hInterface,
118 IN LPWSTR InterfaceName,
119 PVOID ServerCallbackContext,
120 EnumNameServersFunc CallbackRoutine)
121 {
122 LSTATUS Status;
123 LPWSTR NameServer;
124 WCHAR Buffer[50];
125 DWORD Length;
126 LPWSTR Start, Comma;
127
128 /* query static assigned name server */
129 Status = QueryNameServer(hInterface, L"NameServer", &NameServer);
130 if (Status != ERROR_SUCCESS)
131 {
132 /* query dynamic assigned name server */
133 Status = QueryNameServer(hInterface, L"DhcpNameServer", &NameServer);
134
135 if (Status != ERROR_SUCCESS)
136 {
137 /* failed to retrieve name servers */
138 return Status;
139 }
140 }
141
142 /* enumerate all name servers, terminated by comma */
143 Start = NameServer;
144
145 do
146 {
147 /* find next terminator */
148 Comma = wcschr(Start, L',');
149
150 if (Comma)
151 {
152 /* calculate length */
153 Length = Comma - Start;
154
155 /* copy name server */
156 RtlMoveMemory(Buffer, Start, Length * sizeof(WCHAR));
157
158 /* null terminate it */
159 Buffer[Length] = L'\0';
160
161 /* perform callback */
162 CallbackRoutine(InterfaceName, Buffer, ServerCallbackContext);
163
164 }
165 else
166 {
167 /* perform callback */
168 CallbackRoutine(InterfaceName, Start, ServerCallbackContext);
169
170 /* last entry */
171 break;
172 }
173
174 /* increment offset */
175 Start = Comma + 1;
176
177 }while(TRUE);
178
179 /* free name server string */
180 HeapFree(GetProcessHeap(), 0, NameServer);
181
182 /* done */
183 return ERROR_SUCCESS;
184 }
185
186 LSTATUS
187 EnumInterfaces(
188 ENUM_INTERFACE_CALLBACK CallbackRoutine,
189 PVOID InterfaceCallbackContext)
190 {
191 HKEY hKey, hInterface;
192 LSTATUS Status;
193 DWORD NumInterfaces, InterfaceNameLen, Index, Length;
194 LPWSTR InterfaceName;
195
196 /* first open interface key */
197 Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &hKey);
198
199 /* check for success */
200 if (Status != ERROR_SUCCESS)
201 {
202 /* failed to open interface key */
203 return Status;
204 }
205
206 /* now get maximum interface name length and number of interfaces */
207 Status = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &NumInterfaces, &InterfaceNameLen, NULL, NULL, NULL, NULL, NULL, NULL);
208 if (Status != ERROR_SUCCESS)
209 {
210 /* failed to get key info */
211 RegCloseKey(hKey);
212 return Status;
213 }
214
215 /* RegQueryInfoKey does not include terminating null */
216 InterfaceNameLen++;
217
218 /* allocate interface name */
219 InterfaceName = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, InterfaceNameLen * sizeof(WCHAR));
220
221 if (!InterfaceName)
222 {
223 /* no memory */
224 RegCloseKey(hKey);
225 return ERROR_OUTOFMEMORY;
226 }
227
228 /* no enumerate all interfaces */
229 for(Index = 0; Index < NumInterfaces; Index++)
230 {
231 /* query interface name */
232 Length = InterfaceNameLen;
233 Status = RegEnumKeyExW(hKey, Index, InterfaceName, &Length, NULL, NULL, NULL, NULL);
234
235 if (Status == ERROR_SUCCESS)
236 {
237 /* make sure it is null terminated */
238 InterfaceName[Length] = L'\0';
239
240 /* now open child key */
241 Status = RegOpenKeyExW(hKey, InterfaceName, 0, KEY_READ, &hInterface);
242
243 if (Status == ERROR_SUCCESS)
244 {
245 /* perform enumeration callback */
246 CallbackRoutine(hInterface, InterfaceName, InterfaceCallbackContext);
247
248 /* close interface key */
249 RegCloseKey(hInterface);
250 }
251 }
252 }
253
254 /* free interface name */
255 HeapFree(GetProcessHeap(), 0, InterfaceName);
256
257 /* close root interface key */
258 RegCloseKey(hKey);
259
260 /* done */
261 return Status;
262 }
263
264 VOID
265 CountNameServerCallback(
266 IN LPWSTR InterfaceName,
267 IN LPWSTR Server,
268 IN PVOID CallbackContext)
269 {
270 /* get context */
271 PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)CallbackContext;
272
273 /* increment server count */
274 Data->NumServers++;
275 }
276
277 VOID
278 CountServerCallbackTrampoline(
279 HKEY ChildKeyHandle,
280 LPWSTR ChildKeyName,
281 PVOID CallbackContext)
282 {
283 EnumNameServers(ChildKeyHandle, ChildKeyName, CallbackContext, CountNameServerCallback);
284 }
285
286 LSTATUS
287 CountNameServers(
288 IN PNAME_SERVER_LIST_PRIVATE PrivateData )
289 {
290 return EnumInterfaces(CountServerCallbackTrampoline, (PVOID)PrivateData);
291 }
292
293 VOID
294 CreateNameServerListCallback(
295 IN LPWSTR InterfaceName,
296 IN LPWSTR Server,
297 IN PVOID CallbackContext)
298 {
299 /* get context */
300 PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)CallbackContext;
301
302 /* convert to ansi ns string */
303 if (WideCharToMultiByte(CP_ACP, 0, Server, -1, Data->pCurrent->IpAddress.String, 16, NULL, NULL))
304 {
305 /* store offset to next name server struct */
306 Data->pCurrent->Next = (struct _IP_ADDR_STRING*)(Data->pCurrent + 1);
307
308 /* move to next entry */
309 Data->pCurrent = Data->pCurrent->Next;
310
311 /* increment server count */
312 Data->NumServers++;
313 }
314 else
315 {
316 /* failed to convert dns server */
317 Data->pCurrent->IpAddress.String[0] = '\0';
318 }
319 }
320
321 VOID
322 CreateNameServerListCallbackTrampoline(
323 HKEY ChildKeyHandle,
324 LPWSTR ChildKeyName,
325 PVOID CallbackContext)
326 {
327 EnumNameServers(ChildKeyHandle, ChildKeyName, CallbackContext, CreateNameServerListCallback);
328 }
329
330 LSTATUS
331 MakeNameServerList(
332 PNAME_SERVER_LIST_PRIVATE PrivateData )
333 {
334 return EnumInterfaces(CreateNameServerListCallbackTrampoline, (PVOID)PrivateData);
335 }
336
337 PIPHLP_RES_INFO
338 getResInfo()
339 {
340 NAME_SERVER_LIST_PRIVATE PrivateNSEnum;
341 PIPHLP_RES_INFO ResInfo;
342 IP_ADDR_STRING * DnsList = NULL;
343 LSTATUS Status;
344
345 PrivateNSEnum.NumServers = 0;
346
347 /* count name servers */
348 Status = CountNameServers(&PrivateNSEnum);
349
350 if (Status != ERROR_SUCCESS)
351 {
352 /* failed to enumerate name servers */
353 return NULL;
354 }
355
356 /* are there any servers */
357 if (PrivateNSEnum.NumServers)
358 {
359 /* allocate dns servers */
360 DnsList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PrivateNSEnum.NumServers * sizeof(IP_ADDR_STRING));
361
362 if (!DnsList)
363 {
364 /* no memory */
365 return NULL;
366 }
367 }
368
369 /* allocate private struct */
370 ResInfo = (PIPHLP_RES_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IPHLP_RES_INFO));
371
372 if(!ResInfo)
373 {
374 /* no memory */
375 if (DnsList)
376 {
377 /* free dns list */
378 HeapFree( GetProcessHeap(), 0, DnsList);
379 }
380 return NULL;
381 }
382
383 /* are there any servers */
384 if (PrivateNSEnum.NumServers)
385 {
386 /* initialize enumeration context */
387 PrivateNSEnum.NumServers = 0;
388 PrivateNSEnum.pCurrent = DnsList;
389
390 /* enumerate servers */
391 MakeNameServerList( &PrivateNSEnum );
392
393 /* store result */
394 ResInfo->DnsList = DnsList;
395 ResInfo->riCount = PrivateNSEnum.NumServers;
396 }
397
398 /* done */
399 return ResInfo;
400 }
401
402 VOID disposeResInfo( PIPHLP_RES_INFO InfoPtr )
403 {
404 HeapFree(GetProcessHeap(), 0, InfoPtr->DnsList);
405 RtlFreeHeap( GetProcessHeap(), 0, InfoPtr );
406 }