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 DWORD ret
= ERROR_NOT_SUPPORTED
;
155 if (!name
|| !entry
) return ERROR_INVALID_PARAMETER
;
161 if ((fp
= fopen("/proc/net/dev", "r")))
165 int nameLen
= strlen(name
);
167 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
169 while (*ptr
&& isspace(*ptr
)) ptr
++;
170 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
173 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u",
174 &entry
->dwInOctets
, &entry
->dwInUcastPkts
,
175 &entry
->dwInErrors
, &entry
->dwInDiscards
,
177 &entry
->dwInNUcastPkts
, &entry
->dwOutOctets
,
178 &entry
->dwOutUcastPkts
, &entry
->dwOutErrors
,
179 &entry
->dwOutDiscards
);
187 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
189 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
190 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
193 char *buf
= NULL
, *end
;
194 struct if_msghdr
*ifm
;
195 struct if_data ifdata
;
197 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
199 ERR ("failed to get size of iflist\n");
202 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
205 ret
= ERROR_OUTOFMEMORY
;
208 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
210 ERR ("failed to get iflist\n");
213 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
215 ifm
= (struct if_msghdr
*) buf
;
216 if(ifm
->ifm_type
== RTM_IFINFO
&& ifm
->ifm_data
.ifi_type
== IFT_ETHER
)
218 ifdata
= ifm
->ifm_data
;
219 entry
->dwMtu
= ifdata
.ifi_mtu
;
220 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
221 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
222 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
223 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
224 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
225 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
226 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
227 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
228 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
234 HeapFree (GetProcessHeap (), 0, buf
);
237 FIXME( "unimplemented\n" );
243 /******************************************************************
244 * GetIcmpStatistics (IPHLPAPI.@)
246 * Get the ICMP statistics for the local computer.
249 * stats [Out] buffer for ICMP statistics
253 * Failure: error code from winerror.h
255 DWORD WINAPI
GetIcmpStatistics(PMIB_ICMP stats
)
257 DWORD ret
= ERROR_NOT_SUPPORTED
;
259 if (!stats
) return ERROR_INVALID_PARAMETER
;
260 memset( stats
, 0, sizeof(MIB_ICMP
) );
266 if ((fp
= fopen("/proc/net/snmp", "r")))
268 static const char hdr
[] = "Icmp:";
271 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
273 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
274 /* last line was a header, get another */
275 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
276 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
279 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
280 &stats
->stats
.icmpInStats
.dwMsgs
,
281 &stats
->stats
.icmpInStats
.dwErrors
,
282 &stats
->stats
.icmpInStats
.dwDestUnreachs
,
283 &stats
->stats
.icmpInStats
.dwTimeExcds
,
284 &stats
->stats
.icmpInStats
.dwParmProbs
,
285 &stats
->stats
.icmpInStats
.dwSrcQuenchs
,
286 &stats
->stats
.icmpInStats
.dwRedirects
,
287 &stats
->stats
.icmpInStats
.dwEchoReps
,
288 &stats
->stats
.icmpInStats
.dwTimestamps
,
289 &stats
->stats
.icmpInStats
.dwTimestampReps
,
290 &stats
->stats
.icmpInStats
.dwAddrMasks
,
291 &stats
->stats
.icmpInStats
.dwAddrMaskReps
,
292 &stats
->stats
.icmpOutStats
.dwMsgs
,
293 &stats
->stats
.icmpOutStats
.dwErrors
,
294 &stats
->stats
.icmpOutStats
.dwDestUnreachs
,
295 &stats
->stats
.icmpOutStats
.dwTimeExcds
,
296 &stats
->stats
.icmpOutStats
.dwParmProbs
,
297 &stats
->stats
.icmpOutStats
.dwSrcQuenchs
,
298 &stats
->stats
.icmpOutStats
.dwRedirects
,
299 &stats
->stats
.icmpOutStats
.dwEchoReps
,
300 &stats
->stats
.icmpOutStats
.dwTimestamps
,
301 &stats
->stats
.icmpOutStats
.dwTimestampReps
,
302 &stats
->stats
.icmpOutStats
.dwAddrMasks
,
303 &stats
->stats
.icmpOutStats
.dwAddrMaskReps
);
311 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
313 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
314 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
315 struct icmpstat icmp_stat
;
316 size_t needed
= sizeof(icmp_stat
);
319 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) != -1)
322 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
323 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
324 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
326 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
328 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
329 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
330 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
331 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
332 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
333 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
334 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
335 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
336 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
337 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
338 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
340 #ifdef HAVE_ICPS_OUTHIST
342 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
343 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
344 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
346 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
348 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
349 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
350 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
351 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
352 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
353 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
354 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
355 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
356 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
357 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
358 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
359 #endif /* ICPS_OUTHIST */
363 #else /* ICMPCTL_STATS */
364 FIXME( "unimplemented\n" );
370 /******************************************************************
371 * GetIpStatistics (IPHLPAPI.@)
373 * Get the IP statistics for the local computer.
376 * stats [Out] buffer for IP statistics
380 * Failure: error code from winerror.h
382 DWORD WINAPI
GetIpStatistics(PMIB_IPSTATS stats
)
384 DWORD ret
= ERROR_NOT_SUPPORTED
;
385 MIB_IPFORWARDTABLE
*fwd_table
;
387 if (!stats
) return ERROR_INVALID_PARAMETER
;
388 memset( stats
, 0, sizeof(*stats
) );
390 stats
->dwNumIf
= stats
->dwNumAddr
= getNumInterfaces();
391 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table
, FALSE
, GetProcessHeap(), 0 ))
393 stats
->dwNumRoutes
= fwd_table
->dwNumEntries
;
394 HeapFree( GetProcessHeap(), 0, fwd_table
);
401 if ((fp
= fopen("/proc/net/snmp", "r")))
403 static const char hdr
[] = "Ip:";
406 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
408 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
409 /* last line was a header, get another */
410 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
411 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
414 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
415 &stats
->dwForwarding
,
416 &stats
->dwDefaultTTL
,
417 &stats
->dwInReceives
,
418 &stats
->dwInHdrErrors
,
419 &stats
->dwInAddrErrors
,
420 &stats
->dwForwDatagrams
,
421 &stats
->dwInUnknownProtos
,
422 &stats
->dwInDiscards
,
423 &stats
->dwInDelivers
,
424 &stats
->dwOutRequests
,
425 &stats
->dwOutDiscards
,
426 &stats
->dwOutNoRoutes
,
427 &stats
->dwReasmTimeout
,
428 &stats
->dwReasmReqds
,
430 &stats
->dwReasmFails
,
433 &stats
->dwFragCreates
);
434 /* hmm, no routingDiscards */
442 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS)
444 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
445 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
446 int ip_ttl
, ip_forwarding
;
447 struct ipstat ip_stat
;
450 needed
= sizeof(ip_stat
);
451 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
453 ERR ("failed to get ipstat\n");
454 return ERROR_NOT_SUPPORTED
;
457 needed
= sizeof(ip_ttl
);
458 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
460 ERR ("failed to get ip Default TTL\n");
461 return ERROR_NOT_SUPPORTED
;
464 needed
= sizeof(ip_forwarding
);
465 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
467 ERR ("failed to get ip forwarding\n");
468 return ERROR_NOT_SUPPORTED
;
471 stats
->dwForwarding
= ip_forwarding
;
472 stats
->dwDefaultTTL
= ip_ttl
;
473 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
474 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
475 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
476 stats
->dwInReceives
= ip_stat
.ips_total
;
477 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
478 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
479 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
480 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
481 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
482 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
483 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
484 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
485 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
486 stats
->dwOutRequests
= ip_stat
.ips_localout
;
487 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
491 FIXME( "unimplemented\n" );
497 /******************************************************************
498 * GetTcpStatistics (IPHLPAPI.@)
500 * Get the TCP statistics for the local computer.
503 * stats [Out] buffer for TCP statistics
507 * Failure: error code from winerror.h
509 DWORD WINAPI
GetTcpStatistics(PMIB_TCPSTATS stats
)
511 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
512 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
514 #define TCPTV_REXMTMAX 128
516 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
517 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
519 struct tcpstat tcp_stat
;
523 return ERROR_INVALID_PARAMETER
;
524 needed
= sizeof(tcp_stat
);
526 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) == -1)
528 ERR ("failed to get tcpstat\n");
529 return ERROR_NOT_SUPPORTED
;
532 stats
->dwRtoAlgorithm
= MIB_TCP_RTO_VANJ
;
533 stats
->dwRtoMin
= TCPTV_MIN
;
534 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
535 stats
->dwMaxConn
= -1;
536 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
537 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
538 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
539 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
540 stats
->dwCurrEstab
= 0;
541 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
542 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
543 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
544 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
545 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
546 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
552 MIB_TCPTABLE
*tcp_table
;
555 return ERROR_INVALID_PARAMETER
;
557 memset(stats
, 0, sizeof(MIB_TCPSTATS
));
559 /* get from /proc/net/snmp, no error if can't */
560 fp
= fopen("/proc/net/snmp", "r");
562 static const char hdr
[] = "Tcp:";
563 char buf
[512] = { 0 }, *ptr
;
567 ptr
= fgets(buf
, sizeof(buf
), fp
);
568 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
570 /* last line was a header, get another */
571 ptr
= fgets(buf
, sizeof(buf
), fp
);
572 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
577 stats
->dwRtoAlgorithm
= strtoul(ptr
, &endPtr
, 10);
581 stats
->dwRtoMin
= strtoul(ptr
, &endPtr
, 10);
585 stats
->dwRtoMax
= strtoul(ptr
, &endPtr
, 10);
589 stats
->dwMaxConn
= strtoul(ptr
, &endPtr
, 10);
593 stats
->dwActiveOpens
= strtoul(ptr
, &endPtr
, 10);
597 stats
->dwPassiveOpens
= strtoul(ptr
, &endPtr
, 10);
601 stats
->dwAttemptFails
= strtoul(ptr
, &endPtr
, 10);
605 stats
->dwEstabResets
= strtoul(ptr
, &endPtr
, 10);
609 stats
->dwCurrEstab
= strtoul(ptr
, &endPtr
, 10);
613 stats
->dwInSegs
= strtoul(ptr
, &endPtr
, 10);
617 stats
->dwOutSegs
= strtoul(ptr
, &endPtr
, 10);
621 stats
->dwRetransSegs
= strtoul(ptr
, &endPtr
, 10);
625 stats
->dwInErrs
= strtoul(ptr
, &endPtr
, 10);
629 stats
->dwOutRsts
= strtoul(ptr
, &endPtr
, 10);
632 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
634 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
635 HeapFree( GetProcessHeap(), 0, tcp_table
);
643 ERR ("unimplemented!\n");
644 return ERROR_NOT_SUPPORTED
;
652 /******************************************************************
653 * GetUdpStatistics (IPHLPAPI.@)
655 * Get the UDP statistics for the local computer.
658 * stats [Out] buffer for UDP statistics
662 * Failure: error code from winerror.h
664 DWORD WINAPI
GetUdpStatistics(PMIB_UDPSTATS stats
)
666 #if defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS)
667 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
668 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
669 struct udpstat udp_stat
;
670 MIB_UDPTABLE
*udp_table
;
673 return ERROR_INVALID_PARAMETER
;
675 needed
= sizeof(udp_stat
);
677 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) == -1)
679 ERR ("failed to get udpstat\n");
680 return ERROR_NOT_SUPPORTED
;
683 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
684 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
685 stats
->dwNoPorts
= udp_stat
.udps_noport
;
686 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
687 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
689 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
690 HeapFree( GetProcessHeap(), 0, udp_table
);
692 else stats
->dwNumAddrs
= 0;
699 return ERROR_INVALID_PARAMETER
;
701 memset(stats
, 0, sizeof(MIB_UDPSTATS
));
703 /* get from /proc/net/snmp, no error if can't */
704 fp
= fopen("/proc/net/snmp", "r");
706 static const char hdr
[] = "Udp:";
707 char buf
[512] = { 0 }, *ptr
;
711 ptr
= fgets(buf
, sizeof(buf
), fp
);
712 } while (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1));
714 /* last line was a header, get another */
715 ptr
= fgets(buf
, sizeof(buf
), fp
);
716 if (ptr
&& strncasecmp(buf
, hdr
, sizeof(hdr
) - 1) == 0) {
721 stats
->dwInDatagrams
= strtoul(ptr
, &endPtr
, 10);
725 stats
->dwNoPorts
= strtoul(ptr
, &endPtr
, 10);
729 stats
->dwInErrors
= strtoul(ptr
, &endPtr
, 10);
733 stats
->dwOutDatagrams
= strtoul(ptr
, &endPtr
, 10);
737 stats
->dwNumAddrs
= strtoul(ptr
, &endPtr
, 10);
746 ERR ("unimplemented!\n");
747 return ERROR_NOT_SUPPORTED
;
755 static MIB_IPFORWARDTABLE
*append_ipforward_row( HANDLE heap
, DWORD flags
, MIB_IPFORWARDTABLE
*table
,
756 DWORD
*count
, const MIB_IPFORWARDROW
*row
)
758 if (table
->dwNumEntries
>= *count
)
760 MIB_IPFORWARDTABLE
*new_table
;
761 DWORD new_count
= table
->dwNumEntries
* 2;
763 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
764 FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[new_count
] ))))
766 HeapFree( heap
, 0, table
);
772 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
776 static int compare_ipforward_rows(const void *a
, const void *b
)
778 const MIB_IPFORWARDROW
*rowA
= a
;
779 const MIB_IPFORWARDROW
*rowB
= b
;
782 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
783 if ((ret
= rowA
->dwForwardProto
- rowB
->dwForwardProto
) != 0) return ret
;
784 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
785 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
788 /******************************************************************
789 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
791 * Get the route table.
792 * Like GetIpForwardTable(), but allocate the returned table from heap.
795 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
796 * allocated and returned.
797 * bOrder [In] whether to sort the table
798 * heap [In] heap from which the table is allocated
799 * flags [In] flags to HeapAlloc
802 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
803 * on failure, NO_ERROR on success.
805 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, BOOL bOrder
,
806 HANDLE heap
, DWORD flags
)
808 MIB_IPFORWARDTABLE
*table
;
809 MIB_IPFORWARDROW row
;
810 DWORD ret
= NO_ERROR
, count
= 16;
812 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable
, bOrder
, heap
, flags
);
814 if (!ppIpForwardTable
) return ERROR_INVALID_PARAMETER
;
816 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[count
] ))))
817 return ERROR_OUTOFMEMORY
;
819 table
->dwNumEntries
= 0;
825 if ((fp
= fopen("/proc/net/route", "r")))
830 /* skip header line */
831 ptr
= fgets(buf
, sizeof(buf
), fp
);
832 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
834 memset( &row
, 0, sizeof(row
) );
836 while (!isspace(*ptr
)) ptr
++;
838 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
841 row
.dwForwardDest
= strtoul(ptr
, &ptr
, 16);
842 row
.dwForwardNextHop
= strtoul(ptr
+ 1, &ptr
, 16);
843 flags
= strtoul(ptr
+ 1, &ptr
, 16);
845 if (!(flags
& RTF_UP
)) row
.dwForwardType
= MIB_IPROUTE_TYPE_INVALID
;
846 else if (flags
& RTF_GATEWAY
) row
.dwForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
847 else row
.dwForwardType
= MIB_IPROUTE_TYPE_DIRECT
;
849 strtoul(ptr
+ 1, &ptr
, 16); /* refcount, skip */
850 strtoul(ptr
+ 1, &ptr
, 16); /* use, skip */
851 row
.dwForwardMetric1
= strtoul(ptr
+ 1, &ptr
, 16);
852 row
.dwForwardMask
= strtoul(ptr
+ 1, &ptr
, 16);
853 /* FIXME: other protos might be appropriate, e.g. the default
854 * route is typically set with MIB_IPPROTO_NETMGMT instead */
855 row
.dwForwardProto
= MIB_IPPROTO_LOCAL
;
857 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
862 else ret
= ERROR_NOT_SUPPORTED
;
864 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
866 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
868 char *buf
= NULL
, *lim
, *next
, *addrPtr
;
869 struct rt_msghdr
*rtm
;
871 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
873 ERR ("sysctl 1 failed!\n");
874 ret
= ERROR_NOT_SUPPORTED
;
878 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
881 ret
= ERROR_OUTOFMEMORY
;
885 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
887 ret
= ERROR_NOT_SUPPORTED
;
892 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
896 rtm
= (struct rt_msghdr
*)next
;
898 if (rtm
->rtm_type
!= RTM_GET
)
900 WARN ("Got unexpected message type 0x%x!\n",
905 /* Ignore all entries except for gateway routes which aren't
907 if (!(rtm
->rtm_flags
& RTF_GATEWAY
) ||
908 (rtm
->rtm_flags
& RTF_MULTICAST
))
911 memset( &row
, 0, sizeof(row
) );
912 row
.dwForwardIfIndex
= rtm
->rtm_index
;
913 row
.dwForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
914 row
.dwForwardMetric1
= rtm
->rtm_rmx
.rmx_hopcount
;
915 row
.dwForwardProto
= MIB_IPPROTO_LOCAL
;
917 addrPtr
= (char *)(rtm
+ 1);
919 for (i
= 1; i
; i
<<= 1)
924 if (!(i
& rtm
->rtm_addrs
))
927 sa
= (struct sockaddr
*)addrPtr
;
928 ADVANCE (addrPtr
, sa
);
930 /* default routes are encoded by length-zero sockaddr */
933 else if (sa
->sa_family
!= AF_INET
)
935 WARN ("Received unsupported sockaddr family 0x%x\n",
941 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
943 addr
= sin
->sin_addr
.s_addr
;
948 case RTA_DST
: row
.dwForwardDest
= addr
; break;
949 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
950 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
952 WARN ("Unexpected address type 0x%x\n", i
);
956 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
960 HeapFree( GetProcessHeap (), 0, buf
);
963 FIXME( "not implemented\n" );
964 ret
= ERROR_NOT_SUPPORTED
;
967 if (!table
) return ERROR_OUTOFMEMORY
;
970 if (bOrder
&& table
->dwNumEntries
)
971 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipforward_rows
);
972 *ppIpForwardTable
= table
;
974 else HeapFree( heap
, flags
, table
);
975 TRACE( "returning ret %u table %p\n", ret
, table
);
979 static MIB_IPNETTABLE
*append_ipnet_row( HANDLE heap
, DWORD flags
, MIB_IPNETTABLE
*table
,
980 DWORD
*count
, const MIB_IPNETROW
*row
)
982 if (table
->dwNumEntries
>= *count
)
984 MIB_IPNETTABLE
*new_table
;
985 DWORD new_count
= table
->dwNumEntries
* 2;
987 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
988 FIELD_OFFSET(MIB_IPNETTABLE
, table
[new_count
] ))))
990 HeapFree( heap
, 0, table
);
996 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1000 static int compare_ipnet_rows(const void *a
, const void *b
)
1002 const MIB_IPNETROW
*rowA
= a
;
1003 const MIB_IPNETROW
*rowB
= b
;
1005 return ntohl(rowA
->dwAddr
) - ntohl(rowB
->dwAddr
);
1009 /******************************************************************
1010 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1012 * Get the IP-to-physical address mapping table.
1013 * Like GetIpNetTable(), but allocate the returned table from heap.
1016 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1017 * allocated and returned.
1018 * bOrder [In] whether to sort the table
1019 * heap [In] heap from which the table is allocated
1020 * flags [In] flags to HeapAlloc
1023 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1024 * on failure, NO_ERROR on success.
1026 DWORD WINAPI
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE
*ppIpNetTable
, BOOL bOrder
,
1027 HANDLE heap
, DWORD flags
)
1029 MIB_IPNETTABLE
*table
;
1031 DWORD ret
= NO_ERROR
, count
= 16;
1033 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable
, bOrder
, heap
, flags
);
1035 if (!ppIpNetTable
) return ERROR_INVALID_PARAMETER
;
1037 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPNETTABLE
, table
[count
] ))))
1038 return ERROR_OUTOFMEMORY
;
1040 table
->dwNumEntries
= 0;
1046 if ((fp
= fopen("/proc/net/arp", "r")))
1048 char buf
[512], *ptr
;
1051 /* skip header line */
1052 ptr
= fgets(buf
, sizeof(buf
), fp
);
1053 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1055 memset( &row
, 0, sizeof(row
) );
1057 row
.dwAddr
= inet_addr(ptr
);
1058 while (*ptr
&& !isspace(*ptr
)) ptr
++;
1059 strtoul(ptr
+ 1, &ptr
, 16); /* hw type (skip) */
1060 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1063 if (flags
& ATF_COM
) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1067 if (flags
& ATF_PERM
) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
1070 row
.dwType
= MIB_IPNET_TYPE_OTHER
;
1072 while (*ptr
&& isspace(*ptr
)) ptr
++;
1073 while (*ptr
&& !isspace(*ptr
))
1075 row
.bPhysAddr
[row
.dwPhysAddrLen
++] = strtoul(ptr
, &ptr
, 16);
1078 while (*ptr
&& isspace(*ptr
)) ptr
++;
1079 while (*ptr
&& !isspace(*ptr
)) ptr
++; /* mask (skip) */
1080 while (*ptr
&& isspace(*ptr
)) ptr
++;
1081 getInterfaceIndexByName(ptr
, &row
.dwIndex
);
1083 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1088 else ret
= ERROR_NOT_SUPPORTED
;
1090 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1092 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1093 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1095 char *buf
= NULL
, *lim
, *next
;
1096 struct rt_msghdr
*rtm
;
1097 struct sockaddr_inarp
*sinarp
;
1098 struct sockaddr_dl
*sdl
;
1100 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1102 ERR ("failed to get arp table\n");
1103 ret
= ERROR_NOT_SUPPORTED
;
1107 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1110 ret
= ERROR_OUTOFMEMORY
;
1114 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1116 ret
= ERROR_NOT_SUPPORTED
;
1124 rtm
= (struct rt_msghdr
*)next
;
1125 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1126 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1127 if(sdl
->sdl_alen
) /* arp entry */
1129 memset( &row
, 0, sizeof(row
) );
1130 row
.dwAddr
= sinarp
->sin_addr
.s_addr
;
1131 row
.dwIndex
= sdl
->sdl_index
;
1132 row
.dwPhysAddrLen
= min( 8, sdl
->sdl_alen
);
1133 memcpy( row
.bPhysAddr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], row
.dwPhysAddrLen
);
1134 if(rtm
->rtm_rmx
.rmx_expire
== 0) row
.dwType
= MIB_IPNET_TYPE_STATIC
;
1135 else if(sinarp
->sin_other
& SIN_PROXY
) row
.dwType
= MIB_IPNET_TYPE_OTHER
;
1136 else if(rtm
->rtm_rmx
.rmx_expire
!= 0) row
.dwType
= MIB_IPNET_TYPE_DYNAMIC
;
1137 else row
.dwType
= MIB_IPNET_TYPE_INVALID
;
1139 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1142 next
+= rtm
->rtm_msglen
;
1145 HeapFree( GetProcessHeap (), 0, buf
);
1148 FIXME( "not implemented\n" );
1149 ret
= ERROR_NOT_SUPPORTED
;
1152 if (!table
) return ERROR_OUTOFMEMORY
;
1155 if (bOrder
&& table
->dwNumEntries
)
1156 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipnet_rows
);
1157 *ppIpNetTable
= table
;
1159 else HeapFree( heap
, flags
, table
);
1160 TRACE( "returning ret %u table %p\n", ret
, table
);
1165 static MIB_UDPTABLE
*append_udp_row( HANDLE heap
, DWORD flags
, MIB_UDPTABLE
*table
,
1166 DWORD
*count
, const MIB_UDPROW
*row
)
1168 if (table
->dwNumEntries
>= *count
)
1170 MIB_UDPTABLE
*new_table
;
1171 DWORD new_count
= table
->dwNumEntries
* 2;
1173 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_UDPTABLE
, table
[new_count
] ))))
1175 HeapFree( heap
, 0, table
);
1181 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1185 static int compare_udp_rows(const void *a
, const void *b
)
1187 const MIB_UDPROW
*rowA
= a
;
1188 const MIB_UDPROW
*rowB
= b
;
1191 if ((ret
= rowA
->dwLocalAddr
- rowB
->dwLocalAddr
) != 0) return ret
;
1192 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
1196 /******************************************************************
1197 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
1199 * Get the UDP listener table.
1200 * Like GetUdpTable(), but allocate the returned table from heap.
1203 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
1204 * allocated and returned.
1205 * bOrder [In] whether to sort the table
1206 * heap [In] heap from which the table is allocated
1207 * flags [In] flags to HeapAlloc
1210 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
1211 * returns otherwise.
1213 DWORD WINAPI
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE
*ppUdpTable
, BOOL bOrder
,
1214 HANDLE heap
, DWORD flags
)
1216 MIB_UDPTABLE
*table
;
1218 DWORD ret
= NO_ERROR
, count
= 16;
1220 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable
, bOrder
, heap
, flags
);
1222 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
1224 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_UDPTABLE
, table
[count
] ))))
1225 return ERROR_OUTOFMEMORY
;
1227 table
->dwNumEntries
= 0;
1233 if ((fp
= fopen("/proc/net/udp", "r")))
1235 char buf
[512], *ptr
;
1238 /* skip header line */
1239 ptr
= fgets(buf
, sizeof(buf
), fp
);
1240 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1242 if (sscanf( ptr
, "%u: %x:%x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
) != 3)
1244 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1245 if (!(table
= append_udp_row( heap
, flags
, table
, &count
, &row
)))
1250 else ret
= ERROR_NOT_SUPPORTED
;
1253 FIXME( "not implemented\n" );
1254 ret
= ERROR_NOT_SUPPORTED
;
1257 if (!table
) return ERROR_OUTOFMEMORY
;
1260 if (bOrder
&& table
->dwNumEntries
)
1261 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_udp_rows
);
1262 *ppUdpTable
= table
;
1264 else HeapFree( heap
, flags
, table
);
1265 TRACE( "returning ret %u table %p\n", ret
, table
);
1270 static MIB_TCPTABLE
*append_tcp_row( HANDLE heap
, DWORD flags
, MIB_TCPTABLE
*table
,
1271 DWORD
*count
, const MIB_TCPROW
*row
)
1273 if (table
->dwNumEntries
>= *count
)
1275 MIB_TCPTABLE
*new_table
;
1276 DWORD new_count
= table
->dwNumEntries
* 2;
1278 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, FIELD_OFFSET(MIB_TCPTABLE
, table
[new_count
] ))))
1280 HeapFree( heap
, 0, table
);
1286 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1291 /* Why not a lookup table? Because the TCPS_* constants are different
1292 on different platforms */
1293 static DWORD
TCPStateToMIBState (int state
)
1297 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1298 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1299 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1300 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1301 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1302 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1303 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1304 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1305 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1306 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1308 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1313 static int compare_tcp_rows(const void *a
, const void *b
)
1315 const MIB_TCPROW
*rowA
= a
;
1316 const MIB_TCPROW
*rowB
= b
;
1319 if ((ret
= ntohl (rowA
->dwLocalAddr
) - ntohl (rowB
->dwLocalAddr
)) != 0) return ret
;
1320 if ((ret
= ntohs ((unsigned short)rowA
->dwLocalPort
) -
1321 ntohs ((unsigned short)rowB
->dwLocalPort
)) != 0) return ret
;
1322 if ((ret
= ntohl (rowA
->dwRemoteAddr
) - ntohl (rowB
->dwRemoteAddr
)) != 0) return ret
;
1323 return ntohs ((unsigned short)rowA
->dwRemotePort
) - ntohs ((unsigned short)rowB
->dwRemotePort
);
1327 /******************************************************************
1328 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
1330 * Get the TCP connection table.
1331 * Like GetTcpTable(), but allocate the returned table from heap.
1334 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
1335 * allocated and returned.
1336 * bOrder [In] whether to sort the table
1337 * heap [In] heap from which the table is allocated
1338 * flags [In] flags to HeapAlloc
1341 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
1342 * returns otherwise.
1344 DWORD WINAPI
AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE
*ppTcpTable
, BOOL bOrder
,
1345 HANDLE heap
, DWORD flags
)
1347 MIB_TCPTABLE
*table
;
1349 DWORD ret
= NO_ERROR
, count
= 16;
1351 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable
, bOrder
, heap
, flags
);
1353 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
1355 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_TCPTABLE
, table
[count
] ))))
1356 return ERROR_OUTOFMEMORY
;
1358 table
->dwNumEntries
= 0;
1364 if ((fp
= fopen("/proc/net/tcp", "r")))
1366 char buf
[512], *ptr
;
1369 /* skip header line */
1370 ptr
= fgets(buf
, sizeof(buf
), fp
);
1371 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1373 if (sscanf( ptr
, "%x: %x:%x %x:%x %x", &dummy
, &row
.dwLocalAddr
, &row
.dwLocalPort
,
1374 &row
.dwRemoteAddr
, &row
.dwRemotePort
, &row
.dwState
) != 6)
1376 row
.dwLocalPort
= htons( row
.dwLocalPort
);
1377 row
.dwRemotePort
= htons( row
.dwRemotePort
);
1378 row
.dwState
= TCPStateToMIBState( row
.dwState
);
1379 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
)))
1384 else ret
= ERROR_NOT_SUPPORTED
;
1386 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
1390 struct xinpgen
*pXIG
, *pOrigXIG
;
1392 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
1394 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1395 ret
= ERROR_NOT_SUPPORTED
;
1399 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
1402 ret
= ERROR_OUTOFMEMORY
;
1406 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
1408 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
1409 ret
= ERROR_NOT_SUPPORTED
;
1413 /* Might be nothing here; first entry is just a header it seems */
1414 if (Len
<= sizeof (struct xinpgen
)) goto done
;
1416 pOrigXIG
= (struct xinpgen
*)Buf
;
1419 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
1420 pXIG
->xig_len
> sizeof (struct xinpgen
);
1421 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
1423 struct tcpcb
*pTCPData
= NULL
;
1424 struct inpcb
*pINData
;
1425 struct xsocket
*pSockData
;
1427 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
1428 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
1429 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
1431 /* Ignore sockets for other protocols */
1432 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
1435 /* Ignore PCBs that were freed while generating the data */
1436 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
1439 /* we're only interested in IPv4 addresses */
1440 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
1441 (pINData
->inp_vflag
& INP_IPV6
))
1444 /* If all 0's, skip it */
1445 if (!pINData
->inp_laddr
.s_addr
&&
1446 !pINData
->inp_lport
&&
1447 !pINData
->inp_faddr
.s_addr
&&
1448 !pINData
->inp_fport
)
1451 /* Fill in structure details */
1452 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
1453 row
.dwLocalPort
= pINData
->inp_lport
;
1454 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
1455 row
.dwRemotePort
= pINData
->inp_fport
;
1456 row
.dwState
= TCPStateToMIBState (pTCPData
->t_state
);
1457 if (!(table
= append_tcp_row( heap
, flags
, table
, &count
, &row
))) break;
1461 HeapFree (GetProcessHeap (), 0, Buf
);
1464 FIXME( "not implemented\n" );
1465 ret
= ERROR_NOT_SUPPORTED
;
1468 if (!table
) return ERROR_OUTOFMEMORY
;
1471 if (bOrder
&& table
->dwNumEntries
)
1472 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_tcp_rows
);
1473 *ppTcpTable
= table
;
1475 else HeapFree( heap
, flags
, table
);
1476 TRACE( "returning ret %u table %p\n", ret
, table
);