1 /* Copyright (C) 2003 Juan Lang
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.
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.
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
17 * This file implements statistics getting using the /proc filesystem exported
18 * by Linux, and maybe other OSes.
21 #include "ipprivate.h"
25 #ifndef TCPS_ESTABLISHED
26 # define TCPS_ESTABLISHED TCP_ESTABLISHED
29 # define TCPS_SYN_SENT TCP_SYN_SENT
31 #ifndef TCPS_SYN_RECEIVED
32 # define TCPS_SYN_RECEIVED TCP_SYN_RECV
34 #ifndef TCPS_FIN_WAIT_1
35 # define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1
37 #ifndef TCPS_FIN_WAIT_2
38 # define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2
40 #ifndef TCPS_TIME_WAIT
41 # define TCPS_TIME_WAIT TCP_TIME_WAIT
44 # define TCPS_CLOSED TCP_CLOSE
46 #ifndef TCPS_CLOSE_WAIT
47 # define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT
50 # define TCPS_LAST_ACK TCP_LAST_ACK
53 # define TCPS_LISTEN TCP_LISTEN
56 # define TCPS_CLOSING TCP_CLOSING
59 BOOL
isIpEntity( HANDLE tcpFile
, TDIEntityID
*ent
) {
60 DWORD entityType
, returnedLen
;
62 TCP_REQUEST_QUERY_INFORMATION_EX req
;
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
;
72 IOCTL_TCP_QUERY_INFORMATION_EX
,
80 DPRINT("Ent: %04x:d -> %04x\n",
81 ent
->tei_entity
, ent
->tei_instance
, entityType
);
83 return NT_SUCCESS(status
) && entityType
== CL_NL_IP
;
86 NTSTATUS
getNthIpEntity( HANDLE tcpFile
, DWORD index
, TDIEntityID
*ent
) {
87 DWORD numEntities
= 0;
89 TDIEntityID
*entitySet
= 0;
90 NTSTATUS status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
93 if( !NT_SUCCESS(status
) )
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;
104 DPRINT("Index %d is entity #%d - %04x:%08x\n", index
, i
,
105 entitySet
[i
].tei_entity
, entitySet
[i
].tei_instance
);
107 if( numRoutes
== index
&& i
< numEntities
) {
108 memcpy( ent
, &entitySet
[i
], sizeof(*ent
) );
109 tdiFreeThingSet( entitySet
);
110 return STATUS_SUCCESS
;
112 tdiFreeThingSet( entitySet
);
113 return STATUS_UNSUCCESSFUL
;
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
;
123 memset( entry
, 0, sizeof( *entry
) );
125 DPRINT("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n",
126 (DWORD
)tcpFile
, ent
->tei_instance
);
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
;
133 status
= DeviceIoControl( tcpFile
,
134 IOCTL_TCP_QUERY_INFORMATION_EX
,
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"
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
,
165 entry
->ipsi_numroutes
,
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
;
177 DPRINT("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n",
178 (DWORD
)tcpFile
, ent
->tei_instance
);
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
;
185 status
= DeviceIoControl( tcpFile
,
186 IOCTL_TCP_QUERY_INFORMATION_EX
,
190 sizeof(*routes
) * numRoutes
,
197 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
200 return ERROR_INVALID_PARAMETER
;
202 return ERROR_INVALID_PARAMETER
;
207 DWORD
getInterfaceStatsByIndex(DWORD index
, PMIB_IFROW entry
)
209 return ERROR_INVALID_PARAMETER
;
212 DWORD
getICMPStats(MIB_ICMP
*stats
)
217 return ERROR_INVALID_PARAMETER
;
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");
223 const char hdr
[] = "Icmp:";
224 char buf
[512] = { 0 }, *ptr
;
227 ptr
= fgets(buf
, sizeof(buf
), fp
);
228 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
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) {
237 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
241 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
245 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
249 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
253 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
257 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
261 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
265 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
269 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
273 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
277 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
281 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
285 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
289 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
293 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
297 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
301 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
305 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
309 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
313 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
317 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
321 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
325 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
329 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
339 DWORD
getIPStats(PMIB_IPSTATS stats
, DWORD family
)
342 return ERROR_INVALID_PARAMETER
;
346 DWORD
getTCPStats(MIB_TCPSTATS
*stats
, DWORD family
)
349 return ERROR_INVALID_PARAMETER
;
353 DWORD
getUDPStats(MIB_UDPSTATS
*stats
, DWORD family
)
356 return ERROR_INVALID_PARAMETER
;
360 static DWORD
getNumWithOneHeader(const char *filename
)
365 DWORD
getNumRoutes(void)
367 DWORD numEntities
, numRoutes
= 0;
368 TDIEntityID
*entitySet
;
375 status
= openTcpFile( &tcpFile
);
377 if( !NT_SUCCESS(status
) ) {
378 TRACE("failure: %08x\n", (int)status
);
382 status
= tdiGetEntityIDSet( tcpFile
, &entitySet
, &numEntities
);
384 if( !NT_SUCCESS(status
) ) {
385 TRACE("failure: %08x\n", (int)status
);
389 for( i
= 0; i
< numEntities
; i
++ ) {
390 if( isIpEntity( tcpFile
, &entitySet
[i
] ) ) {
392 memset( &isnmp
, 0, sizeof( isnmp
) );
393 status
= tdiGetMibForIpEntity( tcpFile
, &entitySet
[i
], &isnmp
);
394 if( !NT_SUCCESS(status
) ) {
395 tdiFreeThingSet( entitySet
);
398 numRoutes
+= isnmp
.ipsi_numroutes
;
402 TRACE("numRoutes: %d\n", (int)numRoutes
);
404 closeTcpFile( tcpFile
);
409 VOID
HexDump( PCHAR Data
, DWORD Len
) {
412 for( i
= 0; i
< Len
; i
++ ) {
414 if( i
) fprintf(stderr
,"\n");
415 fprintf(stderr
,"%08x:", i
);
417 fprintf( stderr
, " %02x", Data
[i
] & 0xff );
419 fprintf(stderr
,"\n");
422 RouteTable
*getRouteTable(void)
424 RouteTable
*out_route_table
;
425 DWORD numRoutes
= getNumRoutes(), routesAdded
= 0;
429 NTSTATUS status
= openTcpFile( &tcpFile
);
432 if( !NT_SUCCESS(status
) )
435 out_route_table
= HeapAlloc( GetProcessHeap(), 0,
437 (sizeof(RouteEntry
) * (numRoutes
- 1)) );
439 out_route_table
->numRoutes
= numRoutes
;
441 for( i
= 0; routesAdded
< numRoutes
; i
++ ) {
443 IPRouteEntry
*route_set
;
445 getNthIpEntity( tcpFile
, i
, &ent
);
446 tdiGetMibForIpEntity( tcpFile
, &ent
, &snmpInfo
);
447 route_set
= HeapAlloc( GetProcessHeap(), 0,
448 sizeof( IPRouteEntry
) *
449 snmpInfo
.ipsi_numroutes
);
451 DPRINT( "%d routes in instance %d\n", snmpInfo
.ipsi_numroutes
, i
);
454 closeTcpFile( tcpFile
);
455 HeapFree( GetProcessHeap(), 0, out_route_table
);
459 tdiGetRoutesForIpEntity( tcpFile
, &ent
, numRoutes
, route_set
);
461 DPRINT("Route set returned\n");
464 sizeof( IPRouteEntry
) *
465 snmpInfo
.ipsi_numroutes
);
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
=
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
;
482 routesAdded
+= snmpInfo
.ipsi_numroutes
;
485 return out_route_table
;
488 DWORD
getNumArpEntries(void)
490 return getNumWithOneHeader("/proc/net/arp");
493 PMIB_IPNETTABLE
getArpTable(void)
498 DWORD
getNumUdpEntries(void)
500 return getNumWithOneHeader("/proc/net/udp");
503 PMIB_UDPTABLE
getUdpTable(void)
505 DWORD numEntries
= getNumUdpEntries();
508 ret
= (PMIB_UDPTABLE
)calloc(1, sizeof(MIB_UDPTABLE
) +
509 (numEntries
- 1) * sizeof(MIB_UDPROW
));
513 /* get from /proc/net/udp, no error if can't */
514 fp
= fopen("/proc/net/udp", "r");
516 char buf
[512] = { 0 }, *ptr
;
518 /* skip header line */
519 ptr
= fgets(buf
, sizeof(buf
), fp
);
520 while (ptr
&& ret
->dwNumEntries
< numEntries
) {
521 ptr
= fgets(buf
, sizeof(buf
), fp
);
526 strtoul(ptr
, &endPtr
, 16); /* skip */
531 ret
->table
[ret
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
, &endPtr
,
537 ret
->table
[ret
->dwNumEntries
].dwLocalPort
= strtoul(ptr
, &endPtr
,
550 DWORD
getNumTcpEntries(void)
552 return getNumWithOneHeader("/proc/net/tcp");
555 PMIB_TCPTABLE
getTcpTable(void)