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"
29 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 #include <sys/socket.h>
39 #ifdef HAVE_SYS_SOCKETVAR_H
40 #include <sys/socketvar.h>
42 #ifdef HAVE_SYS_TIMEOUT_H
43 #include <sys/timeout.h>
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
48 #ifdef HAVE_NETINET_IN_SYSTM_H
49 #include <netinet/in_systm.h>
51 #ifdef HAVE_ARPA_INET_H
52 #include <arpa/inet.h>
57 #ifdef HAVE_NET_IF_DL_H
58 #include <net/if_dl.h>
60 #ifdef HAVE_NET_IF_TYPES_H
61 #include <net/if_types.h>
63 #ifdef HAVE_NET_ROUTE_H
64 #include <net/route.h>
66 #ifdef HAVE_NET_IF_ARP_H
67 #include <net/if_arp.h>
69 #ifdef HAVE_NETINET_IF_ETHER_H
70 #include <netinet/if_ether.h>
72 #ifdef HAVE_NETINET_IF_INARP_H
73 #include <netinet/if_inarp.h>
75 #ifdef HAVE_NETINET_IP_H
76 #include <netinet/ip.h>
78 #ifdef HAVE_NETINET_TCP_H
79 #include <netinet/tcp.h>
81 #ifdef HAVE_NETINET_IP_VAR_H
82 #include <netinet/ip_var.h>
84 #ifdef HAVE_NETINET_TCP_FSM_H
85 #include <netinet/tcp_fsm.h>
87 #ifdef HAVE_NETINET_IN_PCB_H
88 #include <netinet/in_pcb.h>
90 #ifdef HAVE_NETINET_TCP_TIMER_H
91 #include <netinet/tcp_timer.h>
93 #ifdef HAVE_NETINET_TCP_VAR_H
94 #include <netinet/tcp_var.h>
96 #ifdef HAVE_NETINET_IP_ICMP_H
97 #include <netinet/ip_icmp.h>
99 #ifdef HAVE_NETINET_ICMP_VAR_H
100 #include <netinet/icmp_var.h>
102 #ifdef HAVE_NETINET_UDP_H
103 #include <netinet/udp.h>
105 #ifdef HAVE_NETINET_UDP_VAR_H
106 #include <netinet/udp_var.h>
108 #ifdef HAVE_SYS_PROTOSW_H
109 #include <sys/protosw.h>
111 #ifdef HAVE_SYS_SYSCTL_H
112 #include <sys/sysctl.h>
117 #ifdef HAVE_INET_MIB2_H
118 #include <inet/mib2.h>
120 #ifdef HAVE_STROPTS_H
123 #ifdef HAVE_SYS_TIHDR_H
124 #include <sys/tihdr.h>
126 #ifdef HAVE_SYS_PARAM_H
127 #include <sys/param.h>
129 #ifdef HAVE_SYS_QUEUE_H
130 #include <sys/queue.h>
132 #ifdef HAVE_SYS_USER_H
133 /* Make sure the definitions of struct kinfo_proc are the same. */
134 #include <sys/user.h>
136 #ifdef HAVE_LIBPROCSTAT_H
137 #include <libprocstat.h>
139 #ifdef HAVE_LIBPROC_H
145 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
148 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
151 #include "ntstatus.h"
152 #define WIN32_NO_STATUS
153 #define NONAMELESSUNION
157 #include "wine/debug.h"
158 #include "wine/server.h"
159 #include "wine/unicode.h"
161 #ifndef HAVE_NETINET_TCP_FSM_H
162 #define TCPS_ESTABLISHED 1
163 #define TCPS_SYN_SENT 2
164 #define TCPS_SYN_RECEIVED 3
165 #define TCPS_FIN_WAIT_1 4
166 #define TCPS_FIN_WAIT_2 5
167 #define TCPS_TIME_WAIT 6
168 #define TCPS_CLOSED 7
169 #define TCPS_CLOSE_WAIT 8
170 #define TCPS_LAST_ACK 9
171 #define TCPS_LISTEN 10
172 #define TCPS_CLOSING 11
175 #ifndef RTF_MULTICAST
176 #define RTF_MULTICAST 0 /* Not available on NetBSD/OpenBSD */
180 #define RTF_LLINFO 0 /* Not available on FreeBSD 8 and above */
183 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi
);
186 static DWORD
kstat_get_ui32( kstat_t
*ksp
, const char *name
)
189 kstat_named_t
*data
= ksp
->ks_data
;
191 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
192 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui32
;
196 static ULONGLONG
kstat_get_ui64( kstat_t
*ksp
, const char *name
)
199 kstat_named_t
*data
= ksp
->ks_data
;
201 for (i
= 0; i
< ksp
->ks_ndata
; i
++)
202 if (!strcmp( data
[i
].name
, name
)) return data
[i
].value
.ui64
;
207 #if defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
208 static int open_streams_mib( const char *proto
)
214 struct T_optmgmt_req req_header
;
215 struct opthdr opt_header
;
218 if ((fd
= open( "/dev/arp", O_RDWR
)) == -1)
220 WARN( "could not open /dev/arp: %s\n", strerror(errno
) );
223 if (proto
) ioctl( fd
, I_PUSH
, proto
);
225 request
.req_header
.PRIM_type
= T_SVR4_OPTMGMT_REQ
;
226 request
.req_header
.OPT_length
= sizeof(request
.opt_header
);
227 request
.req_header
.OPT_offset
= FIELD_OFFSET( struct request
, opt_header
);
228 request
.req_header
.MGMT_flags
= T_CURRENT
;
229 request
.opt_header
.level
= MIB2_IP
;
230 request
.opt_header
.name
= 0;
231 request
.opt_header
.len
= 0;
233 buf
.len
= sizeof(request
);
234 buf
.buf
= (caddr_t
)&request
;
235 if (putmsg( fd
, &buf
, NULL
, 0 ) == -1)
237 WARN( "putmsg: %s\n", strerror(errno
) );
244 static void *read_mib_entry( int fd
, int level
, int name
, int *len
)
252 struct T_optmgmt_ack ack_header
;
253 struct opthdr opt_header
;
258 buf
.maxlen
= sizeof(reply
);
259 buf
.buf
= (caddr_t
)&reply
;
260 if ((ret
= getmsg( fd
, &buf
, NULL
, &flags
)) < 0) return NULL
;
261 if (!(ret
& MOREDATA
)) return NULL
;
262 if (reply
.ack_header
.PRIM_type
!= T_OPTMGMT_ACK
) return NULL
;
263 if (buf
.len
< sizeof(reply
.ack_header
)) return NULL
;
264 if (reply
.ack_header
.OPT_length
< sizeof(reply
.opt_header
)) return NULL
;
266 if (!(data
= HeapAlloc( GetProcessHeap(), 0, reply
.opt_header
.len
))) return NULL
;
267 buf
.maxlen
= reply
.opt_header
.len
;
268 buf
.buf
= (caddr_t
)data
;
270 if (getmsg( fd
, NULL
, &buf
, &flags
) >= 0 &&
271 reply
.opt_header
.level
== level
&&
272 reply
.opt_header
.name
== name
)
277 HeapFree( GetProcessHeap(), 0, data
);
280 #endif /* HAVE_SYS_TIHDR_H && T_OPTMGMT_ACK */
282 DWORD
getInterfaceStatsByName(const char *name
, PMIB_IFROW entry
)
284 DWORD ret
= ERROR_NOT_SUPPORTED
;
286 if (!name
|| !entry
) return ERROR_INVALID_PARAMETER
;
292 if ((fp
= fopen("/proc/net/dev", "r")))
296 int nameLen
= strlen(name
);
298 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
300 while (*ptr
&& isspace(*ptr
)) ptr
++;
301 if (strncasecmp(ptr
, name
, nameLen
) == 0 && *(ptr
+ nameLen
) == ':')
304 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u",
305 &entry
->dwInOctets
, &entry
->dwInUcastPkts
,
306 &entry
->dwInErrors
, &entry
->dwInDiscards
,
308 &entry
->dwInNUcastPkts
, &entry
->dwOutOctets
,
309 &entry
->dwOutUcastPkts
, &entry
->dwOutErrors
,
310 &entry
->dwOutDiscards
);
318 #elif defined(HAVE_LIBKSTAT)
323 if ((kc
= kstat_open()) &&
324 (ksp
= kstat_lookup( kc
, NULL
, -1, (char *)name
)) &&
325 kstat_read( kc
, ksp
, NULL
) != -1 &&
326 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
328 entry
->dwMtu
= 1500; /* FIXME */
329 entry
->dwSpeed
= min( kstat_get_ui64( ksp
, "ifspeed" ), ~0u );
330 entry
->dwInOctets
= kstat_get_ui32( ksp
, "rbytes" );
331 entry
->dwInNUcastPkts
= kstat_get_ui32( ksp
, "multircv" );
332 entry
->dwInNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstrcv" );
333 entry
->dwInUcastPkts
= kstat_get_ui32( ksp
, "ipackets" ) - entry
->dwInNUcastPkts
;
334 entry
->dwInDiscards
= kstat_get_ui32( ksp
, "norcvbuf" );
335 entry
->dwInErrors
= kstat_get_ui32( ksp
, "ierrors" );
336 entry
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "unknowns" );
337 entry
->dwOutOctets
= kstat_get_ui32( ksp
, "obytes" );
338 entry
->dwOutNUcastPkts
= kstat_get_ui32( ksp
, "multixmt" );
339 entry
->dwOutNUcastPkts
+= kstat_get_ui32( ksp
, "brdcstxmt" );
340 entry
->dwOutUcastPkts
= kstat_get_ui32( ksp
, "opackets" ) - entry
->dwOutNUcastPkts
;
341 entry
->dwOutDiscards
= 0; /* FIXME */
342 entry
->dwOutErrors
= kstat_get_ui32( ksp
, "oerrors" );
343 entry
->dwOutQLen
= kstat_get_ui32( ksp
, "noxmtbuf" );
346 if (kc
) kstat_close( kc
);
348 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
350 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, if_nametoindex(name
)};
351 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
354 char *buf
= NULL
, *end
;
355 struct if_msghdr
*ifm
;
356 struct if_data ifdata
;
358 if(sysctl(mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
360 ERR ("failed to get size of iflist\n");
363 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
366 ret
= ERROR_OUTOFMEMORY
;
369 if(sysctl(mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
371 ERR ("failed to get iflist\n");
374 for ( end
= buf
+ needed
; buf
< end
; buf
+= ifm
->ifm_msglen
)
376 ifm
= (struct if_msghdr
*) buf
;
377 if(ifm
->ifm_type
== RTM_IFINFO
)
379 ifdata
= ifm
->ifm_data
;
380 entry
->dwMtu
= ifdata
.ifi_mtu
;
381 entry
->dwSpeed
= ifdata
.ifi_baudrate
;
382 entry
->dwInOctets
= ifdata
.ifi_ibytes
;
383 entry
->dwInErrors
= ifdata
.ifi_ierrors
;
384 entry
->dwInDiscards
= ifdata
.ifi_iqdrops
;
385 entry
->dwInUcastPkts
= ifdata
.ifi_ipackets
;
386 entry
->dwInNUcastPkts
= ifdata
.ifi_imcasts
;
387 entry
->dwOutOctets
= ifdata
.ifi_obytes
;
388 entry
->dwOutUcastPkts
= ifdata
.ifi_opackets
;
389 entry
->dwOutErrors
= ifdata
.ifi_oerrors
;
395 HeapFree (GetProcessHeap (), 0, buf
);
398 FIXME( "unimplemented\n" );
404 /******************************************************************
405 * GetIcmpStatistics (IPHLPAPI.@)
407 * Get the ICMP statistics for the local computer.
410 * stats [Out] buffer for ICMP statistics
414 * Failure: error code from winerror.h
416 DWORD WINAPI
GetIcmpStatistics(PMIB_ICMP stats
)
418 DWORD ret
= ERROR_NOT_SUPPORTED
;
420 if (!stats
) return ERROR_INVALID_PARAMETER
;
421 memset( stats
, 0, sizeof(MIB_ICMP
) );
427 if ((fp
= fopen("/proc/net/snmp", "r")))
429 static const char hdr
[] = "Icmp:";
432 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
434 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
435 /* last line was a header, get another */
436 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
437 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
440 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",
441 &stats
->stats
.icmpInStats
.dwMsgs
,
442 &stats
->stats
.icmpInStats
.dwErrors
,
443 &stats
->stats
.icmpInStats
.dwDestUnreachs
,
444 &stats
->stats
.icmpInStats
.dwTimeExcds
,
445 &stats
->stats
.icmpInStats
.dwParmProbs
,
446 &stats
->stats
.icmpInStats
.dwSrcQuenchs
,
447 &stats
->stats
.icmpInStats
.dwRedirects
,
448 &stats
->stats
.icmpInStats
.dwEchoReps
,
449 &stats
->stats
.icmpInStats
.dwTimestamps
,
450 &stats
->stats
.icmpInStats
.dwTimestampReps
,
451 &stats
->stats
.icmpInStats
.dwAddrMasks
,
452 &stats
->stats
.icmpInStats
.dwAddrMaskReps
,
453 &stats
->stats
.icmpOutStats
.dwMsgs
,
454 &stats
->stats
.icmpOutStats
.dwErrors
,
455 &stats
->stats
.icmpOutStats
.dwDestUnreachs
,
456 &stats
->stats
.icmpOutStats
.dwTimeExcds
,
457 &stats
->stats
.icmpOutStats
.dwParmProbs
,
458 &stats
->stats
.icmpOutStats
.dwSrcQuenchs
,
459 &stats
->stats
.icmpOutStats
.dwRedirects
,
460 &stats
->stats
.icmpOutStats
.dwEchoReps
,
461 &stats
->stats
.icmpOutStats
.dwTimestamps
,
462 &stats
->stats
.icmpOutStats
.dwTimestampReps
,
463 &stats
->stats
.icmpOutStats
.dwAddrMasks
,
464 &stats
->stats
.icmpOutStats
.dwAddrMaskReps
);
472 #elif defined(HAVE_LIBKSTAT)
474 static char ip
[] = "ip", icmp
[] = "icmp";
478 if ((kc
= kstat_open()) &&
479 (ksp
= kstat_lookup( kc
, ip
, 0, icmp
)) &&
480 kstat_read( kc
, ksp
, NULL
) != -1 &&
481 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
483 stats
->stats
.icmpInStats
.dwMsgs
= kstat_get_ui32( ksp
, "inMsgs" );
484 stats
->stats
.icmpInStats
.dwErrors
= kstat_get_ui32( ksp
, "inErrors" );
485 stats
->stats
.icmpInStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "inDestUnreachs" );
486 stats
->stats
.icmpInStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "inTimeExcds" );
487 stats
->stats
.icmpInStats
.dwParmProbs
= kstat_get_ui32( ksp
, "inParmProbs" );
488 stats
->stats
.icmpInStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "inSrcQuenchs" );
489 stats
->stats
.icmpInStats
.dwRedirects
= kstat_get_ui32( ksp
, "inRedirects" );
490 stats
->stats
.icmpInStats
.dwEchos
= kstat_get_ui32( ksp
, "inEchos" );
491 stats
->stats
.icmpInStats
.dwEchoReps
= kstat_get_ui32( ksp
, "inEchoReps" );
492 stats
->stats
.icmpInStats
.dwTimestamps
= kstat_get_ui32( ksp
, "inTimestamps" );
493 stats
->stats
.icmpInStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "inTimestampReps" );
494 stats
->stats
.icmpInStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "inAddrMasks" );
495 stats
->stats
.icmpInStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "inAddrMaskReps" );
496 stats
->stats
.icmpOutStats
.dwMsgs
= kstat_get_ui32( ksp
, "outMsgs" );
497 stats
->stats
.icmpOutStats
.dwErrors
= kstat_get_ui32( ksp
, "outErrors" );
498 stats
->stats
.icmpOutStats
.dwDestUnreachs
= kstat_get_ui32( ksp
, "outDestUnreachs" );
499 stats
->stats
.icmpOutStats
.dwTimeExcds
= kstat_get_ui32( ksp
, "outTimeExcds" );
500 stats
->stats
.icmpOutStats
.dwParmProbs
= kstat_get_ui32( ksp
, "outParmProbs" );
501 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= kstat_get_ui32( ksp
, "outSrcQuenchs" );
502 stats
->stats
.icmpOutStats
.dwRedirects
= kstat_get_ui32( ksp
, "outRedirects" );
503 stats
->stats
.icmpOutStats
.dwEchos
= kstat_get_ui32( ksp
, "outEchos" );
504 stats
->stats
.icmpOutStats
.dwEchoReps
= kstat_get_ui32( ksp
, "outEchoReps" );
505 stats
->stats
.icmpOutStats
.dwTimestamps
= kstat_get_ui32( ksp
, "outTimestamps" );
506 stats
->stats
.icmpOutStats
.dwTimestampReps
= kstat_get_ui32( ksp
, "outTimestampReps" );
507 stats
->stats
.icmpOutStats
.dwAddrMasks
= kstat_get_ui32( ksp
, "outAddrMasks" );
508 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= kstat_get_ui32( ksp
, "outAddrMaskReps" );
511 if (kc
) kstat_close( kc
);
513 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && defined(HAVE_STRUCT_ICMPSTAT_ICPS_INHIST)
515 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
516 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
517 struct icmpstat icmp_stat
;
518 size_t needed
= sizeof(icmp_stat
);
521 if(sysctl(mib
, MIB_LEN
, &icmp_stat
, &needed
, NULL
, 0) != -1)
524 stats
->stats
.icmpInStats
.dwMsgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
525 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
526 stats
->stats
.icmpInStats
.dwMsgs
+= icmp_stat
.icps_inhist
[i
];
528 stats
->stats
.icmpInStats
.dwErrors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
530 stats
->stats
.icmpInStats
.dwDestUnreachs
= icmp_stat
.icps_inhist
[ICMP_UNREACH
];
531 stats
->stats
.icmpInStats
.dwTimeExcds
= icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
532 stats
->stats
.icmpInStats
.dwParmProbs
= icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
533 stats
->stats
.icmpInStats
.dwSrcQuenchs
= icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
534 stats
->stats
.icmpInStats
.dwRedirects
= icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
535 stats
->stats
.icmpInStats
.dwEchos
= icmp_stat
.icps_inhist
[ICMP_ECHO
];
536 stats
->stats
.icmpInStats
.dwEchoReps
= icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
537 stats
->stats
.icmpInStats
.dwTimestamps
= icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
538 stats
->stats
.icmpInStats
.dwTimestampReps
= icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
539 stats
->stats
.icmpInStats
.dwAddrMasks
= icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
540 stats
->stats
.icmpInStats
.dwAddrMaskReps
= icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
542 #ifdef HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST
544 stats
->stats
.icmpOutStats
.dwMsgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
545 for(i
= 0; i
<= ICMP_MAXTYPE
; i
++)
546 stats
->stats
.icmpOutStats
.dwMsgs
+= icmp_stat
.icps_outhist
[i
];
548 stats
->stats
.icmpOutStats
.dwErrors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
550 stats
->stats
.icmpOutStats
.dwDestUnreachs
= icmp_stat
.icps_outhist
[ICMP_UNREACH
];
551 stats
->stats
.icmpOutStats
.dwTimeExcds
= icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
552 stats
->stats
.icmpOutStats
.dwParmProbs
= icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
553 stats
->stats
.icmpOutStats
.dwSrcQuenchs
= icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
554 stats
->stats
.icmpOutStats
.dwRedirects
= icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
555 stats
->stats
.icmpOutStats
.dwEchos
= icmp_stat
.icps_outhist
[ICMP_ECHO
];
556 stats
->stats
.icmpOutStats
.dwEchoReps
= icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
557 stats
->stats
.icmpOutStats
.dwTimestamps
= icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
558 stats
->stats
.icmpOutStats
.dwTimestampReps
= icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
559 stats
->stats
.icmpOutStats
.dwAddrMasks
= icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
560 stats
->stats
.icmpOutStats
.dwAddrMaskReps
= icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
561 #endif /* HAVE_STRUCT_ICMPSTAT_ICPS_OUTHIST */
565 #else /* ICMPCTL_STATS */
566 FIXME( "unimplemented\n" );
571 /******************************************************************
572 * GetIcmpStatisticsEx (IPHLPAPI.@)
574 * Get the IPv4 and IPv6 ICMP statistics for the local computer.
577 * stats [Out] buffer for ICMP statistics
578 * family [In] specifies whether IPv4 or IPv6 statistics are returned
582 * Failure: error code from winerror.h
584 DWORD WINAPI
GetIcmpStatisticsEx(PMIB_ICMP_EX stats
, DWORD family
)
586 DWORD ret
= ERROR_NOT_SUPPORTED
;
589 if (!stats
) return ERROR_INVALID_PARAMETER
;
590 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
591 memset( stats
, 0, sizeof(MIB_ICMP_EX
) );
593 if (family
== WS_AF_INET6
)
599 if ((fp
= fopen("/proc/net/snmp6", "r")))
601 struct icmpstatstruct
{
605 static const struct icmpstatstruct icmpinstatlist
[] = {
606 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH
},
607 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG
},
608 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED
},
609 { "Icmp6InParmProblems", ICMP6_PARAM_PROB
},
610 { "Icmp6InEchos", ICMP6_ECHO_REQUEST
},
611 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY
},
612 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY
},
613 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT
},
614 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION
},
615 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT
},
616 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT
},
617 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT
},
618 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT
},
619 { "Icmp6InRedirects", ND_REDIRECT
},
620 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT
},
622 static const struct icmpstatstruct icmpoutstatlist
[] = {
623 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH
},
624 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG
},
625 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED
},
626 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB
},
627 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST
},
628 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY
},
629 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY
},
630 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT
},
631 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION
},
632 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT
},
633 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT
},
634 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT
},
635 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT
},
636 { "Icmp6OutRedirects", ND_REDIRECT
},
637 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT
},
639 char buf
[512], *ptr
, *value
;
642 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
644 if (!(value
= strchr(buf
, ' ')))
647 /* terminate the valuename */
651 /* and strip leading spaces from value */
653 while (*value
==' ') value
++;
654 if ((ptr
= strchr(value
, '\n')))
657 if (!strcasecmp(buf
, "Icmp6InMsgs"))
659 if (sscanf(value
, "%d", &res
)) stats
->icmpInStats
.dwMsgs
= res
;
663 if (!strcasecmp(buf
, "Icmp6InErrors"))
665 if (sscanf(value
, "%d", &res
)) stats
->icmpInStats
.dwErrors
= res
;
669 for (i
= 0; i
< sizeof(icmpinstatlist
)/sizeof(icmpinstatlist
[0]); i
++)
671 if (!strcasecmp(buf
, icmpinstatlist
[i
].name
))
673 if (sscanf(value
, "%d", &res
))
674 stats
->icmpInStats
.rgdwTypeCount
[icmpinstatlist
[i
].pos
] = res
;
679 if (!strcasecmp(buf
, "Icmp6OutMsgs"))
681 if (sscanf(value
, "%d", &res
)) stats
->icmpOutStats
.dwMsgs
= res
;
685 if (!strcasecmp(buf
, "Icmp6OutErrors"))
687 if (sscanf(value
, "%d", &res
)) stats
->icmpOutStats
.dwErrors
= res
;
691 for (i
= 0; i
< sizeof(icmpoutstatlist
)/sizeof(icmpoutstatlist
[0]); i
++)
693 if (!strcasecmp(buf
, icmpoutstatlist
[i
].name
))
695 if (sscanf(value
, "%d", &res
))
696 stats
->icmpOutStats
.rgdwTypeCount
[icmpoutstatlist
[i
].pos
] = res
;
707 FIXME( "unimplemented for IPv6\n" );
712 ret
= GetIcmpStatistics(&ipv4stats
);
715 stats
->icmpInStats
.dwMsgs
= ipv4stats
.stats
.icmpInStats
.dwMsgs
;
716 stats
->icmpInStats
.dwErrors
= ipv4stats
.stats
.icmpInStats
.dwErrors
;
717 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_DST_UNREACH
] = ipv4stats
.stats
.icmpInStats
.dwDestUnreachs
;
718 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_SOURCE_QUENCH
] = ipv4stats
.stats
.icmpInStats
.dwSrcQuenchs
;
719 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_REDIRECT
] = ipv4stats
.stats
.icmpInStats
.dwRedirects
;
720 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_ECHO_REQUEST
] = ipv4stats
.stats
.icmpInStats
.dwEchos
;
721 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_TIME_EXCEEDED
] = ipv4stats
.stats
.icmpInStats
.dwTimeExcds
;
722 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_PARAM_PROB
] = ipv4stats
.stats
.icmpInStats
.dwParmProbs
;
723 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
] = ipv4stats
.stats
.icmpInStats
.dwTimestamps
;
724 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
] = ipv4stats
.stats
.icmpInStats
.dwTimestampReps
;
725 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_MASK_REQUEST
] = ipv4stats
.stats
.icmpInStats
.dwAddrMasks
;
726 stats
->icmpInStats
.rgdwTypeCount
[ICMP4_MASK_REPLY
] = ipv4stats
.stats
.icmpInStats
.dwAddrMaskReps
;
728 stats
->icmpOutStats
.dwMsgs
= ipv4stats
.stats
.icmpOutStats
.dwMsgs
;
729 stats
->icmpOutStats
.dwErrors
= ipv4stats
.stats
.icmpOutStats
.dwErrors
;
730 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_DST_UNREACH
] = ipv4stats
.stats
.icmpOutStats
.dwDestUnreachs
;
731 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_SOURCE_QUENCH
] = ipv4stats
.stats
.icmpOutStats
.dwSrcQuenchs
;
732 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_REDIRECT
] = ipv4stats
.stats
.icmpOutStats
.dwRedirects
;
733 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_ECHO_REQUEST
] = ipv4stats
.stats
.icmpOutStats
.dwEchos
;
734 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_TIME_EXCEEDED
] = ipv4stats
.stats
.icmpOutStats
.dwTimeExcds
;
735 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_PARAM_PROB
] = ipv4stats
.stats
.icmpOutStats
.dwParmProbs
;
736 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REQUEST
] = ipv4stats
.stats
.icmpOutStats
.dwTimestamps
;
737 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_TIMESTAMP_REPLY
] = ipv4stats
.stats
.icmpOutStats
.dwTimestampReps
;
738 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_MASK_REQUEST
] = ipv4stats
.stats
.icmpOutStats
.dwAddrMasks
;
739 stats
->icmpOutStats
.rgdwTypeCount
[ICMP4_MASK_REPLY
] = ipv4stats
.stats
.icmpOutStats
.dwAddrMaskReps
;
744 /******************************************************************
745 * GetIpStatisticsEx (IPHLPAPI.@)
747 * Get the IPv4 and IPv6 statistics for the local computer.
750 * stats [Out] buffer for IP statistics
751 * family [In] specifies whether IPv4 or IPv6 statistics are returned
755 * Failure: error code from winerror.h
757 DWORD WINAPI
GetIpStatisticsEx(PMIB_IPSTATS stats
, DWORD family
)
759 DWORD ret
= ERROR_NOT_SUPPORTED
;
760 MIB_IPFORWARDTABLE
*fwd_table
;
762 if (!stats
) return ERROR_INVALID_PARAMETER
;
763 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
764 memset( stats
, 0, sizeof(*stats
) );
766 stats
->dwNumIf
= stats
->dwNumAddr
= get_interface_indices( FALSE
, NULL
);
767 if (!AllocateAndGetIpForwardTableFromStack( &fwd_table
, FALSE
, GetProcessHeap(), 0 ))
769 stats
->dwNumRoutes
= fwd_table
->dwNumEntries
;
770 HeapFree( GetProcessHeap(), 0, fwd_table
);
773 if (family
== WS_AF_INET6
)
779 if ((fp
= fopen("/proc/net/snmp6", "r")))
785 { "Ip6InReceives", &stats
->dwInReceives
},
786 { "Ip6InHdrErrors", &stats
->dwInHdrErrors
},
787 { "Ip6InAddrErrors", &stats
->dwInAddrErrors
},
788 { "Ip6OutForwDatagrams", &stats
->dwForwDatagrams
},
789 { "Ip6InUnknownProtos", &stats
->dwInUnknownProtos
},
790 { "Ip6InDiscards", &stats
->dwInDiscards
},
791 { "Ip6InDelivers", &stats
->dwInDelivers
},
792 { "Ip6OutRequests", &stats
->dwOutRequests
},
793 { "Ip6OutDiscards", &stats
->dwOutDiscards
},
794 { "Ip6OutNoRoutes", &stats
->dwOutNoRoutes
},
795 { "Ip6ReasmTimeout", &stats
->dwReasmTimeout
},
796 { "Ip6ReasmReqds", &stats
->dwReasmReqds
},
797 { "Ip6ReasmOKs", &stats
->dwReasmOks
},
798 { "Ip6ReasmFails", &stats
->dwReasmFails
},
799 { "Ip6FragOKs", &stats
->dwFragOks
},
800 { "Ip6FragFails", &stats
->dwFragFails
},
801 { "Ip6FragCreates", &stats
->dwFragCreates
},
802 /* hmm, no routingDiscards, defaultTTL and forwarding? */
804 char buf
[512], *ptr
, *value
;
807 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
809 if (!(value
= strchr(buf
, ' ')))
812 /* terminate the valuename */
816 /* and strip leading spaces from value */
818 while (*value
==' ') value
++;
819 if ((ptr
= strchr(value
, '\n')))
822 for (i
= 0; i
< sizeof(ipstatlist
)/sizeof(ipstatlist
[0]); i
++)
823 if (!strcasecmp(buf
, ipstatlist
[i
].name
))
825 if (sscanf(value
, "%d", &res
)) *ipstatlist
[i
].elem
= res
;
834 FIXME( "unimplemented for IPv6\n" );
843 if ((fp
= fopen("/proc/net/snmp", "r")))
845 static const char hdr
[] = "Ip:";
848 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
850 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
851 /* last line was a header, get another */
852 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
853 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
856 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
857 &stats
->u
.dwForwarding
,
858 &stats
->dwDefaultTTL
,
859 &stats
->dwInReceives
,
860 &stats
->dwInHdrErrors
,
861 &stats
->dwInAddrErrors
,
862 &stats
->dwForwDatagrams
,
863 &stats
->dwInUnknownProtos
,
864 &stats
->dwInDiscards
,
865 &stats
->dwInDelivers
,
866 &stats
->dwOutRequests
,
867 &stats
->dwOutDiscards
,
868 &stats
->dwOutNoRoutes
,
869 &stats
->dwReasmTimeout
,
870 &stats
->dwReasmReqds
,
872 &stats
->dwReasmFails
,
875 &stats
->dwFragCreates
);
876 /* hmm, no routingDiscards */
884 #elif defined(HAVE_LIBKSTAT)
886 static char ip
[] = "ip";
890 if ((kc
= kstat_open()) &&
891 (ksp
= kstat_lookup( kc
, ip
, 0, ip
)) &&
892 kstat_read( kc
, ksp
, NULL
) != -1 &&
893 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
895 stats
->u
.dwForwarding
= kstat_get_ui32( ksp
, "forwarding" );
896 stats
->dwDefaultTTL
= kstat_get_ui32( ksp
, "defaultTTL" );
897 stats
->dwInReceives
= kstat_get_ui32( ksp
, "inReceives" );
898 stats
->dwInHdrErrors
= kstat_get_ui32( ksp
, "inHdrErrors" );
899 stats
->dwInAddrErrors
= kstat_get_ui32( ksp
, "inAddrErrors" );
900 stats
->dwForwDatagrams
= kstat_get_ui32( ksp
, "forwDatagrams" );
901 stats
->dwInUnknownProtos
= kstat_get_ui32( ksp
, "inUnknownProtos" );
902 stats
->dwInDiscards
= kstat_get_ui32( ksp
, "inDiscards" );
903 stats
->dwInDelivers
= kstat_get_ui32( ksp
, "inDelivers" );
904 stats
->dwOutRequests
= kstat_get_ui32( ksp
, "outRequests" );
905 stats
->dwRoutingDiscards
= kstat_get_ui32( ksp
, "routingDiscards" );
906 stats
->dwOutDiscards
= kstat_get_ui32( ksp
, "outDiscards" );
907 stats
->dwOutNoRoutes
= kstat_get_ui32( ksp
, "outNoRoutes" );
908 stats
->dwReasmTimeout
= kstat_get_ui32( ksp
, "reasmTimeout" );
909 stats
->dwReasmReqds
= kstat_get_ui32( ksp
, "reasmReqds" );
910 stats
->dwReasmOks
= kstat_get_ui32( ksp
, "reasmOKs" );
911 stats
->dwReasmFails
= kstat_get_ui32( ksp
, "reasmFails" );
912 stats
->dwFragOks
= kstat_get_ui32( ksp
, "fragOKs" );
913 stats
->dwFragFails
= kstat_get_ui32( ksp
, "fragFails" );
914 stats
->dwFragCreates
= kstat_get_ui32( ksp
, "fragCreates" );
917 if (kc
) kstat_close( kc
);
919 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
921 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
922 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
923 int ip_ttl
, ip_forwarding
;
924 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
925 struct ipstat ip_stat
;
926 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
927 struct ip_stats ip_stat
;
931 needed
= sizeof(ip_stat
);
932 if(sysctl(mib
, MIB_LEN
, &ip_stat
, &needed
, NULL
, 0) == -1)
934 ERR ("failed to get ipstat\n");
935 return ERROR_NOT_SUPPORTED
;
938 needed
= sizeof(ip_ttl
);
939 if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl
, &needed
, NULL
, 0) == -1)
941 ERR ("failed to get ip Default TTL\n");
942 return ERROR_NOT_SUPPORTED
;
945 needed
= sizeof(ip_forwarding
);
946 if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding
, &needed
, NULL
, 0) == -1)
948 ERR ("failed to get ip forwarding\n");
949 return ERROR_NOT_SUPPORTED
;
952 stats
->u
.dwForwarding
= ip_forwarding
;
953 stats
->dwDefaultTTL
= ip_ttl
;
954 stats
->dwInDelivers
= ip_stat
.ips_delivered
;
955 stats
->dwInHdrErrors
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
;
956 stats
->dwInAddrErrors
= ip_stat
.ips_cantforward
;
957 stats
->dwInReceives
= ip_stat
.ips_total
;
958 stats
->dwForwDatagrams
= ip_stat
.ips_forward
;
959 stats
->dwInUnknownProtos
= ip_stat
.ips_noproto
;
960 stats
->dwInDiscards
= ip_stat
.ips_fragdropped
;
961 stats
->dwOutDiscards
= ip_stat
.ips_odropped
;
962 stats
->dwReasmOks
= ip_stat
.ips_reassembled
;
963 stats
->dwFragOks
= ip_stat
.ips_fragmented
;
964 stats
->dwFragFails
= ip_stat
.ips_cantfrag
;
965 stats
->dwReasmTimeout
= ip_stat
.ips_fragtimeout
;
966 stats
->dwOutNoRoutes
= ip_stat
.ips_noroute
;
967 stats
->dwOutRequests
= ip_stat
.ips_localout
;
968 stats
->dwReasmReqds
= ip_stat
.ips_fragments
;
972 FIXME( "unimplemented for IPv4\n" );
977 /******************************************************************
978 * GetIpStatistics (IPHLPAPI.@)
980 * Get the IP statistics for the local computer.
983 * stats [Out] buffer for IP statistics
987 * Failure: error code from winerror.h
989 DWORD WINAPI
GetIpStatistics(PMIB_IPSTATS stats
)
991 return GetIpStatisticsEx(stats
, WS_AF_INET
);
994 /******************************************************************
995 * GetTcpStatisticsEx (IPHLPAPI.@)
997 * Get the IPv4 and IPv6 TCP statistics for the local computer.
1000 * stats [Out] buffer for TCP statistics
1001 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1005 * Failure: error code from winerror.h
1007 DWORD WINAPI
GetTcpStatisticsEx(PMIB_TCPSTATS stats
, DWORD family
)
1009 DWORD ret
= ERROR_NOT_SUPPORTED
;
1011 if (!stats
) return ERROR_INVALID_PARAMETER
;
1012 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
1013 memset( stats
, 0, sizeof(*stats
) );
1015 if (family
== WS_AF_INET6
)
1017 FIXME( "unimplemented for IPv6\n" );
1025 if ((fp
= fopen("/proc/net/snmp", "r")))
1027 static const char hdr
[] = "Tcp:";
1028 MIB_TCPTABLE
*tcp_table
;
1029 char buf
[512], *ptr
;
1031 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1033 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
1034 /* last line was a header, get another */
1035 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
1036 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
1039 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
1040 &stats
->u
.dwRtoAlgorithm
,
1044 &stats
->dwActiveOpens
,
1045 &stats
->dwPassiveOpens
,
1046 &stats
->dwAttemptFails
,
1047 &stats
->dwEstabResets
,
1048 &stats
->dwCurrEstab
,
1051 &stats
->dwRetransSegs
,
1053 &stats
->dwOutRsts
);
1057 if (!AllocateAndGetTcpTableFromStack( &tcp_table
, FALSE
, GetProcessHeap(), 0 ))
1059 stats
->dwNumConns
= tcp_table
->dwNumEntries
;
1060 HeapFree( GetProcessHeap(), 0, tcp_table
);
1066 #elif defined(HAVE_LIBKSTAT)
1068 static char tcp
[] = "tcp";
1072 if ((kc
= kstat_open()) &&
1073 (ksp
= kstat_lookup( kc
, tcp
, 0, tcp
)) &&
1074 kstat_read( kc
, ksp
, NULL
) != -1 &&
1075 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
1077 stats
->u
.dwRtoAlgorithm
= kstat_get_ui32( ksp
, "rtoAlgorithm" );
1078 stats
->dwRtoMin
= kstat_get_ui32( ksp
, "rtoMin" );
1079 stats
->dwRtoMax
= kstat_get_ui32( ksp
, "rtoMax" );
1080 stats
->dwMaxConn
= kstat_get_ui32( ksp
, "maxConn" );
1081 stats
->dwActiveOpens
= kstat_get_ui32( ksp
, "activeOpens" );
1082 stats
->dwPassiveOpens
= kstat_get_ui32( ksp
, "passiveOpens" );
1083 stats
->dwAttemptFails
= kstat_get_ui32( ksp
, "attemptFails" );
1084 stats
->dwEstabResets
= kstat_get_ui32( ksp
, "estabResets" );
1085 stats
->dwCurrEstab
= kstat_get_ui32( ksp
, "currEstab" );
1086 stats
->dwInSegs
= kstat_get_ui32( ksp
, "inSegs" );
1087 stats
->dwOutSegs
= kstat_get_ui32( ksp
, "outSegs" );
1088 stats
->dwRetransSegs
= kstat_get_ui32( ksp
, "retransSegs" );
1089 stats
->dwInErrs
= kstat_get_ui32( ksp
, "inErrs" );
1090 stats
->dwOutRsts
= kstat_get_ui32( ksp
, "outRsts" );
1091 stats
->dwNumConns
= kstat_get_ui32( ksp
, "connTableSize" );
1094 if (kc
) kstat_close( kc
);
1096 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
1098 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
1100 #define TCPTV_REXMTMAX 128
1102 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
1103 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1105 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
1106 struct tcpstat tcp_stat
;
1107 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
1108 struct tcp_stats tcp_stat
;
1110 size_t needed
= sizeof(tcp_stat
);
1112 if(sysctl(mib
, MIB_LEN
, &tcp_stat
, &needed
, NULL
, 0) != -1)
1114 stats
->u
.RtoAlgorithm
= MIB_TCP_RTO_VANJ
;
1115 stats
->dwRtoMin
= TCPTV_MIN
;
1116 stats
->dwRtoMax
= TCPTV_REXMTMAX
;
1117 stats
->dwMaxConn
= -1;
1118 stats
->dwActiveOpens
= tcp_stat
.tcps_connattempt
;
1119 stats
->dwPassiveOpens
= tcp_stat
.tcps_accepts
;
1120 stats
->dwAttemptFails
= tcp_stat
.tcps_conndrops
;
1121 stats
->dwEstabResets
= tcp_stat
.tcps_drops
;
1122 stats
->dwCurrEstab
= 0;
1123 stats
->dwInSegs
= tcp_stat
.tcps_rcvtotal
;
1124 stats
->dwOutSegs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
1125 stats
->dwRetransSegs
= tcp_stat
.tcps_sndrexmitpack
;
1126 stats
->dwInErrs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
1127 stats
->dwOutRsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
1128 stats
->dwNumConns
= tcp_stat
.tcps_connects
;
1131 else ERR ("failed to get tcpstat\n");
1134 FIXME( "unimplemented\n" );
1139 /******************************************************************
1140 * GetTcpStatistics (IPHLPAPI.@)
1142 * Get the TCP statistics for the local computer.
1145 * stats [Out] buffer for TCP statistics
1149 * Failure: error code from winerror.h
1151 DWORD WINAPI
GetTcpStatistics(PMIB_TCPSTATS stats
)
1153 return GetTcpStatisticsEx(stats
, WS_AF_INET
);
1156 /******************************************************************
1157 * GetUdpStatistics (IPHLPAPI.@)
1159 * Get the IPv4 and IPv6 UDP statistics for the local computer.
1162 * stats [Out] buffer for UDP statistics
1163 * family [In] specifies whether IPv4 or IPv6 statistics are returned
1167 * Failure: error code from winerror.h
1169 DWORD WINAPI
GetUdpStatisticsEx(PMIB_UDPSTATS stats
, DWORD family
)
1171 DWORD ret
= ERROR_NOT_SUPPORTED
;
1173 if (!stats
) return ERROR_INVALID_PARAMETER
;
1174 if (family
!= WS_AF_INET
&& family
!= WS_AF_INET6
) return ERROR_INVALID_PARAMETER
;
1175 memset( stats
, 0, sizeof(*stats
) );
1177 stats
->dwNumAddrs
= get_interface_indices( FALSE
, NULL
);
1179 if (family
== WS_AF_INET6
)
1185 if ((fp
= fopen("/proc/net/snmp6", "r")))
1191 { "Udp6InDatagrams", &stats
->dwInDatagrams
},
1192 { "Udp6NoPorts", &stats
->dwNoPorts
},
1193 { "Udp6InErrors", &stats
->dwInErrors
},
1194 { "Udp6OutDatagrams", &stats
->dwOutDatagrams
},
1196 char buf
[512], *ptr
, *value
;
1199 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1201 if (!(value
= strchr(buf
, ' ')))
1204 /* terminate the valuename */
1208 /* and strip leading spaces from value */
1210 while (*value
==' ') value
++;
1211 if ((ptr
= strchr(value
, '\n')))
1214 for (i
= 0; i
< sizeof(udpstatlist
)/sizeof(udpstatlist
[0]); i
++)
1215 if (!strcasecmp(buf
, udpstatlist
[i
].name
))
1217 if (sscanf(value
, "%d", &res
)) *udpstatlist
[i
].elem
= res
;
1226 FIXME( "unimplemented for IPv6\n" );
1235 if ((fp
= fopen("/proc/net/snmp", "r")))
1237 static const char hdr
[] = "Udp:";
1238 char buf
[512], *ptr
;
1240 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1242 if (strncasecmp(buf
, hdr
, sizeof(hdr
) - 1)) continue;
1243 /* last line was a header, get another */
1244 if (!(ptr
= fgets(buf
, sizeof(buf
), fp
))) break;
1245 if (!strncasecmp(buf
, hdr
, sizeof(hdr
) - 1))
1248 sscanf( ptr
, "%u %u %u %u %u",
1249 &stats
->dwInDatagrams
, &stats
->dwNoPorts
,
1250 &stats
->dwInErrors
, &stats
->dwOutDatagrams
, &stats
->dwNumAddrs
);
1258 #elif defined(HAVE_LIBKSTAT)
1260 static char udp
[] = "udp";
1263 MIB_UDPTABLE
*udp_table
;
1265 if ((kc
= kstat_open()) &&
1266 (ksp
= kstat_lookup( kc
, udp
, 0, udp
)) &&
1267 kstat_read( kc
, ksp
, NULL
) != -1 &&
1268 ksp
->ks_type
== KSTAT_TYPE_NAMED
)
1270 stats
->dwInDatagrams
= kstat_get_ui32( ksp
, "inDatagrams" );
1271 stats
->dwNoPorts
= 0; /* FIXME */
1272 stats
->dwInErrors
= kstat_get_ui32( ksp
, "inErrors" );
1273 stats
->dwOutDatagrams
= kstat_get_ui32( ksp
, "outDatagrams" );
1274 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
1276 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
1277 HeapFree( GetProcessHeap(), 0, udp_table
);
1281 if (kc
) kstat_close( kc
);
1283 #elif defined(HAVE_SYS_SYSCTL_H) && defined(UDPCTL_STATS) && defined(HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS)
1285 int mib
[] = {CTL_NET
, PF_INET
, IPPROTO_UDP
, UDPCTL_STATS
};
1286 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1287 struct udpstat udp_stat
;
1288 MIB_UDPTABLE
*udp_table
;
1289 size_t needed
= sizeof(udp_stat
);
1291 if(sysctl(mib
, MIB_LEN
, &udp_stat
, &needed
, NULL
, 0) != -1)
1293 stats
->dwInDatagrams
= udp_stat
.udps_ipackets
;
1294 stats
->dwOutDatagrams
= udp_stat
.udps_opackets
;
1295 stats
->dwNoPorts
= udp_stat
.udps_noport
;
1296 stats
->dwInErrors
= udp_stat
.udps_hdrops
+ udp_stat
.udps_badsum
+ udp_stat
.udps_fullsock
+ udp_stat
.udps_badlen
;
1297 if (!AllocateAndGetUdpTableFromStack( &udp_table
, FALSE
, GetProcessHeap(), 0 ))
1299 stats
->dwNumAddrs
= udp_table
->dwNumEntries
;
1300 HeapFree( GetProcessHeap(), 0, udp_table
);
1304 else ERR ("failed to get udpstat\n");
1307 FIXME( "unimplemented for IPv4\n" );
1312 /******************************************************************
1313 * GetUdpStatistics (IPHLPAPI.@)
1315 * Get the UDP statistics for the local computer.
1318 * stats [Out] buffer for UDP statistics
1322 * Failure: error code from winerror.h
1324 DWORD WINAPI
GetUdpStatistics(PMIB_UDPSTATS stats
)
1326 return GetUdpStatisticsEx(stats
, WS_AF_INET
);
1329 static MIB_IPFORWARDTABLE
*append_ipforward_row( HANDLE heap
, DWORD flags
, MIB_IPFORWARDTABLE
*table
,
1330 DWORD
*count
, const MIB_IPFORWARDROW
*row
)
1332 if (table
->dwNumEntries
>= *count
)
1334 MIB_IPFORWARDTABLE
*new_table
;
1335 DWORD new_count
= table
->dwNumEntries
* 2;
1337 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
1338 FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[new_count
] ))))
1340 HeapFree( heap
, 0, table
);
1346 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1350 static int compare_ipforward_rows(const void *a
, const void *b
)
1352 const MIB_IPFORWARDROW
*rowA
= a
;
1353 const MIB_IPFORWARDROW
*rowB
= b
;
1356 if ((ret
= rowA
->dwForwardDest
- rowB
->dwForwardDest
) != 0) return ret
;
1357 if ((ret
= rowA
->u2
.dwForwardProto
- rowB
->u2
.dwForwardProto
) != 0) return ret
;
1358 if ((ret
= rowA
->dwForwardPolicy
- rowB
->dwForwardPolicy
) != 0) return ret
;
1359 return rowA
->dwForwardNextHop
- rowB
->dwForwardNextHop
;
1362 /******************************************************************
1363 * AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
1365 * Get the route table.
1366 * Like GetIpForwardTable(), but allocate the returned table from heap.
1369 * ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
1370 * allocated and returned.
1371 * bOrder [In] whether to sort the table
1372 * heap [In] heap from which the table is allocated
1373 * flags [In] flags to HeapAlloc
1376 * ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
1377 * on failure, NO_ERROR on success.
1379 DWORD WINAPI
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE
*ppIpForwardTable
, BOOL bOrder
,
1380 HANDLE heap
, DWORD flags
)
1382 MIB_IPFORWARDTABLE
*table
;
1383 MIB_IPFORWARDROW row
;
1384 DWORD ret
= NO_ERROR
, count
= 16;
1386 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpForwardTable
, bOrder
, heap
, flags
);
1388 if (!ppIpForwardTable
) return ERROR_INVALID_PARAMETER
;
1390 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPFORWARDTABLE
, table
[count
] ))))
1391 return ERROR_OUTOFMEMORY
;
1393 table
->dwNumEntries
= 0;
1399 if ((fp
= fopen("/proc/net/route", "r")))
1401 char buf
[512], *ptr
;
1404 /* skip header line */
1405 ptr
= fgets(buf
, sizeof(buf
), fp
);
1406 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1408 memset( &row
, 0, sizeof(row
) );
1410 while (!isspace(*ptr
)) ptr
++;
1412 if (getInterfaceIndexByName(buf
, &row
.dwForwardIfIndex
) != NO_ERROR
)
1415 row
.dwForwardDest
= strtoul(ptr
, &ptr
, 16);
1416 row
.dwForwardNextHop
= strtoul(ptr
+ 1, &ptr
, 16);
1417 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1419 if (!(flags
& RTF_UP
)) row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INVALID
;
1420 else if (flags
& RTF_GATEWAY
) row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_INDIRECT
;
1421 else row
.u1
.ForwardType
= MIB_IPROUTE_TYPE_DIRECT
;
1423 strtoul(ptr
+ 1, &ptr
, 16); /* refcount, skip */
1424 strtoul(ptr
+ 1, &ptr
, 16); /* use, skip */
1425 row
.dwForwardMetric1
= strtoul(ptr
+ 1, &ptr
, 16);
1426 row
.dwForwardMask
= strtoul(ptr
+ 1, &ptr
, 16);
1427 /* FIXME: other protos might be appropriate, e.g. the default
1428 * route is typically set with MIB_IPPROTO_NETMGMT instead */
1429 row
.u2
.ForwardProto
= MIB_IPPROTO_LOCAL
;
1431 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1436 else ret
= ERROR_NOT_SUPPORTED
;
1438 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1441 int fd
, len
, namelen
;
1442 mib2_ipRouteEntry_t
*entry
;
1445 if ((fd
= open_streams_mib( NULL
)) != -1)
1447 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_ROUTE
, &len
)))
1449 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1451 row
.dwForwardDest
= entry
->ipRouteDest
;
1452 row
.dwForwardMask
= entry
->ipRouteMask
;
1453 row
.dwForwardPolicy
= 0;
1454 row
.dwForwardNextHop
= entry
->ipRouteNextHop
;
1455 row
.u1
.dwForwardType
= entry
->ipRouteType
;
1456 row
.u2
.dwForwardProto
= entry
->ipRouteProto
;
1457 row
.dwForwardAge
= entry
->ipRouteAge
;
1458 row
.dwForwardNextHopAS
= 0;
1459 row
.dwForwardMetric1
= entry
->ipRouteMetric1
;
1460 row
.dwForwardMetric2
= entry
->ipRouteMetric2
;
1461 row
.dwForwardMetric3
= entry
->ipRouteMetric3
;
1462 row
.dwForwardMetric4
= entry
->ipRouteMetric4
;
1463 row
.dwForwardMetric5
= entry
->ipRouteMetric5
;
1464 namelen
= min( sizeof(name
) - 1, entry
->ipRouteIfIndex
.o_length
);
1465 memcpy( name
, entry
->ipRouteIfIndex
.o_bytes
, namelen
);
1467 getInterfaceIndexByName( name
, &row
.dwForwardIfIndex
);
1468 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
))) break;
1470 HeapFree( GetProcessHeap(), 0, data
);
1474 else ret
= ERROR_NOT_SUPPORTED
;
1476 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1478 int mib
[6] = {CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0};
1480 char *buf
= NULL
, *lim
, *next
, *addrPtr
;
1481 struct rt_msghdr
*rtm
;
1483 if (sysctl (mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
1485 ERR ("sysctl 1 failed!\n");
1486 ret
= ERROR_NOT_SUPPORTED
;
1490 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1493 ret
= ERROR_OUTOFMEMORY
;
1497 if (sysctl (mib
, 6, buf
, &needed
, NULL
, 0) < 0)
1499 ret
= ERROR_NOT_SUPPORTED
;
1504 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1508 rtm
= (struct rt_msghdr
*)next
;
1510 if (rtm
->rtm_type
!= RTM_GET
)
1512 WARN ("Got unexpected message type 0x%x!\n",
1517 /* Ignore gateway routes which are multicast */
1518 if ((rtm
->rtm_flags
& RTF_GATEWAY
) && (rtm
->rtm_flags
& RTF_MULTICAST
))
1521 memset( &row
, 0, sizeof(row
) );
1522 row
.dwForwardIfIndex
= rtm
->rtm_index
;
1523 row
.u1
.ForwardType
= (rtm
->rtm_flags
& RTF_GATEWAY
) ? MIB_IPROUTE_TYPE_INDIRECT
: MIB_IPROUTE_TYPE_DIRECT
;
1524 row
.dwForwardMetric1
= rtm
->rtm_rmx
.rmx_hopcount
;
1525 row
.u2
.ForwardProto
= MIB_IPPROTO_LOCAL
;
1527 addrPtr
= (char *)(rtm
+ 1);
1529 for (i
= 1; i
; i
<<= 1)
1531 struct sockaddr
*sa
;
1534 if (!(i
& rtm
->rtm_addrs
))
1537 sa
= (struct sockaddr
*)addrPtr
;
1538 ADVANCE (addrPtr
, sa
);
1540 /* default routes are encoded by length-zero sockaddr */
1541 if (sa
->sa_len
== 0) {
1544 switch(sa
->sa_family
) {
1546 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
1547 addr
= sin
->sin_addr
.s_addr
;
1552 if(i
== RTA_GATEWAY
&& row
.u1
.ForwardType
== MIB_IPROUTE_TYPE_DIRECT
) {
1553 /* For direct route we may simply use dest addr as next hop */
1554 C_ASSERT(RTA_DST
< RTA_GATEWAY
);
1555 addr
= row
.dwForwardDest
;
1561 WARN ("Received unsupported sockaddr family 0x%x\n", sa
->sa_family
);
1568 case RTA_DST
: row
.dwForwardDest
= addr
; break;
1569 case RTA_GATEWAY
: row
.dwForwardNextHop
= addr
; break;
1570 case RTA_NETMASK
: row
.dwForwardMask
= addr
; break;
1572 WARN ("Unexpected address type 0x%x\n", i
);
1576 if (!(table
= append_ipforward_row( heap
, flags
, table
, &count
, &row
)))
1580 HeapFree( GetProcessHeap (), 0, buf
);
1583 FIXME( "not implemented\n" );
1584 ret
= ERROR_NOT_SUPPORTED
;
1587 if (!table
) return ERROR_OUTOFMEMORY
;
1590 if (bOrder
&& table
->dwNumEntries
)
1591 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipforward_rows
);
1592 *ppIpForwardTable
= table
;
1594 else HeapFree( heap
, flags
, table
);
1595 TRACE( "returning ret %u table %p\n", ret
, table
);
1599 static MIB_IPNETTABLE
*append_ipnet_row( HANDLE heap
, DWORD flags
, MIB_IPNETTABLE
*table
,
1600 DWORD
*count
, const MIB_IPNETROW
*row
)
1602 if (table
->dwNumEntries
>= *count
)
1604 MIB_IPNETTABLE
*new_table
;
1605 DWORD new_count
= table
->dwNumEntries
* 2;
1607 if (!(new_table
= HeapReAlloc( heap
, flags
, table
,
1608 FIELD_OFFSET(MIB_IPNETTABLE
, table
[new_count
] ))))
1610 HeapFree( heap
, 0, table
);
1616 memcpy( &table
->table
[table
->dwNumEntries
++], row
, sizeof(*row
) );
1620 static int compare_ipnet_rows(const void *a
, const void *b
)
1622 const MIB_IPNETROW
*rowA
= a
;
1623 const MIB_IPNETROW
*rowB
= b
;
1625 return ntohl(rowA
->dwAddr
) - ntohl(rowB
->dwAddr
);
1629 /******************************************************************
1630 * AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
1632 * Get the IP-to-physical address mapping table.
1633 * Like GetIpNetTable(), but allocate the returned table from heap.
1636 * ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
1637 * allocated and returned.
1638 * bOrder [In] whether to sort the table
1639 * heap [In] heap from which the table is allocated
1640 * flags [In] flags to HeapAlloc
1643 * ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
1644 * on failure, NO_ERROR on success.
1646 DWORD WINAPI
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE
*ppIpNetTable
, BOOL bOrder
,
1647 HANDLE heap
, DWORD flags
)
1649 MIB_IPNETTABLE
*table
;
1651 DWORD ret
= NO_ERROR
, count
= 16;
1653 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppIpNetTable
, bOrder
, heap
, flags
);
1655 if (!ppIpNetTable
) return ERROR_INVALID_PARAMETER
;
1657 if (!(table
= HeapAlloc( heap
, flags
, FIELD_OFFSET(MIB_IPNETTABLE
, table
[count
] ))))
1658 return ERROR_OUTOFMEMORY
;
1660 table
->dwNumEntries
= 0;
1666 if ((fp
= fopen("/proc/net/arp", "r")))
1668 char buf
[512], *ptr
;
1671 /* skip header line */
1672 ptr
= fgets(buf
, sizeof(buf
), fp
);
1673 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
1675 memset( &row
, 0, sizeof(row
) );
1677 row
.dwAddr
= inet_addr(ptr
);
1678 while (*ptr
&& !isspace(*ptr
)) ptr
++;
1679 strtoul(ptr
+ 1, &ptr
, 16); /* hw type (skip) */
1680 flags
= strtoul(ptr
+ 1, &ptr
, 16);
1683 if (flags
& ATF_COM
) row
.u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
1687 if (flags
& ATF_PERM
) row
.u
.Type
= MIB_IPNET_TYPE_STATIC
;
1690 row
.u
.Type
= MIB_IPNET_TYPE_OTHER
;
1692 while (*ptr
&& isspace(*ptr
)) ptr
++;
1693 while (*ptr
&& !isspace(*ptr
))
1695 row
.bPhysAddr
[row
.dwPhysAddrLen
++] = strtoul(ptr
, &ptr
, 16);
1698 while (*ptr
&& isspace(*ptr
)) ptr
++;
1699 while (*ptr
&& !isspace(*ptr
)) ptr
++; /* mask (skip) */
1700 while (*ptr
&& isspace(*ptr
)) ptr
++;
1701 getInterfaceIndexByName(ptr
, &row
.dwIndex
);
1703 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1708 else ret
= ERROR_NOT_SUPPORTED
;
1710 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
1713 int fd
, len
, namelen
;
1714 mib2_ipNetToMediaEntry_t
*entry
;
1717 if ((fd
= open_streams_mib( NULL
)) != -1)
1719 if ((data
= read_mib_entry( fd
, MIB2_IP
, MIB2_IP_MEDIA
, &len
)))
1721 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
1723 row
.dwPhysAddrLen
= min( entry
->ipNetToMediaPhysAddress
.o_length
, MAXLEN_PHYSADDR
);
1724 memcpy( row
.bPhysAddr
, entry
->ipNetToMediaPhysAddress
.o_bytes
, row
.dwPhysAddrLen
);
1725 row
.dwAddr
= entry
->ipNetToMediaNetAddress
;
1726 row
.u
.Type
= entry
->ipNetToMediaType
;
1727 namelen
= min( sizeof(name
) - 1, entry
->ipNetToMediaIfIndex
.o_length
);
1728 memcpy( name
, entry
->ipNetToMediaIfIndex
.o_bytes
, namelen
);
1730 getInterfaceIndexByName( name
, &row
.dwIndex
);
1731 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
))) break;
1733 HeapFree( GetProcessHeap(), 0, data
);
1737 else ret
= ERROR_NOT_SUPPORTED
;
1739 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1741 int mib
[] = {CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
};
1742 #define MIB_LEN (sizeof(mib) / sizeof(mib[0]))
1744 char *buf
= NULL
, *lim
, *next
;
1745 struct rt_msghdr
*rtm
;
1746 struct sockaddr_inarp
*sinarp
;
1747 struct sockaddr_dl
*sdl
;
1749 if (sysctl (mib
, MIB_LEN
, NULL
, &needed
, NULL
, 0) == -1)
1751 ERR ("failed to get arp table\n");
1752 ret
= ERROR_NOT_SUPPORTED
;
1756 buf
= HeapAlloc (GetProcessHeap (), 0, needed
);
1759 ret
= ERROR_OUTOFMEMORY
;
1763 if (sysctl (mib
, MIB_LEN
, buf
, &needed
, NULL
, 0) == -1)
1765 ret
= ERROR_NOT_SUPPORTED
;
1773 rtm
= (struct rt_msghdr
*)next
;
1774 sinarp
=(struct sockaddr_inarp
*)(rtm
+ 1);
1775 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ ROUNDUP(sinarp
->sin_len
));
1776 if(sdl
->sdl_alen
) /* arp entry */
1778 memset( &row
, 0, sizeof(row
) );
1779 row
.dwAddr
= sinarp
->sin_addr
.s_addr
;
1780 row
.dwIndex
= sdl
->sdl_index
;
1781 row
.dwPhysAddrLen
= min( 8, sdl
->sdl_alen
);
1782 memcpy( row
.bPhysAddr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], row
.dwPhysAddrLen
);
1783 if(rtm
->rtm_rmx
.rmx_expire
== 0) row
.u
.Type
= MIB_IPNET_TYPE_STATIC
;
1784 else if(sinarp
->sin_other
& SIN_PROXY
) row
.u
.Type
= MIB_IPNET_TYPE_OTHER
;
1785 else if(rtm
->rtm_rmx
.rmx_expire
!= 0) row
.u
.Type
= MIB_IPNET_TYPE_DYNAMIC
;
1786 else row
.u
.Type
= MIB_IPNET_TYPE_INVALID
;
1788 if (!(table
= append_ipnet_row( heap
, flags
, table
, &count
, &row
)))
1791 next
+= rtm
->rtm_msglen
;
1794 HeapFree( GetProcessHeap (), 0, buf
);
1797 FIXME( "not implemented\n" );
1798 ret
= ERROR_NOT_SUPPORTED
;
1801 if (!table
) return ERROR_OUTOFMEMORY
;
1804 if (bOrder
&& table
->dwNumEntries
)
1805 qsort( table
->table
, table
->dwNumEntries
, sizeof(row
), compare_ipnet_rows
);
1806 *ppIpNetTable
= table
;
1808 else HeapFree( heap
, flags
, table
);
1809 TRACE( "returning ret %u table %p\n", ret
, table
);
1813 static DWORD
get_tcp_table_sizes( TCP_TABLE_CLASS
class, DWORD row_count
, DWORD
*row_size
)
1819 case TCP_TABLE_BASIC_LISTENER
:
1820 case TCP_TABLE_BASIC_CONNECTIONS
:
1821 case TCP_TABLE_BASIC_ALL
:
1823 table_size
= FIELD_OFFSET(MIB_TCPTABLE
, table
[row_count
]);
1824 if (row_size
) *row_size
= sizeof(MIB_TCPROW
);
1827 case TCP_TABLE_OWNER_PID_LISTENER
:
1828 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
1829 case TCP_TABLE_OWNER_PID_ALL
:
1831 table_size
= FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID
, table
[row_count
]);
1832 if (row_size
) *row_size
= sizeof(MIB_TCPROW_OWNER_PID
);
1835 case TCP_TABLE_OWNER_MODULE_LISTENER
:
1836 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
1837 case TCP_TABLE_OWNER_MODULE_ALL
:
1839 table_size
= FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE
, table
[row_count
]);
1840 if (row_size
) *row_size
= sizeof(MIB_TCPROW_OWNER_MODULE
);
1844 ERR("unhandled class %u\n", class);
1850 static MIB_TCPTABLE
*append_tcp_row( TCP_TABLE_CLASS
class, HANDLE heap
, DWORD flags
,
1851 MIB_TCPTABLE
*table
, DWORD
*count
,
1852 const MIB_TCPROW_OWNER_MODULE
*row
, DWORD row_size
)
1854 if (table
->dwNumEntries
>= *count
)
1856 MIB_TCPTABLE
*new_table
;
1857 DWORD new_count
= table
->dwNumEntries
* 2, new_table_size
;
1859 new_table_size
= get_tcp_table_sizes( class, new_count
, NULL
);
1860 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, new_table_size
)))
1862 HeapFree( heap
, 0, table
);
1868 memcpy( (char *)table
->table
+ (table
->dwNumEntries
* row_size
), row
, row_size
);
1869 table
->dwNumEntries
++;
1874 /* Why not a lookup table? Because the TCPS_* constants are different
1875 on different platforms */
1876 static inline MIB_TCP_STATE
TCPStateToMIBState (int state
)
1880 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
1881 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
1882 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
1883 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
1884 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
1885 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
1886 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
1887 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
1888 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
1889 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
1891 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
1895 static int compare_tcp_rows(const void *a
, const void *b
)
1897 const MIB_TCPROW
*rowA
= a
;
1898 const MIB_TCPROW
*rowB
= b
;
1901 if ((ret
= ntohl (rowA
->dwLocalAddr
) - ntohl (rowB
->dwLocalAddr
)) != 0) return ret
;
1902 if ((ret
= ntohs ((unsigned short)rowA
->dwLocalPort
) -
1903 ntohs ((unsigned short)rowB
->dwLocalPort
)) != 0) return ret
;
1904 if ((ret
= ntohl (rowA
->dwRemoteAddr
) - ntohl (rowB
->dwRemoteAddr
)) != 0) return ret
;
1905 return ntohs ((unsigned short)rowA
->dwRemotePort
) - ntohs ((unsigned short)rowB
->dwRemotePort
);
1911 unsigned int unix_pid
;
1914 static struct pid_map
*get_pid_map( unsigned int *num_entries
)
1916 HANDLE snapshot
= NULL
;
1917 struct pid_map
*map
;
1918 unsigned int i
= 0, count
= 16, size
= count
* sizeof(*map
);
1921 if (!(map
= HeapAlloc( GetProcessHeap(), 0, size
))) return NULL
;
1923 SERVER_START_REQ( create_snapshot
)
1925 req
->flags
= SNAP_PROCESS
;
1926 req
->attributes
= 0;
1927 if (!(ret
= wine_server_call( req
)))
1928 snapshot
= wine_server_ptr_handle( reply
->handle
);
1933 while (ret
== STATUS_SUCCESS
)
1935 SERVER_START_REQ( next_process
)
1937 req
->handle
= wine_server_obj_handle( snapshot
);
1938 req
->reset
= (i
== 0);
1939 if (!(ret
= wine_server_call( req
)))
1943 struct pid_map
*new_map
;
1945 size
= count
* sizeof(*new_map
);
1947 if (!(new_map
= HeapReAlloc( GetProcessHeap(), 0, map
, size
)))
1949 HeapFree( GetProcessHeap(), 0, map
);
1955 map
[i
].pid
= reply
->pid
;
1956 map
[i
].unix_pid
= reply
->unix_pid
;
1965 NtClose( snapshot
);
1969 static unsigned int find_owning_pid( struct pid_map
*map
, unsigned int num_entries
, UINT_PTR inode
)
1972 unsigned int i
, len_socket
;
1975 sprintf( socket
, "socket:[%lu]", inode
);
1976 len_socket
= strlen( socket
);
1977 for (i
= 0; i
< num_entries
; i
++)
1980 struct dirent
*dirent
;
1983 sprintf( dir
, "/proc/%u/fd", map
[i
].unix_pid
);
1984 if ((dirfd
= opendir( dir
)))
1986 while ((dirent
= readdir( dirfd
)))
1988 char link
[sizeof(dirent
->d_name
) + 32], name
[32];
1991 sprintf( link
, "/proc/%u/fd/%s", map
[i
].unix_pid
, dirent
->d_name
);
1992 if ((len
= readlink( link
, name
, 32 )) > 0) name
[len
] = 0;
1993 if (len
== len_socket
&& !strcmp( socket
, name
))
2003 #elif defined(HAVE_LIBPROCSTAT)
2004 struct procstat
*pstat
;
2005 struct kinfo_proc
*proc
;
2006 struct filestat_list
*fds
;
2007 struct filestat
*fd
;
2008 struct sockstat sock
;
2009 unsigned int i
, proc_count
;
2011 pstat
= procstat_open_sysctl();
2012 if (!pstat
) return 0;
2014 for (i
= 0; i
< num_entries
; i
++)
2016 proc
= procstat_getprocs( pstat
, KERN_PROC_PID
, map
[i
].unix_pid
, &proc_count
);
2017 if (!proc
|| proc_count
< 1) continue;
2019 fds
= procstat_getfiles( pstat
, proc
, 0 );
2022 procstat_freeprocs( pstat
, proc
);
2026 STAILQ_FOREACH( fd
, fds
, next
)
2028 char errbuf
[_POSIX2_LINE_MAX
];
2030 if (fd
->fs_type
!= PS_FST_TYPE_SOCKET
) continue;
2032 procstat_get_socket_info( pstat
, fd
, &sock
, errbuf
);
2034 if (sock
.so_pcb
== inode
)
2036 procstat_freefiles( pstat
, fds
);
2037 procstat_freeprocs( pstat
, proc
);
2038 procstat_close( pstat
);
2043 procstat_freefiles( pstat
, fds
);
2044 procstat_freeprocs( pstat
, proc
);
2047 procstat_close( pstat
);
2049 #elif defined(HAVE_PROC_PIDINFO)
2050 struct proc_fdinfo
*fds
;
2051 struct socket_fdinfo sock
;
2052 unsigned int i
, j
, n
, fd_len
;
2054 for (i
= 0; i
< num_entries
; i
++)
2056 fd_len
= proc_pidinfo( map
[i
].unix_pid
, PROC_PIDLISTFDS
, 0, NULL
, 0 );
2057 if (fd_len
<= 0) continue;
2059 fds
= HeapAlloc( GetProcessHeap(), 0, fd_len
);
2062 proc_pidinfo( map
[i
].unix_pid
, PROC_PIDLISTFDS
, 0, fds
, fd_len
);
2063 n
= fd_len
/ sizeof(struct proc_fdinfo
);
2064 for (j
= 0; j
< n
; j
++)
2066 if (fds
[j
].proc_fdtype
!= PROX_FDTYPE_SOCKET
) continue;
2068 proc_pidfdinfo( map
[i
].unix_pid
, fds
[j
].proc_fd
, PROC_PIDFDSOCKETINFO
, &sock
, sizeof(sock
) );
2069 if (sock
.psi
.soi_pcb
== inode
)
2071 HeapFree( GetProcessHeap(), 0, fds
);
2076 HeapFree( GetProcessHeap(), 0, fds
);
2080 FIXME( "not implemented\n" );
2085 static BOOL
match_class( TCP_TABLE_CLASS
class, MIB_TCP_STATE state
)
2089 case TCP_TABLE_BASIC_ALL
:
2090 case TCP_TABLE_OWNER_PID_ALL
:
2091 case TCP_TABLE_OWNER_MODULE_ALL
:
2094 case TCP_TABLE_BASIC_LISTENER
:
2095 case TCP_TABLE_OWNER_PID_LISTENER
:
2096 case TCP_TABLE_OWNER_MODULE_LISTENER
:
2097 if (state
== MIB_TCP_STATE_LISTEN
) return TRUE
;
2100 case TCP_TABLE_BASIC_CONNECTIONS
:
2101 case TCP_TABLE_OWNER_PID_CONNECTIONS
:
2102 case TCP_TABLE_OWNER_MODULE_CONNECTIONS
:
2103 if (state
== MIB_TCP_STATE_ESTAB
) return TRUE
;
2107 ERR( "unhandled class %u\n", class );
2112 DWORD
build_tcp_table( TCP_TABLE_CLASS
class, void **tablep
, BOOL order
, HANDLE heap
, DWORD flags
,
2115 MIB_TCPTABLE
*table
;
2116 MIB_TCPROW_OWNER_MODULE row
;
2117 DWORD ret
= NO_ERROR
, count
= 16, table_size
, row_size
;
2119 if (!(table_size
= get_tcp_table_sizes( class, count
, &row_size
)))
2120 return ERROR_INVALID_PARAMETER
;
2122 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
2123 return ERROR_OUTOFMEMORY
;
2125 table
->dwNumEntries
= 0;
2131 if ((fp
= fopen("/proc/net/tcp", "r")))
2133 char buf
[512], *ptr
;
2134 struct pid_map
*map
= NULL
;
2135 unsigned int dummy
, num_entries
= 0;
2138 if (class >= TCP_TABLE_OWNER_PID_LISTENER
) map
= get_pid_map( &num_entries
);
2140 /* skip header line */
2141 ptr
= fgets(buf
, sizeof(buf
), fp
);
2142 while ((ptr
= fgets(buf
, sizeof(buf
), fp
)))
2144 if (sscanf( ptr
, "%x: %x:%x %x:%x %x %*s %*s %*s %*s %*s %d", &dummy
,
2145 &row
.dwLocalAddr
, &row
.dwLocalPort
, &row
.dwRemoteAddr
,
2146 &row
.dwRemotePort
, &row
.dwState
, &inode
) != 7)
2148 row
.dwLocalPort
= htons( row
.dwLocalPort
);
2149 row
.dwRemotePort
= htons( row
.dwRemotePort
);
2150 row
.dwState
= TCPStateToMIBState( row
.dwState
);
2151 if (!match_class( class, row
.dwState
)) continue;
2153 if (class >= TCP_TABLE_OWNER_PID_LISTENER
)
2154 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, inode
);
2155 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER
)
2157 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2158 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2160 if (!(table
= append_tcp_row( class, heap
, flags
, table
, &count
, &row
, row_size
)))
2163 HeapFree( GetProcessHeap(), 0, map
);
2166 else ret
= ERROR_NOT_SUPPORTED
;
2168 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2172 mib2_tcpConnEntry_t
*entry
;
2174 if ((fd
= open_streams_mib( "tcp" )) != -1)
2176 if ((data
= read_mib_entry( fd
, MIB2_TCP
, MIB2_TCP_CONN
, &len
)))
2178 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
2180 row
.dwLocalAddr
= entry
->tcpConnLocalAddress
;
2181 row
.dwLocalPort
= htons( entry
->tcpConnLocalPort
);
2182 row
.dwRemoteAddr
= entry
->tcpConnRemAddress
;
2183 row
.dwRemotePort
= htons( entry
->tcpConnRemPort
);
2184 row
.dwState
= entry
->tcpConnState
;
2185 if (!match_class( class, row
.dwState
)) continue;
2186 if (!(table
= append_tcp_row( class, heap
, flags
, table
, &count
, &row
, row_size
)))
2189 HeapFree( GetProcessHeap(), 0, data
);
2193 else ret
= ERROR_NOT_SUPPORTED
;
2195 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2199 struct xinpgen
*pXIG
, *pOrigXIG
;
2200 struct pid_map
*pMap
= NULL
;
2201 unsigned NumEntries
;
2203 if (sysctlbyname ("net.inet.tcp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
2205 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2206 ret
= ERROR_NOT_SUPPORTED
;
2210 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
2213 ret
= ERROR_OUTOFMEMORY
;
2217 if (sysctlbyname ("net.inet.tcp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
2219 ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
2220 ret
= ERROR_NOT_SUPPORTED
;
2224 if (class >= TCP_TABLE_OWNER_PID_LISTENER
) pMap
= get_pid_map( &NumEntries
);
2226 /* Might be nothing here; first entry is just a header it seems */
2227 if (Len
<= sizeof (struct xinpgen
)) goto done
;
2229 pOrigXIG
= (struct xinpgen
*)Buf
;
2232 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
2233 pXIG
->xig_len
> sizeof (struct xinpgen
);
2234 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
2236 struct tcpcb
*pTCPData
= NULL
;
2237 struct inpcb
*pINData
;
2238 struct xsocket
*pSockData
;
2240 pTCPData
= &((struct xtcpcb
*)pXIG
)->xt_tp
;
2241 pINData
= &((struct xtcpcb
*)pXIG
)->xt_inp
;
2242 pSockData
= &((struct xtcpcb
*)pXIG
)->xt_socket
;
2244 /* Ignore sockets for other protocols */
2245 if (pSockData
->xso_protocol
!= IPPROTO_TCP
)
2248 /* Ignore PCBs that were freed while generating the data */
2249 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
2252 /* we're only interested in IPv4 addresses */
2253 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
2254 (pINData
->inp_vflag
& INP_IPV6
))
2257 /* If all 0's, skip it */
2258 if (!pINData
->inp_laddr
.s_addr
&&
2259 !pINData
->inp_lport
&&
2260 !pINData
->inp_faddr
.s_addr
&&
2261 !pINData
->inp_fport
)
2264 /* Fill in structure details */
2265 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
2266 row
.dwLocalPort
= pINData
->inp_lport
;
2267 row
.dwRemoteAddr
= pINData
->inp_faddr
.s_addr
;
2268 row
.dwRemotePort
= pINData
->inp_fport
;
2269 row
.dwState
= TCPStateToMIBState (pTCPData
->t_state
);
2270 if (!match_class( class, row
.dwState
)) continue;
2271 if (class >= TCP_TABLE_OWNER_PID_LISTENER
)
2272 row
.dwOwningPid
= find_owning_pid( pMap
, NumEntries
, (UINT_PTR
)pSockData
->so_pcb
);
2273 if (class >= TCP_TABLE_OWNER_MODULE_LISTENER
)
2275 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2276 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2278 if (!(table
= append_tcp_row( class, heap
, flags
, table
, &count
, &row
, row_size
)))
2283 HeapFree( GetProcessHeap(), 0, pMap
);
2284 HeapFree (GetProcessHeap (), 0, Buf
);
2287 FIXME( "not implemented\n" );
2288 ret
= ERROR_NOT_SUPPORTED
;
2291 if (!table
) return ERROR_OUTOFMEMORY
;
2294 if (order
&& table
->dwNumEntries
)
2295 qsort( table
->table
, table
->dwNumEntries
, row_size
, compare_tcp_rows
);
2298 else HeapFree( heap
, flags
, table
);
2299 if (size
) *size
= get_tcp_table_sizes( class, count
, NULL
);
2300 TRACE( "returning ret %u table %p\n", ret
, table
);
2304 /******************************************************************
2305 * AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
2307 * Get the TCP connection table.
2308 * Like GetTcpTable(), but allocate the returned table from heap.
2311 * ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
2312 * allocated and returned.
2313 * bOrder [In] whether to sort the table
2314 * heap [In] heap from which the table is allocated
2315 * flags [In] flags to HeapAlloc
2318 * ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
2319 * returns otherwise.
2321 DWORD WINAPI
AllocateAndGetTcpTableFromStack( PMIB_TCPTABLE
*ppTcpTable
, BOOL bOrder
,
2322 HANDLE heap
, DWORD flags
)
2324 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppTcpTable
, bOrder
, heap
, flags
);
2326 if (!ppTcpTable
) return ERROR_INVALID_PARAMETER
;
2327 return build_tcp_table( TCP_TABLE_BASIC_ALL
, (void **)ppTcpTable
, bOrder
, heap
, flags
, NULL
);
2330 static DWORD
get_udp_table_sizes( UDP_TABLE_CLASS
class, DWORD row_count
, DWORD
*row_size
)
2336 case UDP_TABLE_BASIC
:
2338 table_size
= FIELD_OFFSET(MIB_UDPTABLE
, table
[row_count
]);
2339 if (row_size
) *row_size
= sizeof(MIB_UDPROW
);
2342 case UDP_TABLE_OWNER_PID
:
2344 table_size
= FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID
, table
[row_count
]);
2345 if (row_size
) *row_size
= sizeof(MIB_UDPROW_OWNER_PID
);
2348 case UDP_TABLE_OWNER_MODULE
:
2350 table_size
= FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE
, table
[row_count
]);
2351 if (row_size
) *row_size
= sizeof(MIB_UDPROW_OWNER_MODULE
);
2355 ERR("unhandled class %u\n", class);
2361 static MIB_UDPTABLE
*append_udp_row( UDP_TABLE_CLASS
class, HANDLE heap
, DWORD flags
,
2362 MIB_UDPTABLE
*table
, DWORD
*count
,
2363 const MIB_UDPROW_OWNER_MODULE
*row
, DWORD row_size
)
2365 if (table
->dwNumEntries
>= *count
)
2367 MIB_UDPTABLE
*new_table
;
2368 DWORD new_count
= table
->dwNumEntries
* 2, new_table_size
;
2370 new_table_size
= get_udp_table_sizes( class, new_count
, NULL
);
2371 if (!(new_table
= HeapReAlloc( heap
, flags
, table
, new_table_size
)))
2373 HeapFree( heap
, 0, table
);
2379 memcpy( (char *)table
->table
+ (table
->dwNumEntries
* row_size
), row
, row_size
);
2380 table
->dwNumEntries
++;
2384 static int compare_udp_rows(const void *a
, const void *b
)
2386 const MIB_UDPROW
*rowA
= a
;
2387 const MIB_UDPROW
*rowB
= b
;
2390 if ((ret
= rowA
->dwLocalAddr
- rowB
->dwLocalAddr
) != 0) return ret
;
2391 return rowA
->dwLocalPort
- rowB
->dwLocalPort
;
2394 DWORD
build_udp_table( UDP_TABLE_CLASS
class, void **tablep
, BOOL order
, HANDLE heap
, DWORD flags
,
2397 MIB_UDPTABLE
*table
;
2398 MIB_UDPROW_OWNER_MODULE row
;
2399 DWORD ret
= NO_ERROR
, count
= 16, table_size
, row_size
;
2401 if (!(table_size
= get_udp_table_sizes( class, count
, &row_size
)))
2402 return ERROR_INVALID_PARAMETER
;
2404 if (!(table
= HeapAlloc( heap
, flags
, table_size
)))
2405 return ERROR_OUTOFMEMORY
;
2407 table
->dwNumEntries
= 0;
2408 memset( &row
, 0, sizeof(row
) );
2414 if ((fp
= fopen( "/proc/net/udp", "r" )))
2416 char buf
[512], *ptr
;
2417 struct pid_map
*map
= NULL
;
2418 unsigned int dummy
, num_entries
= 0;
2421 if (class >= UDP_TABLE_OWNER_PID
) map
= get_pid_map( &num_entries
);
2423 /* skip header line */
2424 ptr
= fgets( buf
, sizeof(buf
), fp
);
2425 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
2427 if (sscanf( ptr
, "%u: %x:%x %*s %*s %*s %*s %*s %*s %*s %d", &dummy
,
2428 &row
.dwLocalAddr
, &row
.dwLocalPort
, &inode
) != 4)
2430 row
.dwLocalPort
= htons( row
.dwLocalPort
);
2432 if (class >= UDP_TABLE_OWNER_PID
)
2433 row
.dwOwningPid
= find_owning_pid( map
, num_entries
, inode
);
2434 if (class >= UDP_TABLE_OWNER_MODULE
)
2436 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2438 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2440 if (!(table
= append_udp_row( class, heap
, flags
, table
, &count
, &row
, row_size
)))
2443 HeapFree( GetProcessHeap(), 0, map
);
2446 else ret
= ERROR_NOT_SUPPORTED
;
2448 #elif defined(HAVE_SYS_TIHDR_H) && defined(T_OPTMGMT_ACK)
2452 mib2_udpEntry_t
*entry
;
2454 if ((fd
= open_streams_mib( "udp" )) != -1)
2456 if ((data
= read_mib_entry( fd
, MIB2_UDP
, MIB2_UDP_ENTRY
, &len
)))
2458 for (entry
= data
; (char *)(entry
+ 1) <= (char *)data
+ len
; entry
++)
2460 row
.dwLocalAddr
= entry
->udpLocalAddress
;
2461 row
.dwLocalPort
= htons( entry
->udpLocalPort
);
2462 if (!(table
= append_udp_row( class, heap
, flags
, table
, &count
, &row
, row_size
))) break;
2464 HeapFree( GetProcessHeap(), 0, data
);
2468 else ret
= ERROR_NOT_SUPPORTED
;
2470 #elif defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_STRUCT_XINPGEN)
2474 struct xinpgen
*pXIG
, *pOrigXIG
;
2475 struct pid_map
*pMap
= NULL
;
2476 unsigned NumEntries
;
2478 if (sysctlbyname ("net.inet.udp.pcblist", NULL
, &Len
, NULL
, 0) < 0)
2480 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2481 ret
= ERROR_NOT_SUPPORTED
;
2485 Buf
= HeapAlloc (GetProcessHeap (), 0, Len
);
2488 ret
= ERROR_OUTOFMEMORY
;
2492 if (sysctlbyname ("net.inet.udp.pcblist", Buf
, &Len
, NULL
, 0) < 0)
2494 ERR ("Failure to read net.inet.udp.pcblist via sysctlbyname!\n");
2495 ret
= ERROR_NOT_SUPPORTED
;
2499 if (class >= UDP_TABLE_OWNER_PID
)
2500 pMap
= get_pid_map( &NumEntries
);
2502 /* Might be nothing here; first entry is just a header it seems */
2503 if (Len
<= sizeof (struct xinpgen
)) goto done
;
2505 pOrigXIG
= (struct xinpgen
*)Buf
;
2508 for (pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
);
2509 pXIG
->xig_len
> sizeof (struct xinpgen
);
2510 pXIG
= (struct xinpgen
*)((char *)pXIG
+ pXIG
->xig_len
))
2512 struct inpcb
*pINData
;
2513 struct xsocket
*pSockData
;
2515 pINData
= &((struct xinpcb
*)pXIG
)->xi_inp
;
2516 pSockData
= &((struct xinpcb
*)pXIG
)->xi_socket
;
2518 /* Ignore sockets for other protocols */
2519 if (pSockData
->xso_protocol
!= IPPROTO_UDP
)
2522 /* Ignore PCBs that were freed while generating the data */
2523 if (pINData
->inp_gencnt
> pOrigXIG
->xig_gen
)
2526 /* we're only interested in IPv4 addresses */
2527 if (!(pINData
->inp_vflag
& INP_IPV4
) ||
2528 (pINData
->inp_vflag
& INP_IPV6
))
2531 /* If all 0's, skip it */
2532 if (!pINData
->inp_laddr
.s_addr
&&
2533 !pINData
->inp_lport
)
2536 /* Fill in structure details */
2537 row
.dwLocalAddr
= pINData
->inp_laddr
.s_addr
;
2538 row
.dwLocalPort
= pINData
->inp_lport
;
2539 if (class >= UDP_TABLE_OWNER_PID
)
2540 row
.dwOwningPid
= find_owning_pid( pMap
, NumEntries
, (UINT_PTR
)pSockData
->so_pcb
);
2541 if (class >= UDP_TABLE_OWNER_MODULE
)
2543 row
.liCreateTimestamp
.QuadPart
= 0; /* FIXME */
2545 memset( &row
.OwningModuleInfo
, 0, sizeof(row
.OwningModuleInfo
) );
2547 if (!(table
= append_udp_row( class, heap
, flags
, table
, &count
, &row
, row_size
))) break;
2551 HeapFree( GetProcessHeap(), 0, pMap
);
2552 HeapFree (GetProcessHeap (), 0, Buf
);
2555 FIXME( "not implemented\n" );
2556 ret
= ERROR_NOT_SUPPORTED
;
2559 if (!table
) return ERROR_OUTOFMEMORY
;
2562 if (order
&& table
->dwNumEntries
)
2563 qsort( table
->table
, table
->dwNumEntries
, row_size
, compare_udp_rows
);
2566 else HeapFree( heap
, flags
, table
);
2567 if (size
) *size
= get_udp_table_sizes( class, count
, NULL
);
2568 TRACE( "returning ret %u table %p\n", ret
, table
);
2572 /******************************************************************
2573 * AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
2575 * Get the UDP listener table.
2576 * Like GetUdpTable(), but allocate the returned table from heap.
2579 * ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
2580 * allocated and returned.
2581 * bOrder [In] whether to sort the table
2582 * heap [In] heap from which the table is allocated
2583 * flags [In] flags to HeapAlloc
2586 * ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
2587 * returns otherwise.
2589 DWORD WINAPI
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE
*ppUdpTable
, BOOL bOrder
,
2590 HANDLE heap
, DWORD flags
)
2592 TRACE("table %p, bOrder %d, heap %p, flags 0x%08x\n", ppUdpTable
, bOrder
, heap
, flags
);
2594 if (!ppUdpTable
) return ERROR_INVALID_PARAMETER
;
2595 return build_udp_table( UDP_TABLE_BASIC
, (void **)ppUdpTable
, bOrder
, heap
, flags
, NULL
);