Big merge in wine code. This merged version is far more complete than
[reactos.git] / reactos / lib / iphlpapi / ipstats_reactos.c
1 /* Copyright (C) 2003 Juan Lang
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * This file implements statistics getting using the /proc filesystem exported
18 * by Linux, and maybe other OSes.
19 */
20
21 #include "ipprivate.h"
22 #include "ipstats.h"
23 #include "ifenum.h"
24
25 #ifndef TCPS_ESTABLISHED
26 # define TCPS_ESTABLISHED TCP_ESTABLISHED
27 #endif
28 #ifndef TCPS_SYN_SENT
29 # define TCPS_SYN_SENT TCP_SYN_SENT
30 #endif
31 #ifndef TCPS_SYN_RECEIVED
32 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
33 #endif
34 #ifndef TCPS_FIN_WAIT_1
35 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
36 #endif
37 #ifndef TCPS_FIN_WAIT_2
38 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
39 #endif
40 #ifndef TCPS_TIME_WAIT
41 # define TCPS_TIME_WAIT TCP_TIME_WAIT
42 #endif
43 #ifndef TCPS_CLOSED
44 # define TCPS_CLOSED TCP_CLOSE
45 #endif
46 #ifndef TCPS_CLOSE_WAIT
47 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
48 #endif
49 #ifndef TCPS_LAST_ACK
50 # define TCPS_LAST_ACK TCP_LAST_ACK
51 #endif
52 #ifndef TCPS_LISTEN
53 # define TCPS_LISTEN TCP_LISTEN
54 #endif
55 #ifndef TCPS_CLOSING
56 # define TCPS_CLOSING TCP_CLOSING
57 #endif
58
59 BOOL isIpEntity( HANDLE tcpFile, TDIEntityID *ent ) {
60 DWORD entityType, returnedLen;
61 NTSTATUS status;
62 TCP_REQUEST_QUERY_INFORMATION_EX req;
63
64 req.ID.toi_class = INFO_CLASS_GENERIC;
65 req.ID.toi_type = INFO_TYPE_PROVIDER;
66 req.ID.toi_id = ENTITY_TYPE_ID;
67 req.ID.toi_entity = *ent;
68
69 status =
70 DeviceIoControl
71 ( tcpFile,
72 IOCTL_TCP_QUERY_INFORMATION_EX,
73 &req,
74 sizeof(req),
75 &entityType,
76 sizeof(entityType),
77 &returnedLen,
78 NULL );
79
80 DPRINT("Ent: %04x:d -> %04x\n",
81 ent->tei_entity, ent->tei_instance, entityType );
82
83 return NT_SUCCESS(status) && entityType == CL_NL_IP;
84 }
85
86 NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) {
87 DWORD numEntities = 0;
88 DWORD numRoutes = 0;
89 TDIEntityID *entitySet = 0;
90 NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
91 int i;
92
93 if( !NT_SUCCESS(status) )
94 return status;
95
96 for( i = 0; i < numEntities; i++ ) {
97 if( isIpEntity( tcpFile, &entitySet[i] ) ) {
98 DPRINT("Entity %d is an IP Entity\n", i);
99 if( numRoutes == index ) break;
100 else numRoutes++;
101 }
102 }
103
104 DPRINT("Index %d is entity #%d - %04x:%08x\n", index, i,
105 entitySet[i].tei_entity, entitySet[i].tei_instance );
106
107 if( numRoutes == index && i < numEntities ) {
108 memcpy( ent, &entitySet[i], sizeof(*ent) );
109 tdiFreeThingSet( entitySet );
110 return STATUS_SUCCESS;
111 } else {
112 tdiFreeThingSet( entitySet );
113 return STATUS_UNSUCCESSFUL;
114 }
115 }
116
117 NTSTATUS tdiGetMibForIpEntity
118 ( HANDLE tcpFile, TDIEntityID *ent, IPSNMPInfo *entry ) {
119 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
120 NTSTATUS status = STATUS_SUCCESS;
121 DWORD returnSize;
122
123 memset( entry, 0, sizeof( *entry ) );
124
125 DPRINT("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n",
126 (DWORD)tcpFile, ent->tei_instance);
127
128 req.ID.toi_class = INFO_CLASS_PROTOCOL;
129 req.ID.toi_type = INFO_TYPE_PROVIDER;
130 req.ID.toi_id = IP_MIB_STATS_ID;
131 req.ID.toi_entity = *ent;
132
133 status = DeviceIoControl( tcpFile,
134 IOCTL_TCP_QUERY_INFORMATION_EX,
135 &req,
136 sizeof(req),
137 entry,
138 sizeof(*entry),
139 &returnSize,
140 NULL );
141
142 DPRINT("TdiGetMibForIpEntity() => {\n"
143 " ipsi_forwarding ............ %d\n"
144 " ipsi_defaultttl ............ %d\n"
145 " ipsi_inreceives ............ %d\n"
146 " ipsi_indelivers ............ %d\n"
147 " ipsi_outrequests ........... %d\n"
148 " ipsi_routingdiscards ....... %d\n"
149 " ipsi_outdiscards ........... %d\n"
150 " ipsi_outnoroutes ........... %d\n"
151 " ipsi_numif ................. %d\n"
152 " ipsi_numaddr ............... %d\n"
153 " ipsi_numroutes ............. %d\n"
154 "} status %08x\n",
155 entry->ipsi_forwarding,
156 entry->ipsi_defaultttl,
157 entry->ipsi_inreceives,
158 entry->ipsi_indelivers,
159 entry->ipsi_outrequests,
160 entry->ipsi_routingdiscards,
161 entry->ipsi_outdiscards,
162 entry->ipsi_outnoroutes,
163 entry->ipsi_numif,
164 entry->ipsi_numaddr,
165 entry->ipsi_numroutes,
166 status);
167
168 return status;
169 }
170
171 NTSTATUS tdiGetRoutesForIpEntity
172 ( HANDLE tcpFile, TDIEntityID *ent, int numRoutes, IPRouteEntry *routes ) {
173 TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT;
174 NTSTATUS status = STATUS_SUCCESS;
175 DWORD returnSize;
176
177 DPRINT("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
178 (DWORD)tcpFile, ent->tei_instance);
179
180 req.ID.toi_class = INFO_CLASS_PROTOCOL;
181 req.ID.toi_type = INFO_TYPE_PROVIDER;
182 req.ID.toi_id = IP_MIB_ROUTETABLE_ENTRY_ID;
183 req.ID.toi_entity = *ent;
184
185 status = DeviceIoControl( tcpFile,
186 IOCTL_TCP_QUERY_INFORMATION_EX,
187 &req,
188 sizeof(req),
189 routes,
190 sizeof(*routes) * numRoutes,
191 &returnSize,
192 NULL );
193
194 return status;
195 }
196
197 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
198 {
199 if (!name)
200 return ERROR_INVALID_PARAMETER;
201 if (!entry)
202 return ERROR_INVALID_PARAMETER;
203
204 return NO_ERROR;
205 }
206
207 DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry)
208 {
209 return ERROR_INVALID_PARAMETER;
210 }
211
212 DWORD getICMPStats(MIB_ICMP *stats)
213 {
214 FILE *fp;
215
216 if (!stats)
217 return ERROR_INVALID_PARAMETER;
218
219 memset(stats, 0, sizeof(MIB_ICMP));
220 /* get most of these stats from /proc/net/snmp, no error if can't */
221 fp = fopen("/proc/net/snmp", "r");
222 if (fp) {
223 const char hdr[] = "Icmp:";
224 char buf[512] = { 0 }, *ptr;
225
226 do {
227 ptr = fgets(buf, sizeof(buf), fp);
228 } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1));
229 if (ptr) {
230 /* last line was a header, get another */
231 ptr = fgets(buf, sizeof(buf), fp);
232 if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) {
233 char *endPtr;
234
235 ptr += sizeof(hdr);
236 if (ptr && *ptr) {
237 stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10);
238 ptr = endPtr;
239 }
240 if (ptr && *ptr) {
241 stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10);
242 ptr = endPtr;
243 }
244 if (ptr && *ptr) {
245 stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
246 ptr = endPtr;
247 }
248 if (ptr && *ptr) {
249 stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
250 ptr = endPtr;
251 }
252 if (ptr && *ptr) {
253 stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
254 ptr = endPtr;
255 }
256 if (ptr && *ptr) {
257 stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
258 ptr = endPtr;
259 }
260 if (ptr && *ptr) {
261 stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10);
262 ptr = endPtr;
263 }
264 if (ptr && *ptr) {
265 stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
266 ptr = endPtr;
267 }
268 if (ptr && *ptr) {
269 stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
270 ptr = endPtr;
271 }
272 if (ptr && *ptr) {
273 stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
274 ptr = endPtr;
275 }
276 if (ptr && *ptr) {
277 stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
278 ptr = endPtr;
279 }
280 if (ptr && *ptr) {
281 stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
282 ptr = endPtr;
283 }
284 if (ptr && *ptr) {
285 stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10);
286 ptr = endPtr;
287 }
288 if (ptr && *ptr) {
289 stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10);
290 ptr = endPtr;
291 }
292 if (ptr && *ptr) {
293 stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10);
294 ptr = endPtr;
295 }
296 if (ptr && *ptr) {
297 stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10);
298 ptr = endPtr;
299 }
300 if (ptr && *ptr) {
301 stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10);
302 ptr = endPtr;
303 }
304 if (ptr && *ptr) {
305 stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10);
306 ptr = endPtr;
307 }
308 if (ptr && *ptr) {
309 stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10);
310 ptr = endPtr;
311 }
312 if (ptr && *ptr) {
313 stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10);
314 ptr = endPtr;
315 }
316 if (ptr && *ptr) {
317 stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10);
318 ptr = endPtr;
319 }
320 if (ptr && *ptr) {
321 stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10);
322 ptr = endPtr;
323 }
324 if (ptr && *ptr) {
325 stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10);
326 ptr = endPtr;
327 }
328 if (ptr && *ptr) {
329 stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10);
330 ptr = endPtr;
331 }
332 }
333 }
334 fclose(fp);
335 }
336 return NO_ERROR;
337 }
338
339 DWORD getIPStats(PMIB_IPSTATS stats, DWORD family)
340 {
341 if (!stats)
342 return ERROR_INVALID_PARAMETER;
343 return NO_ERROR;
344 }
345
346 DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family)
347 {
348 if (!stats)
349 return ERROR_INVALID_PARAMETER;
350 return NO_ERROR;
351 }
352
353 DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family)
354 {
355 if (!stats)
356 return ERROR_INVALID_PARAMETER;
357 return NO_ERROR;
358 }
359
360 static DWORD getNumWithOneHeader(const char *filename)
361 {
362 return 0;
363 }
364
365 DWORD getNumRoutes(void)
366 {
367 DWORD numEntities, numRoutes = 0;
368 TDIEntityID *entitySet;
369 HANDLE tcpFile;
370 int i;
371 NTSTATUS status;
372
373 TRACE("called.\n");
374
375 status = openTcpFile( &tcpFile );
376
377 if( !NT_SUCCESS(status) ) {
378 TRACE("failure: %08x\n", (int)status );
379 return 0;
380 }
381
382 status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities );
383
384 if( !NT_SUCCESS(status) ) {
385 TRACE("failure: %08x\n", (int)status );
386 return 0;
387 }
388
389 for( i = 0; i < numEntities; i++ ) {
390 if( isIpEntity( tcpFile, &entitySet[i] ) ) {
391 IPSNMPInfo isnmp;
392 memset( &isnmp, 0, sizeof( isnmp ) );
393 status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp );
394 if( !NT_SUCCESS(status) ) {
395 tdiFreeThingSet( entitySet );
396 return status;
397 }
398 numRoutes += isnmp.ipsi_numroutes;
399 }
400 }
401
402 TRACE("numRoutes: %d\n", (int)numRoutes);
403
404 closeTcpFile( tcpFile );
405
406 return numRoutes;
407 }
408
409 VOID HexDump( PCHAR Data, DWORD Len ) {
410 int i;
411
412 for( i = 0; i < Len; i++ ) {
413 if( !(i & 0xf) ) {
414 if( i ) fprintf(stderr,"\n");
415 fprintf(stderr,"%08x:", i);
416 }
417 fprintf( stderr, " %02x", Data[i] & 0xff );
418 }
419 fprintf(stderr,"\n");
420 }
421
422 RouteTable *getRouteTable(void)
423 {
424 RouteTable *out_route_table;
425 DWORD numRoutes = getNumRoutes(), routesAdded = 0;
426 IPSNMPInfo snmpInfo;
427 TDIEntityID ent;
428 HANDLE tcpFile;
429 NTSTATUS status = openTcpFile( &tcpFile );
430 int i;
431
432 if( !NT_SUCCESS(status) )
433 return 0;
434
435 out_route_table = HeapAlloc( GetProcessHeap(), 0,
436 sizeof(RouteTable) +
437 (sizeof(RouteEntry) * (numRoutes - 1)) );
438
439 out_route_table->numRoutes = numRoutes;
440
441 for( i = 0; routesAdded < numRoutes; i++ ) {
442 int j;
443 IPRouteEntry *route_set;
444
445 getNthIpEntity( tcpFile, i, &ent );
446 tdiGetMibForIpEntity( tcpFile, &ent, &snmpInfo );
447 route_set = HeapAlloc( GetProcessHeap(), 0,
448 sizeof( IPRouteEntry ) *
449 snmpInfo.ipsi_numroutes );
450
451 DPRINT( "%d routes in instance %d\n", snmpInfo.ipsi_numroutes, i );
452
453 if( !route_set ) {
454 closeTcpFile( tcpFile );
455 HeapFree( GetProcessHeap(), 0, out_route_table );
456 return 0;
457 }
458
459 tdiGetRoutesForIpEntity( tcpFile, &ent, numRoutes, route_set );
460
461 DPRINT("Route set returned\n");
462 #if 0
463 HexDump( route_set,
464 sizeof( IPRouteEntry ) *
465 snmpInfo.ipsi_numroutes );
466 #endif
467
468 for( j = 0; j < snmpInfo.ipsi_numroutes; j++ ) {
469 int routeNum = j + routesAdded;
470 out_route_table->routes[routeNum].dest =
471 route_set[j].ire_dest;
472 out_route_table->routes[routeNum].mask =
473 route_set[j].ire_mask;
474 out_route_table->routes[routeNum].gateway =
475 route_set[j].ire_gw;
476 out_route_table->routes[routeNum].ifIndex =
477 route_set[j].ire_index;
478 out_route_table->routes[routeNum].metric =
479 route_set[j].ire_metric;
480 }
481
482 routesAdded += snmpInfo.ipsi_numroutes;
483 }
484
485 return out_route_table;
486 }
487
488 DWORD getNumArpEntries(void)
489 {
490 return getNumWithOneHeader("/proc/net/arp");
491 }
492
493 PMIB_IPNETTABLE getArpTable(void)
494 {
495 return 0;
496 }
497
498 DWORD getNumUdpEntries(void)
499 {
500 return getNumWithOneHeader("/proc/net/udp");
501 }
502
503 PMIB_UDPTABLE getUdpTable(void)
504 {
505 DWORD numEntries = getNumUdpEntries();
506 PMIB_UDPTABLE ret;
507
508 ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) +
509 (numEntries - 1) * sizeof(MIB_UDPROW));
510 if (ret) {
511 FILE *fp;
512
513 /* get from /proc/net/udp, no error if can't */
514 fp = fopen("/proc/net/udp", "r");
515 if (fp) {
516 char buf[512] = { 0 }, *ptr;
517
518 /* skip header line */
519 ptr = fgets(buf, sizeof(buf), fp);
520 while (ptr && ret->dwNumEntries < numEntries) {
521 ptr = fgets(buf, sizeof(buf), fp);
522 if (ptr) {
523 char *endPtr;
524
525 if (ptr && *ptr) {
526 strtoul(ptr, &endPtr, 16); /* skip */
527 ptr = endPtr;
528 }
529 if (ptr && *ptr) {
530 ptr++;
531 ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr,
532 16);
533 ptr = endPtr;
534 }
535 if (ptr && *ptr) {
536 ptr++;
537 ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr,
538 16);
539 ptr = endPtr;
540 }
541 ret->dwNumEntries++;
542 }
543 }
544 fclose(fp);
545 }
546 }
547 return ret;
548 }
549
550 DWORD getNumTcpEntries(void)
551 {
552 return getNumWithOneHeader("/proc/net/tcp");
553 }
554
555 PMIB_TCPTABLE getTcpTable(void)
556 {
557 return 0;
558 }