[INETMIB1_WINETEST]
[reactos.git] / 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 = sizeof(bogus) / sizeof(bogus[0]);
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 = sizeof(mib2IfTable) / sizeof(mib2IfTable[0]);
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 = sizeof(mib2IfDescr) / sizeof(mib2IfDescr[0]);
165 vars[0].name.ids = mib2IfDescr;
166 vars[1].name.idLength =
167 sizeof(mib2IfAdminStatus) / sizeof(mib2IfAdminStatus[0]);
168 vars[1].name.ids = mib2IfAdminStatus;
169 vars[2].name.idLength =
170 sizeof(mib2IfOperStatus) / sizeof(mib2IfOperStatus[0]);
171 vars[2].name.ids = mib2IfOperStatus;
172 list.len = 3;
173 SetLastError(0xdeadbeef);
174 error = 0xdeadbeef;
175 index = 0xdeadbeef;
176 ret = pSnmpExtensionQuery(SNMP_PDU_GET, &list, &error, &index);
177 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
178 ok(error == SNMP_ERRORSTATUS_NOSUCHNAME,
179 "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error);
180 ok(index == 1, "expected index 1, got %d\n", index);
181 /* but a GetNext succeeds with the same values, because GetNext gets the
182 * entry after the specified OID, not the entry specified by it. The
183 * successor to the table is the first entry in the table.
184 * The OIDs need to be allocated, because GetNext modifies them to indicate
185 * the end of data.
186 */
187 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
188 SnmpUtilOidCpy(&vars2[1].name, &vars[1].name);
189 SnmpUtilOidCpy(&vars2[2].name, &vars[2].name);
190 list.list = vars2;
191 moreData = TRUE;
192 noChange = FALSE;
193 entry = 0;
194 do {
195 SetLastError(0xdeadbeef);
196 error = 0xdeadbeef;
197 index = 0xdeadbeef;
198 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
199 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
200 ok(error == SNMP_ERRORSTATUS_NOERROR,
201 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
202 ok(index == 0, "expected index 0, got %d\n", index);
203 if (!ret)
204 moreData = FALSE;
205 else if (error)
206 moreData = FALSE;
207 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
208 vars[0].name.idLength))
209 moreData = FALSE;
210 else if (SnmpUtilOidNCmp(&vars2[1].name, &vars[1].name,
211 vars[1].name.idLength))
212 moreData = FALSE;
213 else if (SnmpUtilOidNCmp(&vars2[2].name, &vars[2].name,
214 vars[2].name.idLength))
215 moreData = FALSE;
216 else if (!SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) ||
217 !SnmpUtilOidCmp(&vars[1].name, &vars2[1].name) ||
218 !SnmpUtilOidCmp(&vars[2].name, &vars2[2].name))
219 {
220 /* If the OID isn't modified, the function isn't implemented on this
221 * platform, skip the remaining tests.
222 */
223 noChange = TRUE;
224 }
225 if (moreData)
226 {
227 UINT lastID;
228
229 /* Check the OIDs. For these types of values (display strings and
230 * integers) they should increase by 1 for each element of the table
231 * according to RFC 1158. Windows sometimes has a weird value in the
232 * table, so allow any value as long as it's greater than the previous
233 * value on Windows.
234 */
235 ok(vars2[0].name.idLength == vars[0].name.idLength + 1,
236 "expected length %d, got %d\n", vars[0].name.idLength + 1,
237 vars2[0].name.idLength);
238 lastID = vars2[0].name.ids[vars2[0].name.idLength - 1];
239 ok(lastID == entry + 1 || broken(lastID > entry),
240 "expected %d, got %d\n", entry + 1, lastID);
241 ok(vars2[1].name.idLength == vars[1].name.idLength + 1,
242 "expected length %d, got %d\n", vars[1].name.idLength + 1,
243 vars2[1].name.idLength);
244 lastID = vars2[1].name.ids[vars2[1].name.idLength - 1];
245 ok(lastID == entry + 1 || broken(lastID > entry),
246 "expected %d, got %d\n", entry + 1, lastID);
247 ok(vars2[2].name.idLength == vars[2].name.idLength + 1,
248 "expected length %d, got %d\n", vars[2].name.idLength + 1,
249 vars2[2].name.idLength);
250 lastID = vars2[2].name.ids[vars2[2].name.idLength - 1];
251 ok(lastID == entry + 1 || broken(lastID > entry),
252 "expected %d, got %d\n", entry + 1, lastID);
253 entry = lastID;
254 /* Check the types while we're at it */
255 ok(vars2[0].value.asnType == ASN_OCTETSTRING,
256 "expected ASN_OCTETSTRING, got %02x\n", vars2[0].value.asnType);
257 ok(vars2[1].value.asnType == ASN_INTEGER,
258 "expected ASN_INTEGER, got %02x\n", vars2[1].value.asnType);
259 ok(vars2[2].value.asnType == ASN_INTEGER,
260 "expected ASN_INTEGER, got %02x\n", vars2[2].value.asnType);
261 }
262 else if (noChange)
263 skip("no change in OID, no MIB2 IF table implementation\n");
264 } while (moreData && !noChange);
265 SnmpUtilVarBindFree(&vars2[0]);
266 SnmpUtilVarBindFree(&vars2[1]);
267 SnmpUtilVarBindFree(&vars2[2]);
268
269 /* Even though SnmpExtensionInit says this DLL supports the MIB2 system
270 * variables, on recent systems (at least Win2k) the first variable it
271 * returns a value for is the first interface.
272 */
273 vars[0].name.idLength = sizeof(mib2System) / sizeof(mib2System[0]);
274 vars[0].name.ids = mib2System;
275 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
276 vars2[0].value.asnType = 0;
277 list.len = 1;
278 list.list = vars2;
279 noChange = FALSE;
280 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
281 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
282 ok(error == SNMP_ERRORSTATUS_NOERROR,
283 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
284 ok(index == 0, "expected index 0, got %d\n", index);
285 vars3[0].name.idLength = sizeof(mib2If) / sizeof(mib2If[0]);
286 vars3[0].name.ids = mib2If;
287 ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength) ||
288 !SnmpUtilOidNCmp(&vars2[0].name, &vars3[0].name, vars3[0].name.idLength),
289 "expected 1.3.6.1.2.1.1 or 1.3.6.1.2.1.2, got %s\n",
290 SnmpUtilOidToA(&vars2[0].name));
291 SnmpUtilVarBindFree(&vars2[0]);
292
293 /* Check the type and OIDs of the IP address table */
294 vars[0].name.idLength = sizeof(mib2IpAddr) / sizeof(mib2IpAddr[0]);
295 vars[0].name.ids = mib2IpAddr;
296 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
297 vars2[0].value.asnType = 0;
298 list.len = 1;
299 list.list = vars2;
300 moreData = TRUE;
301 do {
302 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
303 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
304 ok(error == SNMP_ERRORSTATUS_NOERROR,
305 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
306 ok(index == 0, "expected index 0, got %d\n", index);
307 if (!ret)
308 moreData = FALSE;
309 else if (error)
310 moreData = FALSE;
311 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
312 vars[0].name.idLength))
313 moreData = FALSE;
314 else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name))
315 {
316 /* If the OID isn't modified, the function isn't implemented on this
317 * platform, skip the remaining tests.
318 */
319 noChange = TRUE;
320 }
321 if (moreData)
322 {
323 /* Make sure the size of the OID is right.
324 * FIXME: don't know if IPv6 addrs are shared with this table.
325 * Don't think so, but I'm not certain.
326 */
327 ok(vars2[0].name.idLength == vars[0].name.idLength + 4,
328 "expected length %d, got %d\n", vars[0].name.idLength + 4,
329 vars2[0].name.idLength);
330 /* Make sure the type is right */
331 ok(vars2[0].value.asnType == ASN_IPADDRESS,
332 "expected type ASN_IPADDRESS, got %02x\n",
333 vars2[0].value.asnType);
334 if (vars2[0].value.asnType == ASN_IPADDRESS)
335 {
336 UINT i;
337
338 /* This looks uglier than it is: the base OID for the IP
339 * address, 1.3.6.1.2.1.4.20.1.1, is appended with the IP
340 * address of the entry. So e.g. the loopback address is
341 * identified in MIB2 as 1.3.6.1.2.1.4.20.1.1.127.0.0.1
342 */
343 for (i = 0; i < vars2[0].value.asnValue.address.length; i++)
344 {
345 ok(vars2[0].value.asnValue.address.stream[i] ==
346 vars2[0].name.ids[vars2[0].name.idLength - 4 + i],
347 "expected ident byte %d to be %d, got %d\n", i,
348 vars2[0].value.asnValue.address.stream[i],
349 vars2[0].name.ids[vars2[0].name.idLength - 4 + i]);
350 }
351 }
352 }
353 else if (noChange)
354 skip("no change in OID, no MIB2 IP address table implementation\n");
355 } while (moreData && !noChange);
356 SnmpUtilVarBindFree(&vars2[0]);
357
358 /* Check the type and OIDs of the IP route table */
359 vars[0].name.idLength = DEFINE_SIZEOF(mib2IpRouteTable);
360 vars[0].name.ids = mib2IpRouteTable;
361 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
362 vars2[0].value.asnType = 0;
363 list.len = 1;
364 list.list = vars2;
365 moreData = TRUE;
366 noChange = FALSE;
367 do {
368 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
369 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
370 ok(error == SNMP_ERRORSTATUS_NOERROR,
371 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
372 ok(index == 0, "expected index 0, got %d\n", index);
373 if (!ret)
374 moreData = FALSE;
375 else if (error)
376 moreData = FALSE;
377 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
378 vars[0].name.idLength))
379 moreData = FALSE;
380 else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name))
381 {
382 /* If the OID isn't modified, the function isn't implemented on this
383 * platform, skip the remaining tests.
384 */
385 noChange = TRUE;
386 }
387 if (moreData)
388 {
389 /* Make sure the size of the OID is right.
390 * FIXME: don't know if IPv6 addrs are shared with this table.
391 * Don't think so, but I'm not certain.
392 */
393 ok(vars2[0].name.idLength == vars[0].name.idLength + 4,
394 "expected length %d, got %d\n", vars[0].name.idLength + 4,
395 vars2[0].name.idLength);
396 /* Make sure the type is right */
397 ok(vars2[0].value.asnType == ASN_IPADDRESS,
398 "expected type ASN_IPADDRESS, got %02x\n",
399 vars2[0].value.asnType);
400 if (vars2[0].value.asnType == ASN_IPADDRESS)
401 {
402 UINT i;
403
404 /* The base OID for the route table, 1.3.6.1.2.1.4.21.1.1, is
405 * appended with the dest IP address of the entry. So e.g. a
406 * route entry for 224.0.0.0 is identified in MIB2 as
407 * 1.3.6.1.2.1.4.21.1.1.224.0.0.0
408 */
409 for (i = 0; i < vars2[0].value.asnValue.address.length; i++)
410 {
411 ok(vars2[0].value.asnValue.address.stream[i] ==
412 vars2[0].name.ids[vars2[0].name.idLength - 4 + i],
413 "expected ident byte %d to be %d, got %d\n", i,
414 vars2[0].value.asnValue.address.stream[i],
415 vars2[0].name.ids[vars2[0].name.idLength - 4 + i]);
416 }
417 }
418 }
419 else if (noChange)
420 skip("no change in OID, no MIB2 IP route table implementation\n");
421 } while (moreData && !noChange);
422 SnmpUtilVarBindFree(&vars2[0]);
423
424 /* Check the type and OIDs of the UDP table */
425 vars[0].name.idLength = DEFINE_SIZEOF(mib2UdpTable);
426 vars[0].name.ids = mib2UdpTable;
427 SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
428 vars2[0].value.asnType = 0;
429 list.len = 1;
430 list.list = vars2;
431 moreData = TRUE;
432 noChange = FALSE;
433 do {
434 ret = pSnmpExtensionQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
435 ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index);
436 /* FIXME: error and index aren't checked here because the UDP table is
437 * the last OID currently supported by Wine, so the last GetNext fails.
438 * todo_wine is also not effective because it will succeed for all but
439 * the last GetNext. Remove the if (0) if any later OID is supported
440 * by Wine.
441 */
442 if (0) {
443 ok(error == SNMP_ERRORSTATUS_NOERROR,
444 "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
445 ok(index == 0, "expected index 0, got %d\n", index);
446 }
447 if (!ret)
448 moreData = FALSE;
449 else if (error)
450 moreData = FALSE;
451 else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
452 vars[0].name.idLength))
453 moreData = FALSE;
454 else if (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name))
455 {
456 /* If the OID isn't modified, the function isn't implemented on this
457 * platform, skip the remaining tests.
458 */
459 noChange = TRUE;
460 }
461 if (moreData)
462 {
463 /* Make sure the size of the OID is right. */
464 ok(vars2[0].name.idLength == vars[0].name.idLength + 5,
465 "expected length %d, got %d\n", vars[0].name.idLength + 5,
466 vars2[0].name.idLength);
467 /* Make sure the type is right */
468 ok(vars2[0].value.asnType == ASN_IPADDRESS,
469 "expected type ASN_IPADDRESS, got %02x\n",
470 vars2[0].value.asnType);
471 if (vars2[0].value.asnType == ASN_IPADDRESS)
472 {
473 UINT i;
474
475 /* Again with the ugly: the base OID for the UDP table,
476 * 1.3.6.1.2.1.7.5.1, is appended with the local IP address and
477 * port number of the entry. So e.g. an entry for
478 * 192.168.1.1:4000 is identified in MIB2 as
479 * 1.3.6.1.2.1.7.5.1.192.168.1.1.4000
480 */
481 for (i = 0; i < vars2[0].value.asnValue.address.length; i++)
482 {
483 ok(vars2[0].value.asnValue.address.stream[i] ==
484 vars2[0].name.ids[vars2[0].name.idLength - 5 + i],
485 "expected ident byte %d to be %d, got %d\n", i,
486 vars2[0].value.asnValue.address.stream[i],
487 vars2[0].name.ids[vars2[0].name.idLength - 5 + i]);
488 }
489 }
490 }
491 else if (noChange)
492 skip("no change in OID, no MIB2 UDP table implementation\n");
493 } while (moreData && !noChange);
494 SnmpUtilVarBindFree(&vars2[0]);
495 }
496
497 START_TEST(main)
498 {
499 HMODULE mod;
500
501 if (!(mod = init_test_functions()))
502 return;
503
504 testInit();
505 testQuery();
506
507 uninit_test_functions(mod);
508 }