2 * Copyright (C) 2003,2006 Juan Lang
3 * Copyright (C) 2007 TransGaming Technologies Inc.
4 * Copyright (C) 2009 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
28 #include <sys/types.h>
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
35 #ifdef HAVE_SYS_SOCKETVAR_H
36 #include <sys/socketvar.h>
38 #ifdef HAVE_SYS_TIMEOUT_H
39 #include <sys/timeout.h>
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
53 #ifdef HAVE_NET_IF_DL_H
54 #include <net/if_dl.h>
56 #ifdef HAVE_NET_IF_TYPES_H
57 #include <net/if_types.h>
59 #ifdef HAVE_NET_ROUTE_H
60 #include <net/route.h>
62 #ifdef HAVE_NET_IF_ARP_H
63 #include <net/if_arp.h>
65 #ifdef HAVE_NETINET_IF_ETHER_H
66 #include <netinet/if_ether.h>
68 #ifdef HAVE_NETINET_IF_INARP_H
69 #include <netinet/if_inarp.h>
71 #ifdef HAVE_NETINET_IP_H
72 #include <netinet/ip.h>
74 #ifdef HAVE_NETINET_TCP_H
75 #include <netinet/tcp.h>
77 #ifdef HAVE_NETINET_IP_VAR_H
78 #include <netinet/ip_var.h>
80 #ifdef HAVE_NETINET_TCP_FSM_H
81 #include <netinet/tcp_fsm.h>
83 #ifdef HAVE_NETINET_IN_PCB_H
84 #include <netinet/in_pcb.h>
86 #ifdef HAVE_NETINET_TCP_TIMER_H
87 #include <netinet/tcp_timer.h>
89 #ifdef HAVE_NETINET_TCP_VAR_H
90 #include <netinet/tcp_var.h>
92 #ifdef HAVE_NETINET_IP_ICMP_H
93 #include <netinet/ip_icmp.h>
95 #ifdef HAVE_NETINET_ICMP_VAR_H
96 #include <netinet/icmp_var.h>
98 #ifdef HAVE_NETINET_UDP_H
99 #include <netinet/udp.h>
101 #ifdef HAVE_NETINET_UDP_VAR_H
102 #include <netinet/udp_var.h>
104 #ifdef HAVE_SYS_PROTOSW_H
105 #include <sys/protosw.h>
107 #ifdef HAVE_SYS_SYSCTL_H
108 #include <sys/sysctl.h>
113 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
116 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
121 #include "iprtrmib.h"
125 #include "wine/debug.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
];
326 #ifdef HAVE_ICPS_OUTHIST
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
];
345 #else /* ICPS_OUTHIST */
346 memset( &stats
->stats
.icmpOutStats
, 0, sizeof(stats
->stats
.icmpOutStats
) );
347 #endif /* ICPS_OUTHIST */
351 #else /* ICMPCTL_STATS */
355 return ERROR_INVALID_PARAMETER
;
357 memset(stats
, 0, sizeof(MIB_ICMP
));
358 /* get most of these stats from /proc/net/snmp, no error if can't */
359 fp
= fopen("/proc/net/snmp", "r");
361 static const char hdr
[] = "Icmp:";
362 char buf
[512] = { 0 }, *ptr
;
365 ptr
= fgets(buf
, sizeof(buf
), fp
);
366 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
368 /* last line was a header, get another */
369 ptr
= fgets(buf
, sizeof(buf
), fp
);
370 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
375 stats
->stats
.icmpInStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
379 stats
->stats
.icmpInStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
383 stats
->stats
.icmpInStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
387 stats
->stats
.icmpInStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
391 stats
->stats
.icmpInStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
395 stats
->stats
.icmpInStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
399 stats
->stats
.icmpInStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
403 stats
->stats
.icmpInStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
407 stats
->stats
.icmpInStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
411 stats
->stats
.icmpInStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
415 stats
->stats
.icmpInStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
419 stats
->stats
.icmpInStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
423 stats
->stats
.icmpOutStats
.dwMsgs
= strtoul(ptr
, &endPtr
, 10);
427 stats
->stats
.icmpOutStats
.dwErrors
= strtoul(ptr
, &endPtr
, 10);
431 stats
->stats
.icmpOutStats
.dwDestUnreachs
= strtoul(ptr
, &endPtr
, 10);
435 stats
->stats
.icmpOutStats
.dwTimeExcds
= strtoul(ptr
, &endPtr
, 10);
439 stats
->stats
.icmpOutStats
.dwParmProbs
= strtoul(ptr
, &endPtr
, 10);
443 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= strtoul(ptr
, &endPtr
, 10);
447 stats
->stats
.icmpOutStats
.dwRedirects
= strtoul(ptr
, &endPtr
, 10);
451 stats
->stats
.icmpOutStats
.dwEchoReps
= strtoul(ptr
, &endPtr
, 10);
455 stats
->stats
.icmpOutStats
.dwTimestamps
= strtoul(ptr
, &endPtr
, 10);
459 stats
->stats
.icmpOutStats
.dwTimestampReps
= strtoul(ptr
, &endPtr
, 10);
463 stats
->stats
.icmpOutStats
.dwAddrMasks
= strtoul(ptr
, &endPtr
, 10);
467 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= strtoul(ptr
, &endPtr
, 10);
476 ERR ("unimplemented!\n");
477 return ERROR_NOT_SUPPORTED
;
484 DWORD
getIPStats(PMIB_IPSTATS stats
)
486 #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
487 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
488 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
489 int ip_ttl
, ip_forwarding
;
490 struct ipstat ip_stat
;
494 return ERROR_INVALID_PARAMETER
;
496 needed
= sizeof(ip_stat
);
497 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
499 ERR ("failed to get ipstat\n");
500 return ERROR_NOT_SUPPORTED
;
503 needed
= sizeof(ip_ttl
);
504 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
506 ERR ("failed to get ip Default TTL\n");
507 return ERROR_NOT_SUPPORTED
;
510 needed
= sizeof(ip_forwarding
);
511 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
513 ERR ("failed to get ip forwarding\n");
514 return ERROR_NOT_SUPPORTED
;
517 stats
->dwForwarding
= ip_forwarding
;
518 stats
->dwDefaultTTL
= ip_ttl
;
519 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
520 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
521 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
522 stats
->dwInReceives
= ip_stat
.ips_total
;
523 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
524 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
525 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
526 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
527 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
528 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
529 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
530 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
531 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
532 stats
->dwOutRequests
= ip_stat
.ips_localout
;
533 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
540 return ERROR_INVALID_PARAMETER
;
542 memset(stats
, 0, sizeof(MIB_IPSTATS
));
543 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
544 stats
->dwNumRoutes
= getNumRoutes();
546 /* get most of these stats from /proc/net/snmp, no error if can't */
547 fp
= fopen("/proc/net/snmp", "r");
549 static const char hdr
[] = "Ip:";
550 char buf
[512] = { 0 }, *ptr
;
553 ptr
= fgets(buf
, sizeof(buf
), fp
);
554 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
556 /* last line was a header, get another */
557 ptr
= fgets(buf
, sizeof(buf
), fp
);
558 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
563 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
567 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
571 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
575 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
579 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
583 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
587 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
591 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
595 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
599 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
603 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
607 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
611 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
615 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
619 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
623 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
627 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
631 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
635 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
638 /* hmm, no routingDiscards */
645 ERR ("unimplemented!\n");
646 return ERROR_NOT_SUPPORTED
;
653 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
655 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
656 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
658 #define TCPTV_REXMTMAX 128
660 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
661 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
663 struct tcpstat tcp_stat
;
667 return ERROR_INVALID_PARAMETER
;
668 needed
= sizeof(tcp_stat
);
670 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) == -1)
672 ERR ("failed to get tcpstat\n");
673 return ERROR_NOT_SUPPORTED
;
676 stats
->dwRtoAlgorithm
= MIB_TCP_RTO_VANJ
;
677 stats
->dwRtoMin
= TCPTV_MIN
;
678 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
679 stats
->dwMaxConn
= -1;
680 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
681 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
682 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
683 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
684 stats
->dwCurrEstab
= 0;
685 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
686 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
687 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
688 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
689 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
690 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
698 return ERROR_INVALID_PARAMETER
;
700 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
702 /* get from /proc/net/snmp, no error if can't */
703 fp
= fopen("/proc/net/snmp", "r");
705 static const char hdr
[] = "Tcp:";
706 char buf
[512] = { 0 }, *ptr
;
710 ptr
= fgets(buf
, sizeof(buf
), fp
);
711 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
713 /* last line was a header, get another */
714 ptr
= fgets(buf
, sizeof(buf
), fp
);
715 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
720 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
724 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
728 stats
->dwRtoMax
= strtoul(ptr
, &endPtr
, 10);
732 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
736 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
740 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
744 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
748 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
752 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
756 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
760 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
764 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
768 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
772 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
775 stats
->dwNumConns
= getNumTcpEntries();
782 ERR ("unimplemented!\n");
783 return ERROR_NOT_SUPPORTED
;
790 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
792 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
793 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
794 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
795 struct udpstat udp_stat
;
798 return ERROR_INVALID_PARAMETER
;
800 needed
= sizeof(udp_stat
);
802 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) == -1)
804 ERR ("failed to get udpstat\n");
805 return ERROR_NOT_SUPPORTED
;
808 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
809 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
810 stats
->dwNoPorts
= udp_stat
.udps_noport
;
811 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
812 stats
->dwNumAddrs
= getNumUdpEntries();
819 return ERROR_INVALID_PARAMETER
;
821 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
823 /* get from /proc/net/snmp, no error if can't */
824 fp
= fopen("/proc/net/snmp", "r");
826 static const char hdr
[] = "Udp:";
827 char buf
[512] = { 0 }, *ptr
;
831 ptr
= fgets(buf
, sizeof(buf
), fp
);
832 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
834 /* last line was a header, get another */
835 ptr
= fgets(buf
, sizeof(buf
), fp
);
836 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
841 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
845 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
849 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
853 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
857 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
866 ERR ("unimplemented!\n");
867 return ERROR_NOT_SUPPORTED
;
874 static DWORD
getNumWithOneHeader(const char *filename
)
876 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
879 struct xinpgen
*pXIG
, *pOrigXIG
;
881 DWORD NumEntries
= 0;
883 if (!strcmp (filename
, "net.inet.tcp.pcblist"))
884 Protocol
= IPPROTO_TCP
;
885 else if (!strcmp (filename
, "net.inet.udp.pcblist"))
886 Protocol
= IPPROTO_UDP
;
889 ERR ("Unsupported mib '%s', needs protocol mapping\n",
894 if (sysctlbyname (filename
, NULL
, &Len
, NULL
, 0) < 0)
896 WARN ("Unable to read '%s' via sysctlbyname\n", filename
);
900 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
903 ERR ("Out of memory!\n");
907 if (sysctlbyname (filename
, Buf
, &Len
, NULL
, 0) < 0)
909 ERR ("Failure to read '%s' via sysctlbyname!\n", filename
);
910 HeapFree (GetProcessHeap (), 0, Buf
);
914 /* Might be nothing here; first entry is just a header it seems */
915 if (Len
<= sizeof (struct xinpgen
))
917 HeapFree (GetProcessHeap (), 0, Buf
);
921 pOrigXIG
= (struct xinpgen
*)Buf
;
924 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
925 pXIG
->xig_len
> sizeof (struct xinpgen
);
926 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
928 struct tcpcb
*pTCPData
= NULL
;
929 struct inpcb
*pINData
;
930 struct xsocket
*pSockData
;
932 if (Protocol
== IPPROTO_TCP
)
934 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
935 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
936 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
940 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
941 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
944 /* Ignore sockets for other protocols */
945 if (pSockData
->xso_protocol
!= Protocol
)
948 /* Ignore PCBs that were freed while generating the data */
949 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
952 /* we're only interested in IPv4 addresses */
953 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
954 (pINData
->inp_vflag
& INP_IPV6
))
957 /* If all 0's, skip it */
958 if (!pINData
->inp_laddr
.s_addr
&&
959 !pINData
->inp_lport
&&
960 !pINData
->inp_faddr
.s_addr
&&
967 HeapFree (GetProcessHeap (), 0, Buf
);
973 fp
= fopen(filename
, "r");
975 char buf
[512] = { 0 }, *ptr
;
978 ptr
= fgets(buf
, sizeof(buf
), fp
);
981 ptr
= fgets(buf
, sizeof(buf
), fp
);
989 ERR ("Unable to open '%s' to count entries!\n", filename
);
995 DWORD
getNumRoutes(void)
997 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
998 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1000 char *buf
, *lim
, *next
;
1001 struct rt_msghdr
*rtm
;
1002 DWORD RouteCount
= 0;
1004 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1006 ERR ("sysctl 1 failed!\n");
1010 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1013 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1015 ERR ("sysctl 2 failed!\n");
1016 HeapFree (GetProcessHeap (), 0, buf
);
1021 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1023 rtm
= (struct rt_msghdr
*)next
;
1025 if (rtm
->rtm_type
!= RTM_GET
)
1027 WARN ("Got unexpected message type 0x%x!\n",
1032 /* Ignore all entries except for gateway routes which aren't
1034 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) || (rtm
->rtm_flags
& RTF_MULTICAST
))
1040 HeapFree (GetProcessHeap (), 0, buf
);
1043 return getNumWithOneHeader("/proc/net/route");
1047 DWORD
getRouteTable(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, HANDLE heap
,
1052 if (!ppIpForwardTable
)
1053 ret
= ERROR_INVALID_PARAMETER
;
1055 DWORD numRoutes
= getNumRoutes();
1056 DWORD size
= sizeof(MIB_IPFORWARDTABLE
);
1057 PMIB_IPFORWARDTABLE table
;
1060 size
+= (numRoutes
- 1) * sizeof(MIB_IPFORWARDROW
);
1061 table
= HeapAlloc(heap
, flags
, size
);
1063 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1064 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1066 char *buf
, *lim
, *next
, *addrPtr
;
1067 struct rt_msghdr
*rtm
;
1069 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1071 ERR ("sysctl 1 failed!\n");
1072 HeapFree (GetProcessHeap (), 0, table
);
1076 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1079 HeapFree (GetProcessHeap (), 0, table
);
1080 return ERROR_OUTOFMEMORY
;
1083 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1085 ERR ("sysctl 2 failed!\n");
1086 HeapFree (GetProcessHeap (), 0, table
);
1087 HeapFree (GetProcessHeap (), 0, buf
);
1091 *ppIpForwardTable
= table
;
1092 table
->dwNumEntries
= 0;
1095 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1099 rtm
= (struct rt_msghdr
*)next
;
1101 if (rtm
->rtm_type
!= RTM_GET
)
1103 WARN ("Got unexpected message type 0x%x!\n",
1108 /* Ignore all entries except for gateway routes which aren't
1110 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1111 (rtm
->rtm_flags
& RTF_MULTICAST
))
1114 memset (&table
->table
[table
->dwNumEntries
], 0,
1115 sizeof (MIB_IPFORWARDROW
));
1116 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= rtm
->rtm_index
;
1117 table
->table
[table
->dwNumEntries
].dwForwardType
=
1118 MIB_IPROUTE_TYPE_INDIRECT
;
1119 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1120 rtm
->rtm_rmx
.rmx_hopcount
;
1121 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1124 addrPtr
= (char *)(rtm
+ 1);
1126 for (i
= 1; i
; i
<<= 1)
1128 struct sockaddr
*sa
;
1131 if (!(i
& rtm
->rtm_addrs
))
1134 sa
= (struct sockaddr
*)addrPtr
;
1135 ADVANCE (addrPtr
, sa
);
1137 /* default routes are encoded by length-zero sockaddr */
1138 if (sa
->sa_len
== 0)
1140 else if (sa
->sa_family
!= AF_INET
)
1142 WARN ("Received unsupported sockaddr family 0x%x\n",
1148 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1150 addr
= sin
->sin_addr
.s_addr
;
1156 table
->table
[table
->dwNumEntries
].dwForwardDest
= addr
;
1160 table
->table
[table
->dwNumEntries
].dwForwardNextHop
= addr
;
1164 table
->table
[table
->dwNumEntries
].dwForwardMask
= addr
;
1168 WARN ("Unexpected address type 0x%x\n", i
);
1172 table
->dwNumEntries
++;
1175 HeapFree (GetProcessHeap (), 0, buf
);
1181 *ppIpForwardTable
= table
;
1182 table
->dwNumEntries
= 0;
1183 /* get from /proc/net/route, no error if can't */
1184 fp
= fopen("/proc/net/route", "r");
1186 char buf
[512] = { 0 }, *ptr
;
1188 /* skip header line */
1189 ptr
= fgets(buf
, sizeof(buf
), fp
);
1190 while (ptr
&& table
->dwNumEntries
< numRoutes
) {
1191 memset(&table
->table
[table
->dwNumEntries
], 0,
1192 sizeof(MIB_IPFORWARDROW
));
1193 ptr
= fgets(buf
, sizeof(buf
), fp
);
1197 while (!isspace(*ptr
))
1201 if (getInterfaceIndexByName(buf
, &index
) == NO_ERROR
) {
1204 table
->table
[table
->dwNumEntries
].dwForwardIfIndex
= index
;
1206 table
->table
[table
->dwNumEntries
].dwForwardDest
=
1207 strtoul(ptr
, &endPtr
, 16);
1211 table
->table
[table
->dwNumEntries
].dwForwardNextHop
=
1212 strtoul(ptr
, &endPtr
, 16);
1216 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1218 if (!(flags
& RTF_UP
))
1219 table
->table
[table
->dwNumEntries
].dwForwardType
=
1220 MIB_IPROUTE_TYPE_INVALID
;
1221 else if (flags
& RTF_GATEWAY
)
1222 table
->table
[table
->dwNumEntries
].dwForwardType
=
1223 MIB_IPROUTE_TYPE_INDIRECT
;
1225 table
->table
[table
->dwNumEntries
].dwForwardType
=
1226 MIB_IPROUTE_TYPE_DIRECT
;
1230 strtoul(ptr
, &endPtr
, 16); /* refcount, skip */
1234 strtoul(ptr
, &endPtr
, 16); /* use, skip */
1238 table
->table
[table
->dwNumEntries
].dwForwardMetric1
=
1239 strtoul(ptr
, &endPtr
, 16);
1243 table
->table
[table
->dwNumEntries
].dwForwardMask
=
1244 strtoul(ptr
, &endPtr
, 16);
1247 /* FIXME: other protos might be appropriate, e.g. the default
1248 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1249 table
->table
[table
->dwNumEntries
].dwForwardProto
=
1251 table
->dwNumEntries
++;
1259 ERR ("unimplemented!\n");
1260 return ERROR_NOT_SUPPORTED
;
1265 ret
= ERROR_OUTOFMEMORY
;
1270 DWORD
getNumArpEntries(void)
1272 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1273 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1274 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1275 DWORD arpEntries
= 0;
1277 char *buf
, *lim
, *next
;
1278 struct rt_msghdr
*rtm
;
1279 struct sockaddr_inarp
*sinarp
;
1280 struct sockaddr_dl
*sdl
;
1282 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1284 ERR ("failed to get size of arp table\n");
1288 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1291 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1293 ERR ("failed to get arp table\n");
1294 HeapFree (GetProcessHeap (), 0, buf
);
1302 rtm
= (struct rt_msghdr
*)next
;
1303 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1304 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1305 if(sdl
->sdl_alen
) /* arp entry */
1307 next
+= rtm
->rtm_msglen
;
1309 HeapFree (GetProcessHeap (), 0, buf
);
1312 return getNumWithOneHeader("/proc/net/arp");
1315 DWORD
getArpTable(PMIB_IPNETTABLE
*ppIpNetTable
, HANDLE heap
, DWORD flags
)
1317 DWORD ret
= NO_ERROR
;
1319 ret
= ERROR_INVALID_PARAMETER
;
1321 DWORD numEntries
= getNumArpEntries();
1322 DWORD size
= sizeof(MIB_IPNETTABLE
);
1323 PMIB_IPNETTABLE table
;
1326 size
+= (numEntries
- 1) * sizeof(MIB_IPNETROW
);
1327 table
= HeapAlloc(heap
, flags
, size
);
1328 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1331 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1332 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1334 char *buf
, *lim
, *next
;
1335 struct rt_msghdr
*rtm
;
1336 struct sockaddr_inarp
*sinarp
;
1337 struct sockaddr_dl
*sdl
;
1339 *ppIpNetTable
= table
;
1340 table
->dwNumEntries
= 0;
1342 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1344 ERR ("failed to get size of arp table\n");
1345 return ERROR_NOT_SUPPORTED
;
1348 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1349 if (!buf
) return ERROR_OUTOFMEMORY
;
1351 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1353 ERR ("failed to get arp table\n");
1354 HeapFree (GetProcessHeap (), 0, buf
);
1355 return ERROR_NOT_SUPPORTED
;
1362 rtm
= (struct rt_msghdr
*)next
;
1363 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1364 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1365 if(sdl
->sdl_alen
) /* arp entry */
1367 DWORD byte
= strtoul(&sdl
->sdl_data
[sdl
->sdl_alen
], NULL
, 16);
1368 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1369 table
->table
[table
->dwNumEntries
].dwAddr
= sinarp
->sin_addr
.s_addr
;
1370 table
->table
[table
->dwNumEntries
].dwIndex
= sdl
->sdl_index
;
1371 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
= sdl
->sdl_alen
;
1373 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1374 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1376 if(rtm
->rtm_rmx
.rmx_expire
== 0)
1377 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_STATIC
;
1378 else if(sinarp
->sin_other
& SIN_PROXY
)
1379 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1380 else if(rtm
->rtm_rmx
.rmx_expire
!= 0)
1381 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1383 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_INVALID
;
1385 table
->dwNumEntries
++;
1387 next
+= rtm
->rtm_msglen
;
1389 HeapFree (GetProcessHeap (), 0, buf
);
1392 ret
= ERROR_OUTOFMEMORY
;
1398 *ppIpNetTable
= table
;
1399 table
->dwNumEntries
= 0;
1400 /* get from /proc/net/arp, no error if can't */
1401 fp
= fopen("/proc/net/arp", "r");
1403 char buf
[512] = { 0 }, *ptr
;
1405 /* skip header line */
1406 ptr
= fgets(buf
, sizeof(buf
), fp
);
1407 while (ptr
&& table
->dwNumEntries
< numEntries
) {
1408 ptr
= fgets(buf
, sizeof(buf
), fp
);
1412 memset(&table
->table
[table
->dwNumEntries
], 0, sizeof(MIB_IPNETROW
));
1413 table
->table
[table
->dwNumEntries
].dwAddr
= inet_addr(ptr
);
1414 while (ptr
&& *ptr
&& !isspace(*ptr
))
1418 strtoul(ptr
, &endPtr
, 16); /* hw type (skip) */
1422 DWORD flags
= strtoul(ptr
, &endPtr
, 16);
1425 if (flags
& ATF_COM
)
1426 table
->table
[table
->dwNumEntries
].dwType
=
1427 MIB_IPNET_TYPE_DYNAMIC
;
1431 if (flags
& ATF_PERM
)
1432 table
->table
[table
->dwNumEntries
].dwType
=
1433 MIB_IPNET_TYPE_STATIC
;
1436 table
->table
[table
->dwNumEntries
].dwType
= MIB_IPNET_TYPE_OTHER
;
1440 while (ptr
&& *ptr
&& isspace(*ptr
))
1442 while (ptr
&& *ptr
&& !isspace(*ptr
)) {
1443 DWORD byte
= strtoul(ptr
, &endPtr
, 16);
1445 if (endPtr
&& *endPtr
) {
1447 table
->table
[table
->dwNumEntries
].bPhysAddr
[
1448 table
->table
[table
->dwNumEntries
].dwPhysAddrLen
++] =
1454 strtoul(ptr
, &endPtr
, 16); /* mask (skip) */
1457 getInterfaceIndexByName(ptr
,
1458 &table
->table
[table
->dwNumEntries
].dwIndex
);
1459 table
->dwNumEntries
++;
1465 ret
= ERROR_NOT_SUPPORTED
;
1468 ret
= ERROR_OUTOFMEMORY
;
1473 DWORD
getNumUdpEntries(void)
1475 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1476 return getNumWithOneHeader ("net.inet.udp.pcblist");
1478 return getNumWithOneHeader("/proc/net/udp");
1482 static MIB_UDPTABLE
*append_udp_row( HANDLE heap
, DWORD flags
, MIB_UDPTABLE
*table
,
1483 DWORD
*count
, const MIB_UDPROW
*row
)
1485 if (table
->dwNumEntries
>= *count
)
1487 MIB_UDPTABLE
*new_table
;
1488 DWORD new_count
= table
->dwNumEntries
* 2;
1490 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_UDPTABLE
, table
[new_count
] ))))
1492 HeapFree( heap
, 0, table
);
1498 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1502 DWORD
getUdpTable(PMIB_UDPTABLE
*ppUdpTable
, HANDLE heap
, DWORD flags
)
1504 MIB_UDPTABLE
*table
;
1506 DWORD ret
= NO_ERROR
, count
= 16;
1508 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
1510 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_UDPTABLE
, table
[count
] ))))
1511 return ERROR_OUTOFMEMORY
;
1513 table
->dwNumEntries
= 0;
1519 if ((fp
= fopen("/proc/net/udp", "r")))
1521 char buf
[512], *ptr
;
1524 /* skip header line */
1525 ptr
= fgets(buf
, sizeof(buf
), fp
);
1526 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1528 if (sscanf( ptr
, "%u: %x:%x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
) != 3)
1530 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1531 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
)))
1536 else ret
= ERROR_NOT_SUPPORTED
;
1539 FIXME( "not implemented\n" );
1540 ret
= ERROR_NOT_SUPPORTED
;
1543 if (!table
) return ERROR_OUTOFMEMORY
;
1544 if (!ret
) *ppUdpTable
= table
;
1545 else HeapFree( heap
, flags
, table
);
1550 DWORD
getNumTcpEntries(void)
1552 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
1553 return getNumWithOneHeader ("net.inet.tcp.pcblist");
1555 return getNumWithOneHeader ("/proc/net/tcp");
1559 static MIB_TCPTABLE
*append_tcp_row( HANDLE heap
, DWORD flags
, MIB_TCPTABLE
*table
,
1560 DWORD
*count
, const MIB_TCPROW
*row
)
1562 if (table
->dwNumEntries
>= *count
)
1564 MIB_TCPTABLE
*new_table
;
1565 DWORD new_count
= table
->dwNumEntries
* 2;
1567 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_TCPTABLE
, table
[new_count
] ))))
1569 HeapFree( heap
, 0, table
);
1575 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1580 /* Why not a lookup table? Because the TCPS_* constants are different
1581 on different platforms */
1582 static DWORD
TCPStateToMIBState (int state
)
1586 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1587 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1588 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1589 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1590 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1591 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1592 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1593 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1594 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1595 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1597 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1602 DWORD
getTcpTable(PMIB_TCPTABLE
*ppTcpTable
, HANDLE heap
, DWORD flags
)
1604 MIB_TCPTABLE
*table
;
1606 DWORD ret
= NO_ERROR
, count
= 16;
1608 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
1610 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_TCPTABLE
, table
[count
] ))))
1611 return ERROR_OUTOFMEMORY
;
1613 table
->dwNumEntries
= 0;
1619 if ((fp
= fopen("/proc/net/tcp", "r")))
1621 char buf
[512], *ptr
;
1624 /* skip header line */
1625 ptr
= fgets(buf
, sizeof(buf
), fp
);
1626 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1628 if (sscanf( ptr
, "%x: %x:%x %x:%x %x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
,
1629 &row
.dwRemoteAddr
, &row
.dwRemotePort
, &row
.dwState
) != 6)
1631 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1632 row
.dwRemotePort
= htons( row
.dwRemotePort
);
1633 row
.dwState
= TCPStateToMIBState( row
.dwState
);
1634 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
)))
1639 else ret
= ERROR_NOT_SUPPORTED
;
1641 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1645 struct xinpgen
*pXIG
, *pOrigXIG
;
1647 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1649 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1650 ret
= ERROR_NOT_SUPPORTED
;
1654 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1657 ret
= ERROR_OUTOFMEMORY
;
1661 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1663 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1664 ret
= ERROR_NOT_SUPPORTED
;
1668 /* Might be nothing here; first entry is just a header it seems */
1669 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1671 pOrigXIG
= (struct xinpgen
*)Buf
;
1674 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1675 pXIG
->xig_len
> sizeof (struct xinpgen
);
1676 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1678 struct tcpcb
*pTCPData
= NULL
;
1679 struct inpcb
*pINData
;
1680 struct xsocket
*pSockData
;
1682 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1683 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1684 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1686 /* Ignore sockets for other protocols */
1687 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1690 /* Ignore PCBs that were freed while generating the data */
1691 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1694 /* we're only interested in IPv4 addresses */
1695 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1696 (pINData
->inp_vflag
& INP_IPV6
))
1699 /* If all 0's, skip it */
1700 if (!pINData
->inp_laddr
.s_addr
&&
1701 !pINData
->inp_lport
&&
1702 !pINData
->inp_faddr
.s_addr
&&
1703 !pINData
->inp_fport
)
1706 /* Fill in structure details */
1707 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1708 row
.dwLocalPort
= pINData
->inp_lport
;
1709 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
1710 row
.dwRemotePort
= pINData
->inp_fport
;
1711 row
.dwState
= TCPStateToMIBState (pTCPData
->t_state
);
1712 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1716 HeapFree (GetProcessHeap (), 0, Buf
);
1719 FIXME( "not implemented\n" );
1720 ret
= ERROR_NOT_SUPPORTED
;
1723 if (!table
) return ERROR_OUTOFMEMORY
;
1724 if (!ret
) *ppTcpTable
= table
;
1725 else HeapFree( heap
, flags
, table
);