1 /* Copyright (C) 2003,2006 Juan Lang
2 * Copyright (C) 2007 TransGaming Technologies Inc.
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.
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.
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
18 * This file implements statistics getting using the /proc filesystem exported
19 * by Linux, and maybe other OSes.
23 #include "wine/port.h"
24 #include "wine/debug.h"
30 #include <sys/types.h>
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
37 #ifdef HAVE_SYS_SOCKETVAR_H
38 #include <sys/socketvar.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
49 #ifdef HAVE_NET_IF_DL_H
50 #include <net/if_dl.h>
52 #ifdef HAVE_NET_IF_TYPES_H
53 #include <net/if_types.h>
55 #ifdef HAVE_NET_ROUTE_H
56 #include <net/route.h>
58 #ifdef HAVE_NET_IF_ARP_H
59 #include <net/if_arp.h>
61 #ifdef HAVE_NETINET_IF_ETHER_H
62 #include <netinet/if_ether.h>
64 #ifdef HAVE_NETINET_IP_H
65 #include <netinet/ip.h>
67 #ifdef HAVE_NETINET_TCP_H
68 #include <netinet/tcp.h>
70 #ifdef HAVE_NETINET_TCP_FSM_H
71 #include <netinet/tcp_fsm.h>
73 #ifdef HAVE_NETINET_IN_PCB_H
74 #include <netinet/in_pcb.h>
76 #ifdef HAVE_NETINET_TCP_VAR_H
77 #include <netinet/tcp_var.h>
79 #ifdef HAVE_NETINET_TCP_TIMER_H
80 #include <netinet/tcp_timer.h>
82 #ifdef HAVE_NETINET_IP_ICMP_H
83 #include <netinet/ip_icmp.h>
85 #ifdef HAVE_NETINET_ICMP_VAR_H
86 #include <netinet/icmp_var.h>
88 #ifdef HAVE_NETINET_IP_VAR_H
89 #include <netinet/ip_var.h>
91 #ifdef HAVE_NETINET_UDP_H
92 #include <netinet/udp.h>
94 #ifdef HAVE_NETINET_UDP_VAR_H
95 #include <netinet/udp_var.h>
98 #ifdef HAVE_SYS_SYSCTL_H
99 #include <sys/sysctl.h>
104 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
107 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
112 #include "iprtrmib.h"
116 #ifndef HAVE_NETINET_TCP_FSM_H
117 #define TCPS_ESTABLISHED 1
118 #define TCPS_SYN_SENT 2
119 #define TCPS_SYN_RECEIVED 3
120 #define TCPS_FIN_WAIT_1 4
121 #define TCPS_FIN_WAIT_2 5
122 #define TCPS_TIME_WAIT 6
123 #define TCPS_CLOSED 7
124 #define TCPS_CLOSE_WAIT 8
125 #define TCPS_LAST_ACK 9
126 #define TCPS_LISTEN 10
127 #define TCPS_CLOSING 11
130 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
132 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
134 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
135 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
136 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
140 struct if_msghdr
*ifm
;
141 struct if_data ifdata
;
143 return ERROR_INVALID_PARAMETER
;
145 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
147 ERR ("failed to get size of iflist\n");
148 return ERROR_NOT_SUPPORTED
;
150 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
151 if (!buf
) return ERROR_NOT_SUPPORTED
;
152 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
154 ERR ("failed to get iflist\n");
155 HeapFree (GetProcessHeap (), 0, buf
);
156 return ERROR_NOT_SUPPORTED
;
159 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
161 ifm
= (struct if_msghdr
*) buf
;
162 if(ifm
->ifm_type
== RTM_IFINFO
&& ifm
->ifm_data
.ifi_type
== IFT_ETHER
)
164 ifdata
= ifm
->ifm_data
;
165 entry
->dwMtu
= ifdata
.ifi_mtu
;
166 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
167 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
168 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
169 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
170 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
171 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
172 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
173 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
174 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
175 HeapFree (GetProcessHeap (), 0, buf
);
179 HeapFree (GetProcessHeap (), 0, buf
);
180 return ERROR_NOT_SUPPORTED
;
182 /* get interface stats from /proc/net/dev, no error if can't
183 no inUnknownProtos, outNUcastPkts, outQLen */
187 return ERROR_INVALID_PARAMETER
;
188 fp
= fopen("/proc/net/dev", "r");
190 char buf
[512] = { 0 }, *ptr
;
191 int nameLen
= strlen(name
), nameFound
= 0;
194 ptr
= fgets(buf
, sizeof(buf
), fp
);
195 while (ptr
&& !nameFound
) {
196 while (*ptr
&& isspace(*ptr
))
198 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
201 ptr
= fgets(buf
, sizeof(buf
), fp
);
208 entry
->dwInOctets
= strtoul(ptr
, &endPtr
, 10);
212 entry
->dwInUcastPkts
= strtoul(ptr
, &endPtr
, 10);
216 entry
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
220 entry
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
224 strtoul(ptr
, &endPtr
, 10); /* skip */
228 strtoul(ptr
, &endPtr
, 10); /* skip */
232 strtoul(ptr
, &endPtr
, 10); /* skip */
236 entry
->dwInNUcastPkts
= strtoul(ptr
, &endPtr
, 10);
240 entry
->dwOutOctets
= strtoul(ptr
, &endPtr
, 10);
244 entry
->dwOutUcastPkts
= strtoul(ptr
, &endPtr
, 10);
248 entry
->dwOutErrors
= strtoul(ptr
, &endPtr
, 10);
252 entry
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
260 ERR ("unimplemented!\n");
261 return ERROR_NOT_SUPPORTED
;
268 DWORD
getICMPStats(MIB_ICMP
*stats
)
270 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
271 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
272 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
274 struct icmpstat icmp_stat
;
278 return ERROR_INVALID_PARAMETER
;
280 needed
= sizeof(icmp_stat
);
281 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) == -1)
283 ERR ("failed to get icmpstat\n");
284 return ERROR_NOT_SUPPORTED
;
289 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
290 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
291 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
293 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
295 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
296 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
297 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
298 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
299 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
300 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
301 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
302 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
303 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
304 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
305 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
309 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
310 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
311 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
313 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
315 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
316 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
317 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
318 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
319 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
320 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
321 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
322 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
323 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
324 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
325 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
332 return ERROR_INVALID_PARAMETER
;
334 memset(stats
, 0, sizeof(MIB_ICMP
));
335 /* get most of these stats from /proc/net/snmp, no error if can't */
336 fp
= fopen("/proc/net/snmp", "r");
338 static const char hdr
[] = "Icmp:";
339 char buf
[512] = { 0 }, *ptr
;
342 ptr
= fgets(buf
, sizeof(buf
), fp
);
343 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
345 /* last line was a header, get another */
346 ptr
= fgets(buf
, sizeof(buf
), fp
);
347 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
352 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
356 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
360 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
364 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
368 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
372 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
376 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
380 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
384 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
388 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
392 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
396 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
400 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
404 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
408 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
412 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
416 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
420 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
424 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
428 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
432 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
436 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
440 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
444 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
453 ERR ("unimplemented!\n");
454 return ERROR_NOT_SUPPORTED
;
461 DWORD
getIPStats(PMIB_IPSTATS stats
)
463 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
464 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
465 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
466 int ip_ttl
, ip_forwarding
;
467 struct ipstat ip_stat
;
471 return ERROR_INVALID_PARAMETER
;
473 needed
= sizeof(ip_stat
);
474 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
476 ERR ("failed to get ipstat\n");
477 return ERROR_NOT_SUPPORTED
;
480 needed
= sizeof(ip_ttl
);
481 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
483 ERR ("failed to get ip Default TTL\n");
484 return ERROR_NOT_SUPPORTED
;
487 needed
= sizeof(ip_forwarding
);
488 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
490 ERR ("failed to get ip forwarding\n");
491 return ERROR_NOT_SUPPORTED
;
494 stats
->dwForwarding
= ip_forwarding
;
495 stats
->dwDefaultTTL
= ip_ttl
;
496 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
497 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
498 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
499 stats
->dwInReceives
= ip_stat
.ips_total
;
500 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
501 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
502 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
503 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
504 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
505 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
506 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
507 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
508 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
509 stats
->dwOutRequests
= ip_stat
.ips_localout
;
510 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
517 return ERROR_INVALID_PARAMETER
;
519 memset(stats
, 0, sizeof(MIB_IPSTATS
));
520 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
521 stats
->dwNumRoutes
= getNumRoutes();
523 /* get most of these stats from /proc/net/snmp, no error if can't */
524 fp
= fopen("/proc/net/snmp", "r");
526 static const char hdr
[] = "Ip:";
527 char buf
[512] = { 0 }, *ptr
;
530 ptr
= fgets(buf
, sizeof(buf
), fp
);
531 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
533 /* last line was a header, get another */
534 ptr
= fgets(buf
, sizeof(buf
), fp
);
535 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
540 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
544 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
548 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
552 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
556 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
560 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
564 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
568 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
572 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
576 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
580 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
584 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
588 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
592 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
596 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
600 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
604 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
608 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
612 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
615 /* hmm, no routingDiscards */
622 ERR ("unimplemented!\n");
623 return ERROR_NOT_SUPPORTED
;
630 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
632 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
633 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
635 #define TCPTV_REXMTMAX 128
637 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
638 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
640 struct tcpstat tcp_stat
;
644 return ERROR_INVALID_PARAMETER
;
645 needed
= sizeof(tcp_stat
);
647 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) == -1)
649 ERR ("failed to get tcpstat\n");
650 return ERROR_NOT_SUPPORTED
;
653 stats
->dwRtoAlgorithm
= MIB_TCP_RTO_VANJ
;
654 stats
->dwRtoMin
= TCPTV_MIN
;
655 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
656 stats
->dwMaxConn
= -1;
657 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
658 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
659 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
660 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
661 stats
->dwCurrEstab
= 0;
662 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
663 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
664 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
665 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
666 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
667 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
675 return ERROR_INVALID_PARAMETER
;
677 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
679 /* get from /proc/net/snmp, no error if can't */
680 fp
= fopen("/proc/net/snmp", "r");
682 static const char hdr
[] = "Tcp:";
683 char buf
[512] = { 0 }, *ptr
;
687 ptr
= fgets(buf
, sizeof(buf
), fp
);
688 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
690 /* last line was a header, get another */
691 ptr
= fgets(buf
, sizeof(buf
), fp
);
692 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
697 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
701 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
705 stats
->dwRtoMax
= strtoul(ptr
, &endPtr
, 10);
709 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
713 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
717 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
721 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
725 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
729 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
733 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
737 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
741 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
745 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
749 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
752 stats
->dwNumConns
= getNumTcpEntries();
759 ERR ("unimplemented!\n");
760 return ERROR_NOT_SUPPORTED
;
767 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
769 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
770 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
771 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
772 struct udpstat udp_stat
;
775 return ERROR_INVALID_PARAMETER
;
777 needed
= sizeof(udp_stat
);
779 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) == -1)
781 ERR ("failed to get udpstat\n");
782 return ERROR_NOT_SUPPORTED
;
785 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
786 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
787 stats
->dwNoPorts
= udp_stat
.udps_noport
;
788 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
789 stats
->dwNumAddrs
= getNumUdpEntries();
796 return ERROR_INVALID_PARAMETER
;
798 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
800 /* get from /proc/net/snmp, no error if can't */
801 fp
= fopen("/proc/net/snmp", "r");
803 static const char hdr
[] = "Udp:";
804 char buf
[512] = { 0 }, *ptr
;
808 ptr
= fgets(buf
, sizeof(buf
), fp
);
809 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
811 /* last line was a header, get another */
812 ptr
= fgets(buf
, sizeof(buf
), fp
);
813 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
818 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
822 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
826 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
830 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
834 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
843 ERR ("unimplemented!\n");
844 return ERROR_NOT_SUPPORTED
;
851 static DWORD
getNumWithOneHeader(const char *filename
)
853 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
856 struct xinpgen
*pXIG
, *pOrigXIG
;
858 DWORD NumEntries
= 0;
860 if (!strcmp (filename
, "net.inet.tcp.pcblist"))
861 Protocol
= IPPROTO_TCP
;
862 else if (!strcmp (filename
, "net.inet.udp.pcblist"))
863 Protocol
= IPPROTO_UDP
;
866 ERR ("Unsupported mib '%s', needs protocol mapping\n",
871 if (sysctlbyname (filename
, NULL
, &Len
, NULL
, 0) < 0)
873 WARN ("Unable to read '%s' via sysctlbyname\n", filename
);
877 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
880 ERR ("Out of memory!\n");
884 if (sysctlbyname (filename
, Buf
, &Len
, NULL
, 0) < 0)
886 ERR ("Failure to read '%s' via sysctlbyname!\n", filename
);
887 HeapFree (GetProcessHeap (), 0, Buf
);
891 /* Might be nothing here; first entry is just a header it seems */
892 if (Len
<= sizeof (struct xinpgen
))
894 HeapFree (GetProcessHeap (), 0, Buf
);
898 pOrigXIG
= (struct xinpgen
*)Buf
;
901 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
902 pXIG
->xig_len
> sizeof (struct xinpgen
);
903 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
905 struct tcpcb
*pTCPData
= NULL
;
906 struct inpcb
*pINData
;
907 struct xsocket
*pSockData
;
909 if (Protocol
== IPPROTO_TCP
)
911 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
912 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
913 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
917 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
918 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
921 /* Ignore sockets for other protocols */
922 if (pSockData
->xso_protocol
!= Protocol
)
925 /* Ignore PCBs that were freed while generating the data */
926 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
929 /* we're only interested in IPv4 addresses */
930 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
931 (pINData
->inp_vflag
& INP_IPV6
))
934 /* If all 0's, skip it */
935 if (!pINData
->inp_laddr
.s_addr
&&
936 !pINData
->inp_lport
&&
937 !pINData
->inp_faddr
.s_addr
&&
944 HeapFree (GetProcessHeap (), 0, Buf
);
950 fp
= fopen(filename
, "r");
952 char buf
[512] = { 0 }, *ptr
;
955 ptr
= fgets(buf
, sizeof(buf
), fp
);
958 ptr
= fgets(buf
, sizeof(buf
), fp
);
966 ERR ("Unable to open '%s' to count entries!\n", filename
);
972 DWORD
getNumRoutes(void)
974 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
975 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
977 char *buf
, *lim
, *next
;
978 struct rt_msghdr
*rtm
;
979 DWORD RouteCount
= 0;
981 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
983 ERR ("sysctl 1 failed!\n");
987 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
990 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
992 ERR ("sysctl 2 failed!\n");
993 HeapFree (GetProcessHeap (), 0, buf
);
998 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1000 rtm
= (struct rt_msghdr
*)next
;
1002 if (rtm
->rtm_type
!= RTM_GET
)
1004 WARN ("Got unexpected message type 0x%x!\n",
1009 /* Ignore all entries except for gateway routes which aren't
1011 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) || (rtm
->rtm_flags
& RTF_MULTICAST
))
1017 HeapFree (GetProcessHeap (), 0, buf
);
1020 return getNumWithOneHeader("/proc/net/route");
1024 DWORD
getRouteTable(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, HANDLE heap
,
1029 if (!ppIpForwardTable
)
1030 ret
= ERROR_INVALID_PARAMETER
;
1032 DWORD numRoutes
= getNumRoutes();
1033 DWORD size
= sizeof(MIB_IPFORWARDTABLE
);
1034 PMIB_IPFORWARDTABLE table
;
1037 size
+= (numRoutes
- 1) * sizeof(MIB_IPFORWARDROW
);
1038 table
= HeapAlloc(heap
, flags
, size
);
1040 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1041 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1043 char *buf
, *lim
, *next
, *addrPtr
;
1044 struct rt_msghdr
*rtm
;
1046 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1048 ERR ("sysctl 1 failed!\n");
1049 HeapFree (GetProcessHeap (), 0, table
);
1053 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1056 HeapFree (GetProcessHeap (), 0, table
);
1057 return ERROR_OUTOFMEMORY
;
1060 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1062 ERR ("sysctl 2 failed!\n");
1063 HeapFree (GetProcessHeap (), 0, table
);
1064 HeapFree (GetProcessHeap (), 0, buf
);
1068 *ppIpForwardTable
= table
;
1069 table
->dwNumEntries
= 0;
1072 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1076 rtm
= (struct rt_msghdr
*)next
;
1078 if (rtm
->rtm_type
!= RTM_GET
)
1080 WARN ("Got unexpected message type 0x%x!\n",
1085 /* Ignore all entries except for gateway routes which aren't
1087 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1088 (rtm
->rtm_flags
& RTF_MULTICAST
))
1091 memset (&table
->table
[table
->dwNumEntries
], 0,
1092 sizeof (MIB_IPFORWARDROW
));
1093 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= rtm
->rtm_index
;
1094 table
->table
[table
->dwNumEntries
].dwForwardType
=
1095 MIB_IPROUTE_TYPE_INDIRECT
;
1096 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1097 rtm
->rtm_rmx
.rmx_hopcount
;
1098 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1101 addrPtr
= (char *)(rtm
+ 1);
1103 for (i
= 1; i
; i
<<= 1)
1105 struct sockaddr
*sa
;
1108 if (!(i
& rtm
->rtm_addrs
))
1111 sa
= (struct sockaddr
*)addrPtr
;
1112 ADVANCE (addrPtr
, sa
);
1114 /* default routes are encoded by length-zero sockaddr */
1115 if (sa
->sa_len
== 0)
1117 else if (sa
->sa_family
!= AF_INET
)
1119 WARN ("Received unsupported sockaddr family 0x%x\n",
1125 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1127 addr
= sin
->sin_addr
.s_addr
;
1133 table
->table
[table
->dwNumEntries
].dwForwardDest
= addr
;
1137 table
->table
[table
->dwNumEntries
].dwForwardNextHop
= addr
;
1141 table
->table
[table
->dwNumEntries
].dwForwardMask
= addr
;
1145 WARN ("Unexpected address type 0x%x\n", i
);
1149 table
->dwNumEntries
++;
1152 HeapFree (GetProcessHeap (), 0, buf
);
1158 *ppIpForwardTable
= table
;
1159 table
->dwNumEntries
= 0;
1160 /* get from /proc/net/route, no error if can't */
1161 fp
= fopen("/proc/net/route", "r");
1163 char buf
[512] = { 0 }, *ptr
;
1165 /* skip header line */
1166 ptr
= fgets(buf
, sizeof(buf
), fp
);
1167 while (ptr
&& table
->dwNumEntries
< numRoutes
) {
1168 memset(&table
->table
[table
->dwNumEntries
], 0,
1169 sizeof(MIB_IPFORWARDROW
));
1170 ptr
= fgets(buf
, sizeof(buf
), fp
);
1174 while (!isspace(*ptr
))
1178 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
1181 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= index
;
1183 table
->table
[table
->dwNumEntries
].dwForwardDest
=
1184 strtoul(ptr
, &endPtr
, 16);
1188 table
->table
[table
->dwNumEntries
].dwForwardNextHop
=
1189 strtoul(ptr
, &endPtr
, 16);
1193 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1195 if (!(flags
& RTF_UP
))
1196 table
->table
[table
->dwNumEntries
].dwForwardType
=
1197 MIB_IPROUTE_TYPE_INVALID
;
1198 else if (flags
& RTF_GATEWAY
)
1199 table
->table
[table
->dwNumEntries
].dwForwardType
=
1200 MIB_IPROUTE_TYPE_INDIRECT
;
1202 table
->table
[table
->dwNumEntries
].dwForwardType
=
1203 MIB_IPROUTE_TYPE_DIRECT
;
1207 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
1211 strtoul(ptr
, &endPtr
, 16); /* use, skip */
1215 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1216 strtoul(ptr
, &endPtr
, 16);
1220 table
->table
[table
->dwNumEntries
].dwForwardMask
=
1221 strtoul(ptr
, &endPtr
, 16);
1224 /* FIXME: other protos might be appropriate, e.g. the default
1225 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1226 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1228 table
->dwNumEntries
++;
1236 ERR ("unimplemented!\n");
1237 return ERROR_NOT_SUPPORTED
;
1242 ret
= ERROR_OUTOFMEMORY
;
1247 DWORD
getNumArpEntries(void)
1249 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1250 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1251 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1252 DWORD arpEntries
= 0;
1254 char *buf
, *lim
, *next
;
1255 struct rt_msghdr
*rtm
;
1256 struct sockaddr_inarp
*sinarp
;
1257 struct sockaddr_dl
*sdl
;
1259 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1261 ERR ("failed to get size of arp table\n");
1265 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1268 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1270 ERR ("failed to get arp table\n");
1271 HeapFree (GetProcessHeap (), 0, buf
);
1279 rtm
= (struct rt_msghdr
*)next
;
1280 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1281 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1282 if(sdl
->sdl_alen
) /* arp entry */
1284 next
+= rtm
->rtm_msglen
;
1286 HeapFree (GetProcessHeap (), 0, buf
);
1289 return getNumWithOneHeader("/proc/net/arp");
1292 DWORD
getArpTable(PMIB_IPNETTABLE
*ppIpNetTable
, HANDLE heap
, DWORD flags
)
1294 DWORD ret
= NO_ERROR
;
1296 ret
= ERROR_INVALID_PARAMETER
;
1298 DWORD numEntries
= getNumArpEntries();
1299 DWORD size
= sizeof(MIB_IPNETTABLE
);
1300 PMIB_IPNETTABLE table
;
1303 size
+= (numEntries
- 1) * sizeof(MIB_IPNETROW
);
1304 table
= HeapAlloc(heap
, flags
, size
);
1305 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1308 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1309 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1311 char *buf
, *lim
, *next
;
1312 struct rt_msghdr
*rtm
;
1313 struct sockaddr_inarp
*sinarp
;
1314 struct sockaddr_dl
*sdl
;
1316 *ppIpNetTable
= table
;
1317 table
->dwNumEntries
= 0;
1319 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1321 ERR ("failed to get size of arp table\n");
1322 return ERROR_NOT_SUPPORTED
;
1325 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1326 if (!buf
) return ERROR_OUTOFMEMORY
;
1328 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1330 ERR ("failed to get arp table\n");
1331 HeapFree (GetProcessHeap (), 0, buf
);
1332 return ERROR_NOT_SUPPORTED
;
1339 rtm
= (struct rt_msghdr
*)next
;
1340 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1341 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1342 if(sdl
->sdl_alen
) /* arp entry */
1344 DWORD byte
= strtoul(&sdl
->sdl_data
[sdl
->sdl_alen
], NULL
, 16);
1345 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1346 table
->table
[table
->dwNumEntries
].dwAddr
= sinarp
->sin_addr
.s_addr
;
1347 table
->table
[table
->dwNumEntries
].dwIndex
= sdl
->sdl_index
;
1348 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
= sdl
->sdl_alen
;
1350 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1351 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1353 if(rtm
->rtm_rmx
.rmx_expire
== 0)
1354 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_STATIC
;
1355 else if(sinarp
->sin_other
& SIN_PROXY
)
1356 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1357 else if(rtm
->rtm_rmx
.rmx_expire
!= 0)
1358 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1360 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_INVALID
;
1362 table
->dwNumEntries
++;
1364 next
+= rtm
->rtm_msglen
;
1366 HeapFree (GetProcessHeap (), 0, buf
);
1369 ret
= ERROR_OUTOFMEMORY
;
1375 *ppIpNetTable
= table
;
1376 table
->dwNumEntries
= 0;
1377 /* get from /proc/net/arp, no error if can't */
1378 fp
= fopen("/proc/net/arp", "r");
1380 char buf
[512] = { 0 }, *ptr
;
1382 /* skip header line */
1383 ptr
= fgets(buf
, sizeof(buf
), fp
);
1384 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1385 ptr
= fgets(buf
, sizeof(buf
), fp
);
1389 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1390 table
->table
[table
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
1391 while (ptr
&& *ptr
&& !isspace(*ptr
))
1395 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
1399 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1402 if (flags
& ATF_COM
)
1403 table
->table
[table
->dwNumEntries
].dwType
=
1404 MIB_IPNET_TYPE_DYNAMIC
;
1408 if (flags
& ATF_PERM
)
1409 table
->table
[table
->dwNumEntries
].dwType
=
1410 MIB_IPNET_TYPE_STATIC
;
1413 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1417 while (ptr
&& *ptr
&& isspace(*ptr
))
1419 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
1420 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
1422 if (endPtr
&& *endPtr
) {
1424 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1425 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1431 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
1434 getInterfaceIndexByName(ptr
,
1435 &table
->table
[table
->dwNumEntries
].dwIndex
);
1436 table
->dwNumEntries
++;
1442 ret
= ERROR_NOT_SUPPORTED
;
1445 ret
= ERROR_OUTOFMEMORY
;
1450 DWORD
getNumUdpEntries(void)
1452 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1453 return getNumWithOneHeader ("net.inet.udp.pcblist");
1455 return getNumWithOneHeader("/proc/net/udp");
1459 DWORD
getUdpTable(PMIB_UDPTABLE
*ppUdpTable
, HANDLE heap
, DWORD flags
)
1463 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1464 ERR ("unimplemented!\n");
1465 return ERROR_NOT_SUPPORTED
;
1469 ret
= ERROR_INVALID_PARAMETER
;
1471 DWORD numEntries
= getNumUdpEntries();
1472 DWORD size
= sizeof(MIB_UDPTABLE
);
1473 PMIB_UDPTABLE table
;
1476 size
+= (numEntries
- 1) * sizeof(MIB_UDPROW
);
1477 table
= HeapAlloc(heap
, flags
, size
);
1482 *ppUdpTable
= table
;
1483 table
->dwNumEntries
= 0;
1484 /* get from /proc/net/udp, no error if can't */
1485 fp
= fopen("/proc/net/udp", "r");
1487 char buf
[512] = { 0 }, *ptr
;
1489 /* skip header line */
1490 ptr
= fgets(buf
, sizeof(buf
), fp
);
1491 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1492 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_UDPROW
));
1493 ptr
= fgets(buf
, sizeof(buf
), fp
);
1498 strtoul(ptr
, &endPtr
, 16); /* skip */
1503 table
->table
[table
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
,
1509 table
->table
[table
->dwNumEntries
].dwLocalPort
= strtoul(ptr
,
1513 table
->dwNumEntries
++;
1519 ret
= ERROR_NOT_SUPPORTED
;
1522 ret
= ERROR_OUTOFMEMORY
;
1528 DWORD
getNumTcpEntries(void)
1530 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1531 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1533 return getNumWithOneHeader ("/proc/net/tcp");
1538 /* Why not a lookup table? Because the TCPS_* constants are different
1539 on different platforms */
1540 static DWORD
TCPStateToMIBState (int state
)
1544 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1545 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1546 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1547 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1548 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1549 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1550 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1551 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1552 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1553 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1555 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1560 DWORD
getTcpTable(PMIB_TCPTABLE
*ppTcpTable
, DWORD maxEntries
, HANDLE heap
,
1564 PMIB_TCPTABLE table
;
1565 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1568 struct xinpgen
*pXIG
, *pOrigXIG
;
1571 char buf
[512] = { 0 }, *ptr
;
1575 return ERROR_INVALID_PARAMETER
;
1577 numEntries
= getNumTcpEntries ();
1581 DWORD size
= sizeof(MIB_TCPTABLE
);
1584 size
+= (numEntries
- 1) * sizeof (MIB_TCPROW
);
1585 *ppTcpTable
= HeapAlloc (heap
, flags
, size
);
1588 ERR ("Out of memory!\n");
1589 return ERROR_OUTOFMEMORY
;
1591 maxEntries
= numEntries
;
1594 table
= *ppTcpTable
;
1595 table
->dwNumEntries
= 0;
1599 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1601 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1603 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1604 return ERROR_OUTOFMEMORY
;
1607 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1610 ERR ("Out of memory!\n");
1611 return ERROR_OUTOFMEMORY
;
1614 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1616 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1617 HeapFree (GetProcessHeap (), 0, Buf
);
1618 return ERROR_OUTOFMEMORY
;
1621 /* Might be nothing here; first entry is just a header it seems */
1622 if (Len
<= sizeof (struct xinpgen
))
1624 HeapFree (GetProcessHeap (), 0, Buf
);
1628 pOrigXIG
= (struct xinpgen
*)Buf
;
1631 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1632 (pXIG
->xig_len
> sizeof (struct xinpgen
)) &&
1633 (table
->dwNumEntries
< maxEntries
);
1634 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1636 struct tcpcb
*pTCPData
= NULL
;
1637 struct inpcb
*pINData
;
1638 struct xsocket
*pSockData
;
1640 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1641 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1642 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1644 /* Ignore sockets for other protocols */
1645 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1648 /* Ignore PCBs that were freed while generating the data */
1649 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1652 /* we're only interested in IPv4 addresses */
1653 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1654 (pINData
->inp_vflag
& INP_IPV6
))
1657 /* If all 0's, skip it */
1658 if (!pINData
->inp_laddr
.s_addr
&&
1659 !pINData
->inp_lport
&&
1660 !pINData
->inp_faddr
.s_addr
&&
1661 !pINData
->inp_fport
)
1664 /* Fill in structure details */
1665 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1666 pINData
->inp_laddr
.s_addr
;
1667 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1669 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1670 pINData
->inp_faddr
.s_addr
;
1671 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1673 table
->table
[table
->dwNumEntries
].dwState
=
1674 TCPStateToMIBState (pTCPData
->t_state
);
1676 table
->dwNumEntries
++;
1679 HeapFree (GetProcessHeap (), 0, Buf
);
1681 /* get from /proc/net/tcp, no error if can't */
1682 fp
= fopen("/proc/net/tcp", "r");
1684 return ERROR_NOT_SUPPORTED
;
1686 /* skip header line */
1687 ptr
= fgets(buf
, sizeof(buf
), fp
);
1688 while (ptr
&& table
->dwNumEntries
< maxEntries
) {
1689 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_TCPROW
));
1690 ptr
= fgets(buf
, sizeof(buf
), fp
);
1694 while (ptr
&& *ptr
&& *ptr
!= ':')
1699 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1700 strtoul(ptr
, &endPtr
, 16);
1705 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1706 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1710 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1711 strtoul(ptr
, &endPtr
, 16);
1716 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1717 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1721 DWORD state
= strtoul(ptr
, &endPtr
, 16);
1723 table
->table
[table
->dwNumEntries
].dwState
=
1724 TCPStateToMIBState (state
);
1727 table
->dwNumEntries
++;