nuttcp-6.1.2/0002755000222400001560000000000011140134212012553 5ustar robmusketeersnuttcp-6.1.2/nuttcp.80000664000222400001560000003743511140131101014167 0ustar robmusketeers.TH NUTTCP 8 "3 February 2007" "nuttcp-v6.1.2" "Under Construction" .SH NAME nuttcp \- network performance measurement tool .SH SYNOPSIS .na .de OP .ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" .el .RB "[\ " "\\$1" "\ ]" .. .B nuttcp -h .br .B nuttcp -V .br .B nuttcp -t .OP \-bdDsuv .OP \-c dscp_value .OP \-l buffer_len .OP \-n num_bufs .br .ti +10 .OP \-w window_size .OP \-ws server_window .OP \-wb .br .ti +10 .OP \-p data_port .OP \-P control_port .br .ti +10 .OP \-N num_streams .OP \-R "xmit_rate_limit\fP [m|g]" .br .ti +10 .OP \-T "xmit_timeout\fP [m]" .I host [ .B < .I input ] .br .B nuttcp -r .OP \-bBdsuv .OP \-c dscp_value .OP \-l buffer_len .OP \-n num_bufs .br .ti +10 .OP \-w window_size .OP \-ws server_window .OP \-wb .br .ti +10 .OP \-p data_port .OP \-P control_port .br .ti +10 .OP \-N num_streams .OP \-R "xmit_rate_limit\fP [m|g]" .br .ti +10 .OP \-T "xmit_timeout\fP [m]" [ .I host ] [ .B > .I output ] .br .B nuttcp -S .OP \-P control_port .br .B nuttcp -1 .OP \-P control_port .ad .SH DESCRIPTION nuttcp is a network performance measurement tool intended for use by network and system managers. Its most basic usage is to determine the raw TCP (or UDP) network layer throughput by transferring memory buffers from a source system across an interconnecting network to a destination system, either transferring data for a specified time interval, or alternatively transferring a specified number of bytes. In addition to reporting the achieved network throughput in Mbps, nuttcp also provides additional useful information related to the data transfer such as user, system, and wall-clock time, transmitter and receiver CPU utilization, and loss percentage (for UDP transfers). .PP nuttcp is based on nttcp, which in turn was an enhancement by someone at Silicon Graphics (SGI) on the original ttcp, which was written by Mike Muuss at BRL sometime before December 1984, to compare the performance of TCP stacks by U.C. Berkeley and BBN to help DARPA decide which version to place in the first BSD Unix release. nuttcp has several useful features beyond those of the basic ttcp/nttcp, such as a server mode, rate limiting, multiple parallel streams, and timer based usage. More recent changes include IPv6 support, IPv4 multicast, and the ability to set the maximum segment size or TOS/DSCP bits. nuttcp is continuing to evolve to meet new requirements that arise and to add desired new features. nuttcp has been successfully built and run on a variety of Solaris, SGI, and PPC/X86 Linux systems, and should probably work fine on most flavors of Unix. It has also been used successfully on various versions of the Windows operating system. .PP There are two basic modes of operation for nuttcp. The original or classic mode is the transmitter/receiver mode, which is also the way the original ttcp and nttcp worked. In this mode, a receiver is first initiated on the destination host using "nuttcp -r", and then a transmitter must be started on the source host using "nuttcp -t". This mode is somewhat deprecated and is no longer recommended for general use. The preferred and recommended mode of operation for nuttcp is the new client/server mode. With this mode, a server is first started on one system using "nuttcp -S" (or "nuttcp -1"), and then a client may either transmit data to (using "nuttcp -t") or receive data from (using "nuttcp -r") the server system. All the information provided by nuttcp is reported by the client, including the information from the server, thus providing a full snapshot of both the transmitter and receiver ends of the data transfer. .PP The server may be started by a normal, non-privileged user by issuing either a "nuttcp -S" or a "nuttcp -1" command. However, the optimal and recommended method of running a server is to run "nuttcp -S" via the inetd/xinetd daemon. This method has several significant advantages, including being more robust, allowing multiple simultaneous connections, and providing for access control over who is allowed to use the nuttcp server via the hosts.allow (and hosts.deny) file. By default, the nuttcp server listens for commands on port 5000, and the actual nuttcp data transfers take place on port 5001. .PP The .I host parameter must be specified for the transmitter, and provides the host name or IP address of the receiver. In classic transmitter/receiver mode, the .I host parameter may not be specified for the receiver. In client/server mode, when the client is the receiver, the .I host parameter specifies the host name or IP address of the transmitter (server). .PP Normally, a nuttcp data transfer is memory-to-memory. However, by using the "-s" option, it is possible to also perform memory-to-disk, disk-to-memory, and disk-to-disk data transfers. Using the "-s" option with the transmitter will cause nuttcp to read its data from the standard input instead of using a prefabricated memory buffer, while using the "-s" option on the receiver causes nuttcp to write its data to standard output. All these types of data transfers are possible with the classic transmitter/receiver mode. For security reasons, the "-s" option is disabled on the server, so it is not possible to access the disk on the server side of a data transfer. .PP The allowed options to nuttcp are: .SH OPTIONS .TP .B \-h Print out a usage statement. Running nuttcp with no arguments will also produce a usage statement. .TP .B \-V Prints the nuttcp version number. The nuttcp version is also printed as part of the normal nuttcp output when the "-v" verbose output is used (but not when using the default brief output). In client/server mode, the version number of both the client and server is identified. .TP .B \-t Indicates that this nuttcp is the transmitter. In client/server mode, this means the server specified by the .I host parameter is the receiver. .TP .B \-r Indicates that this nuttcp is the receiver. In client/server mode, this means the server specified by the .I host parameter is the transmitter. .TP .B \-S Indicates that this nuttcp is the server. The only option that may be specified to the server is the "-P" option, which allows one to change the control port used by the server, but only when the server is started by a normal, non-privileged user. When the server is initiated by inetd/xinetd, the server control port should be specified in the .I services file. .TP .B \-1 Basically the same as the "-S" option, but indicates a one-shot server, i.e. the server exits after the first data transfer initiated by a client. The "-1" option should only be used when the server is started by a normal, non-privileged user. This option will probably rarely need to be used, but can be useful for a quick test and eliminates the possibilty of leaving a non-access controlled nuttcp server running on the system (which can happen when using the "-S" option and forgetting to kill the nuttcp server after finishing a series of tests). .TP .B \-b Produce brief one-line output, which includes the amount of data transferred in MB (1024**2 bytes), the time interval in seconds, the TCP (or UDP) network throughput in Mbps (millions of bits per second), the transmitter and/or receiver CPU utilization, and for UDP data transfers also outputs the loss percentage. In client/server mode, most of the printed statistics are from the viewpoint of the receiver. This is the default output format. .TP .B \-B This option is only valid for the receiver, and forces the receiver to read a full buffer (as specified by the "-l" buffer length option) from the network. It is mainly intended to be used with the "-s" option to only output full buffers to standard output (e.g. for use with tar). It is also implicitly set whenever the number of streams as specified by the "-N" option is greater than 1. This option is not passed to the server. .TP .B \-d For TCP data transfers, sets the SO_DEBUG option on the data socket. This option is not passed to the server. It is a rarely used option which may possibly be removed or renamed in a future version of nuttcp. .TP .B \-D This option is only valid for the transmitter, and only for TCP data transfers, in which case it sets the TCP_NODELAY option on the data socket, which turns off the Nagle algorithm causing data packets to be sent as soon as possible without introducing any unnecessary delays. This option is not passed to the server. It is a rarely used option which may possibly be removed or renamed in a future version of nuttcp. .TP .B \-s Setting the "-s" option causes nuttcp to either read its data from standard input rather than using prefabricated memory buffers (for "nuttcp -t"), or to write its data out to standard output (for "nuttcp -r"). The "-s" option is disabled for security reasons on the server. .TP .B \-u Use UDP for the data transfer instead of the default of TCP. .TP .B \-v Verbose output that provides some additional information related to the data transfer. In client/server mode, the server is always verbose (implicit "-v" option), but the client controls the extent and type of output via the "-v" and "-b" options. .TP .BI \-c dscp_value Sets the socket option to support COS. Either takes a dscp value or with the t|T modifier it takes the full TOS field. .TP .BI \-l buffer_len Length of the network write/read buffer in bytes for the transmitter/receiver. It defaults to 64 KB (65536) for TCP data transfers and to 8 KB (8192) for UDP. For client/server mode, it sets both the client and server buffer lengths. .TP .BI \-n num_bufs Specifies the number of source buffers written to the network (default is unlimited), and is ignored by the receiver. For client/server mode, if the client issues a "nuttcp -r" command making it the receiver, this parameter is passed to the server since the server is the transmitter in this case. This parameter is also ignored if the "-s" parameter is specified to the transmitter. .TP .BI \-w window_size Indicates the window size in KB of the transmitter (for "nuttcp -t") or receiver (for "nuttcp -r"). Actually, to be technically correct, it sets the sender or receiver TCP socket buffer size, which then effectively sets the window size. For client/server mode, both the transmitter and receiver window sizes are set. The default window size is architecture and system dependent. Note recent Linux systems, out of a misguided desire to be helpful, double whatever window size is actually specified by the user (this is not a bug with nuttcp but a bug/feature of the Linux kernel). Also, with these Linux systems, the actual window size that's used on the intervening network, as observed with tcpdump, is greater than the requested window size, but less than the doubled value set by Linux. .TP .BI \-ws server_window For client/server mode, the "-ws" option provides a mechanism for setting a different window size on the server than the client window size as specified with the "-w" option. .TP .B \-wb Normally, to conserve memory, the transmitter only sets the TCP send socket buffer size and the receiver only sets the TCP receive socket buffer size. However, if the "-wb" option is used, the transmitter will also set the TCP receive socket buffer size and the receiver will also set the TCP send socket buffer size. Under normal circumstances, this should never be necessary. This option was implemented because certain early braindead Solaris 2.8 systems would not properly set the TCP window size unless both the TCP send and receive socket buffer sizes were set (later Solaris 2.8 systems have corrected this deficiency). Thus the 'b' in this option can stand either for "braindead" or "both". .TP .BI \-p data_port Port number used for the data connection, which defaults to port 5001. If multiple streams are specified with the "-N" option, the "-p" option specifies the starting port number for the data connection. For example, if four streams are specified using the default data connection port number, nuttcp will use ports 5001, 5002, 5003, and 5004 for the four TCP (or UDP) connections used to perform the data transfer. .TP .BI \-P control_port For client/server mode, specifies the port number used for the control connection between the client and server, and defaults to port 5000. On the server side, the "-P" option should only be used when the server is started manually by the user. If the server is started by inetd/xinetd (the preferred method), the control connection must be specified by adding a nuttcp entry to the .I services file. .TP .BI \-N num_streams Species the number of parallel TCP (or UDP) data streams to be used for the data transfer, with the default being a single data stream. The maximum number of parallel data streams that can be used is 128. If the number of streams is greater than one, the "-B" option is implicitly set. The current implementation does not fork off separate processes for each data stream, so specifying multiple streams on an SMP machine will not take advantage of its multiple processors. Of course it is always possible to run multiple nuttcp commands in parallel on an SMP system to determine if there is any advantage to running on multiple processors. This is especially simple to do when running in client/server mode when the server is started from the inetd/xinetd daemon. When running multiple nuttcp commands in parallel, the "-T" transmitter timeout option may be used to insure that all the nuttcp commands finish at approximately the same time. .TP .BI \-R xmit_rate_limit\fP [m|g] The transmitter rate limit throttles the speed at which the transmitter sends data to the network, and by default is in Kbps, although the 'm' or 'g' suffix may be used to specify Mbps or Gbps. This option may be used with either TCP or UDP data streams. Because of the way this option is currently implemented, it will consume all the available CPU on the transmitter side of the connection so the "%TX" stats are not meaningful when using the rate limit option. By default the rate limit is applied to the average rate of the data transfer in real time, and not in CPU time, so if nuttcp is switched out of the processor for any reason, when it is switched back in, it is possible that the instantaneous rate may momentarily exceed the specified value. There is an 'i' qualifier to the rate limit option (specified as "-Ri") that will restrict the instantaneous rate at any given point in time to the specified value, although in this case the final rate reported by nuttcp may be less than the specified value since nuttcp won't attempt to catch up if other processes gain control of the CPU. The default is no rate limit. Note another way to throttle the throughput of TCP data streams is to reduce the window size. .TP .BI \-T xmit_time_limit\fP [m] Limits the amount of time that the transmitter will send data to the specified number of seconds, or number of minutes if the 'm' suffix is used. Normally a data transfer will either specify a fixed amount of data to send using the "-n" option, or a fixed period of time to send using the "-T" option. However, if both the "-n" and "-T" options are used, the data transfer will be stopped by whichever option takes affect first. The default is a 10 second time limit for the data transfer. .PP .SH USAGE Under Construction .PP For now, consult the README file for basic usage guidelines. .SH EXAMPLES Under Construction .PP For now, see the examples.txt file for some examples of using nuttcp. .SH SEE ALSO .BR ping (8), .BR traceroute (8), .BR tracepath (8), .BR pathchar (8), .BR netstat (1), .BR mtrace (8) .SH AUTHORS Developed by Bill Fink based on nttcp which in turn was an enhancement of the original ttcp developed by Mike Muuss at BRL. IPv6 capability and some other fixes and enhancements contributed by Rob Scott. Many useful suggestions and testing performed by Phil Dykstra and others. .LP The current version is available via anonymous ftp from: .LP .RS .I ftp://ftp.lcp.nrl.navy.mil/pub/nuttcp/ .RE .LP The authors can be reached at nuttcp@lcp.nrl.navy.mil. .SH BUGS Please send bug reports to nuttcp-bugs@lcp.nrl.navy.mil. nuttcp-6.1.2/binaries0000777000222400001560000000000011140130763014767 2binustar robmusketeersnuttcp-6.1.2/xinetd.d/0002775000222400001560000000000007740305742014315 5ustar robmusketeersnuttcp-6.1.2/xinetd.d/nuttcp0000664000222400001560000000041010441623342015535 0ustar robmusketeers# default: off # description: network performance testing server (developed from ttcp/nttcp) service nuttcp { socket_type = stream wait = no user = nobody server = /usr/local/bin/nuttcp server_args = -S log_on_failure += USERID disable = yes } nuttcp-6.1.2/xinetd.d/nuttcp40000664000222400001560000000044310441623347015634 0ustar robmusketeers# default: off # description: network performance testing server (developed from ttcp/nttcp) service nuttcp { flags = REUSE IPv4 socket_type = stream wait = no user = nobody server = /usr/local/bin/nuttcp server_args = -S -4 log_on_failure += USERID disable = yes } nuttcp-6.1.2/xinetd.d/nuttcp60000664000222400001560000000046210441623353015634 0ustar robmusketeers# default: off # description: network performance testing server (developed from ttcp/nttcp) service nuttcp { flags = REUSE IPv6 v6only = yes socket_type = stream wait = no user = nobody server = /usr/local/bin/nuttcp server_args = -S -6 log_on_failure += USERID disable = yes } nuttcp-6.1.2/missing/0002775000222400001560000000000010070166674014250 5ustar robmusketeersnuttcp-6.1.2/missing/addrinfo.h0000664000222400001560000001120707175157124016210 0ustar robmusketeers/* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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: addrinfo.h,v 1.3 2000/10/24 00:56:52 fenner Exp $ */ #ifndef HAVE_ADDRINFO /* * Error return codes from getaddrinfo() */ #define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ #define EAI_AGAIN 2 /* temporary failure in name resolution */ #define EAI_BADFLAGS 3 /* invalid value for ai_flags */ #define EAI_FAIL 4 /* non-recoverable failure in name resolution */ #define EAI_FAMILY 5 /* ai_family not supported */ #define EAI_MEMORY 6 /* memory allocation failure */ #define EAI_NODATA 7 /* no address associated with hostname */ #define EAI_NONAME 8 /* hostname nor servname provided, or not known */ #define EAI_SERVICE 9 /* servname not supported for ai_socktype */ #define EAI_SOCKTYPE 10 /* ai_socktype not supported */ #define EAI_SYSTEM 11 /* system error returned in errno */ #define EAI_BADHINTS 12 #define EAI_PROTOCOL 13 #define EAI_MAX 14 /* internal error */ #define NETDB_INTERNAL -1 /* see errno */ /* * Flag values for getaddrinfo() */ #define AI_PASSIVE 0x00000001 /* get address to use bind() */ #define AI_CANONNAME 0x00000002 /* fill ai_canonname */ #define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ /* valid flags for addrinfo */ #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) #define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ #define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ #define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */ #define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */ /* special recommended flags for getipnodebyname */ #define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG) struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ size_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for hostname */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; extern void freeaddrinfo (struct addrinfo *); extern void freehostent (struct hostent *); extern char *gai_strerror (int); extern int getaddrinfo (const char *, const char *, const struct addrinfo *, struct addrinfo **); extern int getnameinfo (const struct sockaddr *, size_t, char *, size_t, char *, size_t, int); extern struct hostent *getipnodebyaddr (const void *, size_t, int, int *); extern struct hostent *getipnodebyname (const char *, int, int, int *); extern int inet_pton (int, const char *, void *); extern const char *inet_ntop (int, const void *, char *, size_t); #endif /* HAVE_ADDRINFO */ /* * Constants for getnameinfo() */ #ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endif #ifndef NI_MAXSERV #define NI_MAXSERV 32 #endif /* * Flag values for getnameinfo() */ #ifndef NI_NOFQDN #define NI_NOFQDN 0x00000001 #endif #ifndef NI_NUMERICHOST #define NI_NUMERICHOST 0x00000002 #endif #ifndef NI_NAMEREQD #define NI_NAMEREQD 0x00000004 #endif #ifndef NI_NUMERICSERV #define NI_NUMERICSERV 0x00000008 #endif #ifndef NI_DGRAM #define NI_DGRAM 0x00000010 #endif nuttcp-6.1.2/missing/config.h0000777000222400001560000000000011140130763021040 2config.h.sun4sol26ustar robmusketeersnuttcp-6.1.2/missing/config.h.sun4sol260000664000222400001560000001222007740111275017434 0ustar robmusketeers/* config.h. Generated automatically by configure. */ /* config.h.in. Generated automatically from configure.in by autoheader. */ /* "generated automatically" means DO NOT MAKE CHANGES TO config.h.in -- * make them to acconfig.h and rerun autoheader */ /* Define to empty if the keyword does not work. */ /* #undef const */ /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define if you have SSLeay 0.9.0b with the buggy cast128. */ /* #undef HAVE_BUGGY_CAST128 */ /* Define if you enable IPv6 support */ /* #undef INET6 */ /* Define if you enable support for the libsmi. */ /* #undef LIBSMI */ /* define if you have struct __res_state_ext */ /* #undef HAVE_RES_STATE_EXT */ /* define if your struct __res_state has the nsort member */ /* #undef HAVE_NEW_RES_STATE */ /* define if you have the addrinfo function. */ /* #undef HAVE_ADDRINFO */ /* define if you need to include missing/addrinfoh.h. */ #define NEED_ADDRINFO_H 1 /* define ifyou have the h_errno variable. */ #define HAVE_H_ERRNO 1 /* define if IN6ADDRSZ is defined (XXX not used!) */ /* #undef HAVE_IN6ADDRSZ */ /* define if INADDRSZ is defined (XXX not used!) */ /* #undef HAVE_INADDRSZ */ /* define if this is a development version, to use additional prototypes. */ /* #undef HAVE_OS_PROTO_H */ /* define if RES_USE_INET6 is defined */ /* #undef HAVE_RES_USE_INET6 */ /* define if struct sockaddr has the sa_len member */ /* #undef HAVE_SOCKADDR_SA_LEN */ /* define if you have struct sockaddr_storage */ /* #undef HAVE_SOCKADDR_STORAGE */ /* define if you have ether_ntohost() and it works */ /* #undef USE_ETHER_NTOHOST */ /* define if unaligned memory accesses fail */ #define LBL_ALIGN 1 /* The successful return value from signal (?)XXX */ #define RETSIGVAL /* Define this on IRIX */ /* #undef _BSD_SIGNALS */ /* For HP/UX ANSI compiler? */ /* #undef _HPUX_SOURCE */ /* AIX hack. */ /* #undef _SUN */ /* Workaround for missing sized types */ /* XXX this should move to the more standard uint*_t */ /* #undef int16_t */ /* #undef int32_t */ #define u_int16_t u_short #define u_int32_t u_int #define u_int8_t u_char /* Whether or not to include the possibly-buggy SMB printer */ #define TCPDUMP_DO_SMB 1 /* Long story short: aclocal.m4 depends on autoconf 2.13 * implementation details wrt "const"; newer versions * have different implementation details so for now we * put "const" here. This may cause duplicate definitions * in config.h but that should be OK since they're the same. */ /* #undef const */ /* The number of bytes in a char. */ #define SIZEOF_CHAR 1 /* The number of bytes in a int. */ #define SIZEOF_INT 4 /* The number of bytes in a long. */ #define SIZEOF_LONG 4 /* The number of bytes in a short. */ #define SIZEOF_SHORT 2 /* Define if you have the bpf_dump function. */ /* #undef HAVE_BPF_DUMP */ /* Define if you have the ether_ntohost function. */ /* #undef HAVE_ETHER_NTOHOST */ /* Define if you have the getaddrinfo function. */ /* #undef HAVE_GETADDRINFO */ /* Define if you have the getnameinfo function. */ /* #undef HAVE_GETNAMEINFO */ /* Define if you have the inet_aton function. */ /* #undef HAVE_INET_ATON */ /* Define if you have the inet_ntop function. */ /* #undef HAVE_INET_NTOP */ /* Define if you have the inet_pton function. */ /* #undef HAVE_INET_PTON */ /* Define if you have the pfopen function. */ /* #undef HAVE_PFOPEN */ /* Define if you have the setlinebuf function. */ #define HAVE_SETLINEBUF 1 /* Define if you have the sigaction function. */ /* #undef HAVE_SIGACTION */ /* Define if you have the sigset function. */ #define HAVE_SIGSET 1 /* Define if you have the snprintf function. */ #define HAVE_SNPRINTF 1 /* Define if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 /* Define if you have the strdup function. */ #define HAVE_STRDUP 1 /* Define if you have the strlcat function. */ /* #undef HAVE_STRLCAT */ /* Define if you have the strlcpy function. */ /* #undef HAVE_STRLCPY */ /* Define if you have the vfprintf function. */ #define HAVE_VFPRINTF 1 /* Define if you have the vsnprintf function. */ #define HAVE_VSNPRINTF 1 /* Define if you have the header file. */ /* #undef HAVE_CAST_H */ /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ #define HAVE_NETINET_IF_ETHER_H 1 /* Define if you have the header file. */ /* #undef HAVE_RC5_H */ /* Define if you have the header file. */ #define HAVE_RPC_RPCENT_H 1 /* Define if you have the header file. */ /* #undef HAVE_SMI_H */ /* Define if you have the crypto library (-lcrypto). */ /* #undef HAVE_LIBCRYPTO */ /* Define if you have the dnet library (-ldnet). */ /* #undef HAVE_LIBDNET */ /* Define if you have the rpc library (-lrpc). */ /* #undef HAVE_LIBRPC */ /* Define if you have the smi library (-lsmi). */ /* #undef HAVE_LIBSMI */ /* Define as token for inline if inlining supported */ #define inline inline /* define if your compiler has __attribute__ */ #define HAVE___ATTRIBUTE__ 1 nuttcp-6.1.2/missing/inet_pton.c0000664000222400001560000000445407036177462016425 0ustar robmusketeers/* * Copyright (c) 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * 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 Kungliga Tekniska * Högskolan and its contributors. * * 4. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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: inet_pton.c,v 1.2 2000/01/09 21:35:46 fenner Exp $ */ #ifndef lint static const char rcsid[] = "@(#) $Header: /tcpdump/master/tcpdump/missing/inet_pton.c,v 1.2 2000/01/09 21:35:46 fenner Exp $"; #endif #include #include #include #include int inet_pton(int af, const char *src, void *dst) { if (af != AF_INET) { errno = EAFNOSUPPORT; return -1; } return inet_aton (src, dst); } nuttcp-6.1.2/missing/config.h.cygwin0000664000222400001560000001221507740373515017170 0ustar robmusketeers/* config.h. Generated automatically by configure. */ /* config.h.in. Generated automatically from configure.in by autoheader. */ /* "generated automatically" means DO NOT MAKE CHANGES TO config.h.in -- * make them to acconfig.h and rerun autoheader */ /* Define to empty if the keyword does not work. */ /* #undef const */ /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define if you have SSLeay 0.9.0b with the buggy cast128. */ /* #undef HAVE_BUGGY_CAST128 */ /* Define if you enable IPv6 support */ /* #undef INET6 */ /* Define if you enable support for the libsmi. */ /* #undef LIBSMI */ /* define if you have struct __res_state_ext */ /* #undef HAVE_RES_STATE_EXT */ /* define if your struct __res_state has the nsort member */ /* #undef HAVE_NEW_RES_STATE */ /* define if you have the addrinfo function. */ /* #undef HAVE_ADDRINFO */ /* define if you need to include missing/addrinfoh.h. */ #define NEED_ADDRINFO_H 1 /* define ifyou have the h_errno variable. */ #define HAVE_H_ERRNO 1 /* define if IN6ADDRSZ is defined (XXX not used!) */ /* #undef HAVE_IN6ADDRSZ */ /* define if INADDRSZ is defined (XXX not used!) */ /* #undef HAVE_INADDRSZ */ /* define if this is a development version, to use additional prototypes. */ /* #undef HAVE_OS_PROTO_H */ /* define if RES_USE_INET6 is defined */ /* #undef HAVE_RES_USE_INET6 */ /* define if struct sockaddr has the sa_len member */ /* #undef HAVE_SOCKADDR_SA_LEN */ /* define if you have struct sockaddr_storage */ /* #undef HAVE_SOCKADDR_STORAGE */ /* define if you have ether_ntohost() and it works */ /* #undef USE_ETHER_NTOHOST */ /* define if unaligned memory accesses fail */ /* #undef LBL_ALIGN */ /* The successful return value from signal (?)XXX */ #define RETSIGVAL /* Define this on IRIX */ /* #undef _BSD_SIGNALS */ /* For HP/UX ANSI compiler? */ /* #undef _HPUX_SOURCE */ /* AIX hack. */ /* #undef _SUN */ /* Workaround for missing sized types */ /* XXX this should move to the more standard uint*_t */ /* #undef int16_t */ /* #undef int32_t */ /* #undef u_int16_t */ /* #undef u_int32_t */ /* #undef u_int8_t */ /* Whether or not to include the possibly-buggy SMB printer */ #define TCPDUMP_DO_SMB 1 /* Long story short: aclocal.m4 depends on autoconf 2.13 * implementation details wrt "const"; newer versions * have different implementation details so for now we * put "const" here. This may cause duplicate definitions * in config.h but that should be OK since they're the same. */ /* #undef const */ /* The number of bytes in a char. */ #define SIZEOF_CHAR 1 /* The number of bytes in a int. */ #define SIZEOF_INT 4 /* The number of bytes in a long. */ #define SIZEOF_LONG 4 /* The number of bytes in a short. */ #define SIZEOF_SHORT 2 /* Define if you have the bpf_dump function. */ /* #undef HAVE_BPF_DUMP */ /* Define if you have the ether_ntohost function. */ /* #undef HAVE_ETHER_NTOHOST */ /* Define if you have the getaddrinfo function. */ /* #undef HAVE_GETADDRINFO */ /* Define if you have the getnameinfo function. */ /* #undef HAVE_GETNAMEINFO */ /* Define if you have the inet_aton function. */ /* #undef HAVE_INET_ATON */ /* Define if you have the inet_ntop function. */ /* #undef HAVE_INET_NTOP */ /* Define if you have the inet_pton function. */ /* #undef HAVE_INET_PTON */ /* Define if you have the pfopen function. */ /* #undef HAVE_PFOPEN */ /* Define if you have the setlinebuf function. */ #define HAVE_SETLINEBUF 1 /* Define if you have the sigaction function. */ #define HAVE_SIGACTION 1 /* Define if you have the sigset function. */ /* #undef HAVE_SIGSET */ /* Define if you have the snprintf function. */ #define HAVE_SNPRINTF 1 /* Define if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 /* Define if you have the strdup function. */ #define HAVE_STRDUP 1 /* Define if you have the strlcat function. */ #define HAVE_STRLCAT 1 /* Define if you have the strlcpy function. */ #define HAVE_STRLCPY 1 /* Define if you have the vfprintf function. */ #define HAVE_VFPRINTF 1 /* Define if you have the vsnprintf function. */ #define HAVE_VSNPRINTF 1 /* Define if you have the header file. */ /* #undef HAVE_CAST_H */ /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ /* #undef HAVE_NETINET_IF_ETHER_H */ /* Define if you have the header file. */ /* #undef HAVE_RC5_H */ /* Define if you have the header file. */ /* #undef HAVE_RPC_RPCENT_H */ /* Define if you have the header file. */ /* #undef HAVE_SMI_H */ /* Define if you have the crypto library (-lcrypto). */ /* #undef HAVE_LIBCRYPTO */ /* Define if you have the dnet library (-ldnet). */ /* #undef HAVE_LIBDNET */ /* Define if you have the rpc library (-lrpc). */ /* #undef HAVE_LIBRPC */ /* Define if you have the smi library (-lsmi). */ /* #undef HAVE_LIBSMI */ /* Define as token for inline if inlining supported */ #define inline inline /* define if your compiler has __attribute__ */ #define HAVE___ATTRIBUTE__ 1 nuttcp-6.1.2/missing/inet_ntop.c0000664000222400001560000000620507036177461016420 0ustar robmusketeers/* * Copyright (c) 1999 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * 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 Kungliga Tekniska * Högskolan and its contributors. * * 4. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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: inet_ntop.c,v 1.3 2000/01/09 21:35:45 fenner Exp $ */ #ifndef lint static const char rcsid[] = "@(#) $Header: /tcpdump/master/tcpdump/missing/inet_ntop.c,v 1.3 2000/01/09 21:35:45 fenner Exp $"; #endif #include #include #include #include #include /* * */ #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN 16 #endif static const char * inet_ntop_v4 (const void *src, char *dst, size_t size) { const char digits[] = "0123456789"; int i; struct in_addr *addr = (struct in_addr *)src; u_long a = ntohl(addr->s_addr); const char *orig_dst = dst; if (size < INET_ADDRSTRLEN) { errno = ENOSPC; return NULL; } for (i = 0; i < 4; ++i) { int n = (a >> (24 - i * 8)) & 0xFF; int non_zerop = 0; if (non_zerop || n / 100 > 0) { *dst++ = digits[n / 100]; n %= 100; non_zerop = 1; } if (non_zerop || n / 10 > 0) { *dst++ = digits[n / 10]; n %= 10; non_zerop = 1; } *dst++ = digits[n]; if (i != 3) *dst++ = '.'; } *dst++ = '\0'; return orig_dst; } const char * inet_ntop(int af, const void *src, char *dst, size_t size) { switch (af) { case AF_INET : return inet_ntop_v4 (src, dst, size); default : errno = EAFNOSUPPORT; return NULL; } } nuttcp-6.1.2/missing/sockstorage.h0000664000222400001560000000334007006476774016755 0ustar robmusketeers/* * Copyright (C) 1999 WIDE Project. * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. */ struct sockaddr_storage { #ifdef HAVE_SOCKADDR_SA_LEN u_int8_t __ss_len; u_int8_t __ss_family; u_int8_t fill[126]; #else u_int8_t __ss_family; u_int8_t fill[127]; #endif /* HAVE_SOCKADDR_SA_LEN */ }; nuttcp-6.1.2/missing/inet_aton.c0000664000222400001560000000472207740114211016365 0ustar robmusketeers/* * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * 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 Kungliga Tekniska * Högskolan and its contributors. * * 4. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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: inet_aton.c,v 1.2 2000/01/09 21:35:45 fenner Exp $ */ #ifndef lint static const char rcsid[] = "@(#) $Header: /tcpdump/master/tcpdump/missing/inet_aton.c,v 1.2 2000/01/09 21:35:45 fenner Exp $"; #endif #include #include #include #include /* Minimal implementation of inet_aton. * Cannot distinguish between failure and a local broadcast address. */ #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif int inet_aton(const char *cp, struct in_addr *addr) { addr->s_addr = inet_addr(cp); return (addr->s_addr == INADDR_NONE) ? 0 : 1; } nuttcp-6.1.2/missing/getaddrinfo.c0000664000222400001560000006145007740373742016714 0ustar robmusketeers/* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. */ /* * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. * * Issues to be discussed: * - Thread safe-ness must be checked. * - Return values. There are nonstandard return values defined and used * in the source code. This is because RFC2553 is silent about which error * code must be returned for which situation. * Note: * - We use getipnodebyname() just for thread-safeness. There's no intent * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to * getipnodebyname(). * - The code filters out AFs that are not supported by the kernel, * when globbing NULL hostname (to loopback, or wildcard). Is it the right * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG * in ai_flags? */ #ifdef HAVE_CONFIG_H #include #endif #ifndef lint static const char rcsid[] = "@(#) $Header: /tcpdump/master/tcpdump/missing/getaddrinfo.c,v 1.10 2000/10/24 00:56:53 fenner Exp $"; #endif #include #include #if 0 #include #endif #include #include #include #include #ifndef __CYGWIN__ #include #include #endif #include #include #include #include #include #include #include #include #ifndef HAVE_U_INT32_T #include "bittypes.h" #endif #ifndef HAVE_SOCKADDR_STORAGE #include "sockstorage.h" #endif #ifdef NEED_ADDRINFO_H #include "addrinfo.h" #endif #if defined(__KAME__) && defined(INET6) # define FAITH #endif #define SUCCESS 0 #define ANY 0 #define YES 1 #define NO 0 #ifdef FAITH static int translate = NO; static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; #endif static const char in_addrany[] = { 0, 0, 0, 0 }; static const char in6_addrany[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static const char in_loopback[] = { 127, 0, 0, 1 }; static const char in6_loopback[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; struct sockinet { u_char si_len; u_char si_family; u_short si_port; u_int32_t si_scope_id; }; static const struct afd { int a_af; int a_addrlen; int a_socklen; int a_off; const char *a_addrany; const char *a_loopback; int a_scoped; } afdl [] = { #ifdef INET6 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), in6_addrany, in6_loopback, 1}, #endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), in_addrany, in_loopback, 0}, {0, 0, 0, 0, NULL, NULL, 0}, }; struct explore { int e_af; int e_socktype; int e_protocol; const char *e_protostr; int e_wild; #define WILD_AF(ex) ((ex)->e_wild & 0x01) #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) }; static const struct explore explore[] = { #if 0 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, #endif #ifdef INET6 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, #endif { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, { -1, 0, 0, NULL, 0 }, }; #ifdef INET6 #define PTON_MAX 16 #else #define PTON_MAX 4 #endif static int str_isnumber (const char *); static int explore_fqdn (const struct addrinfo *, const char *, const char *, struct addrinfo **); static int explore_null (const struct addrinfo *, const char *, const char *, struct addrinfo **); static int explore_numeric (const struct addrinfo *, const char *, const char *, struct addrinfo **); static int explore_numeric_scope (const struct addrinfo *, const char *, const char *, struct addrinfo **); static int get_name (const char *, const struct afd *, struct addrinfo **, char *, const struct addrinfo *, const char *); static int get_canonname (const struct addrinfo *, struct addrinfo *, const char *); static struct addrinfo *get_ai (const struct addrinfo *, const struct afd *, const char *); static int get_portmatch (const struct addrinfo *, const char *); static int get_port (struct addrinfo *, const char *, int); static const struct afd *find_afd (int); static char *ai_errlist[] = { "Success", "Address family for hostname not supported", /* EAI_ADDRFAMILY */ "Temporary failure in name resolution", /* EAI_AGAIN */ "Invalid value for ai_flags", /* EAI_BADFLAGS */ "Non-recoverable failure in name resolution", /* EAI_FAIL */ "ai_family not supported", /* EAI_FAMILY */ "Memory allocation failure", /* EAI_MEMORY */ "No address associated with hostname", /* EAI_NODATA */ "hostname nor servname provided, or not known", /* EAI_NONAME */ "servname not supported for ai_socktype", /* EAI_SERVICE */ "ai_socktype not supported", /* EAI_SOCKTYPE */ "System error returned in errno", /* EAI_SYSTEM */ "Invalid value for hints", /* EAI_BADHINTS */ "Resolved protocol is unknown", /* EAI_PROTOCOL */ "Unknown error", /* EAI_MAX */ }; /* XXX macros that make external reference is BAD. */ #define GET_AI(ai, afd, addr) \ do { \ /* external reference: pai, error, and label free */ \ (ai) = get_ai(pai, (afd), (addr)); \ if ((ai) == NULL) { \ error = EAI_MEMORY; \ goto free; \ } \ } while (0) #define GET_PORT(ai, serv) \ do { \ /* external reference: error and label free */ \ error = get_port((ai), (serv), 0); \ if (error != 0) \ goto free; \ } while (0) #define GET_CANONNAME(ai, str) \ do { \ /* external reference: pai, error and label free */ \ error = get_canonname(pai, (ai), (str)); \ if (error != 0) \ goto free; \ } while (0) #define ERR(err) \ do { \ /* external reference: error, and label bad */ \ error = (err); \ goto bad; \ } while (0) #define MATCH_FAMILY(x, y, w) \ ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) #define MATCH(x, y, w) \ ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY))) char * gai_strerror(ecode) int ecode; { if (ecode < 0 || ecode > EAI_MAX) ecode = EAI_MAX; return ai_errlist[ecode]; } void freeaddrinfo(ai) struct addrinfo *ai; { struct addrinfo *next; do { next = ai->ai_next; if (ai->ai_canonname) free(ai->ai_canonname); /* no need to free(ai->ai_addr) */ free(ai); } while ((ai = next) != NULL); } static int str_isnumber(p) const char *p; { char *q = (char *)p; while (*q) { if (! isdigit(*q)) return NO; q++; } return YES; } int getaddrinfo(hostname, servname, hints, res) const char *hostname, *servname; const struct addrinfo *hints; struct addrinfo **res; { struct addrinfo sentinel; struct addrinfo *cur; int error = 0; struct addrinfo ai; struct addrinfo ai0; struct addrinfo *pai; const struct afd *afd; const struct explore *ex; #ifdef FAITH static int firsttime = 1; if (firsttime) { /* translator hack */ char *q = getenv("GAI"); if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) translate = YES; firsttime = 0; } #endif sentinel.ai_next = NULL; cur = &sentinel; pai = &ai; pai->ai_flags = 0; pai->ai_family = PF_UNSPEC; pai->ai_socktype = ANY; pai->ai_protocol = ANY; pai->ai_addrlen = 0; pai->ai_canonname = NULL; pai->ai_addr = NULL; pai->ai_next = NULL; if (hostname == NULL && servname == NULL) return EAI_NONAME; if (hints) { /* error check for hints */ if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) ERR(EAI_BADHINTS); /* xxx */ if (hints->ai_flags & ~AI_MASK) ERR(EAI_BADFLAGS); switch (hints->ai_family) { case PF_UNSPEC: case PF_INET: #ifdef INET6 case PF_INET6: #endif break; default: ERR(EAI_FAMILY); } memcpy(pai, hints, sizeof(*pai)); /* * if both socktype/protocol are specified, check if they * are meaningful combination. */ if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { for (ex = explore; ex->e_af >= 0; ex++) { if (pai->ai_family != ex->e_af) continue; if (ex->e_socktype == ANY) continue; if (ex->e_protocol == ANY) continue; if (pai->ai_socktype == ex->e_socktype && pai->ai_protocol != ex->e_protocol) { ERR(EAI_BADHINTS); } } } } /* * check for special cases. (1) numeric servname is disallowed if * socktype/protocol are left unspecified. (2) servname is disallowed * for raw and other inet{,6} sockets. */ if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) #ifdef PF_INET6 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) #endif ) { ai0 = *pai; if (pai->ai_family == PF_UNSPEC) { #ifdef PF_INET6 pai->ai_family = PF_INET6; #else pai->ai_family = PF_INET; #endif } error = get_portmatch(pai, servname); if (error) ERR(error); *pai = ai0; } ai0 = *pai; /* NULL hostname, or numeric hostname */ for (ex = explore; ex->e_af >= 0; ex++) { *pai = ai0; if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) continue; if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) continue; if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) continue; if (pai->ai_family == PF_UNSPEC) pai->ai_family = ex->e_af; if (pai->ai_socktype == ANY && ex->e_socktype != ANY) pai->ai_socktype = ex->e_socktype; if (pai->ai_protocol == ANY && ex->e_protocol != ANY) pai->ai_protocol = ex->e_protocol; if (hostname == NULL) error = explore_null(pai, hostname, servname, &cur->ai_next); else error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); if (error) goto free; while (cur && cur->ai_next) cur = cur->ai_next; } /* * XXX * If numreic representation of AF1 can be interpreted as FQDN * representation of AF2, we need to think again about the code below. */ if (sentinel.ai_next) goto good; if (pai->ai_flags & AI_NUMERICHOST) ERR(EAI_NONAME); if (hostname == NULL) ERR(EAI_NONAME); /* * hostname as alphabetical name. * we would like to prefer AF_INET6 than AF_INET, so we'll make a * outer loop by AFs. */ for (afd = afdl; afd->a_af; afd++) { *pai = ai0; if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) continue; for (ex = explore; ex->e_af >= 0; ex++) { *pai = ai0; if (pai->ai_family == PF_UNSPEC) pai->ai_family = afd->a_af; if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) continue; if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) { continue; } if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) { continue; } if (pai->ai_family == PF_UNSPEC) pai->ai_family = ex->e_af; if (pai->ai_socktype == ANY && ex->e_socktype != ANY) pai->ai_socktype = ex->e_socktype; if (pai->ai_protocol == ANY && ex->e_protocol != ANY) pai->ai_protocol = ex->e_protocol; error = explore_fqdn(pai, hostname, servname, &cur->ai_next); while (cur && cur->ai_next) cur = cur->ai_next; } } /* XXX */ if (sentinel.ai_next) error = 0; if (error) goto free; if (error == 0) { if (sentinel.ai_next) { good: *res = sentinel.ai_next; return SUCCESS; } else error = EAI_FAIL; } free: bad: if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); *res = NULL; return error; } /* * FQDN hostname, DNS lookup */ static int explore_fqdn(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res; { struct hostent *hp; int h_error; int af; char **aplist = NULL, *apbuf = NULL; char *ap; struct addrinfo sentinel, *cur; int i; #ifndef USE_GETIPNODEBY int naddrs; #endif const struct afd *afd; int error; *res = NULL; sentinel.ai_next = NULL; cur = &sentinel; /* * Do not filter unsupported AFs here. We need to honor content of * databases (/etc/hosts, DNS and others). Otherwise we cannot * replace gethostbyname() by getaddrinfo(). */ /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); /* * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG) * rather than hardcoding it. we may need to add AI_ADDRCONFIG * handling code by ourselves in case we don't have getipnodebyname(). */ #ifdef USE_GETIPNODEBY hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error); #else #ifdef HAVE_GETHOSTBYNAME2 hp = gethostbyname2(hostname, pai->ai_family); #else if (pai->ai_family != AF_INET) return 0; hp = gethostbyname(hostname); #ifdef HAVE_H_ERRNO h_error = h_errno; #else h_error = EINVAL; #endif #endif /*HAVE_GETHOSTBYNAME2*/ #endif /*USE_GETIPNODEBY*/ if (hp == NULL) { switch (h_error) { case HOST_NOT_FOUND: case NO_DATA: error = EAI_NODATA; break; case TRY_AGAIN: error = EAI_AGAIN; break; case NO_RECOVERY: case NETDB_INTERNAL: default: error = EAI_FAIL; break; } } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || (hp->h_addr_list[0] == NULL)) { #ifdef USE_GETIPNODEBY freehostent(hp); #endif hp = NULL; error = EAI_FAIL; } if (hp == NULL) goto free; #ifdef USE_GETIPNODEBY aplist = hp->h_addr_list; #else /* * hp will be overwritten if we use gethostbyname2(). * always deep copy for simplification. */ for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++) ; naddrs++; aplist = (char **)malloc(sizeof(aplist[0]) * naddrs); apbuf = (char *)malloc(hp->h_length * naddrs); if (aplist == NULL || apbuf == NULL) { error = EAI_MEMORY; goto free; } memset(aplist, 0, sizeof(aplist[0]) * naddrs); for (i = 0; i < naddrs; i++) { if (hp->h_addr_list[i] == NULL) { aplist[i] = NULL; continue; } memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i], hp->h_length); aplist[i] = &apbuf[i * hp->h_length]; } #endif for (i = 0; aplist[i] != NULL; i++) { af = hp->h_addrtype; ap = aplist[i]; #ifdef AF_INET6 if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { af = AF_INET; ap = ap + sizeof(struct in6_addr) - sizeof(struct in_addr); } #endif if (af != pai->ai_family) continue; if ((pai->ai_flags & AI_CANONNAME) == 0) { GET_AI(cur->ai_next, afd, ap); GET_PORT(cur->ai_next, servname); } else { /* * if AI_CANONNAME and if reverse lookup * fail, return ai anyway to pacify * calling application. * * XXX getaddrinfo() is a name->address * translation function, and it looks * strange that we do addr->name * translation here. */ get_name(ap, afd, &cur->ai_next, ap, pai, servname); } while (cur && cur->ai_next) cur = cur->ai_next; } *res = sentinel.ai_next; return 0; free: #ifdef USE_GETIPNODEBY if (hp) freehostent(hp); #endif if (aplist) free(aplist); if (apbuf) free(apbuf); if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return error; } /* * hostname == NULL. * passive socket -> anyaddr (0.0.0.0 or ::) * non-passive socket -> localhost (127.0.0.1 or ::1) */ static int explore_null(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res; { int s; const struct afd *afd; struct addrinfo *cur; struct addrinfo sentinel; int error; *res = NULL; sentinel.ai_next = NULL; cur = &sentinel; /* * filter out AFs that are not supported by the kernel * XXX errno? */ s = socket(pai->ai_family, SOCK_DGRAM, 0); if (s < 0) { if (errno != EMFILE) return 0; } else close(s); /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); if (pai->ai_flags & AI_PASSIVE) { GET_AI(cur->ai_next, afd, afd->a_addrany); /* xxx meaningless? * GET_CANONNAME(cur->ai_next, "anyaddr"); */ GET_PORT(cur->ai_next, servname); } else { GET_AI(cur->ai_next, afd, afd->a_loopback); /* xxx meaningless? * GET_CANONNAME(cur->ai_next, "localhost"); */ GET_PORT(cur->ai_next, servname); } cur = cur->ai_next; *res = sentinel.ai_next; return 0; free: if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return error; } /* * numeric hostname */ static int explore_numeric(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res; { const struct afd *afd; struct addrinfo *cur; struct addrinfo sentinel; int error; char pton[PTON_MAX]; int flags; *res = NULL; sentinel.ai_next = NULL; cur = &sentinel; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); flags = pai->ai_flags; if (inet_pton(afd->a_af, hostname, pton) == 1) { u_int32_t v4a; #ifdef INET6 u_char pfx; #endif switch (afd->a_af) { case AF_INET: v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr); if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) flags &= ~AI_CANONNAME; v4a >>= IN_CLASSA_NSHIFT; if (v4a == 0 || v4a == IN_LOOPBACKNET) flags &= ~AI_CANONNAME; break; #ifdef INET6 case AF_INET6: pfx = ((struct in6_addr *)pton)->s6_addr[0]; if (pfx == 0 || pfx == 0xfe || pfx == 0xff) flags &= ~AI_CANONNAME; break; #endif } if (pai->ai_family == afd->a_af || pai->ai_family == PF_UNSPEC /*?*/) { if ((flags & AI_CANONNAME) == 0) { GET_AI(cur->ai_next, afd, pton); GET_PORT(cur->ai_next, servname); } else { /* * if AI_CANONNAME and if reverse lookup * fail, return ai anyway to pacify * calling application. * * XXX getaddrinfo() is a name->address * translation function, and it looks * strange that we do addr->name * translation here. */ get_name(pton, afd, &cur->ai_next, pton, pai, servname); } while (cur && cur->ai_next) cur = cur->ai_next; } else ERR(EAI_FAMILY); /*xxx*/ } *res = sentinel.ai_next; return 0; free: bad: if (sentinel.ai_next) freeaddrinfo(sentinel.ai_next); return error; } /* * numeric hostname with scope */ static int explore_numeric_scope(pai, hostname, servname, res) const struct addrinfo *pai; const char *hostname; const char *servname; struct addrinfo **res; { #ifndef SCOPE_DELIMITER return explore_numeric(pai, hostname, servname, res); #else const struct afd *afd; struct addrinfo *cur; int error; char *cp, *hostname2 = NULL; int scope; struct sockaddr_in6 *sin6; /* * if the servname does not match socktype/protocol, ignore it. */ if (get_portmatch(pai, servname) != 0) return 0; afd = find_afd(pai->ai_family); if (!afd->a_scoped) return explore_numeric(pai, hostname, servname, res); cp = strchr(hostname, SCOPE_DELIMITER); if (cp == NULL) return explore_numeric(pai, hostname, servname, res); /* * Handle special case of */ hostname2 = strdup(hostname); if (hostname2 == NULL) return EAI_MEMORY; /* terminate at the delimiter */ hostname2[cp - hostname] = '\0'; cp++; switch (pai->ai_family) { #ifdef INET6 case AF_INET6: scope = if_nametoindex(cp); if (scope == 0) { free(hostname2); return (EAI_NONAME); } break; #endif } error = explore_numeric(pai, hostname2, servname, res); if (error == 0) { for (cur = *res; cur; cur = cur->ai_next) { if (cur->ai_family != AF_INET6) continue; sin6 = (struct sockaddr_in6 *)cur->ai_addr; if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) sin6->sin6_scope_id = scope; } } free(hostname2); return error; #endif } static int get_name(addr, afd, res, numaddr, pai, servname) const char *addr; const struct afd *afd; struct addrinfo **res; char *numaddr; const struct addrinfo *pai; const char *servname; { struct hostent *hp = NULL; struct addrinfo *cur = NULL; int error = 0; char *ap = NULL, *cn = NULL; #ifdef USE_GETIPNODEBY int h_error; hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); #else hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); #endif if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { #ifdef USE_GETIPNODEBY GET_AI(cur, afd, hp->h_addr_list[0]); GET_PORT(cur, servname); GET_CANONNAME(cur, hp->h_name); #else /* hp will be damaged if we use gethostbyaddr() */ if ((ap = (char *)malloc(hp->h_length)) == NULL) { error = EAI_MEMORY; goto free; } memcpy(ap, hp->h_addr_list[0], hp->h_length); if ((cn = strdup(hp->h_name)) == NULL) { error = EAI_MEMORY; goto free; } GET_AI(cur, afd, ap); GET_PORT(cur, servname); GET_CANONNAME(cur, cn); free(ap); ap = NULL; free(cn); cn = NULL; #endif } else { GET_AI(cur, afd, numaddr); GET_PORT(cur, servname); } #ifdef USE_GETIPNODEBY if (hp) freehostent(hp); #endif *res = cur; return SUCCESS; free: if (cur) freeaddrinfo(cur); if (ap) free(ap); if (cn) free(cn); #ifdef USE_GETIPNODEBY if (hp) freehostent(hp); #endif *res = NULL; return error; } static int get_canonname(pai, ai, str) const struct addrinfo *pai; struct addrinfo *ai; const char *str; { if ((pai->ai_flags & AI_CANONNAME) != 0) { ai->ai_canonname = (char *)malloc(strlen(str) + 1); if (ai->ai_canonname == NULL) return EAI_MEMORY; strcpy(ai->ai_canonname, str); } return 0; } static struct addrinfo * get_ai(pai, afd, addr) const struct addrinfo *pai; const struct afd *afd; const char *addr; { char *p; struct addrinfo *ai; ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + (afd->a_socklen)); if (ai == NULL) return NULL; memcpy(ai, pai, sizeof(struct addrinfo)); ai->ai_addr = (struct sockaddr *)(ai + 1); memset(ai->ai_addr, 0, afd->a_socklen); #ifdef HAVE_SOCKADDR_SA_LEN ai->ai_addr->sa_len = afd->a_socklen; #endif ai->ai_addrlen = afd->a_socklen; ai->ai_addr->sa_family = ai->ai_family = afd->a_af; p = (char *)(ai->ai_addr); memcpy(p + afd->a_off, addr, afd->a_addrlen); return ai; } static int get_portmatch(ai, servname) const struct addrinfo *ai; const char *servname; { /* get_port does not touch first argument. when matchonly == 1. */ return get_port((struct addrinfo *)ai, servname, 1); } static int get_port(ai, servname, matchonly) struct addrinfo *ai; const char *servname; int matchonly; { const char *proto; struct servent *sp; int port; int allownumeric; if (servname == NULL) return 0; switch (ai->ai_family) { case AF_INET: #ifdef AF_INET6 case AF_INET6: #endif break; default: return 0; } switch (ai->ai_socktype) { case SOCK_RAW: return EAI_SERVICE; case SOCK_DGRAM: case SOCK_STREAM: allownumeric = 1; break; case ANY: allownumeric = 0; break; default: return EAI_SOCKTYPE; } if (str_isnumber(servname)) { if (!allownumeric) return EAI_SERVICE; port = htons(atoi(servname)); if (port < 0 || port > 65535) return EAI_SERVICE; } else { switch (ai->ai_socktype) { case SOCK_DGRAM: proto = "udp"; break; case SOCK_STREAM: proto = "tcp"; break; default: proto = NULL; break; } if ((sp = getservbyname(servname, proto)) == NULL) return EAI_SERVICE; port = sp->s_port; } if (!matchonly) { switch (ai->ai_family) { case AF_INET: ((struct sockaddr_in *)ai->ai_addr)->sin_port = port; break; #ifdef INET6 case AF_INET6: ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port; break; #endif } } return 0; } static const struct afd * find_afd(af) int af; { const struct afd *afd; if (af == PF_UNSPEC) return NULL; for (afd = afdl; afd->a_af; afd++) { if (afd->a_af == af) return afd; } return NULL; } nuttcp-6.1.2/missing/fakepoll.h0000664000222400001560000001075507741403104016215 0ustar robmusketeers// fakepoll.h // poll using select // Warning: a call to this poll() takes about 4K of stack space. // Greg Parker gparker-web@sealiesoftware.com December 2000 // This code is in the public domain and may be copied or modified without // permission. // Updated May 2002: // * fix crash when an fd is less than 0 // * set errno=EINVAL if an fd is greater or equal to FD_SETSIZE // * don't set POLLIN or POLLOUT in revents if it wasn't requested // in events (only happens when an fd is in the poll set twice) #ifndef _FAKE_POLL_H #define _FAKE_POLL_H #include #ifndef FD_SETSIZE #define FD_SETSIZE OPEN_MAX #endif #include #include #include #include typedef struct pollfd { int fd; /* file desc to poll */ short events; /* events of interest on fd */ short revents; /* events that occurred on fd */ } pollfd_t; // poll flags #define POLLIN 0x0001 #define POLLOUT 0x0004 #define POLLERR 0x0008 // synonyms #define POLLNORM POLLIN #define POLLPRI POLLIN #define POLLRDNORM POLLIN #define POLLRDBAND POLLIN #define POLLWRNORM POLLOUT #define POLLWRBAND POLLOUT // ignored #define POLLHUP 0x0010 #define POLLNVAL 0x0020 inline int poll(struct pollfd *pollSet, int pollCount, int pollTimeout) { struct timeval tv; struct timeval *tvp; fd_set readFDs, writeFDs, exceptFDs; fd_set *readp, *writep, *exceptp; struct pollfd *pollEnd, *p; int selected; int result; int maxFD; if (!pollSet) { pollEnd = NULL; readp = NULL; writep = NULL; exceptp = NULL; maxFD = 0; } else { pollEnd = pollSet + pollCount; readp = &readFDs; writep = &writeFDs; exceptp = &exceptFDs; FD_ZERO(readp); FD_ZERO(writep); FD_ZERO(exceptp); // Find the biggest fd in the poll set maxFD = 0; for (p = pollSet; p < pollEnd; p++) { if (p->fd > maxFD) maxFD = p->fd; } if (maxFD >= FD_SETSIZE) { // At least one fd is too big errno = EINVAL; return -1; } // Transcribe flags from the poll set to the fd sets for (p = pollSet; p < pollEnd; p++) { if (p->fd < 0) { // Negative fd checks nothing and always reports zero } else { if (p->events & POLLIN) FD_SET(p->fd, readp); if (p->events & POLLOUT) FD_SET(p->fd, writep); if (p->events != 0) FD_SET(p->fd, exceptp); // POLLERR is never set coming in; poll() always reports errors // But don't report if we're not listening to anything at all. } } } // poll timeout is in milliseconds. Convert to struct timeval. // poll timeout == -1 : wait forever : select timeout of NULL // poll timeout == 0 : return immediately : select timeout of zero if (pollTimeout >= 0) { tv.tv_sec = pollTimeout / 1000; tv.tv_usec = (pollTimeout % 1000) * 1000; tvp = &tv; } else { tvp = NULL; } selected = select(maxFD+1, readp, writep, exceptp, tvp); if (selected < 0) { // Error during select result = -1; } else if (selected > 0) { // Select found something // Transcribe result from fd sets to poll set. // Also count the number of selected fds. poll returns the // number of ready fds; select returns the number of bits set. int polled = 0; for (p = pollSet; p < pollEnd; p++) { p->revents = 0; if (p->fd < 0) { // Negative fd always reports zero } else { if ((p->events & POLLIN) && FD_ISSET(p->fd, readp)) { p->revents |= POLLIN; } if ((p->events & POLLOUT) && FD_ISSET(p->fd, writep)) { p->revents |= POLLOUT; } if ((p->events != 0) && FD_ISSET(p->fd, exceptp)) { p->revents |= POLLERR; } if (p->revents) polled++; } } result = polled; } else { // selected == 0, select timed out before anything happened // Clear all result bits and return zero. for (p = pollSet; p < pollEnd; p++) { p->revents = 0; } result = 0; } return result; } #endif nuttcp-6.1.2/missing/bittypes.h0000664000222400001560000000451107006476773016274 0ustar robmusketeers/* * Copyright (C) 1999 WIDE Project. * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. */ #ifndef HAVE_U_INT8_T #if SIZEOF_CHAR == 1 typedef unsigned char u_int8_t; #elif SIZEOF_INT == 1 typedef unsigned int u_int8_t; #else /* XXX */ #error "there's no appropriate type for u_int8_t" #endif #endif /* HAVE_U_INT8_T */ #ifndef HAVE_U_INT16_T #if SIZEOF_SHORT == 2 typedef unsigned short u_int16_t; #elif SIZEOF_INT == 2 typedef unsigned int u_int16_t; #elif SIZEOF_CHAR == 2 typedef unsigned char u_int16_t; #else /* XXX */ #error "there's no appropriate type for u_int16_t" #endif #endif /* HAVE_U_INT16_T */ #ifndef HAVE_U_INT32_T #if SIZEOF_INT == 4 typedef unsigned int u_int32_t; #elif SIZEOF_LONG == 4 typedef unsigned long u_int32_t; #elif SIZEOF_SHORT == 4 typedef unsigned short u_int32_t; #else /* XXX */ #error "there's no appropriate type for u_int32_t" #endif #endif /* HAVE_U_INT32_T */ nuttcp-6.1.2/Makefile0000644000222400001560000000377311140132177014233 0ustar robmusketeersAPP = nuttcp-6.1.2 #EXTRAVERSION=-pre1 CC = gcc -Wall #OPT = -g -O0 OPT = -O3 CFLAGS = $(OPT) $(NOIPV6) LIBS = ifneq ($(NOIPV6),) APPEXTV6=-noipv6 endif APPEXT = $(APPEXTV6) CFLAGS.MISSING = -Imissing -DHAVE_CONFIG_H OBJS.GETADD = getaddrinfo.o OBJS.INETFUN = inet_ntop.o inet_pton.o inet_aton.o TAR = tar all: $(APP)$(EXTRAVERSION)$(APPEXT) uniosx: $(MAKE) OPT="-O3 -arch i386 -arch ppc" sgicc32: $(MAKE) CC="cc -n32" OPT="-O -OPT:Olimit=0" sgicc: $(MAKE) CC=cc OPT="-O -OPT:Olimit=0" sol28: $(MAKE) LIBS="-lsocket -lnsl" sol28cc: $(MAKE) CC=cc OPT=-O LIBS="-lsocket -lnsl" sol26: $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS.MISSING)" LIBS="$(OBJS.GETADD) $(OBJS.INETFUN) -lsocket -lnsl" sol26cc: $(MAKE) CC=cc OPT=-O CFLAGS="-O $(NOIPV6) $(CFLAGS.MISSING)" LIBS="$(OBJS.GETADD) $(OBJS.INETFUN) -lsocket -lnsl" cyg: $(MAKE) APPEXT=".exe" oldcyg: $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS.MISSING)" LIBS="$(OBJS.GETADD) $(OBJS.INETFUN)" APPEXT=".exe" win32: $(MAKE) LIBS="$(OBJS.INETFUN) -Lwin32 -llibc.a -Bstatic" APPEXT=".exe" icc: $(MAKE) CC=icc OPT=-O2 # $(MAKE) CC=icc OPT="-w -O3 -parallel -unroll -align -xM -vec_report -par_report2" $(APP)$(EXTRAVERSION)$(APPEXT): $(APP)$(EXTRAVERSION).c $(LIBS) $(CC) $(CFLAGS) -o $@ $< $(LIBS) inet_ntop.o: missing/inet_ntop.c missing/config.h $(CC) $(CFLAGS.MISSING) -o $@ -c $< inet_pton.o: missing/inet_pton.c missing/config.h $(CC) $(CFLAGS.MISSING) -o $@ -c $< inet_aton.o: missing/inet_aton.c missing/config.h $(CC) $(CFLAGS.MISSING) -o $@ -c $< getaddrinfo.o: missing/getaddrinfo.c missing/config.h $(CC) $(CFLAGS.MISSING) -o $@ -c $< clean: rm -f $(APP)$(EXTRAVERSION)$(APPEXT) $(APP)$(EXTRAVERSION).o $(OBJS.GETADD) $(OBJS.INETFUN) tar: (cd ..; $(TAR) cfj $(APP)$(EXTRAVERSION).tar.bz2 --exclude $(APP)/bin --exclude $(APP)/cygwin/*.bz2 --exclude $(APP)/rpm $(APP)$(EXTRAVERSION)$(APPEXT)) (cd ..; $(TAR) cfj $(APP)$(EXTRAVERSION).rpm.tar.bz2 --exclude $(APP)/bin --exclude $(APP)/cygwin --exclude $(APP)/missing --exclude $(APP)/rpm $(APP)$(EXTRAVERSION)$(APPEXT)) nuttcp-6.1.2/nuttcp.html0000664000222400001560000004566110561051555015010 0ustar robmusketeersContent-type: text/html Manpage of NUTTCP

NUTTCP

Section: Under Construction (8)
Updated: 3 February 2007
Index Return to Main Contents
 

NAME

nuttcp - network performance measurement tool  

SYNOPSIS

nuttcp -h
nuttcp -V
nuttcp -t [ -bdDsuv ] [ -c dscp_value ] [ -l buffer_len ] [ -n num_bufs ]

           [ -w window_size ] [ -ws server_window ] [ -wb ]

           [ -p data_port ] [ -P control_port ]

           [ -N num_streams ] [ -R xmit_rate_limit [m|g] ]

           [ -T xmit_timeout [m] ] host [ < input ]
nuttcp -r [ -bBdsuv ] [ -c dscp_value ] [ -l buffer_len ] [ -n num_bufs ]

           [ -w window_size ] [ -ws server_window ] [ -wb ]

           [ -p data_port ] [ -P control_port ]

           [ -N num_streams ] [ -R xmit_rate_limit [m|g] ]

           [ -T xmit_timeout [m] ] [ host ] [ > output ]
nuttcp -S [ -P control_port ]
nuttcp -1 [ -P control_port ]  

DESCRIPTION

nuttcp is a network performance measurement tool intended for use by network and system managers. Its most basic usage is to determine the raw TCP (or UDP) network layer throughput by transferring memory buffers from a source system across an interconnecting network to a destination system, either transferring data for a specified time interval, or alternatively transferring a specified number of bytes. In addition to reporting the achieved network throughput in Mbps, nuttcp also provides additional useful information related to the data transfer such as user, system, and wall-clock time, transmitter and receiver CPU utilization, and loss percentage (for UDP transfers).

nuttcp is based on nttcp, which in turn was an enhancement by someone at Silicon Graphics (SGI) on the original ttcp, which was written by Mike Muuss at BRL sometime before December 1984, to compare the performance of TCP stacks by U.C. Berkeley and BBN to help DARPA decide which version to place in the first BSD Unix release. nuttcp has several useful features beyond those of the basic ttcp/nttcp, such as a server mode, rate limiting, multiple parallel streams, and timer based usage. More recent changes include IPv6 support, IPv4 multicast, and the ability to set the maximum segment size or TOS/DSCP bits. nuttcp is continuing to evolve to meet new requirements that arise and to add desired new features. nuttcp has been successfully built and run on a variety of Solaris, SGI, and PPC/X86 Linux systems, and should probably work fine on most flavors of Unix. It has also been used successfully on various versions of the Windows operating system.

There are two basic modes of operation for nuttcp. The original or classic mode is the transmitter/receiver mode, which is also the way the original ttcp and nttcp worked. In this mode, a receiver is first initiated on the destination host using "nuttcp -r", and then a transmitter must be started on the source host using "nuttcp -t". This mode is somewhat deprecated and is no longer recommended for general use. The preferred and recommended mode of operation for nuttcp is the new client/server mode. With this mode, a server is first started on one system using "nuttcp -S" (or "nuttcp -1"), and then a client may either transmit data to (using "nuttcp -t") or receive data from (using "nuttcp -r") the server system. All the information provided by nuttcp is reported by the client, including the information from the server, thus providing a full snapshot of both the transmitter and receiver ends of the data transfer.

The server may be started by a normal, non-privileged user by issuing either a "nuttcp -S" or a "nuttcp -1" command. However, the optimal and recommended method of running a server is to run "nuttcp -S" via the inetd/xinetd daemon. This method has several significant advantages, including being more robust, allowing multiple simultaneous connections, and providing for access control over who is allowed to use the nuttcp server via the hosts.allow (and hosts.deny) file. By default, the nuttcp server listens for commands on port 5000, and the actual nuttcp data transfers take place on port 5001.

The host parameter must be specified for the transmitter, and provides the host name or IP address of the receiver. In classic transmitter/receiver mode, the host parameter may not be specified for the receiver. In client/server mode, when the client is the receiver, the host parameter specifies the host name or IP address of the transmitter (server).

Normally, a nuttcp data transfer is memory-to-memory. However, by using the "-s" option, it is possible to also perform memory-to-disk, disk-to-memory, and disk-to-disk data transfers. Using the "-s" option with the transmitter will cause nuttcp to read its data from the standard input instead of using a prefabricated memory buffer, while using the "-s" option on the receiver causes nuttcp to write its data to standard output. All these types of data transfers are possible with the classic transmitter/receiver mode. For security reasons, the "-s" option is disabled on the server, so it is not possible to access the disk on the server side of a data transfer.

The allowed options to nuttcp are:  

OPTIONS

-h
Print out a usage statement. Running nuttcp with no arguments will also produce a usage statement.
-V
Prints the nuttcp version number. The nuttcp version is also printed as part of the normal nuttcp output when the "-v" verbose output is used (but not when using the default brief output). In client/server mode, the version number of both the client and server is identified.
-t
Indicates that this nuttcp is the transmitter. In client/server mode, this means the server specified by the host parameter is the receiver.
-r
Indicates that this nuttcp is the receiver. In client/server mode, this means the server specified by the host parameter is the transmitter.
-S
Indicates that this nuttcp is the server. The only option that may be specified to the server is the "-P" option, which allows one to change the control port used by the server, but only when the server is started by a normal, non-privileged user. When the server is initiated by inetd/xinetd, the server control port should be specified in the services file.
-1
Basically the same as the "-S" option, but indicates a one-shot server, i.e. the server exits after the first data transfer initiated by a client. The "-1" option should only be used when the server is started by a normal, non-privileged user. This option will probably rarely need to be used, but can be useful for a quick test and eliminates the possibilty of leaving a non-access controlled nuttcp server running on the system (which can happen when using the "-S" option and forgetting to kill the nuttcp server after finishing a series of tests).
-b
Produce brief one-line output, which includes the amount of data transferred in MB (1024**2 bytes), the time interval in seconds, the TCP (or UDP) network throughput in Mbps (millions of bits per second), the transmitter and/or receiver CPU utilization, and for UDP data transfers also outputs the loss percentage. In client/server mode, most of the printed statistics are from the viewpoint of the receiver. This is the default output format.
-B
This option is only valid for the receiver, and forces the receiver to read a full buffer (as specified by the "-l" buffer length option) from the network. It is mainly intended to be used with the "-s" option to only output full buffers to standard output (e.g. for use with tar). It is also implicitly set whenever the number of streams as specified by the "-N" option is greater than 1. This option is not passed to the server.
-d
For TCP data transfers, sets the SO_DEBUG option on the data socket. This option is not passed to the server. It is a rarely used option which may possibly be removed or renamed in a future version of nuttcp.
-D
This option is only valid for the transmitter, and only for TCP data transfers, in which case it sets the TCP_NODELAY option on the data socket, which turns off the Nagle algorithm causing data packets to be sent as soon as possible without introducing any unnecessary delays. This option is not passed to the server. It is a rarely used option which may possibly be removed or renamed in a future version of nuttcp.
-s
Setting the "-s" option causes nuttcp to either read its data from standard input rather than using prefabricated memory buffers (for "nuttcp -t"), or to write its data out to standard output (for "nuttcp -r"). The "-s" option is disabled for security reasons on the server.
-u
Use UDP for the data transfer instead of the default of TCP.
-v
Verbose output that provides some additional information related to the data transfer. In client/server mode, the server is always verbose (implicit "-v" option), but the client controls the extent and type of output via the "-v" and "-b" options.
-cdscp_value
Sets the socket option to support COS. Either takes a dscp value or with the t|T modifier it takes the full TOS field.
-lbuffer_len
Length of the network write/read buffer in bytes for the transmitter/receiver. It defaults to 64 KB (65536) for TCP data transfers and to 8 KB (8192) for UDP. For client/server mode, it sets both the client and server buffer lengths.
-nnum_bufs
Specifies the number of source buffers written to the network (default is unlimited), and is ignored by the receiver. For client/server mode, if the client issues a "nuttcp -r" command making it the receiver, this parameter is passed to the server since the server is the transmitter in this case. This parameter is also ignored if the "-s" parameter is specified to the transmitter.
-wwindow_size
Indicates the window size in KB of the transmitter (for "nuttcp -t") or receiver (for "nuttcp -r"). Actually, to be technically correct, it sets the sender or receiver TCP socket buffer size, which then effectively sets the window size. For client/server mode, both the transmitter and receiver window sizes are set. The default window size is architecture and system dependent. Note recent Linux systems, out of a misguided desire to be helpful, double whatever window size is actually specified by the user (this is not a bug with nuttcp but a bug/feature of the Linux kernel). Also, with these Linux systems, the actual window size that's used on the intervening network, as observed with tcpdump, is greater than the requested window size, but less than the doubled value set by Linux.
-wsserver_window
For client/server mode, the "-ws" option provides a mechanism for setting a different window size on the server than the client window size as specified with the "-w" option.
-wb
Normally, to conserve memory, the transmitter only sets the TCP send socket buffer size and the receiver only sets the TCP receive socket buffer size. However, if the "-wb" option is used, the transmitter will also set the TCP receive socket buffer size and the receiver will also set the TCP send socket buffer size. Under normal circumstances, this should never be necessary. This option was implemented because certain early braindead Solaris 2.8 systems would not properly set the TCP window size unless both the TCP send and receive socket buffer sizes were set (later Solaris 2.8 systems have corrected this deficiency). Thus the 'b' in this option can stand either for "braindead" or "both".
-pdata_port
Port number used for the data connection, which defaults to port 5001. If multiple streams are specified with the "-N" option, the "-p" option specifies the starting port number for the data connection. For example, if four streams are specified using the default data connection port number, nuttcp will use ports 5001, 5002, 5003, and 5004 for the four TCP (or UDP) connections used to perform the data transfer.
-Pcontrol_port
For client/server mode, specifies the port number used for the control connection between the client and server, and defaults to port 5000. On the server side, the "-P" option should only be used when the server is started manually by the user. If the server is started by inetd/xinetd (the preferred method), the control connection must be specified by adding a nuttcp entry to the services file.
-Nnum_streams
Species the number of parallel TCP (or UDP) data streams to be used for the data transfer, with the default being a single data stream. The maximum number of parallel data streams that can be used is 128. If the number of streams is greater than one, the "-B" option is implicitly set. The current implementation does not fork off separate processes for each data stream, so specifying multiple streams on an SMP machine will not take advantage of its multiple processors. Of course it is always possible to run multiple nuttcp commands in parallel on an SMP system to determine if there is any advantage to running on multiple processors. This is especially simple to do when running in client/server mode when the server is started from the inetd/xinetd daemon. When running multiple nuttcp commands in parallel, the "-T" transmitter timeout option may be used to insure that all the nuttcp commands finish at approximately the same time.
-Rxmit_rate_limit[m|g]
The transmitter rate limit throttles the speed at which the transmitter sends data to the network, and by default is in Kbps, although the 'm' or 'g' suffix may be used to specify Mbps or Gbps. This option may be used with either TCP or UDP data streams. Because of the way this option is currently implemented, it will consume all the available CPU on the transmitter side of the connection so the "%TX" stats are not meaningful when using the rate limit option. By default the rate limit is applied to the average rate of the data transfer in real time, and not in CPU time, so if nuttcp is switched out of the processor for any reason, when it is switched back in, it is possible that the instantaneous rate may momentarily exceed the specified value. There is an 'i' qualifier to the rate limit option (specified as "-Ri") that will restrict the instantaneous rate at any given point in time to the specified value, although in this case the final rate reported by nuttcp may be less than the specified value since nuttcp won't attempt to catch up if other processes gain control of the CPU. The default is no rate limit. Note another way to throttle the throughput of TCP data streams is to reduce the window size.
-Txmit_time_limit[m]
Limits the amount of time that the transmitter will send data to the specified number of seconds, or number of minutes if the 'm' suffix is used. Normally a data transfer will either specify a fixed amount of data to send using the "-n" option, or a fixed period of time to send using the "-T" option. However, if both the "-n" and "-T" options are used, the data transfer will be stopped by whichever option takes affect first. The default is a 10 second time limit for the data transfer.

 

USAGE

Under Construction

For now, consult the README file for basic usage guidelines.  

EXAMPLES

Under Construction

For now, see the examples.txt file for some examples of using nuttcp.  

SEE ALSO

ping(8), traceroute(8), tracepath(8), pathchar(8), netstat(1), mtrace(8)  

AUTHORS

Developed by Bill Fink based on nttcp which in turn was an enhancement of the original ttcp developed by Mike Muuss at BRL. IPv6 capability and some other fixes and enhancements contributed by Rob Scott. Many useful suggestions and testing performed by Phil Dykstra and others.

The current version is available via anonymous ftp from:

ftp://ftp.lcp.nrl.navy.mil/pub/nuttcp/

The authors can be reached at nuttcp@lcp.nrl.navy.mil.  

BUGS

Please send bug reports to nuttcp-bugs@lcp.nrl.navy.mil.


 

Index

NAME
SYNOPSIS
DESCRIPTION
OPTIONS
USAGE
EXAMPLES
SEE ALSO
AUTHORS
BUGS

This document was created by man2html, using the manual pages.
Time: 09:16:29 GMT, February 03, 2007 nuttcp-6.1.2/nuttcp.c0000777000222400001560000000000011140131032016347 2nuttcp-6.1.2.custar robmusketeersnuttcp-6.1.2/examples.txt0000664000222400001560000001345510037666026015163 0ustar robmusketeersNuttcp top 5 commands: +++++++++++++++++++++++ nuttcp Good for a relatively close . This command will use the defaults which is to do a tcp transfer for 10 seconds. It will use the default window size for the hosts it is run on. It will do ipv4 if is either a v4 numeric address or is a name that resolves to a v4 address. It will do v6 if is a v6 numeric address or a name that resolves to a v6 address. [ must already have a server running] Example: [rob@damp-nrl rob]$ nuttcp damp-arl-ge 647.9830 MB / 10.01 sec = 542.9427 Mbps 9 %TX 14 %RX Note that the %TX and %RX are the cpu utilization on the transmitter and receiver. +++++++++++++++++++++++ nuttcp -w6m Good for a cross-country oc12 size link Same as above except it uses a likely much larger window size that is more appropriate for a tcp transfer with a larger bandwidth delay product. For more information on BDP and appropriate window sizing please refer to one of Phil Dykstra's DREN Conference presentations or papers. See http://sd.wareonearth.com/~phil/ [In order to utilize a 6 megabyte window both the transmit and receive systems must support that size. On some systems this requires modifying system parameters. Remember 6m is 6*1024*1024 bytes.] Example: [rob@damp-ssc rob]$ nuttcp -w6m damp-arl-ge 642.2890 MB / 10.31 sec = 522.5387 Mbps 9 %TX 5 %RX +++++++++++++++++++++++ nuttcp -u -i -Ri50m Good for checking on packet loss This nuttcp command transmits a 10 second stream of udp packets at 50Mbps. It will present interval reports once a second. The interval and final reports not only present throughput, but also packet loss. It is important to rate limit udp transfers to avoid causing network problems with your testing. If you know the bandwidth and utilization of the whole path you are testing then you can choose a different number for the rate limit. The default is to use 8192 byte buffers and this may cause undesired fragmentation. If you are still on a 1500 mtu network you should consider -l1200 to set the buffers to 1200 bytes.] Example: [rob@damp-ssc rob]$ nuttcp -u -i -Ri50m damp-asc-atm 0.3281 MB / 1.00 sec = 2.7587 Mbps 706 / 748 ~drop/pkt 94.39 ~%loss 0.3203 MB / 1.00 sec = 2.6873 Mbps 721 / 762 ~drop/pkt 94.62 ~%loss 0.2734 MB / 1.00 sec = 2.2941 Mbps 726 / 761 ~drop/pkt 95.40 ~%loss 0.2969 MB / 1.00 sec = 2.4907 Mbps 729 / 767 ~drop/pkt 95.05 ~%loss 0.2500 MB / 1.00 sec = 2.0974 Mbps 734 / 766 ~drop/pkt 95.82 ~%loss 0.2266 MB / 1.00 sec = 1.9008 Mbps 742 / 771 ~drop/pkt 96.24 ~%loss 0.2266 MB / 1.00 sec = 1.9008 Mbps 697 / 726 ~drop/pkt 96.01 ~%loss 0.2188 MB / 1.00 sec = 1.8353 Mbps 742 / 770 ~drop/pkt 96.36 ~%loss 0.2734 MB / 1.00 sec = 2.2941 Mbps 736 / 771 ~drop/pkt 95.46 ~%loss 0.2188 MB / 1.00 sec = 1.8353 Mbps 745 / 773 ~drop/pkt 96.38 ~%loss 2.6330 MB / 10.00 sec = 2.2087 Mbps 99 %TX 0 %RX 7292 / 7629 drop/pkt 95.58 %loss +++++++++++++++++++++++ nuttcp -w1m 127.0.0.1 nuttcp -w1m ::1 Good for checking a hosts internal capability Since this never goes through an actual interface it is a measure of the cpu power, memory bandwidth and tcp stack efficiency. The first one is ipv4, and the second is ipv6. If you run both it will give you a comparison of the efficiency of a host's v4 and v6 stacks. If the host is a single processor machine you can more or less double the number as the maximum it could ever perform through an actual interface. This does not test things like bus performance or nic card performance. Since this test is very dependent on system load and processor scheduling, the result will vary from test to test, so it is probably a good idea to run several to get a good measure. Example: [rob@damp-ssc rob]$ nuttcp -w1m 127.0.0.1 6340.5000 MB / 9.99 sec = 5321.5008 Mbps 68 %TX 31 %RX [rob@damp-ssc rob]$ [rob@damp-ssc rob]$ nuttcp -w1m ::1 6661.3125 MB / 10.00 sec = 5588.5398 Mbps 71 %TX 28 %RX +++++++++++++++++++++++ For any of these commands you might want to add the following options: -r runs the stream in the other direction, ie. From the server to the client -v turns on verbose reporting (the old default style) which such things as the used window size -F this flips the connect, which you don't need to understand. What you need to know is that if you are behind a NAT, or a port block, this allows you to do a receive by doing -r -F. -R[i] this limits the rate of the transmitter. This is important if you really don't want to use the maximum bandwidth that a host can produce, especially when running udp transfers. The optional extra 'i' is to have the rate limit apply instantaneously as opposed to an average which may go above and below the limit. +++++++++++++++++++++++ Running a nuttcp server: Any user on a machine can run a server by simply running the nuttcp -S command, which starts an ipv4 server. nuttcp -S -6 will start an ipv6 server which depending on the system and kernel setting may also listen on a 4to6 translation. If you get a message about address being in use you can use the -P to run the server on a different port, any client would also have to specify the same -P option to talk to it. Note that under windows port 5000 is in use and opening another server on the port does NOT give you an error, so you will always need a -P option to run a server on windows. A good example of 2 servers on 2 different ports would be: nuttcp -S nuttcp -S -6 -P5008 and the localhost client commands would be nuttcp 127.0.0.1 nuttcp -P5008 ::1 nuttcp servers automatically fork themselves into the background and run until they hit an error or are killed. For permanent availability nuttcp can be run out of inetd or xinetd, examples of which can be found on the ftp site. nuttcp-6.1.2/nuttcp.cat0000664000222400001560000005021510561051543014577 0ustar robmusketeersNUTTCP(8) Under Construction NUTTCP(8) NNAAMMEE nuttcp - network performance measurement tool SSYYNNOOPPSSIISS nnuuttttccpp --hh nnuuttttccpp --VV nnuuttttccpp --tt [ --bbddDDssuuvv ] [ --cc_d_s_c_p___v_a_l_u_e ] [ --ll_b_u_f_f_e_r___l_e_n ] [ --nn_n_u_m___b_u_f_s ] [ --ww_w_i_n_d_o_w___s_i_z_e ] [ --wwss_s_e_r_v_e_r___w_i_n_d_o_w ] [ --wwbb ] [ --pp_d_a_t_a___p_o_r_t ] [ --PP_c_o_n_t_r_o_l___p_o_r_t ] [ --NN_n_u_m___s_t_r_e_a_m_s ] [ --RR_x_m_i_t___r_a_t_e___l_i_m_i_t [m|g] ] [ --TT_x_m_i_t___t_i_m_e_o_u_t [m] ] _h_o_s_t [ << _i_n_p_u_t ] nnuuttttccpp --rr [ --bbBBddssuuvv ] [ --cc_d_s_c_p___v_a_l_u_e ] [ --ll_b_u_f_f_e_r___l_e_n ] [ --nn_n_u_m___b_u_f_s ] [ --ww_w_i_n_d_o_w___s_i_z_e ] [ --wwss_s_e_r_v_e_r___w_i_n_d_o_w ] [ --wwbb ] [ --pp_d_a_t_a___p_o_r_t ] [ --PP_c_o_n_t_r_o_l___p_o_r_t ] [ --NN_n_u_m___s_t_r_e_a_m_s ] [ --RR_x_m_i_t___r_a_t_e___l_i_m_i_t [m|g] ] [ --TT_x_m_i_t___t_i_m_e_o_u_t [m] ] [ _h_o_s_t ] [ >> _o_u_t_p_u_t ] nnuuttttccpp --SS [ --PP_c_o_n_t_r_o_l___p_o_r_t ] nnuuttttccpp --11 [ --PP_c_o_n_t_r_o_l___p_o_r_t ] DDEESSCCRRIIPPTTIIOONN nuttcp is a network performance measurement tool intended for use by network and system managers. Its most basic usage is to determine the raw TCP (or UDP) network layer throughput by transferring memory buffers from a source system across an interconnecting network to a destination system, either transferring data for a specified time interval, or alternatively transferring a specified number of bytes. In addition to reporting the achieved network throughput in Mbps, nuttcp also provides additional useful information related to the data transfer such as user, system, and wall-clock time, transmitter and receiver CPU utilization, and loss percentage (for UDP transfers). nuttcp is based on nttcp, which in turn was an enhancement by someone at Silicon Graphics (SGI) on the original ttcp, which was written by Mike Muuss at BRL sometime before December 1984, to compare the perfor- mance of TCP stacks by U.C. Berkeley and BBN to help DARPA decide which version to place in the first BSD Unix release. nuttcp has several useful features beyond those of the basic ttcp/nttcp, such as a server mode, rate limiting, multiple parallel streams, and timer based usage. More recent changes include IPv6 support, IPv4 multicast, and the abil- ity to set the maximum segment size or TOS/DSCP bits. nuttcp is con- tinuing to evolve to meet new requirements that arise and to add desired new features. nuttcp has been successfully built and run on a variety of Solaris, SGI, and PPC/X86 Linux systems, and should probably work fine on most flavors of Unix. It has also been used successfully on various versions of the Windows operating system. There are two basic modes of operation for nuttcp. The original or classic mode is the transmitter/receiver mode, which is also the way the original ttcp and nttcp worked. In this mode, a receiver is first initiated on the destination host using "nuttcp -r", and then a trans- mitter must be started on the source host using "nuttcp -t". This mode is somewhat deprecated and is no longer recommended for general use. The preferred and recommended mode of operation for nuttcp is the new client/server mode. With this mode, a server is first started on one system using "nuttcp -S" (or "nuttcp -1"), and then a client may either transmit data to (using "nuttcp -t") or receive data from (using "nuttcp -r") the server system. All the information provided by nuttcp is reported by the client, including the information from the server, thus providing a full snapshot of both the transmitter and receiver ends of the data transfer. The server may be started by a normal, non-privileged user by issuing either a "nuttcp -S" or a "nuttcp -1" command. However, the optimal and recommended method of running a server is to run "nuttcp -S" via the inetd/xinetd daemon. This method has several significant advan- tages, including being more robust, allowing multiple simultaneous con- nections, and providing for access control over who is allowed to use the nuttcp server via the hosts.allow (and hosts.deny) file. By default, the nuttcp server listens for commands on port 5000, and the actual nuttcp data transfers take place on port 5001. The _h_o_s_t parameter must be specified for the transmitter, and provides the host name or IP address of the receiver. In classic transmit- ter/receiver mode, the _h_o_s_t parameter may not be specified for the receiver. In client/server mode, when the client is the receiver, the _h_o_s_t parameter specifies the host name or IP address of the transmitter (server). Normally, a nuttcp data transfer is memory-to-memory. However, by using the "-s" option, it is possible to also perform memory-to-disk, disk-to-memory, and disk-to-disk data transfers. Using the "-s" option with the transmitter will cause nuttcp to read its data from the stan- dard input instead of using a prefabricated memory buffer, while using the "-s" option on the receiver causes nuttcp to write its data to standard output. All these types of data transfers are possible with the classic transmitter/receiver mode. For security reasons, the "-s" option is disabled on the server, so it is not possible to access the disk on the server side of a data transfer. The allowed options to nuttcp are: OOPPTTIIOONNSS --hh Print out a usage statement. Running nuttcp with no arguments will also produce a usage statement. --VV Prints the nuttcp version number. The nuttcp version is also printed as part of the normal nuttcp output when the "-v" ver- bose output is used (but not when using the default brief out- put). In client/server mode, the version number of both the client and server is identified. --tt Indicates that this nuttcp is the transmitter. In client/server mode, this means the server specified by the _h_o_s_t parameter is the receiver. --rr Indicates that this nuttcp is the receiver. In client/server mode, this means the server specified by the _h_o_s_t parameter is the transmitter. --SS Indicates that this nuttcp is the server. The only option that may be specified to the server is the "-P" option, which allows one to change the control port used by the server, but only when the server is started by a normal, non-privileged user. When the server is initiated by inetd/xinetd, the server control port should be specified in the _s_e_r_v_i_c_e_s file. --11 Basically the same as the "-S" option, but indicates a one-shot server, i.e. the server exits after the first data transfer ini- tiated by a client. The "-1" option should only be used when the server is started by a normal, non-privileged user. This option will probably rarely need to be used, but can be useful for a quick test and eliminates the possibilty of leaving a non- access controlled nuttcp server running on the system (which can happen when using the "-S" option and forgetting to kill the nuttcp server after finishing a series of tests). --bb Produce brief one-line output, which includes the amount of data transferred in MB (1024**2 bytes), the time interval in seconds, the TCP (or UDP) network throughput in Mbps (millions of bits per second), the transmitter and/or receiver CPU utilization, and for UDP data transfers also outputs the loss percentage. In client/server mode, most of the printed statistics are from the viewpoint of the receiver. This is the default output format. --BB This option is only valid for the receiver, and forces the receiver to read a full buffer (as specified by the "-l" buffer length option) from the network. It is mainly intended to be used with the "-s" option to only output full buffers to stan- dard output (e.g. for use with tar). It is also implicitly set whenever the number of streams as specified by the "-N" option is greater than 1. This option is not passed to the server. --dd For TCP data transfers, sets the SO_DEBUG option on the data socket. This option is not passed to the server. It is a rarely used option which may possibly be removed or renamed in a future version of nuttcp. --DD This option is only valid for the transmitter, and only for TCP data transfers, in which case it sets the TCP_NODELAY option on the data socket, which turns off the Nagle algorithm causing data packets to be sent as soon as possible without introducing any unnecessary delays. This option is not passed to the server. It is a rarely used option which may possibly be removed or renamed in a future version of nuttcp. --ss Setting the "-s" option causes nuttcp to either read its data from standard input rather than using prefabricated memory buffers (for "nuttcp -t"), or to write its data out to standard output (for "nuttcp -r"). The "-s" option is disabled for secu- rity reasons on the server. --uu Use UDP for the data transfer instead of the default of TCP. --vv Verbose output that provides some additional information related to the data transfer. In client/server mode, the server is always verbose (implicit "-v" option), but the client controls the extent and type of output via the "-v" and "-b" options. --cc_d_s_c_p___v_a_l_u_e Sets the socket option to support COS. Either takes a dscp value or with the t|T modifier it takes the full TOS field. --ll_b_u_f_f_e_r___l_e_n Length of the network write/read buffer in bytes for the trans- mitter/receiver. It defaults to 64 KB (65536) for TCP data transfers and to 8 KB (8192) for UDP. For client/server mode, it sets both the client and server buffer lengths. --nn_n_u_m___b_u_f_s Specifies the number of source buffers written to the network (default is unlimited), and is ignored by the receiver. For client/server mode, if the client issues a "nuttcp -r" command making it the receiver, this parameter is passed to the server since the server is the transmitter in this case. This parame- ter is also ignored if the "-s" parameter is specified to the transmitter. --ww_w_i_n_d_o_w___s_i_z_e Indicates the window size in KB of the transmitter (for "nuttcp -t") or receiver (for "nuttcp -r"). Actually, to be technically correct, it sets the sender or receiver TCP socket buffer size, which then effectively sets the window size. For client/server mode, both the transmitter and receiver window sizes are set. The default window size is architecture and system dependent. Note recent Linux systems, out of a misguided desire to be help- ful, double whatever window size is actually specified by the user (this is not a bug with nuttcp but a bug/feature of the Linux kernel). Also, with these Linux systems, the actual win- dow size that's used on the intervening network, as observed with tcpdump, is greater than the requested window size, but less than the doubled value set by Linux. --wwss_s_e_r_v_e_r___w_i_n_d_o_w For client/server mode, the "-ws" option provides a mechanism for setting a different window size on the server than the client window size as specified with the "-w" option. --wwbb Normally, to conserve memory, the transmitter only sets the TCP send socket buffer size and the receiver only sets the TCP receive socket buffer size. However, if the "-wb" option is used, the transmitter will also set the TCP receive socket buffer size and the receiver will also set the TCP send socket buffer size. Under normal circumstances, this should never be necessary. This option was implemented because certain early braindead Solaris 2.8 systems would not properly set the TCP window size unless both the TCP send and receive socket buffer sizes were set (later Solaris 2.8 systems have corrected this deficiency). Thus the 'b' in this option can stand either for "braindead" or "both". --pp_d_a_t_a___p_o_r_t Port number used for the data connection, which defaults to port 5001. If multiple streams are specified with the "-N" option, the "-p" option specifies the starting port number for the data connection. For example, if four streams are specified using the default data connection port number, nuttcp will use ports 5001, 5002, 5003, and 5004 for the four TCP (or UDP) connections used to perform the data transfer. --PP_c_o_n_t_r_o_l___p_o_r_t For client/server mode, specifies the port number used for the control connection between the client and server, and defaults to port 5000. On the server side, the "-P" option should only be used when the server is started manually by the user. If the server is started by inetd/xinetd (the preferred method), the control connection must be specified by adding a nuttcp entry to the _s_e_r_v_i_c_e_s file. --NN_n_u_m___s_t_r_e_a_m_s Species the number of parallel TCP (or UDP) data streams to be used for the data transfer, with the default being a single data stream. The maximum number of parallel data streams that can be used is 128. If the number of streams is greater than one, the "-B" option is implicitly set. The current implementation does not fork off separate processes for each data stream, so speci- fying multiple streams on an SMP machine will not take advantage of its multiple processors. Of course it is always possible to run multiple nuttcp commands in parallel on an SMP system to determine if there is any advantage to running on multiple pro- cessors. This is especially simple to do when running in client/server mode when the server is started from the inetd/xinetd daemon. When running multiple nuttcp commands in parallel, the "-T" transmitter timeout option may be used to insure that all the nuttcp commands finish at approximately the same time. --RR_x_m_i_t___r_a_t_e___l_i_m_i_t[[mm||gg]] The transmitter rate limit throttles the speed at which the transmitter sends data to the network, and by default is in Kbps, although the 'm' or 'g' suffix may be used to specify Mbps or Gbps. This option may be used with either TCP or UDP data streams. Because of the way this option is currently imple- mented, it will consume all the available CPU on the transmitter side of the connection so the "%TX" stats are not meaningful when using the rate limit option. By default the rate limit is applied to the average rate of the data transfer in real time, and not in CPU time, so if nuttcp is switched out of the proces- sor for any reason, when it is switched back in, it is possible that the instantaneous rate may momentarily exceed the specified value. There is an 'i' qualifier to the rate limit option (specified as "-Ri") that will restrict the instantaneous rate at any given point in time to the specified value, although in this case the final rate reported by nuttcp may be less than the specified value since nuttcp won't attempt to catch up if other processes gain control of the CPU. The default is no rate limit. Note another way to throttle the throughput of TCP data streams is to reduce the window size. --TT_x_m_i_t___t_i_m_e___l_i_m_i_t[[mm]] Limits the amount of time that the transmitter will send data to the specified number of seconds, or number of minutes if the 'm' suffix is used. Normally a data transfer will either specify a fixed amount of data to send using the "-n" option, or a fixed period of time to send using the "-T" option. However, if both the "-n" and "-T" options are used, the data transfer will be stopped by whichever option takes affect first. The default is a 10 second time limit for the data transfer. UUSSAAGGEE Under Construction For now, consult the README file for basic usage guidelines. EEXXAAMMPPLLEESS Under Construction For now, see the examples.txt file for some examples of using nuttcp. SSEEEE AALLSSOO ppiinngg(8), ttrraacceerroouuttee(8), ttrraacceeppaatthh(8), ppaatthhcchhaarr(8), nneettssttaatt(1), mmttrraaccee(8) AAUUTTHHOORRSS Developed by Bill Fink based on nttcp which in turn was an enhancement of the original ttcp developed by Mike Muuss at BRL. IPv6 capability and some other fixes and enhancements contributed by Rob Scott. Many useful suggestions and testing performed by Phil Dykstra and others. The current version is available via anonymous ftp from: _f_t_p_:_/_/_f_t_p_._l_c_p_._n_r_l_._n_a_v_y_._m_i_l_/_p_u_b_/_n_u_t_t_c_p_/ The authors can be reached at nuttcp@lcp.nrl.navy.mil. BBUUGGSS Please send bug reports to nuttcp-bugs@lcp.nrl.navy.mil. nuttcp-v5.5.5 3 February 2007 NUTTCP(8) nuttcp-6.1.2/nuttcp-6.1.2.c0000600000222400001560000052017311140131021014667 0ustar robmusketeers/* * N U T T C P . C v6.1.2 * * Copyright(c) 2000 - 2008 Bill Fink. All rights reserved. * Copyright(c) 2003 - 2008 Rob Scott. All rights reserved. * * nuttcp is free, opensource software. You can redistribute it and/or * modify it under the terms of Version 2 of the GNU General Public * License (GPL), as published by the GNU Project (http://www.gnu.org). * A copy of the license can also be found in the LICENSE file. * * 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. * * Based on nttcp * Developed by Bill Fink, billfink@mindspring.com * and Rob Scott, rob@hpcmo.hpc.mil * Latest version available at: * ftp://ftp.lcp.nrl.navy.mil/pub/nuttcp/ * * Test TCP connection. Makes a connection on port 5001 * and transfers fabricated buffers or data copied from stdin. * * Run nuttcp with no arguments to get a usage statement * * Modified for operation under 4.2BSD, 18 Dec 84 * T.C. Slattery, USNA * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85. * * 6.1.2, Bill Fink, 29-Aug-08 * Don't wait forever for unacked data at EOT (limit to 1 minute max) * Extend no data received protection to client too (for scripts) * Give nice error messages to client for above cases * Don't hang getting server info if server exited (timeout reads) * 6.1.1, Bill Fink, 26-Aug-08 * Remove beta designation * Report RTT by default (use "-f-rtt" to suppress) * Moved RTT info to "connect to" line * Correct bogus IP frag warning for e.g. "-l1472" or "-l8972" * Don't report interval host-retrans if no data rcvd (e.g. initial PMTU) * Correct reporting of retrans info with "-fparse" option * Correct reporting of RTT with "-F" flip option * Report doubled send and receive window sizes (for Linux) * Add report of available send and receive window sizes (for Linux) * Touchup TODO list to remove some already completed items * 6.0.7, Bill Fink, 19-Aug-08 * Add delay (default 0.5 sec) to "-a" option & change max retries to 10 * Updated Copyright notice * 6.0.6, Bill Fink, 11-Aug-08 * Delay server forking until after listen() for better error status * Above suggested by Hans Blom (jblom@science.uva.nl) * Make forced server mode the default behavior * Check address family on getpeername() so "ssh host nuttcp -S" works * Add setsid() call for manually started server to create new session * Some minor code cleanup * 6.0.5, Bill Fink, 10-Aug-08 * Allow "-s" from/to stdin/stdout with "-1" oneshot server mode * Switch beta vers message to stderr to not interfere with "-s" option * Don't set default timeout if "-s" specified * Give error message for "-s" with "-S" (xinetd or manually started) * 6.0.4, Bill Fink, 18-Jul-08 * Forgot about 3rd party support for RTT info - fix that * 6.0.3, Bill Fink, 17-Jul-08 * A better (and accurate) way to get RTT info (and not just Linux) * 6.0.2, Bill Fink, 16-Jul-08 * Add RTT info to brief output for Linux * 6.0.1, Bill Fink, 17-Dec-07 * Add reporting of TCP retransmissions (interval reports on Linux TX only) * Add reporting of data transfer RTT for verbose Linux output * Add beta version messages and "-f-beta" option to suppress * Automatically switch "classic" mode to oneshot server mode * Fix UDP loss info bug not updating stream_idx when not need_swap * Fix compiler warning doing sprintf of timeout * Correct comment on NODROPS define * 5.5.5, Bill Fink, 1-Feb-07 * Change default MC addr to be based on client addr instead of xmit addr * 5.5.4, Bill Fink, 3-Nov-06 * Fix bug with negative loss causing huge drop counts on interval reports * Updated Copyright notice and added GPL license notice * 5.5.3, Bill Fink, 23-Oct-06 * Fix bug with "-Ri" instantaneous rate limiting not working properly * 5.5.2, Bill Fink, 25-Jul-06 * Make manually started server multi-threaded * Add "--single-threaded" server option to restore old behavior * Add "-a" client option to retry a failed server connection "again" * (for certain possibly transient errors) * 5.5.1, Bill Fink, 22-Jul-06 * Fix bugs with nbuf_bytes and rate_pps used with 3rd party * Pass "-D" option to server (and also make work for third party) * Allow setting precedence with "-c##p" * 5.4.3, Rob Scott & Bill Fink, 17-Jul-06 * Fix bug with buflen passed to server when no buflen option speicified * (revert 5.3.2: Fix bug with default UDP buflen for 3rd party) * Better way to fix bug with default UDP buflen for 3rd party * Trim trailing '\n' character from err() calls * Use fcntl() to set O_NONBLOCK instead of MSG_DONTWAIT to send() ABORT * (and remove MSG_DONTWAIT from recv() because it's not needed) * Don't re-initialize buflen at completion of server processing * (non inetd: is needed to check for buffer memory allocation change, * caused bug if smaller "-l" followed by larger default "-l") * 5.4.2, Bill Fink, 1-Jul-06 * Fix bug with interrupted UDP receive reporting negative packet loss * Make sure errors (or debug) from server are propagated to the client * Make setsockopt SO_SNDBUF/SO_RCVBUF error not be fatal to server * Don't send stderr to client if nofork is set (manually started server) * 5.4.1, Bill Fink, 30-Jun-06 * Fix bug with UDP reporting > linerate because of bad correction * Send 2nd UDP BOD packet in case 1st is lost, e.g. waiting for ARP reply * (makes UDP BOD more robust for new separate control and data paths) * Fix bug with interval reports after EOD for UDP with small interval * Don't just exit inetd server on no data so can get partial results * (keep an eye out that servers don't start hanging again) * Make default idle data timeout 1/2 of timeout if interval not set * (with a minimum of 5 seconds and a maximum of 60 seconds) * Make server send abort via urgent TCP data if no UDP data received * (non-interval only: so client won't keep transmitting for full period) * Workaround for Windows not handling TCP_MAXSEG getsockopt() * 5.3.4, Bill Fink, 21-Jun-06 * Add "--idle-data-timeout" server option * (server ends transfer if no data received for the specified * timeout interval, previously it was a fixed 60 second timeout) * Shutdown client control connection for writing at end of UDP transfer * (so server can cope better with loss of all EOD packets, which is * mostly of benefit when using separate control and data paths) * 5.3.3, Bill Fink & Mark S. Mathews, 18-Jun-06 * Add new capability for separate control and data paths * (using syntax: nuttcp ctl_name_or_IP/data_name_or_IP) * Extend new capability for multiple independent data paths * (using syntax: nuttcp ctl/data1/data2/.../datan) * Above only supported for transmit or flipped/reversed receive * Fix -Wall compiler warnings on 64-bit systems * Make manually started server also pass stderr to client * (so client will get warning messages from server) * 5.3.2, Bill Fink, 09-Jun-06 * Fix bug with default UDP buflen for 3rd party * Fix compiler warnings with -Wall on FreeBSD * Give warning that windows doesn't support TCP_MAXSEG * 5.3.1, Rob Scott, 06-Jun-06 * Add "-c" COS option for setting DSCP/TOS setting * Fix builds on latest MacOS X * Fix bug with 3rd party unlimited rate UDP not working * Change "-M" option to require a value * Fix compiler warnings with -Wall (thanks to Daniel J Blueman) * Remove 'v' from nuttcp version (simplify RPM packaging) * V5.2.2, Bill Fink, 13-May-06 * Have client report server warnings even if not verbose * V5.2.1, Bill Fink, 12-May-06 * Pass "-M" option to server so it also works for receives * Make "-uu" be a shortcut for "-u -Ru" * V5.1.14, Bill Fink, 11-May-06 * Fix cancellation of UDP receives to work properly * Allow easy building without IPv6 support * Set default UDP buflen to largest 2^n less than MSS of ctlconn * Add /usr/local/sbin and /usr/etc to path * Allow specifying rate in pps by using 'p' suffix * Give warning if actual send/receive window size is less than requested * Make UDP transfers have a default rate limit of 1 Mbps * Allow setting MSS for client transmitter TCP transfers with "-M" option * Give more precision on reporting small UDP percentage data loss * Disallow UDP transfers in "classic" mode * Notify when using "classic" mode * V5.1.13, Bill Fink, 8-Apr-06 * Make "-Ri" instantaneous rate limit for very high rates more accurate * (including compensating for microsecond gettimeofday() granularity) * Fix bug giving bogus time/stats on UDP transmit side with "-Ri" * Allow fractional rate limits (for 'm' and 'g' only) * V5.1.12, Bill Fink & Rob Scott, 4-Oct-05 * Terminate server receiver if client control connection goes away * or if no data received from client within CHECK_CLIENT_INTERVAL * V5.1.11, Rob Scott, 25-Jun-04 * Add support for scoped ipv6 addresses * V5.1.10, Bill Fink, 16-Jun-04 * Allow 'b' suffix on "-w" option to specify window size in bytes * V5.1.9, Bill Fink, 23-May-04 * Fix bug with client error on "-d" option putting server into bad state * Set server accept timeout (currently 5 seconds) to prevent stuck server * Add nuttcp version info to error message from err() exit * V5.1.8, Bill Fink, 22-May-04 * Allow 'd|D' suffix to "-T" option to specify days * Fix compiler warning about unused variable cp in getoptvalp routine * Interval value check against timeout value should be >= * V5.1.7, Bill Fink, 29-Apr-04 * Drop "-nb" option in favor of "-n###[k|m|g|t|p]" * V5.1.6, Bill Fink, 25-Apr-04 * Fix bug with using interval option without timeout * V5.1.5, Bill Fink, 23-Apr-04 * Modification to allow space between option parameter and its value * Permit 'k' or 'm' suffix on "-l" option * Add "-nb" option to specify number of bytes to transfer * Permit 'k', 'm', 'g', 't', or 'p' suffix on "-n" and "-nb" options * V5.1.4, Bill Fink, 21-Apr-04 * Change usage statement to use standard out instead of standard error * Fix bug with interval > timeout, give warning and ignore interval * Fix bug with counting error value in nbytes on interrupted transfers * Fix bug with TCP transmitted & received nbytes not matching * Merge "-t" and "-r" options in Usage: statement * V5.1.3, Bill Fink, 9-Apr-04 * Add "-Sf" force server mode (useful for starting server via rsh/ssh) * Allow non-root user to find nuttcp binary in "." * Fix bug with receives terminating early with manual server mode * Fix bug with UDP receives not terminating with "-Ri" option * Clean up output formatting of nbuf (from "%d" to "%llu") * Add "-SP" to have 3rd party use same outgoing control port as incoming * V5.1.2, Bill Fink & Rob Scott, 18-Mar-04 * Fix bug with nbuf wrapping on really long transfers (int -> uint64_t) * Fix multicast address to be unsigned long to allow shift * Add MacOS uint8_t definition for new use of uint8_t * V5.1.1, Bill Fink, 8-Nov-03 * Add IPv4 multicast support * Delay receiver EOD until EOD1 (for out of order last data packet) * Above also drains UDP receive buffer (wait for fragmentation reassembly) * V5.0.4, Bill Fink, 6-Nov-03 * Fix bug reporting 0 drops when negative loss percentage * V5.0.3, Bill Fink, 6-Nov-03 * Kill server transmission if control connection goes away * Kill 3rd party nuttcp if control connection goes away * V5.0.2, Bill Fink, 4-Nov-03 * Fix bug: some dummy wasn't big enough :-) * V5.0.1, Bill Fink, 3-Nov-03 * Add third party support * Correct usage statement for "-xt" traceroute option * Improved error messages on failed options requiring client/server mode * V4.1.1, David Lapsley and Bill Fink, 24-Oct-03 * Added "-fparse" format option to generate key=value parsable output * Fix bug: need to open data connection on abortconn to clear listen * V4.0.3, Rob Scott, 13-Oct-03 * Minor tweaks to output format for alignment * Interval option "-i" with no explicit value sets interval to 1.0 * V4.0.2, Bill Fink, 10-Oct-03 * Changed "-xt" option to do both forward and reverse traceroute * Changed to use brief output by default ("-v" for old default behavior) * V4.0.1, Rob Scott, 10-Oct-03 * Added IPv6 code * Changed inet get functions to protocol independent versions * Added fakepoll for hosts without poll() (macosx) * Added ifdefs to only include setprio if os supports it (non-win) * Added bits to handle systems without new inet functions (solaris < 2.8) * Removed SYSV obsolete code * Added ifdefs and code to handle cygwin and beginning of windows support * Window size can now be in meg (m|M) and gig (g|G) * Added additional directories to search for traceroute * Changed default to transmit, time limit of 10 seconds, no buffer limit * Added (h|H) as option to specify time in hours * Added getservbyname calls for port, if all fails use old defaults * Changed sockaddr to sockaddr_storage to handle v6 addresses * v3.7.1, Bill Fink, 10-Aug-03 * Add "-fdebugpoll" option to help debug polling for interval reporting * Fix Solaris compiler warning * Use poll instead of separate process for interval reports * v3.6.2, Rob Scott, 18-Mar-03 * Allow setting server window to use default value * Cleaned out BSD42 old code * Marked SYSV code for future removal as it no longer appears necessary * Also set RCVBUF/SNDBUF for udp transfers * Changed transmit SO_DEBUG code to be like receive * Some code rearrangement for setting options before accept/connect * v3.6.1, Bill Fink, 1-Mar-03 * Add -xP nuttcp process priority option * Add instantaneous rate limit capability ("-Ri") * Don't open data connection if server error or doing traceroute * Better cleanup on server connection error (close open data connections) * Don't give normal nuttcp output if server error requiring abort * Implement -xt traceroute option * v3.5.1, Bill Fink, 27-Feb-03 * Don't allow flip option to be used with UDP * Fix bug with UDP and transmit interval option (set stdin unbuffered) * Fix start of UDP timing to be when get BOD * Fix UDP timing when don't get first EOD * Fix ident option used with interval option * Add "-f-percentloss" option to not give %loss info on brief output * Add "-f-drops" option to not give packet drop info on brief output * Add packet drop info to UDP brief output (interval report and final) * Add "-frunningtotal" option to give cumulative stats for "-i" * Add "-fdebuginterval" option to help debug interval reporting * Add "-fxmitstats" option to give transmitter stats * Change flip option from "-f" to "-F" * Fix divide by zero bug with "-i" option and very low rate limit * Fix to allow compiling with Irix native compiler * Fix by Rob Scott to allow compiling on MacOS X * v3.4.5, Bill Fink, 29-Jan-03 * Fix client/server endian issues with UDP loss info for interval option * v3.4.4, Bill Fink, 29-Jan-03 * Remove some debug printout for interval option * Fix bug when using interval option reporting 0.000 MB on final * v3.4.3, Bill Fink, 24-Jan-03 * Added UDP approximate loss info for interval reporting * Changed nbytes and pbytes from double to uint64_t * Changed SIGUSR1 to SIGTERM to kill sleeping child when done * v3.4.2, Bill Fink, 15-Jan-03 * Make work right with receive too * v3.4.1, Bill Fink, 13-Jan-03 * Fix bug interacting with old servers * Add "-f" flip option to reverse direction of data connection open * Fix bug by disabling interval timer when server done * v3.3.2, Bill Fink, 11-Jan-03 * Make "-i" option work for client transmit too * Fix bug which forced "-i" option to be at least 0.1 seconds * v3.3.1, Bill Fink, 7-Jan-03 * Added -i option to set interval timer (client receive only) * Fixed server bug not setting socket address family * v3.2.1, Bill Fink, 25-Feb-02 * Fixed bug so second will definitely kill nuttcp * Changed default control port to 5000 (instead of data port - 1) * Modified -T option to accept fractional seconds * v3.1.10, Bill Fink, 6-Feb-02 * Added -I option to identify nuttcp output * Made server always verbose (filtering is done by client) * Update to usage statement * Minor fix to "-b" output when "-D" option is used * Fix bug with "-s" that appends nuttcp output to receiver data file * Fix bug with "-b" that gave bogus CPU utilization on > 1 hour transfers * v3.1.9, Bill Fink, 21-Dec-01 * Fix bug with "-b" option on SGI systems reporting 0% CPU utilization * v3.1.8, Bill Fink, 21-Dec-01 * Minor change to brief output format to make it simpler to awk * v3.1.7, Bill Fink, 20-Dec-01 * Implement "-b" option for brief output (old "-b" -> "-wb") * Report udp loss percentage when using client/server mode * Fix bug with nbytes on transmitter using timed transfer * Combined send/receive window size printout onto a single line * v3.1.6, Bill Fink, 11-Jun-01 * Fixed minor bug reporting error connecting to inetd server * Previously, Bill Fink, 7-Jun-01 * Added -h (usage) and -V (version) options * Fixed SGI compilation warnings * Added reporting server version to client * Added version info and changed ttcp prints to nuttcp * Fixed bug with inetd server and client using -r option * Added ability to run server from inetd * Added udp capability to server option * Added -T option to set timeout interval * Added -ws option to set server window * Added -S option to support running receiver as daemon * Allow setting UDP buflen up to MAXUDPBUFLEN * Provide -b option for braindead Solaris 2.8 * Added printing of transmit rate limit * Added -w option to usage statement * Added -N option to support multiple streams * Added -R transmit rate limit option * Fix setting of destination IP address on 64-bit Irix systems * Only set window size in appropriate direction to save memory * Fix throughput calculation for large transfers (>= 2 GB) * Fix reporting of Mb/s to give actual millions of bits per second * Fix setting of INET address family in local socket * Fix setting of receiver window size * * TODO/Wish-List: * Transmit interval marking option * Allow at least some traceroute options * IPv6 multicast support * Add "-ut" option to do both UDP and TCP simultaneously * Default rate limit UDP if too much loss * Ping option * Other brief output formats * Linux window size bug/feature note * Network interface interrupts (for Linux only) * netstat -i info * Man page * Forking for multiple streams * Bidirectional option * Graphical interface * OWD info * Jitter info * MTU info * Warning for window size limiting throughput * Auto window size optimization * Transmitter profile and playback options * Server side limitations (per client host/network) * Server side logging * Client/server security (password) * nuttcp server registration * nuttcp proxy support (firewalls) * nuttcp network idle time * * Distribution Status - * OpenSource(tm) * Licensed under version 2 of the GNU GPL * Please send source modifications back to the authors * Derivative works should be redistributed with a modified * source and executable name */ /* #ifndef lint static char RCSid[] = "@(#)$Revision: 1.2 $ (BRL)"; #endif */ #include #include #include #include #include #include /* struct timeval */ #include #ifndef _WIN32 #include #include #include #include #include #include #else #include "win32nuttcp.h" /* from win32 */ #endif /* _WIN32 */ #include #include #include /* Let's try changing the previous unwieldy check */ /* #if defined(linux) || defined(__FreeBSD__) || defined (sgi) || (defined(__MACH__) && defined(_SOCKLEN_T)) || defined(sparc) || defined(__CYGWIN__) */ /* to the following (hopefully equivalent) simpler form like we use * for HAVE_POLL */ #if !defined(_WIN32) && (!defined(__MACH__) || defined(_SOCKLEN_T)) #include #include #include #endif #ifndef ULLONG_MAX #define ULLONG_MAX 18446744073709551615ULL #endif #define MAXRATE 0xffffffffUL #if !defined(__CYGWIN__) && !defined(_WIN32) #define HAVE_SETPRIO #endif #if !defined(_WIN32) && (!defined(__MACH__) || defined(_SOCKLEN_T)) #define HAVE_POLL #endif #if defined(__APPLE__) && defined(__MACH__) #define uint64_t u_int64_t #define uint32_t u_int32_t #define uint16_t u_int16_t #define uint8_t u_int8_t #endif #ifdef HAVE_POLL #include #else #include "fakepoll.h" /* from missing */ #endif /* * _SOCKLEN_T is now defined by apple when they typedef socklen_t * * EAI_NONAME has nothing to do with socklen, but on sparc without it tells * us it's an old enough solaris to need the typedef */ #if (defined(__APPLE__) && defined(__MACH__)) && !defined(_SOCKLEN_T) || (defined(sparc) && !defined(EAI_NONAME)) typedef int socklen_t; #endif #if defined(sparc) && !defined(EAI_NONAME) /* old sparc */ #define sockaddr_storage sockaddr #define ss_family sa_family #endif /* old sparc */ #if defined(_AIX) #define ss_family __ss_family #endif #if !defined(EAI_NONAME) #include "addrinfo.h" /* from missing */ #endif #define BETA_STR "-beta" #define BETA_FEATURES "retrans" static struct timeval time0; /* Time at which timing started */ static struct timeval timepk; /* Time at which last packet sent */ static struct timeval timep; /* Previous time - for interval reporting */ static struct rusage ru0; /* Resource utilization at the start */ static struct sigaction sigact; /* signal handler for alarm */ static struct sigaction savesigact; #define PERF_FMT_OUT "%.4f MB in %.2f real seconds = %.2f KB/sec" \ " = %.4f Mbps\n" #define PERF_FMT_BRIEF "%10.4f MB / %6.2f sec = %9.4f Mbps %d %%TX %d %%RX" #define PERF_FMT_BRIEF2 "%10.4f MB / %6.2f sec = %9.4f Mbps %d %%%s" #define PERF_FMT_BRIEF3 " Trans: %.4f MB" #define PERF_FMT_INTERVAL "%10.4f MB / %6.2f sec = %9.4f Mbps" #define PERF_FMT_INTERVAL2 " Tot: %10.4f MB / %6.2f sec = %9.4f Mbps" #define PERF_FMT_INTERVAL3 " Trans: %10.4f MB" #define PERF_FMT_INTERVAL4 " Tot: %10.4f MB" #define PERF_FMT_IN "%lf MB in %lf real seconds = %lf KB/sec = %lf Mbps\n" #define CPU_STATS_FMT_IN "%*fuser %*fsys %*d:%*dreal %d%%" #define CPU_STATS_FMT_IN2 "%*fuser %*fsys %*d:%*d:%*dreal %d%%" #define LOSS_FMT " %.2f%% data loss" #define LOSS_FMT_BRIEF " %.2f %%loss" #define LOSS_FMT_INTERVAL " %5.2f ~%%loss" #define LOSS_FMT5 " %.5f%% data loss" #define LOSS_FMT_BRIEF5 " %.5f %%loss" #define LOSS_FMT_INTERVAL5 " %7.5f ~%%loss" #define DROP_FMT " %lld / %lld drop/pkt" #define DROP_FMT_BRIEF " %lld / %lld drop/pkt" #define DROP_FMT_INTERVAL " %5lld / %5lld ~drop/pkt" #define RETRANS_FMT "%sretrans = %d" #define RETRANS_FMT_BRIEF " %d %sretrans" #define RETRANS_FMT_INTERVAL " %5d %sretrans" #define RETRANS_FMT_IN "retrans = %d" #define RTT_FMT " RTT=%.3f ms" #define RTT_FMT_BRIEF " %.2f msRTT" #define RTT_FMT_IN "RTT=%lf" #define RTT_FMT_INB "RTT = %lf" #define SIZEOF_TCP_INFO_RETRANS 104 /* define NEW_TCP_INFO if struct tcp_info in /usr/include/netinet/tcp.h * contains tcpi_total_retrans member */ #ifndef NEW_TCP_INFO #define OLD_TCP_INFO #endif /* Parsable output formats */ #define P_PERF_FMT_OUT "megabytes=%.4f real_seconds=%.2f " \ "rate_KBps=%.2f rate_Mbps=%.4f\n" #define P_PERF_FMT_BRIEF "megabytes=%.4f real_seconds=%.2f rate_Mbps=%.4f " \ "tx_cpu=%d rx_cpu=%d" #define P_PERF_FMT_BRIEF3 " tx_megabytes=%.4f" #define P_PERF_FMT_INTERVAL "megabytes=%.4f real_sec=%.2f rate_Mbps=%.4f" #define P_PERF_FMT_INTERVAL2 " total_megabytes=%.4f total_real_sec=%.2f" \ " total_rate_Mbps=%.4f" #define P_PERF_FMT_INTERVAL3 " tx_megabytes=%.4f" #define P_PERF_FMT_INTERVAL4 " tx_total_megabytes=%.4f" #define P_PERF_FMT_IN "megabytes=%lf real_seconds=%lf rate_KBps=%lf " \ "rate_Mbps=%lf\n" #define P_CPU_STATS_FMT_IN "user=%*f system=%*f elapsed=%*d:%*d cpu=%d%%" #define P_CPU_STATS_FMT_IN2 "user=%*f system=%*f elapsed=%*d:%*d:%*d cpu=%d%%" #define P_LOSS_FMT " data_loss=%.5f" #define P_LOSS_FMT_BRIEF " data_loss=%.5f" #define P_LOSS_FMT_INTERVAL " data_loss=%.5f" #define P_DROP_FMT " drop=%lld pkt=%lld" #define P_DROP_FMT_BRIEF " drop=%lld pkt=%lld" #define P_DROP_FMT_INTERVAL " drop=%lld pkt=%lld" #define P_RETRANS_FMT "%sretrans=%d" #define P_RETRANS_FMT_BRIEF " %sretrans=%d" #define P_RETRANS_FMT_INTERVAL " %sretrans=%d" #define P_RETRANS_FMT_IN "retrans=%d" #define P_RTT_FMT " rtt_ms=%.3f" #define P_RTT_FMT_BRIEF " rtt_ms=%.2f" #define P_RTT_FMT_IN "rtt_ms=%lf" #define HELO_FMT "HELO nuttcp v%d.%d.%d\n" #ifndef MAXSTREAM #define MAXSTREAM 128 #endif #define DEFAULT_NBUF 2048 #define DEFAULT_NBYTES 134217728 /* 128 MB */ #define DEFAULT_TIMEOUT 10.0 #define DEFAULT_UDP_RATE 1000 #define DEFAULTUDPBUFLEN 8192 #define DEFAULT_MC_UDPBUFLEN 1024 #define MAXUDPBUFLEN 65507 #define MINMALLOC 1024 #define HI_MC 231ul #define ACCEPT_TIMEOUT 5 #ifndef MAX_CONNECT_TRIES #define MAX_CONNECT_TRIES 10 /* maximum server connect attempts */ #endif #ifndef SERVER_RETRY_USEC #define SERVER_RETRY_USEC 500000 /* server retry time in usec */ #endif #define MAX_EOT_WAIT_SEC 60.0 /* max wait for unacked data at EOT */ #define SRVR_INFO_TIMEOUT 60 /* timeout for reading server info */ #define IDLE_DATA_MIN 5.0 /* minimum value for chk_idle_data */ #define DEFAULT_IDLE_DATA 30.0 /* default value for chk_idle_data */ #define IDLE_DATA_MAX 60.0 /* maximum value for chk_idle_data */ #define NON_JUMBO_ETHER_MSS 1448 /* 1500 - 20:IP - 20:TCP -12:TCPOPTS */ #define TCP_UDP_HDRLEN_DELTA 12 /* difference in tcp & udp hdr sizes */ #if defined(linux) #define TCP_ADV_WIN_SCALE "/proc/sys/net/ipv4/tcp_adv_win_scale" #endif #define XMITSTATS 0x1 /* also give transmitter stats (MB) */ #define DEBUGINTERVAL 0x2 /* add info to assist with * debugging interval reports */ #define RUNNINGTOTAL 0x4 /* give cumulative stats for "-i" */ #define NODROPS 0x8 /* no packet drop stats for "-i" */ #define NOPERCENTLOSS 0x10 /* don't give percent loss for "-i" */ #define DEBUGPOLL 0x20 /* add info to assist with debugging * polling for interval reports */ #define PARSE 0x40 /* generate key=value parsable output */ #define DEBUGMTU 0x80 /* debug info for MTU/MSS code */ #define NORETRANS 0x100 /* no retrans stats for "-i" */ #define DEBUGRETRANS 0x200 /* output info for debugging collection * of TCP retransmission info */ #define NOBETAMSG 0x400 /* suppress beta version message */ #define WANTRTT 0x800 /* output RTT info (default) */ #ifdef NO_IPV6 /* Build without IPv6 support */ #undef AF_INET6 #undef IPV6_V6ONLY #endif void sigpipe( int signum ); void sigint( int signum ); void ignore_alarm( int signum ); void sigalarm( int signum ); static void err( char *s ); static void mes( char *s ); static void errmes( char *s ); void pattern( char *cp, int cnt ); void prep_timer(); double read_timer( char *str, int len ); static void prusage( struct rusage *r0, struct rusage *r1, struct timeval *e, struct timeval *b, char *outp ); static void tvadd( struct timeval *tsum, struct timeval *t0, struct timeval *t1 ); static void tvsub( struct timeval *tdiff, struct timeval *t1, struct timeval *t0 ); static void psecs( long l, char *cp ); int Nread( int fd, char *buf, int count ); int Nwrite( int fd, char *buf, int count ); int delay( int us ); int mread( int fd, char *bufp, unsigned n); char *getoptvalp( char **argv, int index, int reqval, int *skiparg ); int get_retrans( int sockfd ); #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS) void print_tcpinfo(); #endif int vers_major = 6; int vers_minor = 1; int vers_delta = 2; int ivers; int rvers_major = 0; int rvers_minor = 0; int rvers_delta = 0; int irvers; int beta = 0; struct sockaddr_in sinme[MAXSTREAM + 1]; struct sockaddr_in sinhim[MAXSTREAM + 1]; struct sockaddr_in save_sinhim, save_mc; #ifdef AF_INET6 struct sockaddr_in6 sinme6[MAXSTREAM + 1]; struct sockaddr_in6 sinhim6[MAXSTREAM + 1]; #endif struct sockaddr_storage frominet; int domain = PF_UNSPEC; int af = AF_UNSPEC; int explicitaf = 0; /* address family explicit specified (-4|-6) */ int fd[MAXSTREAM + 1]; /* fd array of network sockets */ int nfd; /* fd for accept call */ struct pollfd pollfds[MAXSTREAM + 4]; /* used for reading interval reports */ socklen_t fromlen; int buflen = 64 * 1024; /* length of buffer */ int nbuflen; int mallocsize; char *buf; /* ptr to dynamic buffer */ unsigned long long nbuf = 0; /* number of buffers to send in sinkmode */ int nbuf_bytes = 0; /* set to 1 if nbuf is actually bytes */ /* nick code */ int sendwin=0, sendwinval=0, origsendwin=0; socklen_t optlen; int rcvwin=0, rcvwinval=0, origrcvwin=0; int srvrwin=0; /* end nick code */ #if defined(linux) int sendwinavail=0, rcvwinavail=0, winadjust=0; #endif #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS) #ifdef OLD_TCP_INFO struct tcpinfo { /* for collecting TCP retransmission info */ struct tcp_info _tcpinf; /* add missing structure elements */ u_int32_t tcpi_rcv_rtt; u_int32_t tcpi_rcv_space; u_int32_t tcpi_total_retrans; } tcpinf; #define tcpinfo_state _tcpinf.tcpi_state #define tcpinfo_ca_state _tcpinf.tcpi_ca_state #define tcpinfo_retransmits _tcpinf.tcpi_retransmits #define tcpinfo_unacked _tcpinf.tcpi_unacked #define tcpinfo_sacked _tcpinf.tcpi_sacked #define tcpinfo_lost _tcpinf.tcpi_lost #define tcpinfo_retrans _tcpinf.tcpi_retrans #define tcpinfo_fackets _tcpinf.tcpi_fackets #define tcpinfo_rtt _tcpinf.tcpi_rtt #define tcpinfo_rttvar _tcpinf.tcpi_rttvar #define tcpinfo_snd_ssthresh _tcpinf.tcpi_snd_ssthresh #define tcpinfo_snd_cwnd _tcpinf.tcpi_snd_cwnd #else struct tcp_info tcpinf; #define tcpinfo_state tcpi_state #define tcpinfo_ca_state tcpi_ca_state #define tcpinfo_retransmits tcpi_retransmits #define tcpinfo_unacked tcpi_unacked #define tcpinfo_sacked tcpi_sacked #define tcpinfo_lost tcpi_lost #define tcpinfo_retrans tcpi_retrans #define tcpinfo_fackets tcpi_fackets #define tcpinfo_rtt tcpi_rtt #define tcpinfo_rttvar tcpi_rttvar #define tcpinfo_snd_ssthresh tcpi_snd_ssthresh #define tcpinfo_snd_cwnd tcpi_snd_cwnd #endif #endif int udp = 0; /* 0 = tcp, !0 = udp */ int udplossinfo = 0; /* set to 1 to give UDP loss info for * interval reporting */ int retransinfo = 0; /* set to 1 to give TCP retransmission info * for interval reporting */ int force_retrans = 0; /* set to force sending retrans info */ int send_retrans = 1; /* set to 0 if no need to send retrans info */ int read_retrans = 1; /* set to 0 if no need to read retrans info */ int need_swap; /* client and server are different endian */ int options = 0; /* socket options */ int one = 1; /* for 4.3 BSD style setsockopt() */ /* default port numbers if command arg or getserv doesn't get a port # */ #define DEFAULT_PORT 5001 #define DEFAULT_CTLPORT 5000 unsigned short port = 0; /* TCP port number */ unsigned short ctlport = 0; /* control port for server connection */ int tmpport; char *host; /* ptr to name of host */ char *host3 = NULL; /* ptr to 3rd party host */ int thirdparty = 0; /* set to 1 indicates doing 3rd party nuttcp */ int no3rd = 0; /* set to 1 by server to disallow 3rd party */ int forked = 0; /* set to 1 after server has forked */ int pass_ctlport = 0; /* set to 1 to use same outgoing control port as incoming with 3rd party usage */ char *cmdargs[50]; /* command arguments array */ char tmpargs[50][40]; #ifndef AF_INET6 #define ADDRSTRLEN 16 #else #define ADDRSTRLEN INET6_ADDRSTRLEN int v4mapped = 0; /* set to 1 to enable v4 mapping in v6 server */ #endif #define HOSTNAMELEN 80 char hostbuf[ADDRSTRLEN]; /* buffer to hold text of address */ char host3buf[HOSTNAMELEN + 1]; /* buffer to hold 3rd party name or address */ int trans = 1; /* 0=receive, !0=transmit mode */ int sinkmode = 1; /* 0=normal I/O, !0=sink/source mode */ int nofork = 0; /* set to 1 to not fork server */ int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc * resource usage. */ int nodelay = 0; /* set TCP_NODELAY socket option */ unsigned long rate = MAXRATE; /* transmit rate limit in Kbps */ int irate = 0; /* instantaneous rate limit if set */ double pkt_time; /* packet transmission time in seconds */ uint64_t irate_pk_usec; /* packet transmission time in microseconds */ double irate_pk_nsec; /* nanosecond portion of pkt xmit time */ double irate_cum_nsec = 0.0; /* cumulative nanaseconds over several pkts */ int rate_pps = 0; /* set to 1 if rate is given as pps */ double timeout = 0.0; /* timeout interval in seconds */ double interval = 0.0; /* interval timer in seconds */ double chk_idle_data = 0.0; /* server receiver checks this often */ /* for client having gone away */ double chk_interval = 0.0; /* timer (in seconds) for checking client */ int ctlconnmss; /* control connection maximum segment size */ int datamss = 0; /* data connection maximum segment size */ unsigned int tos = 0; /* 8-bit TOS field for setting DSCP/TOS */ char intervalbuf[256+2]; /* buf for interval reporting */ char linebuf[256+2]; /* line buffer */ int do_poll = 0; /* set to read interval reports (client xmit) */ int got_done = 0; /* set when read last of interval reports */ int reverse = 0; /* reverse direction of data connection open */ int format = 0; /* controls formatting of output */ char fmt[257]; int traceroute = 0; /* do traceroute back to client if set */ int skip_data = 0; /* skip opening of data channel */ #if defined(linux) int multicast = 0; /* set to 1 for multicast UDP transfer */ #else uint8_t multicast = 0; /* set to 1 for multicast UDP transfer */ #endif int mc_param; struct ip_mreq mc_group; /* holds multicast group address */ #ifdef HAVE_SETPRIO int priority = 0; /* nuttcp process priority */ #endif long timeout_sec = 0; struct itimerval itimer; /* for setitimer */ int srvr_helo = 1; /* set to 0 if server doesn't send HELO */ char ident[40 + 1 + 1] = ""; /* identifier for nuttcp output */ int intr = 0; int abortconn = 0; int braindead = 0; /* for braindead Solaris 2.8 systems */ int brief = 1; /* set for brief output */ int brief3 = 1; /* for third party nuttcp */ int done = 0; /* don't output interval report if done */ int got_begin = 0; /* don't output interval report if not begun */ int two_bod = 0; /* newer versions send 2 BOD packets for UDP */ int handle_urg = 0; /* newer versions send/recv urgent TCP data */ int got_eod0 = 0; /* got EOD0 packet - marks end of UDP xfer */ int buflenopt = 0; /* whether or not user specified buflen */ int haverateopt = 0; /* whether or not user specified rate */ int clientserver = 0; /* client server mode (use control channel) */ int client = 0; /* 0=server side, 1=client (initiator) side */ int oneshot = 0; /* 1=run server only once */ int inetd = 0; /* set to 1 if server run from inetd */ pid_t pid; /* process id when forking server process */ pid_t wait_pid; /* return of wait system call */ int pidstat; /* status of forked process */ FILE *ctlconn; /* uses fd[0] for control channel */ int savestdin; /* used to save real standard in */ int savestdout; /* used to save real standard out */ int firsttime = 1; /* flag for first pass through server */ struct in_addr clientaddr; /* IP address of client connecting to server */ #ifdef AF_INET6 struct in6_addr clientaddr6; /* IP address of client connecting to server */ uint32_t clientscope6; /* scope part of IP address of client */ #endif struct hostent *addr; extern int errno; char Usage[] = "\ Usage: nuttcp or nuttcp -h prints this usage info\n\ Usage: nuttcp -V prints version info\n\ Usage: nuttcp -xt [-m] host forward and reverse traceroute to/from server\n\ Usage (transmitter): nuttcp [-t] [-options] [ctl_addr/]host [3rd-party] [out]\n\ -4 Use IPv4\n" #ifdef AF_INET6 " -6 Use IPv6\n" #endif " -c## cos dscp value on data streams (t|T suffix for full TOS field)\n\ -l## length of network write|read buf (default 1K|8K/udp, 64K/tcp)\n\ -s use stdin|stdout for data input|output instead of pattern data\n\ -n## number of source bufs written to network (default unlimited)\n\ -w## transmitter|receiver window size in KB (or (m|M)B or (g|G)B)\n\ -ws## server receive|transmit window size in KB (or (m|M)B or (g|G)B)\n\ -wb braindead Solaris 2.8 (sets both xmit and rcv windows)\n\ -p## port number to send to|listen at (default 5001)\n\ -P## port number for control connection (default 5000)\n\ -u use UDP instead of TCP\n\ -m## use multicast with specified TTL instead of unicast (UDP)\n\ -M## MSS for data connection (TCP)\n\ -N## number of streams (starting at port number), implies -B\n\ -R## transmit rate limit in Kbps (or (m|M)bps or (g|G)bps or (p)ps)\n\ -T## transmit timeout in seconds (or (m|M)inutes or (h|H)ours)\n\ -i## receiver interval reporting in seconds (or (m|M)inutes)\n\ -Ixxx identifier for nuttcp output (max of 40 characters)\n\ -F flip option to reverse direction of data connection open\n\ -a retry failed server connection \"again\" for transient errors\n" #ifdef HAVE_SETPRIO " -xP## set nuttcp process priority (must be root)\n" #endif " -d set TCP SO_DEBUG option on data socket\n\ -v[v] verbose [or very verbose] output\n\ -b brief output (default)\n\ -D xmit only: don't buffer TCP writes (sets TCP_NODELAY sockopt)\n\ -B recv only: only output full blocks of size from -l## (for TAR)\n" #ifdef IPV6_V6ONLY " --disable-v4-mapped disable v4 mapping in v6 server (default)\n" " --enable-v4-mapped enable v4 mapping in v6 server\n" #endif "Usage (server): nuttcp -S[f][P] [-options]\n\ note server mode excludes use of -s\n\ 'P' suboption makes 3rd party {in,out}bound control ports same\n\ -4 Use IPv4 (default)\n" #ifdef AF_INET6 " -6 Use IPv6\n" #endif " -1 oneshot server mode (implied with inetd/xinetd), implies -S\n\ -P## port number for server connection (default 5000)\n\ note don't use with inetd/xinetd (use services file instead)\n" #ifdef HAVE_SETPRIO " -xP## set nuttcp process priority (must be root)\n" #endif " --idle-data-timeout (default: 5/30/60)\n" " server timeout in seconds for idle data connection\n" " --no3rdparty don't allow 3rd party capability\n" " --nofork don't fork server\n" " --single-threaded make manually started server be single threaded\n" #ifdef IPV6_V6ONLY " --disable-v4-mapped disable v4 mapping in v6 server (default)\n" " --enable-v4-mapped enable v4 mapping in v6 server\n" #endif "Format options:\n\ -fxmitstats also give transmitter stats (MB) with -i (UDP only)\n\ -frunningtotal also give cumulative stats on interval reports\n\ -f-drops don't give packet drop info on brief output (UDP)\n\ -f-retrans don't give retrans info on brief output (TCP)\n\ -f-percentloss don't give %%loss info on brief output (UDP)\n\ -fparse generate key=value parsable output\n\ -f-beta suppress beta version message\n\ -f-rtt suppress RTT info \n\ "; char stats[128]; char srvrbuf[4096]; char tmpbuf[257]; uint64_t nbytes = 0; /* bytes on net */ int64_t pbytes = 0; /* previous bytes - for interval reporting */ int64_t ntbytes = 0; /* bytes sent by transmitter */ int64_t ptbytes = 0; /* previous bytes sent by transmitter */ uint64_t ntbytesc = 0; /* bytes sent by transmitter that have * been counted */ uint64_t chk_nbytes = 0; /* byte counter used to test if no more data * being received by server (presumably because * client transmitter went away */ double rtt = 0.0; /* RTT between client and server in ms */ uint32_t nretrans = 0; /* number of TCP retransmissions */ uint32_t iretrans = 0; /* initial number of TCP retransmissions */ uint32_t pretrans = 0; /* previous number of TCP retransmissions */ uint32_t sretrans = 0; /* number of system TCP retransmissions */ int numCalls = 0; /* # of NRead/NWrite calls. */ int nstream = 1; /* number of streams */ int stream_idx = 0; /* current stream */ int start_idx = 1; /* set to use or bypass control channel */ int b_flag = 1; /* use mread() */ int got_srvr_output = 0; /* set when server output has been read */ int reading_srvr_info = 0; /* set when starting to read server info */ int retry_server = 0; /* set to retry control connect() to server */ int num_connect_tries = 0; /* tracks attempted connects to server */ int single_threaded = 0; /* set to make server single threaded */ double srvr_MB; double srvr_realt; double srvr_KBps; double srvr_Mbps; int srvr_cpu_util; double cput = 0.000001, realt = 0.000001; /* user, real time (seconds) */ double realtd = 0.000001; /* real time delta - for interval reporting */ #ifdef SIGPIPE void sigpipe( int signum ) { signal(SIGPIPE, sigpipe); } #endif void sigint( int signum ) { signal(SIGINT, SIG_DFL); fputs("\n*** transfer interrupted ***\n", stdout); if (clientserver && client && !host3 && udp && !trans) shutdown(0, SHUT_WR); else intr = 1; done++; return; } void ignore_alarm( int signum ) { return; } void sigalarm( int signum ) { struct timeval timec; /* Current time */ struct timeval timed; /* Delta time */ /* beginnings of timestamps - not ready for prime time */ /* struct timeval timet; */ /* Transmitter time */ int64_t nrbytes; uint64_t deltarbytes, deltatbytes; double fractloss; int nodata; /* int normal_eod; */ int i; char *cp1, *cp2; short save_events; long flags, saveflags; if (host3 && clientserver && !client) return; if (clientserver && client && reading_srvr_info) { mes("Error: not receiving server info"); exit(1); } if (interval && !trans) { /* Get real time */ gettimeofday(&timec, (struct timezone *)0); tvsub( &timed, &timec, &timep ); realtd = timed.tv_sec + ((double)timed.tv_usec) / 1000000; if( realtd <= 0.0 ) realtd = 0.000001; tvsub( &timed, &timec, &time0 ); realt = timed.tv_sec + ((double)timed.tv_usec) / 1000000; if( realt <= 0.0 ) realt = 0.000001; } if (clientserver && !trans) { struct sockaddr_in peer; socklen_t peerlen = sizeof(peer); nodata = 0; /* normal_eod = 0; */ if (getpeername(fd[0], (struct sockaddr *)&peer, &peerlen) < 0) nodata = 1; if (!client && udp && got_begin) { /* checks if client did a shutdown() for writing * on the control connection */ pollfds[0].fd = fileno(ctlconn); save_events = pollfds[0].events; pollfds[0].events = POLLIN | POLLPRI; pollfds[0].revents = 0; if ((poll(pollfds, 1, 0) > 0) && (pollfds[0].revents & (POLLIN | POLLPRI))) { nodata = 1; /* normal_eod = 1; */ } pollfds[0].events = save_events; } if (interval) { chk_interval += realtd; if (chk_interval >= chk_idle_data) { chk_interval = 0; if ((nbytes - chk_nbytes) == 0) nodata = 1; chk_nbytes = nbytes; } } else { if ((nbytes - chk_nbytes) == 0) nodata = 1; chk_nbytes = nbytes; } if (nodata) { /* Don't just exit anymore so can get partial results * (shouldn't be a problem but keep an eye out that * servers don't start hanging again) */ /* following code untested after recent changes */ /* if ((inetd || (!nofork && !single_threaded)) */ /* && !normal_eod) */ /* exit(1); */ if (!client && udp && !interval && handle_urg) { /* send 'A' for ABORT as urgent TCP data * on control connection (don't block) * * Only server can do this since client * does a shutdown() for writing on the * control connection */ saveflags = fcntl(fd[0], F_GETFL, 0); if (saveflags != -1) { flags = saveflags | O_NONBLOCK; fcntl(fd[0], F_SETFL, flags); } send(fd[0], "A", 1, MSG_OOB); if (saveflags != -1) { flags = saveflags; fcntl(fd[0], F_SETFL, flags); } } for ( i = 1; i <= nstream; i++ ) close(fd[i]); if (client) { mes("Error: not receiving data from server"); exit(1); } intr = 1; return; } if (!interval) return; } if (interval && !trans) { if ((udp && !got_begin) || done) { timep.tv_sec = timec.tv_sec; timep.tv_usec = timec.tv_usec; return; } if (clientserver) { nrbytes = nbytes; if (udplossinfo) { ntbytes = *(int64_t *)(buf + 24); if (need_swap) { cp1 = (char *)&ntbytes; cp2 = buf + 31; for ( i = 0; i < 8; i++ ) *cp1++ = *cp2--; } if (ntbytes > ntbytesc) /* received bytes not counted yet */ nrbytes += buflen; if ((nrbytes > ntbytes) || ((nrbytes - pbytes) > (ntbytes - ptbytes))) /* yes they were counted */ nrbytes -= buflen; } if (read_retrans) { nretrans = *(uint32_t *)(buf + 24); if (need_swap) { cp1 = (char *)&nretrans; cp2 = buf + 27; for ( i = 0; i < 4; i++ ) *cp1++ = *cp2--; } } if (*ident) fprintf(stdout, "%s: ", ident + 1); if (format & PARSE) strcpy(fmt, P_PERF_FMT_INTERVAL); else strcpy(fmt, PERF_FMT_INTERVAL); fprintf(stdout, fmt, (double)(nrbytes - pbytes)/(1024*1024), realtd, (double)(nrbytes - pbytes)/realtd/125000); if (udplossinfo) { if (!(format & NODROPS)) { if (format & PARSE) strcpy(fmt, P_DROP_FMT_INTERVAL); else strcpy(fmt, DROP_FMT_INTERVAL); fprintf(stdout, fmt, ((ntbytes - ptbytes) - (nrbytes - pbytes)) /buflen, (ntbytes - ptbytes)/buflen); } if (!(format & NOPERCENTLOSS)) { deltarbytes = nrbytes - pbytes; deltatbytes = ntbytes - ptbytes; fractloss = (deltatbytes ? 1.0 - (double)deltarbytes /(double)deltatbytes : 0.0); if (format & PARSE) strcpy(fmt, P_LOSS_FMT_INTERVAL); else if ((fractloss != 0.0) && (fractloss < 0.001)) strcpy(fmt, LOSS_FMT_INTERVAL5); else strcpy(fmt, LOSS_FMT_INTERVAL); fprintf(stdout, fmt, fractloss * 100); } } if (read_retrans) { if (format & PARSE) fprintf(stdout, P_RETRANS_FMT_INTERVAL, ((retransinfo == 1) || !nrbytes) ? "" : "host-", (nretrans - pretrans)); else fprintf(stdout, RETRANS_FMT_INTERVAL, (nretrans - pretrans), ((retransinfo == 1) || !nrbytes) ? "" : "host-"); } if (format & RUNNINGTOTAL) { if (format & PARSE) strcpy(fmt, P_PERF_FMT_INTERVAL2); else strcpy(fmt, PERF_FMT_INTERVAL2); fprintf(stdout, fmt, (double)nrbytes/(1024*1024), realt, (double)nrbytes/realt/125000 ); if (udplossinfo) { if (!(format & NODROPS)) { if (format & PARSE) strcpy(fmt, P_DROP_FMT_INTERVAL); else strcpy(fmt, DROP_FMT_INTERVAL); fprintf(stdout, fmt, (ntbytes - nrbytes) /buflen, ntbytes/buflen); } if (!(format & NOPERCENTLOSS)) { fractloss = (ntbytes ? 1.0 - (double)nrbytes /(double)ntbytes : 0.0); if (format & PARSE) strcpy(fmt, P_LOSS_FMT_INTERVAL); else if ((fractloss != 0.0) && (fractloss < 0.001)) strcpy(fmt, LOSS_FMT_INTERVAL5); else strcpy(fmt, LOSS_FMT_INTERVAL); fprintf(stdout, fmt, fractloss * 100); } } if (read_retrans) { if (format & PARSE) fprintf(stdout, P_RETRANS_FMT_INTERVAL, ((retransinfo == 1) || !nrbytes) ? "" : "host-", nretrans); else fprintf(stdout, RETRANS_FMT_INTERVAL, nretrans, ((retransinfo == 1) || !nrbytes) ? "" : "host-"); } } if (udplossinfo && (format & XMITSTATS)) { if (format & PARSE) strcpy(fmt, P_PERF_FMT_INTERVAL3); else strcpy(fmt, PERF_FMT_INTERVAL3); fprintf(stdout, fmt, (double)(ntbytes - ptbytes)/1024/1024); if (format & RUNNINGTOTAL) { if (format & PARSE) strcpy(fmt, P_PERF_FMT_INTERVAL4); else strcpy(fmt, PERF_FMT_INTERVAL4); fprintf(stdout, fmt, (double)ntbytes/1024/1024); if (format & DEBUGINTERVAL) fprintf(stdout, " Pre: %.4f MB", (double)ntbytesc /1024/1024); } } fprintf(stdout, "\n"); fflush(stdout); /* beginnings of timestamps - not ready for prime time */ /* bcopy(buf + 8, &timet.tv_sec, 4); */ /* bcopy(buf + 12, &timet.tv_usec, 4); */ /* tvsub( &timed, &timec, &timet ); */ /* realt = timed.tv_sec + ((double)timed.tv_usec) */ /* / 1000000; */ /* if( realt <= 0.0 ) realt = 0.000001; */ /* fprintf(stdout, "%.3f ms-OWD timet = %08X/%08X timec = %08X/%08X\n", */ /* realt*1000, timet.tv_sec, timet.tv_usec, */ /* timec.tv_sec, timec.tv_usec); */ /* fprintf(stdout, "%.3f ms-OWD\n", realt*1000); */ /* fflush(stdout); */ timep.tv_sec = timec.tv_sec; timep.tv_usec = timec.tv_usec; pbytes = nrbytes; ptbytes = ntbytes; pretrans = nretrans; } } else intr = 1; return; } int main( int argc, char **argv ) { double MB; double rate_opt; double fractloss; int cpu_util; int first_read; int ocorrection = 0; double correction = 0.0; int pollst = 0; int i, j; char *cp1, *cp2; char ch; int error_num = 0; int sockopterr = 0; int save_errno; struct servent *sp = 0; struct addrinfo hints, *res[MAXSTREAM + 1] = { NULL }; struct timeval time_eod; /* time EOD packet was received */ struct timeval timepkrcv; /* time last data packet received */ struct timeval timed; /* time delta */ struct timeval timeconn1; /* time before connect() for RTT */ struct timeval timeconn2; /* time after connect() for RTT */ struct timeval timeconn; /* time to connect() == RTT */ short save_events; int skiparg; int reqval; int got_srvr_retrans; double idle_data_min = IDLE_DATA_MIN; double idle_data_max = IDLE_DATA_MAX; double default_idle_data = DEFAULT_IDLE_DATA; sendwin = 0; rcvwin = 0; srvrwin = -1; format |= WANTRTT; if (argc < 2) goto usage; argv++; argc--; while( argc>0 && argv[0][0] == '-' ) { skiparg = 0; switch (argv[0][1]) { case '4': domain = PF_INET; af = AF_INET; explicitaf = 1; break; #ifdef AF_INET6 case '6': domain = PF_INET6; af = AF_INET6; explicitaf = 1; break; #endif case 'B': b_flag = 1; break; case 't': trans = 1; break; case 'r': trans = 0; break; case 'd': options |= SO_DEBUG; break; case 'D': nodelay = 1; break; case 'n': reqval = 0; if (argv[0][2] == 'b') { fprintf(stderr, "option \"-nb\" no longer supported, use \"-n###[k|m|g|t|p]\" instead\n"); fflush(stderr); exit(1); } cp1 = getoptvalp(argv, 2, reqval, &skiparg); nbuf = strtoull(cp1, NULL, 0); if (nbuf == 0) { if (errno == EINVAL) { fprintf(stderr, "invalid nbuf = %s\n", &argv[0][2]); fflush(stderr); exit(1); } else { nbuf = DEFAULT_NBUF; break; } } if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'b') || (ch == 'B')) nbuf_bytes = 1; else if ((ch == 'k') || (ch == 'K')) { nbuf *= 1024; nbuf_bytes = 1; } else if ((ch == 'm') || (ch == 'M')) { nbuf *= 1048576; nbuf_bytes = 1; } else if ((ch == 'g') || (ch == 'G')) { nbuf *= 1073741824; nbuf_bytes = 1; } else if ((ch == 't') || (ch == 'T')) { nbuf *= 1099511627776ull; nbuf_bytes = 1; } else if ((ch == 'p') || (ch == 'P')) { nbuf *= 1125899906842624ull; nbuf_bytes = 1; } break; case 'l': reqval = 0; cp1 = getoptvalp(argv, 2, reqval, &skiparg); buflen = atoi(cp1); buflenopt = 1; if (buflen < 1) { fprintf(stderr, "invalid buflen = %d\n", buflen); fflush(stderr); exit(1); } if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'k') || (ch == 'K')) buflen *= 1024; else if ((ch == 'm') || (ch == 'M')) buflen *= 1048576; break; case 'w': reqval = 0; if (argv[0][2] == 's') { cp1 = getoptvalp(argv, 3, reqval, &skiparg); srvrwin = atoi(cp1); if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'k') || (ch == 'K')) srvrwin *= 1024; else if ((ch == 'm') || (ch == 'M')) srvrwin *= 1048576; else if ((ch == 'g') || (ch == 'G')) srvrwin *= 1073741824; else if ((ch != 'b') && (ch != 'B')) srvrwin *= 1024; if (srvrwin < 0) { fprintf(stderr, "invalid srvrwin = %d\n", srvrwin); fflush(stderr); exit(1); } } else { if (argv[0][2] == 'b') { braindead = 1; cp1 = getoptvalp(argv, 3, reqval, &skiparg); if (*cp1 == '\0') break; sendwin = atoi(cp1); } else { cp1 = getoptvalp(argv, 2, reqval, &skiparg); sendwin = atoi(cp1); } if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'k') || (ch == 'K')) sendwin *= 1024; else if ((ch == 'm') || (ch == 'M')) sendwin *= 1048576; else if ((ch == 'g') || (ch == 'G')) sendwin *= 1073741824; else if ((ch != 'b') && (ch != 'B')) sendwin *= 1024; rcvwin = sendwin; if (sendwin < 0) { fprintf(stderr, "invalid sendwin = %d\n", sendwin); fflush(stderr); exit(1); } } if (srvrwin == -1) { srvrwin = sendwin; } break; case 's': sinkmode = 0; /* sink/source data */ break; case 'p': reqval = 0; tmpport = atoi(getoptvalp(argv, 2, reqval, &skiparg)); if ((tmpport < 5001) || (tmpport > 65535)) { fprintf(stderr, "invalid port = %d\n", tmpport); fflush(stderr); exit(1); } port = tmpport; break; case 'P': reqval = 0; tmpport = atoi(getoptvalp(argv, 2, reqval, &skiparg)); if ((tmpport < 5000) || (tmpport > 65535)) { fprintf(stderr, "invalid ctlport = %d\n", tmpport); fflush(stderr); exit(1); } ctlport = tmpport; break; case 'u': udp = 1; if (!buflenopt) buflen = DEFAULTUDPBUFLEN; if (argv[0][2] == 'u') { haverateopt = 1; rate = MAXRATE; } break; case 'v': brief = 0; if (argv[0][2] == 'v') verbose = 1; break; case 'N': reqval = 0; nstream = atoi(getoptvalp(argv, 2, reqval, &skiparg)); if (nstream < 1) { fprintf(stderr, "invalid nstream = %d\n", nstream); fflush(stderr); exit(1); } if (nstream > MAXSTREAM) { fprintf(stderr, "nstream = %d > MAXSTREAM, set to %d\n", nstream, MAXSTREAM); nstream = MAXSTREAM; } if (nstream > 1) { b_flag = 1; retransinfo = -1; send_retrans = 0; read_retrans = 0; } break; case 'R': reqval = 0; haverateopt = 1; if (argv[0][2] == 'i') { cp1 = getoptvalp(argv, 3, reqval, &skiparg); sscanf(cp1, "%lf", &rate_opt); irate = 1; } else if (argv[0][2] == 'u') { rate_opt = 0.0; cp1 = &argv[0][3]; } else { cp1 = getoptvalp(argv, 2, reqval, &skiparg); sscanf(cp1, "%lf", &rate_opt); } if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'm') || (ch == 'M')) rate_opt *= 1000; else if ((ch == 'g') || (ch == 'G')) rate_opt *= 1000000; else if (ch == 'p') { rate_pps = 1; if (strlen(cp1) >= 2) { ch = *(cp1 + strlen(cp1) - 2); if ((ch == 'k') || (ch == 'K')) rate_opt *= 1000; if ((ch == 'm') || (ch == 'M')) rate_opt *= 1000000; } } rate = rate_opt; if (rate == 0) rate = MAXRATE; break; case 'T': reqval = 0; cp1 = getoptvalp(argv, 2, reqval, &skiparg); sscanf(cp1, "%lf", &timeout); if (timeout < 0) { fprintf(stderr, "invalid timeout = %f\n", timeout); fflush(stderr); exit(1); } else if (timeout == 0.0) timeout = DEFAULT_TIMEOUT; if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'm') || (ch == 'M')) timeout *= 60.0; else if ((ch == 'h') || (ch == 'H')) timeout *= 3600.0; else if ((ch == 'd') || (ch == 'D')) timeout *= 86400.0; itimer.it_value.tv_sec = timeout; itimer.it_value.tv_usec = (timeout - itimer.it_value.tv_sec)*1000000; if (timeout && !nbuf) nbuf = INT_MAX; break; case 'i': reqval = 0; cp1 = getoptvalp(argv, 2, reqval, &skiparg); sscanf(cp1, "%lf", &interval); if (interval < 0.0) { fprintf(stderr, "invalid interval = %f\n", interval); fflush(stderr); exit(1); } else if (interval == 0.0) interval = 1.0; if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'm') || (ch == 'M')) interval *= 60.0; else if ((ch == 'h') || (ch == 'H')) interval *= 3600.0; break; case 'I': reqval = 1; ident[0] = '-'; strncpy(&ident[1], getoptvalp(argv, 2, reqval, &skiparg), 40); ident[41] = '\0'; break; case 'F': reverse = 1; break; case 'b': reqval = 0; cp1 = getoptvalp(argv, 2, reqval, &skiparg); if (*cp1) brief = atoi(cp1); else brief = 1; break; case 'S': if (strchr(&argv[0][2], 'P')) pass_ctlport = 1; trans = 0; clientserver = 1; brief = 0; verbose = 1; break; case '1': oneshot = 1; trans = 0; clientserver = 1; brief = 0; verbose = 1; break; case 'V': fprintf(stdout, "nuttcp-%d.%d.%d%s\n", vers_major, vers_minor, vers_delta, beta ? BETA_STR : ""); exit(0); case 'f': if (strcmp(&argv[0][2], "xmitstats") == 0) format |= XMITSTATS; else if (strcmp(&argv[0][2], "debuginterval") == 0) format |= DEBUGINTERVAL; else if (strcmp(&argv[0][2], "runningtotal") == 0) format |= RUNNINGTOTAL; else if (strcmp(&argv[0][2], "-percentloss") == 0) format |= NOPERCENTLOSS; else if (strcmp(&argv[0][2], "-drops") == 0) format |= NODROPS; else if (strcmp(&argv[0][2], "-retrans") == 0) format |= NORETRANS; else if (strcmp(&argv[0][2], "debugretrans") == 0) format |= DEBUGRETRANS; else if (strcmp(&argv[0][2], "debugpoll") == 0) format |= DEBUGPOLL; else if (strcmp(&argv[0][2], "debugmtu") == 0) format |= DEBUGMTU; else if (strcmp(&argv[0][2], "parse") == 0) format |= PARSE; else if (strcmp(&argv[0][2], "-beta") == 0) format |= NOBETAMSG; /* below is for compatibility with 6.0.x beta */ else if (strcmp(&argv[0][2], "rtt") == 0) format |= WANTRTT; else if (strcmp(&argv[0][2], "-rtt") == 0) format &= ~WANTRTT; else { if (argv[0][2]) { fprintf(stderr, "invalid format option \"%s\"\n", &argv[0][2]); fflush(stderr); exit(1); } else { fprintf(stderr, "invalid null format option\n"); fprintf(stderr, "perhaps the \"-F\" flip option was intended\n"); fflush(stderr); exit(1); } } break; case 'x': reqval = 0; if (argv[0][2] == 't') { traceroute = 1; brief = 1; } #ifdef HAVE_SETPRIO else if (argv[0][2] == 'P') priority = atoi(getoptvalp(argv, 3, reqval, &skiparg)); #endif else { if (argv[0][2]) { fprintf(stderr, "invalid x option \"%s\"\n", &argv[0][2]); fflush(stderr); exit(1); } else { fprintf(stderr, "invalid null x option\n"); fflush(stderr); exit(1); } } break; case '3': thirdparty = 1; break; case 'm': reqval = 0; cp1 = getoptvalp(argv, 2, reqval, &skiparg); if (*cp1) mc_param = atoi(cp1); else mc_param = 1; if ((mc_param < 1) || (mc_param > 255)) { fprintf(stderr, "invalid multicast ttl = %d\n", mc_param); fflush(stderr); exit(1); } multicast = mc_param; break; case 'M': reqval = 1; datamss = atoi(getoptvalp(argv, 2, reqval, &skiparg)); if (datamss < 0) { fprintf(stderr, "invalid datamss = %d\n", datamss); fflush(stderr); exit(1); } break; case 'c': reqval = 1; cp1 = getoptvalp(argv, 2, reqval, &skiparg); tos = strtol(cp1, NULL, 0); if (*cp1) ch = *(cp1 + strlen(cp1) - 1); else ch = '\0'; if ((ch == 'p') || (ch == 'P')) { /* Precedence */ if (tos > 7) { fprintf(stderr, "invalid precedence = %d\n", tos); fflush(stderr); exit(1); } tos <<= 5; } else if ((ch != 't') && (ch != 'T')) { /* DSCP */ if (tos > 63) { fprintf(stderr, "invalid dscp = %d\n", tos); fflush(stderr); exit(1); } tos <<= 2; } if (tos > 255) { fprintf(stderr, "invalid tos = %d\n", tos); fflush(stderr); exit(1); } break; case 'a': retry_server = 1; break; case '-': if (strcmp(&argv[0][2], "nofork") == 0) { nofork=1; } else if (strcmp(&argv[0][2], "no3rdparty") == 0) { no3rd=1; } else if (strcmp(&argv[0][2], "idle-data-timeout") == 0) { if ((cp1 = strchr(argv[1], '/'))) { if (strchr(cp1 + 1, '/')) { if (sscanf(argv[1], "%lf/%lf/%lf", &idle_data_min, &default_idle_data, &idle_data_max) != 3) { fprintf(stderr, "error scanning idle-data-timeout parameter = %s\n", argv[1]); fflush(stderr); exit(1); } if (idle_data_min <= 0.0) { fprintf(stderr, "invalid value for idle-data-timeout minimum = %f\n", idle_data_min); fflush(stderr); exit(1); } if (default_idle_data <= 0.0) { fprintf(stderr, "invalid value for idle-data-timeout default = %f\n", default_idle_data); fflush(stderr); exit(1); } if (idle_data_max <= 0.0) { fprintf(stderr, "invalid value for idle-data-timeout maximum = %f\n", idle_data_max); fflush(stderr); exit(1); } if (idle_data_max < idle_data_min) { fprintf(stderr, "error: idle-data-timeout maximum of %f < minimum of %f\n", idle_data_max, idle_data_min); fflush(stderr); exit(1); } } else { fprintf(stderr, "invalid idle-data-timeout parameter = %s\n", argv[1]); fflush(stderr); exit(1); } } else { sscanf(argv[1], "%lf", &idle_data_min); if (idle_data_min <= 0.0) { fprintf(stderr, "invalid value for idle-data-timeout = %f\n", idle_data_min); fflush(stderr); exit(1); } idle_data_max = idle_data_min; default_idle_data = idle_data_min; } argv++; argc--; } else if (strcmp(&argv[0][2], "single-threaded") == 0) { single_threaded=1; } #ifdef IPV6_V6ONLY else if (strcmp(&argv[0][2], "disable-v4-mapped") == 0) { v4mapped=0; } else if (strcmp(&argv[0][2], "enable-v4-mapped") == 0) { v4mapped=1; } #endif else { goto usage; } break; case 'h': default: goto usage; } argv++; argc--; if (skiparg) { argv++; argc--; } } if (argc > 2) goto usage; if (trans && (argc < 1)) goto usage; if (clientserver && (argc != 0)) goto usage; if (!clientserver && !trans && (argc < 1)) { fprintf(stderr, "nuttcp: Warning: Using obsolete \"classic\" mode:\n"); fprintf(stderr, " Automatically switching to " "oneshot server mode " "(\"nuttcp -1\")\n"); oneshot = 1; trans = 0; clientserver = 1; brief = 0; verbose = 1; } host3 = NULL; if (argc == 2) { host3 = argv[1]; if (strlen(host3) > HOSTNAMELEN) { fprintf(stderr, "3rd party host '%s' too long\n", host3); fflush(stderr); exit(1); } cp1 = host3; while (*cp1) { if (!isalnum((int)(*cp1)) && (*cp1 != '-') && (*cp1 != '.') && (*cp1 != ':') && (*cp1 != '/')) { fprintf(stderr, "invalid 3rd party host '%s'\n", host3); fflush(stderr); exit(1); } cp1++; } } if (multicast) { udp = 1; if (!buflenopt) buflen = DEFAULT_MC_UDPBUFLEN; nstream = 1; } if (udp && !haverateopt) rate = DEFAULT_UDP_RATE; bzero((char *)&frominet, sizeof(frominet)); bzero((char *)&clientaddr, sizeof(clientaddr)); #ifdef AF_INET6 bzero((char *)&clientaddr6, sizeof(clientaddr6)); clientscope6 = 0; #endif if (!nbuf) { if (timeout == 0.0) { if (sinkmode) { timeout = DEFAULT_TIMEOUT; itimer.it_value.tv_sec = timeout; itimer.it_value.tv_usec = (timeout - itimer.it_value.tv_sec) *1000000; } nbuf = INT_MAX; } } if (srvrwin == -1) { srvrwin = sendwin; } if ((argc == 0) && !explicitaf) { domain = PF_INET; af = AF_INET; } if (argc >= 1) { host = argv[0]; stream_idx = 0; res[0] = NULL; cp1 = host; if (host[strlen(host) - 1] == '/') { fprintf(stderr, "bad hostname or address: trailing '/' not allowed: %s\n", host); fflush(stderr); exit(1); } if (strchr(host, '/') && !trans && !reverse) { fprintf(stderr, "multiple control/data paths not supported for receive\n"); fflush(stderr); exit(1); } if (strchr(host, '/') && trans && reverse) { fprintf(stderr, "multiple control/data paths not supported for flipped transmit\n"); fflush(stderr); exit(1); } if (host[0] == '/') { host++; cp1++; stream_idx = 1; } else if ((cp2 = strchr(host, '/'))) { host = cp2 + 1; } while (stream_idx <= nstream) { bzero(&hints, sizeof(hints)); res[stream_idx] = NULL; if (explicitaf) hints.ai_family = af; if ((cp2 = strchr(cp1, '/'))) { if (stream_idx == nstream) { fprintf(stderr, "bad hostname or address: too many data paths for nstream=%d: %s\n", nstream, argv[0]); fflush(stderr); exit(1); } *cp2 = '\0'; } if ((error_num = getaddrinfo(cp1, NULL, &hints, &res[stream_idx]))) { if (cp2) *cp2++ = '/'; fprintf(stderr, "bad hostname or address: %s: %s\n", gai_strerror(error_num), argv[0]); fflush(stderr); exit(1); } af = res[stream_idx]->ai_family; /* * At the moment PF_ matches AF_ but are maintained seperate and the socket * call is supposed to be PF_ * * For now we set domain from the address family we looked up, but if these * ever get changed to not match some code will have to go here to find the * domain appropriate for the family */ domain = af; stream_idx++; if (cp2) { *cp2++ = '/'; cp1 = cp2; } else cp1 = host; } if (!res[0]) { if ((cp1 = strchr(host, '/'))) *cp1 = '\0'; if ((error_num = getaddrinfo(host, NULL, &hints, &res[0]))) { if (cp1) *cp1++ = '/'; fprintf(stderr, "bad hostname or address: %s: %s\n", gai_strerror(error_num), argv[0]); fflush(stderr); exit(1); } af = res[0]->ai_family; /* see previous comment about domain */ domain = af; if (cp1) *cp1 = '/'; } } #ifdef AF_INET6 if (multicast && (af == AF_INET6)) { fprintf(stderr, "multicast not yet supported for IPv6\n"); fflush(stderr); exit(1); } #endif if (!port) { if (af == AF_INET) { if ((sp = getservbyname( "nuttcp-data", "tcp" ))) port = ntohs(sp->s_port); else port = DEFAULT_PORT; } #ifdef AF_INET6 else if (af == AF_INET6) { if ((sp = getservbyname( "nuttcp6-data", "tcp" ))) port = ntohs(sp->s_port); else { if ((sp = getservbyname( "nuttcp-data", "tcp" ))) port = ntohs(sp->s_port); else port = DEFAULT_PORT; } } #endif else { err("unsupported AF"); } } if (!ctlport) { if (af == AF_INET) { if ((sp = getservbyname( "nuttcp", "tcp" ))) ctlport = ntohs(sp->s_port); else ctlport = DEFAULT_CTLPORT; } #ifdef AF_INET6 else if (af == AF_INET6) { if ((sp = getservbyname( "nuttcp6", "tcp" ))) ctlport = ntohs(sp->s_port); else { if ((sp = getservbyname( "nuttcp", "tcp" ))) ctlport = ntohs(sp->s_port); else ctlport = DEFAULT_CTLPORT; } } #endif else { err("unsupported AF"); } } if ((port < 5000) || ((port + nstream - 1) > 65535)) { fprintf(stderr, "invalid port/nstream = %d/%d\n", port, nstream); fflush(stderr); exit(1); } if ((ctlport >= port) && (ctlport <= (port + nstream - 1))) { fprintf(stderr, "ctlport = %d overlaps port/nstream = %d/%d\n", ctlport, port, nstream); fflush(stderr); exit(1); } if (timeout && (interval >= timeout)) { fprintf(stderr, "ignoring interval=%f which is greater than or equal timeout=%f\n", interval, timeout); fflush(stderr); interval = 0; } if (clientserver) { if (trans) { fprintf(stderr, "server mode only allowed for receiver\n"); goto usage; } udp = 0; start_idx = 0; ident[0] = '\0'; if (af == AF_INET) { struct sockaddr_in peer; socklen_t peerlen = sizeof(peer); if (getpeername(0, (struct sockaddr *)&peer, &peerlen) == 0) { #ifndef AF_INET6 if (peer.sin_family == AF_INET) #else if ((peer.sin_family == AF_INET) || (peer.sin_family == AF_INET6)) #endif { clientaddr = peer.sin_addr; inetd = 1; oneshot = 1; start_idx = 1; } } } #ifdef AF_INET6 else if (af == AF_INET6) { struct sockaddr_in6 peer; socklen_t peerlen = sizeof(peer); if (getpeername(0, (struct sockaddr *)&peer, &peerlen) == 0) { if ((peer.sin6_family == AF_INET) || (peer.sin6_family == AF_INET6)) { clientaddr6 = peer.sin6_addr; clientscope6 = peer.sin6_scope_id; inetd = 1; oneshot = 1; start_idx = 1; } } } #endif else { err("unsupported AF"); } } if (clientserver && !inetd && sinkmode) { close(0); close(1); close(2); open("/dev/null", O_RDWR); dup(0); dup(0); } if (clientserver && !inetd && !oneshot && !sinkmode) { fprintf(stderr, "option \"-s\" invalid with \"-S\" server mode\n"); fprintf(stderr, "option \"-s\" can be used with \"-1\" oneshot server mode\n"); fflush(stderr); exit(1); } #ifdef HAVE_SETPRIO if (priority) { if (setpriority(PRIO_PROCESS, 0, priority) != 0) err("couldn't change priority"); } #endif if (argc >= 1) { start_idx = 0; client = 1; clientserver = 1; } if (interval && !clientserver) { fprintf(stderr, "interval option only supported for client/server mode\n"); fflush(stderr); exit(1); } if (reverse && !clientserver) { fprintf(stderr, "flip option only supported for client/server mode\n"); fflush(stderr); exit(1); } if (reverse && udp) { fprintf(stderr, "flip option not supported for UDP\n"); fflush(stderr); exit(1); } if (traceroute) { nstream = 1; if (!clientserver) { fprintf(stderr, "traceroute option only supported for client/server mode\n"); fflush(stderr); exit(1); } } if (host3) { if (!clientserver) { fprintf(stderr, "3rd party nuttcp only supported for client/server mode\n"); fflush(stderr); exit(1); } } if (udp && (buflen < 5)) { fprintf(stderr, "UDP buflen = %d < 5, set to 5\n", buflen); buflen = 5; /* send more than the sentinel size */ } if (udp && (buflen > MAXUDPBUFLEN)) { fprintf(stderr, "UDP buflen = %d > MAXUDPBUFLEN, set to %d\n", buflen, MAXUDPBUFLEN); buflen = MAXUDPBUFLEN; } if (nbuf_bytes && !host3 && !traceroute) { nbuf /= buflen; } if ((rate != MAXRATE) && rate_pps && !host3 && !traceroute) { uint64_t llrate = rate; llrate *= ((double)buflen * 8 / 1000); rate = llrate; } if (udp && interval) { if (buflen >= 32) udplossinfo = 1; else fprintf(stderr, "Unable to print interval loss information if UDP buflen < 32\n"); } if (!udp && trans) { if (buflen >= 32) { retransinfo = 1; b_flag = 1; } else fprintf(stderr, "Unable to print retransmission information if TCP buflen < 32\n"); } ivers = vers_major*10000 + vers_minor*100 + vers_delta; mallocsize = buflen; if (mallocsize < MINMALLOC) mallocsize = MINMALLOC; if( (buf = (char *)malloc(mallocsize)) == (char *)NULL) err("malloc"); pattern( buf, buflen ); #ifdef SIGPIPE signal(SIGPIPE, sigpipe); #endif signal(SIGINT, sigint); if (clientserver && client && !thirdparty && beta && !(format & NOBETAMSG)) { fprintf(stderr, "nuttcp-%d.%d.%d: ", vers_major, vers_minor, vers_delta); fprintf(stderr, "Using beta vers: %s interface/output " "subject to change\n", BETA_FEATURES); fprintf(stderr, " (to suppress this message " "use \"-f-beta\")\n\n"); fflush(stderr); } doit: if (!udp && trans && (format & DEBUGRETRANS)) { sretrans = get_retrans(-1); fprintf(stdout, "initial system retrans = %d\n", sretrans); } nretrans = 0; for ( stream_idx = start_idx; stream_idx <= nstream; stream_idx++ ) { if (clientserver && (stream_idx == 1)) { retransinfo = 0; send_retrans = 1; read_retrans = 1; if (client) { if (udp && !host3 && !traceroute) { ctlconnmss = 0; optlen = sizeof(ctlconnmss); if (getsockopt(fd[0], IPPROTO_TCP, TCP_MAXSEG, (void *)&ctlconnmss, &optlen) < 0) err("get ctlconn maximum segment size didn't work"); if (!ctlconnmss) { ctlconnmss = NON_JUMBO_ETHER_MSS; if (format & DEBUGMTU) { fprintf(stderr, "nuttcp%s%s: Warning: Control connection MSS reported as 0, using %d\n", trans?"-t":"-r", ident, ctlconnmss); fflush(stderr); } } else if (format & DEBUGMTU) fprintf(stderr, "ctlconnmss = %d\n", ctlconnmss); if (buflenopt) { if (buflen > ctlconnmss + TCP_UDP_HDRLEN_DELTA) { if (format & PARSE) fprintf(stderr, "nuttcp%s%s: Warning=\"IP_frags_or_no_data_reception_since_buflen=%d_>_ctlconnmss=%d\"\n", trans?"-t":"-r", ident, buflen, ctlconnmss); else fprintf(stderr, "nuttcp%s%s: Warning: IP frags or no data reception since buflen=%d > ctlconnmss=%d\n", trans?"-t":"-r", ident, buflen, ctlconnmss); fflush(stderr); } } else { while (buflen > ctlconnmss) { buflen >>= 1; if (nbuf_bytes) nbuf <<= 1; if ((rate != MAXRATE) && rate_pps) rate >>= 1; } } if (format & DEBUGMTU) fprintf(stderr, "buflen = %d\n", buflen); } if (!(ctlconn = fdopen(fd[0], "w"))) err("fdopen: ctlconn for writing"); if (!sinkmode) { if (trans) savestdin=dup(0); else { savestdout=dup(1); close(1); dup(2); } } close(0); dup(fd[0]); if (srvr_helo) { fprintf(ctlconn, HELO_FMT, vers_major, vers_minor, vers_delta); fflush(ctlconn); if (!fgets(buf, mallocsize, stdin)) { if ((errno == ECONNRESET) && (num_connect_tries < MAX_CONNECT_TRIES) && retry_server) { /* retry control * connection to server * for certain possibly * transient errors */ fclose(ctlconn); goto doit; } mes("error from server"); fprintf(stderr, "server aborted connection\n"); fflush(stderr); exit(1); } if (sscanf(buf, HELO_FMT, &rvers_major, &rvers_minor, &rvers_delta) < 3) { rvers_major = 0; rvers_minor = 0; rvers_delta = 0; srvr_helo = 0; while (fgets(buf, mallocsize, stdin)) { if (strncmp(buf, "KO", 2) == 0) break; } fclose(ctlconn); goto doit; } irvers = rvers_major*10000 + rvers_minor*100 + rvers_delta; } if (host3 && nbuf_bytes && (irvers < 50501)) nbuf /= buflen; if (host3 && (rate != MAXRATE) && rate_pps && (irvers < 50501)) { uint64_t llrate = rate; llrate *= ((double)buflen * 8 / 1000); rate = llrate; } if (host3 && !buflenopt && (irvers >= 50302)) buflen = 0; fprintf(ctlconn, "buflen = %d, nbuf = %llu, win = %d, nstream = %d, rate = %lu, port = %hu, trans = %d, braindead = %d", buflen, nbuf, srvrwin, nstream, rate, port, trans, braindead); if (irvers >= 30200) fprintf(ctlconn, ", timeout = %f", timeout); else { timeout_sec = timeout; if (itimer.it_value.tv_usec) timeout_sec++; fprintf(ctlconn, ", timeout = %ld", timeout_sec); if (!trans && itimer.it_value.tv_usec && (brief <= 0)) { fprintf(stdout, "nuttcp-r%s: transmit timeout value rounded up to %ld second%s for old server\n", ident, timeout_sec, (timeout_sec == 1)?"":"s"); } } fprintf(ctlconn, ", udp = %d, vers = %d.%d.%d", udp, vers_major, vers_minor, vers_delta); if (irvers >= 30302) fprintf(ctlconn, ", interval = %f", interval); else { if (interval) { fprintf(stdout, "nuttcp%s%s: interval option not supported by server version %d.%d.%d, need >= 3.3.2\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); interval = 0.0; abortconn = 1; } } if (irvers >= 30401) fprintf(ctlconn, ", reverse = %d", reverse); else { if (reverse) { fprintf(stdout, "nuttcp%s%s: flip option not supported by server version %d.%d.%d, need >= 3.4.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); reverse = 0; abortconn = 1; } } if (irvers >= 30501) fprintf(ctlconn, ", format = %d", format); else { if (format) { fprintf(stdout, "nuttcp%s%s: format option not supported by server version %d.%d.%d, need >= 3.5.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); format = 0; } } if (irvers >= 30601) { fprintf(ctlconn, ", traceroute = %d", traceroute); if (traceroute) skip_data = 1; fprintf(ctlconn, ", irate = %d", irate); } else { if (traceroute) { fprintf(stdout, "nuttcp%s%s: traceroute option not supported by server version %d.%d.%d, need >= 3.6.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); traceroute = 0; abortconn = 1; } if (irate && !trans) { fprintf(stdout, "nuttcp%s%s: instantaneous rate option not supported by server version %d.%d.%d, need >= 3.6.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); irate = 0; } } if (srvrwin && udp && (irvers < 30602)) { fprintf(stdout, "nuttcp%s%s: server version %d.%d.%d ignores UDP window parameter, need >= 3.6.2\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); } if ((irvers < 40101) && (format & PARSE)) { fprintf(stdout, "nuttcp%s%s: \"-fparse\" option not supported by server version %d.%d.%d, need >= 4.1.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); format &= ~PARSE; abortconn = 1; } if (irvers >= 50001) { fprintf(ctlconn, ", thirdparty = %.*s", HOSTNAMELEN, host3 ? host3 : "_NULL_"); if (host3) { skip_data = 1; fprintf(ctlconn, " , brief3 = %d", brief); } } else { if (host3) { fprintf(stdout, "nuttcp%s%s: 3rd party nuttcp not supported by server version %d.%d.%d, need >= 5.0.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); host3 = NULL; abortconn = 1; } } if (irvers >= 50101) { fprintf(ctlconn, " , multicast = %d", multicast); } else { if (multicast) { fprintf(stdout, "nuttcp%s%s: multicast not supported by server version %d.%d.%d, need >= 5.1.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); multicast = 0; abortconn = 1; } } if (irvers >= 50201) { fprintf(ctlconn, " , datamss = %d", datamss); } else { if (datamss && !trans) { fprintf(stdout, "nuttcp%s%s: mss option not supported by server version %d.%d.%d, need >= 5.2.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); datamss = 0; abortconn = 1; } } if (irvers >= 50301) { fprintf(ctlconn, " , tos = %X", tos); } else { if (tos && !trans) { fprintf(stdout, "nuttcp%s%s: tos option not supported by server version %d.%d.%d, need >= 5.3.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); tos = 0; abortconn = 1; } } if (irvers >= 50501) { fprintf(ctlconn, " , nbuf_bytes = %d", nbuf_bytes); fprintf(ctlconn, " , rate_pps = %d", rate_pps); fprintf(ctlconn, " , nodelay = %d", nodelay); } else { if (host3 && udp && nbuf_bytes) { fprintf(stdout, "nuttcp%s%s: Warning: \"-n\" option in bytes for third party not supported\n", trans?"-t":"-r", ident); fprintf(stdout, " Warning: by server version %d.%d.%d, need >= 5.5.1\n", rvers_major, rvers_minor, rvers_delta); fprintf(stdout, " Warning: third party request may not transfer\n"); fprintf(stdout, " Warning: desired number of bytes in some UDP cases\n"); fflush(stdout); nbuf_bytes = 0; } if (host3 && udp && rate_pps) { fprintf(stdout, "nuttcp%s%s: Warning: \"-R\" option in pps for third party not supported\n", trans?"-t":"-r", ident); fprintf(stdout, " Warning: by server version %d.%d.%d, need >= 5.5.1\n", rvers_major, rvers_minor, rvers_delta); fprintf(stdout, " Warning: third party request may not produce\n"); fprintf(stdout, " Warning: desired pps rate in some UDP cases\n"); fflush(stdout); rate_pps = 0; } if (nodelay && !trans) { fprintf(stdout, "nuttcp%s%s: TCP_NODELAY opt not supported by server version %d.%d.%d, need >= 5.5.1\n", trans?"-t":"-r", ident, rvers_major, rvers_minor, rvers_delta); fflush(stdout); nodelay = 0; abortconn = 1; } } fprintf(ctlconn, "\n"); fflush(ctlconn); if (abortconn) { brief = 1; if ((!trans && !reverse) || (trans && reverse)) skip_data = 1; } if (!fgets(buf, mallocsize, stdin)) { mes("error from server"); fprintf(stderr, "server aborted connection\n"); fflush(stderr); exit(1); } if (irvers < 30403) udplossinfo = 0; if (irvers >= 50401) { two_bod = 1; handle_urg = 1; } if (udp || (buflen < 32) || (irvers < 60001)) { if (trans) send_retrans = 0; else read_retrans = 0; } if (strncmp(buf, "OK", 2) != 0) { mes("error from server"); fprintf(stderr, "server "); while (fgets(buf, mallocsize, stdin)) { if (strncmp(buf, "KO", 2) == 0) break; fputs(buf, stderr); } fflush(stderr); exit(1); } if (sscanf(buf, "OK v%d.%d.%d\n", &rvers_major, &rvers_minor, &rvers_delta) < 3) { rvers_major = 0; rvers_minor = 0; rvers_delta = 0; } irvers = rvers_major*10000 + rvers_minor*100 + rvers_delta; usleep(10000); } else { if (inetd) { ctlconn = stdin; } else { if (!(ctlconn = fdopen(fd[0], "r"))) err("fdopen: ctlconn for reading"); } fflush(stdout); if (!inetd) { /* manually started server */ /* send stdout to client */ savestdout=dup(1); close(1); dup(fd[0]); if (!nofork) { /* send stderr to client */ close(2); dup(1); if (!single_threaded) { /* multi-threaded server */ if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid != 0) { /* parent just waits for * quick child exit */ while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; err("wait failed"); } } /* and then accepts another * client connection */ goto cleanup; } /* child just makes a grandchild * and then immediately exits * (avoids zombie processes) */ if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid != 0) exit(0); /* grandkid does all the work */ oneshot = 1; } } } fgets(buf, mallocsize, ctlconn); if (sscanf(buf, HELO_FMT, &rvers_major, &rvers_minor, &rvers_delta) == 3) { fprintf(stdout, HELO_FMT, vers_major, vers_minor, vers_delta); fflush(stdout); fgets(buf, mallocsize, ctlconn); } irvers = rvers_major*10000 + rvers_minor*100 + rvers_delta; if (sscanf(buf, "buflen = %d, nbuf = %llu, win = %d, nstream = %d, rate = %lu, port = %hu, trans = %d, braindead = %d, timeout = %lf, udp = %d, vers = %d.%d.%d", &nbuflen, &nbuf, &sendwin, &nstream, &rate, &port, &trans, &braindead, &timeout, &udp, &rvers_major, &rvers_minor, &rvers_delta) < 13) { trans = !trans; fputs("KO\n", stdout); mes("error scanning parameters"); fprintf(stdout, "may be using older client version than server\n"); fputs(buf, stdout); fputs("KO\n", stdout); goto cleanup; } irvers = rvers_major*10000 + rvers_minor*100 + rvers_delta; if (irvers >= 30302) sscanf(strstr(buf, ", interval =") + 13, "%lf", &interval); else interval = 0.0; if (irvers >= 30401) sscanf(strstr(buf, ", reverse =") + 12, "%d", &reverse); else reverse = 0; if (irvers >= 30501) sscanf(strstr(buf, ", format =") + 11, "%d", &format); else format = 0; if (irvers >= 30601) { sscanf(strstr(buf, ", traceroute =") + 15, "%d", &traceroute); if (traceroute) { skip_data = 1; brief = 1; } sscanf(strstr(buf, ", irate =") + 10, "%d", &irate); } else { traceroute = 0; irate = 0; } if (irvers >= 50001) { sprintf(fmt, "%%%ds", HOSTNAMELEN); sscanf(strstr(buf, ", thirdparty =") + 15, fmt, host3buf); host3buf[HOSTNAMELEN] = '\0'; if (strcmp(host3buf, "_NULL_") == 0) host3 = NULL; else host3 = host3buf; if (host3) { if (no3rd) { fputs("KO\n", stdout); fprintf(stdout, "doesn't allow 3rd party nuttcp\n"); fputs("KO\n", stdout); goto cleanup; } cp1 = host3; while (*cp1) { if (!isalnum((int)(*cp1)) && (*cp1 != '-') && (*cp1 != '.') && (*cp1 != ':') && (*cp1 != '/')) { fputs("KO\n", stdout); mes("invalid 3rd party host"); fprintf(stdout, "3rd party host = '%s'\n", host3); fputs("KO\n", stdout); goto cleanup; } cp1++; } skip_data = 1; brief = 1; sscanf(strstr(buf, ", brief3 =") + 11, "%d", &brief3); } } else { host3 = NULL; } if (irvers >= 50101) { sscanf(strstr(buf, ", multicast =") + 14, "%d", &mc_param); } else { mc_param = 0; } if (irvers >= 50201) { sscanf(strstr(buf, ", datamss =") + 12, "%d", &datamss); } else { datamss = 0; } if (irvers >= 50301) { sscanf(strstr(buf, ", tos =") + 8, "%X", &tos); } else { tos = 0; } if (irvers >= 50501) { sscanf(strstr(buf, ", nbuf_bytes =") + 15, "%d", &nbuf_bytes); sscanf(strstr(buf, ", rate_pps =") + 13, "%d", &rate_pps); sscanf(strstr(buf, ", nodelay =") + 12, "%d", &nodelay); } else { nbuf_bytes = 0; rate_pps = 0; nodelay = 0; } trans = !trans; if (inetd && !sinkmode) { fputs("KO\n", stdout); mes("option \"-s\" invalid with inetd server"); fputs("KO\n", stdout); goto cleanup; } if (!traceroute && !host3 && (nbuflen != buflen)) { if (nbuflen < 1) { fputs("KO\n", stdout); mes("invalid buflen"); fprintf(stdout, "buflen = %d\n", nbuflen); fputs("KO\n", stdout); goto cleanup; } free(buf); mallocsize = nbuflen; if (mallocsize < MINMALLOC) mallocsize = MINMALLOC; if( (buf = (char *)malloc(mallocsize)) == (char *)NULL) err("malloc"); pattern( buf, nbuflen ); } buflen = nbuflen; if (nbuf < 1) { fputs("KO\n", stdout); mes("invalid nbuf"); fprintf(stdout, "nbuf = %llu\n", nbuf); fputs("KO\n", stdout); goto cleanup; } rcvwin = sendwin; if (sendwin < 0) { fputs("KO\n", stdout); mes("invalid win"); fprintf(stdout, "win = %d\n", sendwin); fputs("KO\n", stdout); goto cleanup; } if ((nstream < 1) || (nstream > MAXSTREAM)) { fputs("KO\n", stdout); mes("invalid nstream"); fprintf(stdout, "nstream = %d\n", nstream); fputs("KO\n", stdout); goto cleanup; } if (nstream > 1) { b_flag = 1; retransinfo = -1; send_retrans = 0; read_retrans = 0; } if (rate == 0) rate = MAXRATE; if (timeout < 0) { fputs("KO\n", stdout); mes("invalid timeout"); fprintf(stdout, "timeout = %f\n", timeout); fputs("KO\n", stdout); goto cleanup; } itimer.it_value.tv_sec = timeout; itimer.it_value.tv_usec = (timeout - itimer.it_value.tv_sec) *1000000; if ((port < 5000) || ((port + nstream - 1) > 65535)) { fputs("KO\n", stdout); mes("invalid port/nstream"); fprintf(stdout, "port/nstream = %hu/%d\n", port, nstream); fputs("KO\n", stdout); goto cleanup; } if ((ctlport >= port) && (ctlport <= (port + nstream - 1))) { fputs("KO\n", stdout); mes("ctlport overlaps port/nstream"); fprintf(stdout, "ctlport = %hu, port/nstream = %hu/%d\n", ctlport, port, nstream); fputs("KO\n", stdout); goto cleanup; } if (interval < 0) { fputs("KO\n", stdout); mes("invalid interval"); fprintf(stdout, "interval = %f\n", interval); fputs("KO\n", stdout); goto cleanup; } if (mc_param) { if ((mc_param < 1) || (mc_param > 255)) { fputs("KO\n", stdout); mes("invalid multicast ttl"); fprintf(stdout, "multicast ttl = %d\n", mc_param); fputs("KO\n", stdout); goto cleanup; } udp = 1; nstream = 1; if (rate == MAXRATE) rate = DEFAULT_UDP_RATE; } multicast = mc_param; if (datamss < 0) { fputs("KO\n", stdout); mes("invalid datamss"); fprintf(stdout, "datamss = %d\n", datamss); fputs("KO\n", stdout); goto cleanup; } if (tos > 255) { fputs("KO\n", stdout); mes("invalid tos"); fprintf(stdout, "tos = %d\n", tos); fputs("KO\n", stdout); goto cleanup; } if (nbuf_bytes < 0) { fputs("KO\n", stdout); mes("invalid nbuf_bytes"); fprintf(stdout, "nbuf_bytes = %d\n", nbuf_bytes); fputs("KO\n", stdout); goto cleanup; } if (rate_pps < 0) { fputs("KO\n", stdout); mes("invalid rate_pps"); fprintf(stdout, "rate_pps = %d\n", rate_pps); fputs("KO\n", stdout); goto cleanup; } if (nodelay < 0) { fputs("KO\n", stdout); mes("invalid nodelay"); fprintf(stdout, "nodelay = %d\n", nodelay); fputs("KO\n", stdout); goto cleanup; } fprintf(stdout, "OK v%d.%d.%d\n", vers_major, vers_minor, vers_delta); fflush(stdout); if (udp && interval && (buflen >= 32) && (irvers >= 30403)) udplossinfo = 1; if (irvers >= 50401) { two_bod = 1; handle_urg = 1; } if (udp || (buflen < 32) || (irvers < 60001)) { if (trans) send_retrans = 0; else read_retrans = 0; } if ((trans && !reverse) || (!trans && reverse)) usleep(50000); } if (!udp && trans && (nstream == 1)) { nretrans = get_retrans(fd[0]); if (retransinfo > 0) b_flag = 1; } } if (!client) { if (af == AF_INET) { inet_ntop(af, &clientaddr.s_addr, hostbuf, sizeof(hostbuf)); } #ifdef AF_INET6 else if (af == AF_INET6) { inet_ntop(af, clientaddr6.s6_addr, hostbuf, sizeof(hostbuf)); } #endif host = hostbuf; } if ((stream_idx > 0) && skip_data) break; bzero((char *)&sinme[stream_idx], sizeof(sinme[stream_idx])); bzero((char *)&sinhim[stream_idx], sizeof(sinhim[stream_idx])); #ifdef AF_INET6 bzero((char *)&sinme6[stream_idx], sizeof(sinme6[stream_idx])); bzero((char *)&sinhim6[stream_idx], sizeof(sinhim6[stream_idx])); #endif if (((trans && !reverse) && (stream_idx > 0)) || ((!trans && reverse) && (stream_idx > 0)) || (client && (stream_idx == 0))) { /* xmitr initiates connections (unless reversed) */ if (client) { if (af == AF_INET) { sinhim[stream_idx].sin_family = af; bcopy((char *)&(((struct sockaddr_in *)res[stream_idx]->ai_addr)->sin_addr), (char *)&sinhim[stream_idx].sin_addr.s_addr, sizeof(sinhim[stream_idx].sin_addr.s_addr)); } #ifdef AF_INET6 else if (af == AF_INET6) { sinhim6[stream_idx].sin6_family = af; bcopy((char *)&(((struct sockaddr_in6 *)res[stream_idx]->ai_addr)->sin6_addr), (char *)&sinhim6[stream_idx].sin6_addr.s6_addr, sizeof(sinhim6[stream_idx].sin6_addr.s6_addr)); sinhim6[stream_idx].sin6_scope_id = ((struct sockaddr_in6 *)res[stream_idx]->ai_addr)->sin6_scope_id; } #endif else { err("unsupported AF"); } } else { sinhim[stream_idx].sin_family = af; sinhim[stream_idx].sin_addr = clientaddr; #ifdef AF_INET6 sinhim6[stream_idx].sin6_family = af; sinhim6[stream_idx].sin6_addr = clientaddr6; sinhim6[stream_idx].sin6_scope_id = clientscope6; #endif } if (stream_idx == 0) { sinhim[stream_idx].sin_port = htons(ctlport); #ifdef AF_INET6 sinhim6[stream_idx].sin6_port = htons(ctlport); #endif } else { sinhim[stream_idx].sin_port = htons(port + stream_idx - 1); #ifdef AF_INET6 sinhim6[stream_idx].sin6_port = htons(port + stream_idx - 1); #endif } sinme[stream_idx].sin_port = 0; /* free choice */ #ifdef AF_INET6 sinme6[stream_idx].sin6_port = 0; /* free choice */ #endif } else { /* rcvr listens for connections (unless reversed) */ if (stream_idx == 0) { sinme[stream_idx].sin_port = htons(ctlport); #ifdef AF_INET6 sinme6[stream_idx].sin6_port = htons(ctlport); #endif } else { sinme[stream_idx].sin_port = htons(port + stream_idx - 1); #ifdef AF_INET6 sinme6[stream_idx].sin6_port = htons(port + stream_idx - 1); #endif } } sinme[stream_idx].sin_family = af; #ifdef AF_INET6 sinme6[stream_idx].sin6_family = af; #endif if ((fd[stream_idx] = socket(domain, (udp && (stream_idx != 0))?SOCK_DGRAM:SOCK_STREAM, 0)) < 0) err("socket"); if (stream_idx == nstream) { if (brief <= 0) mes("socket"); #ifdef HAVE_SETPRIO if (priority && (brief <= 0)) { errno = 0; priority = getpriority(PRIO_PROCESS, 0); if (errno) mes("couldn't get priority"); else fprintf(stdout, "nuttcp%s%s: priority = %d\n", trans ? "-t" : "-r", ident, priority); } #endif if (trans) { char tmphost[ADDRSTRLEN] = "\0"; if (multicast) { /* The multicast transmitter just sends * to the multicast group */ if (af == AF_INET) { bcopy((char *)&sinhim[1].sin_addr.s_addr, (char *)&save_sinhim.sin_addr.s_addr, sizeof(struct in_addr)); if (!client && (irvers >= 50505)) { struct sockaddr_in peer; socklen_t peerlen = sizeof(peer); if (getpeername(fd[0], (struct sockaddr *)&peer, &peerlen) < 0) { err("getpeername"); } bcopy((char *)&peer.sin_addr.s_addr, (char *)&sinhim[1].sin_addr.s_addr, sizeof(struct in_addr)); } else { struct sockaddr_in me; socklen_t melen = sizeof(me); if (getsockname(fd[0], (struct sockaddr *)&me, &melen) < 0) { err("getsockname"); } bcopy((char *)&me.sin_addr.s_addr, (char *)&sinhim[1].sin_addr.s_addr, sizeof(struct in_addr)); } sinhim[1].sin_addr.s_addr &= htonl(0xFFFFFF); sinhim[1].sin_addr.s_addr |= htonl(HI_MC << 24); inet_ntop(af, &sinhim[1].sin_addr, tmphost, sizeof(tmphost)); if (setsockopt(fd[1], IPPROTO_IP, IP_MULTICAST_TTL, (void *)&multicast, sizeof(multicast)) < 0) err("setsockopt"); } else { err("unsupported AF"); } } if ((brief <= 0) && (format & PARSE)) { fprintf(stdout,"nuttcp-t%s: buflen=%d ", ident, buflen); if (nbuf != INT_MAX) fprintf(stdout,"nbuf=%llu ", nbuf); fprintf(stdout,"nstream=%d port=%d mode=%s host=%s", nstream, port, udp?"udp":"tcp", multicast ? tmphost : host); if (multicast) fprintf(stdout, " multicast_ttl=%d", multicast); fprintf(stdout, "\n"); if (timeout) fprintf(stdout,"nuttcp-t%s: time_limit=%.2f\n", ident, timeout); if ((rate != MAXRATE) || tos) fprintf(stdout,"nuttcp-t%s:", ident); if (rate != MAXRATE) { fprintf(stdout," rate_limit=%.3f rate_unit=Mbps rate_mode=%s", (double)rate/1000, irate ? "instantaneous" : "aggregate"); if (udp) { unsigned long long ppsrate = ((uint64_t)rate * 1000)/8/buflen; fprintf(stdout," pps_rate=%llu", ppsrate); } } if (tos) fprintf(stdout," tos=0x%X", tos); if ((rate != MAXRATE) || tos) fprintf(stdout,"\n"); } else if (brief <= 0) { fprintf(stdout,"nuttcp-t%s: buflen=%d, ", ident, buflen); if (nbuf != INT_MAX) fprintf(stdout,"nbuf=%llu, ", nbuf); fprintf(stdout,"nstream=%d, port=%d %s -> %s", nstream, port, udp?"udp":"tcp", multicast ? tmphost : host); if (multicast) fprintf(stdout, " ttl=%d", multicast); fprintf(stdout, "\n"); if (timeout) fprintf(stdout,"nuttcp-t%s: time limit = %.2f second%s\n", ident, timeout, (timeout == 1.0)?"":"s"); if ((rate != MAXRATE) || tos) fprintf(stdout,"nuttcp-t%s:", ident); if (rate != MAXRATE) { fprintf(stdout," rate limit = %.3f Mbps (%s)", (double)rate/1000, irate ? "instantaneous" : "aggregate"); if (udp) { unsigned long long ppsrate = ((uint64_t)rate * 1000)/8/buflen; fprintf(stdout,", %llu pps", ppsrate); } if (tos) fprintf(stdout,","); } if (tos) fprintf(stdout," tos = 0x%X", tos); if ((rate != MAXRATE) || tos) fprintf(stdout,"\n"); } } else { if ((brief <= 0) && (format & PARSE)) { fprintf(stdout,"nuttcp-r%s: buflen=%d ", ident, buflen); if (nbuf != INT_MAX) fprintf(stdout,"nbuf=%llu ", nbuf); fprintf(stdout,"nstream=%d port=%d mode=%s\n", nstream, port, udp?"udp":"tcp"); if (tos) fprintf(stdout,"nuttcp-r%s: tos=0x%X\n", ident, tos); if (interval) fprintf(stdout,"nuttcp-r%s: reporting_interval=%.2f\n", ident, interval); } else if (brief <= 0) { fprintf(stdout,"nuttcp-r%s: buflen=%d, ", ident, buflen); if (nbuf != INT_MAX) fprintf(stdout,"nbuf=%llu, ", nbuf); fprintf(stdout,"nstream=%d, port=%d %s\n", nstream, port, udp?"udp":"tcp"); if (tos) fprintf(stdout,"nuttcp-r%s: tos = 0x%X\n", ident, tos); if (interval) fprintf(stdout,"nuttcp-r%s: interval reporting every %.2f second%s\n", ident, interval, (interval == 1.0)?"":"s"); } } } if (setsockopt(fd[stream_idx], SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) < 0) err("setsockopt: so_reuseaddr"); #ifdef IPV6_V6ONLY if ((af == AF_INET6) && !v4mapped) { if (setsockopt(fd[stream_idx], IPPROTO_IPV6, IPV6_V6ONLY, (void *)&one, sizeof(int)) < 0) { err("setsockopt: ipv6_only"); } } #endif if (af == AF_INET) { if (bind(fd[stream_idx], (struct sockaddr *)&sinme[stream_idx], sizeof(sinme[stream_idx])) < 0) err("bind"); } #ifdef AF_INET6 else if (af == AF_INET6) { if (bind(fd[stream_idx], (struct sockaddr *)&sinme6[stream_idx], sizeof(sinme6[stream_idx])) < 0) err("bind"); } #endif else { err("unsupported AF"); } if (stream_idx > 0) { if (trans) { /* Set the transmitter options */ if (sendwin) { if( setsockopt(fd[stream_idx], SOL_SOCKET, SO_SNDBUF, (void *)&sendwin, sizeof(sendwin)) < 0) errmes("unable to setsockopt SO_SNDBUF"); if (braindead && (setsockopt(fd[stream_idx], SOL_SOCKET, SO_RCVBUF, (void *)&rcvwin, sizeof(rcvwin)) < 0)) errmes("unable to setsockopt SO_RCVBUF"); } if (tos) { if( setsockopt(fd[stream_idx], IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(tos)) < 0) err("setsockopt"); } if (nodelay && !udp) { struct protoent *p; p = getprotobyname("tcp"); if( p && setsockopt(fd[stream_idx], p->p_proto, TCP_NODELAY, (void *)&one, sizeof(one)) < 0) err("setsockopt: nodelay"); if ((stream_idx == nstream) && (brief <= 0)) mes("nodelay"); } } else { /* Set the receiver options */ if (rcvwin) { if( setsockopt(fd[stream_idx], SOL_SOCKET, SO_RCVBUF, (void *)&rcvwin, sizeof(rcvwin)) < 0) errmes("unable to setsockopt SO_RCVBUF"); if (braindead && (setsockopt(fd[stream_idx], SOL_SOCKET, SO_SNDBUF, (void *)&sendwin, sizeof(sendwin)) < 0)) errmes("unable to setsockopt SO_SNDBUF"); } if (tos) { if( setsockopt(fd[stream_idx], IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(tos)) < 0) err("setsockopt"); } } } if (!udp || (stream_idx == 0)) { if (((trans && !reverse) && (stream_idx > 0)) || ((!trans && reverse) && (stream_idx > 0)) || (client && (stream_idx == 0))) { /* The transmitter initiates the connection * (unless reversed by the flip option) */ if (options && (stream_idx > 0)) { if( setsockopt(fd[stream_idx], SOL_SOCKET, options, (void *)&one, sizeof(one)) < 0) errmes("unable to setsockopt options"); } usleep(20000); if (trans && (stream_idx > 0) && datamss) { #if defined(__CYGWIN__) || defined(_WIN32) if (format & PARSE) fprintf(stderr, "nuttcp%s%s: Warning=\"setting_maximum_segment_size_not_supported_on_windows\"\n", trans?"-t":"-r", ident); else fprintf(stderr, "nuttcp%s%s: Warning: setting maximum segment size not supported on windows\n", trans?"-t":"-r", ident); fflush(stderr); #endif optlen = sizeof(datamss); if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) if (errno != EINVAL) err("unable to set maximum segment size"); } num_connect_tries++; if (stream_idx == 1) gettimeofday(&timeconn1, (struct timezone *)0); if (af == AF_INET) { error_num = connect(fd[stream_idx], (struct sockaddr *)&sinhim[stream_idx], sizeof(sinhim[stream_idx])); } #ifdef AF_INET6 else if (af == AF_INET6) { error_num = connect(fd[stream_idx], (struct sockaddr *)&sinhim6[stream_idx], sizeof(sinhim6[stream_idx])); } #endif else { err("unsupported AF"); } if(error_num < 0) { if (clientserver && client && (stream_idx == 0) && ((errno == ECONNREFUSED) || (errno == ECONNRESET)) && (num_connect_tries < MAX_CONNECT_TRIES) && retry_server) { /* retry control connection to * server for certain possibly * transient errors */ usleep(SERVER_RETRY_USEC); goto doit; } if (!trans && (stream_idx == 0)) err("connect"); if (stream_idx > 0) { if (clientserver && !client) { for ( i = 1; i <= stream_idx; i++ ) close(fd[i]); goto cleanup; } err("connect"); } if (stream_idx == 0) { clientserver = 0; if (thirdparty) { perror("3rd party connect failed"); fprintf(stderr, "3rd party nuttcp only supported for client/server mode\n"); fflush(stderr); exit(1); } if (interval) { perror("connect failed"); fprintf(stderr, "interval option only supported for client/server mode\n"); fflush(stderr); exit(1); } if (reverse) { perror("connect failed"); fprintf(stderr, "flip option only supported for client/server mode\n"); fflush(stderr); exit(1); } if (traceroute) { perror("connect failed"); fprintf(stderr, "traceroute option only supported for client/server mode\n"); fflush(stderr); exit(1); } if (host3) { perror("connect failed"); fprintf(stderr, "3rd party nuttcp only supported for client/server mode\n"); fflush(stderr); exit(1); } if (multicast) { perror("connect failed"); fprintf(stderr, "multicast only supported for client/server mode\n"); fflush(stderr); exit(1); } if (udp) { perror("connect failed"); fprintf(stderr, "UDP transfers only supported for client/server mode\n"); fflush(stderr); exit(1); } if (format & PARSE) { fprintf(stderr, "nuttcp%s%s: Info=\"attempting_to_switch_to_deprecated_classic_mode\"\n", trans?"-t":"-r", ident); fprintf(stderr, "nuttcp%s%s: Info=\"will_use_less_reliable_transmitter_side_statistics\"\n", trans?"-t":"-r", ident); } else { fprintf(stderr, "nuttcp%s%s: Info: attempting to switch to deprecated \"classic\" mode\n", trans?"-t":"-r", ident); fprintf(stderr, "nuttcp%s%s: Info: will use less reliable transmitter side statistics\n", trans?"-t":"-r", ident); } fflush(stderr); } } if (stream_idx == 1) { gettimeofday(&timeconn2, (struct timezone *)0); tvsub( &timeconn, &timeconn2, &timeconn1 ); rtt = timeconn.tv_sec*1000 + ((double)timeconn.tv_usec)/1000; } if (sockopterr && trans && (stream_idx > 0) && datamss) { optlen = sizeof(datamss); if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) { if (errno != EINVAL) err("unable to set maximum segment size"); else err("setting maximum segment size not supported on this OS"); } } if (stream_idx == nstream) { optlen = sizeof(datamss); if (getsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, &optlen) < 0) err("get dataconn maximum segment size didn't work"); if (format & DEBUGMTU) fprintf(stderr, "datamss = %d\n", datamss); } if ((stream_idx == nstream) && (brief <= 0)) { char tmphost[ADDRSTRLEN] = "\0"; if (af == AF_INET) { inet_ntop(af, &sinhim[stream_idx].sin_addr.s_addr, tmphost, sizeof(tmphost)); } #ifdef AF_INET6 else if (af == AF_INET6) { inet_ntop(af, sinhim6[stream_idx].sin6_addr.s6_addr, tmphost, sizeof(tmphost)); } #endif else { err("unsupported AF"); } if (format & PARSE) { fprintf(stdout, "nuttcp%s%s: connect=%s", trans?"-t":"-r", ident, tmphost); if (trans && datamss) { fprintf(stdout, " mss=%d", datamss); } if (rtt) fprintf(stdout, P_RTT_FMT, rtt); } else { fprintf(stdout, "nuttcp%s%s: connect to %s", trans?"-t":"-r", ident, tmphost); if (rtt || (trans && datamss)) fprintf(stdout, " with"); if (trans && datamss) { fprintf(stdout, " mss=%d", datamss); if (rtt) fprintf(stdout, ","); } if (rtt) fprintf(stdout, RTT_FMT, rtt); } fprintf(stdout, "\n"); } } else { /* The receiver listens for the connection * (unless reversed by the flip option) */ if (trans && (stream_idx > 0) && datamss) { #if defined(__CYGWIN__) || defined(_WIN32) if (format & PARSE) fprintf(stderr, "nuttcp%s%s: Warning=\"setting_maximum_segment_size_not_supported_on_windows\"\n", trans?"-t":"-r", ident); else fprintf(stderr, "nuttcp%s%s: Warning: setting maximum segment size not supported on windows\n", trans?"-t":"-r", ident); fflush(stderr); #endif optlen = sizeof(datamss); if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) if (errno != EINVAL) err("unable to set maximum segment size"); } listen(fd[stream_idx],1); /* allow a queue of 1 */ if (clientserver && !client && (stream_idx == 0) && !inetd && !nofork && !forked) { if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid != 0) exit(0); forked = 1; setsid(); } if (options && (stream_idx > 0)) { if( setsockopt(fd[stream_idx], SOL_SOCKET, options, (void *)&one, sizeof(one)) < 0) errmes("unable to setsockopt options"); } if (sockopterr && trans && (stream_idx > 0) && datamss) { optlen = sizeof(datamss); if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) if (errno != EINVAL) err("unable to set maximum segment size"); } if (clientserver && !client && (stream_idx > 0)) { sigact.sa_handler = ignore_alarm; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGALRM, &sigact, &savesigact); alarm(ACCEPT_TIMEOUT); } fromlen = sizeof(frominet); nfd=accept(fd[stream_idx], (struct sockaddr *)&frominet, &fromlen); save_errno = errno; if (clientserver && !client && (stream_idx > 0)) { alarm(0); sigact.sa_handler = savesigact.sa_handler; sigact.sa_mask = savesigact.sa_mask; sigact.sa_flags = savesigact.sa_flags; sigaction(SIGALRM, &sigact, 0); } if (nfd < 0) { /* check for interrupted system call, * close data streams, cleanup and try * again - all other errors just die */ if ((save_errno == EINTR) && clientserver && !client && (stream_idx > 0)) { for ( i = 1; i <= stream_idx; i++ ) close(fd[i]); goto cleanup; } err("accept"); } af = frominet.ss_family; close(fd[stream_idx]); fd[stream_idx]=nfd; if (sockopterr && trans && (stream_idx > 0) && datamss) { optlen = sizeof(datamss); if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) { if (errno != EINVAL) err("unable to set maximum segment size"); else err("setting maximum segment size not supported on this OS"); } } if (stream_idx == nstream) { optlen = sizeof(datamss); if (getsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, &optlen) < 0) err("get dataconn maximum segment size didn't work"); if (format & DEBUGMTU) fprintf(stderr, "datamss = %d\n", datamss); } if (af == AF_INET) { struct sockaddr_in peer; socklen_t peerlen = sizeof(peer); if (getpeername(fd[stream_idx], (struct sockaddr *)&peer, &peerlen) < 0) { err("getpeername"); } if ((stream_idx == nstream) && (brief <= 0)) { char tmphost[ADDRSTRLEN] = "\0"; inet_ntop(af, &peer.sin_addr.s_addr, tmphost, sizeof(tmphost)); if (format & PARSE) { fprintf(stdout, "nuttcp%s%s: accept=%s", trans?"-t":"-r", ident, tmphost); if (trans && datamss) { fprintf(stdout, " mss=%d", datamss); } } else { fprintf(stdout, "nuttcp%s%s: accept from %s", trans?"-t":"-r", ident, tmphost); if (trans && datamss) { fprintf(stdout, " with mss=%d", datamss); } } fprintf(stdout, "\n"); } if (stream_idx == 0) clientaddr = peer.sin_addr; } #ifdef AF_INET6 else if (af == AF_INET6) { struct sockaddr_in6 peer; socklen_t peerlen = sizeof(peer); if (getpeername(fd[stream_idx], (struct sockaddr *)&peer, &peerlen) < 0) { err("getpeername"); } if ((stream_idx == nstream) && (brief <= 0)) { char tmphost[ADDRSTRLEN] = "\0"; inet_ntop(af, peer.sin6_addr.s6_addr, tmphost, sizeof(tmphost)); if (format & PARSE) { fprintf(stdout, "nuttcp%s%s: accept=%s", trans?"-t":"-r", ident, tmphost); if (trans && datamss) { fprintf(stdout, " mss=%d", datamss); } } else { fprintf(stdout, "nuttcp%s%s: accept from %s", trans?"-t":"-r", ident, tmphost); if (trans && datamss) { fprintf(stdout, " with mss=%d", datamss); } } fprintf(stdout, "\n"); } if (stream_idx == 0) { clientaddr6 = peer.sin6_addr; clientscope6 = peer.sin6_scope_id; } } #endif else { err("unsupported AF"); } } } if (!udp && trans && (stream_idx >= 1) && (retransinfo > 0)) { nretrans = get_retrans(fd[stream_idx]); iretrans = nretrans; } optlen = sizeof(sendwinval); if (getsockopt(fd[stream_idx], SOL_SOCKET, SO_SNDBUF, (void *)&sendwinval, &optlen) < 0) err("get send window size didn't work"); #if defined(linux) sendwinval /= 2; #endif if ((stream_idx > 0) && sendwin && (trans || braindead) && (sendwinval < (0.98 * sendwin))) { if (format & PARSE) fprintf(stderr, "nuttcp%s%s: Warning=\"send_window_size_%d_<_requested_window_size_%d\"\n", trans?"-t":"-r", ident, sendwinval, sendwin); else fprintf(stderr, "nuttcp%s%s: Warning: send window size %d < requested window size %d\n", trans?"-t":"-r", ident, sendwinval, sendwin); fflush(stderr); } optlen = sizeof(rcvwinval); if (getsockopt(fd[stream_idx], SOL_SOCKET, SO_RCVBUF, (void *)&rcvwinval, &optlen) < 0) err("Get recv window size didn't work"); #if defined(linux) rcvwinval /= 2; #endif if ((stream_idx > 0) && rcvwin && (!trans || braindead) && (rcvwinval < (0.98 * rcvwin))) { if (format & PARSE) fprintf(stderr, "nuttcp%s%s: Warning=\"receive_window_size_%d_<_requested_window_size_%d\"\n", trans?"-t":"-r", ident, rcvwinval, rcvwin); else fprintf(stderr, "nuttcp%s%s: Warning: receive window size %d < requested window size %d\n", trans?"-t":"-r", ident, rcvwinval, rcvwin); fflush(stderr); } if (firsttime) { firsttime = 0; origsendwin = sendwinval; origrcvwin = rcvwinval; } if ((stream_idx == nstream) && (brief <= 0)) { #if defined(linux) FILE *adv_ws; sendwinval *= 2; rcvwinval *= 2; if ((adv_ws = fopen(TCP_ADV_WIN_SCALE, "r"))) { fscanf(adv_ws, "%d", &winadjust); } fclose(adv_ws); if (winadjust < 0) { sendwinavail = sendwinval >> -winadjust; rcvwinavail = rcvwinval >> -winadjust; } else if (winadjust > 0) { sendwinavail = sendwinval - (sendwinval >> winadjust); rcvwinavail = rcvwinval - (rcvwinval >> winadjust); } #endif if (format & PARSE) fprintf(stdout,"nuttcp%s%s: send_window_size=%d receive_window_size=%d\n", trans?"-t":"-r", ident, sendwinval, rcvwinval); else fprintf(stdout,"nuttcp%s%s: send window size = %d, receive window size = %d\n", trans?"-t":"-r", ident, sendwinval, rcvwinval); #if defined(linux) if (format & PARSE) fprintf(stdout,"nuttcp%s%s: send_window_avail=%d receive_window_avail=%d\n", trans?"-t":"-r", ident, sendwinavail, rcvwinavail); else fprintf(stdout,"nuttcp%s%s: available send window = %d, available receive window = %d\n", trans?"-t":"-r", ident, sendwinavail, rcvwinavail); #endif } } if (abortconn) exit(1); if (host3 && clientserver) { char path[64]; char *cmd; fflush(stdout); fflush(stderr); cmd = "nuttcp"; if (client) { if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid == 0) { while (fgets(linebuf, sizeof(linebuf), stdin) && !intr) { if (strncmp(linebuf, "DONE", 4) == 0) exit(0); if (*ident && (*linebuf != '\n')) fprintf(stdout, "%s: ", ident + 1); fputs(linebuf, stdout); fflush(stdout); } exit(0); } signal(SIGINT, SIG_IGN); while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; err("wait failed"); } } exit(0); } else { if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid != 0) { sigact.sa_handler = &sigalarm; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGALRM, &sigact, 0); alarm(10); while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; if (errno == EINTR) { pollfds[0].fd = fileno(ctlconn); pollfds[0].events = POLLIN | POLLPRI; pollfds[0].revents = 0; if ((poll(pollfds, 1, 0) > 0) && (pollfds[0].revents & (POLLIN | POLLPRI))) { kill(pid, SIGINT); sleep(1); kill(pid, SIGINT); continue; } sigact.sa_handler = &sigalarm; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGALRM, &sigact, 0); alarm(10); continue; } err("wait failed"); } } fprintf(stdout, "DONE\n"); fflush(stdout); goto cleanup; } close(2); dup(1); i = 0; j = 0; cmdargs[i++] = cmd; cmdargs[i++] = "-3"; if (pass_ctlport) { sprintf(tmpargs[j], "-P%hu", ctlport); cmdargs[i++] = tmpargs[j++]; } if (irvers < 50302) { if ((udp && !multicast && (buflen != DEFAULTUDPBUFLEN)) || (udp && multicast && (buflen != DEFAULT_MC_UDPBUFLEN)) || (!udp && (buflen != 65536))) { sprintf(tmpargs[j], "-l%d", buflen); cmdargs[i++] = tmpargs[j++]; } } else if (buflen) { sprintf(tmpargs[j], "-l%d", buflen); cmdargs[i++] = tmpargs[j++]; } if (nbuf != INT_MAX) { if (nbuf_bytes) sprintf(tmpargs[j], "-n%llub", nbuf); else sprintf(tmpargs[j], "-n%llu", nbuf); cmdargs[i++] = tmpargs[j++]; } if (brief3 != 1) { sprintf(tmpargs[j], "-b%d", brief3); cmdargs[i++] = tmpargs[j++]; } if (sendwin) { sprintf(tmpargs[j], "-w%d", sendwin/1024); cmdargs[i++] = tmpargs[j++]; } if (nstream != 1) { sprintf(tmpargs[j], "-N%d", nstream); cmdargs[i++] = tmpargs[j++]; } if (rate != MAXRATE) { if (rate_pps) sprintf(tmpargs[j], "-R%s%lup", irate ? "i" : "", rate); else sprintf(tmpargs[j], "-R%s%lu", irate ? "i" : "", rate); cmdargs[i++] = tmpargs[j++]; } else { if (udp && !multicast) cmdargs[i++] = "-R0"; } if (port != DEFAULT_PORT) { sprintf(tmpargs[j], "-p%hu", port); cmdargs[i++] = tmpargs[j++]; } if (trans) cmdargs[i++] = "-r"; if (braindead) cmdargs[i++] = "-wb"; if (timeout && (timeout != DEFAULT_TIMEOUT)) { sprintf(tmpargs[j], "-T%f", timeout); cmdargs[i++] = tmpargs[j++]; } if (udp) { if (multicast) { sprintf(tmpargs[j], "-m%d", multicast); cmdargs[i++] = tmpargs[j++]; } else cmdargs[i++] = "-u"; } if (interval) { sprintf(tmpargs[j], "-i%f", interval); cmdargs[i++] = tmpargs[j++]; } if (reverse) cmdargs[i++] = "-F"; if (format) { if (format & XMITSTATS) cmdargs[i++] = "-fxmitstats"; if (format & RUNNINGTOTAL) cmdargs[i++] = "-frunningtotal"; if (format & NOPERCENTLOSS) cmdargs[i++] = "-f-percentloss"; if (format & NODROPS) cmdargs[i++] = "-f-drops"; if (format & NORETRANS) cmdargs[i++] = "-f-retrans"; if (format & PARSE) cmdargs[i++] = "-fparse"; } else { cmdargs[i++] = "-f-rtt"; } if (traceroute) cmdargs[i++] = "-xt"; if (datamss) { sprintf(tmpargs[j], "-M%d", datamss); cmdargs[i++] = tmpargs[j++]; } if (tos) { sprintf(tmpargs[j], "-c0x%Xt", tos); cmdargs[i++] = tmpargs[j++]; } if (nodelay) cmdargs[i++] = "-D"; cmdargs[i++] = host3; cmdargs[i] = NULL; execvp(cmd, cmdargs); if (errno == ENOENT) { strcpy(path, "/usr/local/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/local/bin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/etc/"); strcat(path, cmd); execv(path, cmdargs); } if ((errno == ENOENT) && (getuid() != 0) && (geteuid() != 0)) { strcpy(path, "./"); strcat(path, cmd); execv(path, cmdargs); } perror("execvp failed"); fprintf(stderr, "failed to execute %s\n", cmd); fflush(stdout); fflush(stderr); if (!inetd) exit(0); goto cleanup; } } if (traceroute && clientserver) { char path[64]; char *cmd; fflush(stdout); fflush(stderr); if (multicast) cmd = "mtrace"; else { cmd = "traceroute"; #ifdef AF_INET6 if (af == AF_INET6) cmd = "traceroute6"; #endif } if (client) { if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid != 0) { while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; err("wait failed"); } } fflush(stdout); } else { signal(SIGINT, SIG_DFL); close(2); dup(1); i = 0; cmdargs[i++] = cmd; cmdargs[i++] = host; cmdargs[i] = NULL; execvp(cmd, cmdargs); if (errno == ENOENT) { strcpy(path, "/usr/local/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/local/bin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/etc/"); strcat(path, cmd); execv(path, cmdargs); } perror("execvp failed"); fprintf(stderr, "failed to execute %s\n", cmd); fflush(stdout); fflush(stderr); exit(0); } } fprintf(stdout, "\n"); if (intr) { intr = 0; fprintf(stdout, "\n"); signal(SIGINT, sigint); } if (!skip_data) { for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) close(fd[stream_idx]); } if (client) { if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid == 0) { while (fgets(linebuf, sizeof(linebuf), stdin) && !intr) { if (strncmp(linebuf, "DONE", 4) == 0) exit(0); fputs(linebuf, stdout); fflush(stdout); } exit(0); } signal(SIGINT, SIG_IGN); while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; err("wait failed"); } } exit(0); } else { if (!inetd) { if ((pid = fork()) == (pid_t)-1) err("can't fork"); if (pid != 0) { while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; err("wait failed"); } } fprintf(stdout, "DONE\n"); fflush(stdout); goto cleanup; } } close(2); dup(1); i = 0; cmdargs[i++] = cmd; cmdargs[i++] = host; cmdargs[i] = NULL; execvp(cmd, cmdargs); if (errno == ENOENT) { strcpy(path, "/usr/local/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/local/bin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/sbin/"); strcat(path, cmd); execv(path, cmdargs); } if (errno == ENOENT) { strcpy(path, "/usr/etc/"); strcat(path, cmd); execv(path, cmdargs); } perror("execvp failed"); fprintf(stderr, "failed to execute %s\n", cmd); fflush(stdout); fflush(stderr); if (!inetd) exit(0); goto cleanup; } } if (multicast && !trans) { /* The multicast receiver must join the multicast group */ if (af == AF_INET) { struct sockaddr_in peer; char tmphost[ADDRSTRLEN] = "\0"; char tmphost2[ADDRSTRLEN] = "\0"; socklen_t peerlen = sizeof(peer); if (getpeername(fd[0], (struct sockaddr *)&peer, &peerlen) < 0) { err("getpeername"); } if (client && (irvers >= 50505)) { struct sockaddr_in me; socklen_t melen = sizeof(me); if (getsockname(fd[0], (struct sockaddr *)&me, &melen) < 0) { err("getsockname"); } bcopy((char *)&me.sin_addr.s_addr, (char *)&mc_group.imr_multiaddr.s_addr, sizeof(struct in_addr)); } else { bcopy((char *)&peer.sin_addr.s_addr, (char *)&mc_group.imr_multiaddr.s_addr, sizeof(struct in_addr)); } mc_group.imr_multiaddr.s_addr &= htonl(0xFFFFFF); mc_group.imr_multiaddr.s_addr |= htonl(HI_MC << 24); if (setsockopt(fd[1], IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mc_group, sizeof(mc_group)) < 0) err("setsockopt"); if (brief <= 0) { inet_ntop(af, &peer.sin_addr.s_addr, tmphost, sizeof(tmphost)); inet_ntop(af, &mc_group.imr_multiaddr, tmphost2, sizeof(tmphost2)); if (format & PARSE) fprintf(stdout, "nuttcp%s%s: multicast_source=%s multicast_group=%s\n", trans?"-t":"-r", ident, tmphost, tmphost2); else fprintf(stdout, "nuttcp%s%s: receiving from multicast source %s on group %s\n", trans?"-t":"-r", ident, tmphost, tmphost2); } } else { err("unsupported AF"); } } if (trans && timeout) { itimer.it_value.tv_sec = timeout; itimer.it_value.tv_usec = (timeout - itimer.it_value.tv_sec)*1000000; itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = 0; signal(SIGALRM, sigalarm); if (!udp) setitimer(ITIMER_REAL, &itimer, 0); } else if (!trans && interval) { sigact.sa_handler = &sigalarm; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; sigaction(SIGALRM, &sigact, 0); itimer.it_value.tv_sec = interval; itimer.it_value.tv_usec = (interval - itimer.it_value.tv_sec)*1000000; itimer.it_interval.tv_sec = interval; itimer.it_interval.tv_usec = (interval - itimer.it_interval.tv_sec)*1000000; setitimer(ITIMER_REAL, &itimer, 0); if (clientserver && !client) { chk_idle_data = (interval < idle_data_min) ? idle_data_min : interval; chk_idle_data = (chk_idle_data > idle_data_max) ? idle_data_max : chk_idle_data; } } else if (clientserver && !trans) { sigact.sa_handler = &sigalarm; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; sigaction(SIGALRM, &sigact, 0); if (timeout) { chk_idle_data = timeout/2; } else { if (rate != MAXRATE) chk_idle_data = (double)(nbuf*buflen) /rate/125/2; else chk_idle_data = default_idle_data; } chk_idle_data = (chk_idle_data < idle_data_min) ? idle_data_min : chk_idle_data; chk_idle_data = (chk_idle_data > idle_data_max) ? idle_data_max : chk_idle_data; itimer.it_value.tv_sec = chk_idle_data; itimer.it_value.tv_usec = (chk_idle_data - itimer.it_value.tv_sec) *1000000; itimer.it_interval.tv_sec = chk_idle_data; itimer.it_interval.tv_usec = (chk_idle_data - itimer.it_interval.tv_sec) *1000000; setitimer(ITIMER_REAL, &itimer, 0); } if (interval && clientserver && client && trans) do_poll = 1; if (irate) { pkt_time = (double)buflen/rate/125; irate_pk_usec = pkt_time*1000000; irate_pk_nsec = (pkt_time*1000000 - irate_pk_usec)*1000; } prep_timer(); errno = 0; stream_idx = 0; ocorrection = 0; correction = 0.0; if (do_poll) { long flags; pollfds[0].fd = fileno(ctlconn); pollfds[0].events = POLLIN | POLLPRI; pollfds[0].revents = 0; for ( i = 1; i <= nstream; i++ ) { pollfds[i].fd = fd[i]; pollfds[i].events = POLLOUT; pollfds[i].revents = 0; } flags = fcntl(0, F_GETFL, 0); if (flags < 0) err("fcntl 1"); flags |= O_NONBLOCK; if (fcntl(0, F_SETFL, flags) < 0) err("fcntl 2"); } if (sinkmode) { register int cnt = 0; if (trans) { if(udp) { strcpy(buf, "BOD0"); if (multicast) { bcopy((char *)&sinhim[1].sin_addr.s_addr, (char *)&save_mc.sin_addr.s_addr, sizeof(struct in_addr)); bcopy((char *)&save_sinhim.sin_addr.s_addr, (char *)&sinhim[1].sin_addr.s_addr, sizeof(struct in_addr)); } (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr start */ if (two_bod) { usleep(250000); strcpy(buf, "BOD1"); (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr start */ } if (multicast) { bcopy((char *)&save_mc.sin_addr.s_addr, (char *)&sinhim[1].sin_addr.s_addr, sizeof(struct in_addr)); } if (timeout) setitimer(ITIMER_REAL, &itimer, 0); prep_timer(); } /* beginnings of timestamps - not ready for prime time */ /* bzero(buf + 8, 4); */ /* bzero(buf + 12, 4); */ nbytes += buflen; if (do_poll && (format & DEBUGPOLL)) { fprintf(stdout, "do_poll is set\n"); fflush(stdout); } if (udplossinfo) bcopy(&nbytes, buf + 24, 8); if (!udp && interval && !(format & NORETRANS) && ((retransinfo == 1) || ((retransinfo >= 2) && (force_retrans >= retransinfo)))) { uint32_t tmp; if (retransinfo == 1) tmp = 0x5254524Eu; /* "RTRN" */ else tmp = 0x48525452u; /* "HRTR" */ bcopy(&nretrans, buf + 24, 4); bcopy(&tmp, buf + 28, 4); } else { send_retrans = 0; if (!udp) bzero(buf + 24, 8); } if (nbuf == INT_MAX) nbuf = ULLONG_MAX; while (nbuf-- && ((cnt = Nwrite(fd[stream_idx + 1],buf,buflen)) == buflen) && !intr) { if (clientserver && ((nbuf & 0x3FF) == 0)) { if (!client) { /* check if client went away */ pollfds[0].fd = fileno(ctlconn); save_events = pollfds[0].events; pollfds[0].events = POLLIN | POLLPRI; pollfds[0].revents = 0; if ((poll(pollfds, 1, 0) > 0) && (pollfds[0].revents & (POLLIN | POLLPRI))) intr = 1; pollfds[0].events = save_events; } else if (handle_urg) { /* check for urgent TCP data * on control connection */ pollfds[0].fd = fileno(ctlconn); save_events = pollfds[0].events; pollfds[0].events = POLLPRI; pollfds[0].revents = 0; if ((poll(pollfds, 1, 0) > 0) && (pollfds[0].revents & POLLPRI)) { tmpbuf[0] = '\0'; if ((recv(fd[0], tmpbuf, 1, MSG_OOB) == -1) && (errno == EINVAL)) recv(fd[0], tmpbuf, 1, 0); if (tmpbuf[0] == 'A') intr = 1; else err("recv urgent data"); } pollfds[0].events = save_events; } } nbytes += buflen; cnt = 0; if (udplossinfo) bcopy(&nbytes, buf + 24, 8); if (send_retrans) { nretrans = get_retrans( fd[stream_idx + 1]); nretrans -= iretrans; bcopy(&nretrans, buf + 24, 4); } stream_idx++; stream_idx = stream_idx % nstream; if (do_poll && ((pollst = poll(pollfds, nstream + 1, 5000)) > 0) && (pollfds[0].revents & (POLLIN | POLLPRI)) && !intr) { /* check for server output */ #ifdef DEBUG if (format & DEBUGPOLL) { fprintf(stdout, "got something %d: ", i); for ( i = 0; i < nstream + 1; i++ ) { if (pollfds[i].revents & POLLIN) { fprintf(stdout, " rfd %d", pollfds[i].fd); } if (pollfds[i].revents & POLLPRI) { fprintf(stdout, " pfd %d", pollfds[i].fd); } if (pollfds[i].revents & POLLOUT) { fprintf(stdout, " wfd %d", pollfds[i].fd); } if (pollfds[i].revents & POLLERR) { fprintf(stdout, " xfd %d", pollfds[i].fd); } if (pollfds[i].revents & POLLHUP) { fprintf(stdout, " hfd %d", pollfds[i].fd); } if (pollfds[i].revents & POLLNVAL) { fprintf(stdout, " nfd %d", pollfds[i].fd); } } fprintf(stdout, "\n"); fflush(stdout); } if (format & DEBUGPOLL) { fprintf(stdout, "got server output: %s", intervalbuf); fflush(stdout); } #endif while (fgets(intervalbuf, sizeof(intervalbuf), stdin)) { if (strncmp(intervalbuf, "DONE", 4) == 0) { if (format & DEBUGPOLL) { fprintf(stdout, "got DONE\n"); fflush(stdout); } got_done = 1; intr = 1; do_poll = 0; break; } else if (strncmp(intervalbuf, "nuttcp-r", 8) == 0) { if ((brief <= 0) || strstr(intervalbuf, "Warning") || strstr(intervalbuf, "Error") || strstr(intervalbuf, "Debug")) { if (*ident) { fputs("nuttcp-r", stdout); fputs(ident, stdout); fputs(intervalbuf + 8, stdout); } else fputs(intervalbuf, stdout); fflush(stdout); } } else { if (*ident) fprintf(stdout, "%s: ", ident + 1); fputs(intervalbuf, stdout); fflush(stdout); } } } if (do_poll && (pollst < 0)) { if (errno == EINTR) break; err("poll"); } } nbytes -= buflen; if (intr && (cnt > 0)) nbytes += cnt; if(udp) { if (multicast) bcopy((char *)&save_sinhim.sin_addr.s_addr, (char *)&sinhim[1].sin_addr.s_addr, sizeof(struct in_addr)); strcpy(buf, "EOD0"); (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */ } } else { first_read = 1; need_swap = 0; bzero(buf + 24, 8); if (udp) { ntbytesc = 0; got_eod0 = 0; while (((cnt=Nread(fd[stream_idx + 1],buf,buflen)) > 0) && !intr) { if( cnt <= 4 ) { if (strncmp(buf, "EOD0", 4) == 0) { gettimeofday(&timepkrcv, (struct timezone *)0); got_eod0 = 1; done = 1; continue; } if (strncmp(buf, "EOD", 3) == 0) { ocorrection = buf[3] - '0'; gettimeofday(&time_eod, (struct timezone *)0); done = 1; break; /* "EOF" */ } if (strncmp(buf, "BOD", 3) == 0) { if (two_bod && (buf[3] == '0')) continue; if (interval) setitimer(ITIMER_REAL, &itimer, 0); prep_timer(); got_begin = 1; continue; } break; } else if (!got_begin) { if (interval) setitimer(ITIMER_REAL, &itimer, 0); prep_timer(); got_begin = 1; } else if (got_eod0) { gettimeofday(&timepkrcv, (struct timezone *)0); } if (!got_begin) continue; nbytes += cnt; cnt = 0; /* problematic if the interval timer * goes off right here */ if (udplossinfo) { if (first_read) { bcopy(buf + 24, &ntbytesc, 8); first_read = 0; if (ntbytesc > 0x100000000ull) need_swap = 1; if (!need_swap) { stream_idx++; stream_idx = stream_idx % nstream; continue; } } if (!need_swap) bcopy(buf + 24, &ntbytesc, 8); else { cp1 = (char *)&ntbytesc; cp2 = buf + 31; for ( i = 0; i < 8; i++ ) *cp1++ = *cp2--; } } stream_idx++; stream_idx = stream_idx % nstream; } if (intr && (cnt > 0)) nbytes += cnt; if (got_eod0) { tvsub( &timed, &time_eod, &timepkrcv ); correction = timed.tv_sec + ((double)timed.tv_usec) / 1000000; } } else { while (((cnt=Nread(fd[stream_idx + 1],buf,buflen)) > 0) && !intr) { nbytes += cnt; cnt = 0; if (first_read) { if (interval && !(format & NORETRANS)) { uint32_t tmp; first_read = 0; bcopy(buf + 24, &nretrans, 4); bcopy(buf + 28, &tmp, 4); if (tmp == 0x5254524Eu) { /* "RTRN" */ retransinfo = 1; b_flag = 1; } else if (tmp == 0x48525452u) { /* "HRTR" */ retransinfo = 2; b_flag = 1; } else if (tmp == 0x4E525452u) { /* "NRTR" */ need_swap = 1; retransinfo = 1; b_flag = 1; } else if (tmp == 0x52545248u) { /* "RTRH" */ need_swap = 1; retransinfo = 2; b_flag = 1; } else { retransinfo = -1; read_retrans = 0; } } else read_retrans = 0; } if (read_retrans) { if (!need_swap) bcopy(buf + 24, &nretrans, 4); else { cp1 = (char *)&nretrans; cp2 = buf + 27; for ( i = 0; i < 4; i++ ) *cp1++ = *cp2--; } } stream_idx++; stream_idx = stream_idx % nstream; } if (intr && (cnt > 0)) nbytes += cnt; } } } else { register int cnt; if (trans) { while((cnt=read(savestdin,buf,buflen)) > 0 && Nwrite(fd[stream_idx + 1],buf,cnt) == cnt) { nbytes += cnt; cnt = 0; stream_idx++; stream_idx = stream_idx % nstream; } } else { while((cnt=Nread(fd[stream_idx + 1],buf,buflen)) > 0 && write(savestdout,buf,cnt) == cnt) { nbytes += cnt; cnt = 0; stream_idx++; stream_idx = stream_idx % nstream; } } } if (errno && (errno != EAGAIN)) { if ((errno != EINTR) && (!clientserver || client)) err("IO"); } itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = 0; itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); done = 1; (void)read_timer(stats,sizeof(stats)); if(udp&&trans) { usleep(500000); strcpy(buf, "EOD1"); (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */ stream_idx++; stream_idx = stream_idx % nstream; usleep(500000); strcpy(buf, "EOD2"); (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */ stream_idx++; stream_idx = stream_idx % nstream; usleep(500000); strcpy(buf, "EOD3"); (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */ stream_idx++; stream_idx = stream_idx % nstream; usleep(500000); strcpy(buf, "EOD4"); (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */ stream_idx++; stream_idx = stream_idx % nstream; } if (clientserver && client && !host3 && udp && trans) /* If all the EOD packets get lost at the end of a UDP * transfer, having the client do a shutdown() for writing * on the control connection allows the server to more * quickly realize that the UDP transfer has completed * (mostly of benefit for separate control and data paths) * * Can't do this in the opposite direction since the * server needs to send info back to client */ shutdown(0, SHUT_WR); if (multicast && !trans) { /* Leave the multicast group */ if (af == AF_INET) { if (setsockopt(fd[1], IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mc_group, sizeof(mc_group)) < 0) err("setsockopt"); } else { err("unsupported AF"); } } if (!udp && trans && (format & DEBUGRETRANS)) { sretrans = get_retrans(-1); fprintf(stdout, "before closing system retrans = %d\n", sretrans); } for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) { if (!udp && trans) { #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS) struct timeval timeunack, timec, timed; optlen = sizeof(tcpinf); if (getsockopt(fd[stream_idx], SOL_TCP, TCP_INFO, (void *)&tcpinf, &optlen) < 0) { mes("couldn't collect TCP info\n"); retransinfo = -1; } gettimeofday(&timeunack, (struct timezone *)0); realtd = 0.0; while ((tcpinf.tcpinfo_unacked) && (realtd < MAX_EOT_WAIT_SEC)) { if (format & DEBUGRETRANS) print_tcpinfo(); if (format & DEBUGRETRANS) usleep(100000); else usleep(1000); optlen = sizeof(tcpinf); if (getsockopt(fd[stream_idx], SOL_TCP, TCP_INFO, (void *)&tcpinf, &optlen) < 0) { mes("couldn't collect TCP info\n"); retransinfo = -1; } gettimeofday(&timec, (struct timezone *)0); tvsub(&timed, &timec, &timeunack); realtd = timed.tv_sec + ((double)timed.tv_usec) / 1000000; } if (tcpinf.tcpinfo_unacked) { /* assume receiver went away */ if (clientserver && client) { mes("Error: server not ACKing data"); exit(1); } goto cleanup; } if (format & DEBUGRETRANS) print_tcpinfo(); #endif if (retransinfo > 0) { nretrans = get_retrans(fd[stream_idx]); nretrans -= iretrans; } } close(fd[stream_idx]); } if (!udp && trans && (format & DEBUGRETRANS)) { sretrans = get_retrans(-1); fprintf(stdout, "after closing system retrans = %d\n", sretrans); } if (interval && clientserver && !client && !trans) { fprintf(stdout, "DONE\n"); fflush(stdout); } if( cput <= 0.0 ) cput = 0.000001; if( realt <= 0.0 ) realt = 0.000001; if (udp && !trans) { if (got_eod0) realt -= correction; else realt -= ocorrection * 0.5; } sprintf(srvrbuf, "%.4f", (double)nbytes/1024/1024); sscanf(srvrbuf, "%lf", &MB); if (clientserver && client) reading_srvr_info = 1; if (interval && clientserver && client && trans && !got_done) { long flags; if (format & DEBUGPOLL) { fprintf(stdout, "getting rest of server output\n"); fflush(stdout); } flags = fcntl(0, F_GETFL, 0); if (flags < 0) err("fcntl 3"); flags &= ~O_NONBLOCK; if (fcntl(0, F_SETFL, flags) < 0) err("fcntl 4"); itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT; itimer.it_value.tv_usec = 0; itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); while (fgets(intervalbuf, sizeof(intervalbuf), stdin)) { setitimer(ITIMER_REAL, &itimer, 0); if (strncmp(intervalbuf, "DONE", 4) == 0) { if (format & DEBUGPOLL) { fprintf(stdout, "got DONE 2\n"); fflush(stdout); } break; } if ((!strstr(intervalbuf, " MB / ") || !strstr(intervalbuf, " sec = ")) && (brief > 0)) continue; if (*ident) fprintf(stdout, "%s: ", ident + 1); fputs(intervalbuf, stdout); fflush(stdout); } itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); } if (clientserver && client) { itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT; itimer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); cp1 = srvrbuf; got_srvr_retrans = 0; while (fgets(cp1, sizeof(srvrbuf) - (cp1 - srvrbuf), stdin)) { setitimer(ITIMER_REAL, &itimer, 0); if (*(cp1 + strlen(cp1) - 1) != '\n') { *cp1 = '\0'; break; } if (strstr(cp1, "real") && strstr(cp1, "seconds")) { strcpy(fmt, "nuttcp-%*c: "); if (format & PARSE) strcat(fmt, P_PERF_FMT_IN); else strcat(fmt, PERF_FMT_IN); sscanf(cp1, fmt, &srvr_MB, &srvr_realt, &srvr_KBps, &srvr_Mbps); if (trans && udp) { strncpy(tmpbuf, cp1, 256); *(tmpbuf + 256) = '\0'; if (strncmp(tmpbuf, "nuttcp-r", 8) == 0) sprintf(cp1, "nuttcp-r%s%s", ident, tmpbuf + 8); cp1 += strlen(cp1); cp2 = cp1; sprintf(cp2, "nuttcp-r:"); cp2 += 9; if (format & PARSE) strcpy(fmt, P_DROP_FMT); else strcpy(fmt, DROP_FMT); sprintf(cp2, fmt, (int64_t)(((MB - srvr_MB) *1024*1024) /buflen + 0.5), (uint64_t)((MB*1024*1024) /buflen + 0.5)); cp2 += strlen(cp2); fractloss = ((MB != 0.0) ? 1 - srvr_MB/MB : 0.0); if (format & PARSE) strcpy(fmt, P_LOSS_FMT); else if ((fractloss != 0.0) && (fractloss < 0.001)) strcpy(fmt, LOSS_FMT5); else strcpy(fmt, LOSS_FMT); sprintf(cp2, fmt, fractloss * 100); cp2 += strlen(cp2); sprintf(cp2, "\n"); } } else if (strstr(cp1, "sys")) { strcpy(fmt, "nuttcp-%*c: "); if (format & PARSE) { strcat(fmt, "stats=cpu "); strcat(fmt, P_CPU_STATS_FMT_IN2); } else strcat(fmt, CPU_STATS_FMT_IN2); if (sscanf(cp1, fmt, &srvr_cpu_util) != 7) { strcpy(fmt, "nuttcp-%*c: "); if (format & PARSE) { strcat(fmt, "stats=cpu "); strcat(fmt, P_CPU_STATS_FMT_IN); } else strcat(fmt, CPU_STATS_FMT_IN); sscanf(cp1, fmt, &srvr_cpu_util); } } else if ((cp2 = strstr(cp1, "retrans"))) { got_srvr_retrans = 1; retransinfo = 1; if (strstr(cp1, "host-retrans")) retransinfo = 2; if (format & PARSE) sscanf(cp2, P_RETRANS_FMT_IN, &nretrans); else sscanf(cp2, RETRANS_FMT_IN, &nretrans); /* below is for compatibility with 6.0.x beta */ if ((cp2 = strstr(cp1, "RTT"))) { if (format & PARSE) sscanf(cp2, P_RTT_FMT_IN, &rtt); else sscanf(cp2, RTT_FMT_INB, &rtt); } } else if ((cp2 = strstr(cp1, "RTT"))) { if (format & PARSE) sscanf(cp2, P_RTT_FMT_IN, &rtt); else sscanf(cp2, RTT_FMT_IN, &rtt); } else if ((strstr(cp1, "KB/cpu")) && !verbose) continue; strncpy(tmpbuf, cp1, 256); *(tmpbuf + 256) = '\0'; if (strncmp(tmpbuf, "nuttcp-", 7) == 0) sprintf(cp1, "nuttcp-%c%s%s", tmpbuf[7], ident, tmpbuf + 8); if ((strstr(cp1, "Warning") || strstr(cp1, "Error") || strstr(cp1, "Debug")) && (brief > 0)) { fputs(cp1, stdout); fflush(stdout); } cp1 += strlen(cp1); } itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); got_srvr_output = 1; if (!udp && !trans && !got_srvr_retrans) retransinfo = -1; } if (brief <= 0) { strcpy(fmt, "nuttcp%s%s: "); if (format & PARSE) strcat(fmt, P_PERF_FMT_OUT); else strcat(fmt, PERF_FMT_OUT); fprintf(stdout, fmt, trans?"-t":"-r", ident, (double)nbytes/(1024*1024), realt, (double)nbytes/realt/1024, (double)nbytes/realt/125000 ); if (clientserver && client && !trans && udp) { fprintf(stdout, "nuttcp-r%s:", ident); if (format & PARSE) strcpy(fmt, P_DROP_FMT); else strcpy(fmt, DROP_FMT); fprintf(stdout, fmt, (int64_t)(((srvr_MB - MB)*1024*1024) /buflen + 0.5), (uint64_t)((srvr_MB*1024*1024)/buflen + 0.5)); fractloss = ((srvr_MB != 0.0) ? 1 - MB/srvr_MB : 0.0); if (format & PARSE) strcpy(fmt, P_LOSS_FMT); else if ((fractloss != 0.0) && (fractloss < 0.001)) strcpy(fmt, LOSS_FMT5); else strcpy(fmt, LOSS_FMT); fprintf(stdout, fmt, fractloss * 100); fprintf(stdout, "\n"); } if (verbose) { strcpy(fmt, "nuttcp%s%s: "); if (format & PARSE) strcat(fmt, "megabytes=%.4f cpu_seconds=%.2f KB_per_cpu_second=%.2f\n"); else strcat(fmt, "%.4f MB in %.2f CPU seconds = %.2f KB/cpu sec\n"); fprintf(stdout, fmt, trans?"-t":"-r", ident, (double)nbytes/(1024*1024), cput, (double)nbytes/cput/1024 ); } if (!udp && trans && (retransinfo > 0)) { fprintf(stdout, "nuttcp%s%s: ", trans ? "-t" : "-r", ident); if (format & PARSE) strcpy(fmt, P_RETRANS_FMT); else strcpy(fmt, RETRANS_FMT); fprintf(stdout, fmt, retransinfo == 1 ? "" : "host-", nretrans); fprintf(stdout, "\n"); } strcpy(fmt, "nuttcp%s%s: "); if (format & PARSE) strcat(fmt, "io_calls=%d msec_per_call=%.2f calls_per_sec=%.2f\n"); else strcat(fmt, "%d I/O calls, msec/call = %.2f, calls/sec = %.2f\n"); fprintf(stdout, fmt, trans?"-t":"-r", ident, numCalls, 1024.0 * realt/((double)numCalls), ((double)numCalls)/realt); strcpy(fmt, "nuttcp%s%s: "); if (format & PARSE) strcat(fmt, "stats=cpu %s\n"); else strcat(fmt, "%s\n"); fprintf(stdout, fmt, trans?"-t":"-r", ident, stats); } if (format & PARSE) strcpy(fmt, P_CPU_STATS_FMT_IN2); else strcpy(fmt, CPU_STATS_FMT_IN2); if (sscanf(stats, fmt, &cpu_util) != 6) { if (format & PARSE) strcpy(fmt, P_CPU_STATS_FMT_IN); else strcpy(fmt, CPU_STATS_FMT_IN); sscanf(stats, fmt, &cpu_util); } if (brief && clientserver && client) { if ((brief < 0) || interval) fprintf(stdout, "\n"); if (udp) { if (trans) { if (*ident) fprintf(stdout, "%s: ", ident + 1); if (format & PARSE) strcpy(fmt, P_PERF_FMT_BRIEF); else strcpy(fmt, PERF_FMT_BRIEF); fprintf(stdout, fmt, srvr_MB, srvr_realt, srvr_Mbps, cpu_util, srvr_cpu_util); if (!(format & NODROPS)) { if (format & PARSE) strcpy(fmt, P_DROP_FMT_BRIEF); else strcpy(fmt, DROP_FMT_BRIEF); fprintf(stdout, fmt, (int64_t)(((MB - srvr_MB) *1024*1024) /buflen + 0.5), (uint64_t)((MB*1024*1024) /buflen + 0.5)); } if (!(format & NOPERCENTLOSS)) { fractloss = ((MB != 0.0) ? 1 - srvr_MB/MB : 0.0); if (format & PARSE) strcpy(fmt, P_LOSS_FMT_BRIEF); else if ((fractloss != 0.0) && (fractloss < 0.001)) strcpy(fmt, LOSS_FMT_BRIEF5); else strcpy(fmt, LOSS_FMT_BRIEF); fprintf(stdout, fmt, fractloss * 100); } if (format & XMITSTATS) { if (format & PARSE) strcpy(fmt, P_PERF_FMT_BRIEF3); else strcpy(fmt, PERF_FMT_BRIEF3); fprintf(stdout, fmt, MB); } } else { if (*ident) fprintf(stdout, "%s: ", ident + 1); if (format & PARSE) strcpy(fmt, P_PERF_FMT_BRIEF); else strcpy(fmt, PERF_FMT_BRIEF); fprintf(stdout, fmt, MB, realt, (double)nbytes/realt/125000, srvr_cpu_util, cpu_util); if (!(format & NODROPS)) { if (format & PARSE) strcpy(fmt, P_DROP_FMT_BRIEF); else strcpy(fmt, DROP_FMT_BRIEF); fprintf(stdout, fmt, (int64_t)(((srvr_MB - MB) *1024*1024) /buflen + 0.5), (uint64_t)((srvr_MB*1024*1024) /buflen + 0.5)); } if (!(format & NOPERCENTLOSS)) { fractloss = ((srvr_MB != 0.0) ? 1 - MB/srvr_MB : 0.0); if (format & PARSE) strcpy(fmt, P_LOSS_FMT_BRIEF); else if ((fractloss != 0.0) && (fractloss < 0.001)) strcpy(fmt, LOSS_FMT_BRIEF5); else strcpy(fmt, LOSS_FMT_BRIEF); fprintf(stdout, fmt, fractloss * 100); } if (format & XMITSTATS) { if (format & PARSE) strcpy(fmt, P_PERF_FMT_BRIEF3); else strcpy(fmt, PERF_FMT_BRIEF3); fprintf(stdout, fmt, srvr_MB); } } fprintf(stdout, "\n"); } else if (trans) { if ((retransinfo > 0) && (!(format & NORETRANS))) { if (format & DEBUGRETRANS) { sretrans = get_retrans(-1); fprintf(stdout, "report system retrans = %d\n", sretrans); } } if (*ident) fprintf(stdout, "%s: ", ident + 1); if (format & PARSE) strcpy(fmt, P_PERF_FMT_BRIEF); else strcpy(fmt, PERF_FMT_BRIEF); fprintf(stdout, fmt, srvr_MB, srvr_realt, srvr_Mbps, cpu_util, srvr_cpu_util ); if ((retransinfo > 0) && (!(format & NORETRANS))) { if (format & PARSE) fprintf(stdout, P_RETRANS_FMT_BRIEF, retransinfo == 1 ? "" : "host-", nretrans); else fprintf(stdout, RETRANS_FMT_BRIEF, nretrans, retransinfo == 1 ? "" : "host-"); } if (rtt && (format & WANTRTT)) { if (format & PARSE) strcpy(fmt, P_RTT_FMT_BRIEF); else strcpy(fmt, RTT_FMT_BRIEF); fprintf(stdout, fmt, rtt); } fprintf(stdout, "\n"); } else { if (*ident) fprintf(stdout, "%s: ", ident + 1); if (format & PARSE) strcpy(fmt, P_PERF_FMT_BRIEF); else strcpy(fmt, PERF_FMT_BRIEF); fprintf(stdout, fmt, MB, realt, (double)nbytes/realt/125000, srvr_cpu_util, cpu_util ); if ((retransinfo > 0) && (!(format & NORETRANS))) { if (format & PARSE) fprintf(stdout, P_RETRANS_FMT_BRIEF, retransinfo == 1 ? "" : "host-", nretrans); else fprintf(stdout, RETRANS_FMT_BRIEF, nretrans, retransinfo == 1 ? "" : "host-"); } if (rtt && (format & WANTRTT)) { if (format & PARSE) strcpy(fmt, P_RTT_FMT_BRIEF); else strcpy(fmt, RTT_FMT_BRIEF); fprintf(stdout, fmt, rtt); } fprintf(stdout, "\n"); } } else { if (brief && !clientserver) { if (brief < 0) fprintf(stdout, "\n"); if (*ident) fprintf(stdout, "%s: ", ident + 1); fprintf(stdout, PERF_FMT_BRIEF2 "\n", MB, realt, (double)nbytes/realt/125000, cpu_util, trans?"TX":"RX" ); } } cleanup: if (clientserver) { if (client) { itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT; itimer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); if (brief <= 0) fputs("\n", stdout); if (brief <= 0) { if (got_srvr_output) { fputs(srvrbuf, stdout); } } else { while (fgets(buf, mallocsize, stdin)) { setitimer(ITIMER_REAL, &itimer, 0); fputs(buf, stdout); } } itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); fflush(stdout); close(0); } else { fflush(stdout); close(1); if (!inetd) { dup(savestdout); close(savestdout); fflush(stderr); if (!nofork) { close(2); dup(1); } } } fclose(ctlconn); if (!inetd) close(fd[0]); if (!udp && trans && (retransinfo > 0)) { if (format & DEBUGRETRANS) { sretrans = get_retrans(-1); fprintf(stdout, "final system retrans = %d\n", sretrans); } } } if (clientserver && !client) { itimer.it_value.tv_sec = 0; itimer.it_value.tv_usec = 0; itimer.it_interval.tv_sec = 0; itimer.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &itimer, 0); signal(SIGALRM, SIG_DFL); bzero((char *)&frominet, sizeof(frominet)); bzero((char *)&clientaddr, sizeof(clientaddr)); #ifdef AF_INET6 bzero((char *)&clientaddr6, sizeof(clientaddr)); clientscope6 = 0; #endif cput = 0.000001; realt = 0.000001; nbytes = 0; ntbytes = 0; ntbytesc = 0; chk_nbytes = 0; numCalls = 0; /* Don't re-initialize buflen since it's used to */ /* determine if we need to change the buffer memory */ /* allocation for the next client data stream request */ /* buflen = 64 * 1024; */ /* if (udp) buflen = DEFAULTUDPBUFLEN; */ nbuf = 0; sendwin = origsendwin; rcvwin = origrcvwin; nstream = 1; b_flag = 1; rate = MAXRATE; irate = 0; irate_cum_nsec = 0.0; timeout = 0.0; interval = 0.0; chk_interval = 0.0; chk_idle_data = 0.0; datamss = 0; tos = 0; nodelay = 0; do_poll = 0; pbytes = 0; ptbytes = 0; ident[0] = '\0'; intr = 0; abortconn = 0; port = 5001; trans = 0; braindead = 0; udp = 0; udplossinfo = 0; retransinfo = 0; force_retrans = 0; rtt = 0.0; nretrans = 0; iretrans = 0; pretrans = 0; sretrans = 0; got_srvr_output = 0; reading_srvr_info = 0; reverse = 0; format = 0; traceroute = 0; multicast = 0; skip_data = 0; host3 = NULL; thirdparty = 0; nbuf_bytes = 0; rate_pps = 0; #ifdef HAVE_SETPRIO priority = 0; #endif brief = 0; done = 0; got_begin = 0; two_bod = 0; handle_urg = 0; for ( stream_idx = 0; stream_idx <= nstream; stream_idx++ ) res[stream_idx] = NULL; if (!oneshot) goto doit; } for ( stream_idx = 0; stream_idx <= nstream; stream_idx++ ) if (res[stream_idx]) freeaddrinfo(res[stream_idx]); exit(0); usage: fprintf(stdout,Usage); exit(1); } static void err( char *s ) { long flags, saveflags; fprintf(stderr,"nuttcp%s%s: v%d.%d.%d%s: Error: ", trans?"-t":"-r", ident, vers_major, vers_minor, vers_delta, beta ? BETA_STR : ""); perror(s); fprintf(stderr,"errno=%d\n",errno); fflush(stderr); if ((stream_idx > 0) && !done && clientserver && !client && !trans && handle_urg) { /* send 'A' for ABORT as urgent TCP data * on control connection (don't block) */ saveflags = fcntl(fd[0], F_GETFL, 0); if (saveflags != -1) { flags = saveflags | O_NONBLOCK; fcntl(fd[0], F_SETFL, flags); } send(fd[0], "A", 1, MSG_OOB); if (saveflags != -1) { flags = saveflags; fcntl(fd[0], F_SETFL, flags); } } exit(1); } static void mes( char *s ) { fprintf(stdout,"nuttcp%s%s: v%d.%d.%d%s: %s\n", trans?"-t":"-r", ident, vers_major, vers_minor, vers_delta, beta ? BETA_STR : "", s); } static void errmes( char *s ) { fprintf(stderr,"nuttcp%s%s: v%d.%d.%d%s: Error: ", trans?"-t":"-r", ident, vers_major, vers_minor, vers_delta, beta ? BETA_STR : ""); perror(s); fprintf(stderr,"errno=%d\n",errno); fflush(stderr); } void pattern( register char *cp, register int cnt ) { register char c; c = 0; while( cnt-- > 0 ) { while( !isprint((c&0x7F)) ) c++; *cp++ = (c++&0x7F); } } /* * P R E P _ T I M E R */ void prep_timer() { gettimeofday(&time0, (struct timezone *)0); timep.tv_sec = time0.tv_sec; timep.tv_usec = time0.tv_usec; timepk.tv_sec = time0.tv_sec; timepk.tv_usec = time0.tv_usec; getrusage(RUSAGE_SELF, &ru0); } /* * R E A D _ T I M E R * */ double read_timer( char *str, int len ) { struct timeval timedol; struct rusage ru1; struct timeval td; struct timeval tend, tstart; char line[132]; getrusage(RUSAGE_SELF, &ru1); gettimeofday(&timedol, (struct timezone *)0); prusage(&ru0, &ru1, &timedol, &time0, line); (void)strncpy( str, line, len ); /* Get real time */ tvsub( &td, &timedol, &time0 ); realt = td.tv_sec + ((double)td.tv_usec) / 1000000; /* Get CPU time (user+sys) */ tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime ); tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime ); tvsub( &td, &tend, &tstart ); cput = td.tv_sec + ((double)td.tv_usec) / 1000000; if( cput < 0.00001 ) cput = 0.00001; return( cput ); } static void prusage( register struct rusage *r0, register struct rusage *r1, struct timeval *e, struct timeval *b, char *outp ) { struct timeval tdiff; register time_t t; register char *cp; register int i; int ms; t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+ (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+ (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+ (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000; ms = (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000; #define END(x) {while(*x) x++;} if (format & PARSE) cp = "user=%U system=%S elapsed=%E cpu=%P memory=%Xi+%Dd-%Mmaxrss io=%F+%Rpf swaps=%Ccsw"; else cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw"; for (; *cp; cp++) { if (*cp != '%') *outp++ = *cp; else if (cp[1]) switch(*++cp) { case 'U': tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime); sprintf(outp,"%ld.%01ld", (long)tdiff.tv_sec, (long)tdiff.tv_usec/100000); END(outp); break; case 'S': tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime); sprintf(outp,"%ld.%01ld", (long)tdiff.tv_sec, (long)tdiff.tv_usec/100000); END(outp); break; case 'E': psecs(ms / 100, outp); END(outp); break; case 'P': sprintf(outp,"%d%%", (int) (t*100 / ((ms ? ms : 1)))); END(outp); break; case 'W': i = r1->ru_nswap - r0->ru_nswap; sprintf(outp,"%d", i); END(outp); break; case 'X': sprintf(outp,"%ld", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t); END(outp); break; case 'D': sprintf(outp,"%ld", t == 0 ? 0 : (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t); END(outp); break; case 'K': sprintf(outp,"%ld", t == 0 ? 0 : ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) - (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t); END(outp); break; case 'M': sprintf(outp,"%ld", r1->ru_maxrss/2); END(outp); break; case 'F': sprintf(outp,"%ld", r1->ru_majflt-r0->ru_majflt); END(outp); break; case 'R': sprintf(outp,"%ld", r1->ru_minflt-r0->ru_minflt); END(outp); break; case 'I': sprintf(outp,"%ld", r1->ru_inblock-r0->ru_inblock); END(outp); break; case 'O': sprintf(outp,"%ld", r1->ru_oublock-r0->ru_oublock); END(outp); break; case 'C': sprintf(outp,"%ld+%ld", r1->ru_nvcsw-r0->ru_nvcsw, r1->ru_nivcsw-r0->ru_nivcsw ); END(outp); break; } } *outp = '\0'; } static void tvadd( struct timeval *tsum, struct timeval *t0, struct timeval *t1 ) { tsum->tv_sec = t0->tv_sec + t1->tv_sec; tsum->tv_usec = t0->tv_usec + t1->tv_usec; if (tsum->tv_usec > 1000000) tsum->tv_sec++, tsum->tv_usec -= 1000000; } static void tvsub( struct timeval *tdiff, struct timeval *t1, struct timeval *t0 ) { tdiff->tv_sec = t1->tv_sec - t0->tv_sec; tdiff->tv_usec = t1->tv_usec - t0->tv_usec; if (tdiff->tv_usec < 0) tdiff->tv_sec--, tdiff->tv_usec += 1000000; } static void psecs( long l, register char *cp ) { register int i; i = l / 3600; if (i) { sprintf(cp,"%d:", i); END(cp); i = l % 3600; sprintf(cp,"%d%d", (i/60) / 10, (i/60) % 10); END(cp); } else { i = l; sprintf(cp,"%d", i / 60); END(cp); } i %= 60; *cp++ = ':'; sprintf(cp,"%d%d", i / 10, i % 10); } /* * N R E A D */ int Nread( int fd, char *buf, int count ) { struct sockaddr_storage from; socklen_t len = sizeof(from); register int cnt; if( udp ) { cnt = recvfrom( fd, buf, count, 0, (struct sockaddr *)&from, &len ); numCalls++; } else { if( b_flag ) cnt = mread( fd, buf, count ); /* fill buf */ else { cnt = read( fd, buf, count ); numCalls++; } } return(cnt); } /* * N W R I T E */ int Nwrite( int fd, char *buf, int count ) { struct timeval timedol; struct timeval td; register int cnt = 0; double deltat; if (irate) { /* Get real time */ gettimeofday(&timedol, (struct timezone *)0); tvsub( &td, &timedol, &timepk ); deltat = td.tv_sec + ((double)td.tv_usec) / 1000000; if (deltat >= 2*pkt_time) { timepk.tv_sec = timedol.tv_sec; timepk.tv_usec = timedol.tv_usec; irate_cum_nsec = 0; } while (((double)count/rate/125 > deltat) && !intr) { /* Get real time */ gettimeofday(&timedol, (struct timezone *)0); tvsub( &td, &timedol, &timepk ); deltat = td.tv_sec + ((double)td.tv_usec) / 1000000; } irate_cum_nsec += irate_pk_nsec; if (irate_cum_nsec >= 1000.0) { irate_cum_nsec -= 1000.0; timepk.tv_usec++; } timepk.tv_usec += irate_pk_usec; while (timepk.tv_usec >= 1000000) { timepk.tv_usec -= 1000000; timepk.tv_sec++; } if (intr && (!udp || (count != 4))) return(0); } else { while ((double)nbytes/realt/125 > rate) { /* Get real time */ gettimeofday(&timedol, (struct timezone *)0); tvsub( &td, &timedol, &time0 ); realt = td.tv_sec + ((double)td.tv_usec) / 1000000; if( realt <= 0.0 ) realt = 0.000001; } } /* beginnings of timestamps - not ready for prime time */ /* gettimeofday(&timedol, (struct timezone *)0); */ /* bcopy(&timedol.tv_sec, buf + 8, 4); */ /* bcopy(&timedol.tv_usec, buf + 12, 4); */ if( udp ) { again: if (af == AF_INET) { cnt = sendto( fd, buf, count, 0, (struct sockaddr *)&sinhim[stream_idx + 1], sizeof(sinhim[stream_idx + 1]) ); } #ifdef AF_INET6 else if (af == AF_INET6) { cnt = sendto( fd, buf, count, 0, (struct sockaddr *)&sinhim6[stream_idx + 1], sizeof(sinhim6[stream_idx + 1]) ); } #endif else { err("unsupported AF"); } numCalls++; if( cnt<0 && errno == ENOBUFS ) { delay(18000); errno = 0; goto again; } } else { cnt = write( fd, buf, count ); numCalls++; } return(cnt); } int delay( int us ) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = us; (void)select( 1, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv ); return(1); } /* * M R E A D * * This function performs the function of a read(II) but will * call read(II) multiple times in order to get the requested * number of characters. This can be necessary because * network connections don't deliver data with the same * grouping as it is written with. Written by Robert S. Miles, BRL. */ int mread( int fd, register char *bufp, unsigned n ) { register unsigned count = 0; register int nread; do { nread = read(fd, bufp, n-count); numCalls++; if(nread < 0) { if (errno != EINTR) perror("nuttcp_mread"); return(-1); } if(nread == 0) return((int)count); count += (unsigned)nread; bufp += nread; } while(count < n); return((int)count); } /* * G E T O P T V A L P * * This function returns a character pointer to the option value * pointed at by argv and sets skiparg to 1 if the option and its * value were passed as separate arguments (otherwise it sets * skiparg to 0). index is the position within argv where the * option value resides if the option was specified as a single * argument. reqval indicates whether or not the option requires * a value */ char * getoptvalp( char **argv, int index, int reqval, int *skiparg ) { struct sockaddr_storage dummy; char **nextarg; *skiparg = 0; nextarg = argv + 1; /* if there is a value in the current arg return it */ if (argv[0][index]) return(&argv[0][index]); /* if there isn't a next arg return a pointer to the current arg value (which will be an empty string) */ if (*nextarg == NULL) return(&argv[0][index]); /* if the next arg is another option, return a pointer to the current arg value (which will be an empty string) */ if (**nextarg == '-') return(&argv[0][index]); /* if there is an arg after the next arg and it is another option, return the next arg as the option value */ if (*(nextarg + 1) && (**(nextarg + 1) == '-')) { *skiparg = 1; return(*nextarg); } /* if the option requires a value, return the next arg as the option value */ if (reqval) { *skiparg = 1; return(*nextarg); } /* if the next arg is an Ipv4 address, return a pointer to the current arg value (which will be an empty string) */ if (inet_pton(AF_INET, *nextarg, &dummy) > 0) return(&argv[0][index]); #ifdef AF_INET6 /* if the next arg is an Ipv6 address, return a pointer to the current arg value (which will be an empty string) */ if (inet_pton(AF_INET6, *nextarg, &dummy) > 0) return(&argv[0][index]); #endif /* if the next arg begins with an alphabetic character, assume it is a hostname and thus return a pointer to the current arg value (which will be an empty string). note all current options which don't require a value have numeric values (start with a digit) */ if (isalpha((int)(**nextarg))) return(&argv[0][index]); /* assume the next arg is the option value */ *skiparg = 1; return(*nextarg); } #define PROC_SNMP "/proc/net/snmp" #define PROC_BUF_LEN 256 #define PROC_BUF_LEN2 128 #define NETSTAT "netstat" #if defined(linux) #define RETRANS "segments retransmited" #define NETSTAT_DIR "/bin/" #define NRETRANS_BEFORE #elif defined(__FreeBSD__) #define RETRANS "retransmitted" #define NETSTAT_DIR "/usr/bin/" #define NRETRANS_BEFORE #elif defined(__APPLE__) && defined(__MACH__) #define RETRANS "retransmitted" #define NETSTAT_DIR "/usr/sbin/" #define NRETRANS_BEFORE #elif defined(sparc) #define RETRANS "tcpRetransSegs" #define NETSTAT_DIR "/usr/bin/" #elif defined(sgi) #define RETRANS "retransmitted" #define NETSTAT_DIR "/usr/etc/" #define NRETRANS_BEFORE #elif defined(__CYGWIN__) || defined(_WIN32) #define RETRANS "Segments Retransmitted" #define NETSTAT_DIR "" #else #define RETRANS "retransmitted" #define NETSTAT_DIR "/usr/bin/" #define NRETRANS_BEFORE #endif char proc_buf[PROC_BUF_LEN]; char proc_buf2[PROC_BUF_LEN2]; int get_retrans( int sockfd ) { FILE *proc_snmp; char *cp, *cp2; int num_retrans; int pipefd[2]; int pidstat; pid_t pid = 0; pid_t wait_pid; if (retransinfo < 0) return(0); #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS) if ((retransinfo <= 1) && (sockfd >= 0)) { optlen = sizeof(tcpinf); if (getsockopt(sockfd, SOL_TCP, TCP_INFO, (void *)&tcpinf, &optlen) == 0) { if (optlen >= SIZEOF_TCP_INFO_RETRANS) { retransinfo = 1; b_flag = 1; return(tcpinf.tcpi_total_retrans); } } if (retransinfo == 1) { retransinfo = -1; return(0); } retransinfo = 2; } #endif if ((retransinfo == 3) || (!(proc_snmp = fopen(PROC_SNMP, "r")))) { retransinfo = 3; if (pipe(pipefd) != 0) { retransinfo = -1; return(0); } if ((pid = fork()) == (pid_t)-1) { perror("can't fork"); close(pipefd[0]); close(pipefd[1]); retransinfo = -1; return(0); } if (pid == 0) { signal(SIGINT, SIG_DFL); close(1); close(2); dup(pipefd[1]); dup(pipefd[1]); close(pipefd[0]); close(pipefd[1]); execl(NETSTAT_DIR NETSTAT, NETSTAT, "-s", NULL); perror("execl failed"); fprintf(stderr, "failed to execute %s%s -s\n", NETSTAT_DIR, NETSTAT); fflush(stdout); fflush(stderr); exit(0); } close(pipefd[1]); if (!(proc_snmp = fdopen(pipefd[0], "r"))) { close(pipefd[0]); retransinfo = -1; return(0); } } errno = 0; num_retrans = -1; while (fgets(proc_buf, sizeof(proc_buf), proc_snmp)) { if (retransinfo == 2) { if (strncmp(proc_buf, "Tcp:", 4) != 0) continue; if ((!fgets(proc_buf2, sizeof(proc_buf2), proc_snmp)) || (strncmp(proc_buf2, "Tcp:", 4) != 0)) break; cp = proc_buf; cp2 = proc_buf2; while ((cp = strchr(cp, ' '))) { while (*++cp == ' ') ; if (!(*cp)) goto close; if (!(cp2 = strchr(cp2, ' '))) goto close; while (*++cp2 == ' ') ; if (!(*cp2)) goto close; if (strncmp(cp, "RetransSegs", 11) == 0) { if (!isdigit((int)(*cp2))) goto close; num_retrans = atoi(cp2); goto close; } else continue; } } else { if ((cp = strstr(proc_buf, RETRANS))) { #ifdef NRETRANS_BEFORE num_retrans = atoi(proc_buf); #else cp2 = strchr(cp, '='); cp2++; num_retrans = atoi(cp2); #endif break; } } } close: fclose(proc_snmp); if (retransinfo == 3) { while ((wait_pid = wait(&pidstat)) != pid) { if (wait_pid == (pid_t)-1) { if (errno == ECHILD) break; err("wait failed"); } } } if (num_retrans < 0) { retransinfo = -1; return(0); } return(num_retrans); } #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS) void print_tcpinfo() { fprintf(stdout, "state = %d, ca_state = %d, retransmits = %d, " "unacked = %d, sacked = %d\n", tcpinf.tcpinfo_state, tcpinf.tcpinfo_ca_state, tcpinf.tcpinfo_retransmits, tcpinf.tcpinfo_unacked, tcpinf.tcpinfo_sacked); fprintf(stdout, " lost = %d, retrans = %d, fackets = %d, " "rtt = %d, rttvar = %d\n", tcpinf.tcpinfo_lost, tcpinf.tcpinfo_retrans, tcpinf.tcpinfo_fackets, tcpinf.tcpinfo_rtt, tcpinf.tcpinfo_rttvar); fprintf(stdout, " snd_ssthresh = %d, snd_cwnd = %d, " "total_retrans = %d\n", tcpinf.tcpinfo_snd_ssthresh, tcpinf.tcpinfo_snd_cwnd, tcpinf.tcpi_total_retrans); return; } #endif nuttcp-6.1.2/LICENSE0000644000222400001560000004310307742462034013602 0ustar robmusketeers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 of the License, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. nuttcp-6.1.2/README0000664000222400001560000001304210441464321013445 0ustar robmusketeers6/06/06 Current version is 5.3.1. Introduced since 4.0.3 is max segment setting, tos settings, ipv4 multicast support, as well as many bug fixes and improvements. The beginning of a man page can be found in nuttcp.8 and a set of examples in examples.txt with commentary. Version 4.0.3 introduced IPv6 support and changed the command defaults to brief output, 10 second time limited transmit. The "-xt" option now does both forward and reverse traceroutes. Note the rarely used "-b" option has been changed to instead signify brief output. The old "-b" option is now "-wb". ******************************************************************************** The nuttcp software is geared toward network managers, and is *NOT* intended for general public use. You may send bug reports, feature requests, or general comments to billfink@mindspring.com, but we make no promises about being able to respond. In other words, we hope you find this network performance monitoring tool useful (it's based on the original ttcp/nttcp), but there is no warranty of any kind. It has several useful features beyond those of the basic ttcp/nttcp, such as a server mode, rate limiting, multiple parallel streams, and timer based usage. It has been successfully tested and used on a variety of Solaris, SGI, PPC/X86 Linux, FreeBSD, AIX, and Windows systems, and should probably work on most other flavors of Unix. To get a usage statement, just run nuttcp with no arguments. ******************************************************************************** The source code together with available binaries is available at: ftp://ftp.lcp.nrl.navy.mil/pub/nuttcp/ To find the latest version, follow the "latest" symbolic link. To find a possibly older, better tested version follow the "stable" link. ******************************************************************************** To use as an inetd or xinetd daemon, do the following: 1. Add an entry similar to the following to the /etc/inetd.conf file (for an IPv4 server). nuttcp stream tcp nowait root /usr/local/sbin/tcpd /usr/local/bin/nuttcp -S Sample xinetd configuration files can be found in the "xinetd.d" subdirectory. 2. Add entries like the following to the /etc/services file. nuttcp 5000/tcp nuttcp-data 5001/tcp nuttcp6 5000/tcp nuttcp6-data 5001/tcp For inetd it may be necessary to run the IPv4 and IPv6 servers on different ports. 3. Add a nuttcp entry to the /etc/hosts.allow file to control what hosts you want to allow access to the nuttcp service. 4. Send a HUP signal to the inetd or xinetd process (older xinetd requires USR2 signal). You can also just run a "nuttcp -S" as a normal user process to test out the server functionality before putting it into the inetd.conf or xinetd.d configuration file. The files in the "missing" subdirectory are required to build nuttcp on certain architectures which lack either poll() or the newer inet functions. For MacOS X the only required extra file is "missing/fakepoll.h". Solaris before 2.8 requires all the extra files in missing. The files in the "cygwin" subdirectory are the source, patches, and license for the cygwin library which has been linked into the Windows binary. Finally, here's a basic sample usage of the nuttcp client talking to an already established nuttcp server, specifying a window size of 512 KB and interval reporting every second, and using the default of transmitting to the server for 10 seconds and producing brief output (across a GigE link): % nuttcp -i1 -w512 192.168.75.75 117.8587 MB / 1.00 sec = 989.2512 Mbps 118.0138 MB / 1.00 sec = 989.9721 Mbps 117.9086 MB / 1.00 sec = 989.0879 Mbps 118.0239 MB / 1.00 sec = 990.0540 Mbps 117.9979 MB / 1.00 sec = 989.8300 Mbps 118.0165 MB / 1.00 sec = 990.0062 Mbps 118.0052 MB / 1.00 sec = 989.8798 Mbps 118.0138 MB / 1.00 sec = 989.9880 Mbps 117.9967 MB / 1.00 sec = 989.8121 Mbps 118.0165 MB / 1.00 sec = 990.0102 Mbps 1183.2500 MB / 10.03 sec = 989.8024 Mbps 74 %TX 9 %RX Without the "-i" interval option, the default brief output gives a one-line summary such as the following which demonstrates the simplest use of nuttcp when accepting all the default settings: % nuttcp 192.168.75.75 827.8125 MB / 10.02 sec = 692.8015 Mbps 51 %TX 7 %RX And here's a sample of verbose output. This test was across a 768 Kbps DSL line, doing a receive from the server instead of the default transmit, using a window size of 512 KB, and transferring 8 MB of data (1024 buffers each of length 8192). % nuttcp -r -l8192 -n1024 -w512 -v 192.168.7.20 nuttcp-r: v4.0.3: socket nuttcp-r: buflen=8192, nbuf=1024, nstream=1, port=5001 tcp nuttcp-r: accept from 192.168.7.20 nuttcp-r: send window size = 16384, receive window size = 1048576 nuttcp-r: 8.0000 MB in 126.15 real seconds = 64.94 KB/sec = 0.5320 Mbps nuttcp-r: 5893 I/O calls, msec/call = 21.92, calls/sec = 46.71 nuttcp-r: 0.0user 0.0sys 2:06real 0% 0i+0d 0maxrss 1+0pf 0+0csw nuttcp-t: v4.0.3: socket nuttcp-t: buflen=8192, nbuf=1024, nstream=1, port=5001 tcp -> 192.168.75.30 nuttcp-t: connect to 192.168.75.30 nuttcp-t: send window size = 1048576, receive window size = 87380 nuttcp-t: 8.0000 MB in 116.43 real seconds = 70.36 KB/sec = 0.5764 Mbps nuttcp-t: 1024 I/O calls, msec/call = 116.43, calls/sec = 8.80 nuttcp-t: 0.0user 0.0sys 1:56real 0% 0i+0d 0maxrss 1+0pf 0+0csw We hope you find it useful. -Bill Fink billfink@mindspring.com -Rob Scott rob@hpcmo.hpc.mil Contact the projects authors at nuttcp@lcp.nrl.navy.mil Report bugs to nuttcp-bugs@lcp.nrl.navy.mil nuttcp-6.1.2/cygwin/0002775000222400001560000000000010441613113014062 5ustar robmusketeersnuttcp-6.1.2/cygwin/cygwin-1.5.19-4-ipv6-0.21.diff0000644000222400001560000006047010441610005020346 0ustar robmusketeersdiff -aurN orig/cygwin-1.5.19-4/winsup/cygserver/transport_sockets.cc cygwin-1.5.19-4/winsup/cygserver/transport_sockets.cc --- orig/cygwin-1.5.19-4/winsup/cygserver/transport_sockets.cc 2004-10-19 02:41:37.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygserver/transport_sockets.cc 2006-01-22 11:06:11.678000000 +0900 @@ -202,7 +202,7 @@ socklen_t client_addr_len = sizeof (client_addr); const int accept_fd = - cygwin_accept (_fd, (struct sockaddr *) &client_addr, &client_addr_len); + cygwin_accept (_fd, (struct sockaddr *) &client_addr, (int *)&client_addr_len); if (accept_fd == -1) { diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/autoload.cc cygwin-1.5.19-4/winsup/cygwin/autoload.cc --- orig/cygwin-1.5.19-4/winsup/cygwin/autoload.cc 2006-01-21 00:54:29.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/autoload.cc 2006-01-22 11:06:11.693625000 +0900 @@ -496,6 +496,9 @@ LoadDLLfunc (WSAEventSelect, 12, ws2_32) LoadDLLfunc (WSAEnumNetworkEvents, 12, ws2_32) LoadDLLfunc (__WSAFDIsSet, 8, ws2_32) +LoadDLLfunc (getaddrinfo, 16, ws2_32) +LoadDLLfunc (freeaddrinfo, 4, ws2_32) +LoadDLLfunc (getnameinfo, 28, ws2_32) LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1) LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1) diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/cygwin.din cygwin-1.5.19-4/winsup/cygwin/cygwin.din --- orig/cygwin-1.5.19-4/winsup/cygwin/cygwin.din 2006-01-17 02:14:35.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/cygwin.din 2006-01-22 11:06:11.709250000 +0900 @@ -323,6 +323,13 @@ getsockopt = cygwin_getsockopt SIGFE getsubopt SIGFE getusershell SIGFE +getaddrinfo = cygwin_getaddrinfo SIGFE +gai_strerror = cygwin_gai_strerror SIGFE +freeaddrinfo = cygwin_freeaddrinfo SIGFE +getnameinfo = cygwin_getnameinfo SIGFE +gethostbyname2 = cygwin_gethostbyname2 SIGFE +in6addr_any DATA +in6addr_loopback DATA herror = cygwin_herror SIGFE hstrerror = cygwin_hstrerror NOSIGFE inet_addr = cygwin_inet_addr SIGFE diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/fhandler_socket.cc cygwin-1.5.19-4/winsup/cygwin/fhandler_socket.cc --- orig/cygwin-1.5.19-4/winsup/cygwin/fhandler_socket.cc 2006-01-21 00:54:29.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/fhandler_socket.cc 2006-01-22 11:06:11.724875000 +0900 @@ -49,15 +49,15 @@ /* cygwin internal: map sockaddr into internet domain address */ static int get_inet_addr (const struct sockaddr *in, int inlen, - struct sockaddr_in *out, int *outlen, + struct sockaddr *out, int *outlen, int *type = NULL, int *secret = NULL) { int secret_buf [4]; int* secret_ptr = (secret ? : secret_buf); - if (in->sa_family == AF_INET) + if (in->sa_family == AF_INET || in->sa_family == AF_INET6) { - *out = * (struct sockaddr_in *)in; + memcpy(out, in, inlen); *outlen = inlen; return 1; } @@ -101,7 +101,7 @@ secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3); sin.sin_port = htons (sin.sin_port); sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - *out = sin; + memcpy(out, &sin, sizeof sin); *outlen = sizeof sin; if (type) *type = (ctype == 's' ? SOCK_STREAM : @@ -666,11 +666,11 @@ { int res = -1; bool in_progress = false; - struct sockaddr_in sin; + struct sockaddr_storage sin; DWORD err; int type; - if (!get_inet_addr (name, namelen, &sin, &namelen, &type, connect_secret)) + if (!get_inet_addr (name, namelen, (struct sockaddr *)&sin, &namelen, &type, connect_secret)) return -1; if (get_addr_family () == AF_LOCAL && get_socket_type () != type) @@ -761,13 +761,13 @@ int res = -1; /* Allows NULL peer and len parameters. */ - struct sockaddr_in peer_dummy; + struct sockaddr_storage peer_dummy; int len_dummy; if (!peer) peer = (struct sockaddr *) &peer_dummy; if (!len) { - len_dummy = sizeof (struct sockaddr_in); + len_dummy = sizeof (struct sockaddr_storage); len = &len_dummy; } @@ -1099,7 +1099,7 @@ const int iovcnt = msg->msg_iovlen; struct sockaddr *from = (struct sockaddr *) msg->msg_name; - int *fromlen = from ? &msg->msg_namelen : NULL; + int *fromlen = from ? (int *)&msg->msg_namelen : NULL; int res = SOCKET_ERROR; @@ -1186,9 +1186,9 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags, const struct sockaddr *to, int tolen) { - struct sockaddr_in sin; + struct sockaddr_storage sin; - if (to && !get_inet_addr (to, tolen, &sin, &tolen)) + if (to && !get_inet_addr (to, tolen, (struct sockaddr *)&sin, &tolen)) return SOCKET_ERROR; int res = SOCKET_ERROR; diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in.h cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in.h --- orig/cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in.h 2006-01-17 02:14:36.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in.h 2006-01-22 11:06:11.740500000 +0900 @@ -19,6 +19,7 @@ #define _CYGWIN_IN_H #include +#include typedef uint16_t in_port_t; typedef uint32_t in_addr_t; @@ -36,6 +37,7 @@ IPPROTO_PUP = 12, /* PUP protocol */ IPPROTO_UDP = 17, /* User Datagram Protocol */ IPPROTO_IDP = 22, /* XNS IDP protocol */ + IPPROTO_IPV6 = 41, /* Internet Protocol Version 6 */ IPPROTO_RAW = 255, /* Raw IP packets */ IPPROTO_MAX }; @@ -185,21 +187,4 @@ #endif -#ifdef USE_IPV6 -/* IPv6 definitions as we start to include them. This is just - a beginning dont get excited 8) */ -struct in6_addr -{ - uint8_t s6_addr[16]; -}; - -struct sockaddr_in6 -{ - sa_family_t sin6_family; /* AF_INET6 */ - in_port_t sin6_port; /* Port number. */ - uint32_t sin6_flowinfo; /* Traffic class and flow inf. */ - struct in6_addr sin6_addr; /* IPv6 address. */ - uint32_t sin6_scope_id; /* Set of interfaces for a scope. */ -}; -#endif #endif /* _CYGWIN_IN_H */ diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in6.h cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in6.h --- orig/cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in6.h 1970-01-01 09:00:00.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/include/cygwin/in6.h 2006-01-22 11:06:11.756125000 +0900 @@ -0,0 +1,158 @@ +#ifndef _CYGWIN_IN6_H +#define _CYGWIN_IN6_H + +#define INET6_ADDRSTRLEN 46 + +/* + * IPv6 definitions as we start to include them. This is just + * a beginning dont get excited 8) + */ + +struct in6_addr +{ + union { + u_int8_t __u6_addr8[16]; + u_int16_t __u6_addr16[8]; + u_int32_t __u6_addr32[4]; + } __u6_addr; /* 128-bit IP6 address */ +}; +#define s6_addr __u6_addr.__u6_addr8 + +struct sockaddr_in6 +{ + unsigned short sin6_family; /* AF_INET6 (sa_family_t) */ + unsigned short sin6_port; /* Transport layer port # (in_port_t)*/ + unsigned long sin6_flowinfo; /* IP6 flow information */ + struct in6_addr sin6_addr; /* IP6 address */ + unsigned long sin6_scope_id; /* scope zone index */ +}; + +/* Argument structure for IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP */ + +#define IN6ADDR_ANY_INIT { 0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } + +#ifdef __INSIDE_CYGWIN_NET__ +extern const struct in6_addr in6addr_any; +extern const struct in6_addr in6addr_loopback; +#else +extern __declspec(dllimport) const struct in6_addr in6addr_any; +extern __declspec(dllimport) const struct in6_addr in6addr_loopback; +#endif /* __INSIDE_CYGWIN_NET__ */ + +/* + * Equality + */ +#define IN6_ARE_ADDR_EQUAL(a, b) \ + (memcmp(&(a)->s6_addr[0], &(b)->s6_addr[0], sizeof(struct in6_addr)) == 0) + +/* + * Unspecified + */ +#define IN6_IS_ADDR_UNSPECIFIED(a) \ + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) == 0)) + +/* + * Loopback + */ +#define IN6_IS_ADDR_LOOPBACK(a) \ + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) == ntohl(1))) + +/* + * Multicast + */ +#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff) + +/* + * Unicast Scope + * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). + */ +#define IN6_IS_ADDR_LINKLOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80)) +#define IN6_IS_ADDR_SITELOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0)) + +/* + * Mapped + */ +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff))) + +/* + * IPv4 compatible + */ +#define IN6_IS_ADDR_V4COMPAT(a) \ + ((*(u_int32_t *)(&(a)->s6_addr[0]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[4]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[8]) == 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) != 0) && \ + (*(u_int32_t *)(&(a)->s6_addr[12]) != ntohl(1))) + +#define IPV6_ADDR_SCOPE_NODELOCAL 0x01 +#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 +#define IPV6_ADDR_SCOPE_SITELOCAL 0x05 +#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 +#define IPV6_ADDR_SCOPE_GLOBAL 0x0e + +/* + * Multicast Scope + */ +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_NODELOCAL)) +#define IN6_IS_ADDR_MC_LINKLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_LINKLOCAL)) +#define IN6_IS_ADDR_MC_SITELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_SITELOCAL)) +#define IN6_IS_ADDR_MC_ORGLOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_ORGLOCAL)) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (IPV6_ADDR_MC_SCOPE(a) == IPV6_ADDR_SCOPE_GLOBAL)) + +/* Argument structure for IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP */ + +typedef struct ipv6_mreq { + struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast address. */ + unsigned int ipv6mr_interface; /* Interface index. */ +}; + +/* + * Socket options at the IPPROTO_IPV6 level. + */ +#define IPV6_UNICAST_HOPS 4 /* Set/get IP unicast hop limit. */ +#define IPV6_MULTICAST_IF 9 /* Set/get IP multicast interface. */ +#define IPV6_MULTICAST_HOPS 10 /* Set/get IP multicast ttl. */ +#define IPV6_MULTICAST_LOOP 11 /* Set/get IP multicast loopback. */ +#define IPV6_ADD_MEMBERSHIP 12 /* Add an IP group membership. */ +#define IPV6_DROP_MEMBERSHIP 13 /* Drop an IP group membership. */ +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#define IPV6_PKTINFO 19 /* Receive packet information for ipv6 */ + +/* + * Socket options at the IPPROTO_UDP level. + */ +#define UDP_CHECKSUM_COVERAGE 20 // Set/get UDP-Lite checksum coverage. + +/* + * WARNING: The gai_strerror inline functions below use static buffers, + * and hence are not thread-safe. We'll use buffers long enough to hold + * 1k characters. Any system error messages longer than this will be + * returned as empty strings. However 1k should work for the error codes + * used by getaddrinfo(). + */ +#define GAI_STRERROR_BUFFER_SIZE 1024 + +#endif /* _CYGWIN_IN6_H */ diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/include/cygwin/socket.h cygwin-1.5.19-4/winsup/cygwin/include/cygwin/socket.h --- orig/cygwin-1.5.19-4/winsup/cygwin/include/cygwin/socket.h 2006-01-21 00:47:51.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/include/cygwin/socket.h 2006-01-22 11:06:11.771750000 +0900 @@ -149,9 +149,7 @@ #define AF_HYLINK 15 /* NSC Hyperchannel */ #define AF_APPLETALK 16 /* AppleTalk */ #define AF_NETBIOS 17 /* NetBios-style addresses */ -#if 0 /* Not yet */ #define AF_INET6 23 /* IP version 6 */ -#endif #define AF_MAX 32 /* @@ -177,9 +175,7 @@ #define PF_HYLINK AF_HYLINK #define PF_APPLETALK AF_APPLETALK #define PF_NETBIOS AF_NETBIOS -#if 0 #define PF_INET6 AF_INET6 -#endif #define PF_MAX AF_MAX diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/include/netdb.h cygwin-1.5.19-4/winsup/cygwin/include/netdb.h --- orig/cygwin-1.5.19-4/winsup/cygwin/include/netdb.h 2002-06-11 11:52:15.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/include/netdb.h 2006-01-22 11:06:27.006125000 +0900 @@ -63,6 +63,9 @@ extern "C" { #endif +/* for socklen_t */ +#include + /* * Structures returned by network data base library. All addresses are * supplied in host order, and returned in network order (suitable for @@ -111,6 +114,63 @@ int r_number; /* rpc program number */ }; +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; + + +/* + * Error codes from getaddrinfo(). + */ +#define _WSABASEERR 10000 +#define _WSATRY_AGAIN (_WSABASEERR+1002) +#define _WSAEINVAL (_WSABASEERR+22) +#define _WSANO_RECOVERY (_WSABASEERR+1003) +#define _WSAEAFNOSUPPORT (_WSABASEERR+47) +#define _ERROR_NOT_ENOUGH_MEMORY 8L +#define _WSA_NOT_ENOUGH_MEMORY _ERROR_NOT_ENOUGH_MEMORY +#define _WSANO_DATA (_WSABASEERR+1004) +#define _WSAHOST_NOT_FOUND (_WSABASEERR+1001) +#define _WSATYPE_NOT_FOUND (_WSABASEERR+109) +#define _WSAESOCKTNOSUPPORT (_WSABASEERR+44) + +#define EAI_AGAIN _WSATRY_AGAIN +#define EAI_BADFLAGS _WSAEINVAL +#define EAI_FAIL _WSANO_RECOVERY +#define EAI_FAMILY _WSAEAFNOSUPPORT +#define EAI_MEMORY _WSA_NOT_ENOUGH_MEMORY +#define EAI_NODATA _WSANO_DATA +#define EAI_NONAME _WSAHOST_NOT_FOUND +#define EAI_SERVICE _WSATYPE_NOT_FOUND +#define EAI_SOCKTYPE _WSAESOCKTNOSUPPORT + +/* + * Flags used in "hints" argument to getaddrinfo(). + */ +#define AI_PASSIVE 0x1 /* Socket address will be used in bind() call. */ +#define AI_CANONNAME 0x2 /* Return canonical name in first ai_canonname. */ +#define AI_NUMERICHOST 0x4 /* Nodename must be a numeric address string. */ + + +#define NI_MAXHOST 1025 /* Max size of a fully-qualified domain name. */ +#define NI_MAXSERV 32 /* Max size of a service name. */ + +/* + * Flags for getnameinfo(). + */ +#define NI_NOFQDN 0x01 /* Only return nodename portion for local hosts. */ +#define NI_NUMERICHOST 0x02 /* Return numeric form of the host's address. */ +#define NI_NAMEREQD 0x04 /* Error if the host's name not in DNS. */ +#define NI_NUMERICSERV 0x08 /* Return numeric form of the service (port #). */ +#define NI_DGRAM 0x10 /* Service is a datagram service. */ + /* * Error return codes from gethostbyname() and gethostbyaddr() * (left in extern int h_errno). @@ -158,6 +218,11 @@ void setprotoent (int); void setservent (int); void setrpcent (int); +int getaddrinfo (const char *, const char *, struct addrinfo *, struct addrinfo **); +char *gai_strerror(int); +void freeaddrinfo(struct addrinfo *); +int getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int); +struct hostent *gethostbyname2(const char *, int); #endif #ifdef __cplusplus diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/include/netinet/in.h cygwin-1.5.19-4/winsup/cygwin/include/netinet/in.h --- orig/cygwin-1.5.19-4/winsup/cygwin/include/netinet/in.h 2001-03-26 06:09:52.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/include/netinet/in.h 2006-01-22 11:06:11.787375000 +0900 @@ -12,5 +12,6 @@ #define _NETINET_IN_H #include +#include #endif /* _NETINET_IN_H */ diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/include/netinet/in6.h cygwin-1.5.19-4/winsup/cygwin/include/netinet/in6.h --- orig/cygwin-1.5.19-4/winsup/cygwin/include/netinet/in6.h 1970-01-01 09:00:00.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/include/netinet/in6.h 2006-01-22 11:06:11.803000000 +0900 @@ -0,0 +1,7 @@ +#ifndef _NETINET_IN6_H +#define _NETINET_IN6_H + +#include +#include + +#endif /* _NETINET_IN6_H */ diff -aurN orig/cygwin-1.5.19-4/winsup/cygwin/net.cc cygwin-1.5.19-4/winsup/cygwin/net.cc --- orig/cygwin-1.5.19-4/winsup/cygwin/net.cc 2006-01-21 00:54:29.000000000 +0900 +++ cygwin-1.5.19-4/winsup/cygwin/net.cc 2006-01-22 11:24:29.224875000 +0900 @@ -26,6 +26,7 @@ #include #define USE_SYS_TYPES_FD_SET #include +#include #include #include "cygerrno.h" #include "security.h" @@ -50,6 +51,13 @@ char *password, char *cmd, SOCKET * fd2p); int __stdcall rresvport (int *); int sscanf (const char *, const char *, ...); + + extern const struct in6_addr __declspec (dllexport) in6addr_any = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; + extern const struct in6_addr __declspec (dllexport) in6addr_loopback = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}; } /* End of "C" section */ static fhandler_socket * @@ -569,7 +577,17 @@ debug_printf ("socket (%d, %d, %d)", af, type, protocol); - soc = socket (AF_INET, type, af == AF_LOCAL ? 0 : protocol); + switch (af) + { + case AF_INET6: + case AF_INET: + soc = socket (af, type, protocol); + break; + case AF_UNIX: + default: + soc = socket (AF_INET, type, 0); + break; + } if (soc == INVALID_SOCKET) { @@ -579,7 +597,7 @@ const device *dev; - if (af == AF_INET) + if (af == AF_INET || af == AF_INET6) dev = type == SOCK_STREAM ? tcp_dev : udp_dev; else dev = type == SOCK_STREAM ? stream_dev : dgram_dev; @@ -2111,6 +2129,172 @@ { } +/* exported as getaddrinfo: standards? */ +extern "C" int +cygwin_getaddrinfo (const char *hname, const char *pname, + struct addrinfo *hints, struct addrinfo **res) +{ + + int g; + + g = getaddrinfo (hname, pname, hints, res); + if (g) + { + set_winsock_errno (); + set_host_errno (); + } + else + { + debug_printf ("hname = %s, pname = %s", hname, pname); + h_errno = 0; + } + return g; +} + +/* exported as gai_strerror: standards? */ +extern "C" const char * +cygwin_gai_strerror (int ecode) +{ + switch (ecode) + { + case EAI_AGAIN: + return ("Temporary failure in name resolution"); + case EAI_BADFLAGS: + return ("Invalid value for ai_flags"); + case EAI_FAIL: + return ("Non-recoverable failure in name resolution"); + case EAI_FAMILY: + return ("Address family not supported"); + case EAI_MEMORY: + return ("Memory allocation failure"); + case EAI_NODATA: + return ("No address associated with nodename"); + case EAI_NONAME: + return ("Node name nor service name provided, or not known"); + case EAI_SERVICE: + return ("Service name not supported for socket type"); + case EAI_SOCKTYPE: + return ("Socket type not supported"); + default: + return ("Unknown error"); + } +} + +/* exported as freeaddrinfo: standards? */ +extern "C" void +cygwin_freeaddrinfo (struct addrinfo *ai) +{ + freeaddrinfo(ai); +} + +/* exported as getnameinfo: standards? */ +extern "C" int +cygwin_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags) +{ + int g; + + g = getnameinfo (sa, salen, host, hostlen, serv, servlen, flags); + if (g) + { + set_winsock_errno (); + set_host_errno (); + } + else + { + debug_printf ("getnameinfo protocol family = %d\n", (struct sockaddr *)sa->sa_family); + h_errno = 0; + } + return g; +} + +#define CYGWIN_MAXHOSTNAMELEN 128 +#define CYGWIN_MAXALIASES 35 +#define CYGWIN_MAXADDRS 35 + +static struct hostent host; +static char host_name[CYGWIN_MAXHOSTNAMELEN]; +static char *host_aliases[CYGWIN_MAXALIASES]; +static char host_alias[CYGWIN_MAXHOSTNAMELEN]; + +static char *host_addrtbl[CYGWIN_MAXADDRS]; +static char host_addr[16 * CYGWIN_MAXADDRS]; + +/* exported as gethostbyname2: standards? */ +extern "C" struct hostent * +cygwin_gethostbyname2(const char * name, int af) +{ + struct addrinfo hints; + struct addrinfo * res; + struct addrinfo * res0; + int g; + int offset; + int i; + + if (af != AF_INET && af != AF_INET6) + { + set_errno(EAFNOSUPPORT); + h_errno = 0; + return NULL; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_flags = AI_CANONNAME; + g = getaddrinfo(name, NULL, &hints, &res0); + if (g) + { + set_winsock_errno (); + set_host_errno (); + return NULL; + } + + memset(&host, 0, sizeof(host)); + host.h_name = host_name; + host.h_aliases = host_aliases; + host.h_aliases[0] = host_alias; + host.h_addrtype = af; + host.h_addr_list = host_addrtbl; + + for (i = 0, offset = 0, res = res0; res && i < CYGWIN_MAXADDRS - 1; res = res->ai_next, i++) + { + if (i == 0) + { + strncpy(host_name, res->ai_canonname, CYGWIN_MAXHOSTNAMELEN - 1); + host_name[strlen(res->ai_canonname)] = '\0'; + /* */ + strncpy(host.h_aliases[0], name, CYGWIN_MAXHOSTNAMELEN - 1); + host.h_aliases[0][strlen(name)] = '\0'; + } + host.h_addr_list[i] = (char *)(host_addr + offset); + switch (af) + { + case AF_INET: + host.h_length = sizeof(struct in_addr); + offset += host.h_length; + memcpy(host.h_addr_list[i], + &((struct sockaddr_in *)(res->ai_addr))->sin_addr, host.h_length); + break; + case AF_INET6: + host.h_length = sizeof(struct in6_addr); + offset += host.h_length; + memcpy(host.h_addr_list[i], + &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr, host.h_length); + break; + default: + freeaddrinfo(res0); + set_errno(EAFNOSUPPORT); + h_errno = 0; + return NULL; + } + } + + host.h_addr_list[i] = NULL; + freeaddrinfo(res0); + h_errno = 0; + return &host; +} + /* endhostent: standards? */ extern "C" void endhostent (void) @@ -2179,6 +2363,28 @@ } return 0; } + else if (family == AF_INET6) + { + struct addrinfo hints; + struct addrinfo * res; + int g; + struct sockaddr_in6 * saddr6; + + memset (&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_flags = AI_NUMERICHOST; + g = getaddrinfo (strptr, NULL, &hints, &res); + if (g) + { + set_errno(g); + return 0; + } + saddr6 = (struct sockaddr_in6 *)res->ai_addr; + memcpy (addrptr, &saddr6->sin6_addr, sizeof(struct in6_addr)); + + freeaddrinfo (res); + return 1; + } set_errno (EAFNOSUPPORT); return -1; } @@ -2206,6 +2412,33 @@ strcpy (strptr, temp); return strptr; } + else if (family == AF_INET6) + { + char hname[NI_MAXHOST]; + int g; + struct sockaddr_in6 addr6; + struct sockaddr * paddr; + + memset (&addr6, 0, sizeof(addr6)); + addr6.sin6_family = AF_INET6; + memcpy (&addr6.sin6_addr, addrptr, sizeof(struct in6_addr)); + paddr = (struct sockaddr *)&addr6; + g = getnameinfo (paddr, sizeof(struct sockaddr_in6), + hname, sizeof(hname), NULL, 0, NI_NUMERICHOST); + if (g) + { + set_errno(g); + return NULL; + } + + if (strlen (hname) >= (size_t) len) + { + set_errno (ENOSPC); + return NULL; + } + strcpy (strptr, hname); + return strptr; + } set_errno (EAFNOSUPPORT); return NULL; } diff -aurN orig/cygwin-1.5.19-4/winsup/w32api/include/ws2tcpip.h cygwin-1.5.19-4/winsup/w32api/include/ws2tcpip.h --- orig/cygwin-1.5.19-4/winsup/w32api/include/ws2tcpip.h 2005-04-01 00:46:35.000000000 +0900 +++ cygwin-1.5.19-4/winsup/w32api/include/ws2tcpip.h 2006-01-22 11:06:11.834250000 +0900 @@ -283,6 +283,7 @@ }; typedef struct in6_pktinfo IN6_PKTINFO; +#if !(defined (__INSIDE_CYGWIN__) || (__INSIDE_MSYS__)) struct addrinfo { int ai_flags; int ai_family; @@ -293,6 +294,7 @@ struct sockaddr *ai_addr; struct addrinfo *ai_next; }; +#endif /* !(defined (__INSIDE_CYGWIN__) || (__INSIDE_MSYS__)) */ #if (_WIN32_WINNT >= 0x0501) void WSAAPI freeaddrinfo (struct addrinfo*); diff -aurN orig/cygwin-1.5.19-4/winsup/w32api/lib/wship6.def cygwin-1.5.19-4/winsup/w32api/lib/wship6.def --- orig/cygwin-1.5.19-4/winsup/w32api/lib/wship6.def 1970-01-01 09:00:00.000000000 +0900 +++ cygwin-1.5.19-4/winsup/w32api/lib/wship6.def 2006-01-22 11:06:11.849875000 +0900 @@ -0,0 +1,5 @@ +LIBRARY WSHIP6.DLL +EXPORTS +getaddrinfo@16 +freeaddrinfo@4 +getnameinfo@28 nuttcp-6.1.2/cygwin/gpl.txt0000664000222400001560000004313107741606704015426 0ustar robmusketeers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. nuttcp-6.1.2/cygwin/README0000664000222400001560000000047210701352532014747 0ustar robmusketeersThe cygwin library which is included in the zip'd binary distribution for windows is covered by the GNU Public License. As such, included here are the original sources to libcygwin, and the patches for ipv6, as well as a copy of the GPL. nuttcp itself is OpenSource(tm), and is licensed under the GPL Version 2