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
;
538 MIB_IPFORWARDTABLE
*fwd_table
;
541 return ERROR_INVALID_PARAMETER
;
543 memset(stats
, 0, sizeof(MIB_IPSTATS
));
544 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
545 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table
, FALSE
, GetProcessHeap(), 0 ))
547 stats
->dwNumRoutes
= fwd_table
->dwNumEntries
;
548 HeapFree( GetProcessHeap(), 0, fwd_table
);
551 /* get most of these stats from /proc/net/snmp, no error if can't */
552 fp
= fopen("/proc/net/snmp", "r");
554 static const char hdr
[] = "Ip:";
555 char buf
[512] = { 0 }, *ptr
;
558 ptr
= fgets(buf
, sizeof(buf
), fp
);
559 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
561 /* last line was a header, get another */
562 ptr
= fgets(buf
, sizeof(buf
), fp
);
563 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
568 stats
->dwForwarding
= strtoul(ptr
, &endPtr
, 10);
572 stats
->dwDefaultTTL
= strtoul(ptr
, &endPtr
, 10);
576 stats
->dwInReceives
= strtoul(ptr
, &endPtr
, 10);
580 stats
->dwInHdrErrors
= strtoul(ptr
, &endPtr
, 10);
584 stats
->dwInAddrErrors
= strtoul(ptr
, &endPtr
, 10);
588 stats
->dwForwDatagrams
= strtoul(ptr
, &endPtr
, 10);
592 stats
->dwInUnknownProtos
= strtoul(ptr
, &endPtr
, 10);
596 stats
->dwInDiscards
= strtoul(ptr
, &endPtr
, 10);
600 stats
->dwInDelivers
= strtoul(ptr
, &endPtr
, 10);
604 stats
->dwOutRequests
= strtoul(ptr
, &endPtr
, 10);
608 stats
->dwOutDiscards
= strtoul(ptr
, &endPtr
, 10);
612 stats
->dwOutNoRoutes
= strtoul(ptr
, &endPtr
, 10);
616 stats
->dwReasmTimeout
= strtoul(ptr
, &endPtr
, 10);
620 stats
->dwReasmReqds
= strtoul(ptr
, &endPtr
, 10);
624 stats
->dwReasmOks
= strtoul(ptr
, &endPtr
, 10);
628 stats
->dwReasmFails
= strtoul(ptr
, &endPtr
, 10);
632 stats
->dwFragOks
= strtoul(ptr
, &endPtr
, 10);
636 stats
->dwFragFails
= strtoul(ptr
, &endPtr
, 10);
640 stats
->dwFragCreates
= strtoul(ptr
, &endPtr
, 10);
643 /* hmm, no routingDiscards */
650 ERR ("unimplemented!\n");
651 return ERROR_NOT_SUPPORTED
;
658 DWORD
getTCPStats(MIB_TCPSTATS
*stats
)
660 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
661 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
663 #define TCPTV_REXMTMAX 128
665 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
666 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
668 struct tcpstat tcp_stat
;
672 return ERROR_INVALID_PARAMETER
;
673 needed
= sizeof(tcp_stat
);
675 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) == -1)
677 ERR ("failed to get tcpstat\n");
678 return ERROR_NOT_SUPPORTED
;
681 stats
->dwRtoAlgorithm
= MIB_TCP_RTO_VANJ
;
682 stats
->dwRtoMin
= TCPTV_MIN
;
683 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
684 stats
->dwMaxConn
= -1;
685 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
686 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
687 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
688 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
689 stats
->dwCurrEstab
= 0;
690 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
691 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
692 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
693 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
694 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
695 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
701 MIB_TCPTABLE
*tcp_table
;
704 return ERROR_INVALID_PARAMETER
;
706 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
708 /* get from /proc/net/snmp, no error if can't */
709 fp
= fopen("/proc/net/snmp", "r");
711 static const char hdr
[] = "Tcp:";
712 char buf
[512] = { 0 }, *ptr
;
716 ptr
= fgets(buf
, sizeof(buf
), fp
);
717 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
719 /* last line was a header, get another */
720 ptr
= fgets(buf
, sizeof(buf
), fp
);
721 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
726 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
730 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
734 stats
->dwRtoMax
= strtoul(ptr
, &endPtr
, 10);
738 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
742 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
746 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
750 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
754 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
758 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
762 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
766 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
770 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
774 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
778 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
781 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
783 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
784 HeapFree( GetProcessHeap(), 0, tcp_table
);
792 ERR ("unimplemented!\n");
793 return ERROR_NOT_SUPPORTED
;
800 DWORD
getUDPStats(MIB_UDPSTATS
*stats
)
802 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
803 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
804 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
805 struct udpstat udp_stat
;
806 MIB_UDPTABLE
*udp_table
;
809 return ERROR_INVALID_PARAMETER
;
811 needed
= sizeof(udp_stat
);
813 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) == -1)
815 ERR ("failed to get udpstat\n");
816 return ERROR_NOT_SUPPORTED
;
819 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
820 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
821 stats
->dwNoPorts
= udp_stat
.udps_noport
;
822 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
823 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
825 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
826 HeapFree( GetProcessHeap(), 0, udp_table
);
828 else stats
->dwNumAddrs
= 0;
835 return ERROR_INVALID_PARAMETER
;
837 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
839 /* get from /proc/net/snmp, no error if can't */
840 fp
= fopen("/proc/net/snmp", "r");
842 static const char hdr
[] = "Udp:";
843 char buf
[512] = { 0 }, *ptr
;
847 ptr
= fgets(buf
, sizeof(buf
), fp
);
848 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
850 /* last line was a header, get another */
851 ptr
= fgets(buf
, sizeof(buf
), fp
);
852 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
857 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
861 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
865 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
869 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
873 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
882 ERR ("unimplemented!\n");
883 return ERROR_NOT_SUPPORTED
;
891 static MIB_IPFORWARDTABLE
*append_ipforward_row( HANDLE heap
, DWORD flags
, MIB_IPFORWARDTABLE
*table
,
892 DWORD
*count
, const MIB_IPFORWARDROW
*row
)
894 if (table
->dwNumEntries
>= *count
)
896 MIB_IPFORWARDTABLE
*new_table
;
897 DWORD new_count
= table
->dwNumEntries
* 2;
899 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
900 FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[new_count
] ))))
902 HeapFree( heap
, 0, table
);
908 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
912 static int compare_ipforward_rows(const void *a
, const void *b
)
914 const MIB_IPFORWARDROW
*rowA
= a
;
915 const MIB_IPFORWARDROW
*rowB
= b
;
918 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
919 if ((ret
= rowA
->dwForwardProto
- rowB
->dwForwardProto
) != 0) return ret
;
920 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
921 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
924 /******************************************************************
925 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
927 * Get the route table.
928 * Like GetIpForwardTable(), but allocate the returned table from heap.
931 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
932 * allocated and returned.
933 * bOrder [In] whether to sort the table
934 * heap [In] heap from which the table is allocated
935 * flags [In] flags to HeapAlloc
938 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
939 * on failure, NO_ERROR on success.
941 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, BOOL bOrder
,
942 HANDLE heap
, DWORD flags
)
944 MIB_IPFORWARDTABLE
*table
;
945 MIB_IPFORWARDROW row
;
946 DWORD ret
= NO_ERROR
, count
= 16;
948 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable
, bOrder
, heap
, flags
);
950 if (!ppIpForwardTable
) return ERROR_INVALID_PARAMETER
;
952 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[count
] ))))
953 return ERROR_OUTOFMEMORY
;
955 table
->dwNumEntries
= 0;
961 if ((fp
= fopen("/proc/net/route", "r")))
966 /* skip header line */
967 ptr
= fgets(buf
, sizeof(buf
), fp
);
968 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
970 memset( &row
, 0, sizeof(row
) );
972 while (!isspace(*ptr
)) ptr
++;
974 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
977 row
.dwForwardDest
= strtoul(ptr
, &ptr
, 16);
978 row
.dwForwardNextHop
= strtoul(ptr
+ 1, &ptr
, 16);
979 flags
= strtoul(ptr
+ 1, &ptr
, 16);
981 if (!(flags
& RTF_UP
)) row
.dwForwardType
= MIB_IPROUTE_TYPE_INVALID
;
982 else if (flags
& RTF_GATEWAY
) row
.dwForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
983 else row
.dwForwardType
= MIB_IPROUTE_TYPE_DIRECT
;
985 strtoul(ptr
+ 1, &ptr
, 16); /* refcount, skip */
986 strtoul(ptr
+ 1, &ptr
, 16); /* use, skip */
987 row
.dwForwardMetric1
= strtoul(ptr
+ 1, &ptr
, 16);
988 row
.dwForwardMask
= strtoul(ptr
+ 1, &ptr
, 16);
989 /* FIXME: other protos might be appropriate, e.g. the default
990 * route is typically set with MIB_IPPROTO_NETMGMT instead */
991 row
.dwForwardProto
= MIB_IPPROTO_LOCAL
;
993 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
998 else ret
= ERROR_NOT_SUPPORTED
;
1000 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1002 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1004 char *buf
= NULL
, *lim
, *next
, *addrPtr
;
1005 struct rt_msghdr
*rtm
;
1007 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1009 ERR ("sysctl 1 failed!\n");
1010 ret
= ERROR_NOT_SUPPORTED
;
1014 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1017 ret
= ERROR_OUTOFMEMORY
;
1021 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1023 ret
= ERROR_NOT_SUPPORTED
;
1028 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1032 rtm
= (struct rt_msghdr
*)next
;
1034 if (rtm
->rtm_type
!= RTM_GET
)
1036 WARN ("Got unexpected message type 0x%x!\n",
1041 /* Ignore all entries except for gateway routes which aren't
1043 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
1044 (rtm
->rtm_flags
& RTF_MULTICAST
))
1047 memset( &row
, 0, sizeof(row
) );
1048 row
.dwForwardIfIndex
= rtm
->rtm_index
;
1049 row
.dwForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1050 row
.dwForwardMetric1
= rtm
->rtm_rmx
.rmx_hopcount
;
1051 row
.dwForwardProto
= MIB_IPPROTO_LOCAL
;
1053 addrPtr
= (char *)(rtm
+ 1);
1055 for (i
= 1; i
; i
<<= 1)
1057 struct sockaddr
*sa
;
1060 if (!(i
& rtm
->rtm_addrs
))
1063 sa
= (struct sockaddr
*)addrPtr
;
1064 ADVANCE (addrPtr
, sa
);
1066 /* default routes are encoded by length-zero sockaddr */
1067 if (sa
->sa_len
== 0)
1069 else if (sa
->sa_family
!= AF_INET
)
1071 WARN ("Received unsupported sockaddr family 0x%x\n",
1077 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1079 addr
= sin
->sin_addr
.s_addr
;
1084 case RTA_DST
: row
.dwForwardDest
= addr
; break;
1085 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
1086 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
1088 WARN ("Unexpected address type 0x%x\n", i
);
1092 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1096 HeapFree( GetProcessHeap (), 0, buf
);
1099 FIXME( "not implemented\n" );
1100 ret
= ERROR_NOT_SUPPORTED
;
1103 if (!table
) return ERROR_OUTOFMEMORY
;
1106 if (bOrder
&& table
->dwNumEntries
)
1107 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipforward_rows
);
1108 *ppIpForwardTable
= table
;
1110 else HeapFree( heap
, flags
, table
);
1111 TRACE( "returning ret %u table %p\n", ret
, table
);
1115 static MIB_IPNETTABLE
*append_ipnet_row( HANDLE heap
, DWORD flags
, MIB_IPNETTABLE
*table
,
1116 DWORD
*count
, const MIB_IPNETROW
*row
)
1118 if (table
->dwNumEntries
>= *count
)
1120 MIB_IPNETTABLE
*new_table
;
1121 DWORD new_count
= table
->dwNumEntries
* 2;
1123 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
1124 FIELD_OFFSET(MIB_IPNETTABLE
, table
[new_count
] ))))
1126 HeapFree( heap
, 0, table
);
1132 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1136 static int compare_ipnet_rows(const void *a
, const void *b
)
1138 const MIB_IPNETROW
*rowA
= a
;
1139 const MIB_IPNETROW
*rowB
= b
;
1141 return ntohl(rowA
->dwAddr
) - ntohl(rowB
->dwAddr
);
1145 /******************************************************************
1146 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1148 * Get the IP-to-physical address mapping table.
1149 * Like GetIpNetTable(), but allocate the returned table from heap.
1152 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1153 * allocated and returned.
1154 * bOrder [In] whether to sort the table
1155 * heap [In] heap from which the table is allocated
1156 * flags [In] flags to HeapAlloc
1159 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1160 * on failure, NO_ERROR on success.
1162 DWORD WINAPI
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE
*ppIpNetTable
, BOOL bOrder
,
1163 HANDLE heap
, DWORD flags
)
1165 MIB_IPNETTABLE
*table
;
1167 DWORD ret
= NO_ERROR
, count
= 16;
1169 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable
, bOrder
, heap
, flags
);
1171 if (!ppIpNetTable
) return ERROR_INVALID_PARAMETER
;
1173 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPNETTABLE
, table
[count
] ))))
1174 return ERROR_OUTOFMEMORY
;
1176 table
->dwNumEntries
= 0;
1182 if ((fp
= fopen("/proc/net/arp", "r")))
1184 char buf
[512], *ptr
;
1187 /* skip header line */
1188 ptr
= fgets(buf
, sizeof(buf
), fp
);
1189 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1191 memset( &row
, 0, sizeof(row
) );
1193 row
.dwAddr
= inet_addr(ptr
);
1194 while (*ptr
&& !isspace(*ptr
)) ptr
++;
1195 strtoul(ptr
+ 1, &ptr
, 16); /* hw type (skip) */
1196 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1199 if (flags
& ATF_COM
) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1203 if (flags
& ATF_PERM
) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
1206 row
.dwType
= MIB_IPNET_TYPE_OTHER
;
1208 while (*ptr
&& isspace(*ptr
)) ptr
++;
1209 while (*ptr
&& !isspace(*ptr
))
1211 row
.bPhysAddr
[row
.dwPhysAddrLen
++] = strtoul(ptr
, &ptr
, 16);
1214 while (*ptr
&& isspace(*ptr
)) ptr
++;
1215 while (*ptr
&& !isspace(*ptr
)) ptr
++; /* mask (skip) */
1216 while (*ptr
&& isspace(*ptr
)) ptr
++;
1217 getInterfaceIndexByName(ptr
, &row
.dwIndex
);
1219 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1224 else ret
= ERROR_NOT_SUPPORTED
;
1226 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1228 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1229 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1231 char *buf
= NULL
, *lim
, *next
;
1232 struct rt_msghdr
*rtm
;
1233 struct sockaddr_inarp
*sinarp
;
1234 struct sockaddr_dl
*sdl
;
1236 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1238 ERR ("failed to get arp table\n");
1239 ret
= ERROR_NOT_SUPPORTED
;
1243 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1246 ret
= ERROR_OUTOFMEMORY
;
1250 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1252 ret
= ERROR_NOT_SUPPORTED
;
1260 rtm
= (struct rt_msghdr
*)next
;
1261 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1262 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1263 if(sdl
->sdl_alen
) /* arp entry */
1265 memset( &row
, 0, sizeof(row
) );
1266 row
.dwAddr
= sinarp
->sin_addr
.s_addr
;
1267 row
.dwIndex
= sdl
->sdl_index
;
1268 row
.dwPhysAddrLen
= min( 8, sdl
->sdl_alen
);
1269 memcpy( row
.bPhysAddr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], row
.dwPhysAddrLen
);
1270 if(rtm
->rtm_rmx
.rmx_expire
== 0) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
1271 else if(sinarp
->sin_other
& SIN_PROXY
) row
.dwType
= MIB_IPNET_TYPE_OTHER
;
1272 else if(rtm
->rtm_rmx
.rmx_expire
!= 0) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1273 else row
.dwType
= MIB_IPNET_TYPE_INVALID
;
1275 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1278 next
+= rtm
->rtm_msglen
;
1281 HeapFree( GetProcessHeap (), 0, buf
);
1284 FIXME( "not implemented\n" );
1285 ret
= ERROR_NOT_SUPPORTED
;
1288 if (!table
) return ERROR_OUTOFMEMORY
;
1291 if (bOrder
&& table
->dwNumEntries
)
1292 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipnet_rows
);
1293 *ppIpNetTable
= table
;
1295 else HeapFree( heap
, flags
, table
);
1296 TRACE( "returning ret %u table %p\n", ret
, table
);
1301 static MIB_UDPTABLE
*append_udp_row( HANDLE heap
, DWORD flags
, MIB_UDPTABLE
*table
,
1302 DWORD
*count
, const MIB_UDPROW
*row
)
1304 if (table
->dwNumEntries
>= *count
)
1306 MIB_UDPTABLE
*new_table
;
1307 DWORD new_count
= table
->dwNumEntries
* 2;
1309 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_UDPTABLE
, table
[new_count
] ))))
1311 HeapFree( heap
, 0, table
);
1317 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1321 static int compare_udp_rows(const void *a
, const void *b
)
1323 const MIB_UDPROW
*rowA
= a
;
1324 const MIB_UDPROW
*rowB
= b
;
1327 if ((ret
= rowA
->dwLocalAddr
- rowB
->dwLocalAddr
) != 0) return ret
;
1328 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
1332 /******************************************************************
1333 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1335 * Get the UDP listener table.
1336 * Like GetUdpTable(), but allocate the returned table from heap.
1339 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1340 * allocated and returned.
1341 * bOrder [In] whether to sort the table
1342 * heap [In] heap from which the table is allocated
1343 * flags [In] flags to HeapAlloc
1346 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1347 * returns otherwise.
1349 DWORD WINAPI
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE
*ppUdpTable
, BOOL bOrder
,
1350 HANDLE heap
, DWORD flags
)
1352 MIB_UDPTABLE
*table
;
1354 DWORD ret
= NO_ERROR
, count
= 16;
1356 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable
, bOrder
, heap
, flags
);
1358 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
1360 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_UDPTABLE
, table
[count
] ))))
1361 return ERROR_OUTOFMEMORY
;
1363 table
->dwNumEntries
= 0;
1369 if ((fp
= fopen("/proc/net/udp", "r")))
1371 char buf
[512], *ptr
;
1374 /* skip header line */
1375 ptr
= fgets(buf
, sizeof(buf
), fp
);
1376 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1378 if (sscanf( ptr
, "%u: %x:%x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
) != 3)
1380 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1381 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
)))
1386 else ret
= ERROR_NOT_SUPPORTED
;
1389 FIXME( "not implemented\n" );
1390 ret
= ERROR_NOT_SUPPORTED
;
1393 if (!table
) return ERROR_OUTOFMEMORY
;
1396 if (bOrder
&& table
->dwNumEntries
)
1397 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_udp_rows
);
1398 *ppUdpTable
= table
;
1400 else HeapFree( heap
, flags
, table
);
1401 TRACE( "returning ret %u table %p\n", ret
, table
);
1406 static MIB_TCPTABLE
*append_tcp_row( HANDLE heap
, DWORD flags
, MIB_TCPTABLE
*table
,
1407 DWORD
*count
, const MIB_TCPROW
*row
)
1409 if (table
->dwNumEntries
>= *count
)
1411 MIB_TCPTABLE
*new_table
;
1412 DWORD new_count
= table
->dwNumEntries
* 2;
1414 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_TCPTABLE
, table
[new_count
] ))))
1416 HeapFree( heap
, 0, table
);
1422 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1427 /* Why not a lookup table? Because the TCPS_* constants are different
1428 on different platforms */
1429 static DWORD
TCPStateToMIBState (int state
)
1433 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1434 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1435 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1436 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1437 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1438 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1439 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1440 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1441 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1442 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1444 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1449 static int compare_tcp_rows(const void *a
, const void *b
)
1451 const MIB_TCPROW
*rowA
= a
;
1452 const MIB_TCPROW
*rowB
= b
;
1455 if ((ret
= ntohl (rowA
->dwLocalAddr
) - ntohl (rowB
->dwLocalAddr
)) != 0) return ret
;
1456 if ((ret
= ntohs ((unsigned short)rowA
->dwLocalPort
) -
1457 ntohs ((unsigned short)rowB
->dwLocalPort
)) != 0) return ret
;
1458 if ((ret
= ntohl (rowA
->dwRemoteAddr
) - ntohl (rowB
->dwRemoteAddr
)) != 0) return ret
;
1459 return ntohs ((unsigned short)rowA
->dwRemotePort
) - ntohs ((unsigned short)rowB
->dwRemotePort
);
1463 /******************************************************************
1464 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1466 * Get the TCP connection table.
1467 * Like GetTcpTable(), but allocate the returned table from heap.
1470 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1471 * allocated and returned.
1472 * bOrder [In] whether to sort the table
1473 * heap [In] heap from which the table is allocated
1474 * flags [In] flags to HeapAlloc
1477 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1478 * returns otherwise.
1480 DWORD WINAPI
AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE
*ppTcpTable
, BOOL bOrder
,
1481 HANDLE heap
, DWORD flags
)
1483 MIB_TCPTABLE
*table
;
1485 DWORD ret
= NO_ERROR
, count
= 16;
1487 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable
, bOrder
, heap
, flags
);
1489 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
1491 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_TCPTABLE
, table
[count
] ))))
1492 return ERROR_OUTOFMEMORY
;
1494 table
->dwNumEntries
= 0;
1500 if ((fp
= fopen("/proc/net/tcp", "r")))
1502 char buf
[512], *ptr
;
1505 /* skip header line */
1506 ptr
= fgets(buf
, sizeof(buf
), fp
);
1507 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1509 if (sscanf( ptr
, "%x: %x:%x %x:%x %x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
,
1510 &row
.dwRemoteAddr
, &row
.dwRemotePort
, &row
.dwState
) != 6)
1512 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1513 row
.dwRemotePort
= htons( row
.dwRemotePort
);
1514 row
.dwState
= TCPStateToMIBState( row
.dwState
);
1515 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
)))
1520 else ret
= ERROR_NOT_SUPPORTED
;
1522 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1526 struct xinpgen
*pXIG
, *pOrigXIG
;
1528 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1530 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1531 ret
= ERROR_NOT_SUPPORTED
;
1535 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1538 ret
= ERROR_OUTOFMEMORY
;
1542 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1544 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1545 ret
= ERROR_NOT_SUPPORTED
;
1549 /* Might be nothing here; first entry is just a header it seems */
1550 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1552 pOrigXIG
= (struct xinpgen
*)Buf
;
1555 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1556 pXIG
->xig_len
> sizeof (struct xinpgen
);
1557 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1559 struct tcpcb
*pTCPData
= NULL
;
1560 struct inpcb
*pINData
;
1561 struct xsocket
*pSockData
;
1563 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1564 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1565 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1567 /* Ignore sockets for other protocols */
1568 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1571 /* Ignore PCBs that were freed while generating the data */
1572 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1575 /* we're only interested in IPv4 addresses */
1576 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1577 (pINData
->inp_vflag
& INP_IPV6
))
1580 /* If all 0's, skip it */
1581 if (!pINData
->inp_laddr
.s_addr
&&
1582 !pINData
->inp_lport
&&
1583 !pINData
->inp_faddr
.s_addr
&&
1584 !pINData
->inp_fport
)
1587 /* Fill in structure details */
1588 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1589 row
.dwLocalPort
= pINData
->inp_lport
;
1590 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
1591 row
.dwRemotePort
= pINData
->inp_fport
;
1592 row
.dwState
= TCPStateToMIBState (pTCPData
->t_state
);
1593 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1597 HeapFree (GetProcessHeap (), 0, Buf
);
1600 FIXME( "not implemented\n" );
1601 ret
= ERROR_NOT_SUPPORTED
;
1604 if (!table
) return ERROR_OUTOFMEMORY
;
1607 if (bOrder
&& table
->dwNumEntries
)
1608 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_tcp_rows
);
1609 *ppTcpTable
= table
;
1611 else HeapFree( heap
, flags
, table
);
1612 TRACE( "returning ret %u table %p\n", ret
, table
);