iphlpapi/tests: Fix compilation on systems that don't support nameless unions.
[wine.git] / dlls / iphlpapi / tests / iphlpapi.c
blob0cbfb31e0e5b16ee674c0b4d1764d56b6ca224e8
1 /*
2 * iphlpapi dll test
4 * Copyright (C) 2003 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Some observations that an automated test can't produce:
23 * An adapter index is a key for an adapter. That is, if an index is returned
24 * from one API, that same index may be used successfully in another API, as
25 * long as the adapter remains present.
26 * If the adapter is removed and reinserted, however, the index may change (and
27 * indeed it does change on Win2K).
29 * The Name field of the IP_ADAPTER_INDEX_MAP entries returned by
30 * GetInterfaceInfo is declared as a wide string, but the bytes are actually
31 * an ASCII string on some versions of the IP helper API under Win9x. This was
32 * apparently an MS bug, it's corrected in later versions.
34 * The DomainName field of FIXED_INFO isn't NULL-terminated on Win98.
37 #include <stdarg.h>
38 #include "winsock2.h"
39 #include "windef.h"
40 #include "winbase.h"
41 #include "iphlpapi.h"
42 #include "iprtrmib.h"
43 #include "wine/test.h"
44 #include <stdio.h>
45 #include <stdlib.h>
47 static HMODULE hLibrary = NULL;
49 typedef DWORD (WINAPI *GetNumberOfInterfacesFunc)(PDWORD);
50 typedef DWORD (WINAPI *GetIpAddrTableFunc)(PMIB_IPADDRTABLE,PULONG,BOOL);
51 typedef DWORD (WINAPI *GetIfEntryFunc)(PMIB_IFROW);
52 typedef DWORD (WINAPI *GetFriendlyIfIndexFunc)(DWORD);
53 typedef DWORD (WINAPI *GetIfTableFunc)(PMIB_IFTABLE,PULONG,BOOL);
54 typedef DWORD (WINAPI *GetIpForwardTableFunc)(PMIB_IPFORWARDTABLE,PULONG,BOOL);
55 typedef DWORD (WINAPI *GetIpNetTableFunc)(PMIB_IPNETTABLE,PULONG,BOOL);
56 typedef DWORD (WINAPI *GetInterfaceInfoFunc)(PIP_INTERFACE_INFO,PULONG);
57 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO,PULONG);
58 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO,PULONG);
59 typedef DWORD (WINAPI *GetIcmpStatisticsFunc)(PMIB_ICMP);
60 typedef DWORD (WINAPI *GetIpStatisticsFunc)(PMIB_IPSTATS);
61 typedef DWORD (WINAPI *GetTcpStatisticsFunc)(PMIB_TCPSTATS);
62 typedef DWORD (WINAPI *GetUdpStatisticsFunc)(PMIB_UDPSTATS);
63 typedef DWORD (WINAPI *GetTcpTableFunc)(PMIB_TCPTABLE,PDWORD,BOOL);
64 typedef DWORD (WINAPI *GetUdpTableFunc)(PMIB_UDPTABLE,PDWORD,BOOL);
65 typedef DWORD (WINAPI *GetPerAdapterInfoFunc)(ULONG,PIP_PER_ADAPTER_INFO,PULONG);
66 typedef DWORD (WINAPI *GetAdaptersAddressesFunc)(ULONG,ULONG,PVOID,PIP_ADAPTER_ADDRESSES,PULONG);
67 typedef DWORD (WINAPI *NotifyAddrChangeFunc)(PHANDLE,LPOVERLAPPED);
68 typedef BOOL (WINAPI *CancelIPChangeNotifyFunc)(LPOVERLAPPED);
70 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces = NULL;
71 static GetIpAddrTableFunc gGetIpAddrTable = NULL;
72 static GetIfEntryFunc gGetIfEntry = NULL;
73 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex = NULL;
74 static GetIfTableFunc gGetIfTable = NULL;
75 static GetIpForwardTableFunc gGetIpForwardTable = NULL;
76 static GetIpNetTableFunc gGetIpNetTable = NULL;
77 static GetInterfaceInfoFunc gGetInterfaceInfo = NULL;
78 static GetAdaptersInfoFunc gGetAdaptersInfo = NULL;
79 static GetNetworkParamsFunc gGetNetworkParams = NULL;
80 static GetIcmpStatisticsFunc gGetIcmpStatistics = NULL;
81 static GetIpStatisticsFunc gGetIpStatistics = NULL;
82 static GetTcpStatisticsFunc gGetTcpStatistics = NULL;
83 static GetUdpStatisticsFunc gGetUdpStatistics = NULL;
84 static GetTcpTableFunc gGetTcpTable = NULL;
85 static GetUdpTableFunc gGetUdpTable = NULL;
86 static GetPerAdapterInfoFunc gGetPerAdapterInfo = NULL;
87 static GetAdaptersAddressesFunc gGetAdaptersAddresses = NULL;
88 static NotifyAddrChangeFunc gNotifyAddrChange = NULL;
89 static CancelIPChangeNotifyFunc gCancelIPChangeNotify = NULL;
91 static void loadIPHlpApi(void)
93 hLibrary = LoadLibraryA("iphlpapi.dll");
94 if (hLibrary) {
95 gGetNumberOfInterfaces = (GetNumberOfInterfacesFunc)GetProcAddress(
96 hLibrary, "GetNumberOfInterfaces");
97 gGetIpAddrTable = (GetIpAddrTableFunc)GetProcAddress(
98 hLibrary, "GetIpAddrTable");
99 gGetIfEntry = (GetIfEntryFunc)GetProcAddress(
100 hLibrary, "GetIfEntry");
101 gGetFriendlyIfIndex = (GetFriendlyIfIndexFunc)GetProcAddress(
102 hLibrary, "GetFriendlyIfIndex");
103 gGetIfTable = (GetIfTableFunc)GetProcAddress(
104 hLibrary, "GetIfTable");
105 gGetIpForwardTable = (GetIpForwardTableFunc)GetProcAddress(
106 hLibrary, "GetIpForwardTable");
107 gGetIpNetTable = (GetIpNetTableFunc)GetProcAddress(
108 hLibrary, "GetIpNetTable");
109 gGetInterfaceInfo = (GetInterfaceInfoFunc)GetProcAddress(
110 hLibrary, "GetInterfaceInfo");
111 gGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(
112 hLibrary, "GetAdaptersInfo");
113 gGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(
114 hLibrary, "GetNetworkParams");
115 gGetIcmpStatistics = (GetIcmpStatisticsFunc)GetProcAddress(
116 hLibrary, "GetIcmpStatistics");
117 gGetIpStatistics = (GetIpStatisticsFunc)GetProcAddress(
118 hLibrary, "GetIpStatistics");
119 gGetTcpStatistics = (GetTcpStatisticsFunc)GetProcAddress(
120 hLibrary, "GetTcpStatistics");
121 gGetUdpStatistics = (GetUdpStatisticsFunc)GetProcAddress(
122 hLibrary, "GetUdpStatistics");
123 gGetTcpTable = (GetTcpTableFunc)GetProcAddress(
124 hLibrary, "GetTcpTable");
125 gGetUdpTable = (GetUdpTableFunc)GetProcAddress(
126 hLibrary, "GetUdpTable");
127 gGetPerAdapterInfo = (GetPerAdapterInfoFunc)GetProcAddress(hLibrary, "GetPerAdapterInfo");
128 gGetAdaptersAddresses = (GetAdaptersAddressesFunc)GetProcAddress(hLibrary, "GetAdaptersAddresses");
129 gNotifyAddrChange = (NotifyAddrChangeFunc)GetProcAddress(
130 hLibrary, "NotifyAddrChange");
131 gCancelIPChangeNotify = (CancelIPChangeNotifyFunc)GetProcAddress(
132 hLibrary, "CancelIPChangeNotify");
136 static void freeIPHlpApi(void)
138 if (hLibrary) {
139 gGetNumberOfInterfaces = NULL;
140 gGetIpAddrTable = NULL;
141 gGetIfEntry = NULL;
142 gGetFriendlyIfIndex = NULL;
143 gGetIfTable = NULL;
144 gGetIpForwardTable = NULL;
145 gGetIpNetTable = NULL;
146 gGetInterfaceInfo = NULL;
147 gGetAdaptersInfo = NULL;
148 gGetNetworkParams = NULL;
149 gGetIcmpStatistics = NULL;
150 gGetIpStatistics = NULL;
151 gGetTcpStatistics = NULL;
152 gGetUdpStatistics = NULL;
153 gGetTcpTable = NULL;
154 gGetUdpTable = NULL;
155 gNotifyAddrChange = NULL;
156 gCancelIPChangeNotify = NULL;
157 FreeLibrary(hLibrary);
158 hLibrary = NULL;
162 /* replacement for inet_ntoa */
163 static const char *ntoa( DWORD ip )
165 static char buffer[40];
167 ip = htonl(ip);
168 sprintf( buffer, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff );
169 return buffer;
173 still-to-be-tested 98-only functions:
174 GetUniDirectionalAdapterInfo
176 static void testWin98OnlyFunctions(void)
180 static void testGetNumberOfInterfaces(void)
182 if (gGetNumberOfInterfaces) {
183 DWORD apiReturn, numInterfaces;
185 /* Crashes on Vista */
186 if (0) {
187 apiReturn = gGetNumberOfInterfaces(NULL);
188 if (apiReturn == ERROR_NOT_SUPPORTED)
189 return;
190 ok(apiReturn == ERROR_INVALID_PARAMETER,
191 "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
192 apiReturn);
195 apiReturn = gGetNumberOfInterfaces(&numInterfaces);
196 if (apiReturn == ERROR_NOT_SUPPORTED) {
197 skip("GetNumberOfInterfaces is not supported\n");
198 return;
200 ok(apiReturn == NO_ERROR,
201 "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn);
205 static void testGetIfEntry(DWORD index)
207 if (gGetIfEntry) {
208 DWORD apiReturn;
209 MIB_IFROW row;
211 memset(&row, 0, sizeof(row));
212 apiReturn = gGetIfEntry(NULL);
213 if (apiReturn == ERROR_NOT_SUPPORTED) {
214 skip("GetIfEntry is not supported\n");
215 return;
217 ok(apiReturn == ERROR_INVALID_PARAMETER,
218 "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
219 apiReturn);
220 row.dwIndex = -1; /* hope that's always bogus! */
221 apiReturn = gGetIfEntry(&row);
222 ok(apiReturn == ERROR_INVALID_DATA ||
223 apiReturn == ERROR_FILE_NOT_FOUND /* Vista */,
224 "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
225 apiReturn);
226 row.dwIndex = index;
227 apiReturn = gGetIfEntry(&row);
228 ok(apiReturn == NO_ERROR,
229 "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn);
233 static void testGetIpAddrTable(void)
235 if (gGetIpAddrTable) {
236 DWORD apiReturn;
237 ULONG dwSize = 0;
239 apiReturn = gGetIpAddrTable(NULL, NULL, FALSE);
240 if (apiReturn == ERROR_NOT_SUPPORTED) {
241 skip("GetIpAddrTable is not supported\n");
242 return;
244 ok(apiReturn == ERROR_INVALID_PARAMETER,
245 "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
246 apiReturn);
247 apiReturn = gGetIpAddrTable(NULL, &dwSize, FALSE);
248 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
249 "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
250 apiReturn);
251 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
252 PMIB_IPADDRTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
254 apiReturn = gGetIpAddrTable(buf, &dwSize, FALSE);
255 ok(apiReturn == NO_ERROR,
256 "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
257 apiReturn);
258 if (apiReturn == NO_ERROR && buf->dwNumEntries)
259 testGetIfEntry(buf->table[0].dwIndex);
260 HeapFree(GetProcessHeap(), 0, buf);
265 static void testGetIfTable(void)
267 if (gGetIfTable) {
268 DWORD apiReturn;
269 ULONG dwSize = 0;
271 apiReturn = gGetIfTable(NULL, NULL, FALSE);
272 if (apiReturn == ERROR_NOT_SUPPORTED) {
273 skip("GetIfTable is not supported\n");
274 return;
276 ok(apiReturn == ERROR_INVALID_PARAMETER,
277 "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
278 apiReturn);
279 apiReturn = gGetIfTable(NULL, &dwSize, FALSE);
280 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
281 "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
282 apiReturn);
283 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
284 PMIB_IFTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
286 apiReturn = gGetIfTable(buf, &dwSize, FALSE);
287 ok(apiReturn == NO_ERROR,
288 "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
289 apiReturn);
291 if (apiReturn == NO_ERROR && winetest_debug > 1)
293 DWORD i, j;
294 char name[MAX_INTERFACE_NAME_LEN];
296 trace( "interface table: %u entries\n", buf->dwNumEntries );
297 for (i = 0; i < buf->dwNumEntries; i++)
299 MIB_IFROW *row = &buf->table[i];
300 WideCharToMultiByte( CP_ACP, 0, row->wszName, -1, name, MAX_INTERFACE_NAME_LEN, NULL, NULL );
301 trace( "%u: '%s' type %u mtu %u speed %u phys",
302 row->dwIndex, name, row->dwType, row->dwMtu, row->dwSpeed );
303 for (j = 0; j < row->dwPhysAddrLen; j++)
304 printf( " %02x", row->bPhysAddr[j] );
305 printf( "\n" );
306 trace( " in: bytes %u upkts %u nupkts %u disc %u err %u unk %u\n",
307 row->dwInOctets, row->dwInUcastPkts, row->dwInNUcastPkts,
308 row->dwInDiscards, row->dwInErrors, row->dwInUnknownProtos );
309 trace( " out: bytes %u upkts %u nupkts %u disc %u err %u\n",
310 row->dwOutOctets, row->dwOutUcastPkts, row->dwOutNUcastPkts,
311 row->dwOutDiscards, row->dwOutErrors );
314 HeapFree(GetProcessHeap(), 0, buf);
319 static void testGetIpForwardTable(void)
321 if (gGetIpForwardTable) {
322 DWORD apiReturn;
323 ULONG dwSize = 0;
325 apiReturn = gGetIpForwardTable(NULL, NULL, FALSE);
326 if (apiReturn == ERROR_NOT_SUPPORTED) {
327 skip("GetIpForwardTable is not supported\n");
328 return;
330 ok(apiReturn == ERROR_INVALID_PARAMETER,
331 "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
332 apiReturn);
333 apiReturn = gGetIpForwardTable(NULL, &dwSize, FALSE);
334 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
335 "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
336 apiReturn);
337 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
338 PMIB_IPFORWARDTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
340 apiReturn = gGetIpForwardTable(buf, &dwSize, FALSE);
341 ok(apiReturn == NO_ERROR,
342 "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
343 apiReturn);
345 if (apiReturn == NO_ERROR && winetest_debug > 1)
347 DWORD i;
349 trace( "IP forward table: %u entries\n", buf->dwNumEntries );
350 for (i = 0; i < buf->dwNumEntries; i++)
352 char buffer[40];
353 sprintf( buffer, "dest %s", ntoa( buf->table[i].dwForwardDest ));
354 sprintf( buffer + strlen(buffer), " mask %s", ntoa( buf->table[i].dwForwardMask ));
355 trace( "%u: %s gw %s if %u type %u\n", i, buffer,
356 ntoa( buf->table[i].dwForwardNextHop ),
357 buf->table[i].dwForwardIfIndex, U1(buf->table[i]).dwForwardType );
360 HeapFree(GetProcessHeap(), 0, buf);
365 static void testGetIpNetTable(void)
367 if (gGetIpNetTable) {
368 DWORD apiReturn;
369 ULONG dwSize = 0;
371 apiReturn = gGetIpNetTable(NULL, NULL, FALSE);
372 if (apiReturn == ERROR_NOT_SUPPORTED) {
373 skip("GetIpNetTable is not supported\n");
374 return;
376 ok(apiReturn == ERROR_INVALID_PARAMETER,
377 "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
378 apiReturn);
379 apiReturn = gGetIpNetTable(NULL, &dwSize, FALSE);
380 ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_INSUFFICIENT_BUFFER,
381 "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
382 apiReturn);
383 if (apiReturn == ERROR_NO_DATA)
384 ; /* empty ARP table's okay */
385 else if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
386 PMIB_IPNETTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
388 apiReturn = gGetIpNetTable(buf, &dwSize, FALSE);
389 ok(apiReturn == NO_ERROR ||
390 apiReturn == ERROR_NO_DATA, /* empty ARP table's okay */
391 "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
392 apiReturn);
394 if (apiReturn == NO_ERROR && winetest_debug > 1)
396 DWORD i, j;
398 trace( "IP net table: %u entries\n", buf->dwNumEntries );
399 for (i = 0; i < buf->dwNumEntries; i++)
401 trace( "%u: idx %u type %u addr %s phys",
402 i, buf->table[i].dwIndex, U(buf->table[i]).dwType, ntoa( buf->table[i].dwAddr ));
403 for (j = 0; j < buf->table[i].dwPhysAddrLen; j++)
404 printf( " %02x", buf->table[i].bPhysAddr[j] );
405 printf( "\n" );
408 HeapFree(GetProcessHeap(), 0, buf);
413 static void testGetIcmpStatistics(void)
415 if (gGetIcmpStatistics) {
416 DWORD apiReturn;
417 MIB_ICMP stats;
419 /* Crashes on Vista */
420 if (0) {
421 apiReturn = gGetIcmpStatistics(NULL);
422 if (apiReturn == ERROR_NOT_SUPPORTED)
423 return;
424 ok(apiReturn == ERROR_INVALID_PARAMETER,
425 "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
426 apiReturn);
429 apiReturn = gGetIcmpStatistics(&stats);
430 if (apiReturn == ERROR_NOT_SUPPORTED)
432 skip("GetIcmpStatistics is not supported\n");
433 return;
435 ok(apiReturn == NO_ERROR,
436 "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn);
437 if (apiReturn == NO_ERROR && winetest_debug > 1)
439 trace( "ICMP stats: %8s %8s\n", "in", "out" );
440 trace( " dwMsgs: %8u %8u\n", stats.stats.icmpInStats.dwMsgs, stats.stats.icmpOutStats.dwMsgs );
441 trace( " dwErrors: %8u %8u\n", stats.stats.icmpInStats.dwErrors, stats.stats.icmpOutStats.dwErrors );
442 trace( " dwDestUnreachs: %8u %8u\n", stats.stats.icmpInStats.dwDestUnreachs, stats.stats.icmpOutStats.dwDestUnreachs );
443 trace( " dwTimeExcds: %8u %8u\n", stats.stats.icmpInStats.dwTimeExcds, stats.stats.icmpOutStats.dwTimeExcds );
444 trace( " dwParmProbs: %8u %8u\n", stats.stats.icmpInStats.dwParmProbs, stats.stats.icmpOutStats.dwParmProbs );
445 trace( " dwSrcQuenchs: %8u %8u\n", stats.stats.icmpInStats.dwSrcQuenchs, stats.stats.icmpOutStats.dwSrcQuenchs );
446 trace( " dwRedirects: %8u %8u\n", stats.stats.icmpInStats.dwRedirects, stats.stats.icmpOutStats.dwRedirects );
447 trace( " dwEchos: %8u %8u\n", stats.stats.icmpInStats.dwEchos, stats.stats.icmpOutStats.dwEchos );
448 trace( " dwEchoReps: %8u %8u\n", stats.stats.icmpInStats.dwEchoReps, stats.stats.icmpOutStats.dwEchoReps );
449 trace( " dwTimestamps: %8u %8u\n", stats.stats.icmpInStats.dwTimestamps, stats.stats.icmpOutStats.dwTimestamps );
450 trace( " dwTimestampReps: %8u %8u\n", stats.stats.icmpInStats.dwTimestampReps, stats.stats.icmpOutStats.dwTimestampReps );
451 trace( " dwAddrMasks: %8u %8u\n", stats.stats.icmpInStats.dwAddrMasks, stats.stats.icmpOutStats.dwAddrMasks );
452 trace( " dwAddrMaskReps: %8u %8u\n", stats.stats.icmpInStats.dwAddrMaskReps, stats.stats.icmpOutStats.dwAddrMaskReps );
457 static void testGetIpStatistics(void)
459 if (gGetIpStatistics) {
460 DWORD apiReturn;
461 MIB_IPSTATS stats;
463 apiReturn = gGetIpStatistics(NULL);
464 if (apiReturn == ERROR_NOT_SUPPORTED) {
465 skip("GetIpStatistics is not supported\n");
466 return;
468 ok(apiReturn == ERROR_INVALID_PARAMETER,
469 "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
470 apiReturn);
471 apiReturn = gGetIpStatistics(&stats);
472 ok(apiReturn == NO_ERROR,
473 "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn);
474 if (apiReturn == NO_ERROR && winetest_debug > 1)
476 trace( "IP stats:\n" );
477 trace( " dwForwarding: %u\n", U(stats).dwForwarding );
478 trace( " dwDefaultTTL: %u\n", stats.dwDefaultTTL );
479 trace( " dwInReceives: %u\n", stats.dwInReceives );
480 trace( " dwInHdrErrors: %u\n", stats.dwInHdrErrors );
481 trace( " dwInAddrErrors: %u\n", stats.dwInAddrErrors );
482 trace( " dwForwDatagrams: %u\n", stats.dwForwDatagrams );
483 trace( " dwInUnknownProtos: %u\n", stats.dwInUnknownProtos );
484 trace( " dwInDiscards: %u\n", stats.dwInDiscards );
485 trace( " dwInDelivers: %u\n", stats.dwInDelivers );
486 trace( " dwOutRequests: %u\n", stats.dwOutRequests );
487 trace( " dwRoutingDiscards: %u\n", stats.dwRoutingDiscards );
488 trace( " dwOutDiscards: %u\n", stats.dwOutDiscards );
489 trace( " dwOutNoRoutes: %u\n", stats.dwOutNoRoutes );
490 trace( " dwReasmTimeout: %u\n", stats.dwReasmTimeout );
491 trace( " dwReasmReqds: %u\n", stats.dwReasmReqds );
492 trace( " dwReasmOks: %u\n", stats.dwReasmOks );
493 trace( " dwReasmFails: %u\n", stats.dwReasmFails );
494 trace( " dwFragOks: %u\n", stats.dwFragOks );
495 trace( " dwFragFails: %u\n", stats.dwFragFails );
496 trace( " dwFragCreates: %u\n", stats.dwFragCreates );
497 trace( " dwNumIf: %u\n", stats.dwNumIf );
498 trace( " dwNumAddr: %u\n", stats.dwNumAddr );
499 trace( " dwNumRoutes: %u\n", stats.dwNumRoutes );
504 static void testGetTcpStatistics(void)
506 if (gGetTcpStatistics) {
507 DWORD apiReturn;
508 MIB_TCPSTATS stats;
510 apiReturn = gGetTcpStatistics(NULL);
511 if (apiReturn == ERROR_NOT_SUPPORTED) {
512 skip("GetTcpStatistics is not supported\n");
513 return;
515 ok(apiReturn == ERROR_INVALID_PARAMETER,
516 "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
517 apiReturn);
518 apiReturn = gGetTcpStatistics(&stats);
519 ok(apiReturn == NO_ERROR,
520 "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn);
521 if (apiReturn == NO_ERROR && winetest_debug > 1)
523 trace( "TCP stats:\n" );
524 trace( " dwRtoAlgorithm: %u\n", U(stats).dwRtoAlgorithm );
525 trace( " dwRtoMin: %u\n", stats.dwRtoMin );
526 trace( " dwRtoMax: %u\n", stats.dwRtoMax );
527 trace( " dwMaxConn: %u\n", stats.dwMaxConn );
528 trace( " dwActiveOpens: %u\n", stats.dwActiveOpens );
529 trace( " dwPassiveOpens: %u\n", stats.dwPassiveOpens );
530 trace( " dwAttemptFails: %u\n", stats.dwAttemptFails );
531 trace( " dwEstabResets: %u\n", stats.dwEstabResets );
532 trace( " dwCurrEstab: %u\n", stats.dwCurrEstab );
533 trace( " dwInSegs: %u\n", stats.dwInSegs );
534 trace( " dwOutSegs: %u\n", stats.dwOutSegs );
535 trace( " dwRetransSegs: %u\n", stats.dwRetransSegs );
536 trace( " dwInErrs: %u\n", stats.dwInErrs );
537 trace( " dwOutRsts: %u\n", stats.dwOutRsts );
538 trace( " dwNumConns: %u\n", stats.dwNumConns );
543 static void testGetUdpStatistics(void)
545 if (gGetUdpStatistics) {
546 DWORD apiReturn;
547 MIB_UDPSTATS stats;
549 apiReturn = gGetUdpStatistics(NULL);
550 if (apiReturn == ERROR_NOT_SUPPORTED) {
551 skip("GetUdpStatistics is not supported\n");
552 return;
554 ok(apiReturn == ERROR_INVALID_PARAMETER,
555 "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
556 apiReturn);
557 apiReturn = gGetUdpStatistics(&stats);
558 ok(apiReturn == NO_ERROR,
559 "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn);
560 if (apiReturn == NO_ERROR && winetest_debug > 1)
562 trace( "UDP stats:\n" );
563 trace( " dwInDatagrams: %u\n", stats.dwInDatagrams );
564 trace( " dwNoPorts: %u\n", stats.dwNoPorts );
565 trace( " dwInErrors: %u\n", stats.dwInErrors );
566 trace( " dwOutDatagrams: %u\n", stats.dwOutDatagrams );
567 trace( " dwNumAddrs: %u\n", stats.dwNumAddrs );
572 static void testGetTcpTable(void)
574 if (gGetTcpTable) {
575 DWORD apiReturn;
576 ULONG dwSize = 0;
578 apiReturn = gGetTcpTable(NULL, &dwSize, FALSE);
579 if (apiReturn == ERROR_NOT_SUPPORTED) {
580 skip("GetTcpTable is not supported\n");
581 return;
583 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER ||
584 broken(apiReturn == ERROR_NO_DATA), /* win95 */
585 "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
586 apiReturn);
587 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
588 PMIB_TCPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
590 apiReturn = gGetTcpTable(buf, &dwSize, FALSE);
591 ok(apiReturn == NO_ERROR,
592 "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
593 apiReturn);
595 if (apiReturn == NO_ERROR && winetest_debug > 1)
597 DWORD i;
598 trace( "TCP table: %u entries\n", buf->dwNumEntries );
599 for (i = 0; i < buf->dwNumEntries; i++)
601 char buffer[40];
602 sprintf( buffer, "local %s:%u",
603 ntoa(buf->table[i].dwLocalAddr), ntohs(buf->table[i].dwLocalPort) );
604 trace( "%u: %s remote %s:%u state %u\n",
605 i, buffer, ntoa( buf->table[i].dwRemoteAddr ),
606 ntohs(buf->table[i].dwRemotePort), U(buf->table[i]).dwState );
609 HeapFree(GetProcessHeap(), 0, buf);
614 static void testGetUdpTable(void)
616 if (gGetUdpTable) {
617 DWORD apiReturn;
618 ULONG dwSize = 0;
620 apiReturn = gGetUdpTable(NULL, &dwSize, FALSE);
621 if (apiReturn == ERROR_NOT_SUPPORTED) {
622 skip("GetUdpTable is not supported\n");
623 return;
625 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
626 "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
627 apiReturn);
628 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
629 PMIB_UDPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
631 apiReturn = gGetUdpTable(buf, &dwSize, FALSE);
632 ok(apiReturn == NO_ERROR,
633 "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
634 apiReturn);
636 if (apiReturn == NO_ERROR && winetest_debug > 1)
638 DWORD i;
639 trace( "UDP table: %u entries\n", buf->dwNumEntries );
640 for (i = 0; i < buf->dwNumEntries; i++)
641 trace( "%u: %s:%u\n",
642 i, ntoa( buf->table[i].dwLocalAddr ), ntohs(buf->table[i].dwLocalPort) );
644 HeapFree(GetProcessHeap(), 0, buf);
650 still-to-be-tested NT4-onward functions:
651 CreateIpForwardEntry
652 DeleteIpForwardEntry
653 CreateIpNetEntry
654 DeleteIpNetEntry
655 GetFriendlyIfIndex
656 GetRTTAndHopCount
657 SetIfEntry
658 SetIpForwardEntry
659 SetIpNetEntry
660 SetIpStatistics
661 SetIpTTL
662 SetTcpEntry
664 static void testWinNT4Functions(void)
666 testGetNumberOfInterfaces();
667 testGetIpAddrTable();
668 testGetIfTable();
669 testGetIpForwardTable();
670 testGetIpNetTable();
671 testGetIcmpStatistics();
672 testGetIpStatistics();
673 testGetTcpStatistics();
674 testGetUdpStatistics();
675 testGetTcpTable();
676 testGetUdpTable();
679 static void testGetInterfaceInfo(void)
681 if (gGetInterfaceInfo) {
682 DWORD apiReturn;
683 ULONG len = 0;
685 apiReturn = gGetInterfaceInfo(NULL, NULL);
686 if (apiReturn == ERROR_NOT_SUPPORTED) {
687 skip("GetInterfaceInfo is not supported\n");
688 return;
690 ok(apiReturn == ERROR_INVALID_PARAMETER,
691 "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
692 apiReturn);
693 apiReturn = gGetInterfaceInfo(NULL, &len);
694 ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
695 "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
696 apiReturn);
697 if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
698 PIP_INTERFACE_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
700 apiReturn = gGetInterfaceInfo(buf, &len);
701 ok(apiReturn == NO_ERROR,
702 "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
703 apiReturn);
704 HeapFree(GetProcessHeap(), 0, buf);
709 static void testGetAdaptersInfo(void)
711 if (gGetAdaptersInfo) {
712 DWORD apiReturn;
713 ULONG len = 0;
715 apiReturn = gGetAdaptersInfo(NULL, NULL);
716 if (apiReturn == ERROR_NOT_SUPPORTED) {
717 skip("GetAdaptersInfo is not supported\n");
718 return;
720 ok(apiReturn == ERROR_INVALID_PARAMETER,
721 "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
722 apiReturn);
723 apiReturn = gGetAdaptersInfo(NULL, &len);
724 ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_BUFFER_OVERFLOW,
725 "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
726 apiReturn);
727 if (apiReturn == ERROR_NO_DATA)
728 ; /* no adapter's, that's okay */
729 else if (apiReturn == ERROR_BUFFER_OVERFLOW) {
730 PIP_ADAPTER_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
732 apiReturn = gGetAdaptersInfo(buf, &len);
733 ok(apiReturn == NO_ERROR,
734 "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
735 apiReturn);
736 HeapFree(GetProcessHeap(), 0, buf);
741 static void testGetNetworkParams(void)
743 if (gGetNetworkParams) {
744 DWORD apiReturn;
745 ULONG len = 0;
747 apiReturn = gGetNetworkParams(NULL, NULL);
748 if (apiReturn == ERROR_NOT_SUPPORTED) {
749 skip("GetNetworkParams is not supported\n");
750 return;
752 ok(apiReturn == ERROR_INVALID_PARAMETER,
753 "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
754 apiReturn);
755 apiReturn = gGetNetworkParams(NULL, &len);
756 ok(apiReturn == ERROR_BUFFER_OVERFLOW,
757 "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
758 apiReturn);
759 if (apiReturn == ERROR_BUFFER_OVERFLOW) {
760 PFIXED_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
762 apiReturn = gGetNetworkParams(buf, &len);
763 ok(apiReturn == NO_ERROR,
764 "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
765 apiReturn);
766 HeapFree(GetProcessHeap(), 0, buf);
772 still-to-be-tested 98-onward functions:
773 GetBestInterface
774 GetBestRoute
775 IpReleaseAddress
776 IpRenewAddress
778 static DWORD CALLBACK testWin98Functions(void *p)
780 testGetInterfaceInfo();
781 testGetAdaptersInfo();
782 testGetNetworkParams();
783 return 0;
786 static void testGetPerAdapterInfo(void)
788 DWORD ret, needed;
789 void *buffer;
791 if (!gGetPerAdapterInfo) return;
792 ret = gGetPerAdapterInfo(1, NULL, NULL);
793 if (ret == ERROR_NOT_SUPPORTED) {
794 skip("GetPerAdapterInfo is not supported\n");
795 return;
797 ok( ret == ERROR_INVALID_PARAMETER, "got %u instead of ERROR_INVALID_PARAMETER\n", ret );
798 needed = 0xdeadbeef;
799 ret = gGetPerAdapterInfo(1, NULL, &needed);
800 if (ret == ERROR_NO_DATA) return; /* no such adapter */
801 ok( ret == ERROR_BUFFER_OVERFLOW, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret );
802 ok( needed != 0xdeadbeef, "needed not set\n" );
803 buffer = HeapAlloc( GetProcessHeap(), 0, needed );
804 ret = gGetPerAdapterInfo(1, buffer, &needed);
805 ok( ret == NO_ERROR, "got %u instead of NO_ERROR\n", ret );
806 HeapFree( GetProcessHeap(), 0, buffer );
809 static void testNotifyAddrChange(void)
811 DWORD ret, bytes;
812 OVERLAPPED overlapped;
813 HANDLE handle;
814 BOOL success;
816 if (!gNotifyAddrChange)
818 win_skip("NotifyAddrChange not present\n");
819 return;
821 if (!gCancelIPChangeNotify)
823 win_skip("CancelIPChangeNotify not present\n");
824 return;
827 handle = NULL;
828 ZeroMemory(&overlapped, sizeof(overlapped));
829 ret = gNotifyAddrChange(&handle, &overlapped);
830 if (ret == ERROR_NOT_SUPPORTED)
832 win_skip("NotifyAddrChange is not supported\n");
833 return;
835 ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret);
836 ret = GetLastError();
837 todo_wine ok(ret == ERROR_IO_PENDING, "GetLastError returned %d, expected ERROR_IO_PENDING\n", ret);
838 success = gCancelIPChangeNotify(&overlapped);
839 todo_wine ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
841 ZeroMemory(&overlapped, sizeof(overlapped));
842 success = gCancelIPChangeNotify(&overlapped);
843 ok(success == FALSE, "CancelIPChangeNotify returned TRUE, expected FALSE\n");
845 handle = NULL;
846 ZeroMemory(&overlapped, sizeof(overlapped));
847 overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
848 ret = gNotifyAddrChange(&handle, &overlapped);
849 ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %d, expected ERROR_IO_PENDING\n", ret);
850 todo_wine ok(handle != INVALID_HANDLE_VALUE, "NotifyAddrChange returned invalid file handle\n");
851 success = GetOverlappedResult(handle, &overlapped, &bytes, FALSE);
852 ok(success == FALSE, "GetOverlappedResult returned TRUE, expected FALSE\n");
853 ret = GetLastError();
854 ok(ret == ERROR_IO_INCOMPLETE, "GetLastError returned %d, expected ERROR_IO_INCOMPLETE\n", ret);
855 success = gCancelIPChangeNotify(&overlapped);
856 todo_wine ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n");
858 if (winetest_interactive)
860 handle = NULL;
861 ZeroMemory(&overlapped, sizeof(overlapped));
862 overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
863 trace("Testing asynchronous ipv4 address change notification. Please "
864 "change the ipv4 address of one of your network interfaces\n");
865 ret = gNotifyAddrChange(&handle, &overlapped);
866 ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret);
867 success = GetOverlappedResult(handle, &overlapped, &bytes, TRUE);
868 ok(success == TRUE, "GetOverlappedResult returned FALSE, expected TRUE\n");
871 /* test synchronous functionality */
872 if (winetest_interactive)
874 trace("Testing synchronous ipv4 address change notification. Please "
875 "change the ipv4 address of one of your network interfaces\n");
876 ret = gNotifyAddrChange(NULL, NULL);
877 todo_wine ok(ret == NO_ERROR, "NotifyAddrChange returned %d, expected NO_ERROR\n", ret);
882 still-to-be-tested 2K-onward functions:
883 AddIPAddress
884 CreateProxyArpEntry
885 DeleteIPAddress
886 DeleteProxyArpEntry
887 EnableRouter
888 FlushIpNetTable
889 GetAdapterIndex
890 NotifyRouteChange + CancelIPChangeNotify
891 SendARP
892 UnenableRouter
894 static void testWin2KFunctions(void)
896 testGetPerAdapterInfo();
897 testNotifyAddrChange();
900 static void test_GetAdaptersAddresses(void)
902 ULONG ret, size;
903 IP_ADAPTER_ADDRESSES *aa, *ptr;
904 IP_ADAPTER_UNICAST_ADDRESS *ua;
906 if (!gGetAdaptersAddresses)
908 win_skip("GetAdaptersAddresses not present\n");
909 return;
912 ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, NULL);
913 ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", ret);
915 /* size should be ignored and overwritten if buffer is NULL */
916 size = 0x7fffffff;
917 ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
918 ok(ret == ERROR_BUFFER_OVERFLOW, "expected ERROR_BUFFER_OVERFLOW, got %u\n", ret);
919 if (ret != ERROR_BUFFER_OVERFLOW) return;
921 ptr = HeapAlloc(GetProcessHeap(), 0, size);
922 ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, ptr, &size);
923 ok(!ret, "expected ERROR_SUCCESS got %u\n", ret);
925 for (aa = ptr; !ret && aa; aa = aa->Next)
927 ok(aa->DnsSuffix != NULL, "DnsSuffix is not a valid pointer\n");
928 ok(aa->Description != NULL, "Description is not a valid pointer\n");
929 ok(aa->FriendlyName != NULL, "FriendlyName is not a valid pointer\n");
931 if (winetest_debug <= 1)
932 continue;
934 trace("Length: %u\n", S(U(*aa)).Length);
935 trace("IfIndex: %u\n", S(U(*aa)).IfIndex);
936 trace("Next: %p\n", aa->Next);
937 trace("AdapterName: %s\n", aa->AdapterName);
938 trace("FirstUnicastAddress: %p\n", aa->FirstUnicastAddress);
939 ua = aa->FirstUnicastAddress;
940 while (ua)
942 trace("\tLength: %u\n", S(U(*ua)).Length);
943 trace("\tFlags: 0x%08x\n", S(U(*ua)).Flags);
944 trace("\tNext: %p\n", ua->Next);
945 trace("\tAddress.lpSockaddr: %p\n", ua->Address.lpSockaddr);
946 trace("\tAddress.iSockaddrLength: %d\n", ua->Address.iSockaddrLength);
947 trace("\tPrefixOrigin: %u\n", ua->PrefixOrigin);
948 trace("\tSuffixOrigin: %u\n", ua->SuffixOrigin);
949 trace("\tDadState: %u\n", ua->DadState);
950 trace("\tValidLifetime: 0x%08x\n", ua->ValidLifetime);
951 trace("\tPreferredLifetime: 0x%08x\n", ua->PreferredLifetime);
952 trace("\tLeaseLifetime: 0x%08x\n", ua->LeaseLifetime);
953 trace("\n");
954 ua = ua->Next;
956 trace("FirstAnycastAddress: %p\n", aa->FirstAnycastAddress);
957 trace("FirstMulticastAddress: %p\n", aa->FirstMulticastAddress);
958 trace("FirstDnsServerAddress: %p\n", aa->FirstDnsServerAddress);
959 trace("DnsSuffix: %p\n", aa->DnsSuffix);
960 trace("Description: %p\n", aa->Description);
961 trace("FriendlyName: %p\n", aa->FriendlyName);
962 trace("PhysicalAddress: %02x\n", aa->PhysicalAddress[0]);
963 trace("PhysicalAddressLength: %u\n", aa->PhysicalAddressLength);
964 trace("Flags: 0x%08x\n", aa->Flags);
965 trace("Mtu: %u\n", aa->Mtu);
966 trace("IfType: %u\n", aa->IfType);
967 trace("OperStatus: %u\n", aa->OperStatus);
968 trace("\n");
970 HeapFree(GetProcessHeap(), 0, ptr);
973 START_TEST(iphlpapi)
976 loadIPHlpApi();
977 if (hLibrary) {
978 HANDLE thread;
980 testWin98OnlyFunctions();
981 testWinNT4Functions();
983 /* run testGetXXXX in two threads at once to make sure we don't crash in that case */
984 thread = CreateThread(NULL, 0, testWin98Functions, NULL, 0, NULL);
985 testWin98Functions(NULL);
986 WaitForSingleObject(thread, INFINITE);
988 testWin2KFunctions();
989 test_GetAdaptersAddresses();
990 freeIPHlpApi();