usp10: Handle Ligature Substitution Subtable from GSUB.
[wine] / dlls / iphlpapi / tests / iphlpapi.c
1 /*
2  * iphlpapi dll test
3  *
4  * Copyright (C) 2003 Juan Lang
5  *
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.
10  *
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.
15  *
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
19  */
20
21 /*
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).
28  *
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.
33  *
34  * The DomainName field of FIXED_INFO isn't NULL-terminated on Win98.
35  */
36
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>
46
47 static HMODULE hLibrary = NULL;
48
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
68 static GetNumberOfInterfacesFunc gGetNumberOfInterfaces = NULL;
69 static GetIpAddrTableFunc gGetIpAddrTable = NULL;
70 static GetIfEntryFunc gGetIfEntry = NULL;
71 static GetFriendlyIfIndexFunc gGetFriendlyIfIndex = NULL;
72 static GetIfTableFunc gGetIfTable = NULL;
73 static GetIpForwardTableFunc gGetIpForwardTable = NULL;
74 static GetIpNetTableFunc gGetIpNetTable = NULL;
75 static GetInterfaceInfoFunc gGetInterfaceInfo = NULL;
76 static GetAdaptersInfoFunc gGetAdaptersInfo = NULL;
77 static GetNetworkParamsFunc gGetNetworkParams = NULL;
78 static GetIcmpStatisticsFunc gGetIcmpStatistics = NULL;
79 static GetIpStatisticsFunc gGetIpStatistics = NULL;
80 static GetTcpStatisticsFunc gGetTcpStatistics = NULL;
81 static GetUdpStatisticsFunc gGetUdpStatistics = NULL;
82 static GetTcpTableFunc gGetTcpTable = NULL;
83 static GetUdpTableFunc gGetUdpTable = NULL;
84 static GetPerAdapterInfoFunc gGetPerAdapterInfo = NULL;
85 static GetAdaptersAddressesFunc gGetAdaptersAddresses = NULL;
86
87 static void loadIPHlpApi(void)
88 {
89   hLibrary = LoadLibraryA("iphlpapi.dll");
90   if (hLibrary) {
91     gGetNumberOfInterfaces = (GetNumberOfInterfacesFunc)GetProcAddress(
92      hLibrary, "GetNumberOfInterfaces");
93     gGetIpAddrTable = (GetIpAddrTableFunc)GetProcAddress(
94      hLibrary, "GetIpAddrTable");
95     gGetIfEntry = (GetIfEntryFunc)GetProcAddress(
96      hLibrary, "GetIfEntry");
97     gGetFriendlyIfIndex = (GetFriendlyIfIndexFunc)GetProcAddress(
98      hLibrary, "GetFriendlyIfIndex");
99     gGetIfTable = (GetIfTableFunc)GetProcAddress(
100      hLibrary, "GetIfTable");
101     gGetIpForwardTable = (GetIpForwardTableFunc)GetProcAddress(
102      hLibrary, "GetIpForwardTable");
103     gGetIpNetTable = (GetIpNetTableFunc)GetProcAddress(
104      hLibrary, "GetIpNetTable");
105     gGetInterfaceInfo = (GetInterfaceInfoFunc)GetProcAddress(
106      hLibrary, "GetInterfaceInfo");
107     gGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(
108      hLibrary, "GetAdaptersInfo");
109     gGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(
110      hLibrary, "GetNetworkParams");
111     gGetIcmpStatistics = (GetIcmpStatisticsFunc)GetProcAddress(
112      hLibrary, "GetIcmpStatistics");
113     gGetIpStatistics = (GetIpStatisticsFunc)GetProcAddress(
114      hLibrary, "GetIpStatistics");
115     gGetTcpStatistics = (GetTcpStatisticsFunc)GetProcAddress(
116      hLibrary, "GetTcpStatistics");
117     gGetUdpStatistics = (GetUdpStatisticsFunc)GetProcAddress(
118      hLibrary, "GetUdpStatistics");
119     gGetTcpTable = (GetTcpTableFunc)GetProcAddress(
120      hLibrary, "GetTcpTable");
121     gGetUdpTable = (GetUdpTableFunc)GetProcAddress(
122      hLibrary, "GetUdpTable");
123     gGetPerAdapterInfo = (GetPerAdapterInfoFunc)GetProcAddress(hLibrary, "GetPerAdapterInfo");
124     gGetAdaptersAddresses = (GetAdaptersAddressesFunc)GetProcAddress(hLibrary, "GetAdaptersAddresses");
125   }
126 }
127
128 static void freeIPHlpApi(void)
129 {
130   if (hLibrary) {
131     gGetNumberOfInterfaces = NULL;
132     gGetIpAddrTable = NULL;
133     gGetIfEntry = NULL;
134     gGetFriendlyIfIndex = NULL;
135     gGetIfTable = NULL;
136     gGetIpForwardTable = NULL;
137     gGetIpNetTable = NULL;
138     gGetInterfaceInfo = NULL;
139     gGetAdaptersInfo = NULL;
140     gGetNetworkParams = NULL;
141     gGetIcmpStatistics = NULL;
142     gGetIpStatistics = NULL;
143     gGetTcpStatistics = NULL;
144     gGetUdpStatistics = NULL;
145     gGetTcpTable = NULL;
146     gGetUdpTable = NULL;
147     FreeLibrary(hLibrary);
148     hLibrary = NULL;
149   }
150 }
151
152 /* replacement for inet_ntoa */
153 static const char *ntoa( DWORD ip )
154 {
155     static char buffer[40];
156
157     ip = htonl(ip);
158     sprintf( buffer, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff );
159     return buffer;
160 }
161
162 /*
163 still-to-be-tested 98-only functions:
164 GetUniDirectionalAdapterInfo
165 */
166 static void testWin98OnlyFunctions(void)
167 {
168 }
169
170 static void testGetNumberOfInterfaces(void)
171 {
172   if (gGetNumberOfInterfaces) {
173     DWORD apiReturn, numInterfaces;
174
175     /* Crashes on Vista */
176     if (0) {
177       apiReturn = gGetNumberOfInterfaces(NULL), numInterfaces;
178       if (apiReturn == ERROR_NOT_SUPPORTED)
179         return;
180       ok(apiReturn == ERROR_INVALID_PARAMETER,
181        "GetNumberOfInterfaces(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
182        apiReturn);
183     }
184
185     apiReturn = gGetNumberOfInterfaces(&numInterfaces);
186     if (apiReturn == ERROR_NOT_SUPPORTED) {
187       skip("GetNumberOfInterfaces is not supported\n");
188       return;
189     }
190     ok(apiReturn == NO_ERROR,
191      "GetNumberOfInterfaces returned %d, expected 0\n", apiReturn);
192   }
193 }
194
195 static void testGetIfEntry(DWORD index)
196 {
197   if (gGetIfEntry) {
198     DWORD apiReturn;
199     MIB_IFROW row;
200
201     memset(&row, 0, sizeof(row));
202     apiReturn = gGetIfEntry(NULL);
203     if (apiReturn == ERROR_NOT_SUPPORTED) {
204       skip("GetIfEntry is not supported\n");
205       return;
206     }
207     ok(apiReturn == ERROR_INVALID_PARAMETER,
208      "GetIfEntry(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
209      apiReturn);
210     row.dwIndex = -1; /* hope that's always bogus! */
211     apiReturn = gGetIfEntry(&row);
212     ok(apiReturn == ERROR_INVALID_DATA ||
213      apiReturn == ERROR_FILE_NOT_FOUND /* Vista */,
214      "GetIfEntry(bogus row) returned %d, expected ERROR_INVALID_DATA or ERROR_FILE_NOT_FOUND\n",
215      apiReturn);
216     row.dwIndex = index;
217     apiReturn = gGetIfEntry(&row);
218     ok(apiReturn == NO_ERROR, 
219      "GetIfEntry returned %d, expected NO_ERROR\n", apiReturn);
220   }
221 }
222
223 static void testGetIpAddrTable(void)
224 {
225   if (gGetIpAddrTable) {
226     DWORD apiReturn;
227     ULONG dwSize = 0;
228
229     apiReturn = gGetIpAddrTable(NULL, NULL, FALSE);
230     if (apiReturn == ERROR_NOT_SUPPORTED) {
231       skip("GetIpAddrTable is not supported\n");
232       return;
233     }
234     ok(apiReturn == ERROR_INVALID_PARAMETER,
235      "GetIpAddrTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
236      apiReturn);
237     apiReturn = gGetIpAddrTable(NULL, &dwSize, FALSE);
238     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
239      "GetIpAddrTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
240      apiReturn);
241     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
242       PMIB_IPADDRTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
243
244       apiReturn = gGetIpAddrTable(buf, &dwSize, FALSE);
245       ok(apiReturn == NO_ERROR,
246        "GetIpAddrTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
247        apiReturn);
248       if (apiReturn == NO_ERROR && buf->dwNumEntries)
249         testGetIfEntry(buf->table[0].dwIndex);
250       HeapFree(GetProcessHeap(), 0, buf);
251     }
252   }
253 }
254
255 static void testGetIfTable(void)
256 {
257   if (gGetIfTable) {
258     DWORD apiReturn;
259     ULONG dwSize = 0;
260
261     apiReturn = gGetIfTable(NULL, NULL, FALSE);
262     if (apiReturn == ERROR_NOT_SUPPORTED) {
263       skip("GetIfTable is not supported\n");
264       return;
265     }
266     ok(apiReturn == ERROR_INVALID_PARAMETER,
267      "GetIfTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
268      apiReturn);
269     apiReturn = gGetIfTable(NULL, &dwSize, FALSE);
270     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
271      "GetIfTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
272      apiReturn);
273     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
274       PMIB_IFTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
275
276       apiReturn = gGetIfTable(buf, &dwSize, FALSE);
277       ok(apiReturn == NO_ERROR,
278        "GetIfTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n\n",
279        apiReturn);
280
281       if (apiReturn == NO_ERROR && winetest_debug > 1)
282       {
283           DWORD i, j;
284           char name[MAX_INTERFACE_NAME_LEN];
285
286           trace( "interface table: %u entries\n", buf->dwNumEntries );
287           for (i = 0; i < buf->dwNumEntries; i++)
288           {
289               MIB_IFROW *row = &buf->table[i];
290               WideCharToMultiByte( CP_ACP, 0, row->wszName, -1, name, MAX_INTERFACE_NAME_LEN, NULL, NULL );
291               trace( "%u: '%s' type %u mtu %u speed %u phys",
292                      row->dwIndex, name, row->dwType, row->dwMtu, row->dwSpeed );
293               for (j = 0; j < row->dwPhysAddrLen; j++)
294                   printf( " %02x", row->bPhysAddr[j] );
295               printf( "\n" );
296               trace( "        in: bytes %u upkts %u nupkts %u disc %u err %u unk %u\n",
297                      row->dwInOctets, row->dwInUcastPkts, row->dwInNUcastPkts,
298                      row->dwInDiscards, row->dwInErrors, row->dwInUnknownProtos );
299               trace( "        out: bytes %u upkts %u nupkts %u disc %u err %u\n",
300                      row->dwOutOctets, row->dwOutUcastPkts, row->dwOutNUcastPkts,
301                      row->dwOutDiscards, row->dwOutErrors );
302           }
303       }
304       HeapFree(GetProcessHeap(), 0, buf);
305     }
306   }
307 }
308
309 static void testGetIpForwardTable(void)
310 {
311   if (gGetIpForwardTable) {
312     DWORD apiReturn;
313     ULONG dwSize = 0;
314
315     apiReturn = gGetIpForwardTable(NULL, NULL, FALSE);
316     if (apiReturn == ERROR_NOT_SUPPORTED) {
317       skip("GetIpForwardTable is not supported\n");
318       return;
319     }
320     ok(apiReturn == ERROR_INVALID_PARAMETER,
321      "GetIpForwardTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
322      apiReturn);
323     apiReturn = gGetIpForwardTable(NULL, &dwSize, FALSE);
324     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
325      "GetIpForwardTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
326      apiReturn);
327     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
328       PMIB_IPFORWARDTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
329
330       apiReturn = gGetIpForwardTable(buf, &dwSize, FALSE);
331       ok(apiReturn == NO_ERROR,
332        "GetIpForwardTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
333        apiReturn);
334
335       if (apiReturn == NO_ERROR && winetest_debug > 1)
336       {
337           DWORD i;
338
339           trace( "IP forward table: %u entries\n", buf->dwNumEntries );
340           for (i = 0; i < buf->dwNumEntries; i++)
341           {
342               char buffer[40];
343               sprintf( buffer, "dest %s", ntoa( buf->table[i].dwForwardDest ));
344               sprintf( buffer + strlen(buffer), " mask %s", ntoa( buf->table[i].dwForwardMask ));
345               trace( "%u: %s gw %s if %u type %u\n", i, buffer,
346                      ntoa( buf->table[i].dwForwardNextHop ),
347                      buf->table[i].dwForwardIfIndex, buf->table[i].dwForwardType );
348           }
349       }
350       HeapFree(GetProcessHeap(), 0, buf);
351     }
352   }
353 }
354
355 static void testGetIpNetTable(void)
356 {
357   if (gGetIpNetTable) {
358     DWORD apiReturn;
359     ULONG dwSize = 0;
360
361     apiReturn = gGetIpNetTable(NULL, NULL, FALSE);
362     if (apiReturn == ERROR_NOT_SUPPORTED) {
363       skip("GetIpNetTable is not supported\n");
364       return;
365     }
366     ok(apiReturn == ERROR_INVALID_PARAMETER,
367      "GetIpNetTable(NULL, NULL, FALSE) returned %d, expected ERROR_INVALID_PARAMETER\n",
368      apiReturn);
369     apiReturn = gGetIpNetTable(NULL, &dwSize, FALSE);
370     ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_INSUFFICIENT_BUFFER,
371      "GetIpNetTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_NO_DATA or ERROR_INSUFFICIENT_BUFFER\n",
372      apiReturn);
373     if (apiReturn == ERROR_NO_DATA)
374       ; /* empty ARP table's okay */
375     else if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
376       PMIB_IPNETTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
377
378       apiReturn = gGetIpNetTable(buf, &dwSize, FALSE);
379       ok(apiReturn == NO_ERROR ||
380          apiReturn == ERROR_NO_DATA, /* empty ARP table's okay */
381        "GetIpNetTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
382        apiReturn);
383
384       if (apiReturn == NO_ERROR && winetest_debug > 1)
385       {
386           DWORD i, j;
387
388           trace( "IP net table: %u entries\n", buf->dwNumEntries );
389           for (i = 0; i < buf->dwNumEntries; i++)
390           {
391               trace( "%u: idx %u type %u addr %s phys",
392                      i, buf->table[i].dwIndex, buf->table[i].dwType, ntoa( buf->table[i].dwAddr ));
393               for (j = 0; j < buf->table[i].dwPhysAddrLen; j++)
394                   printf( " %02x", buf->table[i].bPhysAddr[j] );
395               printf( "\n" );
396           }
397       }
398       HeapFree(GetProcessHeap(), 0, buf);
399     }
400   }
401 }
402
403 static void testGetIcmpStatistics(void)
404 {
405   if (gGetIcmpStatistics) {
406     DWORD apiReturn;
407     MIB_ICMP stats;
408
409     /* Crashes on Vista */
410     if (0) {
411       apiReturn = gGetIcmpStatistics(NULL);
412       if (apiReturn == ERROR_NOT_SUPPORTED)
413         return;
414       ok(apiReturn == ERROR_INVALID_PARAMETER,
415        "GetIcmpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
416        apiReturn);
417     }
418
419     apiReturn = gGetIcmpStatistics(&stats);
420     if (apiReturn == ERROR_NOT_SUPPORTED)
421     {
422       skip("GetIcmpStatistics is not supported\n");
423       return;
424     }
425     ok(apiReturn == NO_ERROR,
426      "GetIcmpStatistics returned %d, expected NO_ERROR\n", apiReturn);
427     if (apiReturn == NO_ERROR && winetest_debug > 1)
428     {
429         trace( "ICMP stats:          %8s %8s\n", "in", "out" );
430         trace( "    dwMsgs:          %8u %8u\n", stats.stats.icmpInStats.dwMsgs, stats.stats.icmpOutStats.dwMsgs );
431         trace( "    dwErrors:        %8u %8u\n", stats.stats.icmpInStats.dwErrors, stats.stats.icmpOutStats.dwErrors );
432         trace( "    dwDestUnreachs:  %8u %8u\n", stats.stats.icmpInStats.dwDestUnreachs, stats.stats.icmpOutStats.dwDestUnreachs );
433         trace( "    dwTimeExcds:     %8u %8u\n", stats.stats.icmpInStats.dwTimeExcds, stats.stats.icmpOutStats.dwTimeExcds );
434         trace( "    dwParmProbs:     %8u %8u\n", stats.stats.icmpInStats.dwParmProbs, stats.stats.icmpOutStats.dwParmProbs );
435         trace( "    dwSrcQuenchs:    %8u %8u\n", stats.stats.icmpInStats.dwSrcQuenchs, stats.stats.icmpOutStats.dwSrcQuenchs );
436         trace( "    dwRedirects:     %8u %8u\n", stats.stats.icmpInStats.dwRedirects, stats.stats.icmpOutStats.dwRedirects );
437         trace( "    dwEchos:         %8u %8u\n", stats.stats.icmpInStats.dwEchos, stats.stats.icmpOutStats.dwEchos );
438         trace( "    dwEchoReps:      %8u %8u\n", stats.stats.icmpInStats.dwEchoReps, stats.stats.icmpOutStats.dwEchoReps );
439         trace( "    dwTimestamps:    %8u %8u\n", stats.stats.icmpInStats.dwTimestamps, stats.stats.icmpOutStats.dwTimestamps );
440         trace( "    dwTimestampReps: %8u %8u\n", stats.stats.icmpInStats.dwTimestampReps, stats.stats.icmpOutStats.dwTimestampReps );
441         trace( "    dwAddrMasks:     %8u %8u\n", stats.stats.icmpInStats.dwAddrMasks, stats.stats.icmpOutStats.dwAddrMasks );
442         trace( "    dwAddrMaskReps:  %8u %8u\n", stats.stats.icmpInStats.dwAddrMaskReps, stats.stats.icmpOutStats.dwAddrMaskReps );
443     }
444   }
445 }
446
447 static void testGetIpStatistics(void)
448 {
449   if (gGetIpStatistics) {
450     DWORD apiReturn;
451     MIB_IPSTATS stats;
452
453     apiReturn = gGetIpStatistics(NULL);
454     if (apiReturn == ERROR_NOT_SUPPORTED) {
455       skip("GetIpStatistics is not supported\n");
456       return;
457     }
458     ok(apiReturn == ERROR_INVALID_PARAMETER,
459      "GetIpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
460      apiReturn);
461     apiReturn = gGetIpStatistics(&stats);
462     ok(apiReturn == NO_ERROR,
463       "GetIpStatistics returned %d, expected NO_ERROR\n", apiReturn);
464     if (apiReturn == NO_ERROR && winetest_debug > 1)
465     {
466         trace( "IP stats:\n" );
467         trace( "    dwForwarding:      %u\n", stats.dwForwarding );
468         trace( "    dwDefaultTTL:      %u\n", stats.dwDefaultTTL );
469         trace( "    dwInReceives:      %u\n", stats.dwInReceives );
470         trace( "    dwInHdrErrors:     %u\n", stats.dwInHdrErrors );
471         trace( "    dwInAddrErrors:    %u\n", stats.dwInAddrErrors );
472         trace( "    dwForwDatagrams:   %u\n", stats.dwForwDatagrams );
473         trace( "    dwInUnknownProtos: %u\n", stats.dwInUnknownProtos );
474         trace( "    dwInDiscards:      %u\n", stats.dwInDiscards );
475         trace( "    dwInDelivers:      %u\n", stats.dwInDelivers );
476         trace( "    dwOutRequests:     %u\n", stats.dwOutRequests );
477         trace( "    dwRoutingDiscards: %u\n", stats.dwRoutingDiscards );
478         trace( "    dwOutDiscards:     %u\n", stats.dwOutDiscards );
479         trace( "    dwOutNoRoutes:     %u\n", stats.dwOutNoRoutes );
480         trace( "    dwReasmTimeout:    %u\n", stats.dwReasmTimeout );
481         trace( "    dwReasmReqds:      %u\n", stats.dwReasmReqds );
482         trace( "    dwReasmOks:        %u\n", stats.dwReasmOks );
483         trace( "    dwReasmFails:      %u\n", stats.dwReasmFails );
484         trace( "    dwFragOks:         %u\n", stats.dwFragOks );
485         trace( "    dwFragFails:       %u\n", stats.dwFragFails );
486         trace( "    dwFragCreates:     %u\n", stats.dwFragCreates );
487         trace( "    dwNumIf:           %u\n", stats.dwNumIf );
488         trace( "    dwNumAddr:         %u\n", stats.dwNumAddr );
489         trace( "    dwNumRoutes:       %u\n", stats.dwNumRoutes );
490     }
491   }
492 }
493
494 static void testGetTcpStatistics(void)
495 {
496   if (gGetTcpStatistics) {
497     DWORD apiReturn;
498     MIB_TCPSTATS stats;
499
500     apiReturn = gGetTcpStatistics(NULL);
501     if (apiReturn == ERROR_NOT_SUPPORTED) {
502       skip("GetTcpStatistics is not supported\n");
503       return;
504     }
505     ok(apiReturn == ERROR_INVALID_PARAMETER,
506      "GetTcpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
507      apiReturn);
508     apiReturn = gGetTcpStatistics(&stats);
509     ok(apiReturn == NO_ERROR,
510       "GetTcpStatistics returned %d, expected NO_ERROR\n", apiReturn);
511     if (apiReturn == NO_ERROR && winetest_debug > 1)
512     {
513         trace( "TCP stats:\n" );
514         trace( "    dwRtoAlgorithm: %u\n", stats.dwRtoAlgorithm );
515         trace( "    dwRtoMin:       %u\n", stats.dwRtoMin );
516         trace( "    dwRtoMax:       %u\n", stats.dwRtoMax );
517         trace( "    dwMaxConn:      %u\n", stats.dwMaxConn );
518         trace( "    dwActiveOpens:  %u\n", stats.dwActiveOpens );
519         trace( "    dwPassiveOpens: %u\n", stats.dwPassiveOpens );
520         trace( "    dwAttemptFails: %u\n", stats.dwAttemptFails );
521         trace( "    dwEstabResets:  %u\n", stats.dwEstabResets );
522         trace( "    dwCurrEstab:    %u\n", stats.dwCurrEstab );
523         trace( "    dwInSegs:       %u\n", stats.dwInSegs );
524         trace( "    dwOutSegs:      %u\n", stats.dwOutSegs );
525         trace( "    dwRetransSegs:  %u\n", stats.dwRetransSegs );
526         trace( "    dwInErrs:       %u\n", stats.dwInErrs );
527         trace( "    dwOutRsts:      %u\n", stats.dwOutRsts );
528         trace( "    dwNumConns:     %u\n", stats.dwNumConns );
529     }
530   }
531 }
532
533 static void testGetUdpStatistics(void)
534 {
535   if (gGetUdpStatistics) {
536     DWORD apiReturn;
537     MIB_UDPSTATS stats;
538
539     apiReturn = gGetUdpStatistics(NULL);
540     if (apiReturn == ERROR_NOT_SUPPORTED) {
541       skip("GetUdpStatistics is not supported\n");
542       return;
543     }
544     ok(apiReturn == ERROR_INVALID_PARAMETER,
545      "GetUdpStatistics(NULL) returned %d, expected ERROR_INVALID_PARAMETER\n",
546      apiReturn);
547     apiReturn = gGetUdpStatistics(&stats);
548     ok(apiReturn == NO_ERROR,
549      "GetUdpStatistics returned %d, expected NO_ERROR\n", apiReturn);
550     if (apiReturn == NO_ERROR && winetest_debug > 1)
551     {
552         trace( "UDP stats:\n" );
553         trace( "    dwInDatagrams:  %u\n", stats.dwInDatagrams );
554         trace( "    dwNoPorts:      %u\n", stats.dwNoPorts );
555         trace( "    dwInErrors:     %u\n", stats.dwInErrors );
556         trace( "    dwOutDatagrams: %u\n", stats.dwOutDatagrams );
557         trace( "    dwNumAddrs:     %u\n", stats.dwNumAddrs );
558     }
559   }
560 }
561
562 static void testGetTcpTable(void)
563 {
564   if (gGetTcpTable) {
565     DWORD apiReturn;
566     ULONG dwSize = 0;
567
568     apiReturn = gGetTcpTable(NULL, &dwSize, FALSE);
569     if (apiReturn == ERROR_NOT_SUPPORTED) {
570       skip("GetTcpTable is not supported\n");
571       return;
572     }
573     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER ||
574        broken(apiReturn == ERROR_NO_DATA), /* win95 */
575      "GetTcpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
576      apiReturn);
577     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
578       PMIB_TCPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
579
580       apiReturn = gGetTcpTable(buf, &dwSize, FALSE);
581       ok(apiReturn == NO_ERROR,
582        "GetTcpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
583        apiReturn);
584
585       if (apiReturn == NO_ERROR && winetest_debug > 1)
586       {
587           DWORD i;
588           trace( "TCP table: %u entries\n", buf->dwNumEntries );
589           for (i = 0; i < buf->dwNumEntries; i++)
590           {
591               char buffer[40];
592               sprintf( buffer, "local %s:%u",
593                        ntoa(buf->table[i].dwLocalAddr), ntohs(buf->table[i].dwLocalPort) );
594               trace( "%u: %s remote %s:%u state %u\n",
595                      i, buffer, ntoa( buf->table[i].dwRemoteAddr ),
596                      ntohs(buf->table[i].dwRemotePort), buf->table[i].dwState );
597           }
598       }
599       HeapFree(GetProcessHeap(), 0, buf);
600     }
601   }
602 }
603
604 static void testGetUdpTable(void)
605 {
606   if (gGetUdpTable) {
607     DWORD apiReturn;
608     ULONG dwSize = 0;
609
610     apiReturn = gGetUdpTable(NULL, &dwSize, FALSE);
611     if (apiReturn == ERROR_NOT_SUPPORTED) {
612       skip("GetUdpTable is not supported\n");
613       return;
614     }
615     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
616      "GetUdpTable(NULL, &dwSize, FALSE) returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
617      apiReturn);
618     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
619       PMIB_UDPTABLE buf = HeapAlloc(GetProcessHeap(), 0, dwSize);
620
621       apiReturn = gGetUdpTable(buf, &dwSize, FALSE);
622       ok(apiReturn == NO_ERROR,
623        "GetUdpTable(buf, &dwSize, FALSE) returned %d, expected NO_ERROR\n",
624        apiReturn);
625
626       if (apiReturn == NO_ERROR && winetest_debug > 1)
627       {
628           DWORD i;
629           trace( "UDP table: %u entries\n", buf->dwNumEntries );
630           for (i = 0; i < buf->dwNumEntries; i++)
631               trace( "%u: %s:%u\n",
632                      i, ntoa( buf->table[i].dwLocalAddr ), ntohs(buf->table[i].dwLocalPort) );
633       }
634       HeapFree(GetProcessHeap(), 0, buf);
635     }
636   }
637 }
638
639 /*
640 still-to-be-tested NT4-onward functions:
641 CreateIpForwardEntry
642 DeleteIpForwardEntry
643 CreateIpNetEntry
644 DeleteIpNetEntry
645 GetFriendlyIfIndex
646 GetRTTAndHopCount
647 SetIfEntry
648 SetIpForwardEntry
649 SetIpNetEntry
650 SetIpStatistics
651 SetIpTTL
652 SetTcpEntry
653 */
654 static void testWinNT4Functions(void)
655 {
656   testGetNumberOfInterfaces();
657   testGetIpAddrTable();
658   testGetIfTable();
659   testGetIpForwardTable();
660   testGetIpNetTable();
661   testGetIcmpStatistics();
662   testGetIpStatistics();
663   testGetTcpStatistics();
664   testGetUdpStatistics();
665   testGetTcpTable();
666   testGetUdpTable();
667 }
668
669 static void testGetInterfaceInfo(void)
670 {
671   if (gGetInterfaceInfo) {
672     DWORD apiReturn;
673     ULONG len = 0;
674
675     apiReturn = gGetInterfaceInfo(NULL, NULL);
676     if (apiReturn == ERROR_NOT_SUPPORTED) {
677       skip("GetInterfaceInfo is not supported\n");
678       return;
679     }
680     ok(apiReturn == ERROR_INVALID_PARAMETER,
681      "GetInterfaceInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
682      apiReturn);
683     apiReturn = gGetInterfaceInfo(NULL, &len);
684     ok(apiReturn == ERROR_INSUFFICIENT_BUFFER,
685      "GetInterfaceInfo returned %d, expected ERROR_INSUFFICIENT_BUFFER\n",
686      apiReturn);
687     if (apiReturn == ERROR_INSUFFICIENT_BUFFER) {
688       PIP_INTERFACE_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
689
690       apiReturn = gGetInterfaceInfo(buf, &len);
691       ok(apiReturn == NO_ERROR,
692        "GetInterfaceInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
693        apiReturn);
694       HeapFree(GetProcessHeap(), 0, buf);
695     }
696   }
697 }
698
699 static void testGetAdaptersInfo(void)
700 {
701   if (gGetAdaptersInfo) {
702     DWORD apiReturn;
703     ULONG len = 0;
704
705     apiReturn = gGetAdaptersInfo(NULL, NULL);
706     if (apiReturn == ERROR_NOT_SUPPORTED) {
707       skip("GetAdaptersInfo is not supported\n");
708       return;
709     }
710     ok(apiReturn == ERROR_INVALID_PARAMETER,
711      "GetAdaptersInfo returned %d, expected ERROR_INVALID_PARAMETER\n",
712      apiReturn);
713     apiReturn = gGetAdaptersInfo(NULL, &len);
714     ok(apiReturn == ERROR_NO_DATA || apiReturn == ERROR_BUFFER_OVERFLOW,
715      "GetAdaptersInfo returned %d, expected ERROR_NO_DATA or ERROR_BUFFER_OVERFLOW\n",
716      apiReturn);
717     if (apiReturn == ERROR_NO_DATA)
718       ; /* no adapter's, that's okay */
719     else if (apiReturn == ERROR_BUFFER_OVERFLOW) {
720       PIP_ADAPTER_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
721
722       apiReturn = gGetAdaptersInfo(buf, &len);
723       ok(apiReturn == NO_ERROR,
724        "GetAdaptersInfo(buf, &dwSize) returned %d, expected NO_ERROR\n",
725        apiReturn);
726       HeapFree(GetProcessHeap(), 0, buf);
727     }
728   }
729 }
730
731 static void testGetNetworkParams(void)
732 {
733   if (gGetNetworkParams) {
734     DWORD apiReturn;
735     ULONG len = 0;
736
737     apiReturn = gGetNetworkParams(NULL, NULL);
738     if (apiReturn == ERROR_NOT_SUPPORTED) {
739       skip("GetNetworkParams is not supported\n");
740       return;
741     }
742     ok(apiReturn == ERROR_INVALID_PARAMETER,
743      "GetNetworkParams returned %d, expected ERROR_INVALID_PARAMETER\n",
744      apiReturn);
745     apiReturn = gGetNetworkParams(NULL, &len);
746     ok(apiReturn == ERROR_BUFFER_OVERFLOW,
747      "GetNetworkParams returned %d, expected ERROR_BUFFER_OVERFLOW\n",
748      apiReturn);
749     if (apiReturn == ERROR_BUFFER_OVERFLOW) {
750       PFIXED_INFO buf = HeapAlloc(GetProcessHeap(), 0, len);
751
752       apiReturn = gGetNetworkParams(buf, &len);
753       ok(apiReturn == NO_ERROR,
754        "GetNetworkParams(buf, &dwSize) returned %d, expected NO_ERROR\n",
755        apiReturn);
756       HeapFree(GetProcessHeap(), 0, buf);
757     }
758   }
759 }
760
761 /*
762 still-to-be-tested 98-onward functions:
763 GetBestInterface
764 GetBestRoute
765 IpReleaseAddress
766 IpRenewAddress
767 */
768 static DWORD CALLBACK testWin98Functions(void *p)
769 {
770   testGetInterfaceInfo();
771   testGetAdaptersInfo();
772   testGetNetworkParams();
773   return 0;
774 }
775
776 static void testGetPerAdapterInfo(void)
777 {
778     DWORD ret, needed;
779     void *buffer;
780
781     if (!gGetPerAdapterInfo) return;
782     ret = gGetPerAdapterInfo(1, NULL, NULL);
783     if (ret == ERROR_NOT_SUPPORTED) {
784       skip("GetPerAdapterInfo is not supported\n");
785       return;
786     }
787     ok( ret == ERROR_INVALID_PARAMETER, "got %u instead of ERROR_INVALID_PARAMETER\n", ret );
788     needed = 0xdeadbeef;
789     ret = gGetPerAdapterInfo(1, NULL, &needed);
790     if (ret == ERROR_NO_DATA) return;  /* no such adapter */
791     ok( ret == ERROR_BUFFER_OVERFLOW, "got %u instead of ERROR_BUFFER_OVERFLOW\n", ret );
792     ok( needed != 0xdeadbeef, "needed not set\n" );
793     buffer = HeapAlloc( GetProcessHeap(), 0, needed );
794     ret = gGetPerAdapterInfo(1, buffer, &needed);
795     ok( ret == NO_ERROR, "got %u instead of NO_ERROR\n", ret );
796     HeapFree( GetProcessHeap(), 0, buffer );
797 }
798
799 /*
800 still-to-be-tested 2K-onward functions:
801 AddIPAddress
802 CreateProxyArpEntry
803 DeleteIPAddress
804 DeleteProxyArpEntry
805 EnableRouter
806 FlushIpNetTable
807 GetAdapterIndex
808 NotifyAddrChange
809 NotifyRouteChange
810 SendARP
811 UnenableRouter
812 */
813 static void testWin2KFunctions(void)
814 {
815     testGetPerAdapterInfo();
816 }
817
818 static void test_GetAdaptersAddresses(void)
819 {
820     ULONG ret, size;
821     IP_ADAPTER_ADDRESSES *aa;
822     IP_ADAPTER_UNICAST_ADDRESS *ua;
823
824     if (!gGetAdaptersAddresses)
825     {
826         win_skip("GetAdaptersAddresses not present\n");
827         return;
828     }
829
830     ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, NULL);
831     ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", ret);
832
833     size = 0;
834     ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size);
835     ok(ret == ERROR_BUFFER_OVERFLOW, "expected ERROR_BUFFER_OVERFLOW, got %u\n", ret);
836     if (ret != ERROR_BUFFER_OVERFLOW) return;
837
838     aa = HeapAlloc(GetProcessHeap(), 0, size);
839     ret = gGetAdaptersAddresses(AF_UNSPEC, 0, NULL, aa, &size);
840     ok(!ret, "expected ERROR_SUCCESS got %u\n", ret);
841
842     while (!ret && winetest_debug > 1 && aa)
843     {
844         trace("Length:                %u\n", S(U(*aa)).Length);
845         trace("IfIndex:               %u\n", S(U(*aa)).IfIndex);
846         trace("Next:                  %p\n", aa->Next);
847         trace("AdapterName:           %s\n", aa->AdapterName);
848         trace("FirstUnicastAddress:   %p\n", aa->FirstUnicastAddress);
849         ua = aa->FirstUnicastAddress;
850         while (ua)
851         {
852             trace("\tLength:                  %u\n", S(U(*ua)).Length);
853             trace("\tFlags:                   0x%08x\n", S(U(*ua)).Flags);
854             trace("\tNext:                    %p\n", ua->Next);
855             trace("\tAddress.lpSockaddr:      %p\n", ua->Address.lpSockaddr);
856             trace("\tAddress.iSockaddrLength: %d\n", ua->Address.iSockaddrLength);
857             trace("\tPrefixOrigin:            %u\n", ua->PrefixOrigin);
858             trace("\tSuffixOrigin:            %u\n", ua->SuffixOrigin);
859             trace("\tDadState:                %u\n", ua->DadState);
860             trace("\tValidLifetime:           0x%08x\n", ua->ValidLifetime);
861             trace("\tPreferredLifetime:       0x%08x\n", ua->PreferredLifetime);
862             trace("\tLeaseLifetime:           0x%08x\n", ua->LeaseLifetime);
863             trace("\n");
864             ua = ua->Next;
865         }
866         trace("FirstAnycastAddress:   %p\n", aa->FirstAnycastAddress);
867         trace("FirstMulticastAddress: %p\n", aa->FirstMulticastAddress);
868         trace("FirstDnsServerAddress: %p\n", aa->FirstDnsServerAddress);
869         trace("DnsSuffix:             %p\n", aa->DnsSuffix);
870         trace("Description:           %p\n", aa->Description);
871         trace("FriendlyName:          %p\n", aa->FriendlyName);
872         trace("PhysicalAddress:       %02x\n", aa->PhysicalAddress[0]);
873         trace("PhysicalAddressLength: %u\n", aa->PhysicalAddressLength);
874         trace("Flags:                 0x%08x\n", aa->Flags);
875         trace("Mtu:                   %u\n", aa->Mtu);
876         trace("IfType:                %u\n", aa->IfType);
877         trace("OperStatus:            %u\n", aa->OperStatus);
878         trace("\n");
879         aa = aa->Next;
880     }
881     HeapFree(GetProcessHeap(), 0, aa);
882 }
883
884 START_TEST(iphlpapi)
885 {
886
887   loadIPHlpApi();
888   if (hLibrary) {
889     HANDLE thread;
890
891     testWin98OnlyFunctions();
892     testWinNT4Functions();
893
894     /* run testGetXXXX in two threads at once to make sure we don't crash in that case */
895     thread = CreateThread(NULL, 0, testWin98Functions, NULL, 0, NULL);
896     testWin98Functions(NULL);
897     WaitForSingleObject(thread, INFINITE);
898
899     testWin2KFunctions();
900     test_GetAdaptersAddresses();
901     freeIPHlpApi();
902   }
903 }