[INETMIB1_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / inetmib1 / main.c
1 /*
2 * Copyright 2008 Juan Lang
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18 #include <stdio.h>
19 #include <stdarg.h>
20 #include <windef.h>
21 #include <winbase.h>
22 #include <snmp.h>
23
24 #include "wine/test.h"
25
26 static BOOL (WINAPI *pSnmpExtensionInit)(DWORD, HANDLE*, AsnObjectIdentifier*);
27 static BOOL (WINAPI *pSnmpExtensionQuery)(BYTE, SnmpVarBindList*, AsnInteger32*, AsnInteger32*);
28
29 static HMODULE init_test_functions(void)
30 {
31 HMODULE mod = LoadLibraryA("inetmib1");
32
33 ok(mod != NULL, "failed to load inetmib1.dll\n");
34
35 if (!mod) return NULL;
36
37 pSnmpExtensionInit = (void *)GetProcAddress(mod, "SnmpExtensionInit");
38 pSnmpExtensionQuery = (void *)GetProcAddress(mod, "SnmpExtensionQuery");
39
40 return mod;
41 }
42
43 static void uninit_test_functions(HMODULE mod)
44 {
45 FreeLibrary(mod);
46 }
47
48 static void testInit(void)
49 {
50 BOOL ret;
51 HANDLE event;
52 AsnObjectIdentifier oid;
53
54 if (!pSnmpExtensionInit)
55 {
56 win_skip("no SnmpExtensionInit\n");
57 return;
58 }
59
60 if (0) /* crashes on native */
61 {
62 ret = pSnmpExtensionInit(0, NULL, NULL);
63 ret = pSnmpExtensionInit(0, NULL, &oid);
64 ret = pSnmpExtensionInit(0, &event, NULL);
65 }
66
67 ret = pSnmpExtensionInit(0, &event, &oid);
68 ok(ret, "SnmpExtensionInit failed: %d\n", GetLastError());
69 ok(!strcmp("1.3.6.1.2.1.1", SnmpUtilOidToA(&oid)),
70 "Expected 1.3.6.1.2.1.1, got %s\n", SnmpUtilOidToA(&oid));
71
72
73 if (0)
74 {
75 /* Fails when called on win8, documentation suggests that
76 extension itself is responsible for freeing this oid */
77 SnmpUtilOidFree(&oid);
78 }
79 }
80
81 static void testQuery(void)
82 {
83 BOOL ret, moreData, noChange;
84 SnmpVarBindList list;
85 AsnInteger32 error, index;
86 UINT bogus[] = { 1,2,3,4 };
87 UINT mib2System[] = { 1,3,6,1,2,1,1 };
88 UINT mib2If[] = { 1,3,6,1,2,1,2 };
89 UINT mib2IfTable[] = { 1,3,6,1,2,1,2,2 };
90 UINT mib2IfDescr[] = { 1,3,6,1,2,1,2,2,1,2 };
91 UINT mib2IfAdminStatus[] = { 1,3,6,1,2,1,2,2,1,7 };
92 UINT mib2IfOperStatus[] = { 1,3,6,1,2,1,2,2,1,8 };
93 UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1,1 };
94 UINT mib2IpRouteTable[] = { 1,3,6,1,2,1,4,21,1,1 };
95 UINT mib2UdpTable[] = { 1,3,6,1,2,1,7,5,1,1 };
96 SnmpVarBind vars[3], vars2[3], vars3[3];
97 UINT entry;
98
99 if (!pSnmpExtensionQuery)
100 {
101 win_skip("couldn't find SnmpExtensionQuery\n");
102 return;
103 }
104
105 if (0) /* crashes on native */
106 {
107 ret = pSnmpExtensionQuery(0, NULL, NULL, NULL);
108 ret = pSnmpExtensionQuery(0, NULL, &error, NULL);
109 ret = pSnmpExtensionQuery(0, NULL, NULL, &index);
110 ret = pSnmpExtensionQuery(0, &list, NULL, NULL);
111 ret = pSnmpExtensionQuery(0, &list, &error, NULL);
112 }
113 /* An empty list succeeds */
114 list.len = 0;
115 error = 0xdeadbeef;
116 index = 0xdeadbeef;
117 ret = pSnmpExtensionQuery(SNMP_PDU_GET, &list, &error, &index);
118 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
119 ok(error == SNMP_ERRORSTATUS_NOERROR,
120 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
121 ok(index == 0, "expected index 0, got %d\n", index);
122
123 /* Oddly enough, this "succeeds," even though the OID is clearly
124 * unsupported.
125 */
126 vars[0].name.idLength = ARRAY_SIZE(bogus);
127 vars[0].name.ids = bogus;
128 vars[0].value.asnType = 0;
129 list.len = 1;
130 list.list = vars;
131 SetLastError(0xdeadbeef);
132 error = 0xdeadbeef;
133 index = 0xdeadbeef;
134 ret = pSnmpExtensionQuery(SNMP_PDU_GET, &list, &error, &index);
135 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
136 ok(error == SNMP_ERRORSTATUS_NOERROR ||
137 broken(error == ERROR_FILE_NOT_FOUND) /* NT4 */,
138 "expected SNMP_ERRORSTATUS_NOERROR or ERROR_FILE_NOT_FOUND, got %d\n",
139 error);
140 if (error == SNMP_ERRORSTATUS_NOERROR)
141 ok(index == 0, "expected index 0, got %d\n", index);
142 else if (error == ERROR_FILE_NOT_FOUND)
143 ok(index == 1, "expected index 1, got %d\n", index);
144 /* The OID isn't changed either: */
145 ok(!strcmp("1.2.3.4", SnmpUtilOidToA(&vars[0].name)),
146 "expected 1.2.3.4, got %s\n", SnmpUtilOidToA(&vars[0].name));
147
148 /* The table is not an accessible variable, so it fails */
149 vars[0].name.idLength = ARRAY_SIZE(mib2IfTable);
150 vars[0].name.ids = mib2IfTable;
151 SetLastError(0xdeadbeef);
152 error = 0xdeadbeef;
153 index = 0xdeadbeef;
154 ret = pSnmpExtensionQuery(SNMP_PDU_GET, &list, &error, &index);
155 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
156 ok(error == SNMP_ERRORSTATUS_NOSUCHNAME,
157 "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error);
158 /* The index is 1-based rather than 0-based */
159 ok(index == 1, "expected index 1, got %d\n", index);
160
161 /* A Get fails on something that specifies a table (but not a particular
162 * entry in it)...
163 */
164 vars[0].name.idLength = ARRAY_SIZE(mib2IfDescr);
165 vars[0].name.ids = mib2IfDescr;
166 vars[1].name.idLength = ARRAY_SIZE(mib2IfAdminStatus);
167 vars[1].name.ids = mib2IfAdminStatus;
168 vars[2].name.idLength = ARRAY_SIZE(mib2IfOperStatus);
169 vars[2].name.ids = mib2IfOperStatus;
170 list.len = 3;
171 SetLastError(0xdeadbeef);
172 error = 0xdeadbeef;
173 index = 0xdeadbeef;
174 ret = pSnmpExtensionQuery(SNMP_PDU_GET, &list, &error, &index);
175 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
176 ok(error == SNMP_ERRORSTATUS_NOSUCHNAME,
177 "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error);
178 ok(index == 1, "expected index 1, got %d\n", index);
179 /* but a GetNext succeeds with the same values, because GetNext gets the
180 * entry after the specified OID, not the entry specified by it. The
181 * successor to the table is the first entry in the table.
182 * The OIDs need to be allocated, because GetNext modifies them to indicate
183 * the end of data.
184 */
185 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
186 SnmpUtilOidCpy(&vars2[1].name, &vars[1].name);
187 SnmpUtilOidCpy(&vars2[2].name, &vars[2].name);
188 list.list = vars2;
189 moreData = TRUE;
190 noChange = FALSE;
191 entry = 0;
192 do {
193 SetLastError(0xdeadbeef);
194 error = 0xdeadbeef;
195 index = 0xdeadbeef;
196 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
197 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
198 ok(error == SNMP_ERRORSTATUS_NOERROR,
199 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
200 ok(index == 0, "expected index 0, got %d\n", index);
201 if (!ret)
202 moreData = FALSE;
203 else if (error)
204 moreData = FALSE;
205 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
206 vars[0].name.idLength))
207 moreData = FALSE;
208 else if (SnmpUtilOidNCmp(&vars2[1].name, &vars[1].name,
209 vars[1].name.idLength))
210 moreData = FALSE;
211 else if (SnmpUtilOidNCmp(&vars2[2].name, &vars[2].name,
212 vars[2].name.idLength))
213 moreData = FALSE;
214 else if (!SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) ||
215 !SnmpUtilOidCmp(&vars[1].name, &vars2[1].name) ||
216 !SnmpUtilOidCmp(&vars[2].name, &vars2[2].name))
217 {
218 /* If the OID isn't modified, the function isn't implemented on this
219 * platform, skip the remaining tests.
220 */
221 noChange = TRUE;
222 }
223 if (moreData)
224 {
225 UINT lastID;
226
227 /* Check the OIDs. For these types of values (display strings and
228 * integers) they should increase by 1 for each element of the table
229 * according to RFC 1158. Windows sometimes has a weird value in the
230 * table, so allow any value as long as it's greater than the previous
231 * value on Windows.
232 */
233 ok(vars2[0].name.idLength == vars[0].name.idLength + 1,
234 "expected length %d, got %d\n", vars[0].name.idLength + 1,
235 vars2[0].name.idLength);
236 lastID = vars2[0].name.ids[vars2[0].name.idLength - 1];
237 ok(lastID == entry + 1 || broken(lastID > entry),
238 "expected %d, got %d\n", entry + 1, lastID);
239 ok(vars2[1].name.idLength == vars[1].name.idLength + 1,
240 "expected length %d, got %d\n", vars[1].name.idLength + 1,
241 vars2[1].name.idLength);
242 lastID = vars2[1].name.ids[vars2[1].name.idLength - 1];
243 ok(lastID == entry + 1 || broken(lastID > entry),
244 "expected %d, got %d\n", entry + 1, lastID);
245 ok(vars2[2].name.idLength == vars[2].name.idLength + 1,
246 "expected length %d, got %d\n", vars[2].name.idLength + 1,
247 vars2[2].name.idLength);
248 lastID = vars2[2].name.ids[vars2[2].name.idLength - 1];
249 ok(lastID == entry + 1 || broken(lastID > entry),
250 "expected %d, got %d\n", entry + 1, lastID);
251 entry = lastID;
252 /* Check the types while we're at it */
253 ok(vars2[0].value.asnType == ASN_OCTETSTRING,
254 "expected ASN_OCTETSTRING, got %02x\n", vars2[0].value.asnType);
255 ok(vars2[1].value.asnType == ASN_INTEGER,
256 "expected ASN_INTEGER, got %02x\n", vars2[1].value.asnType);
257 ok(vars2[2].value.asnType == ASN_INTEGER,
258 "expected ASN_INTEGER, got %02x\n", vars2[2].value.asnType);
259 }
260 else if (noChange)
261 skip("no change in OID, no MIB2 IF table implementation\n");
262 } while (moreData && !noChange);
263 SnmpUtilVarBindFree(&vars2[0]);
264 SnmpUtilVarBindFree(&vars2[1]);
265 SnmpUtilVarBindFree(&vars2[2]);
266
267 /* Even though SnmpExtensionInit says this DLL supports the MIB2 system
268 * variables, on recent systems (at least Win2k) the first variable it
269 * returns a value for is the first interface.
270 */
271 vars[0].name.idLength = ARRAY_SIZE(mib2System);
272 vars[0].name.ids = mib2System;
273 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
274 vars2[0].value.asnType = 0;
275 list.len = 1;
276 list.list = vars2;
277 noChange = FALSE;
278 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
279 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
280 ok(error == SNMP_ERRORSTATUS_NOERROR,
281 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
282 ok(index == 0, "expected index 0, got %d\n", index);
283 vars3[0].name.idLength = ARRAY_SIZE(mib2If);
284 vars3[0].name.ids = mib2If;
285 ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength) ||
286 !SnmpUtilOidNCmp(&vars2[0].name, &vars3[0].name, vars3[0].name.idLength),
287 "expected 1.3.6.1.2.1.1 or 1.3.6.1.2.1.2, got %s\n",
288 SnmpUtilOidToA(&vars2[0].name));
289 SnmpUtilVarBindFree(&vars2[0]);
290
291 /* Check the type and OIDs of the IP address table */
292 vars[0].name.idLength = ARRAY_SIZE(mib2IpAddr);
293 vars[0].name.ids = mib2IpAddr;
294 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
295 vars2[0].value.asnType = 0;
296 list.len = 1;
297 list.list = vars2;
298 moreData = TRUE;
299 do {
300 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
301 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
302 ok(error == SNMP_ERRORSTATUS_NOERROR,
303 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
304 ok(index == 0, "expected index 0, got %d\n", index);
305 if (!ret)
306 moreData = FALSE;
307 else if (error)
308 moreData = FALSE;
309 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
310 vars[0].name.idLength))
311 moreData = FALSE;
312 else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name))
313 {
314 /* If the OID isn't modified, the function isn't implemented on this
315 * platform, skip the remaining tests.
316 */
317 noChange = TRUE;
318 }
319 if (moreData)
320 {
321 /* Make sure the size of the OID is right.
322 * FIXME: don't know if IPv6 addrs are shared with this table.
323 * Don't think so, but I'm not certain.
324 */
325 ok(vars2[0].name.idLength == vars[0].name.idLength + 4,
326 "expected length %d, got %d\n", vars[0].name.idLength + 4,
327 vars2[0].name.idLength);
328 /* Make sure the type is right */
329 ok(vars2[0].value.asnType == ASN_IPADDRESS,
330 "expected type ASN_IPADDRESS, got %02x\n",
331 vars2[0].value.asnType);
332 if (vars2[0].value.asnType == ASN_IPADDRESS)
333 {
334 UINT i;
335
336 /* This looks uglier than it is: the base OID for the IP
337 * address, 1.3.6.1.2.1.4.20.1.1, is appended with the IP
338 * address of the entry. So e.g. the loopback address is
339 * identified in MIB2 as 1.3.6.1.2.1.4.20.1.1.127.0.0.1
340 */
341 for (i = 0; i < vars2[0].value.asnValue.address.length; i++)
342 {
343 ok(vars2[0].value.asnValue.address.stream[i] ==
344 vars2[0].name.ids[vars2[0].name.idLength - 4 + i],
345 "expected ident byte %d to be %d, got %d\n", i,
346 vars2[0].value.asnValue.address.stream[i],
347 vars2[0].name.ids[vars2[0].name.idLength - 4 + i]);
348 }
349 }
350 }
351 else if (noChange)
352 skip("no change in OID, no MIB2 IP address table implementation\n");
353 } while (moreData && !noChange);
354 SnmpUtilVarBindFree(&vars2[0]);
355
356 /* Check the type and OIDs of the IP route table */
357 vars[0].name.idLength = DEFINE_SIZEOF(mib2IpRouteTable);
358 vars[0].name.ids = mib2IpRouteTable;
359 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
360 vars2[0].value.asnType = 0;
361 list.len = 1;
362 list.list = vars2;
363 moreData = TRUE;
364 noChange = FALSE;
365 do {
366 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
367 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
368 ok(error == SNMP_ERRORSTATUS_NOERROR,
369 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
370 ok(index == 0, "expected index 0, got %d\n", index);
371 if (!ret)
372 moreData = FALSE;
373 else if (error)
374 moreData = FALSE;
375 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
376 vars[0].name.idLength))
377 moreData = FALSE;
378 else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name))
379 {
380 /* If the OID isn't modified, the function isn't implemented on this
381 * platform, skip the remaining tests.
382 */
383 noChange = TRUE;
384 }
385 if (moreData)
386 {
387 /* Make sure the size of the OID is right.
388 * FIXME: don't know if IPv6 addrs are shared with this table.
389 * Don't think so, but I'm not certain.
390 */
391 ok(vars2[0].name.idLength == vars[0].name.idLength + 4,
392 "expected length %d, got %d\n", vars[0].name.idLength + 4,
393 vars2[0].name.idLength);
394 /* Make sure the type is right */
395 ok(vars2[0].value.asnType == ASN_IPADDRESS,
396 "expected type ASN_IPADDRESS, got %02x\n",
397 vars2[0].value.asnType);
398 if (vars2[0].value.asnType == ASN_IPADDRESS)
399 {
400 UINT i;
401
402 /* The base OID for the route table, 1.3.6.1.2.1.4.21.1.1, is
403 * appended with the dest IP address of the entry. So e.g. a
404 * route entry for 224.0.0.0 is identified in MIB2 as
405 * 1.3.6.1.2.1.4.21.1.1.224.0.0.0
406 */
407 for (i = 0; i < vars2[0].value.asnValue.address.length; i++)
408 {
409 ok(vars2[0].value.asnValue.address.stream[i] ==
410 vars2[0].name.ids[vars2[0].name.idLength - 4 + i],
411 "expected ident byte %d to be %d, got %d\n", i,
412 vars2[0].value.asnValue.address.stream[i],
413 vars2[0].name.ids[vars2[0].name.idLength - 4 + i]);
414 }
415 }
416 }
417 else if (noChange)
418 skip("no change in OID, no MIB2 IP route table implementation\n");
419 } while (moreData && !noChange);
420 SnmpUtilVarBindFree(&vars2[0]);
421
422 /* Check the type and OIDs of the UDP table */
423 vars[0].name.idLength = DEFINE_SIZEOF(mib2UdpTable);
424 vars[0].name.ids = mib2UdpTable;
425 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
426 vars2[0].value.asnType = 0;
427 list.len = 1;
428 list.list = vars2;
429 moreData = TRUE;
430 noChange = FALSE;
431 do {
432 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
433 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
434 /* FIXME: error and index aren't checked here because the UDP table is
435 * the last OID currently supported by Wine, so the last GetNext fails.
436 * todo_wine is also not effective because it will succeed for all but
437 * the last GetNext. Remove the if (0) if any later OID is supported
438 * by Wine.
439 */
440 if (0) {
441 ok(error == SNMP_ERRORSTATUS_NOERROR,
442 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
443 ok(index == 0, "expected index 0, got %d\n", index);
444 }
445 if (!ret)
446 moreData = FALSE;
447 else if (error)
448 moreData = FALSE;
449 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
450 vars[0].name.idLength))
451 moreData = FALSE;
452 else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name))
453 {
454 /* If the OID isn't modified, the function isn't implemented on this
455 * platform, skip the remaining tests.
456 */
457 noChange = TRUE;
458 }
459 if (moreData)
460 {
461 /* Make sure the size of the OID is right. */
462 ok(vars2[0].name.idLength == vars[0].name.idLength + 5,
463 "expected length %d, got %d\n", vars[0].name.idLength + 5,
464 vars2[0].name.idLength);
465 /* Make sure the type is right */
466 ok(vars2[0].value.asnType == ASN_IPADDRESS,
467 "expected type ASN_IPADDRESS, got %02x\n",
468 vars2[0].value.asnType);
469 if (vars2[0].value.asnType == ASN_IPADDRESS)
470 {
471 UINT i;
472
473 /* Again with the ugly: the base OID for the UDP table,
474 * 1.3.6.1.2.1.7.5.1, is appended with the local IP address and
475 * port number of the entry. So e.g. an entry for
476 * 192.168.1.1:4000 is identified in MIB2 as
477 * 1.3.6.1.2.1.7.5.1.192.168.1.1.4000
478 */
479 for (i = 0; i < vars2[0].value.asnValue.address.length; i++)
480 {
481 ok(vars2[0].value.asnValue.address.stream[i] ==
482 vars2[0].name.ids[vars2[0].name.idLength - 5 + i],
483 "expected ident byte %d to be %d, got %d\n", i,
484 vars2[0].value.asnValue.address.stream[i],
485 vars2[0].name.ids[vars2[0].name.idLength - 5 + i]);
486 }
487 }
488 }
489 else if (noChange)
490 skip("no change in OID, no MIB2 UDP table implementation\n");
491 } while (moreData && !noChange);
492 SnmpUtilVarBindFree(&vars2[0]);
493 }
494
495 START_TEST(main)
496 {
497 HMODULE mod;
498
499 if (!(mod = init_test_functions()))
500 return;
501
502 testInit();
503 testQuery();
504
505 uninit_test_functions(mod);
506 }