bing-1.3.5/ 42775 1750 1750 0 7005246653 11760 5ustar fgougetfgougetbing-1.3.5/include/ 42775 1750 1750 0 7000302412 13360 5ustar fgougetfgougetbing-1.3.5/include/netinet/ 42775 1750 1750 0 7000302413 15027 5ustar fgougetfgougetbing-1.3.5/include/netinet/ip_icmp.h100664 1750 1750 14710 6605752453 16765 0ustar fgougetfgouget/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp */ #ifndef _NETINET_IP_ICMP_H_ #define _NETINET_IP_ICMP_H_ /* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ /* * Structure of an icmp header. */ struct icmp { u_char icmp_type; /* type of message, see below */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ union { u_char ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { n_short icd_id; n_short icd_seq; } ih_idseq; int ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { n_short ipm_void; n_short ipm_nextmtu; } ih_pmtu; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_void icmp_hun.ih_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu union { struct id_ts { n_time its_otime; n_time its_rtime; n_time its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; u_long id_mask; char id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data }; /* * Lower bounds on packet lengths for various types. * For the error advice packets must first insure that the * packet is large enought to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. */ #define ICMP_MINLEN 8 /* abs minimum */ #define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ #define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) /* N.B.: must separately check that ip_hl >= 5 */ /* * Definition of type and code field values. */ #define ICMP_ECHOREPLY 0 /* echo reply */ #define ICMP_UNREACH 3 /* dest unreachable, codes: */ #define ICMP_UNREACH_NET 0 /* bad net */ #define ICMP_UNREACH_HOST 1 /* bad host */ #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ #define ICMP_UNREACH_PORT 3 /* bad port */ #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ #define ICMP_REDIRECT 5 /* shorter route, codes: */ #define ICMP_REDIRECT_NET 0 /* for network */ #define ICMP_REDIRECT_HOST 1 /* for host */ #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ #define ICMP_ECHO 8 /* echo service */ #define ICMP_ROUTERADVERT 9 /* router advertisement */ #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #define ICMP_TIMXCEED 11 /* time exceeded, code: */ #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ #define ICMP_PARAMPROB 12 /* ip header bad */ #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ #define ICMP_TSTAMP 13 /* timestamp request */ #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #define ICMP_IREQ 15 /* information request */ #define ICMP_IREQREPLY 16 /* information reply */ #define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREPLY 18 /* address mask reply */ #define ICMP_MAXTYPE 18 #define ICMP_INFOTYPE(type) \ ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #ifdef KERNEL void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); void icmp_input __P((struct mbuf *, int)); void icmp_reflect __P((struct mbuf *)); void icmp_send __P((struct mbuf *, struct mbuf *)); int icmp_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); #endif #endif bing-1.3.5/include/netinet/ip.h100664 1750 1750 13467 6775576314 15775 0ustar fgougetfgouget/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip.h 8.1 (Berkeley) 6/10/93 * ip.h,v 1.5 1995/05/30 08:09:33 rgrimes Exp */ #ifndef _NETINET_IP_H_ #define _NETINET_IP_H_ /* * Definitions for internet protocol version 4. * Per RFC 791, September 1981. */ #define IPVERSION 4 /* * Structure of an internet header, naked of options. * * We declare ip_len and ip_off to be short, rather than u_short * pragmatically since otherwise unsigned comparisons can result * against negative integers quite easily, and fail in subtle ways. */ struct ip { #if BYTE_ORDER == LITTLE_ENDIAN u_char ip_hl:4, /* header length */ ip_v:4; /* version */ #endif #ifndef WIN32 #if BYTE_ORDER == BIG_ENDIAN u_char ip_v:4, /* version */ ip_hl:4; /* header length */ #endif #endif u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ short ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ }; #define IP_MAXPACKET 65535 /* maximum packet size */ /* * Definitions for IP type of service (ip_tos) */ #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #define IPTOS_MINCOST 0x02 /* * Definitions for IP precedence (also in ip_tos) (hopefully unused) */ #define IPTOS_PREC_NETCONTROL 0xe0 #define IPTOS_PREC_INTERNETCONTROL 0xc0 #define IPTOS_PREC_CRITIC_ECP 0xa0 #define IPTOS_PREC_FLASHOVERRIDE 0x80 #define IPTOS_PREC_FLASH 0x60 #define IPTOS_PREC_IMMEDIATE 0x40 #define IPTOS_PREC_PRIORITY 0x20 #define IPTOS_PREC_ROUTINE 0x00 /* * Definitions for options. */ #define IPOPT_COPIED(o) ((o)&0x80) #define IPOPT_CLASS(o) ((o)&0x60) #define IPOPT_NUMBER(o) ((o)&0x1f) #define IPOPT_CONTROL 0x00 #define IPOPT_RESERVED1 0x20 #define IPOPT_DEBMEAS 0x40 #define IPOPT_RESERVED2 0x60 #define IPOPT_EOL 0 /* end of option list */ #define IPOPT_NOP 1 /* no operation */ #define IPOPT_RR 7 /* record packet route */ #define IPOPT_TS 68 /* timestamp */ #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ #define IPOPT_LSRR 131 /* loose source route */ #define IPOPT_SATID 136 /* satnet id */ #define IPOPT_SSRR 137 /* strict source route */ /* * Offsets to fields in options other than EOL and NOP. */ #define IPOPT_OPTVAL 0 /* option ID */ #define IPOPT_OLEN 1 /* option length */ #define IPOPT_OFFSET 2 /* offset within option */ #define IPOPT_MINOFF 4 /* min value of above */ /* * Time stamp option structure. */ struct ip_timestamp { u_char ipt_code; /* IPOPT_TS */ u_char ipt_len; /* size of structure (variable) */ u_char ipt_ptr; /* index of current entry */ #if BYTE_ORDER == LITTLE_ENDIAN u_char ipt_flg:4, /* flags, see below */ ipt_oflw:4; /* overflow counter */ #endif #ifndef WIN32 #if BYTE_ORDER == BIG_ENDIAN u_char ipt_oflw:4, /* overflow counter */ ipt_flg:4; /* flags, see below */ #endif #endif union ipt_timestamp { n_long ipt_time[1]; struct ipt_ta { struct in_addr ipt_addr; n_long ipt_time; } ipt_ta[1]; } ipt_timestamp; }; /* flag bits for ipt_flg */ #define IPOPT_TS_TSONLY 0 /* timestamps only */ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ /* bits for security (not byte swapped) */ #define IPOPT_SECUR_UNCLASS 0x0000 #define IPOPT_SECUR_CONFID 0xf135 #define IPOPT_SECUR_EFTO 0x789a #define IPOPT_SECUR_MMMM 0xbc4d #define IPOPT_SECUR_RESTR 0xaf13 #define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_TOPSECRET 0x6bc5 /* * Internet implementation parameters. */ #define MAXTTL 255 /* maximum time to live (seconds) */ #define IPDEFTTL 64 /* default ttl, from RFC 1340 */ #define IPFRAGTTL 60 /* time to live for frags, slowhz */ #define IPTTLDEC 1 /* subtracted when forwarding */ #define IP_MSS 576 /* default maximum segment size */ #endif bing-1.3.5/include/netinet/ip_var.h100664 1750 1750 17607 6605752453 16635 0ustar fgougetfgouget/* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_var.h 8.1 (Berkeley) 6/10/93 * ip_var.h,v 1.10 1995/05/30 08:09:50 rgrimes Exp */ #ifndef _NETINET_IP_VAR_H_ #define _NETINET_IP_VAR_H_ /* * Overlay for ip header used by other protocols (tcp, udp). */ struct ipovly { caddr_t ih_next, ih_prev; /* for protocol sequence q's */ u_char ih_x1; /* (unused) */ u_char ih_pr; /* protocol */ short ih_len; /* protocol length */ struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ }; /* * Ip reassembly queue structure. Each fragment * being reassembled is attached to one of these structures. * They are timed out after ipq_ttl drops to 0, and may also * be reclaimed if memory becomes tight. */ struct ipq { struct ipq *next,*prev; /* to other reass headers */ u_char ipq_ttl; /* time for reass q to live */ u_char ipq_p; /* protocol of this fragment */ u_short ipq_id; /* sequence id for reassembly */ struct ipasfrag *ipq_next,*ipq_prev; /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; }; /* * Ip header, when holding a fragment. * * Note: ipf_next must be at same offset as ipq_next above */ struct ipasfrag { #if BYTE_ORDER == LITTLE_ENDIAN u_char ip_hl:4, ip_v:4; #endif #if BYTE_ORDER == BIG_ENDIAN u_char ip_v:4, ip_hl:4; #endif u_char ipf_mff; /* XXX overlays ip_tos: use low bit * to avoid destroying tos; * copied from (ip_off&IP_MF) */ short ip_len; u_short ip_id; short ip_off; u_char ip_ttl; u_char ip_p; u_short ip_sum; struct ipasfrag *ipf_next; /* next fragment */ struct ipasfrag *ipf_prev; /* previous fragment */ }; /* * Structure stored in mbuf in inpcb.ip_options * and passed to ip_output when ip options are in use. * The actual length of the options (including ipopt_dst) * is in m_len. */ #define MAX_IPOPTLEN 40 struct ipoption { struct in_addr ipopt_dst; /* first-hop dst if source routed */ char ipopt_list[MAX_IPOPTLEN]; /* options proper */ }; /* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. */ struct ip_moptions { struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ u_long imo_multicast_vif; /* vif num outgoing multicasts */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ u_short imo_num_memberships; /* no. memberships this socket */ struct in_multi *imo_membership[IP_MAX_MEMBERSHIPS]; }; struct ipstat { u_long ips_total; /* total packets received */ u_long ips_badsum; /* checksum bad */ u_long ips_tooshort; /* packet too short */ u_long ips_toosmall; /* not enough data */ u_long ips_badhlen; /* ip header length < data size */ u_long ips_badlen; /* ip length < ip header length */ u_long ips_fragments; /* fragments received */ u_long ips_fragdropped; /* frags dropped (dups, out of space) */ u_long ips_fragtimeout; /* fragments timed out */ u_long ips_forward; /* packets forwarded */ u_long ips_cantforward; /* packets rcvd for unreachable dest */ u_long ips_redirectsent; /* packets forwarded on same net */ u_long ips_noproto; /* unknown or unsupported protocol */ u_long ips_delivered; /* datagrams delivered to upper level*/ u_long ips_localout; /* total ip packets generated here */ u_long ips_odropped; /* lost packets due to nobufs, etc. */ u_long ips_reassembled; /* total packets reassembled ok */ u_long ips_fragmented; /* datagrams sucessfully fragmented */ u_long ips_ofragments; /* output fragments created */ u_long ips_cantfrag; /* don't fragment flag was set, etc. */ u_long ips_badoptions; /* error in option processing */ u_long ips_noroute; /* packets discarded due to no route */ u_long ips_badvers; /* ip version != 4 */ u_long ips_rawout; /* total raw ip packets generated */ }; #ifdef KERNEL /* flags passed to ip_output as last parameter */ #define IP_FORWARDING 0x1 /* most of ip header exists */ #define IP_RAWOUTPUT 0x2 /* raw ip header exists */ #define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ #define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ extern struct ipstat ipstat; extern struct ipq ipq; /* ip reass. queue */ extern u_short ip_id; /* ip packet ctr, for ids */ extern int ip_defttl; /* default IP ttl */ extern u_char ip_protox[]; extern struct socket *ip_rsvpd; /* reservation protocol daemon */ extern struct socket *ip_mrouter; /* multicast routing daemon */ extern int (*legal_vif_num) __P((int)); int ip_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); void ip_deq __P((struct ipasfrag *)); int ip_dooptions __P((struct mbuf *)); void ip_drain __P((void)); void ip_enq __P((struct ipasfrag *, struct ipasfrag *)); void ip_forward __P((struct mbuf *, int)); void ip_freef __P((struct ipq *)); void ip_freemoptions __P((struct ip_moptions *)); int ip_getmoptions __P((int, struct ip_moptions *, struct mbuf **)); void ip_init __P((void)); extern int (*ip_mforward) __P((struct ip *, struct ifnet *, struct mbuf *, struct ip_moptions *)); int ip_optcopy __P((struct ip *, struct ip *)); int ip_output __P((struct mbuf *, struct mbuf *, struct route *, int, struct ip_moptions *)); int ip_pcbopts __P((struct mbuf **, struct mbuf *)); struct ip * ip_reass __P((struct ipasfrag *, struct ipq *)); struct in_ifaddr * ip_rtaddr __P((struct in_addr)); int ip_setmoptions __P((int, struct ip_moptions **, struct mbuf *)); void ip_slowtimo __P((void)); struct mbuf * ip_srcroute __P((void)); void ip_stripoptions __P((struct mbuf *, struct mbuf *)); int ip_sysctl __P((int *, u_int, void *, size_t *, void *, size_t)); void ipintr __P((void)); int rip_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); void rip_init __P((void)); void rip_input __P((struct mbuf *)); int rip_output __P((struct mbuf *, struct socket *, u_long)); int rip_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); int ip_rsvp_init __P((struct socket *)); int ip_rsvp_done __P((void)); void rip_ip_input __P((struct mbuf *mm, register struct socket *ip_mrouter, struct sockaddr *src)); #endif #endif bing-1.3.5/ChangeLog100664 1750 1750 4302 6605754611 13627 0ustar fgougetfgougetFri Apr 23 01:30:49 MET DST 1997 *** Release 1.1.2 *** Fri Apr 23 01:30:49 MET DST 1997 - Putting some Win32 code back in. - Update of the bing man page. - Update of the Readme file. - Enhanced the makefile. Fri Mar 9 01:43:35 MET DST 1997 *** Release 1.1.1 *** Fri Mar 9 01:43:35 MET DST 1997 - bing code after Pierre's cleanup - Pierre added two new options: '-u' and 'f' - bing now supports more than two hosts on the command line. This allows you to exploit the results of a traceroute. - Supports multiple destination hosts. Fri Feb 7 04:23:12 MET DST 1997 *** Release 1.1.0 *** Fri Feb 7 04:23:12 MET DST 1997 - ported to Win32. This involves a new icmp module which hides the interface differences. - The win32 specific parts have been put into the win32 directory and the unix specific parts are in the ux directory. - the Win32 section contains a preformatted version of the manual "bing.8". - README changed. Fri Jul 21 09:47:39 MET DST 1995 *** Release 1.0.4 *** Fri Jul 21 00:42:17 MET DST 1995 - small change in output format. - changed default small packet size. It seems the previous size of 8 bytes was too small and was padded to something bigger on many links. - README changed. Thu Jul 20 01:36:35 MET DST 1995 *** Release 1.0.3 *** Thu Jul 20 00:55:09 MET DST 1995 - new sanity check on rtt deltas. Submitted by - warnings now displayed only at the end, unless -w is used. - enhanced final stats display (should fit in a 25x80 screen in most cases). - README improved. - some cleanups in timeval code. - more Solaris 2 cleanups. Tue Jul 18 22:16:21 MET DST 1995 - portability fixes (Solaris, AIX, Linux, BSDI) - some code cleanup (gcc -Wall) Tue Jul 18 01:06:21 MET DST 1995 *** Release 1.0.2 *** Tue Jul 18 00:25:56 MET DST 1995 - patches for Linux included. Submitted by - sysdep.h created for system-dependent defines. Mon Jul 17 23:44:32 MET DST 1995 - README improved Mon Jul 17 22:38:07 MET DST 1995 - ChangeLog (this file) created - Option -q reversed as -V - Usage corrected. Fix submitted by Sun Jul 16 23:06:07 MET DST 1995 *** Initial release 1.0.1 *** bing-1.3.5/Doc.html100664 1750 1750 103273 7000272276 13507 0ustar fgougetfgouget

infos on bing: mailing list

1. Introduction

This document is a complement to the Readme file. The intent is to provide a more detailed analysis of the mathematics behind bing and the algorithms that are used.

This document may sometimes sound a bit authoritative but in its current state it really is not. This is an early version which is still quite incoplete and chances are that it contains errors so if you think you have found one send an email to me, fgouget@multimania.com, or to the bing mailing list.

2. Features, Bugs, Roadmap, etc.

2.1. Current features

  • Bing will perform the traceroute to the specified host(s). Various forms of traceroute are supported: from a host to another, only the specified hosts... See the manpage for more details.
  • Bing will measure the bandwidth of symetric links using the echo request/echo reply method. It will provide various statistics on the hosts and on the links.
  • This version will analyze the measured rtts and perform consistency checks on them. Then it will perform the linear regressions and use them to indicate which measures can be considered reliable and which are not. Then it will first redo the probes that it found to be inconsistent and those that don't fit the linear regressions well in an attempt to produce the maximum measure improvement per packet sent.

2.2. Bugs and other issues

  • The code badly needs a cleanup. I tried to do somtehing clean and then switched to a mode where I just tried to experiment till it worked.
  • If there is traffic on the link attached to your computer it seems that bing will pick up on that traffic. I'm not sure whether this causes problems in the measures or if it's just annoying messages because for now all the experiments I do go through a modem so I can control all the traffic. This is something I hope to solve when I rewrite the backend.
  • There is a lot of messages that are just debug messages and that pollute the display, especially on the case above.
  • Error handling is incomplete, inexistant or incorrect although there are some cases where it works.
  • When you interrupt bing via Ctrl-C it should ecompute everything using the latest values available and print it before exiting.

2.2. Roadmap

Here is the plan as to what I will try to dewvelop next. Of course if someone contributes code on some other aspect it will be integrated even if I planned to work on it much later.

  • Remove stuff from the main function. Some of it really does not belong there and it would make it simpler to write graphical versions of bing if they were separate. But this has to be done in a way that makes sense, if the methods are too much tied to this particular implementation of bing it's not so interesting.
  • Rewrite the backend. I call the backend all the code that sends the probes, receives the answers, measures the rtt and interprets the probe answers. Currently it only supports ICMP echo request/reply and I want it to support other methods as well including 100% UDP based ones. So the goal is to provide a flexible backend API where I can just plug a new module and do the probes using the UDP echo port for instance.
  • Once this API is written I'll try to implement three modules. The ICMP echo request/reply will be the first one, the one I use to develop the new architecture. Then there will be a UDP/ICMP invalid port module. This module will be used in further developments to measure asymetric links. The last module will be a UDP echo port module. The idea is to be able to go through firewalls that block ICMP, although they are likely to also block the echo port, and also to see if methods involving a regular server, rather than the kernel, can work. As I do this I'll try to solve the backend bugs as far as unexpected packets go.
  • Then I'll try to implement the asymetric links handling. First using only the host level regressions and then trying to provide link level error estimates and probe scheduling that fits asymetric links.

2.3. Other features

  • When trying to answer questions like 'which measure is wrong' or 'why can't I get reliable measures for this link' what would really be needed is a way to dump all the measures done by bing and graph them. I would be interested in seing the graph of the rtt differences between two hosts, I did it for a few cases on my HP28 and this told me that doing a linear regression on the rtt difference is definitely useful. Another graph that may be interesting is a graph of al the rtts collected for a given host and size. So the idea would be to modify bing so that it can dump all its measures in some format (XML based?). Then what we need is a number of scripts that transform these logs into usefull statistics and graphics using something like gnuplot.
  • If the UDP echo port module works well then it would be interesting to develop a module based on one of the UDP time services since it would allow us to have both fixed and variable return size UDP modules.
  • Source routing (loose or not) is not supported and might be useful to measure links that are not 'in a direct line of sight' from your computer.
  • Introduce support for asynchronous probing, i.e. bing sends probes at regular intervals, e.g. 0.1 seconds or as fast as answers arrive, and when an answer arrives deduce the rtt and updates the appropriate host/size record. This might speed up the measurements for far away links with high rtts. On the other hand the risks of probes being delayed or bing retrieving the probe too late may be higher too.
  • Making a version for cursor addressable displays (a la top) or GUIs (Gnome and/or Windows) would be nice. This is in particular true for packet sending strategies that don't do things linearly or if packet sending is node asynchronously. But I don't expect to undertake one of these projects since I don't know curses, the mfc or gtk.
  • Many other options of bing 1.0 are missing. Note that all should not be reintroduced, for instance route recording and ICMP flooding do not belong to bing.

4. Assumptions and limitations

Bing makes a number of assumptions to compute a link's raw bandwidth. If any of these is broken then bing will return erroneous results. How much the results will be affected ? It depends on the link, the assumption that has been broken,...

  • Packets take the same route on their way up and on their way down.
    This is more or less important, it depends on the probe method. If you use a method that allows you to measure the bandwidth of asymetric links the up bandwidth computed by bing should be correct. This is because these methods elicit a fixed size return packet so that the actual speed of the down link does not affect the measurment of the up link.
    But you will not be able to measure the bandwidth of the down link. First because the packets do not go through this link. But even so the down results are very likely not to be meaningful at all. That's because there will probably not be the same number of hosts on the way down as on the way up. So eaThis means that you will not be ab
  • Packets always take the same route (coupled modems,)
  • no bridge/repeater/switches (ethernet repeater)
  • The link bandwidth does not vary with time.
    This may seem obvious but it's not always the case. One counter example is modern modems. Any V34+ or faster modem will monitor the line clarity and adapt the transmission speed accordingly. So if the line quality degrades suddenly the bing results will no longer reflect the line speed and some results may be corrupted. If your link's bandwidth keeps changing the only thing that makes sense is a mesurement of its bandwidth at a given time. But bing needs some time to compute the bandwidth so you'll have to know whether the bandwidth will have significantly changed during the time bing takes to mesure it. Also bing will not give you an average raw bandwidth. That's because bing uses minimum rtt and not average rtt. Average rtt is not usable because it varies too much based on many random factors. Only minimum rtt is significant. But if the link bandwidth slows down, bing will never notice, it will only ignore the new longer rtts.
    If this happens during the first probe of a host, this host will get a bad correlation and the link that leads to it will appear to be slower than it really is. The case where the line suddenly gets better is not as bad. The rtt should get smaller and bing will reflect that.
  • it takes the same time to route a packet as to answer a packet (not nt4)
  • this time is constant (does not vary with size) or negligible
  • time does not go slower or faster (no NTP, don't change time while bing works)

5. Other tools

  • bing 1.1
  • echoping
  • pathchar

where to find them, how do they compare

5. How does it work

5.1. Performing a traceroute

5.2. Mesuring a regular link

5.3. Mesuring an asymetric link

5.4. Packet sending strategies

  • sequential
  • based on correlation
  • based on linear regression precision and its impact on bandwidth estimation
  • based on worst rtt error accros hosts
  • based on worst rtt error per host

5.5. Windows limitations

5.6. Calculating bandwidth

5.7. Delays

Ci=1-(1-p0)*(1-p1)*(1-p2)...

5.8. imprecision et effet sur la bande passante

Consider a string of hosts and links h0 - l1 - h2 - l2 - ... - ln - hn

If the probablility that each host hi delays the transmission of a packet, what is the probability that the packet be delayed by the time in its round-trip ?

The probability for the packet not to be delayed by host hi is 1-pi, and the only way for the packet not to be delayed at all is that it is not delayed by any host. That is this probability is (1-p0)*(1-p1)*...*(1-pn). In all other cases the packet is delayed. Thus the probability Cn that the packet is not delayed at all is:

Cn=1-(1-p0)*(1-p1)*...*(1-pn)

If that probability is the same for all intermediate hosts (or can be bounded between a min and a max) we get:

1-pminn < Cn < 1-pmaxn

What this tells us is that the probability that the packet is not delayed decreases exponentially with the number of hosts. But note that this does not necessarily mean that we cannot measure far away links. You will probably be able to measure a modem link which is many hops away because the delays will probably be small compared to the rtt difference at the two ends of this modem link. But it does put a limit on our chances to get a good measurement of relatively fast and far away links.

5.9. routers, hubs, switches,..

5.10. things that don't work

aggregated pipes: shotgun modems ?, modem aggregation, aggregated fast-ethernet to a switch

determining half-duplex/full duplex

fixed bandwidth may be wrong for modems

fixed latency may be wrong for satellite links

6. The maths and physics being Bing

This section describes how Bing computes the link characteristics such as the bandwidth. It first describes how we modelize the network (the phiysics), then the algorithms (the maths) and then gives a word of caution about how to interpret the results and why the assumptions we have made may be wrong.

6.1. Network link modelisation

Bing attempts to determine the characterics of the the links that connect TCP/IP hosts. That these links be point to point links or buses does not matter. What is important is that each network link forms a direct connection between the two (or more) hosts, i.e. the TCP/IP packets are not stored and forwarded at any point between the two hosts.

So for instance the in the figure below A-B is a network link but not A-C. This is because a hub does not store and forward IP packets, it starts retransmitting IP packets from the segment 1 to the segment 2 as soon as the first byte is received (in fact it operates at the physical level and does not even know what a byte is). So between A and B a TCP/IP packet is never stored and then forwarded. In contrast the router has to first receive the full TCP/IP packet from segment 2 before it can before it can retransmit it on the segment 3. So by the definition above A-C and B-C are not network links.

       Ethernet        Ethernet           Ethernet
       Segment 1       Segment 2          Segment 3
    A ----------- Hub -----+----- Router ----------- C
                           |
                           B

When we attempt to characterize a network link we will be at one end of it. We will then say that packets leaving our computer are going "up" while packets comming to our computer are going "down" (which keeps with the tradition of uploads and downloads). Each network link can then be split in two: an "uplink" and a "downlink".

Of course in some cases the uplink and downlink are in fact exactly the same link, this is the case in particular of ethernet over a coaxial cable. In other cases they may have the same characteristics, this is the case for instance of ethernet over an RJ45 conenction. But there are also a number of situations where the uplink and the downlink have different characteristics, examples are given in a later section.

Then we characterize each half of the link by the following properties:

  • b: the link bandwidth, i.e. the number of bytes that can be transmitted per second. This bandwidth is assumed to be constant in time (at least while we are making our measurement) and independent from the amount of data sent, from the nature of the data sent and from the number of packets sent.
  • l: the link latency, i.e. a delay that is incurred every time that data is sent from one end of the link to the other. We assume that this delay is constant in time (again, at least while we are making our measures) and independent from the amount of data sent.

It follows that the time t it takes to send s bytes (in s we include all the protocal overhead) from one host on the link to the other is:

(1) t = s / b + l

Determining the characteristics of such a network link is then equivalent to determining the values of b and l.

(!!)From there is is trivial to generalize the foNow generalizing the formula above from just one network link to a chain of n+1 hosts (h0..hn) connected via n network linksthe round-trip-time will be of the form:

(2) rtt = (1/bu,1+1/bu,2+...+1/bu,n+1/bd,n+1/bd,n-1+...+1/bd,1)*s+lu,1+lu,2+...+lu,n+ld,n+ld,n-1+...+ld,1

where bu,i and lu,i are respectively the bandwidth and the latency of the uplink connecting the host i-1 to the host i and bd,i and ld,i are respectively the bandwidth and the latency of the downlink connecting the host i to the host i-1.

Finally we can derive from expression (2) that the round-trip-time is an affine function of the packet size, that is, it is of the form:

(3) rtt=a*s+b

where a and b are constants determined by the bandwidth and latency of the intervening network links.

6.2. Intrisic limits and validity of this modelisation

Before we go on to see how we are going to measure the network link's bandwidth let's review the assumptions made by the network link modelisation.

We assume the bandwidth is constant in time. This is not always the case. For instance modems using protocols like V34 or V90 constantly monitor the line quality and adjust their bit rate accordingly. Comes a storm and the bandwidth falls ! The same may happen if your neighbor picks up the phone and the cross-over phenomenon starts perturbing your communication (when two cables are parallel and close to each over for some distance part of the signal on one cable can "cross-over" and appear as a weak perturbation on the over cable). This is the only case I know where the bandwidth is not necessarily constant in time. Even then the bandwidth is not very likely to change during the typical duration of a bing measurement.

We also assume that the bandwidth is independent from the nature of the data sent. Again, modems usually compress the data before sending it which then violates this assumption. The workaround is to send random data which is then incompressible. But this only a partial solution because we can only randomize the packet payload, not its TCP/IP header. So for small packets, where the ratio header size / payload size is high, the bandwidth will be slightly different than for big packets.

We assume that the bandwidth does not depend on the amount of packets sent. This is incorrect if the network link is an aggregate of multiple links. Take for instance a server with four fast ethernet network cards will all the same IP address. Such a server is usually connected to a fast ethernet switch which does load balancing of the traffic on the four server's network cards. In such a situation packets individually "travel" at 100Mbps but we can have four of them travelling at once which makes the aggregate bandwidth 400Mbps. Since the server has a single IP address we see this type of link as a single network link with a 400Mbps bandwidth.
As another example consider the case of a linux box configured as a gateway to the internet by aggregating the bandwidth of two or more modems. In this case too the resulting aggregate link is capable of sending more than one packet simultaneously which results in an aggregate bandwidth which is higher than the rate at which each packet is being transmitted. And in this case all links may not have the same speed. One may be a 19.2kpbs modem while the other may be a 56kbps modem resulting, in addition, in changes in the rate at which a packet is being sent depending on which modem it goes through. (!!) do the boxes have the same IP address on both modems in such a case ?
Finally we can contrast the cases above with that of "shotgun" modems.As far as I understand, these modems aggregate two phone lines together but do so at the bit level which means that a TCP/IP packet is being sent on both lines simultaneously. So in this case the assumption that the bandwidth does not depend on the number of packets is valid.

The assumption that the latency does not depend on time must be true in all but the most extreme cases. A non negligible component of the latency is the length of the network link. The data travels approximately at the speed of light so the longer the distance the higher the latency. One sample case where it may change over time is if the network link actually goes through a low orbit satellite. In such a case the distance sender-satellite-receiver may change a lot as the satellite orbits around the earth. But such network links are currently very rare.

6.3. Measurement methodology

First we must notice that we cannot measure the round-trip-time as defined above and even less the time it takes for a network packet to go from one host to another. In both cases we would need hardware network probe.

What we can do though is measure the time it elapsed between when our software called the method to send the packet and when our software received the packet on the other side. But even this is not practical since we would have to install our software on all the hosts.

So instead we measure the rtt.

6.4. Measurement pitfalls

6.4.1. Routing problems

6.4.2. latency/delays

6.4.3. Buses, bridges and switches

It is quite likely that there will be devices and intermediaries between two hosts. Some are internal to the computer and others are network devices which are usually used to extend the reach of a network. All these intermediaries can be split into three categories.

Immediate retransmission, same bandwidth

This kind of device starts retransmitting a network frame as soon as a fixed amount of data has been received. One such kind of device are devices that don't even know what a frame is. Modems are one such kind of device. They only know about bytes and start retransmitting those bytes as soon as they have filled they transmit buffer. Another kind of device that follows this kind of rule is the network hub like ethernet repeaters. As soon as they have received the start of an ethernet frame they start retransmitting it on the other ports. Since this works both ways if a collision occurs the frame will be dropped the and the initiator will retransmit.

How does this kind of device affect the bing measures?

Let's call d the number of bytes the device must receive before it starts retransmitting the frame on the other side of the link. The device will have to wait until it has received d bytes before it can start retransmitting data. Then the time it takes to retransmit the data is overlapped with the time it takes to receive it. So the one-way trip time is:

ott=s/b+d/b

So such a device is not going to affect our measure of the bandwidth. The only thing we will notice is a slightly increased link latency.

Immediate retransmission, different bandwidth

This kind of device bridges two links of different bandwidths. We further assume that it is bridging a slow link to a faster link. The reverse case is in fact equivalent to the previous type of device. What this device does is that it first waits until it has bufferized enough data to start transmitting to the faster link without running out. Should the frame on the slow link turnout to be invalid, due to a collision or a link failure, it would reproduce a similar condition on the other link so that the data is ignored anyway.

How does this kind of device affect the bing measures?

Let's call respectively bs and bf the bandwidth of the slow and fast links. The device can start retransmitting data only once the time it takes to transmit all the data on the fast link plus some buffer delay of d bytes is the same as the time it takes to receive the remainder of the data from the slow link.

So the total transmission time will be the same as the time it takes to receive all of the data at the slow link speed plus the time to build the buffer and the time to retransmit it on the fast link.

ott=s/bs+d/bf

So we essentially have the same result as in the previous case except that the latency is slightly lower.

Store and forward

This kind of device, by far the most common, waits until it has received all the data from the first link and then retransmits it on the other link. This is what any router and probably most switches do. But this is also how your network card works. It waits until it has received all the data via the PCI/ISA bus and then retransmits it on the second link, the ethernet or fast ethernet link.

How does this kind of device affect the bing measures?

Let's call b1 and b2 the bandwidth of the two links. The device will also introduce some delay but this time it is better described in terms of time rather than in terms of bytes, so let's call it l. There is absolutely no overlap between the receive phase and the transmit phase so the one-way trip time is:

ott=s/b1+l+s/b2

This means that the bandwidth measured by bing is going to be:

b=b1*b2/(b1+b2)

In other words, bing is going to measure the geometric mean of the links bandwidths.

Some examples:

  • Take an old Ethernet card, an 8bit ISA card in a 8MHz ISA bus (PC-AT standard). These cards normally operate in half duplex mode (it's usually even worse) but what is more important to us is that, like their more modern couterparts, you first have to transfer the packet to the card buffer before it is sent on the ethernet. So such cards operate in "Store and Forward" mode. So applying the rules described above the badwidth that will be measured by bing will be, at most, the geometric mean of the bandwidth of the ISA bus and the ethernet. Since the ISA bus described above has a maximum bandwidth of 72Mbps this gives us a maximum of about 8.8MBps. Note that this is a theoretical maximum. If the card imposes some overhead for transfering data to its buffers you will not take benefit of the the full bandwidth of the ISA bus and the resulting bing measurement will be even lower.
  • Let's do the same exercise in a more modern setting. Let's take a 32bits 66MHz PCI bus and a fast ehternet card. The PCI bus bandwidth is 2014Mbps and the fast ehternet bandwidth is 100Mbps so the maximum bing will ever see is about 95Mbps. Now replacing if you replace the fast ethernet card by a gigabit ethernet card it gets even worse: bing will only measure 668Mbps.
  • Let's consider a fast ethernet network composed of PCs with 32bits 66MHz PCI network cards. Let's further assume that each PC is connected to an ethernet switch operating under the "Store and forward" principle. Will be the result returned by bing? Bing will think there is just one network link since it has only two IP addresses: that of the localhst and that of the other PC. But in fact the packet goes through 4 links: a PCI bus, a fast ethernet segment, another fast ethernet segment and another PCI bus. So the maximum bandwidth returned by bing will be the geometric mean of all these which gives 47Mbps.

Are these results significant?

It depends on the combined ability of the hardware and your application to overlap data transfers.
In the first example it is very unlikely that the network card will let you tranfer a packet to its buffer while it is sending the content of another buffer to the network. This means the hardware prevents you from overlapping transfers from memory to the card and from the card to the network. This means you will not be able to send data faster than what big tells you.
In the example involving the network switch you can in fact transfer data on the first network segment while the previous packet is being transfered on the second segment. But this depends on your application. An RPC based client/server application that has to wait until it gets the result of an RPC before it can do more work and issue the next one will be limited by the presence of the switch because the switch doubles the latency. Not only is the 'b' factor of the linear regression probably the double of what it would be with a direct connection but the bandwidth as measured by bing too is just half of what it would be without the switch. So the performance of RPC based applications should closely match the results of bing.
On the other hand the performance of applications like ftp will not be accurately predicted by bing's results because they can overlap multiple data transfers. Modern fast ethernet PCI cards are very likely able to transfer data to or from memory while sending or receiving data to or from the network. So in the switch example above we could have up to four packets in flight at any time. In such cases the bandwidth is limited by the slowest link, the fast ethernet link, ad the ability of the networking protocol implementation to efficiently use it (and that is not a given).

7. The architecture

9. References

Other bandwidth measuring related links:

Ping tools:

  • ping: There are tons of ping tools available. I will only cite one, the one I wrote as an excercise to learn how to use the Windows icmp dll. Note that it's not the most sophisticated nor the most featureful ping around (although it does have one or to features that the standard Windows ping does not have).
    http://www.multimania.com/fgouget/bing/
  • fping: fping allows you to efficiently ping many hosts typically to determine whether they are up or not. Using fping is more efficient than using a script which would ping the hosts in a round-robin fashion because the script would have to wait for one RTT for each host. For 1000 hosts and more this can take a while. Also fping is made to be used in scripts and its output is easy to parse which may be a reason to use it even for only a few hosts.
    http://www.stanford.edu/~schemers/docs/fping/fping.html
    ftp://ftp.lip6.fr/pub/networking/fping-2.0.tar.gz
  • echoping: This tool by Stephane Bortzmeyer is designed to approximately evaluate the performance of a remote host by sending it TCP "echo" (or other protocol) packets. Unlike the ICMP echo packets, the packets sent by echoping actually require that a server process answer so that one can more easily detect if the remote host is completely overloaded or partly out of order.
    http://www.ensta.fr/internet/unix/sys_admin/echoping.html
    ftp://ftp.internatif.org/pub/unix/echoping/echoping-2.2.0.tar.gz
  • traceroute: not quite a ping tool but I did not want to create a new section. You will find the sources at the URL indicated below.
    ftp://ee.lbl.gov/traceroute-1.4a5.tar.Z

You can find a more complete and very good taxonomy of network measurement tools at the following URL: http://www.caida.org/Tools/taxonomy.html.

Libpcap is a library which provides a system-independent interface for packet capture.
ftp://ee.lbl.gov/libpcap-0.4.tar.Z Found this in the Wine list (by gerard patel ): #ifdef __i386__ typedef unsigned long long u64; inline u64 gettick() { u64 ticks; asm volatile ("rdtsc" : "=A"(ticks)); return ticks; } u64 u1, u2; #endif Might be interesting if I could change it to milliseconds. Does this require to be root ? bing-1.3.5/Makefile100664 1750 1750 5714 7005246510 13512 0ustar fgougetfgouget# # $Id: Makefile,v 1.6 1999/10/24 23:30:09 fgouget Exp $ # ########## # # Customise the following variables to match your configuration standards # ########## BINDIR=/usr/local/bin MANDIR=/usr/local/man ########## # # Uncomment the lines below as appropriate for your platform. # ########## # Uncomment if you need the 4.4 BSD compatibility includes. # -> required on Linux (and Win32) #COMPAT_INCS = -Iinclude #COMPAT_INCS = -I/usr/include # Maybe specify some specific compatibility options # -> on AIX activate the BSD mode #COMPAT_DEFS= -D_BSD # On some systems you may need to link with specific libraries # -> on SunOS 5 (Solaris) link with #COMPAT_LIBS=-lnsl -lsocket -L/usr/ucblib -lucb # Define if you lack srandom()/random() # -> required on Win32 (and maybe sometimes on Solaris, but better avoided) #NO_RANDOM = -DNO_RANDOM=1 # Define to use srandom/random rather than srand/rand # -> required on SunOS 4.1.3, SunOS 5, AIX 2 (BOSX 2 really), OSF1 V2.0 #NO_SNPRINTF = -DNO_SNPRINTF=1 # Define if you lack strerror() #NO_STRERROR = -DNO_STRERROR=1 # You may optionally provide some optimisation flags. Optimising bing for # speed should slightly improve the results. # -> if you want to debug bing define COPTIM = -g -Wall -D_DEBUG # -> on Linux, SunOS 4 and OSF1 V2.0 you may specify #COPTIM = -O2 # -> on Solaris you may use #COPTIM = -O # on some hosts like AIX, HP-UX the optimisation options are already set ########## # # Define where tools are stored # ########## INSTALL=install -c GROFF=groff NROFF=nroff RM=/bin/rm ########## # # Compilation rules # ########## BINCS = \ -I. \ $(COMPAT_INCS) BDEFS = \ $(COMPAT_DEFS) \ $(NO_RANDOM) \ $(NO_SNPRINTF) \ $(NO_STRERROR) \ $(CDEBUG) \ $(COPTIM) BLIBS = \ $(COMPAT_LIBS) OBJS= \ bing.o \ bing_misc.o \ bing_probes.o \ bing_stats.o \ lin_reg.o \ icmp_ux.o # (!!) These dependencies are incorrect. They should be computed automatically. # Besides it would be a good idea to use autoconf, would it generate code that # does that for us ? all: bing bing.0 bing.ps dist: clean bing.0 bing.ps bing.o: bing.c bing_stats.h mod_icmp.h $(CC) $(CFLAGS) $(BINCS) $(BDEFS) -o $@ -c bing.c bing_misc.o: bing_misc.c bing_misc.h $(CC) $(CFLAGS) $(BINCS) $(BDEFS) -o $@ -c bing_misc.c bing_probes.o: bing_probes.c bing_probes.h $(CC) $(CFLAGS) $(BINCS) $(BDEFS) -o $@ -c bing_probes.c bing_stats.o: bing_stats.c bing_stats.h $(CC) $(CFLAGS) $(BINCS) $(BDEFS) -o $@ -c bing_stats.c lin_reg.o: lin_reg.c $(CC) $(CFLAGS) $(BINCS) $(BDEFS) -o $@ -c lin_reg.c icmp_ux.o: unix/icmp_ux.c mod_icmp.h $(CC) $(CFLAGS) $(BINCS) $(BDEFS) -o $@ -c unix/icmp_ux.c bing: $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(BLIBS) -lm bing.ps: unix/bing.8 $(GROFF) -man unix/bing.8 > bing.ps bing.0: unix/bing.8 $(NROFF) -man unix/bing.8 > bing.0 clean: $(RM) -f bing bing.ps bing.0 $(OBJS) install: bing unix/bing.8 $(INSTALL) -m 644 -o man -g man unix/bing.8 $(MANDIR)/man8 $(INSTALL) -m 4555 -o root -g staff bing $(BINDIR) bing-1.3.5/Readme.1st100664 1750 1750 6674 6605754614 13724 0ustar fgougetfgouget Bing 1.1.2 Table of Contents ----------------- 1. About this release ? 2. Where to get it ? 3. Why would you want to use this release of bing ? 4. What's new ? 5. Who should you report bugs to ? 1. About this release ? ----------------------- This is an unofficial bing release. I ported bing to the Win32 platform and made changes so that the same code could be compiled on Unix and on Win32. I reported the changes to Pierre and he found them acceptable. He made some more changes that were integrated back into this version. But right now he does not have the time to make an official bing release. This is why decided to get this version out (with his agreement). So here unofficial means that the source code versioning is not done by Pierre and that it is probably better if you bother me rather than Pierre if you have problems (see point 4). Also I have modified the Readme.txt file and the documentation, so assume Pierre is responsible for the good things and I'm responsible for the bad ones ! As for versioning we agreed to use a scheme similar to that of the Linux kernel: x.y.z x is the major version number, actually 1 z is the fix/patch/iteration level y is the minor version. If even then the release is "stable", if odd it is unstable. So the last stable release is 1.0.4 and the current one is 1.1.2. 1.1.2 also means that with this release can be heavily patched/ modified/enhanced. So if you want to hack the source don't hesitate. When the time comes there will be a new version: 1.2.0 or 2.0.0 depending on the amount of changes. 2. Where to get it ? -------------------- Currently it's only available on my Web site: http://www.mygale.org/05/fgouget/bing.html If you have problems getting it, send me an email at: fgouget@club-internet.fr 3. Why would you want to use this release of bing ? -------------------------------------------------- - Because you're using Windows and this is the only release of bing for Win32 platforms to my knowledge. - Because you want to make sure that this release of bing still compiles on your platform. This has to be checked because of the "cleanup" that have been made to the code. It no longer uses the "sysdep.h" file for instance. - Because you want to modify bing. In that case it's better to modify this code because it will avoid having two diverging versions. Too late ??!! Ooops. - Because you want to check that this release of bing did not introduce bugs (especially security bugs) in the Unix version. This is very kind of you and I'll appreciate bug reports very much. 4. What's new ? --------------- - All the icmp specific code has been put in the "mod_icmp" module. The bing core accesses this code via the interface defined in "mod_icmp.h". - The files layout has been modified to accomodate the Unix/Win32 duality. This layout is not yet really satisfactory. - The code has been "cleaned". The process if far from being finished yet (imho). - Pierre added two options '-u' and 'f' - bing now supports multiple hosts on the command line, not only two. - Also read the ChangeLog. 5. Who should you report bugs to ? ---------------------------------- The best place to start with is still the bing user list. Otherwise it is better if you bug me rather than Pierre since after all I took the responsibility for getting this release out. So to contact me, send mail to: fgouget@club-internet.fr bing-1.3.5/Readme.txt100664 1750 1750 36332 6605754615 14047 0ustar fgougetfgouget ** Unofficial Release ** Bing 1.1.2 Table of Contents ----------------- 1. What is bing ? 2. Infos on bing 3. Installing bing 1. Installing bing on Unix systems 2. Installing bing on Windows systems 4. How to use bing 5. Measurement problems 6. Packet loss evaluation 7. Ethernet devices measurement 8. Possible NTP influence 9. Possible enhancements 10. Some maths 1. What is a RTT made of ? 2. Minimising errors 3. The linear regression 4. Measuring asymetric links 11. References 1. What is bing ? ----------------- Bing is a point-to-point bandwidth measurement tool (hence the 'b'), based on ping. Bing determines the real (raw, as opposed to available or average) throughput on a link by measuring ICMP echo requests roundtrip times for different packet sizes for each end of the link. Suppose we are on host A and want to know the throughput between L1 and L2, two extremities of a point-to-point link. A ----( the Internet )--- L1 --- L2 If we know the rtt (roundtrip time) between A and L1, and the rtt between A and L2, we can deduce the rtt between L1 and L2. If we do that for two different packet sizes, we can compute the raw capacity (bps) of the link. Note that bing can also be used to have an idea of ethernet cards performance. Many thanks to the following people for their help, hints, support, and real beers : Marc Baudoin Fran‡ois Berjon Julien Boissinot St‰phane Bortzmeyer Jacques Caron Laurent Chemla Ren‰ Cougnenc Nat Makarevitch Jean-Philippe Nicaise Christian Perrier Bertrand Petit Philippe Regnauld Ollivier Robert Herv‰ Schauer Christophe Wolfhugel Send virtual beers, bug reports, enhancements and flames to : Pierre Beyssac 2. Infos on bing ---------------- You can subscribe to the "bing-users" mailing list by sending a mail containing : subscribe bing-users to . The posting address is 3. Installing bing ------------------ The provided source should compile and run out of the box on : FreeBSD 1.1.5.1 FreeBSD 2.0.5 Linux NetBSD 1.0 SunOS 4.1.3 AIX HP-UX 9 Solaris 2 BSDI 1.0 Ultrix (DECstation) Windows 95 Windows NT 3.51 and 4.0 on i386 (alpha, mips, ppc) 3.1. Installing bing on Unix systems ------------------------------------ On Solaris 2, you should only need to uncomment the CLIBS line in the Makefile. Then (on all systems) : $ make $ su root # make install bing, like ping, needs to be installed setuid root to be able to make its own ICMP packets. Note that, to format the man page (bing.8), you'll need the 'mandoc' macros package. If you don't have it, a preformatted cat page (bing.0) and postscript page (bing.ps) are provided. 3.2. Installing bing on Windows systems --------------------------------------- To compile bing you must also get the icmp package. This is a package which provides the required include files and libraries to send and receive ICMP messages. To compile bing you may have to modify the file makefile.nt so that ICMP_LIBRARY points to the place where you have put the icmp libraries. Then the command below should suffice: nmake -f makefile.nt There are options you may add to this command line to customise the result. All options are disabled by default: - DLL=1 Links bing with the Dll C library rather. This makes bing much smaller but may require that you ship the Dll with it. - DEBUG=1 Builds a debug version. - BROWSER=1 Generates Visual C++'s "browser" database. and commands - all or Builds bing. - clean Removes the generated files. 4. How to use bing ------------------ 1) using 'traceroute', find the IP adresses of the endpoints of the link you want to measure. 2) try : bing -v point1 point2 where 'point1' is the nearest endpoint. Option '-v' is useful to be warned of any routing problems. 3) wait a little for the measure to stabilize. 4) if after a while, the measurement looks weird (typically, negative or amazing throughputs) have a look at the indicated roundtrip times. If they are too small (below a few milliseconds), try to rerun bing with a bigger packet size : bing -S 1000 -v point1 point2 CAUTION : do not increase packet size too much, because this could trigger IP fragmentation/reassembly on the link to measure *or* on intermediate links, which messes up the measures completely. If you stay below 1400 bytes, you should be safe (except on SLIP links where you should not go over 1000). This depends on the MTU (maximum transmit unit) of the link. 5) if, after increasing packet size, you still can't get stable results, try to use the -z option. This option fills packets will random data, defeating compressed links. 6) if you still can't get anything reasonnable, the link you're trying to measure is probably a high-throughput link too far away (network- and throughput-wise) from you, or some weird animal (IP over X25, Frame Relay, ATM, satellite...). You can try to run bing from a better connected machine (with respect to the target link). If you can't, you can always try to think of a way (I'm sure there are) of improving bing to make it work anyway :-). Probably the best solution is to find something else to do (I leave it to your choice entirely, suggestions are : go for a walk, eat, drink, be elected). 5. Measurement problems ----------------------- There are many cases in which the measurements may not be accurate (read: "plain wrong") : - links attained through a link of much lower throughput (typically, don't expect to measure a 34Mbps backbone link through your V32bis dialup account). You can expect to measure links about 15 to 30 times faster than the slower link in your path to them, i.e. up to 512kbps through a V32bis modem, up to 2Mbps through a 64kbps link, and so on. - saturated links. bing works by measuring the minimal rtts. The more saturated links there are in the measure path, the more time it takes to get a packet through all of them with minimal delay. - IP/X25 connections. Due to encapsulation in small packets, it is very difficult to know the "raw" bit capacity because the overhead by IP packet is not fixed and varies with the packet size. However, a clever bing could be able to find out about the encapsulating size by slowly increasing the strobe packet size and detecting steps in the rtt increase. Maybe one day ;-) - more generally, what you might call "hidden multi-hop" links can give strange results. This includes IP over X25, Frame Relay, as well as probably any IP encapsulation over a switched packet network. - padding. On many links, the smallest packet size is bigger than the smallest possible IP packet size and padding occurs. For example it happens on ethernet. It tends to give optimistic results. - non symmetrical routing : -----------------<--- | | | ( somewhere ) | ^ | | A ---( the Internet )--> L1 ---> L2 If the routings are set in such a way that the ICMP echo replies from L2 don't cross the L1-L2 link, bing can't reliably compute the link capacity. It generally happens, at least in France, on links crossing ASs (autonomous systems) between different providers. Sadly, these links happen to be the most interesting to measure, to be able to check providers claims regarding their connection with the rest of the world... I don't think there's an easy way around (this is the same problem as traceroute not being able to report network return paths). I have been objected that high-bandwidth links with dedicated routers might be impossible to measure, due to the way these devices work. Fast routers are designed in such a way that, when receiving a packet, they decode the header as soon as possible, even before the packet is completely received. They can thus decide on an outgoing route for the packet and might even (I'm not sure about that) begin resending it before receiving it completely. This should not directly interfere with ICMP ECHO_REQUEST packets because these packets must be locally processed and this is generally done entirely by software at a lower priority when the packet has been completely received. Moreover, since bing only considers minimal round-trip times in its throughput calculations, you only have to expect that some ICMP ECHO_REQUESTs will be processed by the router as soon as they are received, which should happen often enough if the router is not saturated. 6. Packet loss evaluation ------------------------- Knowing the packet losses on A-L1 and on A-L2, it should be possible to compute the loss between L1 and L2 : A --- L1 --- L2 a b A-L1 packet loss = a A-L2 packet loss = ab L1-L2 packet loss = ab / a Bing attempts to calculate it, but the results are generally not significant. 7. Ethernet devices measurement ------------------------------- This might sound surprising, since ethernet throughput is known to be 10Mbps ! By running bing between two machines on an ethernet, you can evaluate the CPU overhead induced by memory copies and polled I/O. For example, between two Sparc 2 running SunOS 4.1.3, I generally get around 9Mbps. Between two PCs running FreeBSD with NE2000 clones, expect around 4 or 5Mbps (or a little more depending on processor speed). Between two PCs with 3C509 cards, I get about 7Mbps. 8. Possible NTP influence ------------------------- Though I never got any evidence of it, it is possible that running bing on a NTP-synchronized machine introduces a bias in the measurements, when the NTP daemon makes a small correction while bing is waiting for an echo reply packet (almost all the time). I suppose this should mainly have an effect when measuring fast and far away links, which are difficult or impossible to measure anyway. 9. Possible enhancements ------------------------ * It should be possible to measure mono-directional throughput by varying the packet size only for one of the packets, the sent packet or the received packet. For example, sending variable-sized ICMP ECHO_REPLY packets with a small TTL should elicit fixed-size "ttl exceeded" replies. * Another interesting extension would be a mechanism trying to determine the optimal big packet size in such a way that the measurement is accurate enough yet fast. * Bing derives from ping and it shows. Its structure could probably be enhanced, modularised and simplified. Also many options that were significant for ping are not significant for bing and could be removed. * Most of the IP options are not supported by the icmp part of the Win32 version. While they may not really be needed it they could be by building the IP options by hand. * On the Win32 version the rtt resolution is only of a millisecond. It would be nice to find a solution for having a higher resolution. * The Win32 error reporting needs to be fixed. It reflects more what could have happened on Unix that what actually happened and the error codes are usually incorrect. * The makefile is probably too Visual C++ centric. I'd be interested in a 10. Some maths -------------- 10.1. What is a RTT made of ? ----------------------------- Sending a packet from host 1 to host 2 involves pushing data through many layers: your software and the OS network software, the network device then the link then up the layers on host 2. The following figure describes this. Host 1 Link Host 2 Software Device Device Software |---->-----|---->-----|-->--//-->--|---->-----|---->-----| | |----<-----|----<-----|--<--//--<--|----<-----|----<-----| Each of these layers introduces its own delay which depends on the packet size. To model the RTT we will assume that: * each layer introduces a delay which is a linear function of the packet size. * there is no packet queue. This is only realistic on unloaded networks. Thus: Rtt=A1_se+A1_de+A_le+A2_dr+A2_sr + (B1_se+B1_de+B_le+B2_dr+B2_sr) * Se + A2_se+A2_de+A_lr+A1_dr+A1_sr + (B2_se+B2_de+B_le+B1_dr+B1_sr) * Sr where: * Se is the emmitted packet size and Sr is the returned packet size * the delay introduced by the software on host 1 when emitting is A1_se + B1_se * Se * the delay introduced by the device in the same situation is A1_de + B1_de * Se * the delay introduced by the link in the same situation is A_le + B_le * Se where in Ah_ld and Bh_ld h is the host l the layer: software, device or link d is the direction: emmision or reception As you can see this gets quite complex. Does it need to ? * we would like the delay introduced by the software and the device to be negligible. Unfortunately this is not the case. Even when pinging the local host (the device should not even be used) the Rtt can be up to 1ms on slow hosts. * A1_le and A1_lr represent the time it takes for the signal to proagate from host 1 to host 2. This depends on the distance between the hosts and the speed of the signal (usually a fraction of the speed of light). This should be negligible in lans but certainly is not in satellite or transatlantic links. * At the device level the parameters are certainly the same when sending and when receiving a message. At the software level this is probably no longuer true since the treatment is not the same. Also it is probably difficult to define at which point the message turns around. Finally some links are asymetric. Examples of asymetric links include 56K modems, future ADSL links. Internet connections that involve a satellite as the return path do not really enter in this category since they rather involve a routing problem. When we do the difference of the RTT for two different sizes of packets what we get is not the intrisic link RAW capacity. This is clear from the following formula: With a fixed Sr: Rtt_b-Rtt_s = (B1e+Ble+B2r) * (Seb-Ses) With Se=Sr Rtt_b-Rtt-s = (B1e+B1r+Ble+Blr+B2e+B2r) * (Seb-Ses) 10.2. Minimising errors ----------------------- 10.3. The linear regression --------------------------- 10.4. Measuring asymetric links ------------------------------- To measure the bandwidth of asymetric links we should: First measure the uplink badnwidth Rtt1_b-Rtt1_s = (B1e+Ble+B2r) * (Seb-Ses) => We know B1e+Ble+B2r = (Rtt1_b-Rtt1_s) / (Seb-Ses) Rtt2_b-Rtt2_s = (B1e+B1r+Ble+Blr+B2e+B2r) * (Seb-Ses) => B1r+Blr+B2e = (Rtt2_b-Rtt2_s+Rtt1_b-Rtt1_s) / (Seb-Ses) 11. References -------------- * Van Jacobson has done some work on network bandwidth measurements. he has written a paper on this subject and a tool similar to bing: pathchar. You will find both at the following address ftp://ftp.ee.lbl.gov/pathchar. msri-talk.ps.gz is a postscript version of his talk at MSRI on bandwidth measurement. The pathchar-* files are the binaries of the pathchar tool. * Stephane Bortzmeyer has written echoping. bing-1.3.5/bing.c100664 1750 1750 176527 7005246510 13210 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, * measure point-to-point bandwidth. * * Hack by Pierre Beyssac (pb@fasterix.freenix.fr), based on FreeBSD ping. * Comments and bug reports welcome ! * * Original ping author - * Mike Muuss * U. S. Army Ballistic Research Laboratory * December, 1983 * * * Copyright (c) 1995,1997 Pierre Beyssac. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Pierre Beyssac, * Mike Muss, the University of California, Berkeley and its contributors. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY PIERRE BEYSSAC AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* The original UCB copyright notice follows */ /* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Muuss. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* $Id: bing.c,v 1.12 1999/10/24 22:45:03 fgouget Exp $ */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char rcsid[] = "$Id: bing.c,v 1.12 1999/10/24 22:45:03 fgouget Exp $"; #endif /* not lint */ /* ------------------------------------------------------------------------- */ #include #ifndef WIN32 #include #include #endif #include #include /* ctype.h provides endian-ness information (on Linux) */ #include /* types.h provides u_short on HPUX10 and Solaris */ #include /* Network includes/definitions */ #ifdef WIN32 #include "win32/win32.h" #include #include "win32/types.h" #ifdef _DEBUG #include #endif /* This variable is expected by getopt.c */ /* char* __progname; */ #else #include #include #include #endif /* WIN32 */ #include #include #include #include "bing_defs.h" #include "bing_misc.h" #include "bing_probes.h" #include "bing_stats.h" #ifdef WIN32 #include #endif /* * Command line options default values */ #define DEF_OPT_k 0 #define DEF_OPT_n 0 #define DEF_OPT_s PAD_PKT_SIZE #define DEF_OPT_S 1500 #define DEF_OPT_t 3 #define DEF_OPT_u -1 #define DEF_OPT_U 10 /* * Just a few global variables */ char* tool_name; /* Store the name of the tool as retrieved * from argv[0] */ int bing_options; /* Top level flags, i.e. not related with a * lower bing layer */ #define F_RESOLVE 1 /* Do not attempt to convert IP adresses to * symbolic host names */ bing_stats_t bing_stats; /* Stores the data of the bing_stats module. * Most bing data is stored here (packet sizes, * list of key hosts, measurements...) */ struct sockaddr addr_none={PF_INET,0,0}; #ifdef WIN32 BOOL PASCAL ConsoleCtrlHandler(DWORD dwCtrlType) { if (dwCtrlType==CTRL_C_EVENT) { /* (!!) this should be changed to a clean exit */ exit(1); } return FALSE; } #endif /* -------------------------------------------------------------------------- Parse the command line options to extract the operational parameters. The distinction here is that the value for the option 's' is a parameter while the list of packet sizes is an operational parameter. Note that some processing may be required to translate the first one into the other Most operational parameters are stored in the bing_stats structure, the remainder being simple flags. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- argc | X | | Number of command line arguments argv | X | | Command line arguments bing_stats | X | X | Stores all the operation bing parameters, i.e. | | | the packet sizes to use, the list of hosts... bing_options| | X | Remainder of the options. ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if successful, error code to return otherwise ------------+----+-----+-------------------------------------------------- */ int parse_command_line(int argc,char** argv, bing_stats_t *bing_stats,int *bing_options, int *nb_kh,char** *kh_names,struct sockaddr* *kh_addrs, int *retries,int *opt_k) { /* The following two are needed by Solaris */ extern int optind; extern char *optarg; int retcode; /* first used in command line parsing */ int opt; char* opt_p; int opt_n,opt_s,opt_S,opt_t,opt_u,opt_U,opt_z; int opt_nb_hosts; int i; /* first used in hostname resolution */ int j; struct sockaddr addr; int errors; retcode=1; *kh_names=NULL; /* to avoid memory leaks */ *kh_addrs=NULL; /* to avoid memory leaks */ /* * Initialise the options with their default values */ *opt_k=DEF_OPT_k; opt_n=DEF_OPT_n; opt_p=NULL; opt_s=DEF_OPT_s; opt_S=DEF_OPT_S; opt_t=DEF_OPT_t; opt_u=-1; /* Set both opt_u and opt_U to "uninitialised". Their default */ opt_U=-1; /* value will be set, if necessary, after the options have been */ /* parsed. */ opt_z=0; /* * 1. Parse the command line parameters */ while ((opt = getopt(argc, argv, "knp:s:S:t:u:U:z")) != EOF) { switch(opt) { case 'k': /* the listed hosts are the only key hosts. Note that this is * implicit if more than 3 hosts are given on the command line */ *opt_k=1; break; case 'n': /* disable IP address to host name conversion */ opt_n=1; break; case 'p': if (opt_z!=0) { fprintf(stderr,"%s: warning: pattern specified. Ignoring random fill\n",tool_name); opt_z=0; } opt_p=optarg; break; case 's': /* minimum packet size */ if (sscanf(optarg,"%d",&opt_s)!=1) { fprintf(stderr,"%s: error: small packet size expected after option 's'\n",tool_name); goto usage; } if (opt_s>MAX_PKT_SIZE) { fprintf(stderr,"%s: error: small packet size must be < %d\n",tool_name,MAX_PKT_SIZE+1); goto usage; } if (opt_s<0) { fprintf(stderr,"%s: error: small packet size must be >= 0\n",tool_name); goto usage; } if (opt_sMAX_PKT_SIZE) { fprintf(stderr,"%s: error: big packet size must be < %d\n",tool_name,MAX_PKT_SIZE+1); goto usage; } if (opt_S<0) { fprintf(stderr,"%s: error: big packet size must be >= 0\n",tool_name); goto usage; } if (opt_S= 0\n",tool_name); } break; case 'u': /* packet size increment */ if (sscanf(optarg,"%d",&opt_u)!=1) { fprintf(stderr,"%s: error: packet size increment expected after 'u' option\n",tool_name); goto usage; } if (opt_u<=0) { fprintf(stderr,"%s: error: packet size increment must be > 0\n",tool_name); goto usage; } if (opt_U!=-1) { fprintf(stderr,"%s: warning: packet size increment specified. Ignoring '-U %d' specification\n",tool_name,opt_U); opt_U=-1; } break; case 'U': /* number of packet sizes */ if (sscanf(optarg,"%d",&opt_U)!=1) { fprintf(stderr,"%s: error: number of sample packet sizes expected after 'U' option\n",tool_name); goto usage; } if (opt_U<2) { fprintf(stderr,"%s: error: the number of sample packet sizes must be > 2\n",tool_name); goto usage; } if (opt_u!=-1) { fprintf(stderr,"%s: warning: number of sample packet sizes specified. Ignoring '-u %d' specification\n",tool_name,opt_u); opt_u=-1; } break; case 'z': if (opt_p!=NULL) { fprintf(stderr,"%s: warning: random fill specified. Ignoring pattern\n",tool_name); opt_p=NULL; } opt_z=1; break; default: fprintf(stderr,"%s: error: unknown option '%c'\n",tool_name,opt); goto usage; } } if ((opt_u==-1) && (opt_U==-1)) { opt_u=DEF_OPT_u; opt_U=DEF_OPT_U; } opt_nb_hosts=argc-optind; /* (!!) methods */ bing_stats->nb_methods=1; bing_stats->methods=calloc(bing_stats->nb_methods,sizeof(*bing_stats->methods)); bing_stats->methods[0]=BP_OM_ECHO_REPLY; /* * 2. Compute the operational parameters */ if (opt_n==0) *bing_options|=F_RESOLVE; *retries=opt_t; if ((opt_p!=NULL) && (opt_p[0]!='\0')) { /* Set the packets payload pattern * First decode the pattern. */ int len,src,dst; int b; char subpattern[3]; char* pattern; /* check parameter and reallocate the pattern buffer */ len=strlen(opt_p); if (len % 2!=0) { fprintf(stderr,"%s: error: invalid pattern specification\n",tool_name); goto usage; } len=len/2; pattern=malloc(len); if (pattern==NULL) { fprintf(stderr,"%s: error: out of memory (l%d) !\n",tool_name,__LINE__); goto end; } /* fill the pattern buffer with the new pattern */ src=0; dst=0; subpattern[2]='\0'; while (opt_p[src]!='\0') { subpattern[0]=opt_p[src++]; subpattern[1]=opt_p[src++]; if (sscanf(subpattern,"%x",&b)!=1) { free(pattern); fprintf(stderr,"%s: error: %s is not a valid hexadecimal number\n",tool_name,subpattern); goto usage; } pattern[dst++]=(char)b; } /* Then configure the probe handle */ if (probe_set_option(bing_stats->probe_handle,SOL_BP,BPO_PATTERN,pattern,len)<0) { free(pattern); fprintf(stderr,"%s: error: failed to set the pattern\n",tool_name); goto end; } free(pattern); i=BP_FILL_PATTERN; if (probe_set_option(bing_stats->probe_handle,SOL_BP,BPO_FILLING,&i,sizeof(i))<0) { fprintf(stderr,"%s: error: unexpected error (l%d)\n",tool_name,__LINE__); goto end; } } if (opt_z!=0) { /* Specify the random fill */ i=BP_FILL_RANDOM; if (probe_set_option(bing_stats->probe_handle,SOL_BP,BPO_FILLING,&i,sizeof(i))<0) { fprintf(stderr,"%s: error: unexpected error (l%d)\n",tool_name,__LINE__); goto end; } } /* * 2.1. compute the actual packet sizes */ if (opt_s==opt_S) { fprintf(stderr,"%s: error: small packet size must be < big packet size\n",tool_name); goto usage; } if (opt_s>opt_S) { int swap_tmp; fprintf(stderr,"%s: warning: small packet size > big packet size. Switching packet sizes\n",tool_name); swap_tmp=opt_s; opt_s=opt_S; opt_S=swap_tmp; } if (opt_u==-1) { if (opt_U>opt_S-opt_s) { opt_U=opt_S-opt_s; fprintf(stderr,"%s: warning: the packet size interval is too small for the required number of size samples, using only %d samples\n",tool_name,opt_U); } bing_stats->nb_sizes=opt_U; bing_stats->packet_sizes=calloc(bing_stats->nb_sizes,sizeof(*(bing_stats->packet_sizes))); if (bing_stats->packet_sizes==NULL) { fprintf(stderr,"%s: error: out of memory (l%d) !\n",tool_name,__LINE__); goto end; } for (i=0;ipacket_sizes[i]=opt_s+(opt_S-opt_s)*i/(opt_U-1); } } else { if (opt_u>opt_S-opt_s) { opt_u=opt_S-opt_s; fprintf(stderr,"%s: warning: the specified packet size increment is too big, using %d\n",tool_name,opt_u); } if ((opt_S-opt_s)%opt_u==0) bing_stats->nb_sizes=1+(opt_S-opt_s)/opt_u; else { /* the division must be rounded up, hence the final +1 */ bing_stats->nb_sizes=1+(opt_S-opt_s)/opt_u+1; } bing_stats->packet_sizes=calloc(bing_stats->nb_sizes,sizeof(*(bing_stats->packet_sizes))); if (bing_stats->packet_sizes==NULL) { fprintf(stderr,"%s: error: out of memory (l%d) !\n",tool_name,__LINE__); goto end; } for (i=0;inb_sizes-1;i++) { bing_stats->packet_sizes[i]=opt_s+opt_u*i; } bing_stats->packet_sizes[i]=opt_S; } /* * 2.2. Determine the key host list. * 2.2.1. Translate the list of host names into a list of hosts adresses * This step allows us to: * - detect incorrect host names * - detect and eliminate duplicates */ *kh_names=(char**)calloc(opt_nb_hosts,sizeof(**kh_names)); *kh_addrs=(struct sockaddr*)calloc(opt_nb_hosts,sizeof(**kh_addrs)); if ((*kh_names==NULL) || (*kh_addrs==NULL)) { fprintf(stderr,"%s: error: out of memory (l%d) !\n",tool_name,__LINE__); goto end; } errors=0; *nb_kh=0; for (i=0;i2) { fprintf(stderr,"%s: warning: more than two hosts were specified, option 'k' is assumed\n",tool_name); *opt_k=1; } } if (errors!=0) goto end; retcode=0; end: /* Check for memory leaks */ /* (!!) free bing_stats->hosts in case of error */ /*if (*kh_names!=NULL) free(*kh_names); if (*kh_addrs!=NULL) free(*kh_addrs); */ return retcode; usage: retcode=2; fprintf(stderr,"Usage: %s [-k] [-n] [-p hexadecimal_pattern | -z] [-s small_packet_size] [-S big_packet_size] [-u packet_size_increment | -U nb_packet_size_samples] [-t traceroute_attempts] host ...\n",tool_name); goto end; } /** * Performs a traceroute and returns the hosts that were found. Also * displays warnings and error messages is any anomaly is detected. * * @param hosts the return structure that will contain the list of * all the hosts that were found during the traceroute * @param nb_kh the number of specified key hosts. This is the list * of hosts to return if khOnly is true * @param kh_names the names of the key hosts * @param kh_addrs the addresses of the key hosts * @param khOnly if true then don't return intermediate hosts that * were not specified in the key host list. In this mode the * traceroute will just compute the ttls of the key hosts and * check that there is no inconsistency * @return the number of hosts in the hosts array if successful, * -1 otherwise */ int traceroute(bing_stats_t* bing_stats, int* bing_options, int nb_kh, char** kh_names, struct sockaddr* kh_addrs, int khOnly, int retries) { struct sockaddr host_addr,last_addr; int add_all_hosts; int hosts_size; int kh,t; int ttl; char* name; int probe_res; bp_probedata_t probe; int add_host; /* (!!) fix the error handling */ /* Start by allocating the array for the returned hosts. There will be * at least nb_kh hosts in this list */ bing_stats->nb_hosts=0; hosts_size=nb_kh; bing_stats->hosts=malloc(hosts_size*sizeof(*bing_stats->hosts)); /* If we are in the 'bing host' case then we should start adding all * intermediate hosts right away. */ add_all_hosts=(nb_kh==1); addrcpy(&host_addr,&addr_none); addrcpy(&last_addr,&addr_none); ttl=0; for (kh=0;kh=1) { /* * We have already done a traceroute to a host. Check that this new host is * somewhere further on the same path. Sending a probe to this new host * with the ttl of the last host should fail when reaching the last host. */ DEBUG_MSG((stderr,"sending probe to %s, ttl=%d",host_addr2name(&kh_addrs[kh],0),ttl)); t=0; while (tprobe_handle,&kh_addrs[kh],PAD_PKT_SIZE,ttl,&probe); if (probe.contents!=NULL) free(probe.contents); /* (!!) maybe we should not break for source_quench ? Any others ? */ if (probe_res!=BP_RES_TIMEOUT) break; t++; } switch (probe_res) { case BP_RES_HIT: DEBUG_MSG((stderr," -> hit")); fprintf(stderr,"%s: error: reached %s with a ttl of %d\n", tool_name, kh_names[kh], ttl); fprintf(stderr,"%s: error: %s is not on the same network path as %s or the hosts order is wrong\n", tool_name, kh_names[kh], bing_stats->hosts[bing_stats->nb_hosts-1].name); /* Skip to the next key host */ /* (!!) shouldn't we just abort ? */ continue; case BP_RES_TTL_EXCEEDED: DEBUG_MSG((stderr," -> ttl exceeded")); if (addrcmp(&probe.src_addr, &(bing_stats->hosts[bing_stats->nb_hosts-1].address))!=0) { fprintf(stderr,"%s: error: probe to host %s with ttl %d failed at host %s instead of %s\n", tool_name, kh_names[kh], ttl, host_addr2name(&probe.src_addr,0), bing_stats->hosts[bing_stats->nb_hosts-1].name); fprintf(stderr,"%s: error: host %s is not on the same network path as %s\n", tool_name, kh_names[kh], bing_stats->hosts[bing_stats->nb_hosts-1].name); continue; } break; default: DEBUG_MSG((stderr," -> neither: res=%d",probe_res)); fprintf(stderr,"%s: warning: route check step failed at ttl %d for %s (%s)\n", tool_name,ttl,kh_names[kh],host_addr2name(&kh_addrs[kh],0)); return -1; } } host_reached=0; while ((host_reached==0) && (ttlprobe_handle,&kh_addrs[kh],PAD_PKT_SIZE,ttl,&probe); if (probe.contents!=NULL) free(probe.contents); /* (!!) maybe we should not break for source_quench ? Any others ? */ if (probe_res!=BP_RES_TIMEOUT) break; t++; } fprintf(stderr,"ttl=%d probe_res=%d host=%s\n",ttl,probe_res,host_addr2name(&kh_addrs[kh],0)); /* Check the return path */ if (probe_res<0) return -1; if (probe_res!=BP_RES_TIMEOUT) { if (addrcmp(&host_addr,&addr_none)==0) { /* We don't know yet what is the address of the local host. The best * thing to do is to take the destination address of the return packet * because this is going to be the address of the right network interface */ addrcpy(&host_addr,&probe.dst_addr); if (addrcmp(&host_addr,&probe.src_addr)!=0) { if (add_all_hosts!=0) { /* No need to worry about reallocating bing_stats->hosts yet, this is * our first host. Note that necessarily here khOnly==false. */ bing_stats->hosts[bing_stats->nb_hosts].name=strdup(host_addr2name(&host_addr,*bing_options & F_RESOLVE)); addrcpy(&bing_stats->hosts[bing_stats->nb_hosts].address,&host_addr); bing_stats->hosts[bing_stats->nb_hosts].ttl=0; fprintf(stderr," adding host %s at ttl 0\n",bing_stats->hosts[bing_stats->nb_hosts].name); bing_stats->nb_hosts++; } } else { /* We'll let the regular code handle adding this host but first * fix up the ttl. */ ttl=0; } } else if (addrcmp(&host_addr,&probe.dst_addr)!=0) { fprintf(stderr,"%s: error: at ttl %d the return path from %s went through the %s interface instead of %s for the other hosts\n", tool_name, ttl, kh_names[kh], host_addr2name(&probe.dst_addr,0), host_addr2name(&host_addr,0)); break; /* (!!) break, really ??? */ } } add_host=0; switch (probe_res) { case BP_RES_HIT: DEBUG_MSG((stderr," -> hit")); host_reached=1; name=kh_names[kh]; add_host=1; /* If we are in the 'bing host1 host2' and we have just reached host1 and * khOnly is not set then from now on we should add all intermediate hosts */ if ((khOnly==0) && (nb_kh==2)) { add_all_hosts=1; } break; case BP_RES_TTL_EXCEEDED: DEBUG_MSG((stderr," -> ttl exceeded probe.src=%s",host_addr2name(&probe.src_addr,0))); /* We might get stuck on a host for a few ttls */ if (addrcmp(&last_addr,&probe.src_addr)!=0) { name=NULL; add_host=add_all_hosts; } break; case BP_RES_TIMEOUT: /* print a warning and continue as for the default case */ break; default: DEBUG_MSG((stderr," -> neither: probe_res=%d",probe_res)); /* print a warning with the decoded icmp packet that we received */ fprintf(stderr,"%s: error: failed traceroute step %d to %s (%s)\n", tool_name,ttl,kh_names[kh],host_addr2name(&kh_addrs[kh],0)); /* Continue anyway. This might just be that this particular host sets * the return ttl with a value which is too low. A few ttls later it * might all be fine again. */ } if (add_host==1) { /* * Add this host to the bing_stats list of hosts. This is the * list of actual key hosts, i.e. the hosts between which are * the links to analyse. Note that there may be many hops * between two key hosts if the user wants so. In that case he * will get a composite bandwidth estimation. */ if (bing_stats->nb_hosts==hosts_size) { hosts_size++; bing_stats->hosts=realloc(bing_stats->hosts,hosts_size*sizeof(*(bing_stats->hosts))); if (bing_stats->hosts==NULL) { fprintf(stderr,"%s: error: out of memory (l%d)\n",tool_name,__LINE__); return -1; } } bing_stats->hosts[bing_stats->nb_hosts].name=strdup(name!=NULL?name:host_addr2name(&probe.src_addr,*bing_options & F_RESOLVE)); addrcpy(&bing_stats->hosts[bing_stats->nb_hosts].address,&probe.src_addr); bing_stats->hosts[bing_stats->nb_hosts].ttl=ttl; fprintf(stderr," adding host %s at ttl %d\n",bing_stats->hosts[bing_stats->nb_hosts].name,ttl); bing_stats->nb_hosts++; } addrcpy(&last_addr,&probe.src_addr); } } return bing_stats->nb_hosts; } /** * Redoes a probe for all the RTTs which are not in the RTT_STATE_OK * state. * * @param bing_stats the bing_stats * @param h index of the host * @param m method for which to redo the probes * @param randomizer an array used to randomize the order in which the * packet sizes are used. This is because the first probe that we * send to a host seems to always be rather bad so we try to make * sure it's not always the same one * @return 0 if no RTT was updated. This includes the case where no RTT * needed to be updated in the first place. Otherwise returns 1. */ int do_probes(bing_stats_t* bing_stats, int h, int m, int* randomizer) { int s; host_stats_t* host=&bing_stats->hosts[h]; rtt_law_t* rtt_law=&bing_stats->hosts[h].rtt_laws[m]; int updated=0; if ((rtt_law->nb_hinvalid==0) && (rtt_law->nb_linvalid==0) && (rtt_law->nb_redo==0)) return 0; for (s=0;snb_sizes;s++) { /* This internal loop is kind of a random experiment. */ int i; for (i=0;i<3;i++) { if (rtt_law->rtt_stats[randomizer[s]].state!=RTT_STATE_OK) { updated|=method_do_probe(bing_stats->probe_handle, host, bing_stats->packet_sizes[randomizer[s]], rtt_law, randomizer[s]); } } } return updated; } /** * Updates the linear regression results for this {host,method} and eliminates * any RTT which does not satisfy the following criteria: * - intra host rtt[size1] < rtt[size2] if size1 < size2 * - inter host rtt[host h] < rtt[host h+1] for any given size * - the last check is done for both hosts (h-1,h) and hosts (h,h+1) * and at the same time: * - update the linear regression for the host h-1 * - redo from scratch (for fear that the errors accumulate) the * linear regression on the host h * * @param bing_stats the bing_stats * @param h the host's index * @param m the method's index */ void do_host_regression(bing_stats_t* bing_stats,int h,int m) { int s; rtt_law_t* prtt_law=&bing_stats->hosts[h-1].rtt_laws[m]; rtt_law_t* rtt_law=&bing_stats->hosts[h].rtt_laws[m]; rtt_law_t* nrtt_law=&bing_stats->hosts[h+1].rtt_laws[m]; double max_rtt=DBL_MAX; linreg_init(&rtt_law->host_reg); for (s=bing_stats->nb_sizes-1;s>=0;s--) { if ((h+1nb_hosts) && (nrtt_law->rtt_stats[s].min_rttrtt_stats[s].min_rtt; } if (rtt_law->rtt_stats[s].min_rtt>=max_rtt) { /* Any RTT in the invalid state will end up here because min_rtt>=max_rtt. * Any RTT for which we don't have any data yet will also end up here * because min_rtt==DBL_MAX */ rtt_law_set_rtt_state(rtt_law,s,RTT_STATE_HINVALID,max_rtt); } else { /* So here the RTT has to be valid */ linreg_add_sample(&rtt_law->host_reg, rtt_law->rtt_stats[s].nb_bits, rtt_law->rtt_stats[s].min_rtt,0); max_rtt=rtt_law->rtt_stats[s].min_rtt; /* Update the previous host's RTT and linear regression result */ if ((h>0) && (prtt_law->rtt_stats[s].min_rtt>=max_rtt) && (prtt_law->rtt_stats[s].state!=RTT_STATE_HINVALID) ) { rtt_law_set_rtt_state(prtt_law,s,RTT_STATE_HINVALID,max_rtt); linreg_del_sample(&prtt_law->host_reg, prtt_law->rtt_stats[s].nb_bits, prtt_law->rtt_stats[s].min_rtt,1); } } } linreg_update(&rtt_law->host_reg); } /** * Updates the link level regression for the specified host (so this is for the * link between host h-1 and h). RTTs which do not satisfy the following criteria * are put in the RTT_STATE_LINVALID state: * - for any give size, rtt[h,s]-rtt[h-1,s]nb_methods;m++) { rtt_law_t* prtt_law=&bing_stats->hosts[h-1].rtt_laws[m]; rtt_law_t* rtt_law=&bing_stats->hosts[h].rtt_laws[m]; double last_rttd=DBL_MAX; int last_added; int s; linreg_init(&rtt_law->link_reg); for (s=0;snb_sizes;s++) { /* Reset the flags that were set during the last probe round */ rtt_law_set_rtt_state(prtt_law,s,RTT_STATE_OK|RTT_STATE_LINVALID2,0.0); rtt_law_set_rtt_state(rtt_law,s,RTT_STATE_OK|RTT_STATE_LINVALID1,0.0); if ((prtt_law->rtt_stats[s].state!=RTT_STATE_HINVALID) && (rtt_law->rtt_stats[s].state!=RTT_STATE_HINVALID) ) { double rttd=rtt_law->rtt_stats[s].min_rtt-prtt_law->rtt_stats[s].min_rtt; if ((last_rttd!=DBL_MAX) && (last_rttd>=rttd)) { /* There is a local inconsistency, schedule all the involved * RTTs for the next probe round. Note that this cannot happen * if s==0. */ rtt_law_set_rtt_state(prtt_law,s,RTT_STATE_LINVALID|RTT_STATE_LINVALID2,0.0); rtt_law_set_rtt_state(prtt_law,s-1,RTT_STATE_LINVALID|RTT_STATE_LINVALID2,0.0); rtt_law_set_rtt_state(rtt_law,s,RTT_STATE_LINVALID|RTT_STATE_LINVALID1,0.0); rtt_law_set_rtt_state(rtt_law,s-1,RTT_STATE_LINVALID|RTT_STATE_LINVALID1,0.0); if (last_added!=0) { linreg_del_sample(&bing_stats->hosts[h].rtt_laws[m].link_reg, rtt_law->rtt_stats[s-1].nb_bits, last_rttd,0); } last_added=0; } else { linreg_add_sample(&bing_stats->hosts[h].rtt_laws[m].link_reg, rtt_law->rtt_stats[s].nb_bits, rttd,0); last_added=1; } last_rttd=rttd; } else { last_rttd=DBL_MAX; /* last_added not significant in this case */ } } linreg_update(&rtt_law->link_reg); } } /** * Performs a global, across all hosts, methods and sizes, elimination * of invalid RTTs. * @param bing_stats the bing_stats */ void do_host_cleanup(bing_stats_t* bing_stats) { int h,m,s; /* Do a global elimination of inter-host errors: * - for any given size, rtt[host 1] < rtt[host 2] if host 1 comes before host 2 */ for (h=bing_stats->nb_hosts-1;h>=0;h--) { for (m=0;mnb_methods;m++) { double max_rtt=DBL_MAX; for (s=bing_stats->nb_sizes-1;s>=0;s--) { if ((h+1nb_hosts) && (bing_stats->hosts[h+1].rtt_laws[m].rtt_stats[s].min_rtthosts[h+1].rtt_laws[m].rtt_stats[s].min_rtt; } if (bing_stats->hosts[h].rtt_laws[m].rtt_stats[s].min_rtt>=max_rtt) { rtt_law_set_rtt_state(&bing_stats->hosts[h].rtt_laws[m],s,RTT_STATE_HINVALID,max_rtt); } else { max_rtt=bing_stats->hosts[h].rtt_laws[m].rtt_stats[s].min_rtt; } } } } } typedef struct { int index; double v; } double_sort_t; int double_sort(const void* e1,const void* e2) { double v1=((double_sort_t*)e1)->v; double v2=((double_sort_t*)e2)->v; if (v1v2) return 1; return 0; } int double_rabs_sort(const void* e1,const void* e2) { double v1=fabs(((double_sort_t*)e1)->v); double v2=fabs(((double_sort_t*)e2)->v); if (v1>v2) return -1; else if (v1 *

  • Links for which no correlation is available due to lack of data * points and links for which the correlation is based on less than 50% * of the points are automatically put at the bottom of the list (corr=-1). *
  • Links with a 'resulting' correlation of -1 are systematically processed, * whether or not they are in the first 50%. *
  • Link sthat have a very low correlation are very likely to already have * most of their probes in the RTT_STATE_REDO state because of link level * inconsistencies. For these links it is not even necessary to schedule * additional probes. So we substract the probes already scheduled for update * from the target 50% of additional probes. *
  • If the correlation is less than 0.8 both probes are being marked * for update. Otherwise only one of the two is marked for update. * * * I think this algorithm should work fine. But it may be possible that under * some circumstances the worst points are actually those that actually fit the * linear regression the best although it seems quite unlikely due to their * random nature. */ int do_probe_scheduling(bing_stats_t* bing_stats, double_sort_t* links,double_sort_t* link_errors, int* nb_hinvalid,int* nb_linvalid) { int h,m,s; int nb_redo=0; for (m=0;mnb_methods;m++) { *nb_hinvalid=0; *nb_linvalid=0; /* Sort the links based on their correlation (more or less) */ for (h=0;hnb_hosts;h++) { rtt_law_t* rtt_law=&bing_stats->hosts[h].rtt_laws[m]; if (h>0) { linreg_t* link_reg=&rtt_law->link_reg; links[h-1].index=h; if ((link_reg->nb_samplesnb_sizes/2) || (link_reg->nb_samples==0) || (link_reg->corr<0) ) { links[h-1].v=-1; } else { links[h-1].v=link_reg->corr; } } for (s=0;snb_sizes;s++) { if (rtt_law->rtt_stats[s].state==RTT_STATE_REDO) rtt_law_set_rtt_state(rtt_law,s,RTT_STATE_OK,0.0); } *nb_hinvalid+=rtt_law->nb_hinvalid; *nb_linvalid+=rtt_law->nb_linvalid; } qsort(links,bing_stats->nb_hosts-1,sizeof(double_sort_t),&double_sort); #if 0 printf("links from worst to best\n"); for (h=0;hnb_hosts-1;h++) { printf("h=%d corr=%f\n",links[h].index,links[h].v); } #endif /* For the worst links see which probes are causing trouble */ h=0; while (((hnb_hosts/2) || (links[h].v<0)) && (hnb_hosts-1)) { rtt_law_t* prtt_law=&bing_stats->hosts[links[h].index-1].rtt_laws[m]; rtt_law_t* rtt_law=&bing_stats->hosts[links[h].index].rtt_laws[m]; int nb_samples; #if 0 printf("scheduling probes for %d, link_reg.nb_samples=%d\n",links[h].index,rtt_law->link_reg.nb_samples); #endif if (rtt_law->link_reg.nb_samplesnb_sizes/2) { /* More than half the probes are invalid and are thus already scheduled * for the next probe round. There is no need to add more. */ #if 0 printf(" skipping %d\n",links[h].index); #endif h++; continue; } /* Sort the probes according to how well they fit the linear regression */ nb_samples=0; for (s=0;snb_sizes;s++) { if ((prtt_law->rtt_stats[s].state==RTT_STATE_OK) && (rtt_law->rtt_stats[s].state==RTT_STATE_OK) ) { double measured_rttd=rtt_law->rtt_stats[s].min_rtt-prtt_law->rtt_stats[s].min_rtt; double predicted_rttd=rtt_law->link_reg.a*rtt_law->rtt_stats[s].nb_bits+rtt_law->link_reg.b; link_errors[nb_samples].v=measured_rttd-predicted_rttd; link_errors[nb_samples].index=s; nb_samples++; } } qsort(link_errors,nb_samples,sizeof(double_sort_t),&double_rabs_sort); #if 0 printf("probes of link %d from worst to best will schedule the first %d\n",links[h].index,nb_samples-bing_stats->nb_sizes/2+1); for (s=0;snb_sizes/2+1;s++) { if ((links[h].v<0.8) || (link_errors[s].v>0)) { rtt_law_set_rtt_state(prtt_law,link_errors[s].index,RTT_STATE_REDO,0.0); nb_redo++; } if ((links[h].v<0.8) || (link_errors[s].v<0)) { rtt_law_set_rtt_state(rtt_law,link_errors[s].index,RTT_STATE_REDO,0.0); } } nb_redo+=rtt_law->nb_redo; h++; } } return nb_redo; } /** * Prints the characteristics of the given host: * 208.199.87.56/208.199.87.56: 15 ms, corr=0.999, invalid 23%, dropped 0% * host name and address, rtt of a 0bit packet, correlation, % invalid * measures, % dropped packets * * @param bing_stats the bing_stats * @param h the host's index */ void print_host_statistics(bing_stats_t* bing_stats,int h) { host_stats_t* host=&bing_stats->hosts[h]; double latency=DBL_MAX; double corr; int nb_hinvalid; int nb_dropped; int nb_probes=0; printf("%2d %-42s ",h,host->name); if (bing_stats->nb_methods==1) { if (host->rtt_laws[0].host_reg.a!=0) { latency=host->rtt_laws[0].host_reg.b; corr=host->rtt_laws[0].host_reg.corr; } nb_hinvalid=host->rtt_laws[0].nb_hinvalid; nb_dropped=host->rtt_laws[0].nb_dropped; nb_probes=nb_dropped+host->rtt_laws[0].nb_samples; } else { if (host->rtt_laws[0].host_reg.a!=0) { if (host->rtt_laws[1].host_reg.a!=0) { latency=(host->rtt_laws[0].host_reg.b+host->rtt_laws[1].host_reg.b)/2; corr=(host->rtt_laws[0].host_reg.corr+host->rtt_laws[1].host_reg.corr)/2; } else { latency=host->rtt_laws[0].host_reg.b; corr=host->rtt_laws[0].host_reg.corr; } } else if (host->rtt_laws[1].host_reg.a!=0) { latency=host->rtt_laws[1].host_reg.b; corr=host->rtt_laws[1].host_reg.corr; } nb_hinvalid=host->rtt_laws[0].nb_hinvalid+host->rtt_laws[1].nb_hinvalid; nb_dropped=host->rtt_laws[0].nb_dropped+host->rtt_laws[1].nb_dropped; nb_probes=nb_dropped+host->rtt_laws[0].nb_samples+host->rtt_laws[1].nb_samples; } if (corr==0.0) { /* (!!) shouldn't we use the nb_samples field instead ? */ printf("---.--- ms, -.---/--, "); } else { printf("%7.3f ms, %5.3f/%-2d, ",latency,corr,host->rtt_laws[0].host_reg.nb_samples); } printf("%5.1f%%, ",((double)100.0*nb_hinvalid)/bing_stats->nb_sizes); if (nb_probes==0) { printf("--.-%%\n"); } else { printf("%5.1f%%\n",((double)100.0*nb_dropped)/nb_probes); } } /** * Prints the characteristics of the link in the following format: * | 38Mb/s, 100 ms (145 bits), corr=0.75 * bandwidth delay in ms and in bits, correlation * or (for bidirectional) * |< 38Mb/s, 100 ms (145 bits), corr=0.75 * |> 40Mb/s, 80 ms (130 bits), corr=0.80 * where "| ", "|<" and "|>" are the prefixes for a composite * link, a downlink and an uplink */ void print_link_statistics(const char* prefix, linreg_t* link_data) { printf(" %s ",prefix); /* (!!) it is possible to have the bandwidth but not the correlation, * if host h-1 and host h have disjoint valid rtts for instance. * We should deal with this here. * * Also if the bandwidth is negative the latency does not mean anything * anyway and thus should not be displayed. */ if (link_data->a==0) { printf("----.-- b/s, ---.-- ms (----- bytes), -.---/--\n"); } else { double bandwidth=1/link_data->a; if (bandwidth<0) printf("---.--- b/s, "); else if (bandwidth<10) printf("%7g b/s, ",bandwidth*1e3); else if (bandwidth<1e4) printf("%7.2fKb/s, ",bandwidth); else printf("%7.2fMb/s, ",bandwidth/1e3); if (link_data->b<0) { printf("---.-- ms (----- bytes)"); } else { if (link_data->b<1) printf("%6.2f us ",link_data->b*1e3); else printf("%6.2f ms ",link_data->b); if (link_data->a<=0.0) { printf("(----- bytes)"); } else { printf("(%5.0f bytes)",link_data->b/link_data->a/8); } } if (link_data->corr!=0.0) { /* (!!) to fix, corr could really be 0 */ if (link_data->nb_samples<2) { printf(", -----/%d\n",link_data->nb_samples); } else { printf(", %5.3f/%d\n",link_data->corr,link_data->nb_samples); } } else { printf("\n"); } } } /** * Prints the bing results. * * @param bing_stats the bing_stats * @param last_update the index of the last host for which we printed * the statistics. For the first call this should be -1. This * parameter is updated to be equal to current. * @param current this is the index of the current host */ void print_statistics(bing_stats_t* bing_stats,int* last_update,int current) { rtt_law_t* prtt_law0=&bing_stats->hosts[*last_update].rtt_laws[0]; rtt_law_t* prtt_law1=&bing_stats->hosts[*last_update].rtt_laws[1]; int h; if (*last_update==-1) printf("\n\n"); for (h=(*last_update)+1;h<=current;h++) { rtt_law_t* rtt_law0; rtt_law_t* rtt_law1; rtt_law0=&bing_stats->hosts[h].rtt_laws[0]; if (bing_stats->nb_methods!=1) rtt_law1=&bing_stats->hosts[h].rtt_laws[1]; if (h>0) { linreg_t direct_link; linreg_t reverse_link; direct_link.a=rtt_law0->host_reg.a-prtt_law0->host_reg.a; direct_link.b=rtt_law0->host_reg.b-prtt_law0->host_reg.b; direct_link.corr=0; direct_link.nb_samples=0; /* Display the results for the link between host h-1 and host h */ if (bing_stats->nb_methods==1) { print_link_statistics("| ", &rtt_law0->link_reg); print_link_statistics("| ", &direct_link); } else { reverse_link.a=2*(rtt_law1->host_reg.a-prtt_law1->host_reg.a)-(rtt_law0->host_reg.a-prtt_law0->host_reg.a); reverse_link.b=(rtt_law0->host_reg.b-prtt_law0->host_reg.b)-reverse_link.a*(bing_stats->hosts[h].rtt_laws[0].rtt_stats[0].nb_bits-(bing_stats->packet_sizes[0]+28)*8); /* (!!) urgh, this is so ugly */ reverse_link.corr=0; /* or if you wish: ((a1b-a1a)-(a2b-a2a))*(s1r-s1d)+b2b-b2a) */ /* currently there is no rtt_law.link_reg equivalent for the reverse link * so we just display the result we calculated above */ print_link_statistics("|<", &reverse_link); print_link_statistics("|>", &rtt_law0->link_reg); print_link_statistics("|>", &direct_link); } } print_host_statistics(bing_stats,h); prtt_law0=rtt_law0; if (bing_stats->nb_methods!=1) prtt_law1=rtt_law1; } *last_update=current; } /* -------------------------------------------------------------------------- Arranges for the different components to be called in the proper order. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- argc | X | | Number of command line arguments argv | X | | Command line arguments ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if successful, 1 if an error occurred, | | | 2 if usage was given ------------+----+-----+-------------------------------------------------- */ int main(argc, argv) int argc; char** argv; { int retcode; int h,m,s; #ifdef WIN32 char* slash_ptr; #endif /* WIN32 */ int exit; /* (!!) keep this ? */ int* randomizer; int ri; double_sort_t* links; double_sort_t* link_errors; int round; #ifdef _DEBUG #ifdef WIN32 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif #endif tool_name=strrchr(argv[0],'/'); #ifdef WIN32 slash_ptr=tool_name; tool_name=strrchr((tool_name!=NULL?tool_name:argv[0]),'\\'); if (tool_name==NULL) tool_name=slash_ptr; #endif /* WIN32 */ if (tool_name==NULL) tool_name=argv[0]; else tool_name++; /* * Perform some initialisation tasks */ #ifdef WIN32 { WSADATA wsaData; WORD wsaVersionRequested; int err; /* Initialise the winsock */ wsaVersionRequested = MAKEWORD( 1, 1 ); err = WSAStartup( wsaVersionRequested, &wsaData ); if (err!=0) { fprintf(stderr,"%s: error: could not initialise the winsock\n", tool_name); return 1; } /* Install the ^C handler */ /* Not necessary yet SetConsoleCtrlHandler(ConsoleCtrlHandler,TRUE);*/ } #endif /* * Obtain a handle from the probe module right now. On Unix this involves * opening a RAW socket handle and must be done while we have root * privilege. */ bing_stats.probe_handle=probe_open(); if (bing_stats.probe_handle == NULL) { fprintf(stderr, "%s: error: cannot open ICMP module\n", tool_name); return 1; } #ifndef WIN32 /* Relinquish root privilege */ setgid(getgid()); setuid(getuid()); #endif { int nb_kh; char** kh_names; struct sockaddr* kh_addrs; int retries; int opt_k; int kh; /* * Parse the command_line */ retcode=parse_command_line(argc,argv,&bing_stats,&bing_options,&nb_kh,&kh_names,&kh_addrs,&retries,&opt_k); if (retcode!=0) return retcode; printf("Found %d key hosts\n",nb_kh); for (kh=0;kh=3),retries)<0) { return 1; } } free(kh_names); /* Note that we don't need to free the strings themselves */ free(kh_addrs); } /* (!!) For now, print the list of hosts that we came up with */ printf("Found %d hosts\n",bing_stats.nb_hosts); for (retcode=0;retcode0) do_link_regression(&bing_stats,h); /* Display the results for host h */ print_statistics(&bing_stats,&last_update,h); } } if (last_update>=0) { int nb_hinvalid,nb_linvalid,nb_redo; int max_probes; do_host_cleanup(&bing_stats); nb_redo=do_probe_scheduling(&bing_stats,links,link_errors,&nb_hinvalid,&nb_linvalid); max_probes=bing_stats.nb_hosts*bing_stats.nb_sizes; printf("\nRound %d hinvalid: %3d (%3.1f%%), linvalid: %3d (%3.1f%%), redo: %3d (%3.1f%%), total: %4d (%3.1f%%)\n", round, nb_hinvalid,((double)100.0*nb_hinvalid)/max_probes, nb_linvalid,((double)100.0*nb_linvalid)/max_probes, nb_redo,((double)100.0*nb_redo)/max_probes, nb_hinvalid+nb_linvalid+nb_redo,((double)100.0*(nb_hinvalid+nb_linvalid+nb_redo))/max_probes); #ifdef _DEBUG /* Display the RTTs and their state */ for (m=0;mstate==RTT_STATE_HINVALID?rtt_stat->min_rtt_sav:rtt_stat->min_rtt); if (rtt==DBL_MAX) { printf("(-------) "); } else { char c1,c2; switch (rtt_stat->state) { case RTT_STATE_OK: c1=c2=' '; break; case RTT_STATE_HINVALID: c1='('; c2=')'; break; case RTT_STATE_LINVALID|RTT_STATE_LINVALID1: c1='\\'; c2='/'; break; case RTT_STATE_LINVALID|RTT_STATE_LINVALID2: c1='/'; c2='\\'; break; case RTT_STATE_LINVALID|RTT_STATE_LINVALID1|RTT_STATE_LINVALID2: c1=c2='|'; break; case RTT_STATE_REDO: c1=c2='-'; break; } printf("%c%7.3f%c ",c1,rtt,c2); } } printf("\n"); } } #endif #ifdef _DEBUG /* Display the errors at the host level */ for (m=0;mcorr==0.0) || (rtt_stat->state==RTT_STATE_HINVALID) ) { printf("--------- "); } else { double err=rtt_stat->min_rtt-(linreg->a*rtt_stat->nb_bits+linreg->b); printf("%9.4f ",err); } } printf("\n"); } } #endif #ifdef _DEBUG /* Display the link rtt differences */ for (m=0;mstate==RTT_STATE_HINVALID) || (prtt_stat->state==(RTT_STATE_LINVALID|RTT_STATE_LINVALID2)) || (rtt_stat->state==RTT_STATE_HINVALID) || (rtt_stat->state==(RTT_STATE_LINVALID|RTT_STATE_LINVALID1)) ) { printf("--------- "); } else { double rttd=rtt_stat->min_rtt-prtt_stat->min_rtt; printf("%9.4f ",rttd); } } printf("\n"); } } #endif #ifdef _DEBUG /* Display the errors at the link level */ for (m=0;mcorr==0.0) || (prtt_stat->state==RTT_STATE_HINVALID) || (prtt_stat->state==(RTT_STATE_LINVALID|RTT_STATE_LINVALID2)) || (rtt_stat->state==RTT_STATE_HINVALID) || (rtt_stat->state==(RTT_STATE_LINVALID|RTT_STATE_LINVALID1)) ) { printf("--------- "); } else { double err=(rtt_stat->min_rtt-prtt_stat->min_rtt)-(linreg->a*rtt_stat->nb_bits+linreg->b); printf("%9.4f ",err); } } printf("\n"); } } #endif } else { printf("."); fflush(stdout); } } return 0; } bing-1.3.5/bing_defs.h100664 1750 1750 1726 7000272277 14146 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * * This header porives a few common definitions to be used by all parts * of bing. */ /* $Id: bing_defs.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef _bing_defs_h_ #define _bing_defs_h_ #ifdef __cplusplus #define BINGAPI "C" #else #define BINGAPI #endif #if defined(__STDC__) || defined(__cplusplus) #define BINGPROTO(func,param) func param #else #define BINGPROTO(func,param) func() #endif #ifdef NO_SNPRINTF #define snprintf sprintf #define snfargs(str,size,format) str,format #else #ifdef WIN32 #define snprintf _snprintf #endif #define snfargs(str,size,format) str,size,format #endif #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif #ifdef _DEBUG #define DEBUG_MSG(a) \ do { \ fprintf(stderr," --%s:%d-- ",__FILE__,__LINE__); \ fprintf a; \ fprintf(stderr,"\n"); \ fflush(stderr); \ } while (0) #else #define DEBUG_MSG(a) #endif #endif /* end of file */ bing-1.3.5/bing_misc.c100664 1750 1750 13641 7002022416 14160 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * */ /* $Id: bing_misc.c,v 1.5 1999/10/16 07:07:58 fgouget Exp $ */ #include #include /* types.h provides u_short on HPUX10 and Solaris */ #include #ifdef WIN32 #include #else #include #endif #include "bing_defs.h" #include "bing_misc.h" #ifndef INADDR_NONE /* This does not seem to be defined on Solaris */ #define INADDR_NONE (u_long)0xffffffff #endif #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK (u_long)0x7F000001 #endif #ifdef FAKE_NET /* (!!) for testing (without a connection) */ typedef struct { char* name; char* addr; } pseudo_hosts; #define NB_PSEUDO_HOSTS 13 static pseudo_hosts hosts[NB_PSEUDO_HOSTS]={ {"alcatraz","208.199.87.55"}, {"alcatraz.metaintegration.net","208.199.87.55"}, {"host1_1","192.168.1.1"}, {"host1_2","192.168.1.2"}, {"host1_3","192.168.1.3"}, {"host1_4","192.168.1.4"}, {"host1_5","192.168.1.5"}, {"host2_1","192.168.2.1"}, {"host2_2","192.168.2.2"}, {"host2_3","192.168.2.3"}, {"host2_4","192.168.2.4"}, {"host2_5","192.168.2.5"}, {"alcatraz","127.0.0.1"} }; struct hostent* __gethostbyname(char* hostname) { static struct hostent he; static struct in_addr addr; static struct in_addr* he_addr[2]; int i; for (i=0;isa_family!=addr2->sa_family) return addr1->sa_family-addr2->sa_family; switch (addr1->sa_family) { case AF_INET: return memcmp(&(SOCKADDR_IN(addr1)->sin_addr), &(SOCKADDR_IN(addr2)->sin_addr), sizeof(struct in_addr) ); break; default: return memcmp(addr1,addr2,sizeof(struct sockaddr)); } } int addrcmp2(struct sockaddr* addr1, unsigned short family, char* addr2) { if (addr1->sa_family!=family) return addr1->sa_family-family; switch (addr1->sa_family) { case AF_INET: return memcmp(&(SOCKADDR_IN(addr1)->sin_addr), addr2, sizeof(struct in_addr) ); break; default: return memcmp(addr1,addr2,sizeof(struct sockaddr)); } } void addrset(struct sockaddr* sa,struct in_addr ia,unsigned short ip) { struct sockaddr_in* sai=(struct sockaddr_in*)sa; sai->sin_family=PF_INET; sai->sin_port=ip; sai->sin_addr=ia; } struct hostent* getlocalhost(int domain) { struct in_addr addr; if (domain!=AF_INET) return NULL; /* (!!) this seems to be specific to linux, on other platforms it would be addr.S_un.S_addr */ addr.s_addr=INADDR_LOOPBACK; return gethostbyaddr((char*)&addr,sizeof(addr),AF_INET); } int host_name2addr(char* host_string, struct sockaddr* host_addr) { unsigned long int addr; addr=inet_addr(host_string); if (addr==INADDR_NONE) { struct hostent *he; he=gethostbyname(host_string); if (he==NULL) { return -1; } else if (he->h_addrtype!=AF_INET) { return -1; } else { host_addr->sa_family=AF_INET; /* the port *must* be initialized, even in icmp mode ! */ SOCKADDR_IN(host_addr)->sin_port=0; memcpy(&SOCKADDR_IN(host_addr)->sin_addr, he->h_addr, sizeof(SOCKADDR_IN(host_addr)->sin_addr)); } } else { host_addr->sa_family=AF_INET; /* the port *must* be initialized, even in icmp mode ! */ SOCKADDR_IN(host_addr)->sin_port=0; memcpy(&SOCKADDR_IN(host_addr)->sin_addr,&addr,sizeof(SOCKADDR_IN(host_addr)->sin_addr)); } return 0; } char* host_addr2name(struct sockaddr* host_addr, int resolve) { static char host_string[15+1+1+64+1+1]; char* ip_str; switch (host_addr->sa_family) { case AF_INET: ip_str=inet_ntoa(SOCKADDR_IN(host_addr)->sin_addr); if (!resolve) { strncpy(host_string,ip_str,sizeof(host_string)); } else { struct hostent *he; /* (!!) check out how gethostbyaddr works to find a more generic way of doing this */ he=gethostbyaddr((const char*)&(SOCKADDR_IN(host_addr)->sin_addr),4,AF_INET); if (he!=NULL) snprintf(snfargs(host_string,sizeof(host_string),"%s/%s"), he->h_name,ip_str); else snprintf(snfargs(host_string,sizeof(host_string),"/%s"), ip_str); } host_string[sizeof(host_string)-1]='\0'; return host_string; default: return ""; } } bing-1.3.5/bing_misc.h100664 1750 1750 10365 7000272277 14177 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * */ /* $Id: bing_misc.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef _bing_misc_h_ #define _bing_misc_h_ #ifdef WIN32 /* #include "win32/win32.h" #include #include "win32/types.h" */ #else #include #include #include #endif #include "bing_defs.h" #define SOCKADDR_IN(psockaddr) ((struct sockaddr_in*)psockaddr) #define addrcpy(dst,src) memcpy(dst,src,sizeof(struct sockaddr)) /* -------------------------------------------------------------------------- Compares to network addresses in a network type correct way. (!!) with ICMP we don't set the port field thus this function ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- addr1 | X | | The first address addr2 | X | | The second address ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if equal, non 0 otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( addrcmp, ( struct sockaddr* addr1, struct sockaddr* addr2 )); /* -------------------------------------------------------------------------- Compares to network addresses in a network type correct way. (!!) with ICMP we don't set the port field thus this function ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- addr1 | X | | The first address family | X | | The family of the second address addr2 | X | | The second address proper ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if equal, non 0 otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( addrcmp2, ( struct sockaddr* addr1, unsigned short family, char* addr2 )); extern BINGAPI void BINGPROTO( addrset, ( struct sockaddr* addr, struct in_addr ia, unsigned short port )); /* -------------------------------------------------------------------------- Converts a string to an IP address. The address may be specified either as a host name or as the IP address in "dotted" format. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- host_string | X | | Host name either symbolic or in dotted format host_addr | | X | Host address ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if successful, -1 otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( host_name2addr, ( char* host_string, struct sockaddr* host_addr )); /* -------------------------------------------------------------------------- Returns a pointer to a string suitable for representing the host's address. If the options parameter contains the F_NUMERIC option HostAddr2String will not attempt to get the host name so that the returned string will only contain the host adress. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- host_addr | X | | The host IP address resolve | X | | If 1 the address will be conerted to a symbolic | | | host name ------------+----+-----+-------------------------------------------------- RETURN | | X | A pointer to a static area containing the string | | | to display for that host. ------------+----+-----+-------------------------------------------------- */ extern BINGAPI char* BINGPROTO( host_addr2name, ( struct sockaddr* host_addr, int resolve )); #endif /* end of file */ bing-1.3.5/bing_probes.c100664 1750 1750 42442 7005246510 14526 0ustar fgougetfgouget/* * Unofficial release 1.3 * B I N G * */ /* $Id: bing_probes.c,v 1.12 1999/10/24 23:28:14 fgouget Exp $ */ #include #include #include #include /* types.h provides u_short on HPUX10 and Solaris */ #include #ifdef WIN32 #include #include "win32/types.h" #else #include #include #endif #include #include #include "bing_misc.h" #include "bing_probes.h" #include "mod_icmp.h" #ifdef NO_RANDOM #define random rand #define srandom srand #endif /* (!!) this will have to move somewhere else */ #ifndef ICMP_ROUTERADVERT #define ICMP_ROUTERADVERT 9 /* router advertisement */ #endif #ifndef ICMP_ROUTERSOLICIT #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #endif #ifndef ICMP_TIMXCEED #define ICMP_TIMXCEED 11 /* time exceeded, code: */ #endif #ifndef ICMP_PARAMPROB #define ICMP_PARAMPROB 12 /* ip header bad */ #endif #ifndef ICMP_TSTAMP #define ICMP_TSTAMP 13 /* timestamp request */ #endif #ifndef ICMP_TSTAMPREPLY #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #endif #ifndef ICMP_IREQ #define ICMP_IREQ 15 /* information request */ #endif #ifndef ICMP_IREQREPLY #define ICMP_IREQREPLY 16 /* information reply */ #endif #ifndef ICMP_MASKREQ #define ICMP_MASKREQ 17 /* address mask request */ #endif #ifndef ICMP_MASKREPLY #define ICMP_MASKREPLY 18 /* address mask reply */ #endif /* * bing_probes default settings */ #define DEF_UDP_PORT 28933 /* * This structure holds the information kept in a probe handle. */ typedef struct { /* * Options modified via probe_set_option */ unsigned char bp_om:2, /* specifies the probe method */ bp_fill:2, /* specifies the type of packet filling */ bp_unused:4; /* not used */ short udp_port; /* the invalid UDP port to probe in BP_OM_UNREACH_PORT mode */ int pattern_size; /* the pattern size if one exists */ char* pattern; /* the pattern data */ /* * Internal data house-keeping */ icmp_handle icmp_handle; /* the icmp module handle used to send icmp packets */ struct icmp* packet; /* the icmp packet contents, contains the header and data */ /* (!!) does it contain the ip header or just the icmp header? */ int packet_options_size; /* the options size packet+packet_options_size point to the data */ int packet_data_size; /* the packet data size */ int packet_data_update; /* 1 if the packet data needs updating */ } bp_state_t; #define handle2state(h) ((bp_state_t*)h) /* * Some internal functions. */ void dump_packet(char* packet, int size) { struct ip* ip; struct sockaddr src_addr,dst_addr; char* ipopt; int hlen; int j; /* Dump the ip header */ ip=(struct ip*)packet; hlen=ip->ip_hl<<2; SOCKADDR_IN(&src_addr)->sin_family=AF_INET; SOCKADDR_IN(&src_addr)->sin_port=0; SOCKADDR_IN(&src_addr)->sin_addr.s_addr=ip->ip_src.s_addr; SOCKADDR_IN(&dst_addr)->sin_family=AF_INET; SOCKADDR_IN(&dst_addr)->sin_port=0; SOCKADDR_IN(&dst_addr)->sin_addr.s_addr=ip->ip_dst.s_addr; printf("\n"); for (j=0;jip_v, ip->ip_hl, ip->ip_tos, (unsigned short)ip->ip_len, ip->ip_id); printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13, (ip->ip_off) & 0x1fff); printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); printf(" %-15s", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); printf(" %s\n", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); /* dump any option bytes */ if (hlen>sizeof(struct ip)) { printf("IP Options: "); ipopt=(char*)ip+sizeof(struct ip); /* point to options */ while (hlen-->sizeof(struct ip)) { printf("%02x", *ipopt++); } putchar('\n'); } /* Dump the icmp header if any*/ if (ip->ip_p==1) { struct icmp* icp; icp=(struct icmp*)(packet+(ip->ip_hl<<2)); switch (icp->icmp_type) { case ICMP_ECHOREPLY: printf("Echo Reply: code=%d id=%d seq=%d\n",icp->icmp_code,icp->icmp_id,icp->icmp_seq); break; case ICMP_SOURCEQUENCH: printf("ICMP_SOURCEQUENCH"); break; case ICMP_REDIRECT: printf("ICMP_REDIRECT"); break; case ICMP_ECHO: printf("Echo Request: code=%d id=%d seq=%d\n",icp->icmp_code,icp->icmp_id,icp->icmp_seq); break; case ICMP_ROUTERADVERT: printf("ICMP_ROUTERADVERT"); break; case ICMP_ROUTERSOLICIT: printf("ICMP_ROUTERSOLICIT"); break; case ICMP_TIMXCEED: printf("ICMP_TIMXCEED"); break; case ICMP_PARAMPROB: printf("ICMP_PARAMPROB"); break; case ICMP_TSTAMP: printf("ICMP_TSTAMP"); break; case ICMP_TSTAMPREPLY: printf("ICMP_TSTAMPREPLY"); break; case ICMP_IREQ: printf("ICMP_IREQ"); break; case ICMP_IREQREPLY: printf("ICMP_IREQREPLY"); break; case ICMP_MASKREQ: printf("ICMP_MASKREQ"); break; case ICMP_MASKREPLY: printf("ICMP_MASKREPLY"); break; default: printf("unknown type %d\n",icp->icmp_type); } } /* Give short info about the payload */ } /* -------------------------------------------------------------------------- Builds the data field to be sent with the packet. The data put in the packet is either dynamic, e.g. random data, or static (i.e. does not change depending on the packet), e.g. a user specified pattern. In the first case the data is built on the fly while in the second case it is precomputed and recomputed each time the packet size increases. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- state | X | | Internal state information size | X | | The required packet size ------------+----+-----+-------------------------------------------------- RETURN | | X | No return value ------------+----+-----+-------------------------------------------------- */ static int generate_data(bp_state_t* state, int size) { int i; /* maybe reallocate the data buffer */ if (size>state->packet_data_size) { /* Allocate buffers which size is a multiple of 1024 */ state->packet_data_size=(size+state->packet_options_size+1024) & ~1023; state->packet=realloc(state->packet,state->packet_data_size); state->packet_data_size-=state->packet_options_size; if (state->packet==NULL) return -1; state->packet_data_update=1; } /* maybe update the data in the buffer */ if (state->packet_data_update==1) { unsigned char* packet_data; packet_data=((unsigned char*)state->packet)+state->packet_options_size; switch (state->bp_fill) { case BP_FILL_SEQ: /* Default case: just put some predictible data in * the packet. */ for (i=0;ipacket_data_size;i++) { packet_data[i]=(unsigned char)(i & 0xff); } state->packet_data_update=0; break; case BP_FILL_PATTERN: /* Fill the buffer with the pattern. Since this * pattern does not change we can compute it ahead * of time */ i=0; while (ipacket_data_size) { memcpy(packet_data+i,state->pattern, MIN(state->pattern_size,state->packet_data_size-i)); i+=state->pattern_size; } state->packet_data_update=0; break; case BP_FILL_RANDOM: /* Initialise the packet payload with random data. * Note that on some platforms (e.g. Win32) RAND_MAX is less * than INT_MAX. Thus we only use the lower byte of the returned * int which in turn relies on the assumption that RAND_MAX+1 * is a multiple of 256. Fortunately this seems to always be the * case. */ /*printf("Filling the packet with %d random bytes:",state->packet_data_size);*/ for (i=0;ipacket_data_size;i++) { packet_data[i]=(unsigned char)(random() & 0xff); /*if (i%16==0) printf("\n%3d: ",i); printf("%2x,",packet_data[i]);*/ } /*printf("\n");*/ /* Unlike the other types of "filling" this one must be * updated with each outgoing packet, thus we do not reset * packet_data_update. */ break; default: return -1; } } return 0; } /* * Implementation of the bing_probe interface. */ bp_handle probe_open() { bp_state_t* h; /* Allocate the data structure */ h=malloc(sizeof(*h)); if (h==NULL) return NULL; /* Open the ICMP handle. This requires root privilege on Unix */ h->icmp_handle=icmp_open(); if (h->icmp_handle==NULL) { free(h); return NULL; } /* And initialise the other fields */ /* (!!) what should be the default ??? */ h->bp_om=BP_OM_ECHO_REPLY; h->bp_fill=BP_FILL_SEQ; h->udp_port=DEF_UDP_PORT; h->pattern_size=0; h->pattern=NULL; h->packet=NULL; /* (!!) and what if the options are bigger, like if we do loose source routing or some such (which means the packet would also contain the ip options, not only the icmp options */ h->packet_options_size=(char*)h->packet->icmp_data-(char*)h->packet; h->packet_data_size=0; h->packet_data_update=1; return h; } int probe_set_option(bp_handle handle, int level, int option, void* optval, int optlen) { bp_state_t* state; int intval; if (handle==NULL) { errno=EINVAL; return -1; } state=handle2state(handle); if (level!=SOL_BP) return icmp_set_option(state->icmp_handle,level,option,optval,optlen); switch (option) { case BPO_FILLING: intval=*((int*)optval); if (((intval & ~BP_FILL_MASK)!=0) || (intval==BP_FILL_MASK)) { errno=EINVAL; return -1; } if ((intval==BP_FILL_PATTERN) && (state->pattern==NULL)) { errno=EFAULT; return -1; } state->bp_fill=intval; break; case BPO_PATTERN: /* check parameter */ if ((optlen==0) && (state->bp_fill==BP_FILL_PATTERN)) { errno=EINVAL; return -1; } /* and reallocate the pattern buffer */ state->pattern_size=optlen; state->pattern=realloc(state->pattern,state->pattern_size); if (state->pattern==NULL) return (optlen==0?0:-1); state->packet_data_update=1; /* the old pattern is lost */ memcpy(state->pattern,(char*)optval,state->pattern_size); break; case BPO_OM: intval=*((int*)optval); if (((intval & ~BP_OM_MASK)!=0) || (intval==BP_OM_MASK)){ errno=EINVAL; return -1; } state->bp_om=intval; break; case BPO_UDP_PORT: handle2state(handle)->udp_port=(int)optval; break; default: errno=EINVAL; return -1; } return 0; } int do_probe(bp_handle handle, struct sockaddr* target, int size, int ttl, bp_probedata_t *probe) { bp_state_t* state; static int icp_seq=0; int res; int src_addr_size; int ret; probe->contents=NULL; if ((handle==NULL) || (sizebp_om) { case BP_OM_UNREACH_PORT: /* BP_OM_UNREACH_PORT: send a UDP packet to a non-existing port. * We will either receive a TTL Exceeded or a Port Unreachable * ICMP message. */ return -1; break; case BP_OM_ECHO_REPLY: case BP_OM_TTL_EXCEEDED: probe->size=state->packet_options_size+size; probe->contents=malloc(sizeof(struct ip)+probe->size); /* BP_OM_TTL_EXCEEDED and BP_OM_ECHO_REPLY: send an ICMP EchoRequest * message. * In the first case the upper layer should have arranged to receive * TTL Exceeded ICMP messages while in the second case we should receive * Echo Reply ICMP messages. */ state->packet->icmp_type=ICMP_ECHO; state->packet->icmp_code=0; /* icmp_id is set by icmp_send */ state->packet->icmp_seq = icp_seq++; /* (TODO) target should be in the sockaddr format. * Find something else to compute the packet size. * The ttl is not handled. */ if (ttl>0) { probe_set_option(handle, IPPROTO_IP, IP_TTL, &ttl, 4); } res=icmp_send(state->icmp_handle,state->packet, probe->size, target,sizeof(*target)); if (res<0) { return -1; } /* Now try to get the answer to our packet. Since we receive all ICMP * packets for this host we may receive other packets before our own, * we may even receive the packet that we just sent ! */ while (1) { src_addr_size=sizeof(probe->src_addr); res=icmp_recv(state->icmp_handle, probe->contents,probe->size+sizeof(struct ip), &probe->src_addr,&src_addr_size, &probe->rtt); if (res>0) { struct ip* ip; struct icmp* icp; /* On linux the returned size does not take into account the ip header ! * Furthermore the ip->ip_len field does not take into account endianess * issues. That's why I'm using res+(ip->ip_hl<<2). */ /* ip header */ ip=(struct ip*)(probe->contents); /* icmp header */ icp=(struct icmp*)(probe->contents+(ip->ip_hl<<2)); probe->dst_addr.sa_family=PF_INET; memcpy(&((struct sockaddr_in*)(&probe->dst_addr))->sin_addr,&ip->ip_dst,4); ((struct sockaddr_in*)&(probe->dst_addr))->sin_port=0; switch (icp->icmp_type) { case ICMP_ECHOREPLY: /*DEBUG_MSG((stderr,"icmp_type/code=%d/%d rtt=%g",icp->icmp_type,icp->icmp_code,probe->rtt));*/ if ((icp->icmp_seq+1==icp_seq) && (icp->icmp_id==icmp_get_id(state->icmp_handle))) { probe->size=res+(ip->ip_hl<<2); return BP_RES_HIT; } else { printf("received a stale Echo Reply id=%d seq=%d\n",icp->icmp_id,icp->icmp_seq); } break; case ICMP_UNREACH: DEBUG_MSG((stderr,"icmp_type/code=%d/%d rtt=%g",icp->icmp_type,icp->icmp_code,probe->rtt)); if (icp->icmp_code==ICMP_UNREACH_PORT) { probe->size=res+(ip->ip_hl<<2); return BP_RES_HIT; } break; case ICMP_TIMXCEED: DEBUG_MSG((stderr,"icmp_type/code=%d/%d rtt=%g",icp->icmp_type,icp->icmp_code,probe->rtt)); if (icp->icmp_code==ICMP_TIMXCEED_INTRANS) { probe->size=res+(ip->ip_hl<<2); return BP_RES_TTL_EXCEEDED; } break; case ICMP_ECHO: /* this is most likely the echo that we sent */ break; default: DEBUG_MSG((stderr,"icmp_type/code=%d/%d",icp->icmp_type,icp->icmp_code)); dump_packet(probe->contents,probe->size); } } else if (res==0) { DEBUG_MSG((stderr,"probe timeout")); return BP_RES_TIMEOUT; } else { DEBUG_MSG((stderr,"res=%d errno=%d",res,errno)); return res; } /*DEBUG_MSG((stderr,"*** retrying"));*/ } break; } return ret; } int probe_close(bp_handle handle) { bp_state_t* state; if (handle==NULL) { errno=EINVAL; return -1; } state=handle2state(handle); if (state->pattern!=NULL) free(state->pattern); icmp_close(state->icmp_handle); if (state->packet!=NULL) free(state->packet); free(state); return 0; } bing-1.3.5/bing_probes.h100664 1750 1750 22350 7000272277 14533 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * * This part is responsible for sending the probes that bing uses to * measure the Rtts. */ /* $Id: bing_probes.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef _bing_probes_h_ #define _bing_probes_h_ /* types.h provides u_short on HPUX10 and Solaris */ #include #ifdef WIN32 /*#include "win32/win32.h"*/ #include /*#include "win32/types.h"*/ #else #include #include #endif #include "bing_defs.h" /* * Some general limits */ /* (!!) there must be a minimum packet size, what is it ? or is this the payload size */ #define MAX_PKT_SIZE (65536-60-8) #define PAD_PKT_SIZE 44 #define STD_TTL_LIMIT 30 /* * This defines the options to */ /* * To set a bing_probes option, use SOL_BP as the option level and one * of the option names below. */ #define SOL_BP 1515 #define BPO_FILLING 1 #define BPO_PATTERN 2 #define BPO_OM 3 #define BPO_UDP_PORT 4 /* * To specify what the packets payload should be, use BPO_FILLING as the * option and specify one of the following values as the data. * * Note: * You must use BPO_PATTERN before you can enable the use of the pattern * with BPO_FILLING. The parameter of BPO_PATTERN is a pointer to a byte * array the length of which must be given in len. */ #define BP_FILL_MASK 3 #define BP_FILL_SEQ 0 #define BP_FILL_PATTERN 1 #define BP_FILL_RANDOM 2 /* * To specify the probe operating mode, use BPO_OM and set option data * to one of the following values. */ #define BP_OM_MASK 3 #define BP_OM_UNREACH_PORT 0 #define BP_OM_TTL_EXCEEDED 1 #define BP_OM_ECHO_REPLY 2 typedef void* bp_handle; /* * This structure is used by probe_send to return its results */ typedef struct { /* This structure describes the packet that was received by * do_probe in response to its probe. It depends both on the * method used and on the outcome of the probe. */ double rtt; /* the rtt in milliseconds */ struct sockaddr src_addr; /* the host this return packet comes from */ /* (!!) this should be changed to in_addr or even something more general for IP_V6 for instance */ struct sockaddr dst_addr; /* the host this return packet was being sent to */ char type, subtype; /* this is the ICMP packet type and subtype * of the return packet. */ int size; /* the packet size */ char* contents; /* the full packet contents, this includes * the IP header, ICMP... */ } bp_probedata_t; /* -------------------------------------------------------------------------- probe_open performs some initialisation tasks and returns a pointer to be used with the other functions. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- ------------+----+-----+-------------------------------------------------- RETURN | | X | The probe handle if successful, NULL otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI bp_handle BINGPROTO( probe_open, ( void )); /* -------------------------------------------------------------------------- probe_setoption sets a probe/socket option. At the SOL_BP level the valid options are: BPO_UDP_PORT: sets the UDP port used in BP_UNREACH_PORT mode option_data must point to a short in host order BPO_FILLING: sets the pattern used to fill packet in pattern mode. BPO_PATTERN: sets the pattern used to fill the packets option_data must point to an hexadecimal string representing the pattern Options concerning other levels are given to the underlying levels. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- handle | X | | The probe handle to modify level | X | | Level at which the option reside. This may be | | | either SOL_BP or SOL_SOCKET. option | X | | Option to modify optval | X | | The option data. If the option data is an integer | | | it should be pointed to not passed as the pointer.. optlen | X | | The option data length. Note that for a pointer | | | this is the length of the data pointed to. ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if successful, -1 otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( probe_set_option, ( bp_handle handle, int level, int option, void* optval, int optlen )); /* * The following values describe the result of a probe. This is the value * returned by do_probe. See do_probe for a detailed explanation of these * constants. */ #define BP_RES_TIMEOUT 0 #define BP_RES_TTL_EXCEEDED 1 #define BP_RES_HIT 2 #define BP_RES_UNKNOWN 4 /* -------------------------------------------------------------------------- do_probe sends a packet to "probe" the network. It can be used for two purposes: - measure the RTT to a specific host. - perform a traceroute operation by progressively increasing the TTL parameter. When measuring the RTT, do_probe can perform the probe in three different modes: - BP_UNREACH_PORT: We send an UDP packet to a host on an invalid UDP port. We expect to receive a fixed size ICMP Port Unreachable message in return. - BP_ECHO_REPLY: We send an ICMP Echo Request message to the host, and expect to receive an ICMP Echo Reply message of the same size. - BP_TTL_EXCEEDED: This method behaves differently depending on whether it is performed on an intermediate host in the path or on the last host in the network. In the first case we send an ICMP Echo Request message to the last host but with a TTL so that the host we want to probe returns a fixed size ICMP TTL Exceeded message. In the second case we cannot get this behavior and will always receive an ICMP Echo Request message. Thus this method behaves like BP_UNREACH_PORT for intermediate hosts and like BP_ECHO_REPLY for the terminal host. This last method is required on the Win32 platforms because of the restrictions placed on sending and receiving ICMP packets. In addition to the parameters listed below do_probe takes the following parameters from the structure pointed to by the handle parameter: bp_udp_port, bp_pattern_size, bp_pattern. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- handle | X | | Probe handle target | X | | Address of the target host size | X | | Size of the outgoing message payload ttl | X | | Specifies the TTL of the outgoing packet probe | | X | Stores the probe result ------------+----+-----+-------------------------------------------------- RETURN | | X | -1 if an error occured and the probe could not | | | be sent properly or we could not set up to | | | receive the packet. probe does not contain any | | | useful data. | | | BP_RES_TIMEOUT: No answer was ever received and | | | the probe finally timed out. probe does not | | | contain any useful data. | | | BP_RES_TTL_EXCEEDED: The ttl was too small and | | | probe contains the packet we received. | | | BP_RES_HIT: The probe reached the target host and | | | probe contains the packet that it returned. | | | BP_RES_UNKNOWN: Some unknown/other type of | | | packet was received. probe describes this | | | packet for diagnosis purposes. ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( do_probe, ( bp_handle handle, struct sockaddr* target, int size, int ttl, bp_probedata_t *probe )); /* -------------------------------------------------------------------------- probe_close releases the resources allocated by probe_open. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- handle | X | | Probe handle ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if successful, -1 otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( probe_close, ( bp_handle handle )); #endif /* end of file */ bing-1.3.5/bing_stats.c100664 1750 1750 20651 7005246510 14370 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * * This file implements the data gathering and analysis algorithms * that are specific to bing. * */ /* $Id: bing_stats.c,v 1.9 1999/10/23 21:56:06 fgouget Exp $ */ #include #include #include #include #include "bing_stats.h" /* (!!) for debug, remove... */ #include "bing_misc.h" /* * Now the bing stats */ int rtt_stats_init(rtt_stats_t *rtt_stats) { rtt_stats->nb_samples=0; rtt_stats->nb_dropped=0; rtt_stats->nb_bits=0; rtt_stats->state=RTT_STATE_HINVALID; rtt_stats->min_rtt=DBL_MAX; #ifdef _DEBUG rtt_stats->min_rtt_sav=DBL_MAX; #endif rtt_stats->sum_rtt=0; rtt_stats->max_rtt=DBL_MIN; rtt_stats->samples_size=0; rtt_stats->samples=NULL; return 0; } int rtt_law_init(rtt_law_t *rtt_law, int nb_sizes) { int s; rtt_law->rtt_stats=calloc(nb_sizes,sizeof(*rtt_law->rtt_stats)); for (s=0;srtt_stats[s]); } rtt_law->nb_samples=0; rtt_law->nb_dropped=0; rtt_law->nb_hinvalid=nb_sizes; rtt_law->nb_linvalid=0; rtt_law->nb_redo=0; linreg_init(&rtt_law->host_reg); linreg_init(&rtt_law->link_reg); return 0; } /* (!!) note that rtt_law_add is not updating the linear regression anymore */ int rtt_law_add(rtt_law_t* rtt_law, int index, int size, double rtt) { /* Check the parameters */ if (rtt_law==NULL) { errno=EINVAL; return -1; } if (size<0) { rtt_law->rtt_stats[index].nb_dropped++; rtt_law->nb_dropped++; } else { rtt_stats_t* rtt_stats; rtt_stats=&rtt_law->rtt_stats[index]; if (rtt_stats->nb_bits==0) { rtt_stats->nb_bits=8*size; } else if (rtt_stats->nb_bits!=8*size) { /* (!!) oups, do something more, this is really wrong */ printf("the packet size has changed: %d!=%d\n",8*size,rtt_stats->nb_bits); return -1; } /* Add this new sample */ #if 0 if (rtt_stats->nb_samples==rtt_stats->samples_size) { rtt_stats->samples_size+=10; rtt_stats->samples=realloc(rtt_stats->samples, sizeof(*rtt_stats)*(rtt_stats->samples_size)); } rtt_stats->samples[rtt_stats->nb_samples++]=rtt; #endif rtt_law->nb_samples++; /* Update the statistics */ rtt_stats->sum_rtt+=rtt; if (rttmin_rtt) { if (rtt_stats->state==RTT_STATE_HINVALID) { #if 0 if (rtt_stats->min_rtt_sav!=DBL_MAX) printf("validating %d: %9.7f -> %9.7f (min was %9.7f)\n",index,rtt_stats->min_rtt_sav,rtt,rtt_stats->min_rtt); #endif rtt_law_set_rtt_state(rtt_law,index,RTT_STATE_OK,0); } rtt_stats->min_rtt=rtt; return 1; } else if (rtt>rtt_stats->max_rtt) { rtt_stats->max_rtt=rtt; } } return 0; } /** * Sets the state of the specified RTT measurement and updates * the rtt_law_t level statistics accordingly. * * @param rtt_law the host,method on which to operate * @param s the index of the RTT to modify * @param state the new state of the RTT, one of the RTT_STATE_* values. * To unset the RTT_STATE_LINVALID1 or RTT_STATE_LINVALID2 flags * use respectively RTT_STATE_OK|RTT_STATE_LINVALID1 and * RTT_STATE_OK|RTT_STATE_LINVALID2 * @param max_rtt if state is RTT_STATE_HINVALID this is the RTT value * to attain before the RTT is considered valid again. Otherwise * this parameter is not significant * @return the previous state of the RTT */ int rtt_law_set_rtt_state(rtt_law_t *rtt_law, int s, int state, double max_rtt) { int ostate; ostate=rtt_law->rtt_stats[s].state; if (state==ostate) { if ((state==RTT_STATE_HINVALID) && (rtt_law->rtt_stats[s].min_rtt>=max_rtt)) rtt_law->rtt_stats[s].min_rtt=max_rtt; return state; } switch (state) { case RTT_STATE_OK: if (ostate==RTT_STATE_HINVALID) rtt_law->nb_hinvalid--; else if ((ostate & RTT_STATE_MASK)==RTT_STATE_LINVALID) { rtt_law->nb_linvalid--; } else rtt_law->nb_redo--; rtt_law->rtt_stats[s].state=state; break; case RTT_STATE_OK|RTT_STATE_LINVALID1: /* Should only be called if we are already in a the RTT_STATE_LINVALID state */ if (ostate==(RTT_STATE_LINVALID|RTT_STATE_LINVALID1)) { rtt_law->nb_linvalid--; rtt_law->rtt_stats[s].state=RTT_STATE_OK; } else { rtt_law->rtt_stats[s].state&=~RTT_STATE_LINVALID1; } break; case RTT_STATE_OK|RTT_STATE_LINVALID2: /* Should only be called if we are already in a the RTT_STATE_LINVALID state */ if (ostate==(RTT_STATE_LINVALID|RTT_STATE_LINVALID2)) { rtt_law->nb_linvalid--; rtt_law->rtt_stats[s].state=RTT_STATE_OK; } else { rtt_law->rtt_stats[s].state&=~RTT_STATE_LINVALID2; } break; case RTT_STATE_HINVALID: if (ostate==RTT_STATE_REDO) rtt_law->nb_redo--; else if ((ostate & RTT_STATE_MASK)==RTT_STATE_LINVALID) { rtt_law->nb_linvalid--; } rtt_law->nb_hinvalid++; #ifdef _DEBUG /* printf("invalidating %d %9.7f > %9.7f\n",s,rtt_law->rtt_stats[s].min_rtt,max_rtt); */ rtt_law->rtt_stats[s].min_rtt_sav=rtt_law->rtt_stats[s].min_rtt; #endif rtt_law->rtt_stats[s].min_rtt=max_rtt; rtt_law->rtt_stats[s].state=state; break; case RTT_STATE_LINVALID|RTT_STATE_LINVALID1: if (ostate==RTT_STATE_REDO) rtt_law->nb_redo--; if ((ostate & RTT_STATE_MASK)!=RTT_STATE_LINVALID) rtt_law->nb_linvalid++; rtt_law->rtt_stats[s].state=RTT_STATE_LINVALID | (rtt_law->rtt_stats[s].state & ~RTT_STATE_MASK) | RTT_STATE_LINVALID1; break; case RTT_STATE_LINVALID|RTT_STATE_LINVALID2: if (ostate==RTT_STATE_REDO) rtt_law->nb_redo--; if ((ostate & RTT_STATE_MASK)!=RTT_STATE_LINVALID) rtt_law->nb_linvalid++; rtt_law->rtt_stats[s].state=RTT_STATE_LINVALID | (rtt_law->rtt_stats[s].state & ~RTT_STATE_MASK) | RTT_STATE_LINVALID2; break; case RTT_STATE_REDO: if (ostate==RTT_STATE_OK) { rtt_law->nb_redo++; } rtt_law->rtt_stats[s].state=state; break; } return ostate; } int method_init_probe(bp_handle* probe, int method) { /* nothing to do it seems */ return 0; } int method_do_probe(bp_handle* probe_handle, host_stats_t* host, int packet_size, rtt_law_t* rtt_law, int index) { bp_probedata_t probe; int res; /*printf("method_do_probe target=%s port=%d ttl=%d size=%d\n",host_addr2name(&host->address,0),SOCKADDR_IN(&host->address)->sin_port,host->ttl,packet_size);*/ res=do_probe(probe_handle, &host->address, packet_size, host->ttl,&probe); if (probe.contents!=NULL) free(probe.contents); switch (res) { case BP_RES_TTL_EXCEEDED: /* (!!) this is really bad because we should have the right rtt */ printf("(!!) BP_RES_TTL_EXCEEDED\n");fflush(stdout); break; case BP_RES_HIT: /* update the stats about this host */ /* (!!) is it packet_size or probe->size or does it depend on the method ? */ return rtt_law_add(rtt_law,index,2*probe.size,probe.rtt); break; case BP_RES_TIMEOUT: /* this is something to expect */ printf("method_do_probe *time out*\n");fflush(stdout); rtt_law_add(rtt_law,index,-1,0.0); break; case -1: printf("method_do_probe *failed*\n");fflush(stdout); /* (!!) we should display an error message, this is not supposed to happen */ /*(!!)fprintf(stderr,"%s: error: could not send probe of size %d to %s\n", tool_name,packet_size, host->name, host_addr2name(&host->address,0)); / * (!!) is it 0 here ? */ printf("(!!) could not send probe\n");fflush(stdout); break; default: /* (!!) display more details, there may also be more cases to handle */ /*(!!)fprintf(stderr,"%s: error: failed probe of size %d to %s\n", tool_name,packet_size, host->name, host_addr2name(&host->address,0)); / * (!!) is it 0 here ? */ printf("(!!) unknown result %d\n",res);fflush(stdout); break; } return 0; } bing-1.3.5/bing_stats.h100664 1750 1750 27560 7002022416 14375 0ustar fgougetfgouget/* 45678901234567890123456789012345678901234567890123456790123456789012345 */ /* * Unofficial release 1.3.0 * B I N G * */ /* $Id: bing_stats.h,v 1.4 1999/10/16 07:09:58 fgouget Exp $ */ #ifndef _bing_stats_h_ #define _bing_stats_h_ #include "bing_defs.h" #include "bing_probes.h" #include "lin_reg.h" /* * The following 'enumeration' describes the possible states * of the minimum RTT field of rtt_stats_t. *
      *
    • RTT_STATE_OK to RTT_STATE_REDO are exclusive global flags. * RTT_STATE_OK means the RTT is valid and not scheduled for update. *
    • RTT_STATE_HINVALID means the RTT is invalid wrt another RTT. When * in this state the min_rtt field does not indicate the value of * the current minimum RTT but the upper bound for this RTT. *
    • RTT_STATE_REDO means the RTT is valid but scheduled for update. *
    • RTT_STATE_LINVALID indicates that the RTT is invalid with regard * to a link. It is always use together with RTT_STATE_LINVALID1 * and/or RTT_STATE_LINVALID2 which specify the said link, * respectively the link between hosts h-1 and h, and the link * between hosts h and h+1. Note that an RTT can be invalid with * regard to both links and thus RTT_STATE_LINVALID1 and * RTT_STATE_LINVALID2 form a bitmask. */ #define RTT_STATE_OK 0 #define RTT_STATE_HINVALID 1 #define RTT_STATE_LINVALID 2 #define RTT_STATE_REDO 3 #define RTT_STATE_MASK 3 #define RTT_STATE_LINVALID1 4 #define RTT_STATE_LINVALID2 8 /** * This structure contains all the information we have gathered on the RTTs * measured for a given host, method and packet size. */ typedef struct { /** * This is the number of RTTs that we successfully measured, i.e. * this does not count the probes that timed out (see nb_dropped for * that). This is also the number of RTTs stored in the samples * array. */ int nb_samples; /** * This is the number of probes that timed out. Note that nb_samples * plus nb_dropped may be different from the total number of probes sent * because neither counts probes that yielded an invalid result. * (But this is something to check). */ int nb_dropped; /* Number of bits exchanged for each packet size. Note that this * depends on the packet size but also on the probe method because * of the return packet size. Also the size of the exchanged packets is * not the same for the last host when the BP_ECHOREPLY is used because * the last host will always generate an Echo Reply instead of a TTL * Exceeded. */ int nb_bits; /** * This describes the state of the minimum RTT. It can be valid, * inconsistent or marked for update. See the RTT_STATE_XXX enumeration. */ int state; /** * This is the minimum RTT that was measured for this particular host, * method and size. This field must be monotonically decreasing, we must * never put in there a value that would be larger than what was there * before. The RTT is in milliseconds. */ double min_rtt; #ifdef _DEBUG /** * When we determine that the RTT is invalid we replace the value of min_rtt * by the maximum allowable value. But in debug mode we still want to remember * what was the value before so that we can display it from time to time. So we * store it in this field. The RTT is in milliseconds. */ double min_rtt_sav; #endif /** * This is the sum of all the RTTs that have been measured for this host, method * and size. This is used to later compute the mean. */ double sum_rtt; /** * This is the maximum RTT measured for this host, method and size. This * field must be monotonically increasing. But it is actually never used * except (potentially) for display. The RTT is in milliseconds. */ double max_rtt; /* All the RTT values for this {host,method,packet size} */ /** * This is the size of the samples array. This is usually higher than * nb_samples to minimize the number of reallocations. */ int samples_size; /** * This array stores all the RTTs that have been measured. */ double* samples; } rtt_stats_t; /** * This structure contains all the data about a given host and method. It * aggregates some statistics gathered for each individual packaet sizes like * the number of dropped packets and also describes how the RTT evolves with * the packet size. */ typedef struct { /** * This array contains the data that was gathered for each packet size * for this particular host, method. */ rtt_stats_t* rtt_stats; /** * This is the number of RTT samples that have been measured across the packet * sizes. */ int nb_samples; /** * This is the number of RTT probes that have timed out across the packet * sizes. */ int nb_dropped; /** * This is the number of RTT samples that are currently in an 'invalid' state * across all packet sizes. */ int nb_hinvalid; /** * This is the number of RTT samples that are currently in an 'invalid' state * across all packet sizes. */ int nb_linvalid; /** * This is the number of RTT samples that are currently in the 'redo' state * across all packet sizes. */ int nb_redo; /** * One of our main goal is to analyze how the RTT evolves when the packet * size changes. Well, we expect it to be linear and this is the result of * the linear regression. Note that this linear regression does not take * into account any RTT that is in one of the 'invalid' states. */ linreg_t host_reg; /** * This structure describes the characteristics of the network link, either * uplink or uplink and downlink composited together, from the previous host * to this host. This field is not significant for the first host in the list. * These characteristics are computed by doing a linear regression on the * RTT difference between this host and the previous host for each given packet * size. Any RTT which is in the RTT_STATE_HINVALID or the wrong * RTT_STATE_LINVALID is ignored for the purpose of this computation. */ linreg_t link_reg; } rtt_law_t; /** * This structure contains the data specific to a host. */ typedef struct { /** * This is the name of the host. This is either the name the user gave on the * command line for a 'key host', the name we got back from the DNS or simply * the IP address. */ char* name; /** * This is the host's IP address. The port field is not significant. */ struct sockaddr address; /** * This is the ttl of the host or -1 if that information is not known. */ char ttl; /** * For each probe method, this array contains an entry describing how the * RTT behaves as the packet size changes. Each structure in turn contains * information for each packet size and then each probe. */ rtt_law_t* rtt_laws; } host_stats_t; /** * This structure regroups all the bing statistics information plus some * other state information that we need to pass around. */ typedef struct { /** * This is the handle we use to send and receive probes. */ bp_handle probe_handle; /** * Stores the number of probe methods that are in use. This is either 1 or 2. */ int nb_methods; /** * This array stores the probe methods identifiers. */ int* methods; /** * This is the number of different packet sizes to be sent for each host * and method. */ int nb_sizes; /** * This array stores the packet payload sizes in bytes. */ int* packet_sizes; /** * This is the number of hosts to probe. There must be at least two hosts. */ int nb_hosts; /** * This array stores the information concerning each host and also the * link characteristics about the link between each listed host. */ host_stats_t* hosts; } bing_stats_t; /* * More functions for bing statistics */ /* -------------------------------------------------------------------------- (!!) update description bs_probe_init initialises the structure holding the information about the RTT samples ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- probes | X | X | Data about the probes for a given size size | X | X | The total number of bytes exchanged min_rtt | | X | The minimum Rtt. This is duplicated from the | | | data in the probes parameter but is needed for | | | the linear regression. ------------+----+-----+-------------------------------------------------- RETURN | | X | No return value ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( rtt_stats_init, ( rtt_stats_t *rtt_stats )); /* (!!) update description -------------------------------------------------------------------------- bs_add_sample takes into account a new sample. It checks that it is the right size, and computes the new minimum RTT. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- probes | X | X | The number of samples after the sample addition size | X | X | The x value of the sample to add min_rtt | | X | The y value of the sample to add ------------+----+-----+-------------------------------------------------- RETURN | | X | No return value ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( rtt_stats_add, ( int size, int rtt, rtt_stats_t *rtt_stats, int *size1, double *min_rtt )); extern BINGAPI int BINGPROTO( rtt_law_invalidate, ( rtt_law_t *rtt_law, int index, double max_valid )); extern BINGAPI int BINGPROTO( rtt_law_remove_worst_point, ( rtt_law_t *rtt_law, int nb_sizes )); /* -------------------------------------------------------------------------- (!!) update description bs_probe_init initialises the structure holding the information about the RTT samples ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- probes | X | X | Data about the probes for a given size size | X | X | The total number of bytes exchanged min_rtt | | X | The minimum Rtt. This is duplicated from the | | | data in the probes parameter but is needed for | | | the linear regression. ------------+----+-----+-------------------------------------------------- RETURN | | X | No return value ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( rtt_law_init, ( rtt_law_t *rtt_law, int nb_sizes )); /* (!!) */ extern BINGAPI int BINGPROTO( method_init_probe, ( bp_handle* probe_handle, int method )); extern BINGAPI int BINGPROTO( rtt_law_set_rtt_state, ( rtt_law_t *rtt_law, int s, int state, double max_rtt )); /* (!!) */ extern BINGAPI int BINGPROTO( method_do_probe, ( bp_handle* probe_handle, host_stats_t* host, int packet_size, rtt_law_t* rtt_law, int index )); #endif /* end of file */ bing-1.3.5/icmp_dummy.c100664 1750 1750 5222 7000272277 14357 0ustar fgougetfgouget/* $Id: icmp_dummy.c,v 1.2 1999/10/11 05:25:19 fgouget Exp $ */ /* was in */ int do_probe(handle, target, size, ttl, probe) { #ifdef FAKE_NET if ((SOCKADDR_IN(target)->sin_addr.S_un.S_un_b.s_b1==192) && (SOCKADDR_IN(target)->sin_addr.S_un.S_un_b.s_b2==168)) { struct sockaddr_in* itarget=SOCKADDR_IN(target); int retcode; /* Fake the probe results according to the target address */ if (ttl==0) { /* Fake information concerning the local host */ probe->rtt=10*size/100; SOCKADDR_IN(&probe->src_addr)->sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); probe->type=ICMP_TIMXCEED; probe->subtype=ICMP_TIMXCEED_INTRANS; retcode=BP_RES_TTL_EXCEEDED; } else if (ttl>=itarget->sin_addr.S_un.S_un_b.s_b4) { /* Fake information concerning the target host */ probe->rtt=((double)itarget->sin_addr.S_un.S_un_b.s_b3)*itarget->sin_addr.S_un.S_un_b.s_b4*size/100; SOCKADDR_IN(&probe->src_addr)->sin_addr.S_un.S_addr=itarget->sin_addr.S_un.S_addr; probe->type=ICMP_ECHOREPLY; probe->subtype=0; retcode=BP_RES_HIT; } else { /* Do as if the ttl expired in transit */ probe->rtt=((double)itarget->sin_addr.S_un.S_un_b.s_b3)*ttl*size/100; SOCKADDR_IN(&probe->src_addr)->sin_addr.S_un.S_addr=itarget->sin_addr.S_un.S_addr; SOCKADDR_IN(&probe->src_addr)->sin_addr.S_un.S_un_b.s_b4=ttl; probe->type=ICMP_TIMXCEED; probe->subtype=ICMP_TIMXCEED_INTRANS; retcode=BP_RES_TTL_EXCEEDED; } probe->src_addr.sa_family=AF_INET; probe->size=0; probe->contents=NULL; return retcode; } else if ((SOCKADDR_IN(target)->sin_addr.S_un.S_un_b.s_b1==208) && (SOCKADDR_IN(target)->sin_addr.S_un.S_un_b.s_b2==199) && (SOCKADDR_IN(target)->sin_addr.S_un.S_un_b.s_b3==87) && (SOCKADDR_IN(target)->sin_addr.S_un.S_un_b.s_b4==55)) { /* Fake information concerning the local host */ probe->rtt=size/1000; SOCKADDR_IN(&probe->src_addr)->sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); probe->type=ICMP_ECHOREPLY; probe->subtype=0; return BP_RES_HIT; } else { probe->rtt=50; probe->src_addr.sa_family=AF_INET; SOCKADDR_IN(&probe->src_addr)->sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); probe->type=ICMP_UNREACH; probe->subtype=ICMP_UNREACH_NET_UNKNOWN; probe->size=0; probe->contents=NULL; return BP_RES_UNKNOWN; } #endif /* FAKE_NET */ } bing-1.3.5/lin_reg.c100664 1750 1750 10160 7002022416 13636 0ustar fgougetfgouget/* * Unofficial release 1.3.0 * B I N G * */ /* $Id: lin_reg.c,v 1.4 1999/10/16 07:07:58 fgouget Exp $ */ #include #include #include "lin_reg.h" /* * The linear regression stuff. * The basic formula used to do the linear regression are given below but * for more details you should see a maths book. * * We have a set of n samples (xi,yi). Then if we write * * y = a * x + b * * the a and b that best approximate the samples are given by: * * a = Covariance ( xi , yi ) / Variance ( xi ) * * b = Covariance ( xi , yi ) / Variance (xi) * Mean ( xi ) - Mean ( yi ) * * Note that in bing we only care about a. * * To compute a we maintain the variables below: * * sum_x = Sum ( xi ) * sum_x2 = Sum ( xi * xi ) * sum_y = Sum ( yi ) * sum_xy = Sum ( xi * yi ) * * And then the covariance and variance can be computed as: * * Covariance ( xi , yi ) = ( sum_xy - sum_x * sum_y / n ) / ( n - 1 ) * * Variance ( xi ) = ( sum_x2 - sum_x * sum_x / n ) / ( n - 1 ) * * Thus: * * n * sum_xy - sum_x * sum_y * a = ---------------------------- * n * sum_x2 - sum_x * sum_x * * sum_x2 * sum_y - sum_x * sum_xy * b = --------------------------------- * n * sum_x2 - sum_x * sum_x * * * We also compute the correlation value so that we know whether the stats * indeed look like a line or not. The correlation is computed from the * following formula: * * Corr (xi , yi ) = Covariance ( xi , yi ) / Sqrt ( Variance ( xi ) / Variance ( yi ) ) * * i.e. * * n * sum_xy - sum_x * sum_y * Corr (xi , yi ) = ------------------------------------------------------------------------- * Sqrt( ( n * sum_x2 - sum_x * sum_x ) * ( n * sum_y2 - sum_y * sum_y ) ) * */ void linreg_update(linreg_t* linreg) { if (linreg->nb_samples>1) { /* * This function computes the end result from the computed * intermediate statistics. */ linreg->a=(linreg->sum_xy-linreg->sum_x*linreg->sum_y/linreg->nb_samples)/ (linreg->sum_x2-linreg->sum_x*linreg->sum_x/linreg->nb_samples); linreg->b=(linreg->sum_x2*linreg->sum_y-linreg->sum_x*linreg->sum_xy)/ (linreg->nb_samples*linreg->sum_x2-linreg->sum_x*linreg->sum_x); linreg->corr=(linreg->sum_xy-linreg->sum_x*linreg->sum_y/linreg->nb_samples)/ sqrt((linreg->sum_x2-linreg->sum_x*linreg->sum_x/linreg->nb_samples) * (linreg->sum_y2-linreg->sum_y*linreg->sum_y/linreg->nb_samples) ); } else { linreg->a=0; linreg->b=0; linreg->corr=0; } } int linreg_init(linreg_t *linreg) { linreg->nb_samples=0; linreg->sum_x=0.0; linreg->sum_y=0.0; linreg->sum_x2=0.0; linreg->sum_y2=0.0; linreg->sum_xy=0.0; linreg->a=0.0; linreg->b=0.0; linreg->corr=0.0; return 0; } int linreg_add_all(linreg_t *linreg,int nb_samples, int* x, double* y, int update) { int i; /* Initialise the results data structure */ for (i=0;isum_x+=x[i]; linreg->sum_y+=y[i]; linreg->sum_x2+=x[i]*x[i]; linreg->sum_y2+=y[i]*y[i]; linreg->sum_xy+=x[i]*y[i]; linreg->nb_samples++; } /* Update the regression results */ if (update!=0) linreg_update(linreg); return 0; } int linreg_del_sample(linreg_t *linreg, int x, double y, int update) { linreg->nb_samples--; linreg->sum_x-=x; linreg->sum_y-=y; linreg->sum_x2-=x*x; linreg->sum_y2-=y*y; linreg->sum_xy-=x*y; /* Update the regression results */ if (update!=0) linreg_update(linreg); return 0; } int linreg_add_sample(linreg_t *linreg, int x, double y, int update) { linreg->nb_samples++; linreg->sum_x+=x; linreg->sum_y+=y; linreg->sum_x2+=x*x; linreg->sum_y2+=y*y; linreg->sum_xy+=x*y; /* Update the regression results */ if (update!=0) linreg_update(linreg); return 0; } bing-1.3.5/lin_reg.h100664 1750 1750 10154 7000272277 13660 0ustar fgougetfgouget/* * This module provides the linear regression functions used by bing. */ /* $Id: lin_reg.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef _lin_reg_h_ #define _lin_reg_h_ #include "bing_defs.h" typedef struct { /* * The resulting equation parameters: y = a * x + b * We're only interested in a. */ double a; double b; double corr; /* The parameters used to compute a, b and the correlation */ int nb_samples; double sum_x; double sum_y; double sum_x2; double sum_y2; double sum_xy; } linreg_t; /* (!!) */ extern BINGAPI int BINGPROTO( linreg_init, ( linreg_t *linreg )); /* (!!) update -------------------------------------------------------------------------- linreg_compute computes performs the lirnear regression from scratch and thus requires that you provide all the statistic samples. The result is a data structure containing all that is necessary to later update the linear regression results if samples are added or removed. Ignores any sample for which y is DBL_MAX. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- nb_samples | X | | The number of samples x | X | | The x sample values y | X | | The y sample values linreg | | X | The linear regression results ------------+----+-----+-------------------------------------------------- RETURN | | X | 0 if successful, -1 otherwise ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( linreg_add_all_samples, ( linreg_t *linreg, int nb_samples, int* x, double* y, int update )); /* (!!) update -------------------------------------------------------------------------- linreg_del_sample updates the linear regression data when a sample is removed. Note that repeteadly calling this function will degrade the results precision. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- nb_samples | X | | The number of samples after the sample deletion | | | If nul then the linreg values are not updated x | X | | The x value of the sample to delete y | X | | The y value of the sample to delete linreg | X | X | The linear regression results ------------+----+-----+-------------------------------------------------- RETURN | | X | No return value ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( linreg_del_sample, ( linreg_t *linreg, int x, double y, int update )); /* (!!) update -------------------------------------------------------------------------- linreg_add_sample updates the linear regression data when a sample is added. Note that repeteadly calling this function will degrade the results precision. ------------+----+-----+-------------------------------------------------- Parameter | IN | OUT | Role ------------+----+-----+-------------------------------------------------- nb_samples | X | | The number of samples after the sample addition | | | If nul then the linreg values are not updated x | X | | The x value of the sample to add y | X | | The y value of the sample to add linreg | X | X | The linear regression results ------------+----+-----+-------------------------------------------------- RETURN | | X | No return value ------------+----+-----+-------------------------------------------------- */ extern BINGAPI int BINGPROTO( linreg_add_sample, ( linreg_t *linreg, int x, double y, int update )); extern BINGAPI void BINGPROTO( linreg_update, ( linreg_t *linreg )); #endif /* end of file */ bing-1.3.5/makefile.dsp100664 1750 1750 4451 7005246510 14334 0ustar fgougetfgouget# Microsoft Developer Studio Project File - Name="makefile" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 5.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=makefile - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "makefile.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "makefile.mak" CFG="makefile - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "makefile - Win32 Release" (based on "Win32 (x86) External Target") !MESSAGE "makefile - Win32 Debug" (based on "Win32 (x86) External Target") !MESSAGE # Begin Project # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "makefile - Win32 Release" # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Cmd_Line "NMAKE /f makefile.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "makefile.exe" # PROP BASE Bsc_Name "makefile.bsc" # PROP BASE Target_Dir "" # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Cmd_Line "NMAKE /f makefile.mak" # PROP Rebuild_Opt "/a" # PROP Target_File "makefile.exe" # PROP Bsc_Name "makefile.bsc" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "makefile - Win32 Debug" # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Cmd_Line "NMAKE /f makefile.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "makefile.exe" # PROP BASE Bsc_Name "makefile.bsc" # PROP BASE Target_Dir "" # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Cmd_Line "NMAKE /f makefile.nt DEBUG=1 DLL=1" # PROP Rebuild_Opt "/a" # PROP Target_File "bin\bing.exe" # PROP Bsc_Name "makefile.bsc" # PROP Target_Dir "" !ENDIF # Begin Target # Name "makefile - Win32 Release" # Name "makefile - Win32 Debug" !IF "$(CFG)" == "makefile - Win32 Release" !ELSEIF "$(CFG)" == "makefile - Win32 Debug" !ENDIF # Begin Source File SOURCE=.\makefile.nt # End Source File # End Target # End Project bing-1.3.5/makefile.dsw100664 1750 1750 1033 6775576314 14361 0ustar fgougetfgougetMicrosoft Developer Studio Workspace File, Format Version 5.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "makefile"=.\makefile.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### bing-1.3.5/makefile.nt100664 1750 1750 4732 7005246510 14171 0ustar fgougetfgouget##### # Paths ##### # $Id: makefile.nt,v 1.5 1999/10/19 06:11:14 fgouget Exp $ # This path should point to where the icmp libraries are. ICMP_INCLUDE=../icmp_dev-0.1.1 ICMP_LIB=../icmp_dev-0.1.1/i386 # This is where you want the compiler to put the binaries # (including bing.exe). BIN=bin ##### # Macro definitions ##### # General options APPVER = 4.0 TARGETOS = BOTH TARGETLANG = LANG_FRENCH CPU=i386 !ifndef DEBUG NODEBUG=1 !endif !include # compilation !ifdef BROWSER cbrowser=-FR$(*D)/ !endif !ifdef DEBUG cdebug=-Od -Zi -Fd$(*D)/ -D_DEBUG -D_CRTDBG_MAP_ALLOC !endif !ifdef DLL bing_cvars=$(cvarsdll) !else bing_cvars=$(cvars) !endif bing_cvars=-nologo $(bing_cvars) $(cdebug) $(cbrowser) -I$(ICMP_INCLUDE) -I. -Iwin32 -Iinclude -c -Fo$(*D)/ # linking !ifdef DEBUG ldebug=-debug !endif bing_lflags=-nologo -nodefaultlib $(ldebug) -out:$@ !ifdef DLL bing_libs=$(conlibsdll) !else bing_libs=$(conlibs) !endif bing_libs=$(bing_libs) wsock32.lib $(ICMP_LIB)/icmp.lib ###### # What to do ###### L_OBJS= \ $(BIN)/bing.obj \ $(BIN)/bing_misc.obj \ $(BIN)/bing_probes.obj \ $(BIN)/bing_stats.obj \ $(BIN)/lin_reg.obj \ $(BIN)/icmp_win32.obj \ $(BIN)/getopt.obj \ L_EXE= \ $(BIN)/bing.exe \ L_BSC= \ !ifdef BROWSER $(BIN)/bing.bsc \ !endif all: bin_dir $(L_EXE) $(L_BSC) clean: if exist $(BIN)\*.obj del $(BIN)\*.obj if exist $(BIN)\*.exe del $(BIN)\*.exe if exist $(BIN)\*.ilk del $(BIN)\*.ilk if exist $(BIN)\*.pdb del $(BIN)\*.pdb if exist $(BIN)\*.sbr del $(BIN)\*.sbr if exist $(BIN)\*.bsc del $(BIN)\*.bsc if exist $(BIN)\nul rmdir $(BIN) bin_dir: -if not exist $(BIN)\nul mkdir $(BIN) ###### # Commands ###### # compilation $(L_OBJS): $(CC) $(bing_cvars) -o $*.obj $** # link $(L_EXE): $(link) $(bing_lflags) msvcrtd.lib $(bing_libs) $** # browser !ifdef BROWSER $(L_BSC): bscmake -nologo -o $@ $** !endif ##### # Dependencies ##### $(BIN)/bing.obj: bing.c $(BIN)/bing_misc.obj: bing_misc.c $(BIN)/bing_probes.obj: bing_probes.c $(BIN)/bing_stats.obj: bing_stats.c $(BIN)/lin_reg.obj: lin_reg.c $(BIN)/icmp_win32.obj: win32/icmp_win32.c $(BIN)/getopt.obj: win32/getopt.c $(BIN)/bing.exe: \ $(BIN)/bing.obj \ $(BIN)/bing_misc.obj \ $(BIN)/bing_probes.obj \ $(BIN)/bing_stats.obj \ $(BIN)/lin_reg.obj \ $(BIN)/icmp_win32.obj \ $(BIN)/getopt.obj \ !ifdef BROWSER $(BIN)/bing.bsc: \ $(BIN)/bing.sbr \ $(BIN)/bing_misc.sbr \ $(BIN)/bing_probes.sbr \ $(BIN)/bing_stats.sbr \ $(BIN)/lin_reg.sbr \ $(BIN)/icmp_win32.sbr \ $(BIN)/getopt.sbr \ !endif bing-1.3.5/mod_icmp.h100664 1750 1750 5665 7000272277 14023 0ustar fgougetfgouget/* * This file provides a system independant interface to send and * receive ICMP messages. */ /* $Id: mod_icmp.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef _mod_icmp_h_ #define _mod_icmp_h_ #if defined(__STDC__) || defined(__cplusplus) #define PROTO(a,b) a b #else #define PROTO(a,b) a() #endif #ifdef __cplusplus #define API "C" #else #define API #endif typedef void* icmp_handle; /* initialize the ICMP module, return a pointer to it. */ extern icmp_handle PROTO( icmp_open, ( void )); /* set a socket option. Returns >= 0 if successful, -1 otherwise */ extern int PROTO( icmp_set_option, ( icmp_handle handle, /* module handle */ int level, int optname, /* option to be set */ void *optval, /* option value */ int optlen /* length of option value */ )); /* set the timeout for receives */ extern void PROTO( icmp_set_timeout, ( icmp_handle handle, unsigned long timeout /* timeout in microseconds */ )); /* get the ID used in packets */ extern unsigned short PROTO( icmp_get_id, ( icmp_handle handle )); /** * Sends an ICMP message. * (!!) this will have to be extended to support any kind of message (e.g. UDP) * * @param handle the icmp handle * @param msg points to a buffer containing the message * (!!) what does this contain exactly? the ip options, the icmp header, just the data * @param msg_size the message size * @param to_addr the address of the host to which the message is to be sent * @param to_addr_size the size of the destination host address * @return >=0 if successful, -1 otherwise */ extern int PROTO( icmp_send, ( icmp_handle handle, void *msg, int msg_size, struct sockaddr *to_addr, int to_addr_size )); /** * Waits for an ICMP message. * (!!) in fact this should be any message since we might send UDP messages too * * @param handle the icmp handle * @param buffer must point to a buffer in which the message will be stored. If the * buffer is too small the function will fail * (!!) what is stored ? just the datsa, the icmp header, the ip header too ? * @param buffer_size the size of the allocated buffer. This value is modified to * store the actual size of the message * @param from_addr must point to a buffer in which to store the address of the * host this message was received from * @param from_addr_size the size of the from_addr buffer. On return this contains the * actual size of the address stored in the buffer. * @return >0 if successful, 0 if the function timed out and -1 if it failed * (!!) it said "-1: interrupted, should be called again" */ extern int PROTO( icmp_recv, ( icmp_handle handle, char *buffer, int buffer_size, struct sockaddr *from_addr, int *from_addr_size, double *elapsed )); /** * Closes the ICMP handle. * * @return >=0 if successful, -1 otherzise */ extern int PROTO( icmp_close, ( icmp_handle handle )); #endif /* End of File */ bing-1.3.5/todo.txt100664 1750 1750 1504 7005246653 13561 0ustar fgougetfgougetHigh priority ------------- * I need a ChangeLog * The NT makefile does not allow us to link with the debug C library (rather it has to be manually modified) * Write a man page describing the options, and the output of bing. Lower priority -------------- * Berkeley's version of getopt.c does not have a corresponding header file so win32 relies on the GNU version instead. This means we have a licensing problem (GPL vs. BSD). Some other solution must be found. * Recording the measured RTTs should be optional. Once disabled the memory consumption of bing should remain constant. This is currently disbled anyway. * Investigate the use of SO_PMTU on HP to discover the path mtu. But I don't have an HP here... * Compiling on different architectures is kind of a hack currently. Using autoconf might bring some order. bing-1.3.5/unix/ 42775 1750 1750 0 7002022416 12725 5ustar fgougetfgougetbing-1.3.5/unix/icmp_ux.c100664 1750 1750 13142 7002022416 14651 0ustar fgougetfgouget/* $Id: icmp_ux.c,v 1.3 1999/10/16 07:07:58 fgouget Exp $ */ /* Usual includes/declarations */ #include #include #include #include #ifndef WIN32 #include #endif /* More specific includes/declarations */ #include /* Network includes/definitions */ #include #include #include #include #ifdef linux /* Needed for IP structures */ #include #endif /* These come either from the compatibility library or from the * standard libraries. */ #include #include #include "mod_icmp.h" typedef struct { int s; /* Raw socket fd */ short id; /* 16 bit id to be put in the echo request */ struct timeval last_send; /* date of last send */ struct timeval timeout; /* timeout for replies */ fd_set fds; /* Precomputed fd_set for select() */ } mod_icmp_i; #define to_mod_icmp(h) ((mod_icmp_i*)(h)) /* * tvsub -- * Subtract 2 timeval structs: out = out - in. * Out is assumed to be >= in. */ void tvsub(struct timeval *out, struct timeval *in) { if ((out->tv_usec -= in->tv_usec) < 0) { --out->tv_sec; out->tv_usec += 1000000; } out->tv_sec -= in->tv_sec; } /* * in_cksum -- * Checksum routine for Internet Protocol family headers (C Version) */ static int in_cksum(u_short *addr, int len) { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), we add * sequential 16 bit words to it, and at the end, fold back all the * carry bits from the top 16 bits into the lower 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } /* add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return(answer); } icmp_handle icmp_open() { struct protoent *proto; int s; mod_icmp_i *new; proto = getprotobyname("icmp"); if (proto==NULL) { fprintf(stderr, "unknown protocol icmp.\n"); return NULL; } /* * Open a raw socket */ if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { perror("socket"); return NULL; } /* * Everything ok, alloc our private state */ new = (mod_icmp_i *)malloc(sizeof(mod_icmp_i)); if (new == NULL) { close(s); fprintf(stderr, "out of memory!\n"); return NULL; } new->s = s; new->id = getpid() & 0xFFFF; new->timeout.tv_sec=1; new->timeout.tv_usec=0; FD_ZERO(&new->fds); FD_SET(new->s, &new->fds); return (icmp_handle)new; } int icmp_set_option(icmp_handle handle,int level,int optname,void* optval,int optlen) { return setsockopt(to_mod_icmp(handle)->s, level, optname, optval, optlen); } void icmp_set_timeout(icmp_handle handle,unsigned long timeout) { mod_icmp_i *h = to_mod_icmp(handle); h->timeout.tv_sec = timeout / 1000000; h->timeout.tv_usec = timeout % 1000000; } unsigned short icmp_get_id(icmp_handle handle) { mod_icmp_i *h = to_mod_icmp(handle); return h->id; } int icmp_send(icmp_handle handle,void* msg,int msg_size,struct sockaddr *to_addr,int to_addr_size) { mod_icmp_i *h = to_mod_icmp(handle); struct icmp *icmp_header; /* Fill-in the last bits in the icmp message */ icmp_header = (struct icmp *)msg; icmp_header->icmp_id = h->id; /* Compute the checksum */ icmp_header->icmp_cksum = 0; icmp_header->icmp_cksum = in_cksum((u_short *)msg, msg_size); /* printf("s=%d icmp type=%d code=%d id=%d seq=%d checksum=%d\n", h->s, icmp_header->icmp_type, icmp_header->icmp_code, icmp_header->icmp_id, icmp_header->icmp_seq, icmp_header->icmp_cksum);*/ /* Get the send date as late as possible */ gettimeofday(&h->last_send, (struct timezone *)NULL); /* Send packet and return to caller */ return sendto(h->s, (char *)msg, msg_size, 0, (struct sockaddr *)to_addr, to_addr_size); } int icmp_recv(icmp_handle handle,char* buf,int buflen,struct sockaddr *from_addr,int *from_addr_size,double *elapsed) { mod_icmp_i *h = to_mod_icmp(handle); int cc; int rsel; struct timeval tv, selw; /* * Note that we can spare rebuilding the FD mask each time, * since it will only be altered if select() times out, in which * case we exit anyway... */ FD_SET(h->s, &h->fds); /* Set timeout */ selw = h->timeout; /* Wait */ rsel = select(h->s+1, &h->fds, (fd_set *)0, (fd_set *)0, &selw); /* Get date as soon as possible */ gettimeofday(&tv, (struct timezone *)NULL); /* Compute the elapsed time since last icmp_send */ tvsub(&tv, &h->last_send); *elapsed = ((double)tv.tv_sec * 1e3) + ((double)tv.tv_usec / 1e3); if (rsel > 0) { /* Got a reply packet, read it and return it */ cc = recvfrom(h->s, buf, buflen, 0, from_addr, from_addr_size); /* sendto wants sin_port=0 but recvfrom does not even initialize it ! */ ((struct sockaddr_in*)from_addr)->sin_port=0; return cc; } else if (rsel == 0) { /* Time out */ return 0; } else if (errno == EINTR) { return -1; } else { perror("select"); exit(1); } } int icmp_close(icmp_handle handle) { mod_icmp_i *h = to_mod_icmp(handle); close(h->s); free(h); return 0; } bing-1.3.5/unix/bing.8100664 1750 1750 15627 6605754625 14111 0ustar fgougetfgouget.\" Copyright (c) 1985, 1991 The Regents of the University of California. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" bing.8, unofficial release v1.1.2 .\" .Dd April 3, 1995 .Dt BING 8 .Os .Sh NAME .Nm bing .Nd compute point to point throughput using two sizes of .Tn ICMP ECHO_REQUEST packets to pairs of remote hosts. .Sh SYNOPSIS .Nm bing .Op Fl dDnrRPvVwz .Op Fl c Ar count .Op Fl e Ar samples .Op Fl f Ar samplefile .Op Fl i Ar wait .Op Fl p Ar pattern .Op Fl s Ar small packetsize .Op Fl S Ar big packetsize .Op Fl u Ar size increment .Ar host1 .Ar host2 .Ar [...] .Sh DESCRIPTION .Nm Bing determines bandwidth on a point-to-point link by sending .Tn ICMP ECHO_REQUEST packets and measuring their roundtrip times for different packet sizes on each end of the link. .Pp .Ar host1 is supposed to be the nearest end of the link, while .Ar host2 is the other end. .Pp The options are as follows: .Bl -tag -width Ds .It Fl c Ar count Stop after .Ar count resets of the stats. Useful only in conjunction with the .Fl e option. Defaults to 1. .It Fl d Set the .Dv SO_DEBUG option on the socket being used. .It Fl D Display the measured throughput at every received packet. By default, it is displayed only when the computed value changes, which itself changes only when the minimum roundtrip time for one of the packet sizes changes. .It Fl e Ar samples Reset stats after sending .Ar samples .Tn ECHO_REQUEST packets. .It Fl f Ar samplefile Saves the bandwidth measurements to the file .Ar samplefile . .It Fl i Ar wait Wait .Ar wait seconds .Em for each .Tn ECHO_REPLY packet. The default is to wait for four seconds. .It Fl n Numeric output only. No attempt will be made to lookup symbolic names for host addresses. .It Fl P Be pedantic regarding round-trip times. .Pp Normally, .Nm bing assumes that the roundtrip time for a small packet should always be smaller than the roundtrip time for a big packet to the same host, that for a given size the roundtrip time for .Nm host1 should always be smaller than the roundtrip time for .Nm host2, and that the increase in the roundtrip time between .Nm host1 and .Nm host2 should always be bigger for big packets than for small packets. .Pp .Nm Bing takes advantage of this to better determine the minimum roundtrip times. .Pp Option .Fl P disables this behaviour, in the unlikely event it could be of any use someday. Even IP/X25 links are not weird enough to require this, though. .It Fl p Ar pattern You may specify up to 16 ``pad'' bytes to fill out the packet you send. This is useful for diagnosing data-dependent problems in a network. For example, .Dq Li \-p ff will cause the sent packet to be filled with all ones. .It Fl R Record route. Includes the .Tn RECORD_ROUTE option in the .Tn ECHO_REQUEST packet and displays the route buffer on returned packets. Note that the IP header is only large enough for nine such routes. Many hosts ignore or discard this option. .It Fl r Bypass the normal routing tables and send directly to a host on an attached network. If the host is not on a directly-attached network, an error is returned. This option can be used to ping a local host through an interface that has no route through it (e.g., after the interface was dropped by .Xr routed 8 ). .It Fl s Ar packetsize Specifies the number of data bytes to be sent in the small packets. The default and minimum value is 8. .It Fl S Ar packetsize Specifies the number of data bytes to be sent in the big packets. The default is 108. The size should be chosen so that big packet roundtrip times are long enough to be accurately measured (depending on clock resolution and number of hops). .It Fl u Ar size increment Specifies that .Nm bing should start sending packets of the size of .Ar small packetsize and then increase the size by .Ar size increment until it reaches .Ar big packetsize . .It Fl v Verbose output. .Tn ICMP packets other than .Tn ECHO_RESPONSE that are received are listed. .It Fl V Very verbose output. The roundtrip time of each received echo is displayed. .It Fl w Display possible warnings about roundtrip times all the time. By default, warnings are printed only at the end. .It Fl z Fill packets with uncompressible (pseudo-random) data. .El .Pp Round-trip times and packet loss statistics are computed. If duplicate packets are received, they are not included in the packet loss calculation, although the round trip time of these packets is used in calculating the minimum/average/maximum round-trip time numbers. When the specified number of loops have been made or if the program is terminated with a .Dv SIGINT , a brief summary is displayed. .Pp This program is intended for use in network testing, measurement and management. Because of the load it can impose on the network, it is unwise to use .Nm bing during normal operations or from automated scripts. .Sh BUGS Many Hosts and Gateways ignore the .Tn RECORD_ROUTE option. .Pp The maximum IP header length is too small for options like .Tn RECORD_ROUTE to be completely useful. There's not much that that can be done about this, however. .Pp Some of the final stats (average throughputs) almost never give a even marginally correct result. .Sh SEE ALSO .Xr netstat 1 , .Xr ifconfig 8 , .Xr ping 8 , .Xr routed 8 , .Xr traceroute 8 .Sh AUTHOR Pierre Beyssac bing-1.3.5/win32/ 42775 1750 1750 0 7005246510 12712 5ustar fgougetfgougetbing-1.3.5/win32/bing.man100664 1750 1750 14725 6605753607 14471 0ustar fgougetfgouget BING(8) UNIX System Manager's Manual BING(8) NNAAMMEE bbiinngg - compute point to point throughput using two sizes of ICMP ECHO_REQUEST packets to pairs of remote hosts. SSYYNNOOPPSSIISS bbiinngg [--ddDDnnrrRRPPvvVVwwzz] [--cc _c_o_u_n_t] [--ee _s_a_m_p_l_e_s] [--ff _s_a_m_p_l_e_f_i_l_e] [--ii _w_a_i_t] [--pp _p_a_t_t_e_r_n] [--ss _s_m_a_l_l _p_a_c_k_e_t_s_i_z_e] [--SS _b_i_g _p_a_c_k_e_t_s_i_z_e] [--uu _s_i_z_e _i_n_c_r_e_m_e_n_t] _h_o_s_t_1 _h_o_s_t_2 _[_._._._] DDEESSCCRRIIPPTTIIOONN BBiinngg determines bandwidth on a point-to-point link by sending ICMP ECHO_REQUEST packets and measuring their roundtrip times for different packet sizes on each end of the link. _h_o_s_t_1 is supposed to be the nearest end of the link, while _h_o_s_t_2 is the other end. The options are as follows: --cc _c_o_u_n_t Stop after _c_o_u_n_t resets of the stats. Useful only in conjunction with the --ee option. Defaults to 1. --dd Set the SO_DEBUG option on the socket being used. --DD Display the measured throughput at every received packet. By de- fault, it is displayed only when the computed value changes, which itself changes only when the minimum roundtrip time for one of the packet sizes changes. --ee _s_a_m_p_l_e_s Reset stats after sending _s_a_m_p_l_e_s ECHO_REQUEST packets. --ff _s_a_m_p_l_e_f_i_l_e Saves the bandwidth measurements to the file _s_a_m_p_l_e_f_i_l_e. --ii _w_a_i_t Wait _w_a_i_t seconds _f_o_r _e_a_c_h ECHO_REPLY packet. The default is to wait for four seconds. --nn Numeric output only. No attempt will be made to lookup symbolic names for host addresses. --PP Be pedantic regarding round-trip times. Normally, bbiinngg assumes that the roundtrip time for a small packet should always be smaller than the roundtrip time for a big packet to the same host, that for a given size the roundtrip time for hhoosstt11 should always be smaller than the roundtrip time for hhoosstt22,, and that the increase in the roundtrip time between hhoosstt11 and hhoosstt22 should always be bigger for big packets than for small packets. BBiinngg takes advantage of this to better determine the minimum roundtrip times. Option --PP disables this behaviour, in the unlikely event it could be of any use someday. Even IP/X25 links are not weird enough to require this, though. --pp _p_a_t_t_e_r_n You may specify up to 16 ``pad'' bytes to fill out the packet you send. This is useful for diagnosing data-dependent problems in a network. For example, ``-p ff'' will cause the sent packet to be filled with all ones. --RR Record route. Includes the RECORD_ROUTE option in the ECHO_REQUEST packet and displays the route buffer on returned packets. Note that the IP header is only large enough for nine such routes. Many hosts ignore or discard this option. --rr Bypass the normal routing tables and send directly to a host on an attached network. If the host is not on a directly-attached network, an error is returned. This option can be used to ping a local host through an interface that has no route through it (e.g., after the interface was dropped by routed(8)). --ss _p_a_c_k_e_t_s_i_z_e Specifies the number of data bytes to be sent in the small pack- ets. The default and minimum value is 8. --SS _p_a_c_k_e_t_s_i_z_e Specifies the number of data bytes to be sent in the big packets. The default is 108. The size should be chosen so that big packet roundtrip times are long enough to be accurately measured (de- pending on clock resolution and number of hops). --uu _s_i_z_e _i_n_c_r_e_m_e_n_t Specifies that bbiinngg should start sending packets of the size of _s_m_a_l_l _p_a_c_k_e_t_s_i_z_e and then increase the size by _s_i_z_e _i_n_c_r_e_m_e_n_t un- til it reaches _b_i_g _p_a_c_k_e_t_s_i_z_e. --vv Verbose output. ICMP packets other than ECHO_RESPONSE that are received are listed. --VV Very verbose output. The roundtrip time of each received echo is displayed. --ww Display possible warnings about roundtrip times all the time. By default, warnings are printed only at the end. --zz Fill packets with uncompressible (pseudo-random) data. Round-trip times and packet loss statistics are computed. If duplicate packets are received, they are not included in the packet loss calcula- tion, although the round trip time of these packets is used in calculat- ing the minimum/average/maximum round-trip time numbers. When the speci- fied number of loops have been made or if the program is terminated with a SIGINT, a brief summary is displayed. This program is intended for use in network testing, measurement and man- agement. Because of the load it can impose on the network, it is unwise to use bbiinngg during normal operations or from automated scripts. BBUUGGSS Many Hosts and Gateways ignore the RECORD_ROUTE option. The maximum IP header length is too small for options like RECORD_ROUTE to be completely useful. There's not much that that can be done about this, however. Some of the final stats (average throughputs) almost never give a even marginally correct result. SSEEEE AALLSSOO netstat(1), ifconfig(8), ping(8), routed(8), traceroute(8) AAUUTTHHOORR Pierre Beyssac bing-1.3.5/win32/getopt.c100664 1750 1750 51045 6605754627 14522 0ustar fgougetfgouget/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* NOTE!!! AIX requires this to be the first thing in the file. Do not put ANYTHING before it! */ #if !defined (__GNUC__) && defined (_AIX) #pragma alloca #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef __GNUC__ #define alloca __builtin_alloca #else /* not __GNUC__ */ #if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__)))) #include #else #ifndef _AIX char *alloca (); #endif #endif /* alloca.h */ #endif /* not __GNUC__ */ #if !__STDC__ && !defined(const) && IN_GCC #define const #endif /* This tells Alpha OSF/1 not to define a getopt prototype in . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #undef alloca /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #else /* Not GNU C library. */ #define __alloca alloca #endif /* GNU C library. */ /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a long-named option. Because this is not POSIX.2 compliant, it is being phased out. */ /* #define GETOPT_COMPAT */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #ifndef nt386 #include "getopt.h" #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = 0; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) #else /* Avoid depending on library functions or files whose names are inconsistent. */ char *getenv (); static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } static void my_bcopy (from, to, size) const char *from; char *to; int size; { int i; for (i = 0; i < size; i++) to[i] = from[i]; } #endif /* GNU C library. */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (argv) char **argv; { int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); #ifdef WIN32 /* do no use alloca */ char **temp = (char **) malloc (nonopts_size); #else char **temp = (char **) __alloca (nonopts_size); #endif /* Interchange the two blocks of data in ARGV. */ my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size); my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt], (optind - last_nonopt) * sizeof (char *)); my_bcopy ((char *) temp, (char *) &argv[first_nonopt + optind - last_nonopt], nonopts_size); /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; #ifdef WIN32 free(temp); #endif } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int option_index; optarg = 0; /* Initialize the internal data when the first call is made. Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ if (optind == 0) { first_nonopt = last_nonopt = optind = 1; nextchar = NULL; /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (getenv ("POSIXLY_CORRECT") != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; } if (nextchar == NULL || *nextchar == '\0') { if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Now skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) optind++; last_nonopt = optind; } /* Special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0') #ifdef GETOPT_COMPAT && (longopts == NULL || argv[optind][0] != '+' || argv[optind][1] == '\0') #endif /* GETOPT_COMPAT */ ) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Start decoding its characters. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } if (longopts != NULL && ((argv[optind][0] == '-' && (argv[optind][1] == '-' || long_only)) #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ )) { const struct option *p; char *s = nextchar; int exact = 0; int ambig = 0; const struct option *pfound = NULL; int indfound; while (*s && *s != '=') s++; /* Test all options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, s - nextchar)) { if (s - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*s) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = s + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') /* --option */ fprintf (stderr, "%s: option `--%s' doesn't allow an argument\n", argv[0], pfound->name); else /* +option or -option */ fprintf (stderr, "%s: option `%c%s' doesn't allow an argument\n", argv[0], argv[optind - 1][0], pfound->name); } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' #ifdef GETOPT_COMPAT || argv[optind][0] == '+' #endif /* GETOPT_COMPAT */ || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, "%s: unrecognized option `--%s'\n", argv[0], nextchar); else /* +option or -option */ fprintf (stderr, "%s: unrecognized option `%c%s'\n", argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; return '?'; } } /* Look at and handle the next option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { #if 0 if (c < 040 || c >= 0177) fprintf (stderr, "%s: unrecognized option, character code 0%o\n", argv[0], c); else fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); #else /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); #endif } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = 0; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { #if 0 fprintf (stderr, "%s: option `-%c' requires an argument\n", argv[0], c); #else /* 1003.2 specifies the format of this message. */ fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ bing-1.3.5/win32/getopt.c.berkley100664 1750 1750 7634 6605753610 16132 0ustar fgougetfgouget/* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94"; #endif /* LIBC_SCCS and not lint */ #include #include #include int opterr = 1, /* if error message should be printed */ optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ char *optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { extern char *__progname; static char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (optind >= nargc || *(place = nargv[optind]) != '-') { place = EMSG; return (EOF); } if (place[1] && *++place == '-') { /* found "--" */ ++optind; place = EMSG; return (EOF); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means EOF. */ if (optopt == (int)'-') return (EOF); if (!*place) ++optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", __progname, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ optarg = NULL; if (!*place) ++optind; } else { /* need an argument */ if (*place) /* no white space */ optarg = place; else if (nargc <= ++optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", __progname, optopt); return (BADCH); } else /* white space */ optarg = nargv[optind]; place = EMSG; ++optind; } return (optopt); /* dump back option letter */ } bing-1.3.5/win32/getopt.h100664 1750 1750 10474 6605753610 14517 0ustar fgougetfgouget/* Declarations for getopt. Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if __STDC__ #if defined(__GNU_LIBRARY__) /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); #endif /* not __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* not __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ bing-1.3.5/win32/icmp2.c100664 1750 1750 15526 7000272277 14220 0ustar fgougetfgouget/* * This module provides an interface to send and receive ICMP messages * which is closer to the way Unix programs are written than the standard * WIN32 icmp dll's interface. */ /* $Id: icmp2.c,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ /* don't know where it should come from */ #define LITTLE_ENDIAN 0 #define BIG_ENDIAN 1 #define BYTE_ORDER LITTLE_ENDIAN #include "win32/win32.h" #include #include "win32/types.h" #include "netinet/ip.h" #include "netinet/ip_var.h" #include "netinet/ip_icmp.h" #include #include #include "mod_icmp.h" #include #include typedef struct { HANDLE hICMP; /* The ICMP dll handle */ /* "Socket" options */ int rcvbufsize; /* Size of the receive buffer */ struct ip_option_information ip_options;/* The IP options */ unsigned long timeout; /* Time to wait for a reply */ /* A few things to remember about the request */ u_short msg_id; u_short msg_seq; /* Some fields to process the answers */ struct icmp_echo_reply* rcvbuf; /* The buffer in which */ /* IcmpSendEcho will store the answers */ int nb_replies; /* -1 => message not sent yet. */ /* >=0 => number of reply messages */ struct icmp_echo_reply* current; /* Pointer to next reply */ } icmp_state_i; #define handle2state(h) ((icmp_state_i*)h) icmp_handle icmp_open() { icmp_state_i* handle; /* Perform some initialisation to ease error recovery */ handle=NULL; /* Allocate the handle */ handle=malloc(sizeof(icmp_state_i)); /* Fill defaults */ handle->hICMP=IcmpCreateFile(); handle->rcvbufsize=4096; handle->rcvbuf=NULL; handle->nb_replies=-1; /* Set options defaults */ handle->ip_options.Ttl=255; handle->ip_options.Tos=0; handle->ip_options.Flags=0; handle->ip_options.OptionsSize=0; handle->ip_options.OptionsData=NULL; return (icmp_handle)handle; error: if (handle!=NULL) free(handle); return NULL; } int icmp_set_option(icmp_handle handle, int level, int optname, char* optval, int optlen) { int ret; ret=0; switch (level) { case IPPROTO_IP: /* The IP options are handled by building the * corresponding IP structure by hand. */ /* No IP option is supported yet */ errno=ENOSYS; ret=-1; break; case SOL_SOCKET: switch (optname) { case SO_RCVBUF: handle2state(handle)->rcvbufsize=*((int*)optval); break; default: errno=ENOSYS; ret=-1; break; } break; default: errno=ENOSYS; ret=-1; } return ret; } void icmp_set_timeout(icmp_handle handle,unsigned long timeout) { handle2state(handle)->timeout=timeout/1000; } unsigned short icmp_get_id(icmp_handle handle) { return handle2state(handle)->msg_id; } int icmp_send(icmp_handle handle, char* msg, int msg_size, struct sockaddr* to_addr, int to_addr_size) { DWORD reply_size; /* Record some information for the recv */ handle2state(handle)->msg_id=((struct icmp*)msg)->icmp_id; handle2state(handle)->msg_seq=((struct icmp*)msg)->icmp_seq; /* allocate the buffer for the replies */ handle2state(handle)->rcvbuf=realloc(handle2state(handle)->rcvbuf, handle2state(handle)->rcvbufsize); handle2state(handle)->nb_replies=IcmpSendEcho(handle2state(handle)->hICMP, *((IPAddr*)&(((struct sockaddr_in*)to_addr)->sin_addr)), msg+ICMP_MINLEN, (WORD)(msg_size-ICMP_MINLEN), &handle2state(handle)->ip_options, handle2state(handle)->rcvbuf, handle2state(handle)->rcvbufsize, handle2state(handle)->timeout ); if (handle2state(handle)->nb_replies==0) { if (GetLastError()==IP_REQ_TIMED_OUT) return 0; printf("icmp_send: error %d\n",GetLastError()); errno=GetLastError(); return -1; } handle2state(handle)->current=handle2state(handle)->rcvbuf; return msg_size; } int icmp_recv(icmp_handle handle, char* buffer, int buffer_size, struct sockaddr* from_addr, int* from_addr_size, unsigned long* elapsed) { if (handle2state(handle)->nb_replies>0) { struct ip* ip_msg; struct icmp* icmp_msg; /* Misc return values */ ((struct sockaddr_in*)from_addr)->sin_family=AF_INET; ((struct sockaddr_in*)from_addr)->sin_port=0; memcpy(&(((struct sockaddr_in*)from_addr)->sin_addr),&handle2state(handle)->current->Address,4); *elapsed=1000*handle2state(handle)->current->RoundTripTime; /* Reconstruct the ip header */ ip_msg=(struct ip*)buffer; ip_msg->ip_v=4; ip_msg->ip_hl=(sizeof(struct ip) +handle2state(handle)->current->Options.OptionsSize) >> 2; ip_msg->ip_tos=handle2state(handle)->current->Options.Tos; ip_msg->ip_len=((ip_msg->ip_hl) << 2) +ICMP_MINLEN +handle2state(handle)->current->DataSize; ip_msg->ip_id=0; ip_msg->ip_off=0; ip_msg->ip_ttl=handle2state(handle)->current->Options.Ttl; ip_msg->ip_p=0; ip_msg->ip_sum=0; memcpy(&(ip_msg->ip_src),&handle2state(handle)->current->Address,4); memset(&ip_msg->ip_dst,0,4); if (handle2state(handle)->current->Options.OptionsSize>0) memcpy(buffer+sizeof(struct ip), handle2state(handle)->current->Options.OptionsData, handle2state(handle)->current->Options.OptionsSize); /* Reconstruct the icmp header */ icmp_msg=(struct icmp*)(buffer+((ip_msg->ip_hl) << 2)); switch (handle2state(handle)->current->Status) { /* Echo Reply (what we expect) */ case IP_SUCCESS: icmp_msg->icmp_type=0; icmp_msg->icmp_code=0; icmp_msg->icmp_id=handle2state(handle)->msg_id; icmp_msg->icmp_seq=handle2state(handle)->msg_seq; break; /* Destination Unreachable */ case IP_DEST_NET_UNREACHABLE: icmp_msg->icmp_type=3; icmp_msg->icmp_code=0; break; case IP_DEST_HOST_UNREACHABLE: icmp_msg->icmp_type=3; icmp_msg->icmp_code=1; break; case IP_DEST_PROT_UNREACHABLE: icmp_msg->icmp_type=3; icmp_msg->icmp_code=2; break; case IP_DEST_PORT_UNREACHABLE: icmp_msg->icmp_type=3; icmp_msg->icmp_code=3; break; /* Time Exceeded */ case IP_TTL_EXPIRED_TRANSIT: icmp_msg->icmp_type=11; icmp_msg->icmp_code=0; break; case IP_TTL_EXPIRED_REASSEM: icmp_msg->icmp_type=11; icmp_msg->icmp_code=1; break; /* Parameter Problem */ case IP_PARAM_PROBLEM: icmp_msg->icmp_type=12; icmp_msg->icmp_code=0; /* how can I get a value for the pointer field ? */ break; /* Source Quench */ case IP_SOURCE_QUENCH: icmp_msg->icmp_type=4; icmp_msg->icmp_code=0; break; default: handle2state(handle)->nb_replies--; handle2state(handle)->current++; return -handle2state(handle)->current->Status; } /* Who cares about the checksum ? */ icmp_msg->icmp_cksum=0; /* Copy data */ memcpy(buffer+((ip_msg->ip_hl) << 2)+ICMP_MINLEN, handle2state(handle)->current->Data, handle2state(handle)->current->DataSize); handle2state(handle)->nb_replies--; handle2state(handle)->current++; return ip_msg->ip_len; } else return 0; } int icmp_close(icmp_handle handle) { int ret; ret=IcmpCloseHandle((HANDLE)(((icmp_state_i*)handle)->hICMP)); free(handle); return (ret?0:-1); } bing-1.3.5/win32/icmp_win32.c100664 1750 1750 24725 7005246510 15155 0ustar fgougetfgouget/* * This module provides an interface to send and receive ICMP messages * which is closer to the way Unix programs are written than the standard * WIN32 icmp dll's interface. */ /* $Id: icmp_win32.c,v 1.11 1999/10/24 22:47:31 fgouget Exp $ */ /* don't know where it should come form */ #define LITTLE_ENDIAN 0 #define BIG_ENDIAN 1 #define BYTE_ORDER LITTLE_ENDIAN #include "win32/win32.h" #include #include "win32/types.h" #include "netinet/ip.h" #include "netinet/ip_var.h" #include "netinet/ip_icmp.h" #include #include #include "mod_icmp.h" #include #include typedef struct { HANDLE hICMP; /* The ICMP dll handle */ /* "Socket" options */ int rcvbufsize; /* Size of the receive buffer */ struct ip_option_information ip_options;/* The IP options */ unsigned long timeout; /* Time to wait for a reply */ /* A few things to remember about the request */ u_short msg_id; u_short msg_seq; /* Some fields to process the answers */ struct icmp_echo_reply* rcvbuf; /* The buffer in which */ /* IcmpSendEcho will store the answers */ int nb_replies; /* -1 => message not sent yet. */ /* >=0 => number of reply messages */ struct icmp_echo_reply* current; /* Pointer to next reply */ LARGE_INTEGER rtt_in_ticks; /* This is our own measurment of the RTT */ LARGE_INTEGER ticks_freq; } icmp_state_i; #define handle2state(h) ((icmp_state_i*)h) icmp_handle icmp_open() { icmp_state_i* state; /* Give a higher priority so that bing has better * chances not to be delayed when measuring the RTT. */ SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS); /* Perform some initialisation to ease error recovery */ state=NULL; /* Allocate the state */ state=malloc(sizeof(icmp_state_i)); /* Fill defaults */ state->hICMP=IcmpCreateFile(); state->rcvbufsize=4096; state->rcvbuf=NULL; state->nb_replies=-1; QueryPerformanceFrequency(&state->ticks_freq); /* Set options defaults */ state->ip_options.Ttl=255; state->ip_options.Tos=0; state->ip_options.Flags=0; state->ip_options.OptionsSize=0; state->ip_options.OptionsData=NULL; state->timeout=2000; return (icmp_handle)state; } int icmp_set_option(icmp_handle handle, int level, int optname, char* optval, int optlen) { icmp_state_i* state; int ret; ret=0; state=handle2state(handle); switch (level) { case IPPROTO_IP: /* The IP options are handled by building the * corresponding IP structure by hand. */ switch (optname) { case IP_TTL: state->ip_options.Ttl=*((int*)optval); break; case IP_TOS: state->ip_options.Tos=*((int*)optval); break; /*(!!)case IP_FLAGS: state->ip_options.Flags=*((int*)optval); break;*/ case IP_OPTIONS: if (optlen>state->ip_options.OptionsSize) { state->ip_options.OptionsSize=optlen; state->ip_options.OptionsData=realloc(state->ip_options.OptionsData,optlen); if (state->ip_options.OptionsData==NULL) { errno=ENOMEM; ret=-1; goto end; } memcpy(state->ip_options.OptionsData,(char*)optval,state->ip_options.OptionsSize); } break; default: errno=ENOSYS; ret=-1; break; } break; case SOL_SOCKET: switch (optname) { case SO_RCVBUF: state->rcvbufsize=*((int*)optval); break; default: errno=ENOSYS; ret=-1; break; } break; default: errno=ENOSYS; ret=-1; } end: return ret; } void icmp_set_timeout(icmp_handle handle,unsigned long timeout) { handle2state(handle)->timeout=timeout/1000; } unsigned short icmp_get_id(icmp_handle handle) { return handle2state(handle)->msg_id; } int icmp_send(icmp_handle handle, char* msg, int msg_size, struct sockaddr* to_addr, int to_addr_size) { icmp_state_i* state; LARGE_INTEGER start,stop; state=handle2state(handle); /* Record some information for the recv */ state->msg_id=((struct icmp*)msg)->icmp_id; state->msg_seq=((struct icmp*)msg)->icmp_seq; /* allocate the buffer for the replies */ state->rcvbuf=realloc(state->rcvbuf, state->rcvbufsize); QueryPerformanceCounter(&start); state->nb_replies=IcmpSendEcho(state->hICMP, *((IPAddr*)&(((struct sockaddr_in*)to_addr)->sin_addr)), msg+ICMP_MINLEN, (WORD)(msg_size-ICMP_MINLEN), &state->ip_options, state->rcvbuf, state->rcvbufsize, state->timeout ); QueryPerformanceCounter(&stop); if ((state->ticks_freq.QuadPart!=0) && (state->nb_replies==1)) { /* If we have a high performance counter, use it to measure * the RTT. The high performance counter will either give us * a much more precise measure of the RTT than the ICMP * library or it will give us a gross exageration of the RTT * if the execution of our process has been delayed by the * scheduler. Statistically this should give much better * results than the ICMP library (which tends to sometimes * under-estimate the RTT by up to nearly 2 ms which is * BAD in our case. */ state->rtt_in_ticks.QuadPart=stop.QuadPart-start.QuadPart; } else state->rtt_in_ticks.QuadPart=0; if ((state->nb_replies==0) && (GetLastError()!=IP_REQ_TIMED_OUT)) { printf("icmp_send: error %d\n",GetLastError());/* (!!) printf !!! */ state->nb_replies=-1; errno=GetLastError(); return -1; } state->current=state->rcvbuf; return msg_size; } int icmp_recv(icmp_handle handle, char* buffer, int buffer_size, struct sockaddr* from_addr, int* from_addr_size, double *elapsed) { icmp_state_i* state; int ip_header_len; struct ip* ip_msg; struct icmp* icmp_msg; state=handle2state(handle); if (state->nb_replies<0) { /* icmp_send has not been called yet, or it failed */ return -1; } if (state->nb_replies==0) { /* We have not more results to return */ return 0; } if (buffer_sizecurrent->Options.OptionsSize+ICMP_MINLEN+state->current->DataSize) { /* We cannot return the result because the buffer is too small */ errno=EFAULT; return -1; } /* Misc return values */ ((struct sockaddr_in*)from_addr)->sin_family=AF_INET; ((struct sockaddr_in*)from_addr)->sin_port=0; memcpy(&(((struct sockaddr_in*)from_addr)->sin_addr),&state->current->Address,4); if (state->rtt_in_ticks.QuadPart==0) *elapsed=(double)(state->current->RoundTripTime); else *elapsed=((double)(state->rtt_in_ticks.QuadPart*1000))/ state->ticks_freq.QuadPart; /* Reconstruct the ip header */ ip_header_len=sizeof(struct ip)+state->current->Options.OptionsSize; ip_msg=(struct ip*)buffer; ip_msg->ip_v=4; ip_msg->ip_hl=ip_header_len >> 2; ip_msg->ip_tos=state->current->Options.Tos; ip_msg->ip_len=ip_header_len+state->current->DataSize; ip_msg->ip_id=0; ip_msg->ip_off=0; ip_msg->ip_ttl=state->current->Options.Ttl; ip_msg->ip_p=IPPROTO_ICMP; ip_msg->ip_sum=0; memcpy(&(ip_msg->ip_src),&state->current->Address,4); ip_msg->ip_dst.S_un.S_addr=inet_addr("127.0.0.1"); if (state->current->Options.OptionsSize>0) memcpy(buffer+sizeof(struct ip), state->current->Options.OptionsData, state->current->Options.OptionsSize); /* Reconstruct the icmp header */ icmp_msg=(struct icmp*)(buffer+ip_header_len); switch (state->current->Status) { /* Echo Reply (what we expect) */ case IP_SUCCESS: icmp_msg->icmp_type=ICMP_ECHOREPLY; icmp_msg->icmp_code=0; break; /* Destination Unreachable */ case IP_DEST_NET_UNREACHABLE: icmp_msg->icmp_type=ICMP_UNREACH; icmp_msg->icmp_code=ICMP_UNREACH_NET; break; case IP_DEST_HOST_UNREACHABLE: icmp_msg->icmp_type=ICMP_UNREACH; icmp_msg->icmp_code=ICMP_UNREACH_HOST; break; case IP_DEST_PROT_UNREACHABLE: icmp_msg->icmp_type=ICMP_UNREACH; icmp_msg->icmp_code=ICMP_UNREACH_PROTOCOL; break; case IP_DEST_PORT_UNREACHABLE: icmp_msg->icmp_type=ICMP_UNREACH; icmp_msg->icmp_code=ICMP_UNREACH_PORT; break; case IP_BAD_ROUTE: icmp_msg->icmp_type=ICMP_UNREACH; icmp_msg->icmp_code=ICMP_UNREACH_SRCFAIL; break; /* Time Exceeded */ case IP_TTL_EXPIRED_TRANSIT: icmp_msg->icmp_type=ICMP_TIMXCEED; icmp_msg->icmp_code=ICMP_TIMXCEED_INTRANS; break; case IP_TTL_EXPIRED_REASSEM: icmp_msg->icmp_type=ICMP_TIMXCEED; icmp_msg->icmp_code=ICMP_TIMXCEED_REASS; break; /* Parameter Problem */ case IP_PARAM_PROBLEM: icmp_msg->icmp_type=ICMP_PARAMPROB; icmp_msg->icmp_code=0; /* how can I get a value for the pointer field ? */ break; /* Source quench */ case IP_SOURCE_QUENCH: icmp_msg->icmp_type=ICMP_SOURCEQUENCH; icmp_msg->icmp_code=0; break; default: handle2state(handle)->nb_replies--; handle2state(handle)->current++; return handle2state(handle)->current->Status; } if (state->current->Status==IP_SUCCESS) { icmp_msg->icmp_id=state->msg_id; icmp_msg->icmp_seq=state->msg_seq; } else { icmp_msg->icmp_id=0; icmp_msg->icmp_seq=0; } /* Retrieve the data (includes the icmp header) */ memcpy(buffer+ip_header_len+ICMP_MINLEN, state->current->Data, state->current->DataSize); state->nb_replies--; state->current++; return ip_msg->ip_len; } int icmp_close(icmp_handle handle) { int ret; ret=IcmpCloseHandle((HANDLE)(((icmp_state_i*)handle)->hICMP)); free(handle); return (ret?0:-1); } bing-1.3.5/win32/types.h100664 1750 1750 724 7000272277 14311 0ustar fgougetfgouget/* $Id: types.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef bing_types_h_ #define bing_types_h_ #include /* * Missing in Microsoft's types.h */ typedef unsigned short u_short; typedef unsigned long u_long; typedef char* caddr_t; typedef u_short n_short; /* short as received from the net */ typedef u_long n_long; /* long as received from the net */ typedef u_long n_time; /* ms since 00:00 GMT, byte rev */ #endif /* End of File */ bing-1.3.5/win32/win32.h100664 1750 1750 342 7000272277 14103 0ustar fgougetfgouget/* $Id: win32.h,v 1.3 1999/10/11 05:25:19 fgouget Exp $ */ #ifndef bing_win32_h_ #define bing_win32_h_ #define WIN32_LEAN_AND_MEAN #define NOSERVICE #define NOMCX #define NOIME #include #endif /* End of File */