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_SYS_TIMEOUT_H
41 #include <sys/timeout.h>
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
46 #ifdef HAVE_NETINET_IN_SYSTM_H
47 #include <netinet/in_systm.h>
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
55 #ifdef HAVE_NET_IF_DL_H
56 #include <net/if_dl.h>
58 #ifdef HAVE_NET_IF_TYPES_H
59 #include <net/if_types.h>
61 #ifdef HAVE_NET_ROUTE_H
62 #include <net/route.h>
64 #ifdef HAVE_NET_IF_ARP_H
65 #include <net/if_arp.h>
67 #ifdef HAVE_NETINET_IF_ETHER_H
68 #include <netinet/if_ether.h>
70 #ifdef HAVE_NETINET_IF_INARP_H
71 #include <netinet/if_inarp.h>
73 #ifdef HAVE_NETINET_IP_H
74 #include <netinet/ip.h>
76 #ifdef HAVE_NETINET_TCP_H
77 #include <netinet/tcp.h>
79 #ifdef HAVE_NETINET_IP_VAR_H
80 #include <netinet/ip_var.h>
82 #ifdef HAVE_NETINET_TCP_FSM_H
83 #include <netinet/tcp_fsm.h>
85 #ifdef HAVE_NETINET_IN_PCB_H
86 #include <netinet/in_pcb.h>
88 #ifdef HAVE_NETINET_TCP_TIMER_H
89 #include <netinet/tcp_timer.h>
91 #ifdef HAVE_NETINET_TCP_VAR_H
92 #include <netinet/tcp_var.h>
94 #ifdef HAVE_NETINET_IP_ICMP_H
95 #include <netinet/ip_icmp.h>
97 #ifdef HAVE_NETINET_ICMP_VAR_H
98 #include <netinet/icmp_var.h>
100 #ifdef HAVE_NETINET_UDP_H
101 #include <netinet/udp.h>
103 #ifdef HAVE_NETINET_UDP_VAR_H
104 #include <netinet/udp_var.h>
106 #ifdef HAVE_SYS_PROTOSW_H
107 #include <sys/protosw.h>
109 #ifdef HAVE_SYS_SYSCTL_H
110 #include <sys/sysctl.h>
115 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
118 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
123 #include "iprtrmib.h"
127 #ifndef HAVE_NETINET_TCP_FSM_H
128 #define TCPS_ESTABLISHED 1
129 #define TCPS_SYN_SENT 2
130 #define TCPS_SYN_RECEIVED 3
131 #define TCPS_FIN_WAIT_1 4
132 #define TCPS_FIN_WAIT_2 5
133 #define TCPS_TIME_WAIT 6
134 #define TCPS_CLOSED 7
135 #define TCPS_CLOSE_WAIT 8
136 #define TCPS_LAST_ACK 9
137 #define TCPS_LISTEN 10
138 #define TCPS_CLOSING 11
141 #ifndef RTF_MULTICAST
142 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
146 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
149 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
151 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
153 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
154 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
155 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
159 struct if_msghdr
*ifm
;
160 struct if_data ifdata
;
162 return ERROR_INVALID_PARAMETER
;
164 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
166 ERR ("failed to get size of iflist\n");
167 return ERROR_NOT_SUPPORTED
;
169 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
170 if (!buf
) return ERROR_NOT_SUPPORTED
;
171 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
173 ERR ("failed to get iflist\n");
174 HeapFree (GetProcessHeap (), 0, buf
);
175 return ERROR_NOT_SUPPORTED
;
178 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
180 ifm
= (struct if_msghdr
*) buf
;
181 if(ifm
->ifm_type
== RTM_IFINFO
&& ifm
->ifm_data
.ifi_type
== IFT_ETHER
)
183 ifdata
= ifm
->ifm_data
;
184 entry
->dwMtu
= ifdata
.ifi_mtu
;
185 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
186 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
187 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
188 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
189 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
190 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
191 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
192 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
193 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
194 HeapFree (GetProcessHeap (), 0, buf
);
198 HeapFree (GetProcessHeap (), 0, buf
);
199 return ERROR_NOT_SUPPORTED
;
201 /* get interface stats from /proc/net/dev, no error if can't
202 no inUnknownProtos, outNUcastPkts, outQLen */
206 return ERROR_INVALID_PARAMETER
;
207 fp
= fopen("/proc/net/dev", "r");
209 char buf
[512] = { 0 }, *ptr
;
210 int nameLen
= strlen(name
), nameFound
= 0;
213 ptr
= fgets(buf
, sizeof(buf
), fp
);
214 while (ptr
&& !nameFound
) {
215 while (*ptr
&& isspace(*ptr
))
217 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
220 ptr
= fgets(buf
, sizeof(buf
), fp
);
227 entry
->dwInOctets
= strtoul(ptr
, &endPtr
, 10);
231 entry
->dwInUcastPkts
= strtoul(ptr
, &endPtr
, 10);
235 entry
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
239 entry
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
243 strtoul(ptr
, &endPtr
, 10); /* skip */
247 strtoul(ptr
, &endPtr
, 10); /* skip */
251 strtoul(ptr
, &endPtr
, 10); /* skip */
255 entry
->dwInNUcastPkts
= strtoul(ptr
, &endPtr
, 10);
259 entry
->dwOutOctets
= strtoul(ptr
, &endPtr
, 10);
263 entry
->dwOutUcastPkts
= strtoul(ptr
, &endPtr
, 10);
267 entry
->dwOutErrors
= strtoul(ptr
, &endPtr
, 10);
271 entry
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
279 ERR ("unimplemented!\n");
280 return ERROR_NOT_SUPPORTED
;
287 DWORD
getICMPStats(MIB_ICMP
*stats
)
289 #if defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
290 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
291 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
293 struct icmpstat icmp_stat
;
297 return ERROR_INVALID_PARAMETER
;
299 needed
= sizeof(icmp_stat
);
300 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) == -1)
302 ERR ("failed to get icmpstat\n");
303 return ERROR_NOT_SUPPORTED
;
308 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
309 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
310 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
312 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
314 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
315 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
316 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
317 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
318 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
319 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
320 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
321 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
322 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
323 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
324 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
328 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
329 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
330 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
332 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
334 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
335 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
336 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
337 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
338 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
339 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
340 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
341 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
342 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
343 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
344 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
351 return ERROR_INVALID_PARAMETER
;
353 memset(stats
, 0, sizeof(MIB_ICMP
));
354 /* get most of these stats from /proc/net/snmp, no error if can't */
355 fp
= fopen("/proc/net/snmp", "r");
357 static const char hdr
[] = "Icmp:";
358 char buf
[512] = { 0 }, *ptr
;
361 ptr
= fgets(buf
, sizeof(buf
), fp
);
362 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
364 /* last line was a header, get another */
365 ptr
= fgets(buf
, sizeof(buf
), fp
);
366 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
371 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
375 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
379 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
383 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
387 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
391 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
395 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
399 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
403 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
407 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
411 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
415 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
419 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
423 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
427 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
431 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
435 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
439 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
443 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
447 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
451 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
455 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
459 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
463 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
472 ERR ("unimplemented!\n");
473 return ERROR_NOT_SUPPORTED
;
480 DWORD
getIPStats(PMIB_IPSTATS stats
)
482 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
483 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
484 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
485 int ip_ttl
, ip_forwarding
;
486 struct ipstat ip_stat
;
490 return ERROR_INVALID_PARAMETER
;
492 needed
= sizeof(ip_stat
);
493 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
495 ERR ("failed to get ipstat\n");
496 return ERROR_NOT_SUPPORTED
;
499 needed
= sizeof(ip_ttl
);
500 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
502 ERR ("failed to get ip Default TTL\n");
503 return ERROR_NOT_SUPPORTED
;
506 needed
= sizeof(ip_forwarding
);
507 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
509 ERR ("failed to get ip forwarding\n");
510 return ERROR_NOT_SUPPORTED
;
513 stats
->dwForwarding
= ip_forwarding
;
514 stats
->dwDefaultTTL
= ip_ttl
;
515 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
516 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
517 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
518 stats
->dwInReceives
= ip_stat
.ips_total
;
519 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
520 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
521 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
522 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
523 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
524 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
525 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
526 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
527 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
528 stats
->dwOutRequests
= ip_stat
.ips_localout
;
529 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
536 return ERROR_INVALID_PARAMETER
;
538 memset(stats
, 0, sizeof(MIB_IPSTATS
));
539 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
540 stats
->dwNumRoutes
= getNumRoutes();
542 /* get most of these stats from /proc/net/snmp, no error if can't */
543 fp
= fopen("/proc/net/snmp", "r");
545 static const char hdr
[] = "Ip:";
546 char buf
[512] = { 0 }, *ptr
;
549 ptr
= fgets(buf
, sizeof(buf
), fp
);
550 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
552 /* last line was a header, get another */
553 ptr
= fgets(buf
, sizeof(buf
), fp
);
554 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
559 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
563 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
567 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
571 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
575 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
579 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
583 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
587 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
591 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
595 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
599 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
603 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
607 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
611 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
615 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
619 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
623 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
627 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
631 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
634 /* hmm, no routingDiscards */
641 ERR ("unimplemented!\n");
642 return ERROR_NOT_SUPPORTED
;
649 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
651 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
652 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
654 #define TCPTV_REXMTMAX 128
656 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
657 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
659 struct tcpstat tcp_stat
;
663 return ERROR_INVALID_PARAMETER
;
664 needed
= sizeof(tcp_stat
);
666 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) == -1)
668 ERR ("failed to get tcpstat\n");
669 return ERROR_NOT_SUPPORTED
;
672 stats
->dwRtoAlgorithm
= MIB_TCP_RTO_VANJ
;
673 stats
->dwRtoMin
= TCPTV_MIN
;
674 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
675 stats
->dwMaxConn
= -1;
676 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
677 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
678 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
679 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
680 stats
->dwCurrEstab
= 0;
681 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
682 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
683 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
684 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
685 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
686 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
694 return ERROR_INVALID_PARAMETER
;
696 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
698 /* get from /proc/net/snmp, no error if can't */
699 fp
= fopen("/proc/net/snmp", "r");
701 static const char hdr
[] = "Tcp:";
702 char buf
[512] = { 0 }, *ptr
;
706 ptr
= fgets(buf
, sizeof(buf
), fp
);
707 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
709 /* last line was a header, get another */
710 ptr
= fgets(buf
, sizeof(buf
), fp
);
711 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
716 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
720 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
724 stats
->dwRtoMax
= strtoul(ptr
, &endPtr
, 10);
728 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
732 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
736 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
740 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
744 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
748 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
752 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
756 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
760 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
764 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
768 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
771 stats
->dwNumConns
= getNumTcpEntries();
778 ERR ("unimplemented!\n");
779 return ERROR_NOT_SUPPORTED
;
786 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
788 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
789 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
790 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
791 struct udpstat udp_stat
;
794 return ERROR_INVALID_PARAMETER
;
796 needed
= sizeof(udp_stat
);
798 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) == -1)
800 ERR ("failed to get udpstat\n");
801 return ERROR_NOT_SUPPORTED
;
804 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
805 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
806 stats
->dwNoPorts
= udp_stat
.udps_noport
;
807 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
808 stats
->dwNumAddrs
= getNumUdpEntries();
815 return ERROR_INVALID_PARAMETER
;
817 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
819 /* get from /proc/net/snmp, no error if can't */
820 fp
= fopen("/proc/net/snmp", "r");
822 static const char hdr
[] = "Udp:";
823 char buf
[512] = { 0 }, *ptr
;
827 ptr
= fgets(buf
, sizeof(buf
), fp
);
828 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
830 /* last line was a header, get another */
831 ptr
= fgets(buf
, sizeof(buf
), fp
);
832 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
837 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
841 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
845 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
849 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
853 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
862 ERR ("unimplemented!\n");
863 return ERROR_NOT_SUPPORTED
;
870 static DWORD
getNumWithOneHeader(const char *filename
)
872 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
875 struct xinpgen
*pXIG
, *pOrigXIG
;
877 DWORD NumEntries
= 0;
879 if (!strcmp (filename
, "net.inet.tcp.pcblist"))
880 Protocol
= IPPROTO_TCP
;
881 else if (!strcmp (filename
, "net.inet.udp.pcblist"))
882 Protocol
= IPPROTO_UDP
;
885 ERR ("Unsupported mib '%s', needs protocol mapping\n",
890 if (sysctlbyname (filename
, NULL
, &Len
, NULL
, 0) < 0)
892 WARN ("Unable to read '%s' via sysctlbyname\n", filename
);
896 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
899 ERR ("Out of memory!\n");
903 if (sysctlbyname (filename
, Buf
, &Len
, NULL
, 0) < 0)
905 ERR ("Failure to read '%s' via sysctlbyname!\n", filename
);
906 HeapFree (GetProcessHeap (), 0, Buf
);
910 /* Might be nothing here; first entry is just a header it seems */
911 if (Len
<= sizeof (struct xinpgen
))
913 HeapFree (GetProcessHeap (), 0, Buf
);
917 pOrigXIG
= (struct xinpgen
*)Buf
;
920 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
921 pXIG
->xig_len
> sizeof (struct xinpgen
);
922 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
924 struct tcpcb
*pTCPData
= NULL
;
925 struct inpcb
*pINData
;
926 struct xsocket
*pSockData
;
928 if (Protocol
== IPPROTO_TCP
)
930 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
931 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
932 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
936 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
937 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
940 /* Ignore sockets for other protocols */
941 if (pSockData
->xso_protocol
!= Protocol
)
944 /* Ignore PCBs that were freed while generating the data */
945 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
948 /* we're only interested in IPv4 addresses */
949 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
950 (pINData
->inp_vflag
& INP_IPV6
))
953 /* If all 0's, skip it */
954 if (!pINData
->inp_laddr
.s_addr
&&
955 !pINData
->inp_lport
&&
956 !pINData
->inp_faddr
.s_addr
&&
963 HeapFree (GetProcessHeap (), 0, Buf
);
969 fp
= fopen(filename
, "r");
971 char buf
[512] = { 0 }, *ptr
;
974 ptr
= fgets(buf
, sizeof(buf
), fp
);
977 ptr
= fgets(buf
, sizeof(buf
), fp
);
985 ERR ("Unable to open '%s' to count entries!\n", filename
);
991 DWORD
getNumRoutes(void)
993 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
994 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
996 char *buf
, *lim
, *next
;
997 struct rt_msghdr
*rtm
;
998 DWORD RouteCount
= 0;
1000 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1002 ERR ("sysctl 1 failed!\n");
1006 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1009 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1011 ERR ("sysctl 2 failed!\n");
1012 HeapFree (GetProcessHeap (), 0, buf
);
1017 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1019 rtm
= (struct rt_msghdr
*)next
;
1021 if (rtm
->rtm_type
!= RTM_GET
)
1023 WARN ("Got unexpected message type 0x%x!\n",
1028 /* Ignore all entries except for gateway routes which aren't
1030 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) || (rtm
->rtm_flags
& RTF_MULTICAST
))
1036 HeapFree (GetProcessHeap (), 0, buf
);
1039 return getNumWithOneHeader("/proc/net/route");
1043 DWORD
getRouteTable(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, HANDLE heap
,
1048 if (!ppIpForwardTable
)
1049 ret
= ERROR_INVALID_PARAMETER
;
1051 DWORD numRoutes
= getNumRoutes();
1052 DWORD size
= sizeof(MIB_IPFORWARDTABLE
);
1053 PMIB_IPFORWARDTABLE table
;
1056 size
+= (numRoutes
- 1) * sizeof(MIB_IPFORWARDROW
);
1057 table
= HeapAlloc(heap
, flags
, size
);
1059 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1060 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1062 char *buf
, *lim
, *next
, *addrPtr
;
1063 struct rt_msghdr
*rtm
;
1065 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1067 ERR ("sysctl 1 failed!\n");
1068 HeapFree (GetProcessHeap (), 0, table
);
1072 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1075 HeapFree (GetProcessHeap (), 0, table
);
1076 return ERROR_OUTOFMEMORY
;
1079 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1081 ERR ("sysctl 2 failed!\n");
1082 HeapFree (GetProcessHeap (), 0, table
);
1083 HeapFree (GetProcessHeap (), 0, buf
);
1087 *ppIpForwardTable
= table
;
1088 table
->dwNumEntries
= 0;
1091 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1095 rtm
= (struct rt_msghdr
*)next
;
1097 if (rtm
->rtm_type
!= RTM_GET
)
1099 WARN ("Got unexpected message type 0x%x!\n",
1104 /* Ignore all entries except for gateway routes which aren't
1106 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1107 (rtm
->rtm_flags
& RTF_MULTICAST
))
1110 memset (&table
->table
[table
->dwNumEntries
], 0,
1111 sizeof (MIB_IPFORWARDROW
));
1112 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= rtm
->rtm_index
;
1113 table
->table
[table
->dwNumEntries
].dwForwardType
=
1114 MIB_IPROUTE_TYPE_INDIRECT
;
1115 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1116 rtm
->rtm_rmx
.rmx_hopcount
;
1117 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1120 addrPtr
= (char *)(rtm
+ 1);
1122 for (i
= 1; i
; i
<<= 1)
1124 struct sockaddr
*sa
;
1127 if (!(i
& rtm
->rtm_addrs
))
1130 sa
= (struct sockaddr
*)addrPtr
;
1131 ADVANCE (addrPtr
, sa
);
1133 /* default routes are encoded by length-zero sockaddr */
1134 if (sa
->sa_len
== 0)
1136 else if (sa
->sa_family
!= AF_INET
)
1138 WARN ("Received unsupported sockaddr family 0x%x\n",
1144 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1146 addr
= sin
->sin_addr
.s_addr
;
1152 table
->table
[table
->dwNumEntries
].dwForwardDest
= addr
;
1156 table
->table
[table
->dwNumEntries
].dwForwardNextHop
= addr
;
1160 table
->table
[table
->dwNumEntries
].dwForwardMask
= addr
;
1164 WARN ("Unexpected address type 0x%x\n", i
);
1168 table
->dwNumEntries
++;
1171 HeapFree (GetProcessHeap (), 0, buf
);
1177 *ppIpForwardTable
= table
;
1178 table
->dwNumEntries
= 0;
1179 /* get from /proc/net/route, no error if can't */
1180 fp
= fopen("/proc/net/route", "r");
1182 char buf
[512] = { 0 }, *ptr
;
1184 /* skip header line */
1185 ptr
= fgets(buf
, sizeof(buf
), fp
);
1186 while (ptr
&& table
->dwNumEntries
< numRoutes
) {
1187 memset(&table
->table
[table
->dwNumEntries
], 0,
1188 sizeof(MIB_IPFORWARDROW
));
1189 ptr
= fgets(buf
, sizeof(buf
), fp
);
1193 while (!isspace(*ptr
))
1197 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
1200 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= index
;
1202 table
->table
[table
->dwNumEntries
].dwForwardDest
=
1203 strtoul(ptr
, &endPtr
, 16);
1207 table
->table
[table
->dwNumEntries
].dwForwardNextHop
=
1208 strtoul(ptr
, &endPtr
, 16);
1212 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1214 if (!(flags
& RTF_UP
))
1215 table
->table
[table
->dwNumEntries
].dwForwardType
=
1216 MIB_IPROUTE_TYPE_INVALID
;
1217 else if (flags
& RTF_GATEWAY
)
1218 table
->table
[table
->dwNumEntries
].dwForwardType
=
1219 MIB_IPROUTE_TYPE_INDIRECT
;
1221 table
->table
[table
->dwNumEntries
].dwForwardType
=
1222 MIB_IPROUTE_TYPE_DIRECT
;
1226 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
1230 strtoul(ptr
, &endPtr
, 16); /* use, skip */
1234 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1235 strtoul(ptr
, &endPtr
, 16);
1239 table
->table
[table
->dwNumEntries
].dwForwardMask
=
1240 strtoul(ptr
, &endPtr
, 16);
1243 /* FIXME: other protos might be appropriate, e.g. the default
1244 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1245 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1247 table
->dwNumEntries
++;
1255 ERR ("unimplemented!\n");
1256 return ERROR_NOT_SUPPORTED
;
1261 ret
= ERROR_OUTOFMEMORY
;
1266 DWORD
getNumArpEntries(void)
1268 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1269 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1270 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1271 DWORD arpEntries
= 0;
1273 char *buf
, *lim
, *next
;
1274 struct rt_msghdr
*rtm
;
1275 struct sockaddr_inarp
*sinarp
;
1276 struct sockaddr_dl
*sdl
;
1278 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1280 ERR ("failed to get size of arp table\n");
1284 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1287 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1289 ERR ("failed to get arp table\n");
1290 HeapFree (GetProcessHeap (), 0, buf
);
1298 rtm
= (struct rt_msghdr
*)next
;
1299 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1300 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1301 if(sdl
->sdl_alen
) /* arp entry */
1303 next
+= rtm
->rtm_msglen
;
1305 HeapFree (GetProcessHeap (), 0, buf
);
1308 return getNumWithOneHeader("/proc/net/arp");
1311 DWORD
getArpTable(PMIB_IPNETTABLE
*ppIpNetTable
, HANDLE heap
, DWORD flags
)
1313 DWORD ret
= NO_ERROR
;
1315 ret
= ERROR_INVALID_PARAMETER
;
1317 DWORD numEntries
= getNumArpEntries();
1318 DWORD size
= sizeof(MIB_IPNETTABLE
);
1319 PMIB_IPNETTABLE table
;
1322 size
+= (numEntries
- 1) * sizeof(MIB_IPNETROW
);
1323 table
= HeapAlloc(heap
, flags
, size
);
1324 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1327 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1328 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1330 char *buf
, *lim
, *next
;
1331 struct rt_msghdr
*rtm
;
1332 struct sockaddr_inarp
*sinarp
;
1333 struct sockaddr_dl
*sdl
;
1335 *ppIpNetTable
= table
;
1336 table
->dwNumEntries
= 0;
1338 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1340 ERR ("failed to get size of arp table\n");
1341 return ERROR_NOT_SUPPORTED
;
1344 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1345 if (!buf
) return ERROR_OUTOFMEMORY
;
1347 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1349 ERR ("failed to get arp table\n");
1350 HeapFree (GetProcessHeap (), 0, buf
);
1351 return ERROR_NOT_SUPPORTED
;
1358 rtm
= (struct rt_msghdr
*)next
;
1359 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1360 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1361 if(sdl
->sdl_alen
) /* arp entry */
1363 DWORD byte
= strtoul(&sdl
->sdl_data
[sdl
->sdl_alen
], NULL
, 16);
1364 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1365 table
->table
[table
->dwNumEntries
].dwAddr
= sinarp
->sin_addr
.s_addr
;
1366 table
->table
[table
->dwNumEntries
].dwIndex
= sdl
->sdl_index
;
1367 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
= sdl
->sdl_alen
;
1369 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1370 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1372 if(rtm
->rtm_rmx
.rmx_expire
== 0)
1373 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_STATIC
;
1374 else if(sinarp
->sin_other
& SIN_PROXY
)
1375 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1376 else if(rtm
->rtm_rmx
.rmx_expire
!= 0)
1377 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1379 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_INVALID
;
1381 table
->dwNumEntries
++;
1383 next
+= rtm
->rtm_msglen
;
1385 HeapFree (GetProcessHeap (), 0, buf
);
1388 ret
= ERROR_OUTOFMEMORY
;
1394 *ppIpNetTable
= table
;
1395 table
->dwNumEntries
= 0;
1396 /* get from /proc/net/arp, no error if can't */
1397 fp
= fopen("/proc/net/arp", "r");
1399 char buf
[512] = { 0 }, *ptr
;
1401 /* skip header line */
1402 ptr
= fgets(buf
, sizeof(buf
), fp
);
1403 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1404 ptr
= fgets(buf
, sizeof(buf
), fp
);
1408 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1409 table
->table
[table
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
1410 while (ptr
&& *ptr
&& !isspace(*ptr
))
1414 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
1418 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1421 if (flags
& ATF_COM
)
1422 table
->table
[table
->dwNumEntries
].dwType
=
1423 MIB_IPNET_TYPE_DYNAMIC
;
1427 if (flags
& ATF_PERM
)
1428 table
->table
[table
->dwNumEntries
].dwType
=
1429 MIB_IPNET_TYPE_STATIC
;
1432 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1436 while (ptr
&& *ptr
&& isspace(*ptr
))
1438 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
1439 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
1441 if (endPtr
&& *endPtr
) {
1443 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1444 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1450 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
1453 getInterfaceIndexByName(ptr
,
1454 &table
->table
[table
->dwNumEntries
].dwIndex
);
1455 table
->dwNumEntries
++;
1461 ret
= ERROR_NOT_SUPPORTED
;
1464 ret
= ERROR_OUTOFMEMORY
;
1469 DWORD
getNumUdpEntries(void)
1471 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1472 return getNumWithOneHeader ("net.inet.udp.pcblist");
1474 return getNumWithOneHeader("/proc/net/udp");
1478 DWORD
getUdpTable(PMIB_UDPTABLE
*ppUdpTable
, HANDLE heap
, DWORD flags
)
1482 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1483 ERR ("unimplemented!\n");
1484 return ERROR_NOT_SUPPORTED
;
1488 ret
= ERROR_INVALID_PARAMETER
;
1490 DWORD numEntries
= getNumUdpEntries();
1491 DWORD size
= sizeof(MIB_UDPTABLE
);
1492 PMIB_UDPTABLE table
;
1495 size
+= (numEntries
- 1) * sizeof(MIB_UDPROW
);
1496 table
= HeapAlloc(heap
, flags
, size
);
1501 *ppUdpTable
= table
;
1502 table
->dwNumEntries
= 0;
1503 /* get from /proc/net/udp, no error if can't */
1504 fp
= fopen("/proc/net/udp", "r");
1506 char buf
[512] = { 0 }, *ptr
;
1508 /* skip header line */
1509 ptr
= fgets(buf
, sizeof(buf
), fp
);
1510 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1511 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_UDPROW
));
1512 ptr
= fgets(buf
, sizeof(buf
), fp
);
1517 strtoul(ptr
, &endPtr
, 16); /* skip */
1522 table
->table
[table
->dwNumEntries
].dwLocalAddr
= strtoul(ptr
,
1528 table
->table
[table
->dwNumEntries
].dwLocalPort
= strtoul(ptr
,
1532 table
->dwNumEntries
++;
1538 ret
= ERROR_NOT_SUPPORTED
;
1541 ret
= ERROR_OUTOFMEMORY
;
1547 DWORD
getNumTcpEntries(void)
1549 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1550 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1552 return getNumWithOneHeader ("/proc/net/tcp");
1557 /* Why not a lookup table? Because the TCPS_* constants are different
1558 on different platforms */
1559 static DWORD
TCPStateToMIBState (int state
)
1563 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1564 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1565 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1566 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1567 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1568 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1569 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1570 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1571 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1572 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1574 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1579 DWORD
getTcpTable(PMIB_TCPTABLE
*ppTcpTable
, DWORD maxEntries
, HANDLE heap
,
1583 PMIB_TCPTABLE table
;
1584 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1587 struct xinpgen
*pXIG
, *pOrigXIG
;
1590 char buf
[512] = { 0 }, *ptr
;
1594 return ERROR_INVALID_PARAMETER
;
1596 numEntries
= getNumTcpEntries ();
1600 DWORD size
= sizeof(MIB_TCPTABLE
);
1603 size
+= (numEntries
- 1) * sizeof (MIB_TCPROW
);
1604 *ppTcpTable
= HeapAlloc (heap
, flags
, size
);
1607 ERR ("Out of memory!\n");
1608 return ERROR_OUTOFMEMORY
;
1610 maxEntries
= numEntries
;
1613 table
= *ppTcpTable
;
1614 table
->dwNumEntries
= 0;
1618 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1620 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1622 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1623 return ERROR_OUTOFMEMORY
;
1626 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1629 ERR ("Out of memory!\n");
1630 return ERROR_OUTOFMEMORY
;
1633 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1635 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1636 HeapFree (GetProcessHeap (), 0, Buf
);
1637 return ERROR_OUTOFMEMORY
;
1640 /* Might be nothing here; first entry is just a header it seems */
1641 if (Len
<= sizeof (struct xinpgen
))
1643 HeapFree (GetProcessHeap (), 0, Buf
);
1647 pOrigXIG
= (struct xinpgen
*)Buf
;
1650 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1651 (pXIG
->xig_len
> sizeof (struct xinpgen
)) &&
1652 (table
->dwNumEntries
< maxEntries
);
1653 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1655 struct tcpcb
*pTCPData
= NULL
;
1656 struct inpcb
*pINData
;
1657 struct xsocket
*pSockData
;
1659 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1660 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1661 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1663 /* Ignore sockets for other protocols */
1664 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1667 /* Ignore PCBs that were freed while generating the data */
1668 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1671 /* we're only interested in IPv4 addresses */
1672 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1673 (pINData
->inp_vflag
& INP_IPV6
))
1676 /* If all 0's, skip it */
1677 if (!pINData
->inp_laddr
.s_addr
&&
1678 !pINData
->inp_lport
&&
1679 !pINData
->inp_faddr
.s_addr
&&
1680 !pINData
->inp_fport
)
1683 /* Fill in structure details */
1684 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1685 pINData
->inp_laddr
.s_addr
;
1686 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1688 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1689 pINData
->inp_faddr
.s_addr
;
1690 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1692 table
->table
[table
->dwNumEntries
].dwState
=
1693 TCPStateToMIBState (pTCPData
->t_state
);
1695 table
->dwNumEntries
++;
1698 HeapFree (GetProcessHeap (), 0, Buf
);
1700 /* get from /proc/net/tcp, no error if can't */
1701 fp
= fopen("/proc/net/tcp", "r");
1703 return ERROR_NOT_SUPPORTED
;
1705 /* skip header line */
1706 ptr
= fgets(buf
, sizeof(buf
), fp
);
1707 while (ptr
&& table
->dwNumEntries
< maxEntries
) {
1708 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_TCPROW
));
1709 ptr
= fgets(buf
, sizeof(buf
), fp
);
1713 while (ptr
&& *ptr
&& *ptr
!= ':')
1718 table
->table
[table
->dwNumEntries
].dwLocalAddr
=
1719 strtoul(ptr
, &endPtr
, 16);
1724 table
->table
[table
->dwNumEntries
].dwLocalPort
=
1725 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1729 table
->table
[table
->dwNumEntries
].dwRemoteAddr
=
1730 strtoul(ptr
, &endPtr
, 16);
1735 table
->table
[table
->dwNumEntries
].dwRemotePort
=
1736 htons ((unsigned short)strtoul(ptr
, &endPtr
, 16));
1740 DWORD state
= strtoul(ptr
, &endPtr
, 16);
1742 table
->table
[table
->dwNumEntries
].dwState
=
1743 TCPStateToMIBState (state
);
1746 table
->dwNumEntries
++;