1 /*
2 * N U T T C P . C v8.2.2
3 *
4 * Copyright(c) 2000 - 2018 Bill Fink. All rights reserved.
5 * Copyright(c) 2003 - 2018 Rob Scott. All rights reserved.
6 *
7 * nuttcp is free, opensource software. You can redistribute it and/or
8 * modify it under the terms of Version 2 of the GNU General Public
9 * License (GPL), as published by the GNU Project (http://www.gnu.org).
10 * A copy of the license can also be found in the LICENSE file.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * Based on nttcp
18 * Developed by Bill Fink, billfink@mindspring.com
19 * and Rob Scott, rob@hpcmo.hpc.mil
20 * Latest version available at:
21 * http://nuttcp.net/nuttcp/beta/
22 *
23 * Test TCP connection. Makes a connection on port 5000(ctl)/5101(data)
24 * and transfers fabricated buffers or data copied from stdin.
25 *
26 * Run nuttcp with no arguments to get a usage statement
27 *
28 * Modified for operation under 4.2BSD, 18 Dec 84
29 * T.C. Slattery, USNA
30 * Minor improvements, Mike Muuss and Terry Slattery, 16-Oct-85.
31 *
32 * 8.2.2, Bill Fink, 5-Oct-18
33 * Improve warning when third party "-4/-6" is not supported
34 * Add af=inet/inet6 to verbose UDP output
35 * Add ip=<server_ip> to verbose UDP output for client transmitter
36 * 8.2.1, Bill Fink, 3-Oct-18
37 * Fix to pass "-4" or "-6" argument to 3rd party
38 * 8.1.4, Rob Scott, 1-Nov-16
39 * Fix to allow compile with -Werror=format-security as noted by Dhiru Kholia in fedora bug 1037224
40 * Fix missing brackets caught by -Wmisleading-indentation
41 * Add code to print out address family of connect/accept
42 * Add code to translate v4mapped addresses
43 * 8.1.3, Bill Fink, 9-Sep-16
44 * Fix to allow direct I/O on block devices
45 * Fix parsing of "-R i[s]##[/##]" (blank between 'R' and 'i')
46 * Updated Copyright notice for new year
47 * 8.1.2, Bill Fink, 5-Sep-16
48 * Fix to not exercise 8.0.1 and 8.1.1 features for non-Linux systems
49 * Changed nuttcp site to http://nuttcp.net/nuttcp/beta/
50 * Added define test for NOT_LINUX to undefine LINUX for build testing
51 * 8.1.1, Bill Fink, 31-Aug-16
52 * Add "-Ris##" option to emulate smoothed slow start behavior (Linux only)
53 * 8.0.1, Bill Fink, 22-Aug-16
54 * Add reporting of TCP congestion window
55 * 7.3.4, Rob Scott & Bill Fink, 18-Jul-16
56 * Use clock_gettime() on Windows/CYGWIN and Linux (if available)
57 * 7.3.3, Rob Scott, 1-May-15
58 * Fix tos to work for ipv6 by setting traffic class
59 * 7.3.2, Bill Fink, 3-Aug-14
60 * Allow longer server info timeout for third party via --idle-data-timeout
61 * 7.3.1, Bill Fink, 27-Jul-14
62 * Added feature to specify source port with "-p#:#" and "-P#:#"
63 * Updated Copyright notice for new year
64 * 7.2.2, Bill Fink, 25-May-13
65 * Fix Linux bug of exceeding MAX_EOT_WAIT_SEC on lossy large RTT path
66 * with large window causing false "Error: receiver not ACKing data"
67 * Change Linux method for draining socket send queue at EOT while waiting
68 * for any TCP retransmissions to complete - instead of checking
69 * tcpi_unacked value from TCP_INFO getsockopt() use SIOCOUTQ ioctl()
70 * (new error message is "Error: timeout while draining socket send queue")
71 * 7.2.1, Bill Fink, 26-Dec-12
72 * Add "-g" option to specify multicast IP address to use
73 * Clean up really confused transmit code for IPv4/IPv6 SSM multicast
74 * Bug fix from Aristeu Rozanski:
75 * Crash caused by closing TCP_ADV_WIN_SCALE file even if open failed
76 * 7.1.6, Bill Fink, 25-Feb-12
77 * Add "-sd" direct I/O option for non-sinkmode (Linux only)
78 * Fix bug with server CPU affinity being parsed as %X instead of %d
79 * For non-sinkmode insure complete network block is written to stdout
80 * Above fixes nuttscp bug seen with --copy-dir getting premature EOF
81 * Updated Copyright notice for new year
82 * Whitespace style cleanups
83 * 7.1.5, Rob Scott, 19-Jul-11
84 * Not every system has ERESTART added in 7.1.4, wrapped in ifdef
85 * 7.1.4, Bill Fink, 30-May-11
86 * Updated Copyright notice
87 * Use -DHAVE_SS_FAMILY to override _AIX workaround for newer AIX
88 * AIX can get ERESTART rather than EINTR/EAGAIN error on interrupted I/O
89 * Fix non-Linux systems to properly count TCP retrans for multiple streams
90 * Allow xinetd nuttcp server to handle both IPv4 & IPv6 if no explicitaf
91 * Detect EOD for non-sinkmode UDP transfers
92 * Suppress bogus warning when using maximum size UDP packet
93 * 7.1.3, Bill Fink, 1-Apr-10
94 * Fix compiler warnings generated by Ubuntu 9.x gcc 4.3.x/4.4.x versions
95 * (to see warnings compile with -DWANT_WUR)
96 * 7.1.2, Bill Fink, 23-Jan-10
97 * Updated Copyright notice
98 * Terminate non-sinkmode after specified file size with "-n" option
99 * Allow multilink aggregation with "-N##m" option to work for receive
100 * Add "-sz" zero copy option for non-sinkmode when input is a regular file
101 * Fix compiler warnings about strict-aliasing rules for variable group
102 * Remove "-Sf" forced server mode from Usage: statement
103 * Fix zeroing of clientaddr6 during server cleanup
104 * Fix freeaddrinfo() processing during cleanup
105 * Change manually started oneshot server to have parent process just exit
106 * Some minor whitespace cleanup
107 * 7.1.1, Bill Fink, 24-Dec-09
108 * Provide summary TCP retrans info for multi-stream TCP
109 * Fix bug with retrans interval info when -fparse
110 * Add "+stride" or "+n.n.n.n" syntax for multi-stream TCP (IPv4)
111 * Fix third party bug with "-xc" option adding extraneous 't' character
112 * Add optional client-side name resolution for third party host
113 * Add "-N##m" option for multilink aggregation for multiple streams
114 * Add "-xc#/#" and "-P#/#" options to Usage: statement
115 * Some minor whitespace cleanup
116 * 7.0.1, Bill Fink, 18-Sep-09
117 * Enable jitter measurements with "-j" option
118 * Enable one-way delay measurements with "-o" option
119 * Fix bug with RTT and -fparse
120 * 6.2.10, Bill Fink, 1-Aug-09
121 * Change ctl/data port checks to < 1024 instead of < 5000
122 * Fix "--idle-data-timeout" Usage: statement for new default minimum
123 * Improve transmit performance with "-i" by setting poll() timeout to 0
124 * Remove commented out code for unused normal_eod
125 * Don't output interval retrans info if non-sinkmode (for nuttscp)
126 * 6.2.9, Bill Fink, 24-Jun-09
127 * Make retrans info reporting work again on newer Linux distros
128 * Skip check for unACKed data at end of transfer if -DBROKEN_UNACKED
129 * 6.2.8, Bill Fink, 8-Jun-09
130 * Play nice with iperf (change default data port to 5101)
131 * Delay sending of server "OK" until after successful server bind()
132 * Client check for server errors before starting data transfer
133 * Continue checking for server output while draining client transmission
134 * Correct "server not ACKing data" error message (server -> receiver)
135 * Add "--packet-burst" option for Rob
136 * Fix "--idle-data-timeout" Usage: statement for client
137 * Improve accuracy of retrans info timing synchronization (client xmitter)
138 * Change reference to nuttcp repository from ftp:// to http://
139 * Fix bug affecting nuttscp introduced in 6.2.4 (not honoring oneshot)
140 * Whitespace cleanup: get rid of <tab><spaces><tab>, <tab>$, & <spaces>$
141 * Whitespace cleanup: convert 8 spaces to <tab> where appropriate
142 * 6.2.7, Bill Fink, 22-May-09
143 * Allow rate limit to be exceeded temporarily by n packets ("-Rixxx/n")
144 * Fix several reqval parameter settings
145 * 6.2.6, Bill Fink, 17-Apr-09
146 * Allow setting server CPU affinity from client via "-xcs" option
147 * Allow setting client & server CPU affinity via third party
148 * Fix bug with option processing when reqval is set
149 * 6.2.5, Bill Fink, 16-Apr-09
150 * Allow passing of third party control port via "-Pctlport/ctlport3"
151 * Up default idle data minimum to 15 sec to better handle net transients
152 * Don't reset nstream until after last use (fix getaddrinfo() memory leak)
153 * 6.2.4, Bill Fink, 10-Apr-09
154 * Fix bug with simultaneous server connections to manually started server
155 * 6.2.3, Bill Fink, 5-Apr-09
156 * Add "-xc" option to set CPU affinity (Linux only)
157 * Fix Usage: statement: "--idle-data-timeout" both server & client option
158 * Don't reset priority on server cleanup
159 * Fix priority output for "-fparse"
160 * 6.2.2, Bill Fink, 3-Apr-09
161 * Fix bad third party bug causing >= 1 minute transfers to silently fail
162 * Fix Usage: statement: "--idle-data-timeout" not just a server option
163 * 6.2.1, Rob Scott, 22-Mar-09
164 * Added IPv6 and SSM MC support
165 * Ported from Rob's 5.5.5 based code by Bill Fink
166 * 6.1.5, Bill Fink, 5-Mar-09
167 * Fix client lockup with third party when network problem (for scripts)
168 * 6.1.4, Bill Fink, 5-Jan-09
169 * Updated Copyright notice
170 * Bugfix: set chk_idle_data on client (now also checks no data received)
171 * Use argv[0] instead of "nuttcp" for third party
172 * Bugfix: give error message again on error starting server
173 * 6.1.3, Bill Fink, 17-Sep-08
174 * Timeout client accept() too and give nice error message (for scripts)
175 * 6.1.2, Bill Fink, 29-Aug-08
176 * Don't wait forever for unacked data at EOT (limit to 1 minute max)
177 * Extend no data received protection to client too (for scripts)
178 * Give nice error messages to client for above cases
179 * Don't hang getting server info if server exited (timeout reads)
180 * 6.1.1, Bill Fink, 26-Aug-08
181 * Remove beta designation
182 * Report RTT by default (use "-f-rtt" to suppress)
183 * Moved RTT info to "connect to" line
184 * Correct bogus IP frag warning for e.g. "-l1472" or "-l8972"
185 * Don't report interval host-retrans if no data rcvd (e.g. initial PMTU)
186 * Correct reporting of retrans info with "-fparse" option
187 * Correct reporting of RTT with "-F" flip option
188 * Report doubled send and receive window sizes (for Linux)
189 * Add report of available send and receive window sizes (for Linux)
190 * Touchup TODO list to remove some already completed items
191 * 6.0.7, Bill Fink, 19-Aug-08
192 * Add delay (default 0.5 sec) to "-a" option & change max retries to 10
193 * Updated Copyright notice
194 * 6.0.6, Bill Fink, 11-Aug-08
195 * Delay server forking until after listen() for better error status
196 * Above suggested by Hans Blom (jblom@science.uva.nl)
197 * Make forced server mode the default behavior
198 * Check address family on getpeername() so "ssh host nuttcp -S" works
199 * Add setsid() call for manually started server to create new session
200 * Some minor code cleanup
201 * 6.0.5, Bill Fink, 10-Aug-08
202 * Allow "-s" from/to stdin/stdout with "-1" oneshot server mode
203 * Switch beta vers message to stderr to not interfere with "-s" option
204 * Don't set default timeout if "-s" specified
205 * Give error message for "-s" with "-S" (xinetd or manually started)
206 * 6.0.4, Bill Fink, 18-Jul-08
207 * Forgot about 3rd party support for RTT info - fix that
208 * 6.0.3, Bill Fink, 17-Jul-08
209 * A better (and accurate) way to get RTT info (and not just Linux)
210 * 6.0.2, Bill Fink, 16-Jul-08
211 * Add RTT info to brief output for Linux
212 * 6.0.1, Bill Fink, 17-Dec-07
213 * Add reporting of TCP retransmissions (interval reports on Linux TX only)
214 * Add reporting of data transfer RTT for verbose Linux output
215 * Add beta version messages and "-f-beta" option to suppress
216 * Automatically switch "classic" mode to oneshot server mode
217 * Fix UDP loss info bug not updating stream_idx when not need_swap
218 * Fix compiler warning doing sprintf of timeout
219 * Correct comment on NODROPS define
220 * 5.5.5, Bill Fink, 1-Feb-07
221 * Change default MC addr to be based on client addr instead of xmit addr
222 * 5.5.4, Bill Fink, 3-Nov-06
223 * Fix bug with negative loss causing huge drop counts on interval reports
224 * Updated Copyright notice and added GPL license notice
225 * 5.5.3, Bill Fink, 23-Oct-06
226 * Fix bug with "-Ri" instantaneous rate limiting not working properly
227 * 5.5.2, Bill Fink, 25-Jul-06
228 * Make manually started server multi-threaded
229 * Add "--single-threaded" server option to restore old behavior
230 * Add "-a" client option to retry a failed server connection "again"
231 * (for certain possibly transient errors)
232 * 5.5.1, Bill Fink, 22-Jul-06
233 * Fix bugs with nbuf_bytes and rate_pps used with 3rd party
234 * Pass "-D" option to server (and also make work for third party)
235 * Allow setting precedence with "-c##p"
236 * 5.4.3, Rob Scott & Bill Fink, 17-Jul-06
237 * Fix bug with buflen passed to server when no buflen option speicified
238 * (revert 5.3.2: Fix bug with default UDP buflen for 3rd party)
239 * Better way to fix bug with default UDP buflen for 3rd party
240 * Trim trailing '\n' character from err() calls
241 * Use fcntl() to set O_NONBLOCK instead of MSG_DONTWAIT to send() ABORT
242 * (and remove MSG_DONTWAIT from recv() because it's not needed)
243 * Don't re-initialize buflen at completion of server processing
244 * (non inetd: is needed to check for buffer memory allocation change,
245 * caused bug if smaller "-l" followed by larger default "-l")
246 * 5.4.2, Bill Fink, 1-Jul-06
247 * Fix bug with interrupted UDP receive reporting negative packet loss
248 * Make sure errors (or debug) from server are propagated to the client
249 * Make setsockopt SO_SNDBUF/SO_RCVBUF error not be fatal to server
250 * Don't send stderr to client if nofork is set (manually started server)
251 * 5.4.1, Bill Fink, 30-Jun-06
252 * Fix bug with UDP reporting > linerate because of bad correction
253 * Send 2nd UDP BOD packet in case 1st is lost, e.g. waiting for ARP reply
254 * (makes UDP BOD more robust for new separate control and data paths)
255 * Fix bug with interval reports after EOD for UDP with small interval
256 * Don't just exit inetd server on no data so can get partial results
257 * (keep an eye out that servers don't start hanging again)
258 * Make default idle data timeout 1/2 of timeout if interval not set
259 * (with a minimum of 5 seconds and a maximum of 60 seconds)
260 * Make server send abort via urgent TCP data if no UDP data received
261 * (non-interval only: so client won't keep transmitting for full period)
262 * Workaround for Windows not handling TCP_MAXSEG getsockopt()
263 * 5.3.4, Bill Fink, 21-Jun-06
264 * Add "--idle-data-timeout" server option
265 * (server ends transfer if no data received for the specified
266 * timeout interval, previously it was a fixed 60 second timeout)
267 * Shutdown client control connection for writing at end of UDP transfer
268 * (so server can cope better with loss of all EOD packets, which is
269 * mostly of benefit when using separate control and data paths)
270 * 5.3.3, Bill Fink & Mark S. Mathews, 18-Jun-06
271 * Add new capability for separate control and data paths
272 * (using syntax: nuttcp ctl_name_or_IP/data_name_or_IP)
273 * Extend new capability for multiple independent data paths
274 * (using syntax: nuttcp ctl/data1/data2/.../datan)
275 * Above only supported for transmit or flipped/reversed receive
276 * Fix -Wall compiler warnings on 64-bit systems
277 * Make manually started server also pass stderr to client
278 * (so client will get warning messages from server)
279 * 5.3.2, Bill Fink, 09-Jun-06
280 * Fix bug with default UDP buflen for 3rd party
281 * Fix compiler warnings with -Wall on FreeBSD
282 * Give warning that windows doesn't support TCP_MAXSEG
283 * 5.3.1, Rob Scott, 06-Jun-06
284 * Add "-c" COS option for setting DSCP/TOS setting
285 * Fix builds on latest MacOS X
286 * Fix bug with 3rd party unlimited rate UDP not working
287 * Change "-M" option to require a value
288 * Fix compiler warnings with -Wall (thanks to Daniel J Blueman)
289 * Remove 'v' from nuttcp version (simplify RPM packaging)
290 * V5.2.2, Bill Fink, 13-May-06
291 * Have client report server warnings even if not verbose
292 * V5.2.1, Bill Fink, 12-May-06
293 * Pass "-M" option to server so it also works for receives
294 * Make "-uu" be a shortcut for "-u -Ru"
295 * V5.1.14, Bill Fink, 11-May-06
296 * Fix cancellation of UDP receives to work properly
297 * Allow easy building without IPv6 support
298 * Set default UDP buflen to largest 2^n less than MSS of ctlconn
299 * Add /usr/local/sbin and /usr/etc to path
300 * Allow specifying rate in pps by using 'p' suffix
301 * Give warning if actual send/receive window size is less than requested
302 * Make UDP transfers have a default rate limit of 1 Mbps
303 * Allow setting MSS for client transmitter TCP transfers with "-M" option
304 * Give more precision on reporting small UDP percentage data loss
305 * Disallow UDP transfers in "classic" mode
306 * Notify when using "classic" mode
307 * V5.1.13, Bill Fink, 8-Apr-06
308 * Make "-Ri" instantaneous rate limit for very high rates more accurate
309 * (including compensating for microsecond gettimeofday() granularity)
310 * Fix bug giving bogus time/stats on UDP transmit side with "-Ri"
311 * Allow fractional rate limits (for 'm' and 'g' only)
312 * V5.1.12, Bill Fink & Rob Scott, 4-Oct-05
313 * Terminate server receiver if client control connection goes away
314 * or if no data received from client within CHECK_CLIENT_INTERVAL
315 * V5.1.11, Rob Scott, 25-Jun-04
316 * Add support for scoped ipv6 addresses
317 * V5.1.10, Bill Fink, 16-Jun-04
318 * Allow 'b' suffix on "-w" option to specify window size in bytes
319 * V5.1.9, Bill Fink, 23-May-04
320 * Fix bug with client error on "-d" option putting server into bad state
321 * Set server accept timeout (currently 5 seconds) to prevent stuck server
322 * Add nuttcp version info to error message from err() exit
323 * V5.1.8, Bill Fink, 22-May-04
324 * Allow 'd|D' suffix to "-T" option to specify days
325 * Fix compiler warning about unused variable cp in getoptvalp routine
326 * Interval value check against timeout value should be >=
327 * V5.1.7, Bill Fink, 29-Apr-04
328 * Drop "-nb" option in favor of "-n###[k|m|g|t|p]"
329 * V5.1.6, Bill Fink, 25-Apr-04
330 * Fix bug with using interval option without timeout
331 * V5.1.5, Bill Fink, 23-Apr-04
332 * Modification to allow space between option parameter and its value
333 * Permit 'k' or 'm' suffix on "-l" option
334 * Add "-nb" option to specify number of bytes to transfer
335 * Permit 'k', 'm', 'g', 't', or 'p' suffix on "-n" and "-nb" options
336 * V5.1.4, Bill Fink, 21-Apr-04
337 * Change usage statement to use standard out instead of standard error
338 * Fix bug with interval > timeout, give warning and ignore interval
339 * Fix bug with counting error value in nbytes on interrupted transfers
340 * Fix bug with TCP transmitted & received nbytes not matching
341 * Merge "-t" and "-r" options in Usage: statement
342 * V5.1.3, Bill Fink, 9-Apr-04
343 * Add "-Sf" force server mode (useful for starting server via rsh/ssh)
344 * Allow non-root user to find nuttcp binary in "."
345 * Fix bug with receives terminating early with manual server mode
346 * Fix bug with UDP receives not terminating with "-Ri" option
347 * Clean up output formatting of nbuf (from "%d" to "%llu")
348 * Add "-SP" to have 3rd party use same outgoing control port as incoming
349 * V5.1.2, Bill Fink & Rob Scott, 18-Mar-04
350 * Fix bug with nbuf wrapping on really long transfers (int -> uint64_t)
351 * Fix multicast address to be unsigned long to allow shift
352 * Add MacOS uint8_t definition for new use of uint8_t
353 * V5.1.1, Bill Fink, 8-Nov-03
354 * Add IPv4 multicast support
355 * Delay receiver EOD until EOD1 (for out of order last data packet)
356 * Above also drains UDP receive buffer (wait for fragmentation reassembly)
357 * V5.0.4, Bill Fink, 6-Nov-03
358 * Fix bug reporting 0 drops when negative loss percentage
359 * V5.0.3, Bill Fink, 6-Nov-03
360 * Kill server transmission if control connection goes away
361 * Kill 3rd party nuttcp if control connection goes away
362 * V5.0.2, Bill Fink, 4-Nov-03
363 * Fix bug: some dummy wasn't big enough :-)
364 * V5.0.1, Bill Fink, 3-Nov-03
365 * Add third party support
366 * Correct usage statement for "-xt" traceroute option
367 * Improved error messages on failed options requiring client/server mode
368 * V4.1.1, David Lapsley and Bill Fink, 24-Oct-03
369 * Added "-fparse" format option to generate key=value parsable output
370 * Fix bug: need to open data connection on abortconn to clear listen
371 * V4.0.3, Rob Scott, 13-Oct-03
372 * Minor tweaks to output format for alignment
373 * Interval option "-i" with no explicit value sets interval to 1.0
374 * V4.0.2, Bill Fink, 10-Oct-03
375 * Changed "-xt" option to do both forward and reverse traceroute
376 * Changed to use brief output by default ("-v" for old default behavior)
377 * V4.0.1, Rob Scott, 10-Oct-03
378 * Added IPv6 code
379 * Changed inet get functions to protocol independent versions
380 * Added fakepoll for hosts without poll() (macosx)
381 * Added ifdefs to only include setprio if os supports it (non-win)
382 * Added bits to handle systems without new inet functions (solaris < 2.8)
383 * Removed SYSV obsolete code
384 * Added ifdefs and code to handle cygwin and beginning of windows support
385 * Window size can now be in meg (m|M) and gig (g|G)
386 * Added additional directories to search for traceroute
387 * Changed default to transmit, time limit of 10 seconds, no buffer limit
388 * Added (h|H) as option to specify time in hours
389 * Added getservbyname calls for port, if all fails use old defaults
390 * Changed sockaddr to sockaddr_storage to handle v6 addresses
391 * v3.7.1, Bill Fink, 10-Aug-03
392 * Add "-fdebugpoll" option to help debug polling for interval reporting
393 * Fix Solaris compiler warning
394 * Use poll instead of separate process for interval reports
395 * v3.6.2, Rob Scott, 18-Mar-03
396 * Allow setting server window to use default value
397 * Cleaned out BSD42 old code
398 * Marked SYSV code for future removal as it no longer appears necessary
399 * Also set RCVBUF/SNDBUF for udp transfers
400 * Changed transmit SO_DEBUG code to be like receive
401 * Some code rearrangement for setting options before accept/connect
402 * v3.6.1, Bill Fink, 1-Mar-03
403 * Add -xP nuttcp process priority option
404 * Add instantaneous rate limit capability ("-Ri")
405 * Don't open data connection if server error or doing traceroute
406 * Better cleanup on server connection error (close open data connections)
407 * Don't give normal nuttcp output if server error requiring abort
408 * Implement -xt traceroute option
409 * v3.5.1, Bill Fink, 27-Feb-03
410 * Don't allow flip option to be used with UDP
411 * Fix bug with UDP and transmit interval option (set stdin unbuffered)
412 * Fix start of UDP timing to be when get BOD
413 * Fix UDP timing when don't get first EOD
414 * Fix ident option used with interval option
415 * Add "-f-percentloss" option to not give %loss info on brief output
416 * Add "-f-drops" option to not give packet drop info on brief output
417 * Add packet drop info to UDP brief output (interval report and final)
418 * Add "-frunningtotal" option to give cumulative stats for "-i"
419 * Add "-fdebuginterval" option to help debug interval reporting
420 * Add "-fxmitstats" option to give transmitter stats
421 * Change flip option from "-f" to "-F"
422 * Fix divide by zero bug with "-i" option and very low rate limit
423 * Fix to allow compiling with Irix native compiler
424 * Fix by Rob Scott to allow compiling on MacOS X
425 * v3.4.5, Bill Fink, 29-Jan-03
426 * Fix client/server endian issues with UDP loss info for interval option
427 * v3.4.4, Bill Fink, 29-Jan-03
428 * Remove some debug printout for interval option
429 * Fix bug when using interval option reporting 0.000 MB on final
430 * v3.4.3, Bill Fink, 24-Jan-03
431 * Added UDP approximate loss info for interval reporting
432 * Changed nbytes and pbytes from double to uint64_t
433 * Changed SIGUSR1 to SIGTERM to kill sleeping child when done
434 * v3.4.2, Bill Fink, 15-Jan-03
435 * Make <control-C> work right with receive too
436 * v3.4.1, Bill Fink, 13-Jan-03
437 * Fix bug interacting with old servers
438 * Add "-f" flip option to reverse direction of data connection open
439 * Fix bug by disabling interval timer when server done
440 * v3.3.2, Bill Fink, 11-Jan-03
441 * Make "-i" option work for client transmit too
442 * Fix bug which forced "-i" option to be at least 0.1 seconds
443 * v3.3.1, Bill Fink, 7-Jan-03
444 * Added -i option to set interval timer (client receive only)
445 * Fixed server bug not setting socket address family
446 * v3.2.1, Bill Fink, 25-Feb-02
447 * Fixed bug so second <control-C> will definitely kill nuttcp
448 * Changed default control port to 5000 (instead of data port - 1)
449 * Modified -T option to accept fractional seconds
450 * v3.1.10, Bill Fink, 6-Feb-02
451 * Added -I option to identify nuttcp output
452 * Made server always verbose (filtering is done by client)
453 * Update to usage statement
454 * Minor fix to "-b" output when "-D" option is used
455 * Fix bug with "-s" that appends nuttcp output to receiver data file
456 * Fix bug with "-b" that gave bogus CPU utilization on > 1 hour transfers
457 * v3.1.9, Bill Fink, 21-Dec-01
458 * Fix bug with "-b" option on SGI systems reporting 0% CPU utilization
459 * v3.1.8, Bill Fink, 21-Dec-01
460 * Minor change to brief output format to make it simpler to awk
461 * v3.1.7, Bill Fink, 20-Dec-01
462 * Implement "-b" option for brief output (old "-b" -> "-wb")
463 * Report udp loss percentage when using client/server mode
464 * Fix bug with nbytes on transmitter using timed transfer
465 * Combined send/receive window size printout onto a single line
466 * v3.1.6, Bill Fink, 11-Jun-01
467 * Fixed minor bug reporting error connecting to inetd server
468 * Previously, Bill Fink, 7-Jun-01
469 * Added -h (usage) and -V (version) options
470 * Fixed SGI compilation warnings
471 * Added reporting server version to client
472 * Added version info and changed ttcp prints to nuttcp
473 * Fixed bug with inetd server and client using -r option
474 * Added ability to run server from inetd
475 * Added udp capability to server option
476 * Added -T option to set timeout interval
477 * Added -ws option to set server window
478 * Added -S option to support running receiver as daemon
479 * Allow setting UDP buflen up to MAXUDPBUFLEN
480 * Provide -b option for braindead Solaris 2.8
481 * Added printing of transmit rate limit
482 * Added -w option to usage statement
483 * Added -N option to support multiple streams
484 * Added -R transmit rate limit option
485 * Fix setting of destination IP address on 64-bit Irix systems
486 * Only set window size in appropriate direction to save memory
487 * Fix throughput calculation for large transfers (>= 2 GB)
488 * Fix reporting of Mb/s to give actual millions of bits per second
489 * Fix setting of INET address family in local socket
490 * Fix setting of receiver window size
491 *
492 * TODO/Wish-List:
493 * Transmit interval marking option
494 * Allow at least some traceroute options
495 * Add "-ut" option to do both UDP and TCP simultaneously
496 * Default rate limit UDP if too much loss
497 * Ping option
498 * Other brief output formats
499 * Linux window size bug/feature note
500 * Network interface interrupts (for Linux only)
501 * netstat -i info
502 * Man page
503 * Forking for multiple streams
504 * Bidirectional option
505 * Graphical interface
506 * MTU info
507 * Warning for window size limiting throughput
508 * Auto window size optimization
509 * Transmitter profile and playback options
510 * Server side limitations (per client host/network)
511 * Server side logging
512 * Client/server security (password)
513 * nuttcp server registration
514 * nuttcp proxy support (firewalls)
515 * nuttcp network idle time
516 *
517 * Distribution Status -
518 * OpenSource(tm)
519 * Licensed under version 2 of the GNU GPL
520 * Please send source modifications back to the authors
521 * Derivative works should be redistributed with a modified
522 * source and executable name
523 */
524
525 /*
526 #ifndef lint
527 static char RCSid[] = "@(#)$Revision: 1.2 $ (BRL)";
528 #endif
529 */
530
531 #ifdef NOT_LINUX
532 #undef linux
533 #endif
534
535 #ifndef WANT_WUR
536 #undef _FORTIFY_SOURCE
537 #else
538 #define _FORTIFY_SOURCE 2
539 #endif
540
541 #define _FILE_OFFSET_BITS 64
542
543 #if defined(linux)
544 #define _GNU_SOURCE
545 #endif
546
547 #include <stdio.h>
548 #include <signal.h>
549 #include <ctype.h>
550 #include <errno.h>
551 #include <sys/types.h>
552 #include <sys/time.h> /* struct timeval */
553 #include <stdlib.h>
554
555 #ifndef _WIN32
556 #include <sys/socket.h>
557 #include <netinet/in.h>
558 #include <netinet/tcp.h>
559 #include <arpa/inet.h>
560 #include <netdb.h>
561 #include <sys/resource.h>
562 #else
563 #include "win32nuttcp.h" /* from win32 */
564 #endif /* _WIN32 */
565
566 #include <limits.h>
567 #include <string.h>
568 #include <fcntl.h>
569
570 #if defined(linux)
571 #include <sys/stat.h>
572 #include <sys/sendfile.h>
573 #include <sys/ioctl.h>
574 #include <linux/sockios.h>
575 #endif
576
577 /* Let's try changing the previous unwieldy check */
578 /* #if defined(linux) || defined(__FreeBSD__) || defined (sgi) || (defined(__MACH__) && defined(_SOCKLEN_T)) || defined(sparc) || defined(__CYGWIN__) */
579 /* to the following (hopefully equivalent) simpler form like we use
580 * for HAVE_POLL */
581 #if !defined(_WIN32) && (!defined(__MACH__) || defined(_SOCKLEN_T))
582 #include <unistd.h>
583 #include <sys/wait.h>
584 #include <strings.h>
585 #endif
586
587 #ifndef USE_GETTIMEOFDAY
588 #ifndef HAVE_CLOCK_GETTIME
589 #if (defined(linux) && defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 17)) || defined(__CYGWIN__)
590 #define HAVE_CLOCK_GETTIME
591 #endif
592 #endif
593 #endif
594
595 #ifdef HAVE_CLOCK_GETTIME
596 #include <time.h> /* clock_gettime */
597 #endif
598
599 #ifndef ULLONG_MAX
600 #define ULLONG_MAX 18446744073709551615ULL
601 #endif
602
603 #define MAXRATE 0xffffffffUL
604
605 #if !defined(__CYGWIN__) && !defined(_WIN32)
606 #define HAVE_SETPRIO
607 #endif
608
609 #if defined(linux)
610 #define HAVE_SETAFFINITY
611 #endif
612
613 #if !defined(_WIN32) && (!defined(__MACH__) || defined(_SOCKLEN_T))
614 #define HAVE_POLL
615 #endif
616
617 #if defined(__APPLE__) && defined(__MACH__)
618 #define uint64_t u_int64_t
619 #define uint32_t u_int32_t
620 #define uint16_t u_int16_t
621 #define uint8_t u_int8_t
622 #endif
623
624 #ifdef HAVE_POLL
625 #include <sys/poll.h>
626 #else
627 #include "fakepoll.h" /* from missing */
628 #endif
629
630 #ifdef HAVE_SETAFFINITY
631 #include <sched.h>
632 #endif
633
634 #ifndef CPU_SETSIZE
635 #undef HAVE_SETAFFINITY
636 #endif
637
638 /*
639 * _SOCKLEN_T is now defined by apple when they typedef socklen_t
640 *
641 * EAI_NONAME has nothing to do with socklen, but on sparc without it tells
642 * us it's an old enough solaris to need the typedef
643 */
644 #if (defined(__APPLE__) && defined(__MACH__)) && !defined(_SOCKLEN_T) || (defined(sparc) && !defined(EAI_NONAME))
645 typedef int socklen_t;
646 #endif
647
648 #if defined(sparc) && !defined(EAI_NONAME) /* old sparc */
649 #define sockaddr_storage sockaddr
650 #define ss_family sa_family
651 #endif /* old sparc */
652
653 #if defined(_AIX) && !defined(HAVE_SS_FAMILY)
654 #define ss_family __ss_family
655 #endif
656
657 #if !defined(EAI_NONAME)
658 #include "addrinfo.h" /* from missing */
659 #endif
660
661 /*
662 * The following macro is from openssh defines.h by Tatu Ylonen and marked "can be used freely for any purpose"
663 */
664 #if !defined(IN6_IS_ADDR_V4MAPPED)
665 #define IN6_IS_ADDR_V4MAPPED(a) \
666 ((*(const __uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
667 (*(const __uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
668 (*(const __uint32_t *)(const void *)(&(a)->s6_addr[8]) == \
669 ntohl(0x0000ffff)))
670 #endif /* !defined(IN6_IS_ADDR_V4MAPPED) */
671
672 #define BETA_STR "-beta8"
673 #define BETA_FEATURES "jitter/owd"
674
675 union sockaddr_union {
676 struct sockaddr_storage ss;
677 struct sockaddr_in sin;
678 struct sockaddr_in6 sin6;
679 };
680
681 static struct timeval time0; /* Time at which timing started */
682 static struct timeval timepk; /* Time at which last packet sent */
683 static struct timeval timepkr; /* Time at which last packet received */
684 static struct timeval timepkri; /* timepkr for interval reports */
685 static struct timeval timep; /* Previous time - for interval reporting */
686 static struct timeval timetx; /* Transmitter timestamp */
687 static struct timeval timerx; /* Receive timestamp */
688 static struct rusage ru0; /* Resource utilization at the start */
689
690 static struct sigaction sigact; /* signal handler for alarm */
691 static struct sigaction savesigact;
692
693 #define PERF_FMT_OUT "%.4f MB in %.2f real seconds = %.2f KB/sec" \
694 " = %.4f Mbps\n"
695 #define PERF_FMT_BRIEF "%10.4f MB / %6.2f sec = %9.4f Mbps %d %%TX %d %%RX"
696 #define PERF_FMT_BRIEF2 "%10.4f MB / %6.2f sec = %9.4f Mbps %d %%%s"
697 #define PERF_FMT_BRIEF3 " Trans: %.4f MB"
698 #define PERF_FMT_INTERVAL "%10.4f MB / %6.2f sec = %9.4f Mbps"
699 #define PERF_FMT_INTERVAL2 " Tot: %10.4f MB / %6.2f sec = %9.4f Mbps"
700 #define PERF_FMT_INTERVAL3 " Trans: %10.4f MB"
701 #define PERF_FMT_INTERVAL4 " Tot: %10.4f MB"
702 #define PERF_FMT_IN "%lf MB in %lf real seconds = %lf KB/sec = %lf Mbps\n"
703 #define CPU_STATS_FMT_IN "%*fuser %*fsys %*d:%*dreal %d%%"
704 #define CPU_STATS_FMT_IN2 "%*fuser %*fsys %*d:%*d:%*dreal %d%%"
705
706 #define LOSS_FMT " %.2f%% data loss"
707 #define LOSS_FMT_BRIEF " %.2f %%loss"
708 #define LOSS_FMT_INTERVAL " %5.2f ~%%loss"
709 #define LOSS_FMT5 " %.5f%% data loss"
710 #define LOSS_FMT_BRIEF5 " %.5f %%loss"
711 #define LOSS_FMT_INTERVAL5 " %7.5f ~%%loss"
712 #define DROP_FMT " %lld / %lld drop/pkt"
713 #define DROP_FMT_BRIEF " %lld / %lld drop/pkt"
714 #define DROP_FMT_INTERVAL " %5lld / %5lld ~drop/pkt"
715 #define JITTER_MIN 1
716 #define JITTER_AVG 2
717 #define JITTER_MAX 4
718 #define JITTER_IGNORE_OOO 8
719 #define JITTER_FMT "min-jitter = %.4f ms, avg-jitter = %.4f ms, " \
720 "max-jitter = %.4f ms"
721 #define JITTER_MIN_FMT_BRIEF " %.4f msMinJitter"
722 #define JITTER_AVG_FMT_BRIEF " %.4f msAvgJitter"
723 #define JITTER_MAX_FMT_BRIEF " %.4f msMaxJitter"
724 #define JITTER_MIN_FMT_INTERVAL " %.4f msMinJitter"
725 #define JITTER_AVG_FMT_INTERVAL " %.4f msAvgJitter"
726 #define JITTER_MAX_FMT_INTERVAL " %.4f msMaxJitter"
727 #define JITTER_FMT_IN "jitter = %lf ms, avg-jitter = %lf ms, " \
728 "max-jitter = %lf ms"
729 #define OWD_MIN 1
730 #define OWD_AVG 2
731 #define OWD_MAX 4
732 #define OWD_FMT "min-OWD = %.4f ms, avg-OWD = %.4f ms, " \
733 "max-OWD = %.4f ms"
734 #define OWD_MIN_FMT_BRIEF " %.4f msMinOWD"
735 #define OWD_AVG_FMT_BRIEF " %.4f msAvgOWD"
736 #define OWD_MAX_FMT_BRIEF " %.4f msMaxOWD"
737 #define OWD_MIN_FMT_INTERVAL " %.4f msMinOWD"
738 #define OWD_AVG_FMT_INTERVAL " %.4f msAvgOWD"
739 #define OWD_MAX_FMT_INTERVAL " %.4f msMaxOWD"
740 #define OWD_FMT_IN "OWD = %lf ms, avg-OWD = %lf ms, max-OWD = %lf ms"
741 #define RETRANS_FMT "%sretrans = %d"
742 #define RETRANS_FMT_BRIEF " %d %sretrans"
743 #define RETRANS_FMT_BRIEF_STR1 " %d = %d"
744 #define RETRANS_FMT_BRIEF_STR2 " retrans"
745 #define RETRANS_FMT_INTERVAL " %5d %sretrans"
746 #define RETRANS_FMT_IN "retrans = %d"
747 #define CWND_FMT " cwnd = %d KB"
748 #define CWND_FMT_BRIEF " %d KB-cwnd"
749 #define CWND_FMT_BRIEF_STR1 " %d = %d"
750 #define CWND_FMT_BRIEF_STR2 " KB-cwnd"
751 #define CWND_FMT_INTERVAL " %6d KB-cwnd"
752 #define CWND_FMT_IN "cwnd = %d"
753 #define RTT_FMT " RTT=%.3f ms"
754 #define RTT_FMT_BRIEF " %.2f msRTT"
755 #define RTT_FMT_IN "RTT=%lf"
756 #define RTT_FMT_INB "RTT = %lf"
757 #define SIZEOF_TCP_INFO_RETRANS 104
758
759 /* define NEW_TCP_INFO if struct tcp_info in /usr/include/netinet/tcp.h
760 * contains tcpi_total_retrans member
761 *
762 * tcpi_rcv_rtt, tcpi_rcv_space, & tcpi_total_retrans were added
763 * in glibc-headers-2.7 (Fedora 8) which fortunately also defined
764 * TCP_MD5SIG at the same time, so key off of that
765 */
766 #if defined(linux) && defined(TCP_MD5SIG)
767 #define NEW_TCP_INFO
768 #endif
769
770 #ifndef NEW_TCP_INFO
771 #define OLD_TCP_INFO
772 #endif
773
774 /* Parsable output formats */
775
776 #define P_PERF_FMT_OUT "megabytes=%.4f real_seconds=%.2f " \
777 "rate_KBps=%.2f rate_Mbps=%.4f\n"
778 #define P_PERF_FMT_BRIEF "megabytes=%.4f real_seconds=%.2f rate_Mbps=%.4f " \
779 "tx_cpu=%d rx_cpu=%d"
780 #define P_PERF_FMT_BRIEF3 " tx_megabytes=%.4f"
781 #define P_PERF_FMT_INTERVAL "megabytes=%.4f real_sec=%.2f rate_Mbps=%.4f"
782 #define P_PERF_FMT_INTERVAL2 " total_megabytes=%.4f total_real_sec=%.2f" \
783 " total_rate_Mbps=%.4f"
784 #define P_PERF_FMT_INTERVAL3 " tx_megabytes=%.4f"
785 #define P_PERF_FMT_INTERVAL4 " tx_total_megabytes=%.4f"
786 #define P_PERF_FMT_IN "megabytes=%lf real_seconds=%lf rate_KBps=%lf " \
787 "rate_Mbps=%lf\n"
788 #define P_CPU_STATS_FMT_IN "user=%*f system=%*f elapsed=%*d:%*d cpu=%d%%"
789 #define P_CPU_STATS_FMT_IN2 "user=%*f system=%*f elapsed=%*d:%*d:%*d cpu=%d%%"
790
791 #define P_LOSS_FMT " data_loss=%.5f"
792 #define P_LOSS_FMT_BRIEF " data_loss=%.5f"
793 #define P_LOSS_FMT_INTERVAL " data_loss=%.5f"
794 #define P_DROP_FMT " drop=%lld pkt=%lld"
795 #define P_DROP_FMT_BRIEF " drop=%lld pkt=%lld"
796 #define P_DROP_FMT_INTERVAL " drop=%lld pkt=%lld"
797 #define P_JITTER_FMT "msminjitter=%.4f msavgjitter=%.4f " \
798 "msmaxjitter=%.4f"
799 #define P_JITTER_MIN_FMT_BRIEF " msminjitter=%.4f"
800 #define P_JITTER_AVG_FMT_BRIEF " msavgjitter=%.4f"
801 #define P_JITTER_MAX_FMT_BRIEF " msmaxjitter=%.4f"
802 #define P_JITTER_MIN_FMT_INTERVAL " msminjitter=%.4f"
803 #define P_JITTER_AVG_FMT_INTERVAL " msavgjitter=%.4f"
804 #define P_JITTER_MAX_FMT_INTERVAL " msmaxjitter=%.4f"
805 #define P_JITTER_FMT_IN "jitter=%lf msavgjitter=%lf msmaxjitter=%lf"
806 #define P_OWD_FMT "msminOWD=%.4f msavgOWD=%.4f msmaxOWD=%.4f"
807 #define P_OWD_MIN_FMT_BRIEF " msminOWD=%.4f"
808 #define P_OWD_AVG_FMT_BRIEF " msavgOWD=%.4f"
809 #define P_OWD_MAX_FMT_BRIEF " msmaxOWD=%.4f"
810 #define P_OWD_MIN_FMT_INTERVAL " msminOWD=%.4f"
811 #define P_OWD_AVG_FMT_INTERVAL " msavgOWD=%.4f"
812 #define P_OWD_MAX_FMT_INTERVAL " msmaxOWD=%.4f"
813 #define P_OWD_FMT_IN "OWD=%lf msavgOWD=%lf msmaxOWD=%lf"
814 #define P_RETRANS_FMT "%sretrans=%d"
815 #define P_RETRANS_FMT_STREAMS " retrans_by_stream=%d"
816 #define P_RETRANS_FMT_BRIEF " %sretrans=%d"
817 #define P_RETRANS_FMT_INTERVAL " %sretrans=%d"
818 #define P_RETRANS_FMT_IN "retrans=%d"
819 #define P_CWND_FMT " cwnd=%d"
820 #define P_CWND_FMT_STREAMS " cwnd_by_stream=%d"
821 #define P_CWND_FMT_BRIEF " cwnd=%d"
822 #define P_CWND_FMT_INTERVAL " cwnd=%d"
823 #define P_CWND_FMT_IN "cwnd=%d"
824 #define P_RTT_FMT " rtt_ms=%.3f"
825 #define P_RTT_FMT_BRIEF " rtt_ms=%.2f"
826 #define P_RTT_FMT_IN "rtt_ms=%lf"
827
828 #define HELO_FMT "HELO nuttcp v%d.%d.%d\n"
829
830 #ifndef MAXSTREAM
831 #define MAXSTREAM 128
832 #endif
833 #define DEFAULT_NBUF 2048
834 #define DEFAULT_NBYTES 134217728 /* 128 MB */
835 #define DEFAULT_TIMEOUT 10.0
836 #define DEFAULT_UDP_RATE 1000
837 #define DEFAULTUDPBUFLEN 8192
838 #define DEFAULT_MC_UDPBUFLEN 1024
839 #define MAXUDPBUFLEN 65507
840 #define LOW_RATE_HOST3 1000
841 #define MINMALLOC 1024
842 #define HI_MC 231ul
843 #define HI_MC_SSM 232ul
844 /* locally defined global scope IPv6 multicast, FF3E::8000:0-FF3E::FFFF:FFFF */
845 #define HI_MC6 "FF3E::8000:0000"
846 #define HI_MC6_LEN 13
847 #define HI_MC6_ASM "FF2E::0"
848 #define HI_MC6_ASM_LEN 8
849 #ifndef LISTEN_BACKLOG
850 #define LISTEN_BACKLOG 64
851 #endif
852 #define ACCEPT_TIMEOUT 5
853 #ifndef MAX_CONNECT_TRIES
854 #define MAX_CONNECT_TRIES 10 /* maximum server connect attempts */
855 #endif
856 #ifndef SERVER_RETRY_USEC
857 #define SERVER_RETRY_USEC 500000 /* server retry time in usec */
858 #endif
859 #define MAX_EOT_WAIT_SEC 60.0 /* max wait for unsent data at EOT */
860 #define SRVR_INFO_TIMEOUT 60 /* timeout for reading server info */
861 #define IDLE_DATA_MIN 15.0 /* minimum value for chk_idle_data */
862 #define DEFAULT_IDLE_DATA 30.0 /* default value for chk_idle_data */
863 #define IDLE_DATA_MAX 60.0 /* maximum value for chk_idle_data */
864 #define NON_JUMBO_ETHER_MSS 1448 /* 1500 - 20:IP - 20:TCP -12:TCPOPTS */
865 #define TCP_UDP_HDRLEN_DELTA 12 /* difference in tcp & udp hdr sizes */
866 #define TCP_TIMESTAMPS_OPTLEN 12 /* size of TCP timestamps options */
867
868 #if defined(linux)
869 #define TCP_ADV_WIN_SCALE "/proc/sys/net/ipv4/tcp_adv_win_scale"
870 #endif
871
872 #define DEBUGOUTPUT "/tmp/nuttcp-debugout.foo"
873
874 #define BRIEF_RETRANS_STREAMS 0x2 /* brief per stream retrans info */
875 #define BRIEF_CWND_STREAMS 0x4 /* brief per stream cwnd info */
876
877 #define XMITSTATS 0x1 /* also give transmitter stats (MB) */
878 #define DEBUGINTERVAL 0x2 /* add info to assist with
879 * debugging interval reports */
880 #define RUNNINGTOTAL 0x4 /* give cumulative stats for "-i" */
881 #define NODROPS 0x8 /* no packet drop stats for "-i" */
882 #define NOPERCENTLOSS 0x10 /* don't give percent loss for "-i" */
883 #define DEBUGPOLL 0x20 /* add info to assist with debugging
884 * polling for interval reports */
885 #define PARSE 0x40 /* generate key=value parsable output */
886 #define DEBUGMTU 0x80 /* debug info for MTU/MSS code */
887 #define NORETRANS 0x100 /* no retrans stats for "-i" */
888 #define DEBUGRETRANS 0x200 /* output info for debugging collection
889 * of TCP retransmission info */
890 #define NOBETAMSG 0x400 /* suppress beta version message */
891 #define WANTRTT 0x800 /* output RTT info (default) */
892 #define DEBUGJITTER 0x1000 /* debugging info for jitter option */
893 #define NOCWND 0x2000 /* no cwnd stats for "-i" */
894 #define DEBUGIRATE 0x4000 /* debugging info for irate option */
895
896 #ifdef NO_IPV6 /* Build without IPv6 support */
897 #undef AF_INET6
898 #undef IPV6_V6ONLY
899 #endif
900
901 void sigpipe( int signum );
902 void sigint( int signum );
903 void ignore_alarm( int signum );
904 void sigalarm( int signum );
905 static void err( char *s );
906 static void mes( char *s );
907 static void errmes( char *s );
908 void pattern( char *cp, int cnt );
909 void get_timeofday( struct timeval *tv, struct timezone *tz );
910 void prep_timer();
911 double read_timer( char *str, int len );
912 static void prusage( struct rusage *r0, struct rusage *r1, struct timeval *e, struct timeval *b, char *outp );
913 static void tvadd( struct timeval *tsum, struct timeval *t0, struct timeval *t1 );
914 static void tvsub( struct timeval *tdiff, struct timeval *t1, struct timeval *t0 );
915 static void psecs( long l, char *cp );
916 int Nread( int fd, char *buf, int count );
917 int Nwrite( int fd, char *buf, int count );
918 int delay( int us );
919 int mread( int fd, char *bufp, unsigned n );
920 int mwrite( int fd, char *bufp, unsigned n, int last_write );
921 char *getoptvalp( char **argv, int index, int reqval, int *skiparg );
922
923 #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS)
924 void print_tcpinfo();
925 #endif
926
927 int vers_major = 8;
928 int vers_minor = 2;
929 int vers_delta = 2;
930 int ivers;
931 int rvers_major = 0;
932 int rvers_minor = 0;
933 int rvers_delta = 0;
934 int irvers;
935 int beta = 0;
936
937 struct sockaddr_in sinme[MAXSTREAM + 1];
938 struct sockaddr_in sinhim[MAXSTREAM + 1];
939 struct sockaddr_in save_sinhim, save_mc;
940
941 #ifdef AF_INET6
942 struct sockaddr_in6 sinme6[MAXSTREAM + 1];
943 struct sockaddr_in6 sinhim6[MAXSTREAM + 1];
944 struct sockaddr_in6 save_sinhim6, save_mc6;
945 struct in6_addr hi_mc6, hi_mc6_asm;
946 #endif
947
948 struct sockaddr_storage frominet;
949
950 int domain = PF_UNSPEC;
951 int af = AF_UNSPEC;
952 int mc_af = AF_UNSPEC;
953 int explicitaf = 0; /* address family explicit specified (-4|-6) */
954 int fd[MAXSTREAM + 1]; /* fd array of network sockets */
955 int nfd; /* fd for accept call */
956 struct pollfd pollfds[MAXSTREAM + 4]; /* used for reading interval reports */
957 socklen_t fromlen;
958
959 int buflen = 64 * 1024; /* length of buffer */
960 int nbuflen;
961 int mallocsize;
962 char *buf; /* ptr to dynamic buffer */
963 unsigned long long nbuf = 0; /* number of buffers to send in sinkmode */
964 int nbuf_bytes = 0; /* set to 1 if nbuf is actually bytes */
965
966 /* nick code */
967 int sendwin=0, sendwinval=0, origsendwin=0;
968 socklen_t optlen;
969 int rcvwin=0, rcvwinval=0, origrcvwin=0;
970 int srvrwin=0;
971 /* end nick code */
972
973 #if defined(linux)
974 int sendwinavail=0, rcvwinavail=0, winadjust=0;
975 #endif
976
977 #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS)
978 #ifdef OLD_TCP_INFO
979 #define STRUCT_TCPINFO tcpinfo
980 struct tcpinfo { /* for collecting TCP retransmission info */
981 struct tcp_info _tcpinf;
982 /* add missing structure elements */
983 u_int32_t tcpi_rcv_rtt;
984 u_int32_t tcpi_rcv_space;
985 u_int32_t tcpi_total_retrans;
986 } tcpinf;
987 #define tcpinfo_state _tcpinf.tcpi_state
988 #define tcpinfo_ca_state _tcpinf.tcpi_ca_state
989 #define tcpinfo_retransmits _tcpinf.tcpi_retransmits
990 #define tcpinfo_unacked _tcpinf.tcpi_unacked
991 #define tcpinfo_sacked _tcpinf.tcpi_sacked
992 #define tcpinfo_lost _tcpinf.tcpi_lost
993 #define tcpinfo_retrans _tcpinf.tcpi_retrans
994 #define tcpinfo_fackets _tcpinf.tcpi_fackets
995 #define tcpinfo_rtt _tcpinf.tcpi_rtt
996 #define tcpinfo_rttvar _tcpinf.tcpi_rttvar
997 #define tcpinfo_snd_ssthresh _tcpinf.tcpi_snd_ssthresh
998 #define tcpinfo_snd_cwnd _tcpinf.tcpi_snd_cwnd
999 #else
1000 #define STRUCT_TCPINFO tcp_info
1001 struct tcp_info tcpinf;
1002 #define tcpinfo_state tcpi_state
1003 #define tcpinfo_ca_state tcpi_ca_state
1004 #define tcpinfo_retransmits tcpi_retransmits
1005 #define tcpinfo_unacked tcpi_unacked
1006 #define tcpinfo_sacked tcpi_sacked
1007 #define tcpinfo_lost tcpi_lost
1008 #define tcpinfo_retrans tcpi_retrans
1009 #define tcpinfo_fackets tcpi_fackets
1010 #define tcpinfo_rtt tcpi_rtt
1011 #define tcpinfo_rttvar tcpi_rttvar
1012 #define tcpinfo_snd_ssthresh tcpi_snd_ssthresh
1013 #define tcpinfo_snd_cwnd tcpi_snd_cwnd
1014 #endif
1015 #else
1016 #define STRUCT_TCPINFO dummy_tcp_info
1017 struct dummy_tcp_info {
1018 int dummy1;
1019 } tcpinf;
1020 #endif
1021
1022 int get_retrans( int sockfd, struct STRUCT_TCPINFO *tcpinfo );
1023
1024 int udp = 0; /* 0 = tcp, !0 = udp */
1025 int udplossinfo = 0; /* set to 1 to give UDP loss info for
1026 * interval reporting */
1027 int do_jitter = 0; /* set to 1 to enable jitter measurements */
1028 int do_owd = 0; /* set to 1 to enable one-way delay reports */
1029
1030 int retransinfo = 0; /* set to 1 to give TCP retransmission info
1031 * for interval reporting */
1032 int force_retrans = 0; /* set to force sending retrans info */
1033 int send_retrans = 1; /* set to 0 if no need to send retrans info */
1034 int do_retrans = 0; /* set to 1 for client transmitter */
1035 int read_retrans = 1; /* set to 0 if no need to read retrans info */
1036 int got_0retrans = 0; /* set to 1 by client transmitter after
1037 * processing initial server output
1038 * having "0 retrans" */
1039
1040 int init_pkt_cwnd = 0; /* initial congestion window in packets */
1041 int sss_pkt_cwnd = 0; /* smoothed slow start congestion window */
1042 int cwndinfo = 0; /* set to 1 to give TCP congestion window info
1043 * for interval reporting */
1044 int send_cwnd = 1; /* set to 0 if no need to send cwnd info */
1045 int do_cwnd = 0; /* set to 1 for client transmitter */
1046 int read_cwnd = 1; /* set to 0 if no need to read cwnd info */
1047
1048 int need_swap; /* client and server are different endian */
1049 int options = 0; /* socket options */
1050 int one = 1; /* for 4.3 BSD style setsockopt() */
1051 /* default port numbers if command arg or getserv doesn't get a port # */
1052 #define DEFAULT_PORT 5101
1053 #define DEFAULT_CTLPORT 5000
1054 #define IPERF_PORT 5001
1055 unsigned short port = 0; /* TCP port number */
1056 unsigned short srcport = 0; /* TCP source port */
1057 unsigned short ctlport = 0; /* control port for server connection */
1058 unsigned short srcctlport = 0; /* TCP source port for server connection */
1059 unsigned short ctlport3 = 0; /* control port for 3rd party server conn */
1060 int tmpport;
1061 char *host; /* ptr to name of host */
1062 char *stride = NULL; /* ptr to address stride for multi-stream */
1063 char *host3 = NULL; /* ptr to 3rd party host */
1064 int thirdparty = 0; /* set to 1 indicates doing 3rd party nuttcp */
1065 int no3rd = 0; /* set to 1 by server to disallow 3rd party */
1066 int forked = 0; /* set to 1 after server has forked */
1067 int pass_ctlport = 0; /* set to 1 to use same outgoing control port
1068 as incoming with 3rd party usage */
1069 char *nut_cmd; /* command used to invoke nuttcp */
1070 char *cmdargs[50]; /* command arguments array */
1071 char tmpargs[50][50];
1072
1073 #ifndef AF_INET6
1074 #define ADDRSTRLEN 16
1075 #else
1076 #define ADDRSTRLEN INET6_ADDRSTRLEN
1077 int v4mapped = 0; /* set to 1 to enable v4 mapping in v6 server */
1078 #endif
1079
1080 #define HOSTNAMELEN 80
1081 #define HOST3BUFLEN HOSTNAMELEN + 2 + ADDRSTRLEN + 1 + ADDRSTRLEN
1082 /* host3=[=]host3addr[+host3stride] */
1083
1084 char hostbuf[ADDRSTRLEN]; /* buffer to hold text of address */
1085 char host3addr[ADDRSTRLEN]; /* buffer to hold text of 3rd party address */
1086 char host3buf[HOST3BUFLEN + 1]; /* buffer to hold 3rd party name or address */
1087 char clientbuf[NI_MAXHOST]; /* buffer to hold client's resolved hostname */
1088 int trans = 1; /* 0=receive, !0=transmit mode */
1089 int sinkmode = 1; /* 0=normal I/O, !0=sink/source mode */
1090 #if defined(linux)
1091 int zerocopy = 0; /* set to enable zero copy via sendfile() */
1092 int directio = 0; /* set to enable direct I/O */
1093 #endif
1094 int nofork = 0; /* set to 1 to not fork server */
1095 int verbose = 0; /* 0=print basic info, 1=print cpu rate, proc
1096 * resource usage. */
1097 int nodelay = 0; /* set TCP_NODELAY socket option */
1098 unsigned long rate = MAXRATE; /* transmit rate limit in Kbps */
1099 int maxburst = 1; /* number of packets allowed to exceed rate */
1100 int nburst = 1; /* number of packets currently exceeding rate */
1101 int irate = -1; /* instantaneous rate limit if set */
1102 int iratesss = 0; /* set if emulating smoothed slow start */
1103 int af3 = 0; /* used for third party explicitaf */
1104 double pkt_time; /* packet transmission time in seconds */
1105 double pkt_time_ms; /* packet transmission time in milliseconds */
1106 uint64_t irate_pk_usec; /* packet transmission time in microseconds */
1107 double irate_pk_nsec; /* nanosecond portion of pkt xmit time */
1108 double irate_cum_nsec = 0.0; /* cumulative nanaseconds over several pkts */
1109 int rate_pps = 0; /* set to 1 if rate is given as pps */
1110 double timeout = 0.0; /* timeout interval in seconds */
1111 double interval = 0.0; /* interval timer in seconds */
1112 double chk_idle_data = 0.0; /* server receiver checks this often */
1113 /* for client having gone away */
1114 double chk_interval = 0.0; /* timer (in seconds) for checking client */
1115 int ctlconnmss; /* control connection maximum segment size */
1116 int datamss = 0; /* data connection maximum segment size */
1117 unsigned int tos = 0; /* 8-bit TOS field for setting DSCP/TOS */
1118 char intervalbuf[256+2]; /* buf for interval reporting */
1119 char linebuf[256+2]; /* line buffer */
1120 int do_poll = 0; /* set to read interval reports (client xmit) */
1121 int got_done = 0; /* set when read last of interval reports */
1122 int reverse = 0; /* reverse direction of data connection open */
1123 int format = 0; /* controls formatting of output */
1124 char fmt[257];
1125 int traceroute = 0; /* do traceroute back to client if set */
1126 int skip_data = 0; /* skip opening of data channel */
1127 #if defined(linux)
1128 int multicast = 0; /* set to 1 for multicast UDP transfer */
1129 #else
1130 uint8_t multicast = 0; /* set to 1 for multicast UDP transfer */
1131 #endif
1132 int ssm = -1; /* set to 1 for Source Specific Multicast */
1133 /* set to 0 to NOT do SSM */
1134 /* set to -1 to have SSM follow protocol */
1135 /* (off for ipv4, on for ipv6) */
1136 int mc_param;
1137 char *mc_addr = NULL; /* user specified multicast IP address */
1138 char mcgaddr[ADDRSTRLEN]; /* buffer to hold text of MC group address */
1139 struct ip_mreq mc_group; /* holds multicast group address */
1140 #ifdef AF_INET6
1141 struct ipv6_mreq mc6_group; /* holds multicast group address */
1142 #endif
1143 #ifdef MCAST_JOIN_SOURCE_GROUP
1144 struct group_source_req group_source_req; /* holds multicast SSM group and */
1145 /* source information */
1146 #endif
1147
1148 #ifdef HAVE_SETPRIO
1149 int priority = 0; /* nuttcp process priority */
1150 #endif
1151
1152 /* affinity and srvr_affinity need to be defined even if don't
1153 * HAVE_SETAFFINITY, to make parameter passing between client and
1154 * server work out OK, since far end may HAVE_SETAFFINITY
1155 *
1156 * they are set to -1 so they have no effect even if don't
1157 * HAVE_SETAFFINITY
1158 */
1159 int affinity = -1; /* nuttcp process CPU affinity */
1160 int srvr_affinity = -1; /* nuttcp server process CPU affinity */
1161
1162 #ifdef HAVE_SETAFFINITY
1163 int ncores = 1; /* number of CPU cores */
1164 cpu_set_t cpu_set; /* processor CPU set */
1165 #endif
1166
1167 long timeout_sec = 0;
1168 struct itimerval itimer; /* for setitimer */
1169 int srvr_helo = 1; /* set to 0 if server doesn't send HELO */
1170 char ident[40 + 1 + 1] = ""; /* identifier for nuttcp output */
1171 int intr = 0;
1172 int abortconn = 0;
1173 int braindead = 0; /* for braindead Solaris 2.8 systems */
1174 int brief = 1; /* set for brief output */
1175 int brief3 = 1; /* for third party nuttcp */
1176 int done = 0; /* don't output interval report if done */
1177 int got_begin = 0; /* don't output interval report if not begun */
1178 int two_bod = 0; /* newer versions send 2 BOD packets for UDP */
1179 int handle_urg = 0; /* newer versions send/recv urgent TCP data */
1180 int got_eod0 = 0; /* got EOD0 packet - marks end of UDP xfer */
1181 int buflenopt = 0; /* whether or not user specified buflen */
1182 int haverateopt = 0; /* whether or not user specified rate */
1183 int clientserver = 0; /* client server mode (use control channel) */
1184 int client = 0; /* 0=server side, 1=client (initiator) side */
1185 int oneshot = 0; /* 1=run server only once */
1186 int inetd = 0; /* set to 1 if server run from inetd */
1187 pid_t pid; /* process id when forking server process */
1188 pid_t wait_pid; /* return of wait system call */
1189 int pidstat; /* status of forked process */
1190 FILE *ctlconn; /* uses fd[0] for control channel */
1191 FILE *debugout; /* used for voluminous nuttcp debug output */
1192 int savestdin; /* used to save real standard in */
1193 int savestdout; /* used to save real standard out */
1194 int firsttime = 1; /* flag for first pass through server */
1195 struct in_addr clientaddr; /* IP address of client connecting to server */
1196
1197 #ifdef AF_INET6
1198 struct in6_addr clientaddr6; /* IP address of client connecting to server */
1199 uint32_t clientscope6; /* scope part of IP address of client */
1200 #endif
1201
1202 struct hostent *addr;
1203 extern int errno;
1204
1205 const char Usage[] = "\
1206 Usage: nuttcp or nuttcp -h prints this usage info\n\
1207 Usage: nuttcp -V prints version info\n\
1208 Usage: nuttcp -xt [-m] host forward and reverse traceroute to/from server\n\
1209 Usage (transmitter): nuttcp [-t] [-options] [ctl_addr/]host [3rd-party] [<in]\n\
1210 |(receiver): nuttcp -r [-options] [host] [3rd-party] [>out]\n\
1211 -4 Use IPv4\n"
1212 #ifdef AF_INET6
1213 " -6 Use IPv6\n"
1214 #endif
1215 " -c## cos dscp value on data streams (t|T suffix for full TOS field)\n\
1216 -l## length of network write|read buf (default 1K|8K/udp, 64K/tcp)\n"
1217 #if defined(linux)
1218 " -s[d][z] use stdin|stdout for data input|output instead of pattern data\n"
1219 " ('d' suboption uses direct I/O if input|output is regular file)\n"
1220 " ('z' suboption enables zero copy tx if input is regular file)\n"
1221 #else
1222 " -s use stdin|stdout for data input|output instead of pattern data\n"
1223 #endif
1224 " -n## number of source bufs written to network (default unlimited)\n\
1225 -w## transmitter|receiver window size in KB (or (m|M)B or (g|G)B)\n\
1226 -ws## server receive|transmit window size in KB (or (m|M)B or (g|G)B)\n\
1227 -wb braindead Solaris 2.8 (sets both xmit and rcv windows)\n\
1228 -p## port number to send to|listen at (default 5101)\n\
1229 -p#:# specify both source:destination port for -p option\n\
1230 -P## port number for control connection (default 5000)\n\
1231 -P#:# specify both source:destination port for -P option\n\
1232 -P#/# control port to/from 3rd-party host (default 5000)\n\
1233 -u use UDP instead of TCP\n\
1234 -m## use multicast with specified TTL instead of unicast (UDP)\n\
1235 -gxxx user specified multicast IP address for -m option\n\
1236 -M## MSS for data connection (TCP)\n\
1237 -N## number of streams (starting at port number), implies -B\n\
1238 -R## transmit rate limit in Kbps (or (m|M)bps or (g|G)bps or (p)ps)\n\
1239 -Ri#[/#] instantaneous rate limit with optional packet burst\n"
1240 #if defined(linux)
1241 " -Ris## emulated smoothed slow start option for -Ri option (TCP)\n"
1242 #endif
1243 " -T## transmit timeout in seconds (or (m|M)inutes or (h|H)ours)\n\
1244 -j enable jitter measurements (assumes -u and -Ri options)\n\
1245 -o enable one-way delay reports (needs synchronized clocks)\n\
1246 -i## receiver interval reporting in seconds (or (m|M)inutes)\n\
1247 -Ixxx identifier for nuttcp output (max of 40 characters)\n\
1248 -F flip option to reverse direction of data connection open\n\
1249 -a retry failed server connection \"again\" for transient errors\n"
1250 #ifdef HAVE_SETPRIO
1251 " -xP## set nuttcp process priority (must be root)\n"
1252 #endif
1253 #ifdef HAVE_SETAFFINITY
1254 " -xc## set nuttcp client process CPU affinity\n"
1255 " -xcs## set nuttcp server process CPU affinity\n"
1256 " -xc#/# set nuttcp client/server process CPU affinity\n"
1257 #endif
1258 " -d set TCP SO_DEBUG option on data socket\n\
1259 -v[v] verbose [or very verbose] output\n\
1260 -b brief output (default)\n\
1261 -br add per-stream TCP retrans info to brief summary (Linux only)\n"
1262 #if defined(linux)
1263 " -bc add per-stream TCP cwnd info to brief summary (Linux only)\n"
1264 #endif
1265 " -D xmit only: don't buffer TCP writes (sets TCP_NODELAY sockopt)\n\
1266 -B recv only: only output full blocks of size from -l## (for TAR)\n"
1267 " --packet-burst packet burst value for instantaneous rate limit option\n"
1268 " --idle-data-timeout <value|minimum/default/maximum> (default: 15/30/60)\n"
1269 " client timeout in seconds for idle data connection\n"
1270 #ifdef IPV6_V6ONLY
1271 " --disable-v4-mapped disable v4 mapping in v6 server (default)\n"
1272 " --enable-v4-mapped enable v4 mapping in v6 server\n"
1273 #endif
1274 "\n\
1275 Usage (server): nuttcp -S[P] [-options]\n\
1276 note server mode excludes use of -s except for -1 one-shot mode\n\
1277 'P' suboption makes 3rd party {in,out}bound control ports same\n\
1278 -4 Use IPv4 (default)\n"
1279 #ifdef AF_INET6
1280 " -6 Use IPv6\n"
1281 #endif
1282 " -1 oneshot server mode (implied with inetd/xinetd), implies -S\n"
1283 #if defined(linux)
1284 " -s[d][z] use stdin|stdout for data input|output instead of pattern data\n"
1285 " ('d' suboption uses direct I/O if input|output is regular file)\n"
1286 " ('z' suboption enables zero copy tx if input is regular file)\n"
1287 #else
1288 " -s use stdin|stdout for data input|output instead of pattern data\n"
1289 #endif
1290 " -P## port number for server connection (default 5000)\n\
1291 note don't use with inetd/xinetd (use services file instead)\n"
1292 #ifdef HAVE_SETPRIO
1293 " -xP## set nuttcp process priority (must be root)\n"
1294 #endif
1295 #ifdef HAVE_SETAFFINITY
1296 " -xc## set nuttcp server process CPU affinity\n"
1297 #endif
1298 " --idle-data-timeout <value|minimum/default/maximum> (default: 15/30/60)\n"
1299 " server timeout in seconds for idle data connection\n"
1300 " --no3rdparty don't allow 3rd party capability\n"
1301 " --nofork don't fork server\n"
1302 " --single-threaded make manually started server be single threaded\n"
1303 #ifdef IPV6_V6ONLY
1304 " --disable-v4-mapped disable v4 mapping in v6 server (default)\n"
1305 " --enable-v4-mapped enable v4 mapping in v6 server\n"
1306 #endif
1307 "\n\
1308 Multilink aggregation options (TCP only):\n\
1309 nuttcp [-options] -N## [ctl_addr]/host1/host2/.../host## (xmit only)\n\
1310 nuttcp [-options] -N## [ctl_addr/]host+addr_stride (IPv4 only)\n\
1311 nuttcp [-options] -N## [ctl_addr/]host+n.n.n.n (IPv4 only)\n\
1312 nuttcp [-options] -N##m [ctl_addr/]host\n\
1313 where host resolves to multiple addresses\n\
1314 \n\
1315 separate [ctl_addr/] option available only for xmit\n\
1316 \n\
1317 Format options:\n\
1318 -fxmitstats also give transmitter stats (MB) with -i (UDP only)\n\
1319 -frunningtotal also give cumulative stats on interval reports\n\
1320 -f-drops don't give packet drop info on brief output (UDP)\n\
1321 -f-retrans don't give retrans info on brief output (TCP)\n"
1322 #if defined(linux)
1323 " -f-cwnd don't give cwnd info on brief output (TCP)\n"
1324 #endif
1325 " -f-percentloss don't give %%loss info on brief output (UDP)\n\
1326 -fparse generate key=value parsable output\n\
1327 -f-beta suppress beta version message\n\
1328 -f-rtt suppress RTT info \n\
1329 ";
1330
1331 char stats[128];
1332 char srvrbuf[4096];
1333 char tmpbuf[257];
1334 uint64_t nbytes = 0; /* bytes on net */
1335 int64_t pbytes = 0; /* previous bytes - for interval reporting */
1336 int64_t ntbytes = 0; /* bytes sent by transmitter */
1337 int64_t ptbytes = 0; /* previous bytes sent by transmitter */
1338 uint64_t ntbytesc = 0; /* bytes sent by transmitter that have
1339 * been counted */
1340 uint64_t ntbytescp = 0; /* previous ntbytesc count */
1341 uint64_t ntbytescpi = 0; /* ntbytescp for interval reports */
1342 uint64_t chk_nbytes = 0; /* byte counter used to test if no more data
1343 * being received by server (presumably because
1344 * client transmitter went away */
1345
1346 double rtt = 0.0; /* RTT between client and server in ms */
1347 int which_rt = 1; /* which round trip for "-Ris" */
1348 uint32_t nretrans[MAXSTREAM+1]; /* number of TCP retransmissions */
1349 uint32_t iretrans[MAXSTREAM+1]; /* initial number of TCP retransmissions */
1350 uint32_t pretrans = 0; /* previous number of TCP retransmissions */
1351 uint32_t sretrans = 0; /* number of system TCP retransmissions */
1352 uint32_t cwnd[MAXSTREAM+1]; /* TCP congestion window in KB */
1353
1354 int numCalls = 0; /* # of NRead/NWrite calls. */
1355 int nstream = 1; /* number of streams */
1356 int multilink = 0; /* set to use multilink aggregation */
1357 int stream_idx = 0; /* current stream */
1358 int start_idx = 1; /* set to use or bypass control channel */
1359 int b_flag = 1; /* use mread() */
1360 int got_srvr_output = 0; /* set when server output has been read */
1361 int reading_srvr_info = 0; /* set when starting to read server info */
1362 int retry_server = 0; /* set to retry control connect() to server */
1363 int num_connect_tries = 0; /* tracks attempted connects to server */
1364 int single_threaded = 0; /* set to make server single threaded */
1365 double srvr_MB;
1366 double srvr_realt;
1367 double srvr_KBps;
1368 double srvr_Mbps;
1369 int srvr_cpu_util;
1370
1371 double cput = 0.000001, realt = 0.000001; /* user, real time (seconds) */
1372 double realtd = 0.000001; /* real time delta - for interval reporting */
1373 double pkt_delta; /* time delta between packets in ms */
1374 double jitter; /* current jitter measurement in ms */
1375 unsigned long long njitter; /* number of jitter measurements */
1376 double jitter_min; /* jitter minimum */
1377 double jitter_max; /* jitter maximum */
1378 double jitter_avg; /* jitter average */
1379 double jitteri; /* current jitter interval measurement in ms */
1380 unsigned long long njitteri; /* number of jitter interval measurements */
1381 double jitter_mini; /* jitter minimum for interval report */
1382 double jitter_maxi; /* jitter maximum for interval report */
1383 double jitter_avgi; /* jitter average for interval report */
1384 double owd; /* current one-way delay measurement in ms */
1385 unsigned long long nowd; /* number of one-way delay measurements */
1386 double owd_min; /* one-way delay minimum */
1387 double owd_max; /* one-way delay maximum */
1388 double owd_avg; /* one-way delay average */
1389 unsigned long long nowdi; /* number of OWD interval measurements */
1390 double owd_mini; /* OWD minimum for interval report */
1391 double owd_maxi; /* OWD maximum for interval report */
1392 double owd_avgi; /* OWD average for interval report */
1393
1394 void
close_data_channels()1395 close_data_channels()
1396 {
1397 if (fd[1] == -1) return;
1398
1399 if (clientserver && client && !host3 && udp && trans) {
1400 /* If all the EOD packets get lost at the end of a UDP
1401 * transfer, having the client do a shutdown() for writing
1402 * on the control connection allows the server to more
1403 * quickly realize that the UDP transfer has completed
1404 * (mostly of benefit for separate control and data paths)
1405 *
1406 * Can't do this in the opposite direction since the
1407 * server needs to send info back to client */
1408 shutdown(0, SHUT_WR);
1409 }
1410
1411 if (multicast && !trans) {
1412 /* Leave the multicast group */
1413 if ((af == AF_INET) && !ssm) {
1414 if (setsockopt(fd[1], IPPROTO_IP, IP_DROP_MEMBERSHIP,
1415 (void *)&mc_group,
1416 sizeof(mc_group)) < 0) {
1417 err("setsockopt: IP_DROP_MEMBERSHIP");
1418 }
1419 }
1420 #ifdef AF_INET6
1421 else if ((af == AF_INET6) && !ssm) {
1422 if (setsockopt(fd[1], IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1423 (void *)&mc6_group,
1424 sizeof(mc6_group)) < 0) {
1425 err("setsockopt: IPV6_LEAVE_GROUP");
1426 }
1427 }
1428 #endif
1429 #ifdef MCAST_JOIN_SOURCE_GROUP
1430 else if ((af == AF_INET) && ssm) {
1431 /* Leave the source specific multicast group */
1432 if (setsockopt(fd[1], IPPROTO_IP,
1433 MCAST_LEAVE_SOURCE_GROUP,
1434 &group_source_req,
1435 sizeof(group_source_req)) < 0) {
1436 err("setsockopt: MCAST_LEAVE_SOURCE_GROUP");
1437 }
1438 }
1439 #ifdef AF_INET6
1440 else if ((af == AF_INET6) && ssm) {
1441 /* Leave the source specific multicast group */
1442 if (setsockopt(fd[1], IPPROTO_IPV6,
1443 MCAST_LEAVE_SOURCE_GROUP,
1444 &group_source_req,
1445 sizeof(group_source_req)) < 0) {
1446 err("setsockopt: MCAST_LEAVE_SOURCE_GROUP");
1447 }
1448 }
1449 #endif /* AF_INET6 */
1450 #endif /* MCAST_JOIN_SOURCE_GROUP */
1451 }
1452
1453 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) {
1454 close(fd[stream_idx]);
1455 fd[stream_idx] = -1;
1456 }
1457 }
1458
1459 #ifdef SIGPIPE
1460 void
sigpipe(int signum)1461 sigpipe( int signum )
1462 {
1463 signal(SIGPIPE, sigpipe);
1464 }
1465 #endif
1466
1467 void
sigint(int signum)1468 sigint( int signum )
1469 {
1470 signal(SIGINT, SIG_DFL);
1471 fputs("\n*** transfer interrupted ***\n", stdout);
1472 if (clientserver && client && !host3 && udp && !trans)
1473 shutdown(0, SHUT_WR);
1474 else
1475 intr = 1;
1476 done++;
1477 return;
1478 }
1479
1480 void
ignore_alarm(int signum)1481 ignore_alarm( int signum )
1482 {
1483 return;
1484 }
1485
1486 void
sigalarm(int signum)1487 sigalarm( int signum )
1488 {
1489 struct timeval timec; /* Current time */
1490 struct timeval timed; /* Delta time */
1491 int64_t nrbytes;
1492 uint64_t deltarbytes, deltatbytes;
1493 double fractloss;
1494 int nodata;
1495 int i;
1496 char *cp1, *cp2;
1497 short save_events;
1498 long flags, saveflags;
1499
1500 if (host3 && clientserver) {
1501 if (client)
1502 intr = 1;
1503 return;
1504 }
1505
1506 if (clientserver && client && reading_srvr_info) {
1507 mes("Error: not receiving server info");
1508 exit(1);
1509 }
1510
1511 #ifdef HAVE_CLOCK_GETTIME
1512 timec.tv_sec = 0; /* silence bogus compiler warning */
1513 timec.tv_usec = 0; /* silence bogus compiler warning */
1514 #endif
1515
1516 if (interval && !trans) {
1517 /* Get real time */
1518 get_timeofday(&timec, (struct timezone *)0);
1519 tvsub( &timed, &timec, &timep );
1520 realtd = timed.tv_sec + ((double)timed.tv_usec) / 1000000;
1521 if (realtd <= 0.0) realtd = 0.000001;
1522 tvsub( &timed, &timec, &time0 );
1523 realt = timed.tv_sec + ((double)timed.tv_usec)
1524 / 1000000;
1525 if (realt <= 0.0) realt = 0.000001;
1526 }
1527
1528 if (clientserver && !trans) {
1529 struct sockaddr_in peer;
1530 socklen_t peerlen = sizeof(peer);
1531
1532 nodata = 0;
1533
1534 if (getpeername(fd[0], (struct sockaddr *)&peer, &peerlen) < 0)
1535 nodata = 1;
1536
1537 if (!client && udp && got_begin) {
1538 /* checks if client did a shutdown() for writing
1539 * on the control connection */
1540 pollfds[0].fd = fileno(ctlconn);
1541 save_events = pollfds[0].events;
1542 pollfds[0].events = POLLIN | POLLPRI;
1543 pollfds[0].revents = 0;
1544 if ((poll(pollfds, 1, 0) > 0) &&
1545 (pollfds[0].revents & (POLLIN | POLLPRI))) {
1546 nodata = 1;
1547 }
1548 pollfds[0].events = save_events;
1549 }
1550
1551 if (interval) {
1552 chk_interval += realtd;
1553 if (chk_interval >= chk_idle_data) {
1554 chk_interval = 0;
1555 if ((nbytes - chk_nbytes) == 0)
1556 nodata = 1;
1557 chk_nbytes = nbytes;
1558 }
1559 }
1560 else {
1561 if ((nbytes - chk_nbytes) == 0)
1562 nodata = 1;
1563 chk_nbytes = nbytes;
1564 }
1565
1566 if (nodata) {
1567 /* Don't just exit anymore so can get partial results
1568 * (shouldn't be a problem but keep an eye out that
1569 * servers don't start hanging again) */
1570 if (!client && udp && !interval && handle_urg) {
1571 /* send 'A' for ABORT as urgent TCP data
1572 * on control connection (don't block)
1573 *
1574 * Only server can do this since client
1575 * does a shutdown() for writing on the
1576 * control connection */
1577 saveflags = fcntl(fd[0], F_GETFL, 0);
1578 if (saveflags != -1) {
1579 flags = saveflags | O_NONBLOCK;
1580 fcntl(fd[0], F_SETFL, flags);
1581 }
1582 send(fd[0], "A", 1, MSG_OOB);
1583 if (saveflags != -1) {
1584 flags = saveflags;
1585 fcntl(fd[0], F_SETFL, flags);
1586 }
1587 }
1588 if (client) {
1589 mes("Error: not receiving data from server");
1590 exit(1);
1591 }
1592 close_data_channels();
1593 intr = 1;
1594 return;
1595 }
1596
1597 if (!interval)
1598 return;
1599 }
1600
1601 if (interval && !trans) {
1602 if ((udp && !got_begin) || done) {
1603 timep.tv_sec = timec.tv_sec;
1604 timep.tv_usec = timec.tv_usec;
1605 return;
1606 }
1607 if (clientserver) {
1608 nrbytes = nbytes;
1609 if (udplossinfo) {
1610 ntbytes = *(int64_t *)(buf + 24);
1611 if (need_swap) {
1612 cp1 = (char *)&ntbytes;
1613 cp2 = buf + 31;
1614 for ( i = 0; i < 8; i++ )
1615 *cp1++ = *cp2--;
1616 }
1617 if (ntbytes > ntbytesc)
1618 /* received bytes not counted yet */
1619 nrbytes += buflen;
1620 if ((nrbytes > ntbytes) ||
1621 ((nrbytes - pbytes) > (ntbytes - ptbytes)))
1622 /* yes they were counted */
1623 nrbytes -= buflen;
1624 }
1625 if (read_retrans) {
1626 nretrans[1] = *(uint32_t *)(buf + 24);
1627 if (need_swap) {
1628 cp1 = (char *)&nretrans[1];
1629 cp2 = buf + 27;
1630 for ( i = 0; i < 4; i++ )
1631 *cp1++ = *cp2--;
1632 }
1633 }
1634 if (read_cwnd) {
1635 cwnd[1] = *(uint32_t *)(buf + 28);
1636 if (need_swap) {
1637 cp1 = (char *)&cwnd[1];
1638 cp2 = buf + 31;
1639 for ( i = 0; i < 4; i++ )
1640 *cp1++ = *cp2--;
1641 }
1642 if ((cwnd[1] == 0x5254524Eu) || /* "RTRN" */
1643 (cwnd[1] == 0x48525452u)) /* "HRTR" */
1644 cwnd[1] = init_pkt_cwnd;
1645 }
1646 if (*ident)
1647 fprintf(stdout, "%s: ", ident + 1);
1648 if (format & PARSE)
1649 strcpy(fmt, P_PERF_FMT_INTERVAL);
1650 else
1651 strcpy(fmt, PERF_FMT_INTERVAL);
1652 fprintf(stdout, fmt,
1653 (double)(nrbytes - pbytes)/(1024*1024), realtd,
1654 (double)(nrbytes - pbytes)/realtd/125000);
1655 if (udplossinfo) {
1656 if (!(format & NODROPS)) {
1657 if (format & PARSE)
1658 strcpy(fmt,
1659 P_DROP_FMT_INTERVAL);
1660 else
1661 strcpy(fmt, DROP_FMT_INTERVAL);
1662 fprintf(stdout, fmt,
1663 ((ntbytes - ptbytes)
1664 - (nrbytes - pbytes))
1665 /buflen,
1666 (ntbytes - ptbytes)/buflen);
1667 }
1668 if (!(format & NOPERCENTLOSS)) {
1669 deltarbytes = nrbytes - pbytes;
1670 deltatbytes = ntbytes - ptbytes;
1671 fractloss = (deltatbytes ?
1672 1.0 -
1673 (double)deltarbytes
1674 /(double)deltatbytes :
1675 0.0);
1676 if (format & PARSE)
1677 strcpy(fmt,
1678 P_LOSS_FMT_INTERVAL);
1679 else if ((fractloss != 0.0) &&
1680 (fractloss < 0.001))
1681 strcpy(fmt,
1682 LOSS_FMT_INTERVAL5);
1683 else
1684 strcpy(fmt, LOSS_FMT_INTERVAL);
1685 fprintf(stdout, fmt, fractloss * 100);
1686 }
1687 }
1688 if ((do_jitter & JITTER_MIN) && njitteri) {
1689 if (format & PARSE)
1690 strcpy(fmt, P_JITTER_MIN_FMT_INTERVAL);
1691 else
1692 strcpy(fmt, JITTER_MIN_FMT_INTERVAL);
1693 fprintf(stdout, fmt, jitter_mini);
1694 }
1695 if ((do_jitter & JITTER_AVG) && njitteri) {
1696 if (format & PARSE)
1697 strcpy(fmt, P_JITTER_AVG_FMT_INTERVAL);
1698 else
1699 strcpy(fmt, JITTER_AVG_FMT_INTERVAL);
1700 fprintf(stdout, fmt, jitter_avgi/njitteri);
1701 }
1702 if ((do_jitter & JITTER_MAX) && njitteri) {
1703 if (format & PARSE)
1704 strcpy(fmt, P_JITTER_MAX_FMT_INTERVAL);
1705 else
1706 strcpy(fmt, JITTER_MAX_FMT_INTERVAL);
1707 fprintf(stdout, fmt, jitter_maxi);
1708 }
1709 if (do_jitter && njitteri) {
1710 njitteri = 0;
1711 jitter_mini = 1000000.0;
1712 jitter_maxi = -1000000.0;
1713 jitter_avgi = 0.0;
1714 }
1715 if (read_retrans && sinkmode) {
1716 if (format & PARSE)
1717 fprintf(stdout, P_RETRANS_FMT_INTERVAL,
1718 ((retransinfo == 1) ||
1719 !nrbytes) ? "" : "host-",
1720 (nretrans[1] - pretrans));
1721 else
1722 fprintf(stdout, RETRANS_FMT_INTERVAL,
1723 (nretrans[1] - pretrans),
1724 ((retransinfo == 1) ||
1725 !nrbytes) ? "" : "host-");
1726 }
1727 if (read_cwnd && sinkmode) {
1728 if (format & PARSE)
1729 fprintf(stdout, P_CWND_FMT_INTERVAL,
1730 cwnd[1]);
1731 else
1732 fprintf(stdout, CWND_FMT_INTERVAL,
1733 cwnd[1]);
1734 }
1735 if ((do_owd & OWD_MIN) && nowdi) {
1736 if (format & PARSE)
1737 strcpy(fmt, P_OWD_MIN_FMT_INTERVAL);
1738 else
1739 strcpy(fmt, OWD_MIN_FMT_INTERVAL);
1740 fprintf(stdout, fmt, owd_mini);
1741 }
1742 if ((do_owd & OWD_AVG) && nowdi) {
1743 if (format & PARSE)
1744 strcpy(fmt, P_OWD_AVG_FMT_INTERVAL);
1745 else
1746 strcpy(fmt, OWD_AVG_FMT_INTERVAL);
1747 fprintf(stdout, fmt, owd_avgi/nowdi);
1748 }
1749 if ((do_owd & OWD_MAX) && nowdi) {
1750 if (format & PARSE)
1751 strcpy(fmt, P_OWD_MAX_FMT_INTERVAL);
1752 else
1753 strcpy(fmt, OWD_MAX_FMT_INTERVAL);
1754 fprintf(stdout, fmt, owd_maxi);
1755 }
1756 if (do_owd && nowdi) {
1757 nowdi = 0;
1758 owd_mini = 1000000.0;
1759 owd_maxi = -1000000.0;
1760 owd_avgi = 0.0;
1761 }
1762 if (format & RUNNINGTOTAL) {
1763 if (format & PARSE)
1764 strcpy(fmt, P_PERF_FMT_INTERVAL2);
1765 else
1766 strcpy(fmt, PERF_FMT_INTERVAL2);
1767 fprintf(stdout, fmt,
1768 (double)nrbytes/(1024*1024), realt,
1769 (double)nrbytes/realt/125000);
1770 if (udplossinfo) {
1771 if (!(format & NODROPS)) {
1772 if (format & PARSE)
1773 strcpy(fmt,
1774 P_DROP_FMT_INTERVAL);
1775 else
1776 strcpy(fmt,
1777 DROP_FMT_INTERVAL);
1778 fprintf(stdout, fmt,
1779 (ntbytes - nrbytes)
1780 /buflen,
1781 ntbytes/buflen);
1782 }
1783 if (!(format & NOPERCENTLOSS)) {
1784 fractloss = (ntbytes ?
1785 1.0 -
1786 (double)nrbytes
1787 /(double)ntbytes :
1788 0.0);
1789 if (format & PARSE)
1790 strcpy(fmt,
1791 P_LOSS_FMT_INTERVAL);
1792 else if ((fractloss != 0.0) &&
1793 (fractloss < 0.001))
1794 strcpy(fmt,
1795 LOSS_FMT_INTERVAL5);
1796 else
1797 strcpy(fmt,
1798 LOSS_FMT_INTERVAL);
1799 fprintf(stdout, fmt,
1800 fractloss * 100);
1801 }
1802 }
1803 if (read_retrans && sinkmode) {
1804 if (format & PARSE)
1805 fprintf(stdout,
1806 P_RETRANS_FMT_INTERVAL,
1807 ((retransinfo == 1) ||
1808 !nrbytes) ?
1809 "" : "host-",
1810 nretrans[1]);
1811 else
1812 fprintf(stdout,
1813 RETRANS_FMT_INTERVAL,
1814 nretrans[1],
1815 ((retransinfo == 1) ||
1816 !nrbytes) ?
1817 "" : "host-");
1818 }
1819 if (read_cwnd && sinkmode) {
1820 if (format & PARSE)
1821 fprintf(stdout,
1822 P_CWND_FMT_INTERVAL,
1823 cwnd[1]);
1824 else
1825 fprintf(stdout,
1826 CWND_FMT_INTERVAL,
1827 cwnd[1]);
1828 }
1829 }
1830 if (udplossinfo && (format & XMITSTATS)) {
1831 if (format & PARSE)
1832 strcpy(fmt, P_PERF_FMT_INTERVAL3);
1833 else
1834 strcpy(fmt, PERF_FMT_INTERVAL3);
1835 fprintf(stdout, fmt,
1836 (double)(ntbytes - ptbytes)/1024/1024);
1837 if (format & RUNNINGTOTAL) {
1838 if (format & PARSE)
1839 strcpy(fmt,
1840 P_PERF_FMT_INTERVAL4);
1841 else
1842 strcpy(fmt, PERF_FMT_INTERVAL4);
1843 fprintf(stdout, fmt,
1844 (double)ntbytes/1024/1024);
1845 if (format & DEBUGINTERVAL)
1846 fprintf(stdout, " Pre: %.4f MB",
1847 (double)ntbytesc
1848 /1024/1024);
1849 }
1850 }
1851 fprintf(stdout, "\n");
1852 fflush(stdout);
1853 timep.tv_sec = timec.tv_sec;
1854 timep.tv_usec = timec.tv_usec;
1855 pbytes = nrbytes;
1856 ptbytes = ntbytes;
1857 pretrans = nretrans[1];
1858 }
1859 }
1860 else
1861 intr = 1;
1862 return;
1863 }
1864
1865 int
main(int argc,char ** argv)1866 main( int argc, char **argv )
1867 {
1868 double MB;
1869 double rate_opt;
1870 double fractloss;
1871 int cpu_util;
1872 int first_read;
1873 int first_jitter, first_jitteri;
1874 int ocorrection = 0;
1875 double correction = 0.0;
1876 int pollst = 0;
1877 int i = 0, j = 0;
1878 char *cp1 = NULL, *cp2 = NULL, *cp3 = NULL;
1879 char *hostaddr;
1880 char ch = '\0';
1881 int error_num = 0;
1882 int sockopterr = 0;
1883 int save_errno;
1884 struct servent *sp = 0;
1885 struct addrinfo hints, *res[MAXSTREAM + 1] = { NULL },
1886 *host3res, *mcres = NULL;
1887 union sockaddr_union client_ipaddr;
1888 struct sockaddr_storage dummy;
1889 struct timeval time_eod = {0}; /* time EOD packet was received */
1890 struct timeval time_eod0 = {0}; /* time EOD0 packet was received */
1891 struct timeval timed; /* time delta */
1892 struct timeval timeconn1 = {0}; /* time before connect() for RTT */
1893 struct timeval timeconn2 = {0}; /* time after connect() for RTT */
1894 struct timeval timeconn; /* time to connect() == RTT */
1895 union {
1896 unsigned char buf[sizeof(struct in_addr)];
1897 uint32_t ip32;
1898 } ipad_stride; /* IPv4 address stride */
1899 short save_events;
1900 int skiparg;
1901 int reqval;
1902 int got_srvr_retrans;
1903 int got_srvr_cwnd;
1904 uint32_t total_retrans = 0; /* total retrans for all streams */
1905 uint32_t total_snd_cwnd = 0; /* total cwnd for all streams in KB */
1906 double idle_data_min = IDLE_DATA_MIN;
1907 double idle_data_max = IDLE_DATA_MAX;
1908 double default_idle_data = DEFAULT_IDLE_DATA;
1909 char multsrc[ADDRSTRLEN] = "\0";
1910 char multaddr[ADDRSTRLEN] = "\0";
1911 long flags;
1912 int nameinfo_flags;
1913 int implicit_hostaddr;
1914
1915 sendwin = 0;
1916 rcvwin = 0;
1917 srvrwin = -1;
1918 format |= WANTRTT;
1919
1920 if (argc < 2) goto usage;
1921
1922 nut_cmd = argv[0];
1923 argv++; argc--;
1924 while (argc>0 && argv[0][0] == '-') {
1925 skiparg = 0;
1926 switch (argv[0][1]) {
1927
1928 case '4':
1929 domain = PF_INET;
1930 af = AF_INET;
1931 explicitaf = 1;
1932 break;
1933 #ifdef AF_INET6
1934 case '6':
1935 domain = PF_INET6;
1936 af = AF_INET6;
1937 explicitaf = 1;
1938 break;
1939 #endif
1940 case 'B':
1941 b_flag = 1;
1942 break;
1943 case 't':
1944 trans = 1;
1945 break;
1946 case 'r':
1947 trans = 0;
1948 break;
1949 case 'd':
1950 options |= SO_DEBUG;
1951 break;
1952 case 'D':
1953 nodelay = 1;
1954 break;
1955 case 'n':
1956 reqval = 0;
1957 if (argv[0][2] == 'b') {
1958 fprintf(stderr, "option \"-nb\" no longer supported, use \"-n###[k|m|g|t|p]\" instead\n");
1959 fflush(stderr);
1960 exit(1);
1961 }
1962 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
1963 nbuf = strtoull(cp1, NULL, 0);
1964 if (nbuf == 0) {
1965 if (errno == EINVAL) {
1966 fprintf(stderr, "invalid nbuf = %s\n",
1967 &argv[0][2]);
1968 fflush(stderr);
1969 exit(1);
1970 }
1971 else {
1972 nbuf = DEFAULT_NBUF;
1973 break;
1974 }
1975 }
1976 if (*cp1)
1977 ch = *(cp1 + strlen(cp1) - 1);
1978 else
1979 ch = '\0';
1980 if ((ch == 'b') || (ch == 'B'))
1981 nbuf_bytes = 1;
1982 else if ((ch == 'k') || (ch == 'K')) {
1983 nbuf *= 1024;
1984 nbuf_bytes = 1;
1985 }
1986 else if ((ch == 'm') || (ch == 'M')) {
1987 nbuf *= 1048576;
1988 nbuf_bytes = 1;
1989 }
1990 else if ((ch == 'g') || (ch == 'G')) {
1991 nbuf *= 1073741824;
1992 nbuf_bytes = 1;
1993 }
1994 else if ((ch == 't') || (ch == 'T')) {
1995 nbuf *= 1099511627776ull;
1996 nbuf_bytes = 1;
1997 }
1998 else if ((ch == 'p') || (ch == 'P')) {
1999 nbuf *= 1125899906842624ull;
2000 nbuf_bytes = 1;
2001 }
2002 break;
2003 case 'l':
2004 reqval = 1;
2005 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2006 buflen = atoi(cp1);
2007 buflenopt = 1;
2008 if (buflen < 1) {
2009 fprintf(stderr, "invalid buflen = %d\n", buflen);
2010 fflush(stderr);
2011 exit(1);
2012 }
2013 if (*cp1)
2014 ch = *(cp1 + strlen(cp1) - 1);
2015 else
2016 ch = '\0';
2017 if ((ch == 'k') || (ch == 'K'))
2018 buflen *= 1024;
2019 else if ((ch == 'm') || (ch == 'M'))
2020 buflen *= 1048576;
2021 break;
2022 case 'w':
2023 reqval = 1;
2024 if (argv[0][2] == 's') {
2025 cp1 = getoptvalp(argv, 3, reqval, &skiparg);
2026 srvrwin = atoi(cp1);
2027 if (*cp1)
2028 ch = *(cp1 + strlen(cp1) - 1);
2029 else
2030 ch = '\0';
2031 if ((ch == 'k') || (ch == 'K'))
2032 srvrwin *= 1024;
2033 else if ((ch == 'm') || (ch == 'M'))
2034 srvrwin *= 1048576;
2035 else if ((ch == 'g') || (ch == 'G'))
2036 srvrwin *= 1073741824;
2037 else if ((ch != 'b') && (ch != 'B'))
2038 srvrwin *= 1024;
2039 if (srvrwin < 0) {
2040 fprintf(stderr, "invalid srvrwin = %d\n", srvrwin);
2041 fflush(stderr);
2042 exit(1);
2043 }
2044 }
2045 else {
2046 if (argv[0][2] == 'b') {
2047 braindead = 1;
2048 cp1 = getoptvalp(argv, 3, reqval,
2049 &skiparg);
2050 if (*cp1 == '\0')
2051 break;
2052 sendwin = atoi(cp1);
2053 }
2054 else {
2055 cp1 = getoptvalp(argv, 2, reqval,
2056 &skiparg);
2057 sendwin = atoi(cp1);
2058 }
2059
2060 if (*cp1)
2061 ch = *(cp1 + strlen(cp1) - 1);
2062 else
2063 ch = '\0';
2064 if ((ch == 'k') || (ch == 'K'))
2065 sendwin *= 1024;
2066 else if ((ch == 'm') || (ch == 'M'))
2067 sendwin *= 1048576;
2068 else if ((ch == 'g') || (ch == 'G'))
2069 sendwin *= 1073741824;
2070 else if ((ch != 'b') && (ch != 'B'))
2071 sendwin *= 1024;
2072 rcvwin = sendwin;
2073 if (sendwin < 0) {
2074 fprintf(stderr, "invalid sendwin = %d\n", sendwin);
2075 fflush(stderr);
2076 exit(1);
2077 }
2078 }
2079 if (srvrwin == -1) {
2080 srvrwin = sendwin;
2081 }
2082 break;
2083 case 's':
2084 sinkmode = 0; /* sink/source data */
2085 #if defined(linux)
2086 if (strchr(argv[0], 'z'))
2087 zerocopy = 1;
2088 if (strchr(argv[0], 'd'))
2089 directio = 1;
2090 #endif
2091 break;
2092 case 'p':
2093 reqval = 1;
2094 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2095 if ((cp2 = strchr(cp1, ':'))) {
2096 tmpport = atoi(cp1);
2097 if ((tmpport < 1024) || (tmpport > 65535)) {
2098 fprintf(stderr,
2099 "invalid source port = %d\n",
2100 tmpport);
2101 fflush(stderr);
2102 exit(1);
2103 }
2104 srcport = tmpport;
2105 cp1 = cp2 + 1;
2106 }
2107 tmpport = atoi(cp1);
2108 if ((tmpport < 1024) || (tmpport > 65535)) {
2109 fprintf(stderr, "invalid port = %d\n", tmpport);
2110 fflush(stderr);
2111 exit(1);
2112 }
2113 port = tmpport;
2114 break;
2115 case 'P':
2116 reqval = 1;
2117 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2118 if ((cp2 = strchr(cp1, ':'))) {
2119 tmpport = atoi(cp1);
2120 if ((tmpport < 1024) || (tmpport > 65535)) {
2121 fprintf(stderr,
2122 "invalid source "
2123 "control port = %d\n", tmpport);
2124 fflush(stderr);
2125 exit(1);
2126 }
2127 srcctlport = tmpport;
2128 cp1 = cp2 + 1;
2129 }
2130 tmpport = atoi(cp1);
2131 if ((tmpport < 1024) || (tmpport > 65535)) {
2132 fprintf(stderr,
2133 "invalid ctlport = %d\n", tmpport);
2134 fflush(stderr);
2135 exit(1);
2136 }
2137 ctlport = tmpport;
2138 if ((cp2 = strchr(argv[0], '/'))) {
2139 if (strchr(cp2, ':')) {
2140 fprintf(stderr,
2141 "can't specify source control "
2142 "port with third party\n");
2143 fflush(stderr);
2144 exit(1);
2145 }
2146 tmpport = atoi(cp2 + 1);
2147 if ((tmpport < 1024) || (tmpport > 65535)) {
2148 fprintf(stderr,
2149 "invalid third party "
2150 "ctlport = %d\n", tmpport);
2151 fflush(stderr);
2152 exit(1);
2153 }
2154 ctlport3 = tmpport;
2155 }
2156 break;
2157 case 'u':
2158 udp = 1;
2159 if (!buflenopt) buflen = DEFAULTUDPBUFLEN;
2160 if (argv[0][2] == 'u') {
2161 haverateopt = 1;
2162 rate = MAXRATE;
2163 }
2164 break;
2165 case 'j':
2166 reqval = 0;
2167 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2168 if (strchr(cp1, 'm'))
2169 do_jitter |= JITTER_MIN;
2170 if (strchr(cp1, 'a'))
2171 do_jitter |= JITTER_AVG;
2172 if (strchr(cp1, 'x'))
2173 do_jitter |= JITTER_MAX;
2174 if (do_jitter == 0)
2175 do_jitter = JITTER_MAX;
2176 if (strchr(cp1, 'o'))
2177 do_jitter |= JITTER_IGNORE_OOO;
2178 udp = 1;
2179 if (!buflenopt) buflen = DEFAULTUDPBUFLEN;
2180 break;
2181 case 'o':
2182 reqval = 0;
2183 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2184 if (strchr(cp1, 'm'))
2185 do_owd |= OWD_MIN;
2186 if (strchr(cp1, 'a'))
2187 do_owd |= OWD_AVG;
2188 if (strchr(cp1, 'x'))
2189 do_owd |= OWD_MAX;
2190 if (do_owd == 0)
2191 do_owd = OWD_AVG;
2192 break;
2193 case 'v':
2194 brief = 0;
2195 if (argv[0][2] == 'v')
2196 verbose = 1;
2197 break;
2198 case 'N':
2199 reqval = 1;
2200 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2201 nstream = atoi(cp1);
2202 if (strchr(cp1, 'm'))
2203 multilink = 1;
2204 if (nstream < 1) {
2205 fprintf(stderr, "invalid nstream = %d\n", nstream);
2206 fflush(stderr);
2207 exit(1);
2208 }
2209 if (nstream > MAXSTREAM) {
2210 fprintf(stderr, "nstream = %d > MAXSTREAM, set to %d\n",
2211 nstream, MAXSTREAM);
2212 nstream = MAXSTREAM;
2213 }
2214 if (nstream > 1) {
2215 b_flag = 1;
2216 send_retrans = 0;
2217 read_retrans = 0;
2218 send_cwnd = 0;
2219 read_cwnd = 0;
2220 }
2221 break;
2222 case 'R':
2223 reqval = 1;
2224 haverateopt = 1;
2225 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2226 if (*cp1 == 'i') {
2227 cp1++;
2228 if (*cp1 == 's') {
2229 cp1++;
2230 #if defined(linux)
2231 iratesss = 1;
2232 #else
2233 fprintf(stderr, "smoothed slow start not supported for non-Linux\n");
2234 fflush(stderr);
2235 #endif
2236 }
2237 sscanf(cp1, "%lf", &rate_opt);
2238 irate = 1;
2239 }
2240 else if (*cp1 == 'a') {
2241 cp1++;
2242 sscanf(cp1, "%lf", &rate_opt);
2243 irate = 0;
2244 }
2245 else if (*cp1 == 'u') {
2246 cp1++;
2247 rate_opt = 0.0;
2248 irate = 0;
2249 }
2250 else {
2251 sscanf(cp1, "%lf", &rate_opt);
2252 }
2253 if ((cp2 = strchr(cp1, '/'))) {
2254 *cp2++ = '\0';
2255 maxburst = atoi(cp2);
2256 if (maxburst <= 0) {
2257 fprintf(stderr,
2258 "invalid maxburst = %d\n",
2259 maxburst);
2260 fflush(stderr);
2261 exit(1);
2262 }
2263 }
2264 if (*cp1)
2265 ch = *(cp1 + strlen(cp1) - 1);
2266 else
2267 ch = '\0';
2268 if ((ch == 'm') || (ch == 'M'))
2269 rate_opt *= 1000;
2270 else if ((ch == 'g') || (ch == 'G'))
2271 rate_opt *= 1000000;
2272 else if (ch == 'p') {
2273 rate_pps = 1;
2274 if (strlen(cp1) >= 2) {
2275 ch = *(cp1 + strlen(cp1) - 2);
2276 if ((ch == 'k') || (ch == 'K'))
2277 rate_opt *= 1000;
2278 if ((ch == 'm') || (ch == 'M'))
2279 rate_opt *= 1000000;
2280 }
2281 }
2282 rate = rate_opt;
2283 if (rate == 0)
2284 rate = MAXRATE;
2285 break;
2286 case 'T':
2287 reqval = 0;
2288 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2289 sscanf(cp1, "%lf", &timeout);
2290 if (timeout < 0) {
2291 fprintf(stderr, "invalid timeout = %f\n", timeout);
2292 fflush(stderr);
2293 exit(1);
2294 }
2295 else if (timeout == 0.0)
2296 timeout = DEFAULT_TIMEOUT;
2297 if (*cp1)
2298 ch = *(cp1 + strlen(cp1) - 1);
2299 else
2300 ch = '\0';
2301 if ((ch == 'm') || (ch == 'M'))
2302 timeout *= 60.0;
2303 else if ((ch == 'h') || (ch == 'H'))
2304 timeout *= 3600.0;
2305 else if ((ch == 'd') || (ch == 'D'))
2306 timeout *= 86400.0;
2307 itimer.it_value.tv_sec = timeout;
2308 itimer.it_value.tv_usec =
2309 (timeout - itimer.it_value.tv_sec)*1000000;
2310 if (timeout && !nbuf)
2311 nbuf = INT_MAX;
2312 break;
2313 case 'i':
2314 reqval = 0;
2315 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2316 sscanf(cp1, "%lf", &interval);
2317 if (interval < 0.0) {
2318 fprintf(stderr, "invalid interval = %f\n", interval);
2319 fflush(stderr);
2320 exit(1);
2321 }
2322 else if (interval == 0.0)
2323 interval = 1.0;
2324 if (*cp1)
2325 ch = *(cp1 + strlen(cp1) - 1);
2326 else
2327 ch = '\0';
2328 if ((ch == 'm') || (ch == 'M'))
2329 interval *= 60.0;
2330 else if ((ch == 'h') || (ch == 'H'))
2331 interval *= 3600.0;
2332 break;
2333 case 'I':
2334 reqval = 1;
2335 ident[0] = '-';
2336 strncpy(&ident[1],
2337 getoptvalp(argv, 2, reqval, &skiparg), 40);
2338 ident[41] = '\0';
2339 break;
2340 case 'F':
2341 reverse = 1;
2342 break;
2343 case 'b':
2344 reqval = 0;
2345 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2346 if (*cp1) {
2347 if (isalpha((int)(*cp1)))
2348 brief = 1;
2349 else
2350 brief = atoi(cp1);
2351 if (strchr(cp1, 'r'))
2352 brief |= BRIEF_RETRANS_STREAMS;
2353 if (strchr(cp1, 'c')) {
2354 #if defined(linux)
2355 brief |= BRIEF_CWND_STREAMS;
2356 #else
2357 fprintf(stderr, "\"-bc\" option not supported for non-Linux\n");
2358 fflush(stderr);
2359 #endif
2360 }
2361 }
2362 else
2363 brief = 1;
2364 break;
2365 case 'S':
2366 if (strchr(&argv[0][2], 'P'))
2367 pass_ctlport = 1;
2368 trans = 0;
2369 clientserver = 1;
2370 brief = 0;
2371 verbose = 1;
2372 break;
2373 case '1':
2374 oneshot = 1;
2375 trans = 0;
2376 clientserver = 1;
2377 brief = 0;
2378 verbose = 1;
2379 break;
2380 case 'V':
2381 fprintf(stdout, "nuttcp-%d.%d.%d%s\n", vers_major,
2382 vers_minor, vers_delta,
2383 beta ? BETA_STR : "");
2384 exit(0);
2385 case 'f':
2386 if (strcmp(&argv[0][2], "xmitstats") == 0)
2387 format |= XMITSTATS;
2388 else if (strcmp(&argv[0][2], "debuginterval") == 0)
2389 format |= DEBUGINTERVAL;
2390 else if (strcmp(&argv[0][2], "runningtotal") == 0)
2391 format |= RUNNINGTOTAL;
2392 else if (strcmp(&argv[0][2], "-percentloss") == 0)
2393 format |= NOPERCENTLOSS;
2394 else if (strcmp(&argv[0][2], "-drops") == 0)
2395 format |= NODROPS;
2396 else if (strcmp(&argv[0][2], "-retrans") == 0) {
2397 format |= NORETRANS;
2398 format |= NOCWND;
2399 }
2400 else if (strcmp(&argv[0][2], "debugretrans") == 0)
2401 format |= DEBUGRETRANS;
2402 else if (strcmp(&argv[0][2], "-cwnd") == 0)
2403 format |= NOCWND;
2404 else if (strcmp(&argv[0][2], "debugpoll") == 0)
2405 format |= DEBUGPOLL;
2406 else if (strcmp(&argv[0][2], "debugmtu") == 0)
2407 format |= DEBUGMTU;
2408 else if (strcmp(&argv[0][2], "debugjitter") == 0)
2409 format |= DEBUGJITTER;
2410 #if defined(linux)
2411 else if (strcmp(&argv[0][2], "debugirate") == 0)
2412 format |= DEBUGIRATE;
2413 #endif
2414 else if (strcmp(&argv[0][2], "parse") == 0)
2415 format |= PARSE;
2416 else if (strcmp(&argv[0][2], "-beta") == 0)
2417 format |= NOBETAMSG;
2418 /* below is for compatibility with 6.0.x beta */
2419 else if (strcmp(&argv[0][2], "rtt") == 0)
2420 format |= WANTRTT;
2421 else if (strcmp(&argv[0][2], "-rtt") == 0)
2422 format &= ~WANTRTT;
2423 else {
2424 if (argv[0][2]) {
2425 fprintf(stderr, "invalid format option \"%s\"\n", &argv[0][2]);
2426 fflush(stderr);
2427 exit(1);
2428 }
2429 else {
2430 fprintf(stderr, "invalid null format option\n");
2431 fprintf(stderr, "perhaps the \"-F\" flip option was intended\n");
2432 fflush(stderr);
2433 exit(1);
2434 }
2435 }
2436 break;
2437 case 'x':
2438 reqval = 1;
2439 if (argv[0][2] == 't') {
2440 traceroute = 1;
2441 brief = 1;
2442 }
2443 #ifdef HAVE_SETPRIO
2444 else if (argv[0][2] == 'P') {
2445 priority = atoi(getoptvalp(argv, 3, reqval,
2446 &skiparg));
2447 }
2448 #endif
2449 #ifdef HAVE_SETAFFINITY
2450 else if (argv[0][2] == 'c') {
2451 reqval = 1;
2452 if (argv[0][3] == 's') {
2453 cp1 = getoptvalp(argv, 4, reqval,
2454 &skiparg);
2455 srvr_affinity = atoi(cp1);
2456 if (srvr_affinity < 0) {
2457 fprintf(stderr,
2458 "invalid srvr_affinity "
2459 "= %d\n",
2460 srvr_affinity);
2461 fflush(stderr);
2462 exit(1);
2463 }
2464 }
2465 else {
2466 cp1 = getoptvalp(argv, 3, reqval,
2467 &skiparg);
2468 affinity = atoi(cp1);
2469 if ((affinity < 0) ||
2470 (affinity >= CPU_SETSIZE)) {
2471 fprintf(stderr,
2472 "invalid affinity "
2473 "= %d\n", affinity);
2474 fflush(stderr);
2475 exit(1);
2476 }
2477 if ((cp2 = strchr(cp1, '/'))) {
2478 srvr_affinity = atoi(cp2 + 1);
2479 if (srvr_affinity < 0) {
2480 fprintf(stderr,
2481 "invalid "
2482 "srvr_affinity "
2483 "= %d\n",
2484 srvr_affinity);
2485 fflush(stderr);
2486 exit(1);
2487 }
2488 }
2489 }
2490 }
2491 #endif
2492 else {
2493 if (argv[0][2]) {
2494 fprintf(stderr, "invalid x option \"%s\"\n", &argv[0][2]);
2495 fflush(stderr);
2496 exit(1);
2497 }
2498 else {
2499 fprintf(stderr, "invalid null x option\n");
2500 fflush(stderr);
2501 exit(1);
2502 }
2503 }
2504 break;
2505 case '3':
2506 thirdparty = 1;
2507 break;
2508 case 'm':
2509 reqval = 0;
2510 if (argv[0][2] == 'a') {
2511 ssm = 0;
2512 cp1 = getoptvalp(argv, 3, reqval, &skiparg);
2513 }
2514 else if (argv[0][2] == 's') {
2515 #ifdef MCAST_JOIN_SOURCE_GROUP
2516 ssm = 1;
2517 cp1 = getoptvalp(argv, 3, reqval, &skiparg);
2518 #else
2519 fprintf(stderr,
2520 "This system does not support SSM\n");
2521 fflush(stderr);
2522 exit(1);
2523 #endif
2524 }
2525 else {
2526 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2527 }
2528 if (*cp1)
2529 mc_param = atoi(cp1);
2530 else
2531 mc_param = 1;
2532 if ((mc_param < 1) || (mc_param > 255)) {
2533 fprintf(stderr, "invalid multicast ttl = %d\n", mc_param);
2534 fflush(stderr);
2535 exit(1);
2536 }
2537 multicast = mc_param;
2538 break;
2539 case 'g':
2540 reqval = 1;
2541 mc_addr = getoptvalp(argv, 2, reqval, &skiparg);
2542 break;
2543 case 'M':
2544 reqval = 1;
2545 datamss = atoi(getoptvalp(argv, 2, reqval, &skiparg));
2546 if (datamss < 0) {
2547 fprintf(stderr, "invalid datamss = %d\n", datamss);
2548 fflush(stderr);
2549 exit(1);
2550 }
2551 break;
2552 case 'c':
2553 reqval = 1;
2554 cp1 = getoptvalp(argv, 2, reqval, &skiparg);
2555 tos = strtol(cp1, NULL, 0);
2556 if (*cp1)
2557 ch = *(cp1 + strlen(cp1) - 1);
2558 else
2559 ch = '\0';
2560 if ((ch == 'p') || (ch == 'P')) {
2561 /* Precedence */
2562 if (tos > 7) {
2563 fprintf(stderr, "invalid precedence = %d\n", tos);
2564 fflush(stderr);
2565 exit(1);
2566 }
2567 tos <<= 5;
2568 }
2569 else if ((ch != 't') && (ch != 'T')) {
2570 /* DSCP */
2571 if (tos > 63) {
2572 fprintf(stderr, "invalid dscp = %d\n", tos);
2573 fflush(stderr);
2574 exit(1);
2575 }
2576 tos <<= 2;
2577 }
2578 if (tos > 255) {
2579 fprintf(stderr, "invalid tos = %d\n", tos);
2580 fflush(stderr);
2581 exit(1);
2582 }
2583 break;
2584 case 'a':
2585 retry_server = 1;
2586 break;
2587 case '-':
2588 if (strcmp(&argv[0][2], "nofork") == 0) {
2589 nofork=1;
2590 }
2591 else if (strcmp(&argv[0][2], "no3rdparty") == 0) {
2592 no3rd=1;
2593 }
2594 else if (strcmp(&argv[0][2],
2595 "idle-data-timeout") == 0) {
2596 if ((cp1 = strchr(argv[1], '/'))) {
2597 if (strchr(cp1 + 1, '/')) {
2598 if (sscanf(argv[1],
2599 "%lf/%lf/%lf",
2600 &idle_data_min,
2601 &default_idle_data,
2602 &idle_data_max) != 3) {
2603 fprintf(stderr, "error scanning idle-data-timeout parameter = %s\n", argv[1]);
2604 fflush(stderr);
2605 exit(1);
2606 }
2607 if (idle_data_min <= 0.0) {
2608 fprintf(stderr, "invalid value for idle-data-timeout minimum = %f\n", idle_data_min);
2609 fflush(stderr);
2610 exit(1);
2611 }
2612 if (default_idle_data <= 0.0) {
2613 fprintf(stderr, "invalid value for idle-data-timeout default = %f\n", default_idle_data);
2614 fflush(stderr);
2615 exit(1);
2616 }
2617 if (idle_data_max <= 0.0) {
2618 fprintf(stderr, "invalid value for idle-data-timeout maximum = %f\n", idle_data_max);
2619 fflush(stderr);
2620 exit(1);
2621 }
2622 if (idle_data_max <
2623 idle_data_min) {
2624 fprintf(stderr, "error: idle-data-timeout maximum of %f < minimum of %f\n", idle_data_max, idle_data_min);
2625 fflush(stderr);
2626 exit(1);
2627 }
2628 }
2629 else {
2630 fprintf(stderr, "invalid idle-data-timeout parameter = %s\n", argv[1]);
2631 fflush(stderr);
2632 exit(1);
2633 }
2634 }
2635 else {
2636 sscanf(argv[1], "%lf", &idle_data_min);
2637 if (idle_data_min <= 0.0) {
2638 fprintf(stderr, "invalid value for idle-data-timeout = %f\n", idle_data_min);
2639 fflush(stderr);
2640 exit(1);
2641 }
2642 idle_data_max = idle_data_min;
2643 default_idle_data = idle_data_min;
2644 }
2645 argv++;
2646 argc--;
2647 }
2648 else if (strcmp(&argv[0][2], "single-threaded") == 0) {
2649 single_threaded=1;
2650 }
2651 else if (strcmp(&argv[0][2], "packet-burst") == 0) {
2652 maxburst = atoi(argv[1]);
2653 if (maxburst <= 0) {
2654 fprintf(stderr,
2655 "invalid maxburst = %d\n",
2656 maxburst);
2657 fflush(stderr);
2658 exit(1);
2659 }
2660 argv++;
2661 argc--;
2662 }
2663 #ifdef IPV6_V6ONLY
2664 else if (strcmp(&argv[0][2], "disable-v4-mapped") == 0) {
2665 v4mapped=0;
2666 }
2667 else if (strcmp(&argv[0][2], "enable-v4-mapped") == 0) {
2668 v4mapped=1;
2669 }
2670 #endif
2671 else {
2672 goto usage;
2673 }
2674 break;
2675 case 'h':
2676 default:
2677 goto usage;
2678 }
2679 argv++;
2680 argc--;
2681 if (skiparg) {
2682 argv++;
2683 argc--;
2684 }
2685 }
2686
2687 if (argc > 2) goto usage;
2688 if (trans && (argc < 1)) goto usage;
2689 if (clientserver && (argc != 0)) goto usage;
2690
2691 if (!clientserver && !trans && (argc < 1)) {
2692 fprintf(stderr,
2693 "nuttcp: Warning: Using obsolete \"classic\" mode:\n");
2694 fprintf(stderr,
2695 " Automatically switching to "
2696 "oneshot server mode "
2697 "(\"nuttcp -1\")\n");
2698 oneshot = 1;
2699 trans = 0;
2700 clientserver = 1;
2701 brief = 0;
2702 verbose = 1;
2703 }
2704
2705 host3 = NULL;
2706 if (argc == 2) {
2707 host3 = argv[1];
2708 if (strlen(host3) > HOSTNAMELEN) {
2709 fprintf(stderr, "3rd party host '%s' too long\n", host3);
2710 fflush(stderr);
2711 exit(1);
2712 }
2713 cp1 = host3;
2714 while (*cp1) {
2715 if (!isalnum((int)(*cp1)) && (*cp1 != '-') && (*cp1 != '.')
2716 && (*cp1 != ':') && (*cp1 != '/')
2717 && (*cp1 != '+') && (*cp1 != '=')) {
2718 fprintf(stderr, "invalid 3rd party host '%s'\n", host3);
2719 fflush(stderr);
2720 exit(1);
2721 }
2722 cp1++;
2723 }
2724 }
2725
2726 if (multicast) {
2727 udp = 1;
2728 if (!buflenopt) buflen = DEFAULT_MC_UDPBUFLEN;
2729 nstream = 1;
2730 }
2731
2732 if (mc_addr && !multicast) {
2733 fprintf(stderr, "can't use \"-g\" option for non-multicast\n");
2734 fflush(stderr);
2735 exit(1);
2736 }
2737 if (mc_addr && !*mc_addr) {
2738 fprintf(stderr, "no multicast IP address specified for "
2739 "\"-g\" option\n");
2740 fflush(stderr);
2741 exit(1);
2742 }
2743
2744 #ifdef AF_INET6
2745 if (!inet_pton(AF_INET6, HI_MC6, &hi_mc6)) {
2746 err("inet_pton");
2747 }
2748 if (!inet_pton(AF_INET6, HI_MC6_ASM, &hi_mc6_asm)) {
2749 err("inet_pton");
2750 }
2751 #endif
2752
2753 if (udp && !haverateopt)
2754 rate = DEFAULT_UDP_RATE;
2755
2756 bzero((char *)&frominet, sizeof(frominet));
2757 bzero((char *)&clientaddr, sizeof(clientaddr));
2758
2759 #ifdef AF_INET6
2760 bzero((char *)&clientaddr6, sizeof(clientaddr6));
2761 clientscope6 = 0;
2762 #endif
2763
2764 if (!nbuf) {
2765 if (timeout == 0.0) {
2766 if (sinkmode) {
2767 timeout = DEFAULT_TIMEOUT;
2768 itimer.it_value.tv_sec = timeout;
2769 itimer.it_value.tv_usec =
2770 (timeout - itimer.it_value.tv_sec)
2771 *1000000;
2772 }
2773 nbuf = INT_MAX;
2774 }
2775 }
2776
2777 if (srvrwin == -1) {
2778 srvrwin = sendwin;
2779 }
2780
2781 if ((argc == 0) && !explicitaf) {
2782 domain = PF_INET;
2783 af = AF_INET;
2784 }
2785
2786 if (multilink) {
2787 if (nstream == 1) {
2788 fprintf(stderr, "Warning: multilink mode not meaningful for a single stream\n");
2789 fflush(stderr);
2790 }
2791 }
2792
2793 if (argc >= 1) {
2794 host = argv[0];
2795 if ((cp1 = strchr(host, '+'))) {
2796 *cp1++ = '\0';
2797 if (*cp1)
2798 stride = cp1;
2799 }
2800 if (multilink) {
2801 if (stride) {
2802 fprintf(stderr, "don't use both multilink and address stride\n");
2803 fflush(stderr);
2804 exit(1);
2805 }
2806 if ((cp1 = strchr(host, '/')) && strchr(cp1 + 1, '/')) {
2807 fprintf(stderr, "multilink mode not compatible with multiple hosts %s\n", host);
2808 fflush(stderr);
2809 exit(1);
2810 }
2811 }
2812 hostaddr = NULL;
2813 implicit_hostaddr = 0;
2814 if ((cp1 = strchr(host, '='))) {
2815 *cp1++ = '\0';
2816 if (strchr(cp1, '/')) {
2817 fprintf(stderr, "host=addr format not supported for multiple control/data paths\n");
2818 fflush(stderr);
2819 exit(1);
2820 }
2821 if (*cp1) {
2822 if (*cp1 == '=') {
2823 implicit_hostaddr = 1;
2824 cp1++;
2825 }
2826 hostaddr = cp1;
2827 if (!implicit_hostaddr)
2828 host = hostaddr;
2829 }
2830 }
2831 stream_idx = 0;
2832 res[0] = NULL;
2833 cp1 = host;
2834 if (host[strlen(host) - 1] == '/') {
2835 fprintf(stderr, "bad hostname or address: trailing '/' not allowed: %s\n", host);
2836 fflush(stderr);
2837 exit(1);
2838 }
2839 if (strchr(host, '/') && !trans && !reverse) {
2840 fprintf(stderr, "multiple control/data paths not supported for receive\n");
2841 fflush(stderr);
2842 exit(1);
2843 }
2844 if (strchr(host, '/') && trans && reverse) {
2845 fprintf(stderr, "multiple control/data paths not supported for flipped transmit\n");
2846 fflush(stderr);
2847 exit(1);
2848 }
2849 if (host[0] == '/') {
2850 host++;
2851 cp1++;
2852 stream_idx = 1;
2853 }
2854 else if ((cp2 = strchr(host, '/'))) {
2855 host = cp2 + 1;
2856 }
2857
2858 while (stream_idx <= nstream) {
2859 bzero(&hints, sizeof(hints));
2860 res[stream_idx] = NULL;
2861 if (explicitaf) hints.ai_family = af;
2862 if (udp)
2863 hints.ai_socktype = SOCK_DGRAM;
2864 else
2865 hints.ai_socktype = SOCK_STREAM;
2866 if ((cp2 = strchr(cp1, '/'))) {
2867 if (stream_idx == nstream) {
2868 fprintf(stderr, "bad hostname or address: too many data paths for nstream=%d: %s\n", nstream, argv[0]);
2869 fflush(stderr);
2870 exit(1);
2871 }
2872 *cp2 = '\0';
2873 }
2874 if (!(multilink && (stream_idx > 1)) &&
2875 (error_num = getaddrinfo(cp1, NULL, &hints,
2876 &res[stream_idx]))) {
2877 if (implicit_hostaddr && hostaddr) {
2878 if (res[stream_idx]) {
2879 freeaddrinfo(res[stream_idx]);
2880 res[stream_idx] = NULL;
2881 }
2882 error_num =
2883 getaddrinfo(hostaddr, NULL,
2884 &hints,
2885 &res[stream_idx]);
2886 }
2887 if (error_num) {
2888 if (cp2)
2889 *cp2++ = '/';
2890 if (hostaddr) {
2891 if (implicit_hostaddr)
2892 *(hostaddr - 2) = '=';
2893 else
2894 *(hostaddr - 1) = '=';
2895 }
2896 fprintf(stderr, "bad hostname or address: %s: %s\n", gai_strerror(error_num), argv[0]);
2897 fflush(stderr);
2898 exit(1);
2899 }
2900 if (implicit_hostaddr && hostaddr &&
2901 (stream_idx == 1)) {
2902 if (stride)
2903 *(stride - 1) = '+';
2904 cp3 = hostaddr;
2905 while (*cp3) {
2906 *(cp3 - 1) = *cp3;
2907 cp3++;
2908 }
2909 *(cp3 - 1) = '\0';
2910 hostaddr--;
2911 implicit_hostaddr = 0;
2912 if (stride) {
2913 stride--;
2914 *(stride - 1) = '\0';
2915 }
2916 }
2917 }
2918 else if (multilink && (stream_idx > 1)) {
2919 if (res[stream_idx - 1]->ai_next)
2920 res[stream_idx] =
2921 res[stream_idx - 1]->ai_next;
2922 else
2923 res[stream_idx] = res[1];
2924 }
2925 else if (!(multilink && (stream_idx > 1)) &&
2926 implicit_hostaddr && hostaddr) {
2927 if (stride) {
2928 strcat(host, "+");
2929 strncat(host, stride, ADDRSTRLEN);
2930 *(hostaddr - 2) = '\0';
2931 stride = hostaddr - 1;
2932 }
2933 hostaddr = NULL;
2934 }
2935 af = res[stream_idx]->ai_family;
2936 /*
2937 * At the moment PF_ matches AF_ but are maintained seperate and the socket
2938 * call is supposed to be PF_
2939 *
2940 * For now we set domain from the address family we looked up, but if these
2941 * ever get changed to not match some code will have to go here to find the
2942 * domain appropriate for the family
2943 */
2944 domain = af;
2945 stream_idx++;
2946 if (cp2) {
2947 *cp2++ = '/';
2948 cp1 = cp2;
2949 }
2950 else
2951 cp1 = host;
2952 }
2953 if (!res[0]) {
2954 if ((cp1 = strchr(host, '/')))
2955 *cp1 = '\0';
2956 if ((error_num = getaddrinfo(host, NULL, &hints, &res[0]))) {
2957 if (cp1)
2958 *cp1++ = '/';
2959 fprintf(stderr, "bad hostname or address: %s: %s\n", gai_strerror(error_num), argv[0]);
2960 fflush(stderr);
2961 exit(1);
2962 }
2963 af = res[0]->ai_family;
2964 /* see previous comment about domain */
2965 domain = af;
2966 if (cp1)
2967 *cp1 = '/';
2968 }
2969 if (hostaddr) {
2970 host = argv[0];
2971 if (implicit_hostaddr)
2972 *(hostaddr - 2) = '=';
2973 else
2974 *(hostaddr - 1) = '=';
2975 }
2976 }
2977
2978 ipad_stride.ip32 = 0;
2979 if (stride) {
2980 if (strlen(stride) >= ADDRSTRLEN) {
2981 fprintf(stderr, "address stride '%s' too long\n", stride);
2982 fflush(stderr);
2983 exit(1);
2984 }
2985 if (nstream == 1) {
2986 fprintf(stderr, "Warning: stride %s not meaningful for a single stream\n", stride);
2987 fflush(stderr);
2988 }
2989 if (udp) {
2990 fprintf(stderr, "stride %s not valid for UDP\n",
2991 stride);
2992 fflush(stderr);
2993 exit(1);
2994 }
2995 if ((cp1 = strchr(argv[0], '/')) && strchr(cp1 + 1, '/')) {
2996 fprintf(stderr, "stride %s not compatible with multiple hosts %s\n", stride, argv[0]);
2997 fflush(stderr);
2998 exit(1);
2999 }
3000 if (af == AF_INET) {
3001 if (strchr(stride, '.')) {
3002 error_num = inet_pton(AF_INET, stride,
3003 ipad_stride.buf);
3004 if (error_num == 0) {
3005 fprintf(stderr,
3006 "stride %s not in correct presentation format\n",
3007 stride);
3008 fflush(stderr);
3009 exit(1);
3010 }
3011 else if (error_num < 0)
3012 err("inet_pton: stride");
3013 }
3014 else {
3015 ipad_stride.ip32 = atoi(stride);
3016 ipad_stride.ip32 = htonl(ipad_stride.ip32);
3017 }
3018 }
3019 else {
3020 fprintf(stderr, "stride %s not valid for IPv6\n",
3021 stride);
3022 fflush(stderr);
3023 exit(1);
3024 }
3025 *(stride - 1) = '+';
3026 }
3027
3028 if (host3 && !strchr(host3, '=') && !strchr(host3, '/')) {
3029 cp1 = strchr(host3, '+');
3030 if (cp1) {
3031 if (strlen(cp1 + 1) >= ADDRSTRLEN) {
3032 fprintf(stderr, "3rd party address stride '%s' too long\n", cp1 + 1);
3033 fflush(stderr);
3034 exit(1);
3035 }
3036 *cp1 = '\0';
3037 }
3038 if (inet_pton(af, host3, &dummy) != 1) {
3039 bzero(&hints, sizeof(hints));
3040 hints.ai_family = af;
3041 if (udp)
3042 hints.ai_socktype = SOCK_DGRAM;
3043 else
3044 hints.ai_socktype = SOCK_STREAM;
3045 host3res = NULL;
3046 error_num = getaddrinfo(host3, NULL, &hints, &host3res);
3047 if (error_num == 0) {
3048 nameinfo_flags = NI_NUMERICHOST;
3049 error_num = getnameinfo(host3res->ai_addr,
3050 host3res->ai_addrlen,
3051 host3addr, ADDRSTRLEN,
3052 NULL, 0,
3053 nameinfo_flags);
3054 }
3055 if (host3res) {
3056 freeaddrinfo(host3res);
3057 host3res = NULL;
3058 }
3059 if (error_num == 0) {
3060 strncpy(host3buf, host3, HOSTNAMELEN);
3061 strcat(host3buf, "==");
3062 strncat(host3buf, host3addr, ADDRSTRLEN);
3063 if (cp1) {
3064 strcat(host3buf, "+");
3065 strncat(host3buf, cp1 + 1, ADDRSTRLEN);
3066 }
3067 host3 = host3buf;
3068 }
3069 }
3070 if (cp1)
3071 *cp1 = '+';
3072 }
3073
3074 if (!port) {
3075 if (af == AF_INET) {
3076 if ((sp = getservbyname( "nuttcp-data", "tcp" )))
3077 port = ntohs(sp->s_port);
3078 else
3079 port = DEFAULT_PORT;
3080 }
3081 #ifdef AF_INET6
3082 else if (af == AF_INET6) {
3083 if ((sp = getservbyname( "nuttcp6-data", "tcp" )))
3084 port = ntohs(sp->s_port);
3085 else {
3086 if ((sp = getservbyname( "nuttcp-data", "tcp" )))
3087 port = ntohs(sp->s_port);
3088 else
3089 port = DEFAULT_PORT;
3090 }
3091 }
3092 #endif
3093 else {
3094 err("unsupported AF");
3095 }
3096 }
3097
3098 if (!ctlport) {
3099 if (af == AF_INET) {
3100 if ((sp = getservbyname( "nuttcp", "tcp" )))
3101 ctlport = ntohs(sp->s_port);
3102 else
3103 ctlport = DEFAULT_CTLPORT;
3104 }
3105 #ifdef AF_INET6
3106 else if (af == AF_INET6) {
3107 if ((sp = getservbyname( "nuttcp6", "tcp" )))
3108 ctlport = ntohs(sp->s_port);
3109 else {
3110 if ((sp = getservbyname( "nuttcp", "tcp" )))
3111 ctlport = ntohs(sp->s_port);
3112 else
3113 ctlport = DEFAULT_CTLPORT;
3114 }
3115 }
3116 #endif
3117 else {
3118 err("unsupported AF");
3119 }
3120 }
3121
3122 if ((port < 1024) || ((port + nstream - 1) > 65535)) {
3123 fprintf(stderr, "invalid port/nstream = %d/%d\n", port, nstream);
3124 fflush(stderr);
3125 exit(1);
3126 }
3127
3128 if ((ctlport >= port) && (ctlport <= (port + nstream - 1))) {
3129 fprintf(stderr, "ctlport = %d overlaps port/nstream = %d/%d\n", ctlport, port, nstream);
3130 fflush(stderr);
3131 exit(1);
3132 }
3133
3134 if (timeout && (interval >= timeout)) {
3135 fprintf(stderr, "ignoring interval=%f which is greater than or equal timeout=%f\n", interval, timeout);
3136 fflush(stderr);
3137 interval = 0;
3138 }
3139
3140 if (iratesss) {
3141 if (udp) {
3142 fprintf(stderr, "ignoring smoothed slow start option for udp transfer\n");
3143 fflush(stderr);
3144 iratesss = 0;
3145 }
3146 if (maxburst > 1) {
3147 fprintf(stderr, "ignoring maxburst option with smoothed slow start option\n");
3148 fflush(stderr);
3149 maxburst = 1;
3150 }
3151 if (nstream > 1) {
3152 fprintf(stderr, "ignoring smoothed slow start option for multiple streams\n");
3153 fflush(stderr);
3154 iratesss = 0;
3155 }
3156 if (format & NORETRANS) {
3157 fprintf(stderr, "can't do smoothed slow start if no retransmission info\n");
3158 fflush(stderr);
3159 iratesss = 0;
3160 }
3161 if (!(format & NORETRANS) && (format & NOCWND)) {
3162 fprintf(stderr, "can't do smoothed slow start if no congestion window info\n");
3163 fflush(stderr);
3164 iratesss = 0;
3165 }
3166 }
3167
3168 if (clientserver) {
3169 if (trans) {
3170 fprintf(stderr, "server mode only allowed for receiver\n");
3171 goto usage;
3172 }
3173 udp = 0;
3174 start_idx = 0;
3175 ident[0] = '\0';
3176 if (af == AF_INET) {
3177 union peer46 {
3178 struct sockaddr_in peer4;
3179 #ifdef AF_INET6
3180 struct sockaddr_in6 peer6;
3181 #endif
3182 } peer;
3183 socklen_t peerlen = sizeof(peer);
3184 if (getpeername(0, (struct sockaddr *)&peer, &peerlen) == 0) {
3185 #ifndef AF_INET6
3186 if (peer.peer4.sin_family == AF_INET)
3187 #else
3188 if ((peer.peer4.sin_family == AF_INET) ||
3189 (peer.peer6.sin6_family == AF_INET6))
3190 #endif
3191 {
3192 #ifdef AF_INET6
3193 if (!explicitaf &&
3194 (peer.peer6.sin6_family == AF_INET6)) {
3195 af = AF_INET6;
3196 domain = af;
3197 clientaddr6 = peer.peer6.sin6_addr;
3198 clientscope6 = peer.peer6.sin6_scope_id;
3199 client_ipaddr.ss.ss_family = AF_INET6;
3200 client_ipaddr.sin6.sin6_addr =
3201 clientaddr6;
3202 }
3203 else {
3204 clientaddr = peer.peer4.sin_addr;
3205 client_ipaddr.ss.ss_family = AF_INET;
3206 client_ipaddr.sin.sin_addr = clientaddr;
3207 }
3208 #else
3209 clientaddr = peer.peer4.sin_addr;
3210 client_ipaddr.ss.ss_family = AF_INET;
3211 client_ipaddr.sin.sin_addr = clientaddr;
3212 #endif
3213 inetd = 1;
3214 oneshot = 1;
3215 start_idx = 1;
3216 }
3217 }
3218 }
3219 #ifdef AF_INET6
3220 else if (af == AF_INET6) {
3221 struct sockaddr_in6 peer;
3222 socklen_t peerlen = sizeof(peer);
3223 if (getpeername(0, (struct sockaddr *)&peer, &peerlen) == 0) {
3224 if ((peer.sin6_family == AF_INET) ||
3225 (peer.sin6_family == AF_INET6)) {
3226 clientaddr6 = peer.sin6_addr;
3227 clientscope6 = peer.sin6_scope_id;
3228 client_ipaddr.ss.ss_family = AF_INET6;
3229 client_ipaddr.sin6.sin6_addr = clientaddr6;
3230 inetd = 1;
3231 oneshot = 1;
3232 start_idx = 1;
3233 }
3234 }
3235 }
3236 #endif
3237 else {
3238 err("unsupported AF");
3239 }
3240 }
3241
3242 if (clientserver && !inetd && !oneshot && !sinkmode) {
3243 fprintf(stderr, "option \"-s\" invalid with \"-S\" server mode\n");
3244 fprintf(stderr, "option \"-s\" can be used with \"-1\" oneshot server mode\n");
3245 fflush(stderr);
3246 exit(1);
3247 }
3248
3249 #ifdef HAVE_SETPRIO
3250 if (priority) {
3251 if (setpriority(PRIO_PROCESS, 0, priority) != 0)
3252 err("couldn't change priority");
3253 }
3254 #endif
3255
3256 #ifdef HAVE_SETAFFINITY
3257 if ((affinity >= 0) && !host3) {
3258 if ((ncores = sysconf(_SC_NPROCESSORS_CONF)) <= 0)
3259 err("sysconf: couldn't get _SC_NPROCESSORS_CONF");
3260 CPU_ZERO(&cpu_set);
3261 CPU_SET(affinity, &cpu_set);
3262 if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0)
3263 err("couldn't change CPU affinity");
3264 }
3265 #endif
3266
3267 if (argc >= 1) {
3268 start_idx = 0;
3269 client = 1;
3270 clientserver = 1;
3271 }
3272
3273 if (clientserver && !client && srcctlport) {
3274 fprintf(stderr, "can't specify source control port in server mode\n");
3275 fflush(stderr);
3276 exit(1);
3277 }
3278
3279 if (!host3 && clientserver && client && (ssm < 0)) {
3280 if (af == AF_INET) {
3281 ssm = 0;
3282 }
3283 #ifdef AF_INET6
3284 else if (af == AF_INET6) {
3285 #ifdef MCAST_JOIN_SOURCE_GROUP
3286 ssm = 1;
3287 #else
3288 ssm = 0;
3289 #endif
3290 }
3291 #endif
3292 }
3293
3294 mc_af = af;
3295 if (!host3 && clientserver && client && mc_addr) {
3296 bzero(&hints, sizeof(hints));
3297 if (explicitaf)
3298 hints.ai_family = af;
3299 if (udp)
3300 hints.ai_socktype = SOCK_DGRAM;
3301 else
3302 hints.ai_socktype = SOCK_STREAM;
3303 mcres = NULL;
3304 error_num = getaddrinfo(mc_addr, NULL, &hints, &mcres);
3305 if (error_num) {
3306 fprintf(stderr, "getaddrinfo: "
3307 "bad multicast IP address: %s: %s\n",
3308 mc_addr, gai_strerror(error_num));
3309 fflush(stderr);
3310 exit(1);
3311 }
3312 nameinfo_flags = NI_NUMERICHOST;
3313 error_num = getnameinfo(mcres->ai_addr, mcres->ai_addrlen,
3314 mcgaddr, ADDRSTRLEN, NULL, 0,
3315 nameinfo_flags);
3316 if (error_num) {
3317 fprintf(stderr, "getnameinfo: "
3318 "bad multicast IP address: %s: %s\n",
3319 mc_addr, gai_strerror(error_num));
3320 fflush(stderr);
3321 exit(1);
3322 }
3323 mc_addr = mcgaddr;
3324 if (mcres->ai_family == AF_INET) {
3325 struct sockaddr_in *group;
3326 struct in_addr ipv4_mcaddr;
3327
3328 group = (struct sockaddr_in *)mcres->ai_addr;
3329 bcopy((char *)&(group->sin_addr), (char *)&ipv4_mcaddr,
3330 sizeof(struct in_addr));
3331 if (ssm) {
3332 if (((htonl(ipv4_mcaddr.s_addr) & 0xFF000000) !=
3333 (HI_MC_SSM << 24))) {
3334 fprintf(stderr, "bad SSM multicast "
3335 "IP address: %s: "
3336 "use 232.x.y.z\n",
3337 mcgaddr);
3338 fflush(stderr);
3339 exit(1);
3340 }
3341 }
3342 else {
3343 if (((htonl(ipv4_mcaddr.s_addr) & 0xFF000000) !=
3344 (HI_MC << 24))) {
3345 fprintf(stderr, "bad ASM multicast "
3346 "IP address: %s: "
3347 "use 231.x.y.z\n",
3348 mcgaddr);
3349 fflush(stderr);
3350 exit(1);
3351 }
3352 }
3353 }
3354 #ifdef AF_INET6
3355 if (mcres->ai_family == AF_INET6) {
3356 struct sockaddr_in6 *group;
3357
3358 group = (struct sockaddr_in6 *)mcres->ai_addr;
3359 if (ssm) {
3360 if ((bcmp((char *)&(group->sin6_addr),
3361 (char *)&hi_mc6,
3362 HI_MC6_LEN - 1) != 0) ||
3363 (group->sin6_addr.s6_addr[HI_MC6_LEN - 1]
3364 < 0x80)) {
3365 fprintf(stderr,
3366 "bad SSM multicast IP address: "
3367 "%s: use ff3e::[8-f]xxx:yyyy\n",
3368 mcgaddr);
3369 fflush(stderr);
3370 exit(1);
3371 }
3372 }
3373 else {
3374 if ((bcmp((char *)&(group->sin6_addr),
3375 (char *)&hi_mc6_asm,
3376 HI_MC6_ASM_LEN) != 0)) {
3377 fprintf(stderr,
3378 "bad ASM multicast IP address: "
3379 "%s: use ff2e::wwww:xxxx:"
3380 "yyyy:zzzz\n",
3381 mcgaddr);
3382 fflush(stderr);
3383 exit(1);
3384 }
3385 }
3386 }
3387 #endif
3388 mc_af = mcres->ai_family;
3389 }
3390
3391 if (irate < 0) {
3392 if (do_jitter)
3393 irate = 1;
3394 else
3395 irate = 0;
3396 }
3397 if (do_jitter && (rate == MAXRATE)) {
3398 fprintf(stderr, "jitter option not supported for "
3399 "unlimited rate\n");
3400 fflush(stderr);
3401 exit(1);
3402 }
3403 if (do_jitter && !irate) {
3404 fprintf(stderr, "jitter option requires"
3405 " \"-Ri\" instantaneous rate limit option\n");
3406 fflush(stderr);
3407 exit(1);
3408 }
3409 if (interval && !clientserver) {
3410 fprintf(stderr, "interval option only supported for client/server mode\n");
3411 fflush(stderr);
3412 exit(1);
3413 }
3414 if (reverse && !clientserver) {
3415 fprintf(stderr, "flip option only supported for client/server mode\n");
3416 fflush(stderr);
3417 exit(1);
3418 }
3419 if (reverse && udp) {
3420 fprintf(stderr, "flip option not supported for UDP\n");
3421 fflush(stderr);
3422 exit(1);
3423 }
3424 if (client && !sinkmode && udp) {
3425 fprintf(stderr, "Warning: UDP transfers unreliable for non-sinkmode - use at own risk\n");
3426 fflush(stderr);
3427 }
3428 if (traceroute) {
3429 nstream = 1;
3430 if (!clientserver) {
3431 fprintf(stderr, "traceroute option only supported for client/server mode\n");
3432 fflush(stderr);
3433 exit(1);
3434 }
3435 }
3436 if (host3) {
3437 if (!clientserver) {
3438 fprintf(stderr, "3rd party nuttcp only supported for client/server mode\n");
3439 fflush(stderr);
3440 exit(1);
3441 }
3442 }
3443
3444 if (udp && (buflen < 5)) {
3445 fprintf(stderr, "UDP buflen = %d < 5, set to 5\n", buflen);
3446 buflen = 5; /* send more than the sentinel size */
3447 }
3448
3449 if (udp && (buflen > MAXUDPBUFLEN)) {
3450 fprintf(stderr, "UDP buflen = %d > MAXUDPBUFLEN, set to %d\n",
3451 buflen, MAXUDPBUFLEN);
3452 buflen = MAXUDPBUFLEN;
3453 }
3454
3455 if (nbuf_bytes && !host3 && !traceroute) {
3456 nbuf /= buflen;
3457 }
3458
3459 if ((rate != MAXRATE) && rate_pps && !host3 && !traceroute) {
3460 uint64_t llrate = rate;
3461
3462 llrate *= ((double)buflen * 8 / 1000);
3463 rate = llrate;
3464 }
3465
3466 if (udp && interval) {
3467 if (buflen >= 32)
3468 udplossinfo = 1;
3469 else
3470 fprintf(stderr, "Unable to print interval loss information if UDP buflen < 32\n");
3471 }
3472
3473 if (udp && (do_jitter & JITTER_IGNORE_OOO)) {
3474 if (buflen >= 32)
3475 udplossinfo = 1;
3476 else
3477 fprintf(stderr, "Unable to check out of order when calculating jitter if UDP buflen < 32\n");
3478 }
3479
3480 if (!udp && trans) {
3481 if (buflen >= 32) {
3482 retransinfo = 1;
3483 #if defined(linux)
3484 cwndinfo = 1;
3485 #endif
3486 b_flag = 1;
3487 }
3488 else
3489 fprintf(stderr, "Unable to print retransmission information if TCP buflen < 32\n");
3490 }
3491
3492 if (udp && do_owd && (buflen < 16)) {
3493 fprintf(stderr, "Unable to calculate one-way delay if UDP buflen < 16\n");
3494 }
3495
3496 ivers = vers_major*10000 + vers_minor*100 + vers_delta;
3497
3498 mallocsize = buflen;
3499 if (mallocsize < MINMALLOC) mallocsize = MINMALLOC;
3500 #if defined(linux)
3501 if (directio) {
3502 error_num = posix_memalign((void **)&buf, sysconf(_SC_PAGESIZE),
3503 mallocsize);
3504 if (error_num) {
3505 errno = error_num;
3506 err("posix_memalign");
3507 }
3508 }
3509 else
3510 #endif
3511 if ((buf = (char *)malloc(mallocsize)) == (char *)NULL)
3512 err("malloc");
3513
3514 pattern( buf, buflen );
3515
3516 #ifdef SIGPIPE
3517 signal(SIGPIPE, sigpipe);
3518 #endif
3519
3520 signal(SIGINT, sigint);
3521
3522 if (clientserver && client && !thirdparty &&
3523 beta && !(format & NOBETAMSG) && (do_jitter || do_owd)) {
3524 fprintf(stderr, "nuttcp-%d.%d.%d: ",
3525 vers_major, vers_minor, vers_delta);
3526 fprintf(stderr, "Using beta vers: %s interface/output "
3527 "subject to change\n", BETA_FEATURES);
3528 fprintf(stderr, " (to suppress this message "
3529 "use \"-f-beta\")\n\n");
3530 fflush(stderr);
3531 }
3532
3533 doit:
3534 if (!udp && trans && (format & DEBUGRETRANS)) {
3535 sretrans = get_retrans(-1, &tcpinf);
3536 fprintf(stdout, "initial system retrans = %d\n", sretrans);
3537 }
3538 nretrans[0] = 0;
3539 cwnd[0] = 0;
3540
3541 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) {
3542 fd[stream_idx] = -1;
3543 nretrans[stream_idx] = 0;
3544 cwnd[stream_idx] = 0;
3545 }
3546
3547 for ( stream_idx = start_idx; stream_idx <= nstream; stream_idx++ ) {
3548 if (clientserver && (stream_idx == 1)) {
3549 retransinfo = 0;
3550 cwndinfo = 0;
3551 if (nstream == 1) {
3552 send_retrans = 1;
3553 read_retrans = 1;
3554 send_cwnd = 1;
3555 read_cwnd = 1;
3556 }
3557 do_retrans = 0;
3558 do_cwnd = 0;
3559 got_0retrans = 0;
3560 if (client) {
3561 if (udp && !host3 && !traceroute) {
3562 ctlconnmss = 0;
3563 optlen = sizeof(ctlconnmss);
3564 if (getsockopt(fd[0], IPPROTO_TCP, TCP_MAXSEG, (void *)&ctlconnmss, &optlen) < 0)
3565 err("get ctlconn maximum segment size didn't work");
3566 if (!ctlconnmss) {
3567 ctlconnmss = NON_JUMBO_ETHER_MSS;
3568 if (format & DEBUGMTU) {
3569 fprintf(stderr, "nuttcp%s%s: Warning: Control connection MSS reported as 0, using %d\n", trans?"-t":"-r", ident, ctlconnmss);
3570 fflush(stderr);
3571 }
3572 }
3573 else if (format & DEBUGMTU)
3574 fprintf(stderr, "ctlconnmss = %d\n", ctlconnmss);
3575 if (buflenopt) {
3576 if (buflen >
3577 ctlconnmss +
3578 TCP_UDP_HDRLEN_DELTA +
3579 TCP_TIMESTAMPS_OPTLEN) {
3580 if (format & PARSE)
3581 fprintf(stderr, "nuttcp%s%s: Warning=\"IP_frags_or_no_data_reception_since_buflen=%d_>_ctlconnmss=%d\"\n", trans?"-t":"-r", ident, buflen, ctlconnmss);
3582 else
3583 fprintf(stderr, "nuttcp%s%s: Warning: IP frags or no data reception since buflen=%d > ctlconnmss=%d\n", trans?"-t":"-r", ident, buflen, ctlconnmss);
3584 fflush(stderr);
3585 }
3586 }
3587 else {
3588 while (buflen > ctlconnmss) {
3589 buflen >>= 1;
3590 if (nbuf_bytes)
3591 nbuf <<= 1;
3592 if ((rate != MAXRATE) &&
3593 rate_pps)
3594 rate >>= 1;
3595 }
3596 }
3597 if (format & DEBUGMTU)
3598 fprintf(stderr, "buflen = %d\n", buflen);
3599 }
3600 if (!(ctlconn = fdopen(fd[0], "w")))
3601 err("fdopen: ctlconn for writing");
3602 if (!sinkmode) {
3603 if (trans)
3604 savestdin=dup(0);
3605 else {
3606 savestdout=dup(1);
3607 close(1);
3608 dup(2);
3609 }
3610 }
3611 close(0);
3612 dup(fd[0]);
3613 if (srvr_helo) {
3614 fprintf(ctlconn,
3615 HELO_FMT, vers_major,
3616 vers_minor, vers_delta);
3617 fflush(ctlconn);
3618 if (!fgets(buf, mallocsize, stdin)) {
3619 if ((errno == ECONNRESET) &&
3620 (num_connect_tries <
3621 MAX_CONNECT_TRIES) &&
3622 retry_server) {
3623 /* retry control
3624 * connection to server
3625 * for certain possibly
3626 * transient errors */
3627 fclose(ctlconn);
3628 goto doit;
3629 }
3630 mes("error from server");
3631 fprintf(stderr, "server aborted connection\n");
3632 fflush(stderr);
3633 exit(1);
3634 }
3635 if (sscanf(buf, HELO_FMT,
3636 &rvers_major,
3637 &rvers_minor,
3638 &rvers_delta) < 3) {
3639 rvers_major = 0;
3640 rvers_minor = 0;
3641 rvers_delta = 0;
3642 srvr_helo = 0;
3643 while (fgets(buf, mallocsize,
3644 stdin)) {
3645 if (strncmp(buf, "KO", 2) == 0)
3646 break;
3647 }
3648 fclose(ctlconn);
3649 goto doit;
3650 }
3651 irvers = rvers_major*10000
3652 + rvers_minor*100
3653 + rvers_delta;
3654 }
3655 if (host3 && nbuf_bytes && (irvers < 50501))
3656 nbuf /= buflen;
3657 if (host3 && (rate != MAXRATE) && rate_pps &&
3658 (irvers < 50501)) {
3659 uint64_t llrate = rate;
3660
3661 llrate *= ((double)buflen * 8 / 1000);
3662 rate = llrate;
3663 }
3664 if (host3 && !buflenopt && (irvers >= 50302))
3665 buflen = 0;
3666 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);
3667 if (irvers >= 30200)
3668 fprintf(ctlconn, ", timeout = %f", timeout);
3669 else {
3670 timeout_sec = timeout;
3671 if (itimer.it_value.tv_usec)
3672 timeout_sec++;
3673 fprintf(ctlconn, ", timeout = %ld", timeout_sec);
3674 if (!trans && itimer.it_value.tv_usec &&
3675 (brief <= 0)) {
3676 fprintf(stdout, "nuttcp-r%s: transmit timeout value rounded up to %ld second%s for old server\n",
3677 ident, timeout_sec,
3678 (timeout_sec == 1)?"":"s");
3679 }
3680 }
3681 fprintf(ctlconn, ", udp = %d, vers = %d.%d.%d", udp, vers_major, vers_minor, vers_delta);
3682 if (irvers >= 30302)
3683 fprintf(ctlconn, ", interval = %f", interval);
3684 else {
3685 if (interval) {
3686 fprintf(stdout, "nuttcp%s%s: interval option not supported by server version %d.%d.%d, need >= 3.3.2\n",
3687 trans?"-t":"-r",
3688 ident, rvers_major,
3689 rvers_minor,
3690 rvers_delta);
3691 fflush(stdout);
3692 interval = 0.0;
3693 abortconn = 1;
3694 }
3695 }
3696 if (irvers >= 30401)
3697 fprintf(ctlconn, ", reverse = %d", reverse);
3698 else {
3699 if (reverse) {
3700 fprintf(stdout, "nuttcp%s%s: flip option not supported by server version %d.%d.%d, need >= 3.4.1\n",
3701 trans?"-t":"-r",
3702 ident, rvers_major,
3703 rvers_minor,
3704 rvers_delta);
3705 fflush(stdout);
3706 reverse = 0;
3707 abortconn = 1;
3708 }
3709 }
3710 if (irvers >= 30501)
3711 fprintf(ctlconn, ", format = %d", format);
3712 else {
3713 if (format) {
3714 fprintf(stdout, "nuttcp%s%s: format option not supported by server version %d.%d.%d, need >= 3.5.1\n",
3715 trans?"-t":"-r",
3716 ident, rvers_major,
3717 rvers_minor,
3718 rvers_delta);
3719 fflush(stdout);
3720 format = 0;
3721 }
3722 }
3723 if (irvers >= 30601) {
3724 fprintf(ctlconn, ", traceroute = %d", traceroute);
3725 if (traceroute)
3726 skip_data = 1;
3727 fprintf(ctlconn, ", irate = %d", irate);
3728 }
3729 else {
3730 if (traceroute) {
3731 fprintf(stdout, "nuttcp%s%s: traceroute option not supported by server version %d.%d.%d, need >= 3.6.1\n",
3732 trans?"-t":"-r",
3733 ident, rvers_major,
3734 rvers_minor,
3735 rvers_delta);
3736 fflush(stdout);
3737 traceroute = 0;
3738 abortconn = 1;
3739 }
3740 if (irate && !trans) {
3741 fprintf(stdout, "nuttcp%s%s: instantaneous rate option not supported by server version %d.%d.%d, need >= 3.6.1\n",
3742 trans?"-t":"-r",
3743 ident, rvers_major,
3744 rvers_minor,
3745 rvers_delta);
3746 fflush(stdout);
3747 irate = 0;
3748 }
3749 }
3750 if (srvrwin && udp && (irvers < 30602)) {
3751 fprintf(stdout, "nuttcp%s%s: server version %d.%d.%d ignores UDP window parameter, need >= 3.6.2\n",
3752 trans?"-t":"-r",
3753 ident, rvers_major,
3754 rvers_minor,
3755 rvers_delta);
3756 fflush(stdout);
3757 }
3758 if ((irvers < 40101) && (format & PARSE)) {
3759 fprintf(stdout, "nuttcp%s%s: \"-fparse\" option not supported by server version %d.%d.%d, need >= 4.1.1\n",
3760 trans?"-t":"-r",
3761 ident, rvers_major,
3762 rvers_minor,
3763 rvers_delta);
3764 fflush(stdout);
3765 format &= ~PARSE;
3766 abortconn = 1;
3767 }
3768 if (irvers >= 50001) {
3769 cp1 = NULL;
3770 if (host3 && (irvers < 70101) &&
3771 (cp1 = strchr(host3, '=')))
3772 *cp1 = '\0';
3773 fprintf(ctlconn, ", thirdparty = %.*s", HOST3BUFLEN, host3 ? host3 : "_NULL_");
3774 if (host3) {
3775 skip_data = 1;
3776 fprintf(ctlconn, " , brief3 = %d", brief);
3777 }
3778 if (cp1)
3779 *cp1 = '=';
3780 }
3781 else {
3782 if (host3) {
3783 fprintf(stdout, "nuttcp%s%s: 3rd party nuttcp not supported by server version %d.%d.%d, need >= 5.0.1\n",
3784 trans?"-t":"-r",
3785 ident, rvers_major,
3786 rvers_minor,
3787 rvers_delta);
3788 fflush(stdout);
3789 host3 = NULL;
3790 abortconn = 1;
3791 }
3792 }
3793 if (host3 && !abortconn) {
3794 if (irvers >= 60205) {
3795 fprintf(ctlconn,
3796 " , ctlport3 = %hu",
3797 ctlport3);
3798 }
3799 else {
3800 if (ctlport3) {
3801 fprintf(stdout, "nuttcp%s%s: ctlport3 option not supported by server version %d.%d.%d, need >= 6.2.5\n",
3802 trans?"-t":"-r",
3803 ident,
3804 rvers_major,
3805 rvers_minor,
3806 rvers_delta);
3807 fflush(stdout);
3808 ctlport3 = 0;
3809 abortconn = 1;
3810 }
3811 }
3812 }
3813 if (irvers >= 50101) {
3814 fprintf(ctlconn, " , multicast = %d", multicast);
3815 }
3816 else {
3817 if (multicast) {
3818 fprintf(stdout, "nuttcp%s%s: multicast not supported by server version %d.%d.%d, need >= 5.1.1\n",
3819 trans?"-t":"-r",
3820 ident, rvers_major,
3821 rvers_minor,
3822 rvers_delta);
3823 fflush(stdout);
3824 multicast = 0;
3825 abortconn = 1;
3826 }
3827 }
3828 if (irvers >= 60201) {
3829 fprintf(ctlconn, " , ssm = %d", ssm);
3830 }
3831 else {
3832 if (multicast && (ssm == 1)) {
3833 fprintf(stdout, "nuttcp%s%s: ssm not supported by server version %d.%d.%d, need >= 6.2.1\n",
3834 trans?"-t":"-r",
3835 ident, rvers_major,
3836 rvers_minor,
3837 rvers_delta);
3838 fflush(stdout);
3839 ssm = 0;
3840 abortconn = 1;
3841 }
3842 }
3843 if (irvers >= 50201) {
3844 fprintf(ctlconn, " , datamss = %d", datamss);
3845 }
3846 else {
3847 if (datamss && !trans) {
3848 fprintf(stdout, "nuttcp%s%s: mss option not supported by server version %d.%d.%d, need >= 5.2.1\n",
3849 trans?"-t":"-r",
3850 ident, rvers_major,
3851 rvers_minor,
3852 rvers_delta);
3853 fflush(stdout);
3854 datamss = 0;
3855 abortconn = 1;
3856 }
3857 }
3858 if (irvers >= 50301) {
3859 fprintf(ctlconn, " , tos = %X", tos);
3860 }
3861 else {
3862 if (tos && !trans) {
3863 fprintf(stdout, "nuttcp%s%s: tos option not supported by server version %d.%d.%d, need >= 5.3.1\n",
3864 trans?"-t":"-r",
3865 ident, rvers_major,
3866 rvers_minor,
3867 rvers_delta);
3868 fflush(stdout);
3869 tos = 0;
3870 abortconn = 1;
3871 }
3872 }
3873 if (irvers >= 50501) {
3874 fprintf(ctlconn, " , nbuf_bytes = %d", nbuf_bytes);
3875 fprintf(ctlconn, " , rate_pps = %d", rate_pps);
3876 fprintf(ctlconn, " , nodelay = %d", nodelay);
3877 }
3878 else {
3879 if (host3 && udp && nbuf_bytes) {
3880 fprintf(stdout, "nuttcp%s%s: Warning: \"-n\" option in bytes for third party not supported\n",
3881 trans?"-t":"-r", ident);
3882 fprintf(stdout, " Warning: by server version %d.%d.%d, need >= 5.5.1\n",
3883 rvers_major,
3884 rvers_minor,
3885 rvers_delta);
3886 fprintf(stdout, " Warning: third party request may not transfer\n");
3887 fprintf(stdout, " Warning: desired number of bytes in some UDP cases\n");
3888 fflush(stdout);
3889 nbuf_bytes = 0;
3890 }
3891 if (host3 && udp && rate_pps) {
3892 fprintf(stdout, "nuttcp%s%s: Warning: \"-R\" option in pps for third party not supported\n",
3893 trans?"-t":"-r", ident);
3894 fprintf(stdout, " Warning: by server version %d.%d.%d, need >= 5.5.1\n",
3895 rvers_major,
3896 rvers_minor,
3897 rvers_delta);
3898 fprintf(stdout, " Warning: third party request may not produce\n");
3899 fprintf(stdout, " Warning: desired pps rate in some UDP cases\n");
3900 fflush(stdout);
3901 rate_pps = 0;
3902 }
3903 if (nodelay && !trans) {
3904 fprintf(stdout, "nuttcp%s%s: TCP_NODELAY opt not supported by server version %d.%d.%d, need >= 5.5.1\n",
3905 trans?"-t":"-r",
3906 ident, rvers_major,
3907 rvers_minor,
3908 rvers_delta);
3909 fflush(stdout);
3910 nodelay = 0;
3911 abortconn = 1;
3912 }
3913 }
3914 if (irvers >= 60206) {
3915 if (host3) {
3916 fprintf(ctlconn,
3917 " , affinity = %d",
3918 affinity);
3919 fprintf(ctlconn,
3920 " , srvr_affinity = %d",
3921 srvr_affinity);
3922 }
3923 else {
3924 fprintf(ctlconn,
3925 " , affinity = %d",
3926 srvr_affinity);
3927 }
3928 }
3929 else {
3930 if (srvr_affinity >= 0) {
3931 fprintf(stdout, "nuttcp%s%s: affinity option not supported by server version %d.%d.%d, need >= 6.2.6\n",
3932 trans?"-t":"-r",
3933 ident, rvers_major,
3934 rvers_minor,
3935 rvers_delta);
3936 fflush(stdout);
3937 srvr_affinity = -1;
3938 abortconn = 1;
3939 }
3940 }
3941 if (irvers >= 60207) {
3942 fprintf(ctlconn, " , maxburst = %d",
3943 maxburst);
3944 }
3945 else {
3946 if ((maxburst > 1) &&
3947 (!trans || host3)) {
3948 fprintf(stdout, "nuttcp%s%s: packet burst not supported by server version %d.%d.%d, need >= 6.2.7\n",
3949 trans?"-t":"-r",
3950 ident, rvers_major,
3951 rvers_minor,
3952 rvers_delta);
3953 fflush(stdout);
3954 maxburst = 1;
3955 abortconn = 1;
3956 }
3957 }
3958 if (irvers >= 70001) {
3959 fprintf(ctlconn, " , do_jitter = %d", do_jitter);
3960 }
3961 else {
3962 if (do_jitter && trans) {
3963 fprintf(stdout, "nuttcp%s%s: jitter not supported by server version %d.%d.%d, need >= 7.0.1\n",
3964 trans?"-t":"-r",
3965 ident, rvers_major,
3966 rvers_minor,
3967 rvers_delta);
3968 fflush(stdout);
3969 do_jitter = 0;
3970 abortconn = 1;
3971 }
3972 if ((do_jitter & JITTER_IGNORE_OOO) &&
3973 !trans && !(udp && interval)) {
3974 udplossinfo = 0;
3975 fprintf(stdout, "nuttcp%s%s: Unable to check out of order when calculating jitter\n",
3976 trans?"-t":"-r", ident);
3977 fprintf(stdout, " due to using older server version %d.%d.%d, need >= 7.0.1\n",
3978 rvers_major,
3979 rvers_minor,
3980 rvers_delta);
3981 fflush(stdout);
3982 }
3983 }
3984 if (irvers >= 70001) {
3985 fprintf(ctlconn, " , do_owd = %d", do_owd);
3986 }
3987 else {
3988 if (do_owd) {
3989 fprintf(stdout, "nuttcp%s%s: owd not supported by server version %d.%d.%d, need >= 7.0.1\n",
3990 trans?"-t":"-r",
3991 ident, rvers_major,
3992 rvers_minor,
3993 rvers_delta);
3994 fflush(stdout);
3995 do_owd = 0;
3996 abortconn = 1;
3997 }
3998 }
3999 if (irvers >= 70101) {
4000 fprintf(ctlconn, " , stride = %d", ipad_stride.ip32);
4001 }
4002 else {
4003 if (ipad_stride.ip32) {
4004 fprintf(stdout, "nuttcp%s%s: stride not supported by server version %d.%d.%d, need >= 7.1.1\n",
4005 trans?"-t":"-r",
4006 ident, rvers_major,
4007 rvers_minor,
4008 rvers_delta);
4009 fflush(stdout);
4010 ipad_stride.ip32 = 0;
4011 abortconn = 1;
4012 }
4013 }
4014 if (irvers >= 70101) {
4015 fprintf(ctlconn, " , multilink = %d", multilink);
4016 }
4017 else {
4018 if (multilink) {
4019 fprintf(stdout, "nuttcp%s%s: multilink not supported by server version %d.%d.%d, need >= 7.1.1\n",
4020 trans?"-t":"-r",
4021 ident, rvers_major,
4022 rvers_minor,
4023 rvers_delta);
4024 fflush(stdout);
4025 multilink = 0;
4026 abortconn = 1;
4027 }
4028 }
4029 if (irvers >= 70201) {
4030 fprintf(ctlconn, ", group = %.*s", ADDRSTRLEN, mc_addr ? mc_addr : "_NULL_");
4031 }
4032 else {
4033 if (mc_addr) {
4034 fprintf(stdout, "nuttcp%s%s: multicast group option not supported by server version %d.%d.%d, need >= 7.2.1\n",
4035 trans?"-t":"-r",
4036 ident, rvers_major,
4037 rvers_minor,
4038 rvers_delta);
4039 fflush(stdout);
4040 mc_addr = NULL;
4041 abortconn = 1;
4042 }
4043 }
4044 if (irvers >= 70301) {
4045 fprintf(ctlconn, " , srcport = %hu", srcport);
4046 }
4047 else {
4048 if (srcport &&
4049 ((!trans && !reverse) ||
4050 (trans && reverse) ||
4051 host3)) {
4052 fprintf(stdout, "nuttcp%s%s: source port option not supported by server version %d.%d.%d, need >= 7.3.1\n",
4053 trans?"-t":"-r",
4054 ident, rvers_major,
4055 rvers_minor,
4056 rvers_delta);
4057 fflush(stdout);
4058 srcport = 0;
4059 abortconn = 1;
4060 }
4061 }
4062 if (irvers >= 80101) {
4063 fprintf(ctlconn, ", iratesss = %d", iratesss);
4064 }
4065 else {
4066 if (iratesss && !trans) {
4067 fprintf(stdout, "nuttcp%s%s: smoothed slow start option not supported by server version %d.%d.%d, need >= 8.1.1\n",
4068 trans?"-t":"-r",
4069 ident, rvers_major,
4070 rvers_minor,
4071 rvers_delta);
4072 fflush(stdout);
4073 iratesss = 0;
4074 }
4075 }
4076 if ((irvers >= 80201) && host3) {
4077 if (explicitaf) {
4078 if (af == AF_INET)
4079 fprintf(ctlconn,
4080 ", af3 = 4");
4081 if (af == AF_INET6)
4082 fprintf(ctlconn,
4083 ", af3 = 6");
4084 }
4085 else {
4086 fprintf(ctlconn, ", af3 = 0");
4087 }
4088 }
4089 else {
4090 if (host3 && explicitaf) {
4091 fprintf(stdout, "nuttcp%s%s: third party \"-4/-6\" not supported by server version %d.%d.%d, need >= 8.2.1\n",
4092 trans?"-t":"-r",
4093 ident, rvers_major,
4094 rvers_minor,
4095 rvers_delta);
4096 fflush(stdout);
4097 }
4098 }
4099 fprintf(ctlconn, "\n");
4100 fflush(ctlconn);
4101 if (abortconn) {
4102 brief = 1;
4103 if ((!trans && !reverse) ||
4104 (trans && reverse))
4105 skip_data = 1;
4106 }
4107 if (!fgets(buf, mallocsize, stdin)) {
4108 mes("error from server");
4109 fprintf(stderr, "server aborted connection\n");
4110 fflush(stderr);
4111 exit(1);
4112 }
4113 if (irvers < 30403)
4114 udplossinfo = 0;
4115 if (irvers >= 50401) {
4116 two_bod = 1;
4117 handle_urg = 1;
4118 }
4119 if (udp || (buflen < 32) || (irvers < 60001)) {
4120 if (trans)
4121 send_retrans = 0;
4122 else
4123 read_retrans = 0;
4124 }
4125 if (udp || (buflen < 32) || (irvers < 80001)) {
4126 if (trans)
4127 send_cwnd = 0;
4128 else
4129 read_cwnd = 0;
4130 }
4131 if (strncmp(buf, "OK", 2) != 0) {
4132 mes("error from server");
4133 fprintf(stderr, "server ");
4134 while (fgets(buf, mallocsize, stdin)) {
4135 if (strncmp(buf, "KO", 2) == 0)
4136 break;
4137 fputs(buf, stderr);
4138 }
4139 fflush(stderr);
4140 exit(1);
4141 }
4142 if (sscanf(buf, "OK v%d.%d.%d\n", &rvers_major, &rvers_minor, &rvers_delta) < 3) {
4143 rvers_major = 0;
4144 rvers_minor = 0;
4145 rvers_delta = 0;
4146 }
4147 irvers = rvers_major*10000
4148 + rvers_minor*100
4149 + rvers_delta;
4150 usleep(10000);
4151 }
4152 else {
4153 if (inetd) {
4154 ctlconn = stdin;
4155 }
4156 else {
4157 if (!(ctlconn = fdopen(fd[0], "r")))
4158 err("fdopen: ctlconn for reading");
4159 }
4160 fflush(stdout);
4161 if (!inetd) {
4162 /* manually started server */
4163 /* send stdout to client */
4164 savestdout=dup(1);
4165 close(1);
4166 dup(fd[0]);
4167 if (!nofork) {
4168 /* send stderr to client */
4169 close(2);
4170 dup(1);
4171 }
4172 }
4173 if (!fgets(buf, mallocsize, ctlconn)) {
4174 fputs("KO\n", stdout);
4175 mes("no nuttcp HELO message");
4176 fputs("KO\n", stdout);
4177 goto cleanup;
4178 }
4179 if (sscanf(buf, HELO_FMT, &rvers_major,
4180 &rvers_minor, &rvers_delta) == 3) {
4181 fprintf(stdout, HELO_FMT, vers_major,
4182 vers_minor, vers_delta);
4183 fflush(stdout);
4184 if (!fgets(buf, mallocsize, ctlconn)) {
4185 fputs("KO\n", stdout);
4186 mes("no nuttcp parameters");
4187 fputs("KO\n", stdout);
4188 goto cleanup;
4189 }
4190 }
4191 irvers = rvers_major*10000
4192 + rvers_minor*100
4193 + rvers_delta;
4194 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) {
4195 trans = !trans;
4196 fputs("KO\n", stdout);
4197 mes("error scanning parameters");
4198 fprintf(stdout, "may be using older client version than server\n");
4199 fputs(buf, stdout);
4200 fputs("KO\n", stdout);
4201 goto cleanup;
4202 }
4203 irvers = rvers_major*10000
4204 + rvers_minor*100
4205 + rvers_delta;
4206 if (irvers >= 30302)
4207 sscanf(strstr(buf, ", interval =") + 13,
4208 "%lf", &interval);
4209 else
4210 interval = 0.0;
4211 if (irvers >= 30401)
4212 sscanf(strstr(buf, ", reverse =") + 12,
4213 "%d", &reverse);
4214 else
4215 reverse = 0;
4216 if (irvers >= 30501)
4217 sscanf(strstr(buf, ", format =") + 11,
4218 "%d", &format);
4219 else
4220 format = 0;
4221 if (irvers >= 30601) {
4222 sscanf(strstr(buf, ", traceroute =") + 15,
4223 "%d", &traceroute);
4224 if (traceroute) {
4225 skip_data = 1;
4226 brief = 1;
4227 }
4228 sscanf(strstr(buf, ", irate =") + 10,
4229 "%d", &irate);
4230 }
4231 else {
4232 traceroute = 0;
4233 irate = 0;
4234 }
4235 if (irvers >= 50001) {
4236 sprintf(fmt, "%%%ds", HOST3BUFLEN);
4237 sscanf(strstr(buf, ", thirdparty =") + 15,
4238 fmt, host3buf);
4239 host3buf[HOST3BUFLEN] = '\0';
4240 if (strcmp(host3buf, "_NULL_") == 0)
4241 host3 = NULL;
4242 else
4243 host3 = host3buf;
4244 if (host3) {
4245 if (no3rd) {
4246 fputs("KO\n", stdout);
4247 fprintf(stdout, "doesn't allow 3rd party nuttcp\n");
4248 fputs("KO\n", stdout);
4249 goto cleanup;
4250 }
4251 cp1 = host3;
4252 while (*cp1) {
4253 if (!isalnum((int)(*cp1))
4254 && (*cp1 != '-')
4255 && (*cp1 != '.')
4256 && (*cp1 != ':')
4257 && (*cp1 != '/')
4258 && (*cp1 != '+')
4259 && (*cp1 != '=')) {
4260 fputs("KO\n", stdout);
4261 mes("invalid 3rd party host");
4262 fprintf(stdout, "3rd party host = '%s'\n", host3);
4263 fputs("KO\n", stdout);
4264 goto cleanup;
4265 }
4266 cp1++;
4267 }
4268 skip_data = 1;
4269 brief = 1;
4270 sscanf(strstr(buf, ", brief3 =") + 11,
4271 "%d", &brief3);
4272 }
4273 }
4274 else {
4275 host3 = NULL;
4276 }
4277 if (host3 && (irvers >= 60205)) {
4278 sscanf(strstr(buf, ", ctlport3 =") + 13,
4279 "%hu", &ctlport3);
4280 }
4281 else {
4282 ctlport3 = 0;
4283 }
4284 if (irvers >= 50101) {
4285 sscanf(strstr(buf, ", multicast =") + 14,
4286 "%d", &mc_param);
4287 }
4288 else {
4289 mc_param = 0;
4290 }
4291 if (irvers >= 60201) {
4292 sscanf(strstr(buf, ", ssm =") + 8,
4293 "%d", &ssm);
4294 }
4295 else {
4296 ssm = 0;
4297 }
4298 #ifndef MCAST_JOIN_SOURCE_GROUP
4299 if (mc_param && (ssm == 1)) {
4300 fputs("KO\n", stdout);
4301 fprintf(stdout, "server does not support ssm\n");
4302 fputs("KO\n", stdout);
4303 goto cleanup;
4304 }
4305 #endif
4306 if (irvers >= 50201) {
4307 sscanf(strstr(buf, ", datamss =") + 12,
4308 "%d", &datamss);
4309 }
4310 else {
4311 datamss = 0;
4312 }
4313 if (irvers >= 50301) {
4314 sscanf(strstr(buf, ", tos =") + 8,
4315 "%X", &tos);
4316 }
4317 else {
4318 tos = 0;
4319 }
4320 if (irvers >= 50501) {
4321 sscanf(strstr(buf, ", nbuf_bytes =")
4322 + 15,
4323 "%d", &nbuf_bytes);
4324 sscanf(strstr(buf, ", rate_pps =") + 13,
4325 "%d", &rate_pps);
4326 sscanf(strstr(buf, ", nodelay =") + 12,
4327 "%d", &nodelay);
4328 }
4329 else {
4330 nbuf_bytes = 0;
4331 rate_pps = 0;
4332 nodelay = 0;
4333 }
4334 if (irvers >= 60206) {
4335 if (host3) {
4336 sscanf(strstr(buf,
4337 ", affinity =") + 13,
4338 "%d", &affinity);
4339 sscanf(strstr(buf,
4340 ", srvr_affinity =")
4341 + 18,
4342 "%d", &srvr_affinity);
4343 }
4344 else {
4345 sscanf(strstr(buf,
4346 ", affinity =") + 13,
4347 "%d", &srvr_affinity);
4348 }
4349 }
4350 else {
4351 srvr_affinity = -1;
4352 }
4353 if (irvers >= 60207) {
4354 sscanf(strstr(buf, ", maxburst =") + 13,
4355 "%d", &maxburst);
4356 }
4357 else {
4358 maxburst = 1;
4359 }
4360 if (irvers >= 70001) {
4361 sscanf(strstr(buf, ", do_jitter =") + 14,
4362 "%d", &do_jitter);
4363 }
4364 else {
4365 do_jitter = 0;
4366 }
4367 if (irvers >= 70001) {
4368 sscanf(strstr(buf, ", do_owd =") + 11,
4369 "%d", &do_owd);
4370 }
4371 else {
4372 do_owd = 0;
4373 }
4374 if (irvers >= 70101) {
4375 sscanf(strstr(buf, ", stride =") + 11,
4376 "%d", &ipad_stride.ip32);
4377 }
4378 else {
4379 ipad_stride.ip32 = 0;
4380 }
4381 if (irvers >= 70101) {
4382 sscanf(strstr(buf,
4383 ", multilink =") + 14,
4384 "%d", &multilink);
4385 }
4386 else {
4387 multilink = 0;
4388 }
4389 if (irvers >= 70201) {
4390 sprintf(fmt, "%%%ds", ADDRSTRLEN);
4391 sscanf(strstr(buf, ", group =") + 10,
4392 fmt, mcgaddr);
4393 mcgaddr[ADDRSTRLEN - 1] = '\0';
4394 if (strcmp(mcgaddr, "_NULL_") == 0)
4395 mc_addr = NULL;
4396 else
4397 mc_addr = mcgaddr;
4398 if (mc_addr) {
4399 cp1 = mc_addr;
4400 while (*cp1) {
4401 if (!isxdigit((int)(*cp1))
4402 && (*cp1 != '.')
4403 && (*cp1 != ':')) {
4404 fputs("KO\n", stdout);
4405 mes("invalid multicast group");
4406 fprintf(stdout, "multicast group = '%s'\n", mc_addr);
4407 fputs("KO\n", stdout);
4408 goto cleanup;
4409 }
4410 cp1++;
4411 }
4412 }
4413 }
4414 else {
4415 mc_addr = NULL;
4416 }
4417 if (irvers >= 70301) {
4418 sscanf(strstr(buf,
4419 ", srcport =") + 12,
4420 "%hu", &srcport);
4421 }
4422 else {
4423 srcport = 0;
4424 }
4425 if (irvers >= 80101) {
4426 sscanf(strstr(buf, ", iratesss =") + 13,
4427 "%d", &iratesss);
4428 }
4429 else {
4430 iratesss = 0;
4431 }
4432 if ((irvers >= 80201) && host3) {
4433 sscanf(strstr(buf, ", af3 =") + 8,
4434 "%d", &af3);
4435 }
4436 else {
4437 af3 = 0;
4438 }
4439 #if !defined(linux)
4440 iratesss = 0;
4441 #endif
4442 trans = !trans;
4443 if (inetd && !sinkmode) {
4444 fputs("KO\n", stdout);
4445 mes("option \"-s\" invalid with inetd server");
4446 fputs("KO\n", stdout);
4447 goto cleanup;
4448 }
4449 if (!traceroute && !host3 &&
4450 (nbuflen != buflen)) {
4451 if (nbuflen < 1) {
4452 fputs("KO\n", stdout);
4453 mes("invalid buflen");
4454 fprintf(stdout, "buflen = %d\n", nbuflen);
4455 fputs("KO\n", stdout);
4456 goto cleanup;
4457 }
4458 free(buf);
4459 mallocsize = nbuflen;
4460 if (mallocsize < MINMALLOC) mallocsize = MINMALLOC;
4461 #if defined(linux)
4462 if (directio) {
4463 error_num = posix_memalign(
4464 (void **)&buf,
4465 sysconf(_SC_PAGESIZE),
4466 mallocsize);
4467 if (error_num) {
4468 errno = error_num;
4469 err("posix_memalign");
4470 }
4471 }
4472 else
4473 #endif
4474 if ((buf = (char *)malloc(mallocsize)) == (char *)NULL)
4475 err("malloc");
4476 pattern( buf, nbuflen );
4477 }
4478 buflen = nbuflen;
4479 if (nbuf < 1) {
4480 fputs("KO\n", stdout);
4481 mes("invalid nbuf");
4482 fprintf(stdout, "nbuf = %llu\n", nbuf);
4483 fputs("KO\n", stdout);
4484 goto cleanup;
4485 }
4486 rcvwin = sendwin;
4487 if (sendwin < 0) {
4488 fputs("KO\n", stdout);
4489 mes("invalid win");
4490 fprintf(stdout, "win = %d\n", sendwin);
4491 fputs("KO\n", stdout);
4492 goto cleanup;
4493 }
4494 if ((nstream < 1) || (nstream > MAXSTREAM)) {
4495 fputs("KO\n", stdout);
4496 mes("invalid nstream");
4497 fprintf(stdout, "nstream = %d\n", nstream);
4498 fputs("KO\n", stdout);
4499 goto cleanup;
4500 }
4501 if (nstream > 1) {
4502 b_flag = 1;
4503 send_retrans = 0;
4504 read_retrans = 0;
4505 send_cwnd = 0;
4506 read_cwnd = 0;
4507 }
4508 if (rate == 0)
4509 rate = MAXRATE;
4510 if (timeout < 0) {
4511 fputs("KO\n", stdout);
4512 mes("invalid timeout");
4513 fprintf(stdout, "timeout = %f\n", timeout);
4514 fputs("KO\n", stdout);
4515 goto cleanup;
4516 }
4517 itimer.it_value.tv_sec = timeout;
4518 itimer.it_value.tv_usec =
4519 (timeout - itimer.it_value.tv_sec)
4520 *1000000;
4521 if ((port < 1024) || ((port + nstream - 1) > 65535)) {
4522 fputs("KO\n", stdout);
4523 mes("invalid port/nstream");
4524 fprintf(stdout, "port/nstream = %hu/%d\n", port, nstream);
4525 fputs("KO\n", stdout);
4526 goto cleanup;
4527 }
4528 if (srcport && (srcport < 1024)) {
4529 fputs("KO\n", stdout);
4530 mes("invalid srcport");
4531 fprintf(stdout, "srcport = %hu\n", srcport);
4532 fputs("KO\n", stdout);
4533 goto cleanup;
4534 }
4535 if ((ctlport >= port) && (ctlport <= (port + nstream - 1))) {
4536 fputs("KO\n", stdout);
4537 mes("ctlport overlaps port/nstream");
4538 fprintf(stdout, "ctlport = %hu, port/nstream = %hu/%d\n", ctlport, port, nstream);
4539 fputs("KO\n", stdout);
4540 goto cleanup;
4541 }
4542 if (iratesss) {
4543 if (udp) {
4544 fputs("KO\n", stdout);
4545 mes("iratesss not allowed for udp");
4546 fputs("KO\n", stdout);
4547 goto cleanup;
4548 }
4549 if (maxburst > 1) {
4550 fputs("KO\n", stdout);
4551 mes("maxburst > 1 not allowed with iratesss");
4552 fprintf(stdout, "maxburst = %d\n", maxburst);
4553 fputs("KO\n", stdout);
4554 goto cleanup;
4555 }
4556 if (nstream > 1) {
4557 fputs("KO\n", stdout);
4558 mes("nstream > 1 not allowed with iratesss");
4559 fprintf(stdout, "nstream = %d\n", nstream);
4560 fputs("KO\n", stdout);
4561 goto cleanup;
4562 }
4563 }
4564 if (host3 && ctlport3 && (ctlport3 < 1024)) {
4565 fputs("KO\n", stdout);
4566 mes("invalid ctlport3");
4567 fprintf(stdout, "ctlport3 = %hu\n",
4568 ctlport3);
4569 fputs("KO\n", stdout);
4570 goto cleanup;
4571 }
4572 if (interval < 0) {
4573 fputs("KO\n", stdout);
4574 mes("invalid interval");
4575 fprintf(stdout, "interval = %f\n", interval);
4576 fputs("KO\n", stdout);
4577 goto cleanup;
4578 }
4579 if (mc_param) {
4580 if ((mc_param < 1) ||
4581 (mc_param > 255)) {
4582 fputs("KO\n", stdout);
4583 mes("invalid multicast ttl");
4584 fprintf(stdout, "multicast ttl = %d\n", mc_param);
4585 fputs("KO\n", stdout);
4586 goto cleanup;
4587 }
4588 udp = 1;
4589 nstream = 1;
4590 if (rate == MAXRATE)
4591 rate = DEFAULT_UDP_RATE;
4592 }
4593 multicast = mc_param;
4594 if ((!host3 && ((ssm < 0) || (ssm > 1))) ||
4595 (host3 && ((ssm < -1) || (ssm > 1)))) {
4596 fputs("KO\n", stdout);
4597 mes("invalid ssm value");
4598 fprintf(stdout, "ssm = %d\n", ssm);
4599 fputs("KO\n", stdout);
4600 goto cleanup;
4601 }
4602 if (datamss < 0) {
4603 fputs("KO\n", stdout);
4604 mes("invalid datamss");
4605 fprintf(stdout, "datamss = %d\n", datamss);
4606 fputs("KO\n", stdout);
4607 goto cleanup;
4608 }
4609 if (tos > 255) {
4610 fputs("KO\n", stdout);
4611 mes("invalid tos");
4612 fprintf(stdout, "tos = %d\n", tos);
4613 fputs("KO\n", stdout);
4614 goto cleanup;
4615 }
4616 if (nbuf_bytes < 0) {
4617 fputs("KO\n", stdout);
4618 mes("invalid nbuf_bytes");
4619 fprintf(stdout, "nbuf_bytes = %d\n",
4620 nbuf_bytes);
4621 fputs("KO\n", stdout);
4622 goto cleanup;
4623 }
4624 if (rate_pps < 0) {
4625 fputs("KO\n", stdout);
4626 mes("invalid rate_pps");
4627 fprintf(stdout, "rate_pps = %d\n",
4628 rate_pps);
4629 fputs("KO\n", stdout);
4630 goto cleanup;
4631 }
4632 if (nodelay < 0) {
4633 fputs("KO\n", stdout);
4634 mes("invalid nodelay");
4635 fprintf(stdout, "nodelay = %d\n",
4636 nodelay);
4637 fputs("KO\n", stdout);
4638 goto cleanup;
4639 }
4640 if ((srvr_affinity >= 0) && !host3) {
4641 #ifdef HAVE_SETAFFINITY
4642 CPU_ZERO(&cpu_set);
4643 CPU_SET(srvr_affinity, &cpu_set);
4644 if (sched_setaffinity(0,
4645 sizeof(cpu_set_t),
4646 &cpu_set) != 0) {
4647 fputs("KO\n", stdout);
4648 mes("couldn't change server "
4649 "CPU affinity");
4650 fprintf(stdout,
4651 "srvr_affinity = %d\n",
4652 srvr_affinity);
4653 fputs("KO\n", stdout);
4654 goto cleanup;
4655 }
4656 #else
4657 fputs("KO\n", stdout);
4658 mes("server doesn't support setting "
4659 "CPU affinity");
4660 fprintf(stdout,
4661 "srvr_affinity = %d\n",
4662 srvr_affinity);
4663 fputs("KO\n", stdout);
4664 goto cleanup;
4665 #endif
4666 }
4667 if (maxburst < 1) {
4668 fputs("KO\n", stdout);
4669 mes("invalid maxburst");
4670 fprintf(stdout, "maxburst = %d\n",
4671 maxburst);
4672 fputs("KO\n", stdout);
4673 goto cleanup;
4674 }
4675 if (do_jitter < 0) {
4676 fputs("KO\n", stdout);
4677 mes("invalid do_jitter");
4678 fprintf(stdout, "do_jitter = %d\n",
4679 do_jitter);
4680 fputs("KO\n", stdout);
4681 goto cleanup;
4682 }
4683 if (do_jitter && !udp) {
4684 fputs("KO\n", stdout);
4685 fprintf(stdout,
4686 "jitter option"
4687 " not supported for TCP\n");
4688 fputs("KO\n", stdout);
4689 goto cleanup;
4690 }
4691 if (do_jitter && (!rate || (rate == MAXRATE))) {
4692 fputs("KO\n", stdout);
4693 fprintf(stdout,
4694 "jitter option not supported"
4695 " for unlimited rate\n");
4696 fputs("KO\n", stdout);
4697 goto cleanup;
4698 }
4699 if (do_jitter && !irate) {
4700 fputs("KO\n", stdout);
4701 fprintf(stdout,
4702 "jitter option requires"
4703 " instantaneous rate limit\n");
4704 fputs("KO\n", stdout);
4705 goto cleanup;
4706 }
4707 if (do_owd < 0) {
4708 fputs("KO\n", stdout);
4709 mes("invalid do_owd");
4710 fprintf(stdout, "do_owd = %d\n",
4711 do_owd);
4712 fputs("KO\n", stdout);
4713 goto cleanup;
4714 }
4715 if (mc_addr) {
4716 error_num = inet_pton(AF_INET, mc_addr,
4717 &dummy);
4718 #ifdef AF_INET6
4719 if (error_num != 1)
4720 error_num = inet_pton(AF_INET6,
4721 mc_addr,
4722 &dummy);
4723 #endif
4724 if (error_num != 1) {
4725 fputs("KO\n", stdout);
4726 mes("invalid multicast group");
4727 fprintf(stdout, "multicast group = '%s'\n",
4728 mc_addr);
4729 fputs("KO\n", stdout);
4730 goto cleanup;
4731 }
4732 }
4733 /* used to send server "OK" here -
4734 * now delay sending of server OK until
4735 * after successful server bind() -
4736 * catches data port collision */
4737 if (udp && (interval ||
4738 (do_jitter & JITTER_IGNORE_OOO)) &&
4739 (buflen >= 32) && (irvers >= 30403))
4740 udplossinfo = 1;
4741 if (irvers >= 50401) {
4742 two_bod = 1;
4743 handle_urg = 1;
4744 }
4745 if (udp || (buflen < 32) || (irvers < 60001)) {
4746 if (trans)
4747 send_retrans = 0;
4748 else
4749 read_retrans = 0;
4750 }
4751 if (udp || (buflen < 32) || (irvers < 80001)) {
4752 if (trans)
4753 send_cwnd = 0;
4754 else
4755 read_cwnd = 0;
4756 }
4757 }
4758 }
4759
4760 if (clientserver && client && (stream_idx == 1)) {
4761 reading_srvr_info = 1;
4762 pollfds[0].fd = fileno(ctlconn);
4763 pollfds[0].events = POLLIN | POLLPRI;
4764 pollfds[0].revents = 0;
4765 flags = fcntl(0, F_GETFL, 0);
4766 if (flags < 0)
4767 err("fcntl 1");
4768 flags |= O_NONBLOCK;
4769 if (fcntl(0, F_SETFL, flags) < 0)
4770 err("fcntl 2");
4771 itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT;
4772 itimer.it_value.tv_usec = 0;
4773 itimer.it_interval.tv_sec = 0;
4774 itimer.it_interval.tv_usec = 0;
4775 setitimer(ITIMER_REAL, &itimer, 0);
4776 }
4777 if (clientserver && client && (stream_idx == 1) &&
4778 ((pollst = poll(pollfds, 1, 0)) > 0) &&
4779 (pollfds[0].revents & (POLLIN | POLLPRI)) && !got_done) {
4780 /* check for server output (mainly for server error) */
4781 while (fgets(intervalbuf, sizeof(intervalbuf), stdin)) {
4782 setitimer(ITIMER_REAL, &itimer, 0);
4783 if (strncmp(intervalbuf, "DONE", 4) == 0) {
4784 if (format & DEBUGPOLL) {
4785 fprintf(stdout, "got DONE\n");
4786 fflush(stdout);
4787 }
4788 got_done = 1;
4789 intr = 1;
4790 break;
4791 }
4792 else if (strncmp(intervalbuf,
4793 "nuttcp-", 7) == 0) {
4794 if ((brief <= 0) ||
4795 strstr(intervalbuf, "Warning") ||
4796 strstr(intervalbuf, "Error") ||
4797 strstr(intervalbuf, "Debug")) {
4798 if (*ident) {
4799 fputs("nuttcp", stdout);
4800 fputs(trans ?
4801 "-r" : "-t",
4802 stdout);
4803 fputs(ident, stdout);
4804 fputs(intervalbuf + 8,
4805 stdout);
4806 }
4807 else
4808 fputs(intervalbuf,
4809 stdout);
4810 fflush(stdout);
4811 }
4812 if (strstr(intervalbuf, "Error"))
4813 exit(1);
4814 }
4815 else {
4816 if (*ident)
4817 fprintf(stdout, "%s: ",
4818 ident + 1);
4819 fputs(intervalbuf, stdout);
4820 fflush(stdout);
4821 }
4822 }
4823 }
4824 if (clientserver && client && (stream_idx == 1)) {
4825 reading_srvr_info = 0;
4826 flags = fcntl(0, F_GETFL, 0);
4827 if (flags < 0)
4828 err("fcntl 1");
4829 flags &= ~O_NONBLOCK;
4830 if (fcntl(0, F_SETFL, flags) < 0)
4831 err("fcntl 2");
4832 itimer.it_value.tv_sec = 0;
4833 itimer.it_value.tv_usec = 0;
4834 setitimer(ITIMER_REAL, &itimer, 0);
4835 }
4836
4837 if (!client) {
4838 if (af == AF_INET) {
4839 inet_ntop(af, &clientaddr.s_addr, hostbuf, sizeof(hostbuf));
4840 }
4841 #ifdef AF_INET6
4842 else if (af == AF_INET6) {
4843 inet_ntop(af, clientaddr6.s6_addr, hostbuf, sizeof(hostbuf));
4844 }
4845 #endif
4846 host = hostbuf;
4847 }
4848
4849 if (multilink && !client &&
4850 ((trans && !reverse) || (!trans && reverse)) &&
4851 !udp && (stream_idx == 1)) {
4852 nameinfo_flags = NI_NAMEREQD;
4853 if (getnameinfo((struct sockaddr *)&client_ipaddr,
4854 sizeof(struct in6_addr),
4855 clientbuf, NI_MAXHOST,
4856 NULL, 0,
4857 nameinfo_flags) == 0) {
4858 bzero(&hints, sizeof(hints));
4859 res[0] = NULL;
4860 res[1] = NULL;
4861 hints.ai_family = af;
4862 if (udp)
4863 hints.ai_socktype = SOCK_DGRAM;
4864 else
4865 hints.ai_socktype = SOCK_STREAM;
4866 if (getaddrinfo(clientbuf, NULL, &hints,
4867 &res[1]) == 0) {
4868 for ( i = 2; i <= nstream; i++ ) {
4869 if (res[i - 1]->ai_next)
4870 res[i] =
4871 res[i - 1]->ai_next;
4872 else
4873 res[i] = res[1];
4874 }
4875 }
4876 else {
4877 if (res[1]) {
4878 freeaddrinfo(res[1]);
4879 res[1] = NULL;
4880 }
4881 multilink = 0;
4882 }
4883 }
4884 else
4885 multilink = 0;
4886 }
4887
4888 if ((stream_idx > 0) && skip_data) {
4889 if (clientserver && !client && (stream_idx == 1)) {
4890 /* send server "OK" message */
4891 fprintf(stdout, "OK v%d.%d.%d\n", vers_major,
4892 vers_minor, vers_delta);
4893 fflush(stdout);
4894 }
4895 break;
4896 }
4897
4898 bzero((char *)&sinme[stream_idx], sizeof(sinme[stream_idx]));
4899 bzero((char *)&sinhim[stream_idx], sizeof(sinhim[stream_idx]));
4900
4901 #ifdef AF_INET6
4902 bzero((char *)&sinme6[stream_idx], sizeof(sinme6[stream_idx]));
4903 bzero((char *)&sinhim6[stream_idx], sizeof(sinhim6[stream_idx]));
4904 #endif
4905
4906 if (((trans && !reverse) && (stream_idx > 0)) ||
4907 ((!trans && reverse) && (stream_idx > 0)) ||
4908 (client && (stream_idx == 0))) {
4909 /* xmitr initiates connections (unless reversed) */
4910 if (client) {
4911 if (af == AF_INET) {
4912 sinhim[stream_idx].sin_family = af;
4913 if (ipad_stride.ip32 && (stream_idx > 1)) {
4914 sinhim[stream_idx].sin_addr.s_addr =
4915 sinhim[stream_idx - 1].sin_addr.s_addr
4916 + ipad_stride.ip32;
4917 }
4918 else {
4919 bcopy((char *)&(((struct sockaddr_in *)res[stream_idx]->ai_addr)->sin_addr),
4920 (char *)&sinhim[stream_idx].sin_addr.s_addr,
4921 sizeof(sinhim[stream_idx].sin_addr.s_addr));
4922 }
4923 }
4924 #ifdef AF_INET6
4925 else if (af == AF_INET6) {
4926 sinhim6[stream_idx].sin6_family = af;
4927 bcopy((char *)&(((struct sockaddr_in6 *)res[stream_idx]->ai_addr)->sin6_addr),
4928 (char *)&sinhim6[stream_idx].sin6_addr.s6_addr,
4929 sizeof(sinhim6[stream_idx].sin6_addr.s6_addr));
4930 sinhim6[stream_idx].sin6_scope_id = ((struct sockaddr_in6 *)res[stream_idx]->ai_addr)->sin6_scope_id;
4931 }
4932 #endif
4933 else {
4934 err("unsupported AF");
4935 }
4936 }
4937 else {
4938 sinhim[stream_idx].sin_family = af;
4939 if (ipad_stride.ip32 && (stream_idx > 1)) {
4940 sinhim[stream_idx].sin_addr.s_addr =
4941 sinhim[stream_idx - 1].sin_addr.s_addr
4942 + ipad_stride.ip32;
4943 }
4944 else {
4945 if (multilink && (stream_idx > 0))
4946 sinhim[stream_idx].sin_addr =
4947 ((struct sockaddr_in *)res[stream_idx]->ai_addr)->sin_addr;
4948 else
4949 sinhim[stream_idx].sin_addr =
4950 clientaddr;
4951 }
4952 #ifdef AF_INET6
4953 sinhim6[stream_idx].sin6_family = af;
4954 if (multilink && (stream_idx > 0))
4955 sinhim6[stream_idx].sin6_addr =
4956 ((struct sockaddr_in6 *)res[stream_idx]->ai_addr)->sin6_addr;
4957 else
4958 sinhim6[stream_idx].sin6_addr =
4959 clientaddr6;
4960 sinhim6[stream_idx].sin6_scope_id = clientscope6;
4961 #endif
4962 }
4963 if (stream_idx == 0) {
4964 sinhim[stream_idx].sin_port = htons(ctlport);
4965 sinme[stream_idx].sin_port = htons(srcctlport); /* default is free choice */
4966 #ifdef AF_INET6
4967 sinhim6[stream_idx].sin6_port = htons(ctlport);
4968 sinme6[stream_idx].sin6_port = htons(srcctlport); /* default is free choice */
4969 #endif
4970 }
4971 else {
4972 sinhim[stream_idx].sin_port = htons(port + stream_idx - 1);
4973 sinme[stream_idx].sin_port = htons(srcport); /* default is free choice */
4974 #ifdef AF_INET6
4975 sinhim6[stream_idx].sin6_port = htons(port + stream_idx - 1);
4976 sinme6[stream_idx].sin6_port = htons(srcport); /* default is free choice */
4977 #endif
4978 }
4979 }
4980 else {
4981 /* rcvr listens for connections (unless reversed) */
4982 if (stream_idx == 0) {
4983 sinme[stream_idx].sin_port = htons(ctlport);
4984 sinhim[stream_idx].sin_port = htons(srcctlport); /* default is free choice */
4985 #ifdef AF_INET6
4986 sinme6[stream_idx].sin6_port = htons(ctlport);
4987 sinhim6[stream_idx].sin6_port = htons(srcctlport); /* default is free choice */
4988 #endif
4989 }
4990 else {
4991 sinme[stream_idx].sin_port = htons(port + stream_idx - 1);
4992 sinhim[stream_idx].sin_port = htons(srcport); /* default is free choice */
4993 #ifdef AF_INET6
4994 sinme6[stream_idx].sin6_port = htons(port + stream_idx - 1);
4995 sinhim6[stream_idx].sin6_port = htons(srcport); /* default is free choice */
4996 #endif
4997 }
4998 }
4999 sinme[stream_idx].sin_family = af;
5000 #ifdef AF_INET6
5001 sinme6[stream_idx].sin6_family = af;
5002 #endif
5003
5004 if ((fd[stream_idx] = socket(domain, (udp && (stream_idx != 0))?SOCK_DGRAM:SOCK_STREAM, 0)) < 0) {
5005 if (clientserver && !client && (stream_idx == 1)) {
5006 save_errno = errno;
5007 fputs("KO\n", stdout);
5008 mes("Error: socket() on data stream failed");
5009 fputs("Error: ", stdout);
5010 fputs(strerror(save_errno), stdout);
5011 fputs("\n", stdout);
5012 fputs("KO\n", stdout);
5013 goto cleanup;
5014 }
5015 err("socket");
5016 }
5017
5018 if (setsockopt(fd[stream_idx], SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)) < 0) {
5019 if (clientserver && !client && (stream_idx == 1)) {
5020 save_errno = errno;
5021 fputs("KO\n", stdout);
5022 mes("Error: setsockopt()"
5023 " to so_reuseaddr failed");
5024 fputs("Error: ", stdout);
5025 fputs(strerror(save_errno), stdout);
5026 fputs("\n", stdout);
5027 fputs("KO\n", stdout);
5028 goto cleanup;
5029 }
5030 err("setsockopt: so_reuseaddr");
5031 }
5032
5033 #ifdef IPV6_V6ONLY
5034 if ((af == AF_INET6) && explicitaf && !v4mapped) {
5035 if (setsockopt(fd[stream_idx], IPPROTO_IPV6, IPV6_V6ONLY, (void *)&one, sizeof(int)) < 0) {
5036 if (clientserver && !client &&
5037 (stream_idx == 1)) {
5038 save_errno = errno;
5039 fputs("KO\n", stdout);
5040 mes("Error: setsockopt()"
5041 " to ipv6_only failed");
5042 fputs("Error: ", stdout);
5043 fputs(strerror(save_errno), stdout);
5044 fputs("\n", stdout);
5045 fputs("KO\n", stdout);
5046 goto cleanup;
5047 }
5048 err("setsockopt: ipv6_only");
5049 }
5050 }
5051 #endif
5052
5053 if (af == AF_INET) {
5054 if (bind(fd[stream_idx], (struct sockaddr *)&sinme[stream_idx], sizeof(sinme[stream_idx])) < 0) {
5055 if (clientserver && !client && (stream_idx == 1)) {
5056 save_errno = errno;
5057 fputs("KO\n", stdout);
5058 mes("Error: bind() on data stream failed");
5059 fputs("Error: ", stdout);
5060 fputs(strerror(save_errno), stdout);
5061 fputs("\n", stdout);
5062 if (((!trans && !reverse)
5063 || (trans && reverse)) &&
5064 (errno == EADDRINUSE) &&
5065 (port == IPERF_PORT))
5066 fputs("Info: Possible collision"
5067 " with iperf server\n", stdout);
5068 fputs("KO\n", stdout);
5069 goto cleanup;
5070 }
5071 if (clientserver && client && (stream_idx == 1) &&
5072 ((!trans && !reverse) || (trans && reverse)) &&
5073 (errno == EADDRINUSE) && (port == IPERF_PORT)) {
5074 errmes("bind");
5075 fputs("Info: Possible collision"
5076 " with iperf server\n", stderr);
5077 fflush(stderr);
5078 exit(1);
5079 }
5080 err("bind");
5081 }
5082 }
5083 #ifdef AF_INET6
5084 else if (af == AF_INET6) {
5085 if (bind(fd[stream_idx], (struct sockaddr *)&sinme6[stream_idx], sizeof(sinme6[stream_idx])) < 0) {
5086 if (clientserver && !client && (stream_idx == 1)) {
5087 save_errno = errno;
5088 fputs("KO\n", stdout);
5089 mes("Error: bind() on data stream failed");
5090 fputs("Error: ", stdout);
5091 fputs(strerror(save_errno), stdout);
5092 fputs("\n", stdout);
5093 fputs("KO\n", stdout);
5094 goto cleanup;
5095 }
5096 err("bind");
5097 }
5098 }
5099 #endif
5100 else {
5101 if (clientserver && !client && (stream_idx == 1)) {
5102 save_errno = errno;
5103 fputs("KO\n", stdout);
5104 mes("Error: unsupported AF on data stream");
5105 fputs("Error: ", stdout);
5106 fputs(strerror(save_errno), stdout);
5107 fputs("\n", stdout);
5108 fputs("KO\n", stdout);
5109 goto cleanup;
5110 }
5111 err("unsupported AF");
5112 }
5113
5114 if (clientserver && !client && (stream_idx == 1)) {
5115 /* finally OK to send server "OK" message */
5116 fprintf(stdout, "OK v%d.%d.%d\n", vers_major,
5117 vers_minor, vers_delta);
5118 fflush(stdout);
5119 if ((trans && !reverse) || (!trans && reverse))
5120 usleep(50000);
5121 }
5122
5123 if (clientserver && (stream_idx == 1)) {
5124 if (!udp && trans) {
5125 nretrans[0] = get_retrans(fd[0], &tcpinf);
5126 if ((retransinfo > 0) || cwndinfo)
5127 b_flag = 1;
5128 }
5129 }
5130
5131 if (stream_idx == nstream) {
5132 if (brief <= 0)
5133 mes("socket");
5134 #ifdef HAVE_SETPRIO
5135 if (priority && (brief <= 0)) {
5136 errno = 0;
5137 priority = getpriority(PRIO_PROCESS, 0);
5138 if (errno)
5139 mes("couldn't get priority");
5140 else {
5141 if (format & PARSE)
5142 fprintf(stdout,
5143 "nuttcp%s%s: "
5144 "priority=%d\n",
5145 trans ? "-t" : "-r",
5146 ident, priority);
5147 else
5148 fprintf(stdout,
5149 "nuttcp%s%s: "
5150 "priority = %d\n",
5151 trans ? "-t" : "-r",
5152 ident, priority);
5153 }
5154 }
5155 #endif
5156 #ifdef HAVE_SETAFFINITY
5157 if ((affinity >= 0) && (brief <= 0) && !host3) {
5158 int cpu_affinity;
5159
5160 errno = 0;
5161 sched_getaffinity(0, sizeof(cpu_set_t),
5162 &cpu_set);
5163 if (errno)
5164 mes("couldn't get affinity");
5165 else {
5166 for ( cpu_affinity = 0;
5167 cpu_affinity < ncores;
5168 cpu_affinity++ ) {
5169 if (CPU_ISSET(cpu_affinity,
5170 &cpu_set))
5171 break;
5172 }
5173 if (format & PARSE)
5174 fprintf(stdout,
5175 "nuttcp%s%s: "
5176 "cpu_affinity=%d\n",
5177 trans ? "-t" : "-r",
5178 ident, cpu_affinity);
5179 else
5180 fprintf(stdout,
5181 "nuttcp%s%s: "
5182 "affinity = CPU %d\n",
5183 trans ? "-t" : "-r",
5184 ident, cpu_affinity);
5185 }
5186 }
5187 #endif
5188 if (trans) {
5189 if ((brief <= 0) && (format & PARSE)) {
5190 fprintf(stdout, "nuttcp-t%s: buflen=%d ",
5191 ident, buflen);
5192 if (nbuf != INT_MAX)
5193 fprintf(stdout, "nbuf=%llu ", nbuf);
5194 fprintf(stdout, "nstream=%d port=%d",
5195 nstream, port);
5196 if (srcport)
5197 fprintf(stdout, " srcport=%d", srcport);
5198 fprintf(stdout, " mode=%s host=%s",
5199 udp?"udp":"tcp",
5200 host);
5201 if (multicast)
5202 fprintf(stdout, " multicast_ttl=%d",
5203 multicast);
5204 if (udp) {
5205 char tmphost[ADDRSTRLEN] = "\0";
5206 if (af == AF_INET) {
5207 fprintf(stdout, " af=inet");
5208 inet_ntop(af, &sinhim[stream_idx].sin_addr.s_addr,
5209 tmphost, sizeof(tmphost));
5210 if (client && (strcmp(host, tmphost) != 0))
5211 fprintf(stdout, " ip=%s", tmphost);
5212 }
5213 #ifdef AF_INET6
5214 else if (af == AF_INET6) {
5215 fprintf(stdout, " af=inet6");
5216 inet_ntop(af, &sinhim6[stream_idx].sin6_addr.s6_addr,
5217 tmphost, sizeof(tmphost));
5218 if (client && (strcmp(host, tmphost) != 0))
5219 fprintf(stdout, " ip=%s", tmphost);
5220 }
5221 #endif
5222 else {
5223 fprintf(stdout, " af=%d", af);
5224 }
5225 }
5226 fprintf(stdout, "\n");
5227 if (timeout)
5228 fprintf(stdout, "nuttcp-t%s: time_limit=%.2f\n",
5229 ident, timeout);
5230 if ((rate != MAXRATE) || tos)
5231 fprintf(stdout, "nuttcp-t%s:", ident);
5232 if (rate != MAXRATE) {
5233 fprintf(stdout, " rate_limit=%.3f rate_unit=Mbps rate_mode=%s",
5234 (double)rate/1000,
5235 irate ? "instantaneous" : "aggregate");
5236 if (iratesss)
5237 fprintf(stdout, " smoothed_slow_start=on");
5238 if (maxburst > 1)
5239 fprintf(stdout, " packet_burst=%d",
5240 maxburst);
5241 if (udp) {
5242 unsigned long long ppsrate =
5243 ((uint64_t)rate * 1000)/8/buflen;
5244
5245 fprintf(stdout, " pps_rate=%llu",
5246 ppsrate);
5247 }
5248 }
5249 if (tos)
5250 fprintf(stdout, " tos=0x%X", tos);
5251 if ((rate != MAXRATE) || tos)
5252 fprintf(stdout, "\n");
5253 }
5254 else if (brief <= 0) {
5255 fprintf(stdout, "nuttcp-t%s: buflen=%d, ",
5256 ident, buflen);
5257 if (nbuf != INT_MAX)
5258 fprintf(stdout, "nbuf=%llu, ", nbuf);
5259 fprintf(stdout, "nstream=%d, port=%d",
5260 nstream, port);
5261 if (srcport)
5262 fprintf(stdout, ", srcport=%d", srcport);
5263 fprintf(stdout, " %s -> %s",
5264 udp?"udp":"tcp",
5265 host);
5266 if (multicast)
5267 fprintf(stdout, " ttl=%d", multicast);
5268 if (udp) {
5269 char tmphost[ADDRSTRLEN] = "\0";
5270 if (af == AF_INET) {
5271 fprintf(stdout, " af=inet");
5272 inet_ntop(af, &sinhim[stream_idx].sin_addr.s_addr,
5273 tmphost, sizeof(tmphost));
5274 if (client && (strcmp(host, tmphost) != 0))
5275 fprintf(stdout, " ip=%s", tmphost);
5276 }
5277 #ifdef AF_INET6
5278 else if (af == AF_INET6) {
5279 fprintf(stdout, " af=inet6");
5280 inet_ntop(af, &sinhim6[stream_idx].sin6_addr.s6_addr,
5281 tmphost, sizeof(tmphost));
5282 if (client && (strcmp(host, tmphost) != 0))
5283 fprintf(stdout, " ip=%s", tmphost);
5284 }
5285 #endif
5286 else {
5287 fprintf(stdout, " af=%d", af);
5288 }
5289 }
5290 fprintf(stdout, "\n");
5291 if (timeout)
5292 fprintf(stdout, "nuttcp-t%s: time limit = %.2f second%s\n",
5293 ident, timeout,
5294 (timeout == 1.0)?"":"s");
5295 if ((rate != MAXRATE) || tos)
5296 fprintf(stdout, "nuttcp-t%s:", ident);
5297 if (rate != MAXRATE) {
5298 fprintf(stdout, " rate limit = %.3f Mbps (%s)",
5299 (double)rate/1000,
5300 irate ? "instantaneous" : "aggregate");
5301 if (iratesss)
5302 fprintf(stdout, " with smoothed slow start");
5303 if (maxburst > 1)
5304 fprintf(stdout, ", packet burst = %d",
5305 maxburst);
5306 if (udp) {
5307 unsigned long long ppsrate =
5308 ((uint64_t)rate * 1000)/8/buflen;
5309
5310 fprintf(stdout, ", %llu pps", ppsrate);
5311 }
5312 if (tos)
5313 fprintf(stdout, ",");
5314 }
5315 if (tos)
5316 fprintf(stdout, " tos = 0x%X", tos);
5317 if ((rate != MAXRATE) || tos)
5318 fprintf(stdout, "\n");
5319 }
5320 }
5321 else {
5322 if ((brief <= 0) && (format & PARSE)) {
5323 fprintf(stdout, "nuttcp-r%s: buflen=%d ",
5324 ident, buflen);
5325 if (nbuf != INT_MAX)
5326 fprintf(stdout, "nbuf=%llu ", nbuf);
5327 fprintf(stdout, "nstream=%d port=%d",
5328 nstream, port);
5329 if (srcport)
5330 fprintf(stdout, " srcport=%d", srcport);
5331 fprintf(stdout, " mode=%s", udp ? "udp":"tcp");
5332 if (udp) {
5333 if (af == AF_INET) {
5334 fprintf(stdout, " af=inet");
5335 }
5336 #ifdef AF_INET6
5337 else if (af == AF_INET6) {
5338 fprintf(stdout, " af=inet6");
5339 }
5340 #endif
5341 else {
5342 fprintf(stdout, " af=%d", af);
5343 }
5344 }
5345 fprintf(stdout, "\n");
5346 if (tos)
5347 fprintf(stdout, "nuttcp-r%s: tos=0x%X\n",
5348 ident, tos);
5349 if (interval)
5350 fprintf(stdout, "nuttcp-r%s: reporting_interval=%.2f\n",
5351 ident, interval);
5352 }
5353 else if (brief <= 0) {
5354 fprintf(stdout, "nuttcp-r%s: buflen=%d, ",
5355 ident, buflen);
5356 if (nbuf != INT_MAX)
5357 fprintf(stdout, "nbuf=%llu, ", nbuf);
5358 fprintf(stdout, "nstream=%d, port=%d",
5359 nstream, port);
5360 if (srcport)
5361 fprintf(stdout, ", srcport=%d", srcport);
5362 fprintf(stdout, " %s", udp ? "udp":"tcp");
5363 if (udp) {
5364 if (af == AF_INET) {
5365 fprintf(stdout, " af=inet");
5366 }
5367 #ifdef AF_INET6
5368 else if (af == AF_INET6) {
5369 fprintf(stdout, " af=inet6");
5370 }
5371 #endif
5372 else {
5373 fprintf(stdout, " af=%d", af);
5374 }
5375 }
5376 fprintf(stdout, "\n");
5377 if (tos)
5378 fprintf(stdout, "nuttcp-r%s: tos = 0x%X\n",
5379 ident, tos);
5380 if (interval)
5381 fprintf(stdout, "nuttcp-r%s: interval reporting every %.2f second%s\n",
5382 ident, interval,
5383 (interval == 1.0)?"":"s");
5384 }
5385 }
5386 }
5387
5388 if (stream_idx > 0) {
5389 if (trans) {
5390 /* Set the transmitter options */
5391 if (sendwin) {
5392 if (setsockopt(fd[stream_idx], SOL_SOCKET, SO_SNDBUF,
5393 (void *)&sendwin, sizeof(sendwin)) < 0)
5394 errmes("unable to setsockopt SO_SNDBUF");
5395 if (braindead && (setsockopt(fd[stream_idx], SOL_SOCKET, SO_RCVBUF,
5396 (void *)&rcvwin, sizeof(rcvwin)) < 0))
5397 errmes("unable to setsockopt SO_RCVBUF");
5398 }
5399 if (tos) {
5400 if (af == AF_INET) {
5401 if (setsockopt(fd[stream_idx], IPPROTO_IP, IP_TOS,
5402 (void *)&tos, sizeof(tos)) < 0)
5403 err("setsockopt");
5404 }
5405 #ifdef AF_INET6
5406 else if (af == AF_INET6) {
5407 if (setsockopt(fd[stream_idx], IPPROTO_IPV6, IPV6_TCLASS,
5408 (void *)&tos, sizeof(tos)) < 0)
5409 err("setsockopt");
5410 }
5411 #endif
5412 else {
5413 err("unsupported AF");
5414 }
5415 }
5416 if (nodelay && !udp) {
5417 struct protoent *p;
5418 p = getprotobyname("tcp");
5419 if (p && setsockopt(fd[stream_idx], p->p_proto, TCP_NODELAY,
5420 (void *)&one, sizeof(one)) < 0)
5421 err("setsockopt: nodelay");
5422 if ((stream_idx == nstream) && (brief <= 0))
5423 mes("nodelay");
5424 }
5425 }
5426 else {
5427 /* Set the receiver options */
5428 if (rcvwin) {
5429 if (setsockopt(fd[stream_idx], SOL_SOCKET, SO_RCVBUF,
5430 (void *)&rcvwin, sizeof(rcvwin)) < 0)
5431 errmes("unable to setsockopt SO_RCVBUF");
5432 if (braindead && (setsockopt(fd[stream_idx], SOL_SOCKET, SO_SNDBUF,
5433 (void *)&sendwin, sizeof(sendwin)) < 0))
5434 errmes("unable to setsockopt SO_SNDBUF");
5435 }
5436 if (tos) {
5437 if (af == AF_INET) {
5438 if (setsockopt(fd[stream_idx], IPPROTO_IP, IP_TOS,
5439 (void *)&tos, sizeof(tos)) < 0)
5440 err("setsockopt");
5441 }
5442 #ifdef AF_INET6
5443 else if (af == AF_INET6) {
5444 if (setsockopt(fd[stream_idx], IPPROTO_IPV6, IPV6_TCLASS,
5445 (void *)&tos, sizeof(tos)) < 0)
5446 err("setsockopt");
5447 }
5448 #endif
5449 else {
5450 err("unsupported AF");
5451 }
5452 }
5453 }
5454 }
5455 if (!udp || (stream_idx == 0)) {
5456 if (((trans && !reverse) && (stream_idx > 0)) ||
5457 ((!trans && reverse) && (stream_idx > 0)) ||
5458 (client && (stream_idx == 0))) {
5459 /* The transmitter initiates the connection
5460 * (unless reversed by the flip option)
5461 */
5462 if (options && (stream_idx > 0)) {
5463 if (setsockopt(fd[stream_idx], SOL_SOCKET, options, (void *)&one, sizeof(one)) < 0)
5464 errmes("unable to setsockopt options");
5465 }
5466 usleep(20000);
5467 if (trans && (stream_idx > 0) && datamss) {
5468 #if defined(__CYGWIN__) || defined(_WIN32)
5469 if (format & PARSE)
5470 fprintf(stderr, "nuttcp%s%s: Warning=\"setting_maximum_segment_size_not_supported_on_windows\"\n",
5471 trans?"-t":"-r", ident);
5472 else
5473 fprintf(stderr, "nuttcp%s%s: Warning: setting maximum segment size not supported on windows\n",
5474 trans?"-t":"-r", ident);
5475 fflush(stderr);
5476 #endif
5477 optlen = sizeof(datamss);
5478 if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0)
5479 if (errno != EINVAL)
5480 err("unable to set maximum segment size");
5481 }
5482 if (clientserver && !client && (stream_idx == 1)) {
5483 /* check if client went away */
5484 pollfds[0].fd = fileno(ctlconn);
5485 save_events = pollfds[0].events;
5486 pollfds[0].events = POLLIN | POLLPRI;
5487 pollfds[0].revents = 0;
5488 if ((poll(pollfds, 1, 0) > 0) &&
5489 (pollfds[0].revents & (POLLIN | POLLPRI)))
5490 goto cleanup;
5491 pollfds[0].events = save_events;
5492 }
5493 num_connect_tries++;
5494 if (stream_idx == 1)
5495 get_timeofday(&timeconn1, (struct timezone *)0);
5496 if (af == AF_INET) {
5497 error_num = connect(fd[stream_idx], (struct sockaddr *)&sinhim[stream_idx], sizeof(sinhim[stream_idx]));
5498 }
5499 #ifdef AF_INET6
5500 else if (af == AF_INET6) {
5501 error_num = connect(fd[stream_idx], (struct sockaddr *)&sinhim6[stream_idx], sizeof(sinhim6[stream_idx]));
5502 }
5503 #endif
5504 else {
5505 err("unsupported AF");
5506 }
5507 if (error_num < 0) {
5508 if (clientserver && client && (stream_idx == 0)
5509 && ((errno == ECONNREFUSED) ||
5510 (errno == ECONNRESET))
5511 && (num_connect_tries <
5512 MAX_CONNECT_TRIES)
5513 && retry_server) {
5514 /* retry control connection to
5515 * server for certain possibly
5516 * transient errors */
5517 usleep(SERVER_RETRY_USEC);
5518 goto doit;
5519 }
5520 if (!trans && (stream_idx == 0))
5521 err("connect");
5522 if (stream_idx > 0) {
5523 if (clientserver && !client) {
5524 for ( i = 1; i <= stream_idx;
5525 i++ )
5526 close(fd[i]);
5527 goto cleanup;
5528 }
5529 err("connect");
5530 }
5531 if (stream_idx == 0) {
5532 clientserver = 0;
5533 if (thirdparty) {
5534 perror("3rd party connect failed");
5535 fprintf(stderr, "3rd party nuttcp only supported for client/server mode\n");
5536 fflush(stderr);
5537 exit(1);
5538 }
5539 if (interval) {
5540 perror("connect failed");
5541 fprintf(stderr, "interval option only supported for client/server mode\n");
5542 fflush(stderr);
5543 exit(1);
5544 }
5545 if (reverse) {
5546 perror("connect failed");
5547 fprintf(stderr, "flip option only supported for client/server mode\n");
5548 fflush(stderr);
5549 exit(1);
5550 }
5551 if (traceroute) {
5552 perror("connect failed");
5553 fprintf(stderr, "traceroute option only supported for client/server mode\n");
5554 fflush(stderr);
5555 exit(1);
5556 }
5557 if (host3) {
5558 perror("connect failed");
5559 fprintf(stderr, "3rd party nuttcp only supported for client/server mode\n");
5560 fflush(stderr);
5561 exit(1);
5562 }
5563 if (multicast) {
5564 perror("connect failed");
5565 fprintf(stderr, "multicast only supported for client/server mode\n");
5566 fflush(stderr);
5567 exit(1);
5568 }
5569 if (udp) {
5570 perror("connect failed");
5571 fprintf(stderr, "UDP transfers only supported for client/server mode\n");
5572 fflush(stderr);
5573 exit(1);
5574 }
5575 if (format & PARSE) {
5576 fprintf(stderr, "nuttcp%s%s: Info=\"attempting_to_switch_to_deprecated_classic_mode\"\n",
5577 trans?"-t":"-r", ident);
5578 fprintf(stderr, "nuttcp%s%s: Info=\"will_use_less_reliable_transmitter_side_statistics\"\n",
5579 trans?"-t":"-r", ident);
5580 }
5581 else {
5582 fprintf(stderr, "nuttcp%s%s: Info: attempting to switch to deprecated \"classic\" mode\n",
5583 trans?"-t":"-r", ident);
5584 fprintf(stderr, "nuttcp%s%s: Info: will use less reliable transmitter side statistics\n",
5585 trans?"-t":"-r", ident);
5586 }
5587 fflush(stderr);
5588 }
5589 }
5590 if (stream_idx == 1) {
5591 get_timeofday(&timeconn2, (struct timezone *)0);
5592 tvsub( &timeconn, &timeconn2, &timeconn1 );
5593 rtt = timeconn.tv_sec*1000 +
5594 ((double)timeconn.tv_usec)/1000;
5595 }
5596 if (sockopterr && trans &&
5597 (stream_idx > 0) && datamss) {
5598 optlen = sizeof(datamss);
5599 if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) {
5600 if (errno != EINVAL)
5601 err("unable to set maximum segment size");
5602 else
5603 err("setting maximum segment size not supported on this OS");
5604 }
5605 }
5606 if (stream_idx == nstream) {
5607 optlen = sizeof(datamss);
5608 if (getsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, &optlen) < 0)
5609 err("get dataconn maximum segment size didn't work");
5610 if (format & DEBUGMTU)
5611 fprintf(stderr, "datamss = %d\n", datamss);
5612 }
5613 if ((stream_idx == nstream) && (brief <= 0)) {
5614 char tmphost[ADDRSTRLEN] = "\0";
5615 if (af == AF_INET) {
5616 inet_ntop(af, &sinhim[stream_idx].sin_addr.s_addr, tmphost, sizeof(tmphost));
5617 }
5618 #ifdef AF_INET6
5619 else if (af == AF_INET6) {
5620 if (!IN6_IS_ADDR_V4MAPPED(&sinhim6[stream_idx].sin6_addr)) {
5621 inet_ntop(af, sinhim6[stream_idx].sin6_addr.s6_addr, tmphost, sizeof(tmphost));
5622 }
5623 else {
5624 af = AF_INET;
5625 bcopy(((char *)&sinhim6[stream_idx].sin6_addr) + 12,
5626 (char *)&sinhim[stream_idx].sin_addr,
5627 sizeof(struct in_addr));
5628 sinhim[stream_idx].sin_family = AF_INET;
5629 // port gets put in both structs, no translate or copy needed
5630 inet_ntop(af, &sinhim[stream_idx].sin_addr.s_addr, tmphost, sizeof(tmphost));
5631 }
5632 }
5633 #endif
5634 else {
5635 err("unsupported AF");
5636 }
5637
5638 if (format & PARSE) {
5639 fprintf(stdout,
5640 "nuttcp%s%s: connect=%s",
5641 trans?"-t":"-r", ident,
5642 tmphost);
5643 if (trans && datamss) {
5644 fprintf(stdout, " mss=%d",
5645 datamss);
5646 }
5647 if (rtt)
5648 fprintf(stdout, P_RTT_FMT, rtt);
5649 }
5650 else {
5651 fprintf(stdout,
5652 "nuttcp%s%s: connect to %s with",
5653 trans?"-t":"-r", ident,
5654 tmphost);
5655 if (trans && datamss) {
5656 fprintf(stdout, " mss=%d",
5657 datamss);
5658 if (rtt)
5659 fprintf(stdout, ",");
5660 }
5661 if (rtt)
5662 fprintf(stdout, RTT_FMT, rtt);
5663 }
5664 if (af == AF_INET) {
5665 fprintf(stdout, " af=inet");
5666 }
5667 #ifdef AF_INET6
5668 else if (af == AF_INET6) {
5669 fprintf(stdout, " af=inet6");
5670 }
5671 #endif
5672 else {
5673 fprintf(stdout, " af=%d", af);
5674 }
5675 fprintf(stdout, "\n");
5676 }
5677 }
5678 else {
5679 /* The receiver listens for the connection
5680 * (unless reversed by the flip option)
5681 */
5682 if (trans && (stream_idx > 0) && datamss) {
5683 #if defined(__CYGWIN__) || defined(_WIN32)
5684 if (format & PARSE)
5685 fprintf(stderr, "nuttcp%s%s: Warning=\"setting_maximum_segment_size_not_supported_on_windows\"\n",
5686 trans?"-t":"-r", ident);
5687 else
5688 fprintf(stderr, "nuttcp%s%s: Warning: setting maximum segment size not supported on windows\n",
5689 trans?"-t":"-r", ident);
5690 fflush(stderr);
5691 #endif
5692 optlen = sizeof(datamss);
5693 if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0)
5694 if (errno != EINVAL)
5695 err("unable to set maximum segment size");
5696 }
5697 listen(fd[stream_idx], LISTEN_BACKLOG);
5698 if (clientserver && !client && (stream_idx == 0)
5699 && !inetd && !nofork && !forked) {
5700 if ((pid = fork()) == (pid_t)-1)
5701 err("can't fork");
5702 if (pid != 0)
5703 exit(0);
5704 forked = 1;
5705 if (sinkmode) {
5706 close(0);
5707 close(1);
5708 close(2);
5709 open("/dev/null", O_RDWR);
5710 dup(0);
5711 dup(0);
5712 }
5713 setsid();
5714 }
5715 if (options && (stream_idx > 0)) {
5716 if (setsockopt(fd[stream_idx], SOL_SOCKET, options, (void *)&one, sizeof(one)) < 0)
5717 errmes("unable to setsockopt options");
5718 }
5719 if (sockopterr && trans &&
5720 (stream_idx > 0) && datamss) {
5721 optlen = sizeof(datamss);
5722 if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0)
5723 if (errno != EINVAL)
5724 err("unable to set maximum segment size");
5725 }
5726 if (clientserver && (stream_idx > 0)) {
5727 sigact.sa_handler = ignore_alarm;
5728 sigemptyset(&sigact.sa_mask);
5729 sigact.sa_flags = 0;
5730 sigaction(SIGALRM, &sigact, &savesigact);
5731 alarm(ACCEPT_TIMEOUT);
5732 }
5733 acceptnewconn:
5734 fromlen = sizeof(frominet);
5735 nfd=accept(fd[stream_idx], (struct sockaddr *)&frominet, &fromlen);
5736 save_errno = errno;
5737 if (clientserver && (stream_idx > 0)) {
5738 alarm(0);
5739 sigact.sa_handler = savesigact.sa_handler;
5740 sigact.sa_mask = savesigact.sa_mask;
5741 sigact.sa_flags = savesigact.sa_flags;
5742 sigaction(SIGALRM, &sigact, 0);
5743 }
5744 if (nfd < 0) {
5745 /* check for interrupted system call - on
5746 * server, close data streams, cleanup and
5747 * try again - all other errors just die
5748 */
5749 if ((save_errno == EINTR) && clientserver
5750 && (stream_idx > 0)) {
5751 if (client) {
5752 /* if client, just give nice
5753 * error message and exit
5754 */
5755 mes("Error: accept() timeout");
5756 exit(1);
5757 }
5758 for ( i = 1; i <= stream_idx; i++ )
5759 close(fd[i]);
5760 goto cleanup;
5761 }
5762 err("accept");
5763 }
5764 if (clientserver && !client && (stream_idx == 0)
5765 && !inetd && !nofork
5766 && !single_threaded) {
5767 /* multi-threaded manually started server */
5768 if ((pid = fork()) == (pid_t)-1)
5769 err("can't fork");
5770 if (pid != 0) {
5771 /* parent just waits for quick
5772 * child exit */
5773 while ((wait_pid = wait(&pidstat))
5774 != pid) {
5775 if (wait_pid == (pid_t)-1) {
5776 if (errno == ECHILD)
5777 break;
5778 err("wait failed");
5779 }
5780 }
5781 /* and then accept()s another client
5782 * connection */
5783 close(nfd);
5784 stream_idx = 0;
5785 if (oneshot)
5786 exit(0);
5787 goto acceptnewconn;
5788 }
5789 /* child just makes a grandchild and then
5790 * immediately exits (avoid zombie processes) */
5791 if ((pid = fork()) == (pid_t)-1)
5792 err("can't fork");
5793 if (pid != 0)
5794 exit(0);
5795 /* grandkid does all the work */
5796 oneshot = 1;
5797 }
5798 af = frominet.ss_family;
5799 close(fd[stream_idx]);
5800 fd[stream_idx]=nfd;
5801 if (sockopterr && trans &&
5802 (stream_idx > 0) && datamss) {
5803 optlen = sizeof(datamss);
5804 if ((sockopterr = setsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, optlen)) < 0) {
5805 if (errno != EINVAL)
5806 err("unable to set maximum segment size");
5807 else
5808 err("setting maximum segment size not supported on this OS");
5809 }
5810 }
5811 if (stream_idx == nstream) {
5812 optlen = sizeof(datamss);
5813 if (getsockopt(fd[stream_idx], IPPROTO_TCP, TCP_MAXSEG, (void *)&datamss, &optlen) < 0)
5814 err("get dataconn maximum segment size didn't work");
5815 if (format & DEBUGMTU)
5816 fprintf(stderr, "datamss = %d\n", datamss);
5817 }
5818 if (af == AF_INET) {
5819 struct sockaddr_in peer;
5820 socklen_t peerlen = sizeof(peer);
5821 if (getpeername(fd[stream_idx],
5822 (struct sockaddr *)&peer,
5823 &peerlen) < 0) {
5824 err("getpeername");
5825 }
5826 if ((stream_idx == nstream) && (brief <= 0)) {
5827 char tmphost[ADDRSTRLEN] = "\0";
5828 inet_ntop(af, &peer.sin_addr.s_addr, tmphost, sizeof(tmphost));
5829
5830 if (format & PARSE) {
5831 fprintf(stdout,
5832 "nuttcp%s%s: accept=%s",
5833 trans?"-t":"-r", ident,
5834 tmphost);
5835 if (trans && datamss) {
5836 fprintf(stdout, " mss=%d",
5837 datamss);
5838 }
5839 }
5840 else {
5841 fprintf(stdout,
5842 "nuttcp%s%s: accept from %s with",
5843 trans?"-t":"-r", ident,
5844 tmphost);
5845 if (trans && datamss) {
5846 fprintf(stdout, " mss=%d,",
5847 datamss);
5848 }
5849 }
5850 if (af == AF_INET) {
5851 fprintf(stdout, " af=inet");
5852 }
5853 #ifdef AF_INET6
5854 else if (af == AF_INET6) {
5855 fprintf(stdout, " af=inet6");
5856 }
5857 #endif
5858 else {
5859 fprintf(stdout, " af=%d", af);
5860 }
5861 fprintf(stdout, "\n");
5862 }
5863 if (stream_idx == 0) {
5864 clientaddr = peer.sin_addr;
5865 client_ipaddr.ss.ss_family = AF_INET;
5866 client_ipaddr.sin.sin_addr = clientaddr;
5867 }
5868 }
5869 #ifdef AF_INET6
5870 else if (af == AF_INET6) {
5871 struct sockaddr_in6 peer6;
5872 struct sockaddr_in peer4;
5873 socklen_t peerlen = sizeof(peer6);
5874 if (getpeername(fd[stream_idx],
5875 (struct sockaddr *)&peer6,
5876 &peerlen) < 0) {
5877 err("getpeername");
5878 }
5879 if ((stream_idx == nstream) && (brief <= 0)) {
5880 char tmphost[ADDRSTRLEN] = "\0";
5881 if (!IN6_IS_ADDR_V4MAPPED(&peer6.sin6_addr)) {
5882 inet_ntop(af, peer6.sin6_addr.s6_addr, tmphost, sizeof(tmphost));
5883 }
5884 else {
5885 af = AF_INET;
5886 bcopy(((char *)&peer6.sin6_addr.s6_addr) + 12,
5887 (char *)&peer4.sin_addr.s_addr,
5888 sizeof(struct in_addr));
5889 peer4.sin_family = AF_INET;
5890 peer4.sin_port = peer6.sin6_port;
5891 inet_ntop(af, &peer4.sin_addr.s_addr, tmphost, sizeof(tmphost));
5892 }
5893 if (format & PARSE) {
5894 fprintf(stdout,
5895 "nuttcp%s%s: accept=%s",
5896 trans?"-t":"-r", ident,
5897 tmphost);
5898 if (trans && datamss) {
5899 fprintf(stdout, " mss=%d", datamss);
5900 }
5901 }
5902 else {
5903 fprintf(stdout,
5904 "nuttcp%s%s: accept from %s with",
5905 trans?"-t":"-r", ident,
5906 tmphost);
5907 if (trans && datamss) {
5908 fprintf(stdout, " mss=%d,",
5909 datamss);
5910 }
5911 }
5912 if (af == AF_INET) {
5913 fprintf(stdout, " af=inet");
5914 }
5915 #ifdef AF_INET6
5916 else if (af == AF_INET6) {
5917 fprintf(stdout, " af=inet6");
5918 }
5919 #endif
5920 else {
5921 fprintf(stdout, " af=%d", af);
5922 }
5923 fprintf(stdout, "\n");
5924 }
5925 if (stream_idx == 0) {
5926 if (af == AF_INET6) { // we didnt fix a mapped v4 ip
5927 clientaddr6 = peer6.sin6_addr;
5928 clientscope6 = peer6.sin6_scope_id;
5929 client_ipaddr.ss.ss_family = AF_INET6;
5930 client_ipaddr.sin6.sin6_addr = clientaddr6;
5931 }
5932 else { // mapped so af is AF_INET
5933 clientaddr = peer4.sin_addr;
5934 client_ipaddr.ss.ss_family = AF_INET;
5935 client_ipaddr.sin.sin_addr = clientaddr;
5936 }
5937 }
5938 }
5939 #endif
5940 else {
5941 err("unsupported AF");
5942 }
5943 }
5944 }
5945 if (!udp && trans && (stream_idx >= 1) && (retransinfo > 0)) {
5946 if ((stream_idx == 1) || (retransinfo == 1)) {
5947 nretrans[stream_idx] =
5948 get_retrans(fd[stream_idx], &tcpinf);
5949 iretrans[stream_idx] = nretrans[stream_idx];
5950 #if defined(linux)
5951 if (retransinfo == 1) {
5952 cwnd[stream_idx] =
5953 tcpinf.tcpinfo_snd_cwnd
5954 *datamss/1024;
5955 if (stream_idx == 1) {
5956 init_pkt_cwnd =
5957 tcpinf.tcpinfo_snd_cwnd;
5958 sss_pkt_cwnd = init_pkt_cwnd;
5959 }
5960 }
5961 #endif
5962 }
5963 }
5964 optlen = sizeof(sendwinval);
5965 if (getsockopt(fd[stream_idx], SOL_SOCKET, SO_SNDBUF, (void *)&sendwinval, &optlen) < 0)
5966 err("get send window size didn't work");
5967 #if defined(linux)
5968 sendwinval /= 2;
5969 #endif
5970 if ((stream_idx > 0) && sendwin && (trans || braindead) &&
5971 (sendwinval < (0.98 * sendwin))) {
5972 if (format & PARSE)
5973 fprintf(stderr, "nuttcp%s%s: Warning=\"send_window_size_%d_<_requested_window_size_%d\"\n",
5974 trans?"-t":"-r", ident,
5975 sendwinval, sendwin);
5976 else
5977 fprintf(stderr, "nuttcp%s%s: Warning: send window size %d < requested window size %d\n",
5978 trans?"-t":"-r", ident,
5979 sendwinval, sendwin);
5980 fflush(stderr);
5981 }
5982 optlen = sizeof(rcvwinval);
5983 if (getsockopt(fd[stream_idx], SOL_SOCKET, SO_RCVBUF, (void *)&rcvwinval, &optlen) < 0)
5984 err("Get recv window size didn't work");
5985 #if defined(linux)
5986 rcvwinval /= 2;
5987 #endif
5988 if ((stream_idx > 0) && rcvwin && (!trans || braindead) &&
5989 (rcvwinval < (0.98 * rcvwin))) {
5990 if (format & PARSE)
5991 fprintf(stderr, "nuttcp%s%s: Warning=\"receive_window_size_%d_<_requested_window_size_%d\"\n",
5992 trans?"-t":"-r", ident,
5993 rcvwinval, rcvwin);
5994 else
5995 fprintf(stderr, "nuttcp%s%s: Warning: receive window size %d < requested window size %d\n",
5996 trans?"-t":"-r", ident,
5997 rcvwinval, rcvwin);
5998 fflush(stderr);
5999 }
6000
6001 if (firsttime) {
6002 firsttime = 0;
6003 origsendwin = sendwinval;
6004 origrcvwin = rcvwinval;
6005 }
6006
6007 if ((stream_idx == nstream) && (brief <= 0)) {
6008 #if defined(linux)
6009 FILE *adv_ws;
6010
6011 sendwinval *= 2;
6012 rcvwinval *= 2;
6013 if ((adv_ws = fopen(TCP_ADV_WIN_SCALE, "r"))) {
6014 if (fscanf(adv_ws, "%d", &winadjust) <= 0)
6015 winadjust = 2;
6016 fclose(adv_ws);
6017 }
6018 else {
6019 winadjust = 2;
6020 }
6021 if (winadjust < 0) {
6022 sendwinavail = sendwinval >> -winadjust;
6023 rcvwinavail = rcvwinval >> -winadjust;
6024 }
6025 else if (winadjust > 0) {
6026 sendwinavail = sendwinval -
6027 (sendwinval >> winadjust);
6028 rcvwinavail = rcvwinval -
6029 (rcvwinval >> winadjust);
6030 }
6031 #endif
6032 if (format & PARSE)
6033 fprintf(stdout, "nuttcp%s%s: send_window_size=%d receive_window_size=%d\n", trans?"-t":"-r", ident, sendwinval, rcvwinval);
6034 else
6035 fprintf(stdout, "nuttcp%s%s: send window size = %d, receive window size = %d\n", trans?"-t":"-r", ident, sendwinval, rcvwinval);
6036 #if defined(linux)
6037 if (format & PARSE)
6038 fprintf(stdout, "nuttcp%s%s: send_window_avail=%d receive_window_avail=%d\n", trans?"-t":"-r", ident, sendwinavail, rcvwinavail);
6039 else
6040 fprintf(stdout, "nuttcp%s%s: available send window = %d, available receive window = %d\n", trans?"-t":"-r", ident, sendwinavail, rcvwinavail);
6041 if (!udp && trans && init_pkt_cwnd) {
6042 if (format & PARSE)
6043 fprintf(stdout, "nuttcp%s%s: initial_congestion_window_kb=%d initial_congestion_window_pkt=%d\n", trans?"-t":"-r", ident, init_pkt_cwnd*datamss/1024, init_pkt_cwnd);
6044 else
6045 fprintf(stdout, "nuttcp%s%s: initial congestion window = %d KB (%d packets)\n", trans?"-t":"-r", ident, init_pkt_cwnd*datamss/1024, init_pkt_cwnd);
6046 }
6047 #endif
6048 }
6049 }
6050
6051 if (abortconn)
6052 exit(1);
6053
6054 if (host3 && clientserver) {
6055 char path[64];
6056 char *cmd;
6057
6058 fflush(stdout);
6059 fflush(stderr);
6060 cmd = nut_cmd;
6061
6062 if (client) {
6063 if ((pid = fork()) == (pid_t)-1)
6064 err("can't fork");
6065 if (pid == 0) {
6066 if (interval) {
6067 itimer.it_value.tv_sec = interval;
6068 }
6069 else if (timeout) {
6070 itimer.it_value.tv_sec = timeout;
6071 }
6072 else {
6073 if (rate != MAXRATE)
6074 itimer.it_value.tv_sec =
6075 (double)(2*nbuf*buflen)
6076 /rate/125;
6077 else
6078 itimer.it_value.tv_sec =
6079 (double)(nbuf*buflen)
6080 /LOW_RATE_HOST3/125;
6081 if (itimer.it_value.tv_sec < 7200)
6082 itimer.it_value.tv_sec = 7200;
6083 }
6084 itimer.it_value.tv_sec +=
6085 idle_data_max < SRVR_INFO_TIMEOUT ?
6086 SRVR_INFO_TIMEOUT : idle_data_max;
6087 itimer.it_value.tv_usec = 0;
6088 itimer.it_interval.tv_sec = 0;
6089 itimer.it_interval.tv_usec = 0;
6090 setitimer(ITIMER_REAL, &itimer, 0);
6091 while (fgets(linebuf, sizeof(linebuf),
6092 stdin) && !intr) {
6093 setitimer(ITIMER_REAL, &itimer, 0);
6094 if (strncmp(linebuf, "DONE", 4)
6095 == 0)
6096 exit(0);
6097 if (*ident && (*linebuf != '\n'))
6098 fprintf(stdout, "%s: ",
6099 ident + 1);
6100 fputs(linebuf, stdout);
6101 fflush(stdout);
6102 }
6103 itimer.it_value.tv_sec = 0;
6104 itimer.it_value.tv_usec = 0;
6105 setitimer(ITIMER_REAL, &itimer, 0);
6106 exit(0);
6107 }
6108 signal(SIGINT, SIG_IGN);
6109 while ((wait_pid = wait(&pidstat)) != pid) {
6110 if (wait_pid == (pid_t)-1) {
6111 if (errno == ECHILD)
6112 break;
6113 err("wait failed");
6114 }
6115 }
6116 exit(0);
6117 }
6118 else {
6119 if ((pid = fork()) == (pid_t)-1)
6120 err("can't fork");
6121 if (pid != 0) {
6122 sigact.sa_handler = &sigalarm;
6123 sigemptyset(&sigact.sa_mask);
6124 sigact.sa_flags = 0;
6125 sigaction(SIGALRM, &sigact, 0);
6126 alarm(10);
6127 while ((wait_pid = wait(&pidstat))
6128 != pid) {
6129 if (wait_pid == (pid_t)-1) {
6130 if (errno == ECHILD)
6131 break;
6132 if (errno == EINTR) {
6133 pollfds[0].fd =
6134 fileno(ctlconn);
6135 pollfds[0].events =
6136 POLLIN | POLLPRI;
6137 pollfds[0].revents = 0;
6138 if ((poll(pollfds, 1, 0)
6139 > 0)
6140 && (pollfds[0].revents &
6141 (POLLIN | POLLPRI))) {
6142 kill(pid,
6143 SIGINT);
6144 sleep(1);
6145 kill(pid,
6146 SIGINT);
6147 continue;
6148 }
6149 sigact.sa_handler =
6150 &sigalarm;
6151 sigemptyset(&sigact.sa_mask);
6152 sigact.sa_flags = 0;
6153 sigaction(SIGALRM,
6154 &sigact, 0);
6155 alarm(10);
6156 continue;
6157 }
6158 err("wait failed");
6159 }
6160 }
6161 fprintf(stdout, "DONE\n");
6162 fflush(stdout);
6163 goto cleanup;
6164 }
6165 close(2);
6166 dup(1);
6167 i = 0;
6168 j = 0;
6169 cmdargs[i++] = cmd;
6170 cmdargs[i++] = "-3";
6171 if (af3) {
6172 if (af3 == 4)
6173 cmdargs[i++] = "-4";
6174 if (af3 == 6)
6175 cmdargs[i++] = "-6";
6176 }
6177 if (ctlport3) {
6178 sprintf(tmpargs[j], "-P%hu", ctlport3);
6179 cmdargs[i++] = tmpargs[j++];
6180 }
6181 else {
6182 if (pass_ctlport) {
6183 sprintf(tmpargs[j], "-P%hu", ctlport);
6184 cmdargs[i++] = tmpargs[j++];
6185 }
6186 }
6187 if (affinity >= 0) {
6188 sprintf(tmpargs[j], "-xc%d", affinity);
6189 cmdargs[i++] = tmpargs[j++];
6190 }
6191 if (srvr_affinity >= 0) {
6192 sprintf(tmpargs[j], "-xcs%d", srvr_affinity);
6193 cmdargs[i++] = tmpargs[j++];
6194 }
6195 if (irvers < 50302) {
6196 if ((udp && !multicast
6197 && (buflen != DEFAULTUDPBUFLEN)) ||
6198 (udp && multicast
6199 && (buflen != DEFAULT_MC_UDPBUFLEN)) ||
6200 (!udp && (buflen != 65536))) {
6201 sprintf(tmpargs[j], "-l%d", buflen);
6202 cmdargs[i++] = tmpargs[j++];
6203 }
6204 }
6205 else if (buflen) {
6206 sprintf(tmpargs[j], "-l%d", buflen);
6207 cmdargs[i++] = tmpargs[j++];
6208 }
6209 if (nbuf != INT_MAX) {
6210 if (nbuf_bytes)
6211 sprintf(tmpargs[j], "-n%llub", nbuf);
6212 else
6213 sprintf(tmpargs[j], "-n%llu", nbuf);
6214 cmdargs[i++] = tmpargs[j++];
6215 }
6216 if (brief3 != 1) {
6217 sprintf(tmpargs[j], "-b%d", brief3);
6218 cmdargs[i++] = tmpargs[j++];
6219 }
6220 if (sendwin) {
6221 sprintf(tmpargs[j], "-w%d", sendwin/1024);
6222 cmdargs[i++] = tmpargs[j++];
6223 }
6224 if (nstream != 1) {
6225 sprintf(tmpargs[j], "-N%d%s", nstream,
6226 multilink ? "m" : "");
6227 cmdargs[i++] = tmpargs[j++];
6228 }
6229 if (rate != MAXRATE) {
6230 if (maxburst > 1) {
6231 if (rate_pps)
6232 sprintf(tmpargs[j],
6233 "-R%s%lup/%d",
6234 irate ? "i" : "",
6235 rate, maxburst);
6236 else
6237 sprintf(tmpargs[j],
6238 "-R%s%lu/%d",
6239 irate ? "i" : "",
6240 rate, maxburst);
6241 }
6242 else {
6243 if (rate_pps)
6244 sprintf(tmpargs[j],
6245 "-R%s%s%lup",
6246 irate ? "i" : "",
6247 iratesss ? "s" : "",
6248 rate);
6249 else
6250 sprintf(tmpargs[j],
6251 "-R%s%s%lu",
6252 irate ? "i" : "",
6253 iratesss ? "s" : "",
6254 rate);
6255 }
6256 cmdargs[i++] = tmpargs[j++];
6257 }
6258 else {
6259 if (udp && !multicast)
6260 cmdargs[i++] = "-R0";
6261 }
6262 if (srcport) {
6263 sprintf(tmpargs[j], "-p%hu:%hu", srcport, port);
6264 cmdargs[i++] = tmpargs[j++];
6265 }
6266 else if (port != DEFAULT_PORT) {
6267 sprintf(tmpargs[j], "-p%hu", port);
6268 cmdargs[i++] = tmpargs[j++];
6269 }
6270 if (trans)
6271 cmdargs[i++] = "-r";
6272 if (braindead)
6273 cmdargs[i++] = "-wb";
6274 if (timeout && (timeout != DEFAULT_TIMEOUT)) {
6275 sprintf(tmpargs[j], "-T%f", timeout);
6276 cmdargs[i++] = tmpargs[j++];
6277 }
6278 if (udp) {
6279 if (multicast) {
6280 if (ssm == 1)
6281 sprintf(tmpargs[j], "-ms%d",
6282 multicast);
6283 else if (ssm == 0)
6284 sprintf(tmpargs[j], "-ma%d",
6285 multicast);
6286 else
6287 sprintf(tmpargs[j], "-m%d",
6288 multicast);
6289 cmdargs[i++] = tmpargs[j++];
6290 if (mc_addr) {
6291 sprintf(tmpargs[j], "-g%s",
6292 mc_addr);
6293 cmdargs[i++] = tmpargs[j++];
6294 }
6295 }
6296 else
6297 cmdargs[i++] = "-u";
6298 }
6299 if (do_jitter) {
6300 cmdargs[i++] = "-j";
6301 }
6302 if (do_owd) {
6303 cmdargs[i++] = "-o";
6304 }
6305 if (interval) {
6306 sprintf(tmpargs[j], "-i%f", interval);
6307 cmdargs[i++] = tmpargs[j++];
6308 }
6309 if (reverse)
6310 cmdargs[i++] = "-F";
6311 if (format) {
6312 if (format & XMITSTATS)
6313 cmdargs[i++] = "-fxmitstats";
6314 if (format & RUNNINGTOTAL)
6315 cmdargs[i++] = "-frunningtotal";
6316 if (format & NOPERCENTLOSS)
6317 cmdargs[i++] = "-f-percentloss";
6318 if (format & NODROPS)
6319 cmdargs[i++] = "-f-drops";
6320 if (format & NORETRANS)
6321 cmdargs[i++] = "-f-retrans";
6322 if (!(format & NORETRANS) && (format & NOCWND))
6323 cmdargs[i++] = "-f-cwnd";
6324 if (format & PARSE)
6325 cmdargs[i++] = "-fparse";
6326 }
6327 else {
6328 cmdargs[i++] = "-f-rtt";
6329 }
6330 if (traceroute)
6331 cmdargs[i++] = "-xt";
6332 if (datamss) {
6333 sprintf(tmpargs[j], "-M%d", datamss);
6334 cmdargs[i++] = tmpargs[j++];
6335 }
6336 if (tos) {
6337 sprintf(tmpargs[j], "-c0x%Xt", tos);
6338 cmdargs[i++] = tmpargs[j++];
6339 }
6340 if (nodelay)
6341 cmdargs[i++] = "-D";
6342 if (ipad_stride.ip32) {
6343 sprintf(tmpargs[j], "%s+%d", host3,
6344 ipad_stride.ip32);
6345 cmdargs[i++] = tmpargs[j++];
6346 }
6347 else
6348 cmdargs[i++] = host3;
6349 cmdargs[i] = NULL;
6350 execvp(cmd, cmdargs);
6351 if (errno == ENOENT) {
6352 strcpy(path, "/usr/local/sbin/");
6353 strcat(path, cmd);
6354 execv(path, cmdargs);
6355 }
6356 if (errno == ENOENT) {
6357 strcpy(path, "/usr/local/bin/");
6358 strcat(path, cmd);
6359 execv(path, cmdargs);
6360 }
6361 if (errno == ENOENT) {
6362 strcpy(path, "/usr/sbin/");
6363 strcat(path, cmd);
6364 execv(path, cmdargs);
6365 }
6366 if (errno == ENOENT) {
6367 strcpy(path, "/sbin/");
6368 strcat(path, cmd);
6369 execv(path, cmdargs);
6370 }
6371 if (errno == ENOENT) {
6372 strcpy(path, "/usr/etc/");
6373 strcat(path, cmd);
6374 execv(path, cmdargs);
6375 }
6376 if ((errno == ENOENT) && (getuid() != 0)
6377 && (geteuid() != 0)) {
6378 strcpy(path, "./");
6379 strcat(path, cmd);
6380 execv(path, cmdargs);
6381 }
6382 perror("execvp failed");
6383 fprintf(stderr, "failed to execute %s\n", cmd);
6384 fflush(stdout);
6385 fflush(stderr);
6386 if (!inetd)
6387 exit(0);
6388 goto cleanup;
6389 }
6390 }
6391
6392 if (traceroute && clientserver) {
6393 char path[64];
6394 char *cmd;
6395
6396 fflush(stdout);
6397 fflush(stderr);
6398 if (multicast) {
6399 cmd = "mtrace";
6400 #ifdef AF_INET6
6401 if (af == AF_INET6)
6402 cmd = "mtrace6";
6403 #endif
6404 }
6405 else {
6406 cmd = "traceroute";
6407 #ifdef AF_INET6
6408 if (af == AF_INET6)
6409 cmd = "traceroute6";
6410 #endif
6411 }
6412 if (client) {
6413 if ((pid = fork()) == (pid_t)-1)
6414 err("can't fork");
6415 if (pid != 0) {
6416 while ((wait_pid = wait(&pidstat)) != pid) {
6417 if (wait_pid == (pid_t)-1) {
6418 if (errno == ECHILD)
6419 break;
6420 err("wait failed");
6421 }
6422 }
6423 fflush(stdout);
6424 }
6425 else {
6426 signal(SIGINT, SIG_DFL);
6427 close(2);
6428 dup(1);
6429 i = 0;
6430 cmdargs[i++] = cmd;
6431 cmdargs[i++] = host;
6432 cmdargs[i] = NULL;
6433 execvp(cmd, cmdargs);
6434 if (errno == ENOENT) {
6435 strcpy(path, "/usr/local/sbin/");
6436 strcat(path, cmd);
6437 execv(path, cmdargs);
6438 }
6439 if (errno == ENOENT) {
6440 strcpy(path, "/usr/local/bin/");
6441 strcat(path, cmd);
6442 execv(path, cmdargs);
6443 }
6444 if (errno == ENOENT) {
6445 strcpy(path, "/usr/sbin/");
6446 strcat(path, cmd);
6447 execv(path, cmdargs);
6448 }
6449 if (errno == ENOENT) {
6450 strcpy(path, "/sbin/");
6451 strcat(path, cmd);
6452 execv(path, cmdargs);
6453 }
6454 if (errno == ENOENT) {
6455 strcpy(path, "/usr/etc/");
6456 strcat(path, cmd);
6457 execv(path, cmdargs);
6458 }
6459 perror("execvp failed");
6460 fprintf(stderr, "failed to execute %s\n", cmd);
6461 fflush(stdout);
6462 fflush(stderr);
6463 exit(0);
6464 }
6465 }
6466 fprintf(stdout, "\n");
6467 if (intr) {
6468 intr = 0;
6469 fprintf(stdout, "\n");
6470 signal(SIGINT, sigint);
6471 }
6472 if (!skip_data) {
6473 for ( stream_idx = 1; stream_idx <= nstream;
6474 stream_idx++ )
6475 close(fd[stream_idx]);
6476 }
6477 if (client) {
6478 if ((pid = fork()) == (pid_t)-1)
6479 err("can't fork");
6480 if (pid == 0) {
6481 while (fgets(linebuf, sizeof(linebuf),
6482 stdin) && !intr) {
6483 if (strncmp(linebuf, "DONE", 4)
6484 == 0)
6485 exit(0);
6486 fputs(linebuf, stdout);
6487 fflush(stdout);
6488 }
6489 exit(0);
6490 }
6491 signal(SIGINT, SIG_IGN);
6492 while ((wait_pid = wait(&pidstat)) != pid) {
6493 if (wait_pid == (pid_t)-1) {
6494 if (errno == ECHILD)
6495 break;
6496 err("wait failed");
6497 }
6498 }
6499 exit(0);
6500 }
6501 else {
6502 if (!inetd) {
6503 if ((pid = fork()) == (pid_t)-1)
6504 err("can't fork");
6505 if (pid != 0) {
6506 while ((wait_pid = wait(&pidstat))
6507 != pid) {
6508 if (wait_pid == (pid_t)-1) {
6509 if (errno == ECHILD)
6510 break;
6511 err("wait failed");
6512 }
6513 }
6514 fprintf(stdout, "DONE\n");
6515 fflush(stdout);
6516 goto cleanup;
6517 }
6518 }
6519 close(2);
6520 dup(1);
6521 i = 0;
6522 cmdargs[i++] = cmd;
6523 cmdargs[i++] = host;
6524 cmdargs[i] = NULL;
6525 execvp(cmd, cmdargs);
6526 if (errno == ENOENT) {
6527 strcpy(path, "/usr/local/sbin/");
6528 strcat(path, cmd);
6529 execv(path, cmdargs);
6530 }
6531 if (errno == ENOENT) {
6532 strcpy(path, "/usr/local/bin/");
6533 strcat(path, cmd);
6534 execv(path, cmdargs);
6535 }
6536 if (errno == ENOENT) {
6537 strcpy(path, "/usr/sbin/");
6538 strcat(path, cmd);
6539 execv(path, cmdargs);
6540 }
6541 if (errno == ENOENT) {
6542 strcpy(path, "/sbin/");
6543 strcat(path, cmd);
6544 execv(path, cmdargs);
6545 }
6546 if (errno == ENOENT) {
6547 strcpy(path, "/usr/etc/");
6548 strcat(path, cmd);
6549 execv(path, cmdargs);
6550 }
6551 perror("execvp failed");
6552 fprintf(stderr, "failed to execute %s\n", cmd);
6553 fflush(stdout);
6554 fflush(stderr);
6555 if (!inetd)
6556 exit(0);
6557 goto cleanup;
6558 }
6559 }
6560
6561 if (multicast) {
6562 struct sockaddr_in peer;
6563 socklen_t peerlen = sizeof(peer);
6564 struct sockaddr_in me;
6565 socklen_t melen = sizeof(me);
6566 #ifdef AF_INET6
6567 struct sockaddr_in6 peer6;
6568 socklen_t peer6len = sizeof(peer6);
6569 struct sockaddr_in6 me6;
6570 socklen_t me6len = sizeof(me6);
6571 #endif
6572 if (mc_addr && !client) {
6573 bzero(&hints, sizeof(hints));
6574 hints.ai_flags = AI_NUMERICHOST;
6575 if (udp)
6576 hints.ai_socktype = SOCK_DGRAM;
6577 else
6578 hints.ai_socktype = SOCK_STREAM;
6579 mcres = NULL;
6580 error_num = getaddrinfo(mc_addr, NULL, &hints, &mcres);
6581 if (error_num) {
6582 sprintf(tmpbuf, "getaddrinfo: "
6583 "bad multicast IP address: "
6584 "%s: %s",
6585 mc_addr, gai_strerror(error_num));
6586 errno = EINVAL;
6587 err(tmpbuf);
6588 }
6589 if (mcres->ai_family == AF_INET) {
6590 struct sockaddr_in *group;
6591 struct in_addr ipv4_mcaddr;
6592
6593 group = (struct sockaddr_in *)mcres->ai_addr;
6594 bcopy((char *)&(group->sin_addr),
6595 (char *)&ipv4_mcaddr,
6596 sizeof(struct in_addr));
6597 if (ssm) {
6598 if (((htonl(ipv4_mcaddr.s_addr)
6599 & 0xFF000000) !=
6600 (HI_MC_SSM << 24))) {
6601 sprintf(tmpbuf,
6602 "bad SSM multicast "
6603 "IP address: %s: "
6604 "use 232.x.y.z",
6605 mcgaddr);
6606 errno = EINVAL;
6607 err(tmpbuf);
6608 }
6609 }
6610 else {
6611 if (((htonl(ipv4_mcaddr.s_addr)
6612 & 0xFF000000) !=
6613 (HI_MC << 24))) {
6614 sprintf(tmpbuf,
6615 "bad ASM multicast "
6616 "IP address: %s: "
6617 "use 231.x.y.z",
6618 mcgaddr);
6619 errno = EINVAL;
6620 err(tmpbuf);
6621 }
6622 }
6623 }
6624 #ifdef AF_INET6
6625 if (mcres->ai_family == AF_INET6) {
6626 struct sockaddr_in6 *group;
6627
6628 group = (struct sockaddr_in6 *)mcres->ai_addr;
6629 if (ssm) {
6630 if ((bcmp((char *)&(group->sin6_addr),
6631 (char *)&hi_mc6,
6632 HI_MC6_LEN - 1) != 0) ||
6633 (group->sin6_addr.s6_addr[HI_MC6_LEN - 1]
6634 < 0x80)) {
6635 sprintf(tmpbuf,
6636 "bad SSM multicast "
6637 "IP address: %s: use "
6638 "ff3e::[8-f]xxx:yyyy",
6639 mcgaddr);
6640 errno = EINVAL;
6641 err(tmpbuf);
6642 }
6643 }
6644 else {
6645 if ((bcmp((char *)&(group->sin6_addr),
6646 (char *)&hi_mc6_asm,
6647 HI_MC6_ASM_LEN) != 0)) {
6648 sprintf(tmpbuf,
6649 "bad ASM multicast "
6650 "IP address: %s: use "
6651 "ff2e::wwww:xxxx:"
6652 "yyyy:zzzz",
6653 mcgaddr);
6654 errno = EINVAL;
6655 err(tmpbuf);
6656 }
6657 }
6658 }
6659 #endif
6660 mc_af = mcres->ai_family;
6661 }
6662
6663 if (mc_af == AF_INET) {
6664 if (getpeername(fd[0], (struct sockaddr *)&peer,
6665 &peerlen) < 0) {
6666 err("getpeername");
6667 }
6668 if (getsockname(fd[0], (struct sockaddr *)&me,
6669 &melen) < 0) {
6670 err("getsockname");
6671 }
6672 }
6673 #ifdef AF_INET6
6674 else if (mc_af == AF_INET6) {
6675 if (getpeername(fd[0], (struct sockaddr *)&peer6,
6676 &peer6len) < 0) {
6677 err("getpeername");
6678 }
6679 if (getsockname(fd[0], (struct sockaddr *)&me6,
6680 &me6len) < 0) {
6681 err("getsockname");
6682 }
6683 }
6684 #endif /* AF_INET6 */
6685 else {
6686 err("unsupported AF");
6687 }
6688
6689 if (!trans) {
6690 if ((mc_af == AF_INET) && !ssm) { /* IPv4 ASM */
6691 /* The multicast receiver must join the mc group */
6692 if (mc_addr) {
6693 struct sockaddr_in *user_group;
6694
6695 user_group =
6696 (struct sockaddr_in *)mcres->ai_addr;
6697 bcopy((char *)&(user_group->sin_addr.s_addr),
6698 (char *)&mc_group.imr_multiaddr.s_addr,
6699 sizeof(struct in_addr));
6700 }
6701 else if (client && (irvers >= 50505)) {
6702 bcopy((char *)&me.sin_addr.s_addr,
6703 (char *)&mc_group.imr_multiaddr.s_addr,
6704 sizeof(struct in_addr));
6705 }
6706 else {
6707 bcopy((char *)&peer.sin_addr.s_addr,
6708 (char *)&mc_group.imr_multiaddr.s_addr,
6709 sizeof(struct in_addr));
6710 }
6711 if (!mc_addr) {
6712 mc_group.imr_multiaddr.s_addr &=
6713 htonl(0xFFFFFF);
6714 mc_group.imr_multiaddr.s_addr |=
6715 htonl(HI_MC << 24);
6716 }
6717 if (setsockopt(fd[1], IPPROTO_IP, IP_ADD_MEMBERSHIP,
6718 (void *)&mc_group, sizeof(mc_group)) < 0)
6719 err("setsockopt: IP_ADD_MEMBERSHIP");
6720 if (brief <= 0) {
6721 inet_ntop(mc_af, &peer.sin_addr.s_addr,
6722 multsrc, sizeof(multsrc));
6723 inet_ntop(mc_af, &mc_group.imr_multiaddr,
6724 multaddr, sizeof(multaddr));
6725
6726 if (format & PARSE) {
6727 fprintf(stdout,
6728 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=0\n",
6729 trans?"-t":"-r", ident,
6730 multsrc, multaddr);
6731 }
6732 else {
6733 fprintf(stdout,
6734 "nuttcp%s%s: receive from multicast source %s\n",
6735 trans?"-t":"-r", ident,
6736 multsrc);
6737 fprintf(stdout,
6738 "nuttcp%s%s: using asm on multicast group %s\n",
6739 trans?"-t":"-r", ident,
6740 multaddr);
6741 }
6742 }
6743 }
6744 #ifdef AF_INET6
6745 else if ((mc_af == AF_INET6) && !ssm) { /* IPv6 ASM */
6746 /* The multicast receiver must join the mc group */
6747 if (mc_addr) {
6748 struct sockaddr_in6 *user_group;
6749
6750 user_group =
6751 (struct sockaddr_in6 *)mcres->ai_addr;
6752 bcopy((char *)&(user_group->sin6_addr),
6753 (char *)&mc6_group.ipv6mr_multiaddr,
6754 sizeof(struct in6_addr));
6755 }
6756 else if (client) {
6757 bcopy((char *)&me6.sin6_addr,
6758 (char *)&mc6_group.ipv6mr_multiaddr,
6759 sizeof(struct in6_addr));
6760 }
6761 else {
6762 bcopy((char *)&peer6.sin6_addr,
6763 (char *)&mc6_group.ipv6mr_multiaddr,
6764 sizeof(struct in6_addr));
6765 }
6766 if (!mc_addr) {
6767 bcopy((char *)&hi_mc6_asm,
6768 (char *)&mc6_group.ipv6mr_multiaddr,
6769 HI_MC6_ASM_LEN);
6770 }
6771 if (setsockopt(fd[1], IPPROTO_IPV6, IPV6_JOIN_GROUP,
6772 (void *)&mc6_group,
6773 sizeof(mc6_group)) < 0)
6774 err("setsockopt: IPV6_JOIN_GROUP");
6775 if (brief <= 0) {
6776 inet_ntop(mc_af, &peer6.sin6_addr,
6777 multsrc, sizeof(multsrc));
6778 inet_ntop(mc_af, &mc6_group.ipv6mr_multiaddr,
6779 multaddr, sizeof(multaddr));
6780
6781 if (format & PARSE) {
6782 fprintf(stdout,
6783 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=0\n",
6784 trans?"-t":"-r", ident,
6785 multsrc, multaddr);
6786 }
6787 else {
6788 fprintf(stdout,
6789 "nuttcp%s%s: receive from multicast source %s\n",
6790 trans?"-t":"-r", ident,
6791 multsrc);
6792 fprintf(stdout,
6793 "nuttcp%s%s: using asm on multicast group %s\n",
6794 trans?"-t":"-r", ident,
6795 multaddr);
6796 }
6797 }
6798 }
6799 #endif /* AF_INET6 */
6800 #ifdef MCAST_JOIN_SOURCE_GROUP
6801 else if ((mc_af == AF_INET) && ssm) { /* IPv4 SSM */
6802 /* multicast receiver joins the mc source group */
6803 union sockaddr_union group_ipaddr;
6804 struct sockaddr_in *group;
6805 struct sockaddr_in *source;
6806
6807 group = &group_ipaddr.sin;
6808 source =
6809 (struct sockaddr_in *)&group_source_req.gsr_source;
6810 group_source_req.gsr_interface = 0; /* any interface */
6811 if (mc_addr) {
6812 struct sockaddr_in *user_group;
6813
6814 user_group =
6815 (struct sockaddr_in *)mcres->ai_addr;
6816 bcopy((char *)user_group, (char *)group,
6817 sizeof(struct sockaddr_in));
6818 }
6819 else if (client) {
6820 bcopy((char *)&me, (char *)group,
6821 sizeof(struct sockaddr_in));
6822 }
6823 else {
6824 bcopy((char *)&peer, (char *)group,
6825 sizeof(struct sockaddr_in));
6826 }
6827 bcopy((char *)&peer, (char *)source,
6828 sizeof(struct sockaddr_in));
6829 if (!mc_addr) {
6830 group->sin_addr.s_addr &= htonl(0xFFFFFF);
6831 group->sin_addr.s_addr |=
6832 htonl(HI_MC_SSM << 24);
6833 }
6834 group_source_req.gsr_group = group_ipaddr.ss;
6835 if (setsockopt(fd[1], IPPROTO_IP,
6836 MCAST_JOIN_SOURCE_GROUP,
6837 &group_source_req,
6838 sizeof(group_source_req)) < 0)
6839 err("setsockopt: MCAST_JOIN_SOURCE_GROUP");
6840 if (brief <= 0) {
6841 inet_ntop(mc_af, &source->sin_addr.s_addr,
6842 multsrc, sizeof(multsrc));
6843 inet_ntop(mc_af, &group->sin_addr.s_addr,
6844 multaddr, sizeof(multaddr));
6845 if (format & PARSE) {
6846 fprintf(stdout,
6847 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=1\n",
6848 trans?"-t":"-r", ident,
6849 multsrc, multaddr);
6850 }
6851 else {
6852 fprintf(stdout,
6853 "nuttcp%s%s: receive from multicast source %s\n",
6854 trans?"-t":"-r", ident,
6855 multsrc);
6856 fprintf(stdout,
6857 "nuttcp%s%s: using ssm on multicast group %s\n",
6858 trans?"-t":"-r", ident,
6859 multaddr);
6860 }
6861 }
6862 }
6863 #ifdef AF_INET6
6864 else if ((mc_af == AF_INET6) && ssm) { /* IPv6 SSM */
6865 /* multicast receiver joins the mc source group */
6866 struct sockaddr_in6 *group;
6867 struct sockaddr_in6 *source;
6868
6869 group =
6870 (struct sockaddr_in6 *)&group_source_req.gsr_group;
6871 source =
6872 (struct sockaddr_in6 *)&group_source_req.gsr_source;
6873 group_source_req.gsr_interface = 0; /* any interface */
6874 if (mc_addr) {
6875 struct sockaddr_in6 *user_group;
6876
6877 user_group =
6878 (struct sockaddr_in6 *)mcres->ai_addr;
6879 bcopy((char *)user_group, (char *)group,
6880 sizeof(struct sockaddr_in6));
6881 }
6882 else if (client) {
6883 bcopy((char *)&me6, (char *)group,
6884 sizeof(struct sockaddr_in6));
6885 }
6886 else {
6887 bcopy((char *)&peer6, (char *)group,
6888 sizeof(struct sockaddr_in6));
6889 }
6890 bcopy((char *)&peer6, (char *)source,
6891 sizeof(struct sockaddr_in6));
6892 if (!mc_addr) {
6893 bcopy((char *)&hi_mc6,
6894 (char *)&group->sin6_addr,
6895 HI_MC6_LEN);
6896 }
6897 if (setsockopt(fd[1], IPPROTO_IPV6,
6898 MCAST_JOIN_SOURCE_GROUP,
6899 &group_source_req,
6900 sizeof(group_source_req)) < 0)
6901 err("setsockopt: MCAST_JOIN_SOURCE_GROUP");
6902 if (brief <= 0) {
6903 inet_ntop(mc_af, &source->sin6_addr.s6_addr,
6904 multsrc, sizeof(multsrc));
6905 inet_ntop(mc_af, &group->sin6_addr.s6_addr,
6906 multaddr, sizeof(multaddr));
6907 if (format & PARSE) {
6908 fprintf(stdout,
6909 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=1\n",
6910 trans?"-t":"-r", ident,
6911 multsrc, multaddr);
6912 }
6913 else {
6914 fprintf(stdout,
6915 "nuttcp%s%s: receive from multicast source %s\n",
6916 trans?"-t":"-r", ident,
6917 multsrc);
6918 fprintf(stdout,
6919 "nuttcp%s%s: using ssm on multicast group %s\n",
6920 trans?"-t":"-r", ident,
6921 multaddr);
6922 }
6923 }
6924 }
6925 #endif /* AF_INET6 */
6926 #endif /* MCAST_JOIN_SOURCE_GROUP */
6927 else {
6928 err("unsupported AF");
6929 }
6930 }
6931 else { /* trans */
6932 if (mc_af == AF_INET) {
6933 bcopy((char *)&sinhim[1].sin_addr.s_addr,
6934 (char *)&save_sinhim.sin_addr.s_addr,
6935 sizeof(struct in_addr));
6936 }
6937 #ifdef AF_INET6
6938 else if (mc_af == AF_INET6) {
6939 bcopy((char *)&sinhim6[1], (char *)&save_sinhim6,
6940 sizeof(struct sockaddr_in6));
6941 }
6942 #endif
6943 if ((mc_af == AF_INET) && !ssm) { /* IPv4 ASM */
6944 /* The multicast transmitter just sends to mc group */
6945 if (mc_addr) {
6946 struct sockaddr_in *user_group;
6947
6948 user_group =
6949 (struct sockaddr_in *)mcres->ai_addr;
6950 bcopy((char *)&(user_group->sin_addr.s_addr),
6951 (char *)&sinhim[1].sin_addr.s_addr,
6952 sizeof(struct in_addr));
6953 }
6954 else if (client || (irvers < 50505)) {
6955 bcopy((char *)&me.sin_addr.s_addr,
6956 (char *)&sinhim[1].sin_addr.s_addr,
6957 sizeof(struct in_addr));
6958 }
6959 else {
6960 bcopy((char *)&peer.sin_addr.s_addr,
6961 (char *)&sinhim[1].sin_addr.s_addr,
6962 sizeof(struct in_addr));
6963 }
6964 if (!mc_addr) {
6965 sinhim[1].sin_addr.s_addr &= htonl(0xFFFFFF);
6966 sinhim[1].sin_addr.s_addr |= htonl(HI_MC << 24);
6967 }
6968 if (setsockopt(fd[1], IPPROTO_IP, IP_MULTICAST_TTL,
6969 (void *)&multicast,
6970 sizeof(multicast)) < 0)
6971 err("setsockopt: IP_MULTICAST_TTL");
6972 if (brief <= 0) {
6973 inet_ntop(mc_af, &me.sin_addr.s_addr,
6974 multsrc, sizeof(multsrc));
6975 inet_ntop(mc_af, &sinhim[1].sin_addr.s_addr,
6976 multaddr, sizeof(multaddr));
6977 if (format & PARSE) {
6978 fprintf(stdout,
6979 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=0\n",
6980 trans?"-t":"-r", ident,
6981 multsrc, multaddr);
6982 }
6983 else {
6984 fprintf(stdout,
6985 "nuttcp%s%s: sending from multicast source %s\n",
6986 trans?"-t":"-r", ident,
6987 multsrc);
6988 fprintf(stdout,
6989 "nuttcp%s%s: using asm on multicast group %s\n",
6990 trans?"-t":"-r", ident,
6991 multaddr);
6992 }
6993 }
6994 }
6995 #ifdef AF_INET6
6996 else if ((mc_af == AF_INET6) && !ssm) { /* IPv6 ASM */
6997 /* The multicast transmitter just sends to mc group */
6998 if (mc_addr) {
6999 struct sockaddr_in6 *user_group;
7000
7001 user_group =
7002 (struct sockaddr_in6 *)mcres->ai_addr;
7003 bcopy((char *)&(user_group->sin6_addr),
7004 (char *)&sinhim6[1].sin6_addr,
7005 sizeof(struct in6_addr));
7006 }
7007 else if (client) {
7008 bcopy((char *)&me6.sin6_addr,
7009 (char *)&sinhim6[1].sin6_addr,
7010 sizeof(struct in6_addr));
7011 }
7012 else {
7013 bcopy((char *)&peer6.sin6_addr,
7014 (char *)&sinhim6[1].sin6_addr,
7015 sizeof(struct in6_addr));
7016 }
7017 if (!mc_addr) {
7018 bcopy((char *)&hi_mc6_asm,
7019 (char *)&sinhim6[1].sin6_addr,
7020 HI_MC6_ASM_LEN);
7021 }
7022 if (setsockopt(fd[1], IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
7023 (void *)&multicast,
7024 sizeof(multicast)) < 0)
7025 err("setsockopt: IPV6_MULTICAST_HOPS");
7026 if (brief <= 0) {
7027 inet_ntop(mc_af, &me6.sin6_addr.s6_addr,
7028 multsrc, sizeof(multsrc));
7029 inet_ntop(mc_af, &sinhim6[1].sin6_addr.s6_addr,
7030 multaddr, sizeof(multaddr));
7031 if (format & PARSE) {
7032 fprintf(stdout,
7033 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=0\n",
7034 trans?"-t":"-r", ident,
7035 multsrc, multaddr);
7036 }
7037 else {
7038 fprintf(stdout,
7039 "nuttcp%s%s: sending from multicast source %s\n",
7040 trans?"-t":"-r", ident,
7041 multsrc);
7042 fprintf(stdout,
7043 "nuttcp%s%s: using asm on multicast group %s\n",
7044 trans?"-t":"-r", ident,
7045 multaddr);
7046 }
7047 }
7048 }
7049 #endif /* AF_INET6 */
7050 #ifdef MCAST_JOIN_SOURCE_GROUP
7051 else if ((mc_af == AF_INET) && ssm) { /* IPv4 SSM */
7052 /* The multicast transmitter just sends to mc group */
7053 if (mc_addr) {
7054 struct sockaddr_in *user_group;
7055
7056 user_group =
7057 (struct sockaddr_in *)mcres->ai_addr;
7058 bcopy((char *)&(user_group->sin_addr.s_addr),
7059 (char *)&sinhim[1].sin_addr.s_addr,
7060 sizeof(struct in_addr));
7061 }
7062 else if (client) {
7063 bcopy((char *)&me.sin_addr.s_addr,
7064 (char *)&sinhim[1].sin_addr.s_addr,
7065 sizeof(struct in_addr));
7066 }
7067 else {
7068 bcopy((char *)&peer.sin_addr.s_addr,
7069 (char *)&sinhim[1].sin_addr.s_addr,
7070 sizeof(struct in_addr));
7071 }
7072 if (!mc_addr) {
7073 sinhim[1].sin_addr.s_addr &= htonl(0xFFFFFF);
7074 sinhim[1].sin_addr.s_addr |=
7075 htonl(HI_MC_SSM << 24);
7076 }
7077 if (setsockopt(fd[1], IPPROTO_IP, IP_MULTICAST_TTL,
7078 (void *)&multicast,
7079 sizeof(multicast)) < 0)
7080 err("setsockopt: IP_MULTICAST_TTL");
7081 if (brief <= 0) {
7082 inet_ntop(mc_af, &me.sin_addr.s_addr,
7083 multsrc, sizeof(multsrc));
7084 inet_ntop(mc_af, &sinhim[1].sin_addr.s_addr,
7085 multaddr, sizeof(multaddr));
7086 if (format & PARSE) {
7087 fprintf(stdout,
7088 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=1\n",
7089 trans?"-t":"-r", ident,
7090 multsrc, multaddr);
7091 }
7092 else {
7093 fprintf(stdout,
7094 "nuttcp%s%s: sending from multicast source %s\n",
7095 trans?"-t":"-r", ident,
7096 multsrc);
7097 fprintf(stdout,
7098 "nuttcp%s%s: using ssm on multicast group %s\n",
7099 trans?"-t":"-r", ident,
7100 multaddr);
7101 }
7102 }
7103 }
7104 #ifdef AF_INET6
7105 else if ((mc_af == AF_INET6) && ssm) { /* IPv6 SSM */
7106 /* The multicast transmitter just sends to mc group */
7107 if (mc_addr) {
7108 struct sockaddr_in6 *user_group;
7109
7110 user_group =
7111 (struct sockaddr_in6 *)mcres->ai_addr;
7112 bcopy((char *)&(user_group->sin6_addr),
7113 (char *)&sinhim6[1].sin6_addr,
7114 sizeof(struct in6_addr));
7115 }
7116 else if (client) {
7117 bcopy((char *)&me6.sin6_addr,
7118 (char *)&sinhim6[1].sin6_addr,
7119 sizeof(struct in6_addr));
7120 }
7121 else {
7122 bcopy((char *)&peer6.sin6_addr,
7123 (char *)&sinhim6[1].sin6_addr,
7124 sizeof(struct in6_addr));
7125 }
7126 if (!mc_addr) {
7127 bcopy((char *)&hi_mc6,
7128 (char *)&sinhim6[1].sin6_addr,
7129 HI_MC6_LEN);
7130 }
7131 if (setsockopt(fd[1], IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
7132 (void *)&multicast,
7133 sizeof(multicast)) < 0)
7134 err("setsockopt: IPV6_MULTICAST_HOPS");
7135 if (brief <= 0) {
7136 inet_ntop(mc_af, &me6.sin6_addr.s6_addr,
7137 multsrc, sizeof(multsrc));
7138 inet_ntop(mc_af, &sinhim6[1].sin6_addr.s6_addr,
7139 multaddr, sizeof(multaddr));
7140 if (format & PARSE) {
7141 fprintf(stdout,
7142 "nuttcp%s%s: multicast_source=%s multicast_group=%s ssm=1\n",
7143 trans?"-t":"-r", ident,
7144 multsrc, multaddr);
7145 }
7146 else {
7147 fprintf(stdout,
7148 "nuttcp%s%s: sending from multicast source %s\n",
7149 trans?"-t":"-r", ident,
7150 multsrc);
7151 fprintf(stdout,
7152 "nuttcp%s%s: using ssm on multicast group %s\n",
7153 trans?"-t":"-r", ident,
7154 multaddr);
7155 }
7156 }
7157 }
7158 #endif /* AF_INET6 */
7159 #endif /* MCAST_JOIN_SOURCE_GROUP */
7160 else {
7161 err("unsupported AF");
7162 }
7163 }
7164
7165 if (mcres) {
7166 freeaddrinfo(mcres);
7167 mcres = NULL;
7168 }
7169 }
7170
7171 if (trans && timeout) {
7172 itimer.it_value.tv_sec = timeout;
7173 itimer.it_value.tv_usec =
7174 (timeout - itimer.it_value.tv_sec)*1000000;
7175 itimer.it_interval.tv_sec = 0;
7176 itimer.it_interval.tv_usec = 0;
7177 signal(SIGALRM, sigalarm);
7178 if (!udp)
7179 setitimer(ITIMER_REAL, &itimer, 0);
7180 }
7181 else if (!trans && interval) {
7182 sigact.sa_handler = &sigalarm;
7183 sigemptyset(&sigact.sa_mask);
7184 sigact.sa_flags = SA_RESTART;
7185 sigaction(SIGALRM, &sigact, 0);
7186 itimer.it_value.tv_sec = interval;
7187 itimer.it_value.tv_usec =
7188 (interval - itimer.it_value.tv_sec)*1000000;
7189 itimer.it_interval.tv_sec = interval;
7190 itimer.it_interval.tv_usec =
7191 (interval - itimer.it_interval.tv_sec)*1000000;
7192 setitimer(ITIMER_REAL, &itimer, 0);
7193 if (clientserver) {
7194 chk_idle_data = (interval < idle_data_min) ?
7195 idle_data_min : interval;
7196 chk_idle_data = (chk_idle_data > idle_data_max) ?
7197 idle_data_max : chk_idle_data;
7198 }
7199 }
7200 else if (clientserver && !trans) {
7201 sigact.sa_handler = &sigalarm;
7202 sigemptyset(&sigact.sa_mask);
7203 sigact.sa_flags = SA_RESTART;
7204 sigaction(SIGALRM, &sigact, 0);
7205 if (timeout) {
7206 chk_idle_data = timeout/2;
7207 }
7208 else {
7209 if (rate != MAXRATE)
7210 chk_idle_data = (double)(nbuf*buflen)
7211 /rate/125/2;
7212 else
7213 chk_idle_data = default_idle_data;
7214 }
7215 chk_idle_data = (chk_idle_data < idle_data_min) ?
7216 idle_data_min : chk_idle_data;
7217 chk_idle_data = (chk_idle_data > idle_data_max) ?
7218 idle_data_max : chk_idle_data;
7219 itimer.it_value.tv_sec = chk_idle_data;
7220 itimer.it_value.tv_usec =
7221 (chk_idle_data - itimer.it_value.tv_sec)
7222 *1000000;
7223 itimer.it_interval.tv_sec = chk_idle_data;
7224 itimer.it_interval.tv_usec =
7225 (chk_idle_data - itimer.it_interval.tv_sec)
7226 *1000000;
7227 setitimer(ITIMER_REAL, &itimer, 0);
7228 }
7229
7230 if (interval && clientserver && client && trans)
7231 do_poll = 1;
7232
7233 if (irate) {
7234 pkt_time = (double)buflen/rate/125;
7235 irate_pk_usec = pkt_time*1000000;
7236 irate_pk_nsec = (pkt_time*1000000 - irate_pk_usec)*1000;
7237 pkt_time_ms = pkt_time*1000;
7238 }
7239 #ifdef DEBUG
7240 if (irate && (format & DEBUGIRATE)) {
7241 debugout = fopen(DEBUGOUTPUT, "a+");
7242 if (debugout)
7243 fprintf(debugout, "BEGIN nuttcp debug output\n");
7244 }
7245 #endif
7246 prep_timer();
7247 errno = 0;
7248 stream_idx = 0;
7249 ocorrection = 0;
7250 correction = 0.0;
7251 if (do_poll) {
7252 long flags;
7253
7254 pollfds[0].fd = fileno(ctlconn);
7255 pollfds[0].events = POLLIN | POLLPRI;
7256 pollfds[0].revents = 0;
7257 for ( i = 1; i <= nstream; i++ ) {
7258 pollfds[i].fd = fd[i];
7259 pollfds[i].events = POLLOUT;
7260 pollfds[i].revents = 0;
7261 }
7262 flags = fcntl(0, F_GETFL, 0);
7263 if (flags < 0)
7264 err("fcntl 1");
7265 flags |= O_NONBLOCK;
7266 if (fcntl(0, F_SETFL, flags) < 0)
7267 err("fcntl 2");
7268 }
7269 if (sinkmode) {
7270 register int cnt = 0;
7271 if (trans) {
7272 if (udp) {
7273 strcpy(buf, "BOD0");
7274 if (multicast) {
7275 bcopy((char *)&sinhim[1].sin_addr.s_addr,
7276 (char *)&save_mc.sin_addr.s_addr,
7277 sizeof(struct in_addr));
7278 bcopy((char *)&save_sinhim.sin_addr.s_addr,
7279 (char *)&sinhim[1].sin_addr.s_addr,
7280 sizeof(struct in_addr));
7281 }
7282 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr start */
7283 if (two_bod) {
7284 usleep(250000);
7285 strcpy(buf, "BOD1");
7286 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr start */
7287 }
7288 if (multicast) {
7289 bcopy((char *)&save_mc.sin_addr.s_addr,
7290 (char *)&sinhim[1].sin_addr.s_addr,
7291 sizeof(struct in_addr));
7292 }
7293 if (timeout)
7294 setitimer(ITIMER_REAL, &itimer, 0);
7295 prep_timer();
7296 }
7297 bzero(buf + 8, 8); /* zero out timestamp */
7298 nbytes += buflen;
7299 if (do_poll && (format & DEBUGPOLL)) {
7300 fprintf(stdout, "do_poll is set\n");
7301 fflush(stdout);
7302 }
7303 if (udplossinfo)
7304 bcopy(&nbytes, buf + 24, 8);
7305 if (!udp && !(format & NORETRANS) &&
7306 (nstream == 1) &&
7307 ((retransinfo == 1) ||
7308 ((retransinfo >= 2) &&
7309 (force_retrans >= retransinfo)))) {
7310 uint32_t tmp;
7311
7312 if (client) {
7313 if (trans || send_retrans)
7314 do_retrans = 1;
7315 if (trans)
7316 send_retrans = 1;
7317 if (!udp)
7318 bzero(buf + 24, 8);
7319 }
7320 else {
7321 if (retransinfo == 1)
7322 tmp = 0x5254524Eu; /* "RTRN" */
7323 else
7324 tmp = 0x48525452u; /* "HRTR" */
7325 bcopy(&nretrans[1], buf + 24, 4);
7326 bcopy(&tmp, buf + 28, 4);
7327 do_retrans = 0;
7328 }
7329 }
7330 else {
7331 send_retrans = 0;
7332 do_retrans = 0;
7333 if (!udp)
7334 bzero(buf + 24, 8);
7335 }
7336 if (!udp && !(format & NOCWND) &&
7337 (nstream == 1) && cwndinfo) {
7338 if (client) {
7339 if (trans || send_cwnd)
7340 do_cwnd = 1;
7341 if (trans)
7342 send_cwnd = 1;
7343 }
7344 else {
7345 do_cwnd = 0;
7346 }
7347 }
7348 else {
7349 send_cwnd = 0;
7350 do_cwnd = 0;
7351 }
7352 if (nbuf == INT_MAX)
7353 nbuf = ULLONG_MAX;
7354 if (!client) {
7355 /* check if client went away */
7356 pollfds[0].fd = fileno(ctlconn);
7357 save_events = pollfds[0].events;
7358 pollfds[0].events = POLLIN | POLLPRI;
7359 pollfds[0].revents = 0;
7360 if ((poll(pollfds, 1, 0) > 0) &&
7361 (pollfds[0].revents & (POLLIN | POLLPRI))) {
7362 nbuf = 0;
7363 intr = 1;
7364 }
7365 pollfds[0].events = save_events;
7366 }
7367 while (nbuf-- && ((cnt = Nwrite(fd[stream_idx + 1], buf, buflen)) == buflen) && !intr) {
7368 if (clientserver && ((nbuf & 0x3FF) == 0)) {
7369 if (!client) {
7370 /* check if client went away */
7371 pollfds[0].fd = fileno(ctlconn);
7372 save_events = pollfds[0].events;
7373 pollfds[0].events = POLLIN | POLLPRI;
7374 pollfds[0].revents = 0;
7375 if ((poll(pollfds, 1, 0) > 0)
7376 && (pollfds[0].revents &
7377 (POLLIN | POLLPRI)))
7378 intr = 1;
7379 pollfds[0].events = save_events;
7380 }
7381 else if (handle_urg) {
7382 /* check for urgent TCP data
7383 * on control connection */
7384 pollfds[0].fd = fileno(ctlconn);
7385 save_events = pollfds[0].events;
7386 pollfds[0].events = POLLPRI;
7387 pollfds[0].revents = 0;
7388 if ((poll(pollfds, 1, 0) > 0)
7389 && (pollfds[0].revents &
7390 POLLPRI)) {
7391 tmpbuf[0] = '\0';
7392 if ((recv(fd[0], tmpbuf, 1,
7393 MSG_OOB) == -1) &&
7394 (errno == EINVAL))
7395 recv(fd[0], tmpbuf,
7396 1, 0);
7397 if (tmpbuf[0] == 'A')
7398 intr = 1;
7399 else
7400 err("recv urgent data");
7401 }
7402 pollfds[0].events = save_events;
7403 }
7404 }
7405 nbytes += buflen;
7406 cnt = 0;
7407 if (udplossinfo)
7408 bcopy(&nbytes, buf + 24, 8);
7409 if (send_retrans) {
7410 nretrans[1] = get_retrans(
7411 fd[stream_idx + 1],
7412 &tcpinf);
7413 nretrans[1] -= iretrans[1];
7414 bcopy(&nretrans[1], buf + 24, 4);
7415 }
7416 #if defined(linux)
7417 if (send_cwnd) {
7418 cwnd[1] = tcpinf.tcpinfo_snd_cwnd
7419 *datamss/1024;
7420 bcopy(&cwnd[1], buf + 28, 4);
7421 }
7422 #endif
7423 stream_idx++;
7424 stream_idx = stream_idx % nstream;
7425 if (do_poll &&
7426 ((pollst = poll(pollfds, nstream + 1, 0))
7427 > 0) &&
7428 (pollfds[0].revents & (POLLIN | POLLPRI)) && !intr) {
7429 /* check for server output */
7430 #ifdef DEBUG
7431 if (format & DEBUGPOLL) {
7432 fprintf(stdout, "got something %d: ", i);
7433 for ( i = 0; i < nstream + 1; i++ ) {
7434 if (pollfds[i].revents & POLLIN) {
7435 fprintf(stdout, " rfd %d",
7436 pollfds[i].fd);
7437 }
7438 if (pollfds[i].revents & POLLPRI) {
7439 fprintf(stdout, " pfd %d",
7440 pollfds[i].fd);
7441 }
7442 if (pollfds[i].revents & POLLOUT) {
7443 fprintf(stdout, " wfd %d",
7444 pollfds[i].fd);
7445 }
7446 if (pollfds[i].revents & POLLERR) {
7447 fprintf(stdout, " xfd %d",
7448 pollfds[i].fd);
7449 }
7450 if (pollfds[i].revents & POLLHUP) {
7451 fprintf(stdout, " hfd %d",
7452 pollfds[i].fd);
7453 }
7454 if (pollfds[i].revents & POLLNVAL) {
7455 fprintf(stdout, " nfd %d",
7456 pollfds[i].fd);
7457 }
7458 }
7459 fprintf(stdout, "\n");
7460 fflush(stdout);
7461 }
7462 if (format & DEBUGPOLL) {
7463 fprintf(stdout, "got server output: %s", intervalbuf);
7464 fflush(stdout);
7465 }
7466 #endif
7467 while (fgets(intervalbuf, sizeof(intervalbuf), stdin))
7468 {
7469 if (strncmp(intervalbuf, "DONE", 4) == 0) {
7470 if (format & DEBUGPOLL) {
7471 fprintf(stdout, "got DONE\n");
7472 fflush(stdout);
7473 }
7474 got_done = 1;
7475 intr = 1;
7476 do_poll = 0;
7477 break;
7478 }
7479 else if (strncmp(intervalbuf, "nuttcp-r", 8) == 0) {
7480 if ((brief <= 0) ||
7481 strstr(intervalbuf,
7482 "Warning") ||
7483 strstr(intervalbuf,
7484 "Error") ||
7485 strstr(intervalbuf,
7486 "Debug")) {
7487 if (*ident) {
7488 fputs("nuttcp-r", stdout);
7489 fputs(ident, stdout);
7490 fputs(intervalbuf + 8, stdout);
7491 }
7492 else
7493 fputs(intervalbuf, stdout);
7494 fflush(stdout);
7495 }
7496 }
7497 else {
7498 if (*ident)
7499 fprintf(stdout, "%s: ", ident + 1);
7500 cp1 = intervalbuf +
7501 strlen(intervalbuf) - 1;
7502 /* ugly kludge to get rid of
7503 * server "0 retrans" info at
7504 * start of transfer for small
7505 * interval reports -
7506 * hopefully it won't be
7507 * necessary to also check
7508 * at end of transfer when
7509 * processing server output */
7510 if (!got_0retrans) {
7511 if (format & PARSE) {
7512 if ((cp2 = strstr(
7513 intervalbuf,
7514 "host-"
7515 "retrans")))
7516 *(cp2 - 1) = '\0';
7517 else if ((cp2 = strstr(
7518 intervalbuf,
7519 "retrans")))
7520 *(cp2 - 1) = '\0';
7521 else {
7522 *cp1 = '\0';
7523 got_0retrans = 1;
7524 }
7525 }
7526 else if (strstr(intervalbuf,
7527 "KB-cwnd")) {
7528 if (strstr(intervalbuf,
7529 "host-retrans"))
7530 *(cp1 - 34) = '\0';
7531 else if (strstr(
7532 intervalbuf,
7533 "retrans"))
7534 *(cp1 - 29) = '\0';
7535 else {
7536 *cp1 = '\0';
7537 got_0retrans = 1;
7538 }
7539 }
7540 else {
7541 if (strstr(intervalbuf,
7542 "host-retrans"))
7543 *(cp1 - 19) = '\0';
7544 else if (strstr(
7545 intervalbuf,
7546 "retrans"))
7547 *(cp1 - 14) = '\0';
7548 else {
7549 *cp1 = '\0';
7550 got_0retrans = 1;
7551 }
7552 }
7553 }
7554 else {
7555 *cp1 = '\0';
7556 }
7557 if (do_retrans) {
7558 cp1 = strstr(intervalbuf,
7559 "Mbps") + 4;
7560 ch = '\0';
7561 if (cp1) {
7562 if (format & PARSE) {
7563 cp1 = strchr(cp1,
7564 '.');
7565 if (cp1)
7566 cp1 += 5;
7567 }
7568 ch = *cp1;
7569 }
7570 if (ch)
7571 *cp1 = '\0';
7572 }
7573 fputs(intervalbuf, stdout);
7574 if (do_retrans && sinkmode) {
7575 nretrans[1] =
7576 get_retrans(fd[stream_idx
7577 + 1],
7578 &tcpinf);
7579 nretrans[1] -= iretrans[1];
7580 if (format & PARSE)
7581 fprintf(stdout,
7582 P_RETRANS_FMT_INTERVAL,
7583 (retransinfo == 1) ?
7584 "" : "host-",
7585 (nretrans[1] -
7586 pretrans));
7587 else
7588 fprintf(stdout,
7589 RETRANS_FMT_INTERVAL,
7590 (nretrans[1] -
7591 pretrans),
7592 (retransinfo == 1) ?
7593 "" : "host-");
7594 pretrans = nretrans[1];
7595 }
7596 #if defined(linux)
7597 if (do_cwnd && sinkmode) {
7598 cwnd[1] =
7599 tcpinf.tcpinfo_snd_cwnd
7600 *datamss/1024;
7601 if (format & PARSE)
7602 fprintf(stdout,
7603 P_CWND_FMT_INTERVAL,
7604 cwnd[1]);
7605 else
7606 fprintf(stdout,
7607 CWND_FMT_INTERVAL,
7608 cwnd[1]);
7609 }
7610 #endif
7611 if (do_retrans && cp1 && ch) {
7612 *cp1 = ch;
7613 fputs(cp1, stdout);
7614 }
7615 fprintf(stdout, "\n");
7616 fflush(stdout);
7617 }
7618 }
7619 }
7620 if (do_poll && (pollst < 0)) {
7621 if (errno == EINTR)
7622 break;
7623 err("poll");
7624 }
7625 }
7626 nbytes -= buflen;
7627 if (intr && (cnt > 0))
7628 nbytes += cnt;
7629 if (udp) {
7630 if (multicast)
7631 bcopy((char *)&save_sinhim.sin_addr.s_addr,
7632 (char *)&sinhim[1].sin_addr.s_addr,
7633 sizeof(struct in_addr));
7634 strcpy(buf, "EOD0");
7635 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */
7636 }
7637 }
7638 else {
7639 first_read = 1;
7640 first_jitter = 1;
7641 first_jitteri = 1;
7642 nowd = 0;
7643 nowdi = 0;
7644 owd_min = 1000000.0;
7645 owd_mini = 1000000.0;
7646 owd_max = -1000000.0;
7647 owd_maxi = -1000000.0;
7648 owd_avg = 0.0;
7649 owd_avgi = 0.0;
7650 need_swap = 0;
7651 bzero(buf + 24, 8);
7652 if (udp) {
7653 ntbytesc = 0;
7654 got_eod0 = 0;
7655 while (((cnt=Nread(fd[stream_idx + 1], buf, buflen)) > 0) && !intr) {
7656 if (cnt <= 4) {
7657 if (strncmp(buf, "EOD0", 4) == 0) {
7658 get_timeofday(&time_eod0,
7659 (struct timezone *)0);
7660 got_eod0 = 1;
7661 done = 1;
7662 continue;
7663 }
7664 if (strncmp(buf, "EOD", 3) == 0) {
7665 ocorrection = buf[3] - '0';
7666 get_timeofday(&time_eod,
7667 (struct timezone *)0);
7668 done = 1;
7669 break; /* "EOF" */
7670 }
7671 if (strncmp(buf, "BOD", 3) == 0) {
7672 if (two_bod &&
7673 (buf[3] == '0'))
7674 continue;
7675 if (interval)
7676 setitimer(ITIMER_REAL,
7677 &itimer, 0);
7678 prep_timer();
7679 got_begin = 1;
7680 continue;
7681 }
7682 break;
7683 }
7684 else if (!got_begin) {
7685 if (interval)
7686 setitimer(ITIMER_REAL,
7687 &itimer, 0);
7688 prep_timer();
7689 got_begin = 1;
7690 }
7691 else if (got_eod0) {
7692 /* got data after EOD0, so
7693 * extend EOD0 time */
7694 get_timeofday(&time_eod0,
7695 (struct timezone *)0);
7696 }
7697 if (!got_begin)
7698 continue;
7699 nbytes += cnt;
7700 cnt = 0;
7701 /* problematic if the interval timer
7702 * goes off right here */
7703 if (udplossinfo) {
7704 if (first_read) {
7705 bcopy(buf + 24, &ntbytesc,
7706 8);
7707 first_read = 0;
7708 if (ntbytesc > 0x100000000ull)
7709 need_swap = 1;
7710 if (!need_swap) {
7711 stream_idx++;
7712 stream_idx =
7713 stream_idx
7714 % nstream;
7715 continue;
7716 }
7717 }
7718 if (!need_swap)
7719 bcopy(buf + 24, &ntbytesc,
7720 8);
7721 else {
7722 cp1 = (char *)&ntbytesc;
7723 cp2 = buf + 31;
7724 for ( i = 0; i < 8; i++ )
7725 *cp1++ = *cp2--;
7726 }
7727 }
7728 if (do_jitter) {
7729 if (first_jitter) {
7730 get_timeofday(
7731 &timepkr,
7732 (struct timezone *)0);
7733 timepkri = timepkr;
7734 first_jitter = 0;
7735 first_jitteri = 0;
7736 ntbytescp = ntbytesc;
7737 ntbytescpi = ntbytesc;
7738 jitter = 0.0;
7739 jitteri = 0.0;
7740 njitter = 0;
7741 njitteri = 0;
7742 jitter_min = 1000000.0;
7743 jitter_mini = 1000000.0;
7744 jitter_max = -1000000.0;
7745 jitter_maxi = -1000000.0;
7746 jitter_avg = 0.0;
7747 jitter_avgi = 0.0;
7748 #ifdef DEBUG
7749 if (clientserver &&
7750 client &&
7751 (format & DEBUGJITTER))
7752 fprintf(stdout,
7753 "pkt_time_ms"
7754 " = %6.3f ms\n",
7755 pkt_time_ms);
7756 #endif
7757 stream_idx++;
7758 stream_idx =
7759 stream_idx % nstream;
7760 continue;
7761 }
7762 /* formula for jitter is from
7763 * RFC1889 - note synchronized
7764 * clocks are not required since
7765 * source packet delta time is
7766 * known (pkt_time_ms)
7767 *
7768 * D(i,j)=(Rj-Ri)-(Sj-Si)
7769 * =(Rj-Sj)-(Ri-Si)
7770 * J=J+(|D(i-1,i)|-J)/16
7771 *
7772 * for nuttcp we just use the raw
7773 * absolute value of the delta
7774 *
7775 * J=|D(i-1,i)|
7776 */
7777
7778 if (!do_owd) {
7779 get_timeofday(&timerx,
7780 (struct timezone *)0);
7781 }
7782 if (do_jitter & JITTER_IGNORE_OOO) {
7783 /* first check that packet
7784 * is next in sequence */
7785 if (udplossinfo &&
7786 (ntbytescp + buflen)
7787 != ntbytesc) {
7788 ntbytescp = ntbytesc;
7789 ntbytescpi = ntbytesc;
7790 timepkr = timerx;
7791 timepkri = timerx;
7792 stream_idx++;
7793 stream_idx =
7794 stream_idx % nstream;
7795 continue;
7796 }
7797 }
7798
7799 tvsub( &timed, &timerx, &timepkr );
7800 pkt_delta =
7801 timed.tv_sec*1000
7802 + ((double)timed.tv_usec)
7803 / 1000;
7804 pkt_delta -= pkt_time_ms;
7805 if (pkt_delta >= 0)
7806 jitter = pkt_delta;
7807 else
7808 jitter = -pkt_delta;
7809 njitter++;
7810 if (jitter < jitter_min)
7811 jitter_min = jitter;
7812 if (jitter > jitter_max)
7813 jitter_max = jitter;
7814 jitter_avg += jitter;
7815 #ifdef DEBUG
7816 if (clientserver && client &&
7817 (format & DEBUGJITTER))
7818 fprintf(stdout,
7819 "pkt_delta = %6.3f ms, "
7820 "jitter = %9.6f ms\n",
7821 pkt_delta, jitter);
7822 #endif
7823 timepkr = timerx;
7824 ntbytescp = ntbytesc;
7825 if (!interval) {
7826 stream_idx++;
7827 stream_idx =
7828 stream_idx % nstream;
7829 continue;
7830 }
7831 if (first_jitteri) {
7832 get_timeofday(
7833 &timepkri,
7834 (struct timezone *)0);
7835 first_jitteri = 0;
7836 ntbytescpi = ntbytesc;
7837 jitteri = 0.0;
7838 njitteri = 0;
7839 jitter_mini = 1000000.0;
7840 jitter_maxi = -1000000.0;
7841 jitter_avgi = 0.0;
7842 stream_idx++;
7843 stream_idx =
7844 stream_idx % nstream;
7845 continue;
7846 }
7847 tvsub( &timed, &timerx, &timepkri );
7848 pkt_delta =
7849 timed.tv_sec*1000
7850 + ((double)timed.tv_usec)
7851 / 1000;
7852 pkt_delta -= pkt_time_ms;
7853 if (pkt_delta >= 0)
7854 jitteri = pkt_delta;
7855 else
7856 jitteri = -pkt_delta;
7857 njitteri++;
7858 if (jitteri < jitter_mini)
7859 jitter_mini = jitteri;
7860 if (jitteri > jitter_maxi)
7861 jitter_maxi = jitteri;
7862 jitter_avgi += jitteri;
7863 timepkri = timerx;
7864 ntbytescpi = ntbytesc;
7865 }
7866 stream_idx++;
7867 stream_idx = stream_idx % nstream;
7868 }
7869 if (intr && (cnt > 0))
7870 nbytes += cnt;
7871 if (got_eod0) {
7872 tvsub( &timed, &time_eod, &time_eod0 );
7873 correction = timed.tv_sec +
7874 ((double)timed.tv_usec)
7875 / 1000000;
7876 }
7877 }
7878 else {
7879 while (((cnt=Nread(fd[stream_idx + 1], buf, buflen)) > 0) && !intr) {
7880 nbytes += cnt;
7881 cnt = 0;
7882 if (first_read) {
7883 if (interval && !(format & NORETRANS)) {
7884 uint32_t tmp;
7885
7886 first_read = 0;
7887 bcopy(buf + 24, &nretrans[1], 4);
7888 bcopy(buf + 28, &tmp, 4);
7889 if (tmp == 0x5254524Eu) {
7890 /* "RTRN" */
7891 retransinfo = 1;
7892 #if defined(linux)
7893 cwndinfo = 1;
7894 #endif
7895 b_flag = 1;
7896 }
7897 else if (tmp == 0x48525452u) {
7898 /* "HRTR" */
7899 retransinfo = 2;
7900 cwndinfo = 0;
7901 read_cwnd = 0;
7902 b_flag = 1;
7903 }
7904 else if (tmp == 0x4E525452u) {
7905 /* "NRTR" */
7906 need_swap = 1;
7907 retransinfo = 1;
7908 #if defined(linux)
7909 cwndinfo = 1;
7910 #endif
7911 b_flag = 1;
7912 }
7913 else if (tmp == 0x52545248u) {
7914 /* "RTRH" */
7915 need_swap = 1;
7916 retransinfo = 2;
7917 cwndinfo = 0;
7918 read_cwnd = 0;
7919 b_flag = 1;
7920 }
7921 else {
7922 retransinfo = -1;
7923 cwndinfo = 0;
7924 read_retrans = 0;
7925 read_cwnd = 0;
7926 }
7927 if (format & NOCWND) {
7928 cwndinfo = 0;
7929 read_cwnd = 0;
7930 }
7931 }
7932 else {
7933 read_retrans = 0;
7934 read_cwnd = 0;
7935 }
7936 }
7937 if (read_retrans) {
7938 if (!need_swap)
7939 bcopy(buf + 24,
7940 &nretrans[1], 4);
7941 else {
7942 cp1 = (char *)&nretrans[1];
7943 cp2 = buf + 27;
7944 for ( i = 0; i < 4; i++ )
7945 *cp1++ = *cp2--;
7946 }
7947 }
7948 if (read_cwnd) {
7949 if (!need_swap)
7950 bcopy(buf + 28,
7951 &cwnd[1], 4);
7952 else {
7953 cp1 = (char *)&cwnd[1];
7954 cp2 = buf + 31;
7955 for ( i = 0; i < 4; i++ )
7956 *cp1++ = *cp2--;
7957 }
7958 }
7959 stream_idx++;
7960 stream_idx = stream_idx % nstream;
7961 }
7962 if (intr && (cnt > 0))
7963 nbytes += cnt;
7964 }
7965 }
7966 }
7967 else {
7968 register int cnt;
7969 if (trans) {
7970 #if defined(linux)
7971 struct stat instat;
7972
7973 if (fstat(savestdin, &instat) == 0) {
7974 if (!S_ISREG(instat.st_mode) &&
7975 !S_ISBLK(instat.st_mode)) {
7976 zerocopy = 0;
7977 directio = 0;
7978 }
7979 }
7980 else {
7981 zerocopy = 0;
7982 directio = 0;
7983 }
7984
7985 if (directio) {
7986 flags = fcntl(savestdin, F_GETFL, 0);
7987 if (flags < 0)
7988 errmes("fcntl get O_DIRECT");
7989 else {
7990 flags |= O_DIRECT;
7991 if (fcntl(savestdin,
7992 F_SETFL, flags) < 0)
7993 errmes("fcntl set O_DIRECT");
7994 }
7995 }
7996
7997 if (zerocopy) {
7998 while (nbuf-- &&
7999 ((cnt=sendfile(fd[stream_idx + 1],
8000 savestdin,
8001 (off_t *)&nbytes,
8002 buflen)) > 0)) {
8003 cnt = 0;
8004 stream_idx++;
8005 stream_idx = stream_idx % nstream;
8006 }
8007 }
8008 else
8009 #endif
8010 {
8011 while (nbuf-- &&
8012 ((cnt=read(savestdin, buf, buflen)) > 0) &&
8013 (Nwrite(fd[stream_idx + 1], buf, cnt)
8014 == cnt)) {
8015 nbytes += cnt;
8016 cnt = 0;
8017 stream_idx++;
8018 stream_idx = stream_idx % nstream;
8019 }
8020 }
8021 if (udp) {
8022 strcpy(buf, "EOD0");
8023 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */
8024 }
8025 }
8026 else {
8027 #if defined(linux)
8028 struct stat outstat;
8029
8030 if (fstat(savestdout, &outstat) == 0) {
8031 if (!S_ISREG(outstat.st_mode) &&
8032 !S_ISBLK(outstat.st_mode))
8033 directio = 0;
8034 }
8035 else
8036 directio = 0;
8037
8038 if (directio) {
8039 flags = fcntl(savestdout, F_GETFL, 0);
8040 if (flags < 0)
8041 errmes("fcntl get O_DIRECT");
8042 else {
8043 flags |= O_DIRECT;
8044 if (fcntl(savestdout,
8045 F_SETFL, flags) < 0)
8046 errmes("fcntl set O_DIRECT");
8047 }
8048 }
8049 #endif
8050 while ((cnt=Nread(fd[stream_idx + 1], buf, buflen)) > 0 &&
8051 ((cnt != 4) || strncmp(buf, "EOD", 3) != 0) &&
8052 mwrite(savestdout, buf, cnt,
8053 cnt != buflen) == cnt) {
8054 nbytes += cnt;
8055 cnt = 0;
8056 stream_idx++;
8057 stream_idx = stream_idx % nstream;
8058 }
8059 }
8060 }
8061 if (errno && (errno != EAGAIN)) {
8062 if ((errno != EINTR) &&
8063 #ifdef ERESTART
8064 (errno != ERESTART) &&
8065 #endif
8066 (!clientserver || client)) err("IO");
8067 }
8068 itimer.it_value.tv_sec = 0;
8069 itimer.it_value.tv_usec = 0;
8070 itimer.it_interval.tv_sec = 0;
8071 itimer.it_interval.tv_usec = 0;
8072 setitimer(ITIMER_REAL, &itimer, 0);
8073 done = 1;
8074 (void)read_timer(stats, sizeof(stats));
8075 if (udp&&trans) {
8076 usleep(500000);
8077 strcpy(buf, "EOD1");
8078 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */
8079 stream_idx++;
8080 stream_idx = stream_idx % nstream;
8081 usleep(500000);
8082 strcpy(buf, "EOD2");
8083 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */
8084 stream_idx++;
8085 stream_idx = stream_idx % nstream;
8086 usleep(500000);
8087 strcpy(buf, "EOD3");
8088 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */
8089 stream_idx++;
8090 stream_idx = stream_idx % nstream;
8091 usleep(500000);
8092 strcpy(buf, "EOD4");
8093 (void)Nwrite( fd[stream_idx + 1], buf, 4 ); /* rcvr end */
8094 stream_idx++;
8095 stream_idx = stream_idx % nstream;
8096 }
8097
8098 if (!udp && trans && (format & DEBUGRETRANS)) {
8099 sretrans = get_retrans(-1, &tcpinf);
8100 fprintf(stdout, "before closing system retrans = %d\n",
8101 sretrans);
8102 }
8103
8104 #ifdef DEBUG
8105 if (clientserver && client && !trans && do_jitter && njitter &&
8106 (format & DEBUGJITTER)) {
8107 fprintf(stdout, "njitter = %lld\n", njitter);
8108 fprintf(stdout, "jitter_min = %9.6f ms\n", jitter_min);
8109 fprintf(stdout, "jitter_max = %9.6f ms\n", jitter_max);
8110 fprintf(stdout, "jitter_avg = %9.6f ms\n", jitter_avg/njitter);
8111 }
8112 #endif
8113
8114 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) {
8115 if (!udp && trans) {
8116 #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS) && !defined(BROKEN_UNACKED)
8117 /* if -DBROKEN_UNACKED skip check for unACKed data
8118 * (workaround motivated by possible bug encountered
8119 * on a Suse Linux 10.1 system)
8120 */
8121 struct timeval timeunsent, timec, timed;
8122 double xmitrate;
8123 int unsent, xmitunsent;
8124 long flags;
8125
8126 optlen = sizeof(tcpinf);
8127 if (getsockopt(fd[stream_idx], SOL_TCP, TCP_INFO,
8128 (void *)&tcpinf, &optlen) < 0) {
8129 mes("couldn't collect TCP info\n");
8130 retransinfo = -1;
8131 cwndinfo = 0;
8132 }
8133 if (ioctl(fd[stream_idx], SIOCOUTQ, &unsent) < 0) {
8134 mes("couldn't get SIOCOUTQ value\n");
8135 unsent = -1;
8136 }
8137 get_timeofday(&timeunsent, (struct timezone *)0);
8138 realtd = 0.0;
8139 xmitrate = ((double)nbytes-(double)unsent)/realt;
8140 xmitunsent = (double)unsent/xmitrate;
8141 xmitunsent = 2*xmitunsent + MAX_EOT_WAIT_SEC;
8142 if (clientserver && client) {
8143 reading_srvr_info = 1;
8144 pollfds[0].fd = fileno(ctlconn);
8145 pollfds[0].events = POLLIN | POLLPRI;
8146 pollfds[0].revents = 0;
8147 flags = fcntl(0, F_GETFL, 0);
8148 if (flags < 0)
8149 err("fcntl 1");
8150 flags |= O_NONBLOCK;
8151 if (fcntl(0, F_SETFL, flags) < 0)
8152 err("fcntl 2");
8153 itimer.it_value.tv_sec = xmitunsent + 10;
8154 itimer.it_value.tv_usec = 0;
8155 itimer.it_interval.tv_sec = 0;
8156 itimer.it_interval.tv_usec = 0;
8157 setitimer(ITIMER_REAL, &itimer, 0);
8158 }
8159 while ((unsent > 0) && (realtd < xmitunsent)) {
8160 if (clientserver && client &&
8161 ((pollst = poll(pollfds, 1, 0)) > 0) &&
8162 (pollfds[0].revents & (POLLIN | POLLPRI)) &&
8163 !got_done) {
8164 /* check for server output */
8165 while (fgets(intervalbuf,
8166 sizeof(intervalbuf), stdin))
8167 {
8168 setitimer(ITIMER_REAL, &itimer, 0);
8169 get_timeofday(&timeunsent,
8170 (struct timezone *)0);
8171 if (strncmp(intervalbuf, "DONE", 4)
8172 == 0) {
8173 if (format & DEBUGPOLL) {
8174 fprintf(stdout,
8175 "got DONE\n");
8176 fflush(stdout);
8177 }
8178 got_done = 1;
8179 intr = 1;
8180 break;
8181 }
8182 else if (strncmp(intervalbuf,
8183 "nuttcp-", 7) == 0) {
8184 if ((brief <= 0) ||
8185 strstr(intervalbuf,
8186 "Warning") ||
8187 strstr(intervalbuf,
8188 "Error") ||
8189 strstr(intervalbuf,
8190 "Debug")) {
8191 if (*ident) {
8192 fputs("nuttcp",
8193 stdout);
8194 fputs(trans ?
8195 "-r" : "-t",
8196 stdout);
8197 fputs(ident,
8198 stdout);
8199 fputs(intervalbuf
8200 + 8,
8201 stdout);
8202 }
8203 else
8204 fputs(intervalbuf,
8205 stdout);
8206 fflush(stdout);
8207 }
8208 if (strstr(intervalbuf,
8209 "Error"))
8210 exit(1);
8211 }
8212 else {
8213 if (*ident)
8214 fprintf(stdout, "%s: ",
8215 ident + 1);
8216 intervalbuf[strlen(intervalbuf)
8217 - 1] = '\0';
8218 if (do_retrans) {
8219 cp1 = strstr(intervalbuf,
8220 "Mbps") + 4;
8221 ch = '\0';
8222 if (cp1) {
8223 if (format & PARSE) {
8224 cp1 = strchr(cp1,
8225 '.');
8226 if (cp1)
8227 cp1 += 5;
8228 }
8229 ch = *cp1;
8230 }
8231 if (ch)
8232 *cp1 = '\0';
8233 }
8234 fputs(intervalbuf, stdout);
8235 if (do_retrans && sinkmode &&
8236 (nstream == 1)) {
8237 nretrans[1] =
8238 get_retrans(
8239 fd[stream_idx],
8240 &tcpinf);
8241 nretrans[1] -= iretrans[1];
8242 if (format & PARSE)
8243 fprintf(stdout,
8244 P_RETRANS_FMT_INTERVAL,
8245 (retransinfo == 1) ?
8246 "" : "host-",
8247 (nretrans[1]
8248 - pretrans));
8249 else
8250 fprintf(stdout,
8251 RETRANS_FMT_INTERVAL,
8252 (nretrans[1]
8253 - pretrans),
8254 (retransinfo == 1) ?
8255 "" : "host-");
8256 pretrans =
8257 nretrans[1];
8258 }
8259 if (do_cwnd && sinkmode &&
8260 (nstream == 1)) {
8261 cwnd[1] =
8262 tcpinf.tcpinfo_snd_cwnd
8263 *datamss/1024;
8264 if (format & PARSE)
8265 fprintf(stdout,
8266 P_CWND_FMT_INTERVAL,
8267 cwnd[1]);
8268 else
8269 fprintf(stdout,
8270 CWND_FMT_INTERVAL,
8271 cwnd[1]);
8272 }
8273 if (do_retrans && cp1 && ch) {
8274 *cp1 = ch;
8275 fputs(cp1, stdout);
8276 }
8277 fprintf(stdout, "\n");
8278 fflush(stdout);
8279 }
8280 }
8281 }
8282 if (format & DEBUGRETRANS)
8283 print_tcpinfo();
8284 if (format & DEBUGRETRANS)
8285 usleep(100000);
8286 else
8287 usleep(1000);
8288 optlen = sizeof(tcpinf);
8289 if (getsockopt(fd[stream_idx],
8290 SOL_TCP, TCP_INFO,
8291 (void *)&tcpinf, &optlen) < 0) {
8292 mes("couldn't collect TCP info\n");
8293 retransinfo = -1;
8294 cwndinfo = 0;
8295 }
8296 if (ioctl(fd[stream_idx], SIOCOUTQ,
8297 &unsent) < 0) {
8298 mes("couldn't get SIOCOUTQ value\n");
8299 unsent = -1;
8300 }
8301 get_timeofday(&timec, (struct timezone *)0);
8302 tvsub(&timed, &timec, &timeunsent);
8303 realtd = timed.tv_sec
8304 + ((double)timed.tv_usec) / 1000000;
8305 }
8306 if (clientserver && client) {
8307 reading_srvr_info = 0;
8308 flags = fcntl(0, F_GETFL, 0);
8309 if (flags < 0)
8310 err("fcntl 1");
8311 flags &= ~O_NONBLOCK;
8312 if (fcntl(0, F_SETFL, flags) < 0)
8313 err("fcntl 2");
8314 itimer.it_value.tv_sec = 0;
8315 itimer.it_value.tv_usec = 0;
8316 setitimer(ITIMER_REAL, &itimer, 0);
8317 }
8318
8319 if (getsockopt(fd[stream_idx], SOL_TCP, TCP_INFO,
8320 (void *)&tcpinf, &optlen) < 0) {
8321 mes("couldn't collect TCP info\n");
8322 retransinfo = -1;
8323 cwndinfo = 0;
8324 }
8325 if (unsent > 0) {
8326 /* assume receiver went away */
8327 if (clientserver && client) {
8328 mes("Error: timeout while draining "
8329 "socket send queue");
8330 exit(1);
8331 }
8332 goto cleanup;
8333 }
8334
8335 if (format & DEBUGRETRANS)
8336 print_tcpinfo();
8337 #endif
8338 if (retransinfo > 0) {
8339 if ((stream_idx == 1) || (retransinfo == 1)) {
8340 nretrans[stream_idx] =
8341 get_retrans(fd[stream_idx],
8342 &tcpinf);
8343 nretrans[stream_idx] -=
8344 iretrans[stream_idx];
8345 #if defined(linux)
8346 if (retransinfo == 1)
8347 cwnd[stream_idx] =
8348 tcpinf.tcpinfo_snd_cwnd
8349 *datamss/1024;
8350 #endif
8351 }
8352 }
8353 }
8354 }
8355 if (!udp && trans && (format & DEBUGRETRANS)) {
8356 sretrans = get_retrans(-1, &tcpinf);
8357 fprintf(stdout, "after closing system retrans = %d\n",
8358 sretrans);
8359 }
8360
8361 if (interval && clientserver && client && do_retrans && !got_done) {
8362 /* don't fully close data channels yet since there
8363 * may be some straggler interval reports to which we
8364 * will need to append retrans info, so just shutdown()
8365 * for writing for now */
8366 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ )
8367 shutdown(fd[stream_idx], SHUT_WR);
8368 }
8369 else
8370 close_data_channels();
8371
8372 if (interval && clientserver && !client && !trans) {
8373 fprintf(stdout, "DONE\n");
8374 fflush(stdout);
8375 }
8376
8377 if (cput <= 0.0) cput = 0.000001;
8378 if (realt <= 0.0) realt = 0.000001;
8379
8380 if (udp && !trans) {
8381 if (got_eod0)
8382 realt -= correction;
8383 else
8384 realt -= ocorrection * 0.5;
8385 }
8386
8387 sprintf(srvrbuf, "%.4f", (double)nbytes/1024/1024);
8388 sscanf(srvrbuf, "%lf", &MB);
8389
8390 if (clientserver && client)
8391 reading_srvr_info = 1;
8392
8393 if (interval && clientserver && client && trans && !got_done) {
8394 long flags;
8395
8396 if (format & DEBUGPOLL) {
8397 fprintf(stdout, "getting rest of server output\n");
8398 fflush(stdout);
8399 }
8400 flags = fcntl(0, F_GETFL, 0);
8401 if (flags < 0)
8402 err("fcntl 3");
8403 flags &= ~O_NONBLOCK;
8404 if (fcntl(0, F_SETFL, flags) < 0)
8405 err("fcntl 4");
8406 itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT;
8407 itimer.it_value.tv_usec = 0;
8408 itimer.it_interval.tv_sec = 0;
8409 itimer.it_interval.tv_usec = 0;
8410 setitimer(ITIMER_REAL, &itimer, 0);
8411 while (fgets(intervalbuf, sizeof(intervalbuf), stdin)) {
8412 setitimer(ITIMER_REAL, &itimer, 0);
8413 if (strncmp(intervalbuf, "DONE", 4) == 0) {
8414 if (format & DEBUGPOLL) {
8415 fprintf(stdout, "got DONE 2\n");
8416 fflush(stdout);
8417 }
8418 break;
8419 }
8420 if ((!strstr(intervalbuf, " MB / ") ||
8421 !strstr(intervalbuf, " sec = ")) && (brief > 0))
8422 continue;
8423 if (*ident)
8424 fprintf(stdout, "%s: ", ident + 1);
8425 intervalbuf[strlen(intervalbuf) - 1] = '\0';
8426 if (do_retrans) {
8427 cp1 = strstr(intervalbuf, "Mbps") + 4;
8428 ch = '\0';
8429 if (cp1) {
8430 if (format & PARSE) {
8431 cp1 = strchr(cp1, '.');
8432 if (cp1)
8433 cp1 += 5;
8434 }
8435 ch = *cp1;
8436 }
8437 if (ch)
8438 *cp1 = '\0';
8439 }
8440 fputs(intervalbuf, stdout);
8441 if (do_retrans && sinkmode) {
8442 nretrans[1] = get_retrans(fd[1], &tcpinf);
8443 nretrans[1] -= iretrans[1];
8444 if (format & PARSE)
8445 fprintf(stdout, P_RETRANS_FMT_INTERVAL,
8446 (retransinfo == 1) ?
8447 "" : "host-",
8448 (nretrans[1] - pretrans));
8449 else
8450 fprintf(stdout, RETRANS_FMT_INTERVAL,
8451 (nretrans[1] - pretrans),
8452 (retransinfo == 1) ?
8453 "" : "host-");
8454 pretrans = nretrans[1];
8455 }
8456 #if defined(linux)
8457 if (do_cwnd && sinkmode) {
8458 cwnd[1] = tcpinf.tcpinfo_snd_cwnd
8459 *datamss/1024;
8460 if (format & PARSE)
8461 fprintf(stdout, P_CWND_FMT_INTERVAL,
8462 cwnd[1]);
8463 else
8464 fprintf(stdout, CWND_FMT_INTERVAL,
8465 cwnd[1]);
8466 }
8467 #endif
8468 if (do_retrans && cp1 && ch) {
8469 *cp1 = ch;
8470 fputs(cp1, stdout);
8471 }
8472 fprintf(stdout, "\n");
8473 fflush(stdout);
8474 }
8475 itimer.it_value.tv_sec = 0;
8476 itimer.it_value.tv_usec = 0;
8477 setitimer(ITIMER_REAL, &itimer, 0);
8478 }
8479
8480 if (interval && clientserver && client && do_retrans) {
8481 /* it's OK to fully close the data channels now */
8482 close_data_channels();
8483 }
8484
8485 if (clientserver && client) {
8486 itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT;
8487 itimer.it_value.tv_usec = 0;
8488 setitimer(ITIMER_REAL, &itimer, 0);
8489 cp1 = srvrbuf;
8490 got_srvr_retrans = 0;
8491 got_srvr_cwnd = 0;
8492 while (fgets(cp1, sizeof(srvrbuf) - (cp1 - srvrbuf), stdin)) {
8493 setitimer(ITIMER_REAL, &itimer, 0);
8494 if (*(cp1 + strlen(cp1) - 1) != '\n') {
8495 *cp1 = '\0';
8496 break;
8497 }
8498 if (strstr(cp1, "real") && strstr(cp1, "seconds")) {
8499 strcpy(fmt, "nuttcp-%*c: ");
8500 if (format & PARSE)
8501 strcat(fmt, P_PERF_FMT_IN);
8502 else
8503 strcat(fmt, PERF_FMT_IN);
8504 sscanf(cp1, fmt,
8505 &srvr_MB, &srvr_realt, &srvr_KBps,
8506 &srvr_Mbps);
8507 if (trans && udp) {
8508 strncpy(tmpbuf, cp1, 256);
8509 *(tmpbuf + 256) = '\0';
8510 if (strncmp(tmpbuf,
8511 "nuttcp-r", 8) == 0)
8512 sprintf(cp1, "nuttcp-r%s%s",
8513 ident, tmpbuf + 8);
8514 cp1 += strlen(cp1);
8515 cp2 = cp1;
8516 sprintf(cp2, "nuttcp-r:");
8517 cp2 += 9;
8518 if (format & PARSE)
8519 strcpy(fmt, P_DROP_FMT);
8520 else
8521 strcpy(fmt, DROP_FMT);
8522 sprintf(cp2, fmt,
8523 (int64_t)(((MB - srvr_MB)
8524 *1024*1024)
8525 /buflen + 0.5),
8526 (uint64_t)((MB*1024*1024)
8527 /buflen + 0.5));
8528 cp2 += strlen(cp2);
8529 fractloss = ((MB != 0.0) ?
8530 1 - srvr_MB/MB : 0.0);
8531 if (format & PARSE)
8532 strcpy(fmt, P_LOSS_FMT);
8533 else if ((fractloss != 0.0) &&
8534 (fractloss < 0.001))
8535 strcpy(fmt, LOSS_FMT5);
8536 else
8537 strcpy(fmt, LOSS_FMT);
8538 sprintf(cp2, fmt, fractloss * 100);
8539 cp2 += strlen(cp2);
8540 sprintf(cp2, "\n");
8541 }
8542 }
8543 else if (strstr(cp1, "sys")) {
8544 strcpy(fmt, "nuttcp-%*c: ");
8545 if (format & PARSE) {
8546 strcat(fmt, "stats=cpu ");
8547 strcat(fmt, P_CPU_STATS_FMT_IN2);
8548 }
8549 else
8550 strcat(fmt, CPU_STATS_FMT_IN2);
8551 if (sscanf(cp1, fmt,
8552 &srvr_cpu_util) != 7) {
8553 strcpy(fmt, "nuttcp-%*c: ");
8554 if (format & PARSE) {
8555 strcat(fmt, "stats=cpu ");
8556 strcat(fmt,
8557 P_CPU_STATS_FMT_IN);
8558 }
8559 else
8560 strcat(fmt, CPU_STATS_FMT_IN);
8561 sscanf(cp1, fmt,
8562 &srvr_cpu_util);
8563 }
8564 }
8565 else if ((cp2 = strstr(cp1, "retrans"))) {
8566 got_srvr_retrans = 1;
8567 retransinfo = 1;
8568 if (strstr(cp1, "host-retrans"))
8569 retransinfo = 2;
8570 if (format & PARSE)
8571 sscanf(cp2, P_RETRANS_FMT_IN,
8572 &total_retrans);
8573 else
8574 sscanf(cp2, RETRANS_FMT_IN,
8575 &total_retrans);
8576 if (format & PARSE) {
8577 if ((cp2 = strstr(cp2,
8578 "retrans_by_stream=")))
8579 cp2 += 18;
8580 else
8581 cp2 = NULL;
8582 }
8583 else {
8584 if ((cp2 = strstr(cp2, "( ")))
8585 cp2 += 2;
8586 else
8587 cp2 = NULL;
8588 }
8589 if (cp2) {
8590 sscanf(cp2, "%d", &nretrans[1]);
8591 stream_idx = 2;
8592 while ((stream_idx <= nstream) &&
8593 (cp2 = strchr(cp2, '+'))) {
8594 cp2++;
8595 sscanf(cp2, "%d",
8596 &nretrans[stream_idx]);
8597 stream_idx++;
8598 }
8599 }
8600 /* below is for compatibility with 6.0.x beta */
8601 if ((cp2 = strstr(cp1, "RTT"))) {
8602 if (format & PARSE)
8603 sscanf(cp2, P_RTT_FMT_IN, &rtt);
8604 else
8605 sscanf(cp2, RTT_FMT_INB, &rtt);
8606 }
8607 if ((cp2 = strstr(cp1, "cwnd"))) {
8608 got_srvr_cwnd = 1;
8609 cwndinfo = 1;
8610 if (format & PARSE)
8611 sscanf(cp2, P_CWND_FMT_IN,
8612 &total_snd_cwnd);
8613 else
8614 sscanf(cp2, CWND_FMT_IN,
8615 &total_snd_cwnd);
8616 if (format & PARSE) {
8617 if ((cp2 = strstr(cp2,
8618 "cwnd_by_stream=")))
8619 cp2 += 15;
8620 else
8621 cp2 = NULL;
8622 }
8623 else {
8624 if ((cp2 = strstr(cp2, "( ")))
8625 cp2 += 2;
8626 else
8627 cp2 = NULL;
8628 }
8629 if (cp2) {
8630 sscanf(cp2, "%d", &cwnd[1]);
8631 stream_idx = 2;
8632 while ((stream_idx <=
8633 nstream) &&
8634 (cp2 = strchr(cp2,
8635 '+'))) {
8636 cp2++;
8637 sscanf(cp2, "%d",
8638 &cwnd[stream_idx]);
8639 stream_idx++;
8640 }
8641 }
8642 }
8643 }
8644 else if ((cp2 = strstr(cp1, "RTT")) ||
8645 (cp2 = strstr(cp1, "rtt"))) {
8646 if (format & PARSE)
8647 sscanf(cp2, P_RTT_FMT_IN, &rtt);
8648 else
8649 sscanf(cp2, RTT_FMT_IN, &rtt);
8650 }
8651 else if ((cp2 = strstr(cp1, "jitter"))) {
8652 if (format & PARSE)
8653 sscanf(cp2, P_JITTER_FMT_IN,
8654 &jitter_min, &jitter_avg,
8655 &jitter_max);
8656 else
8657 sscanf(cp2, JITTER_FMT_IN,
8658 &jitter_min, &jitter_avg,
8659 &jitter_max);
8660 njitter = 1;
8661 }
8662 else if ((cp2 = strstr(cp1, "OWD"))) {
8663 if (format & PARSE)
8664 sscanf(cp2, P_OWD_FMT_IN,
8665 &owd_min, &owd_avg, &owd_max);
8666 else
8667 sscanf(cp2, OWD_FMT_IN,
8668 &owd_min, &owd_avg, &owd_max);
8669 nowd = 1;
8670 }
8671 else if ((strstr(cp1, "KB/cpu")) && !verbose)
8672 continue;
8673 strncpy(tmpbuf, cp1, 256);
8674 *(tmpbuf + 256) = '\0';
8675 if (strncmp(tmpbuf, "nuttcp-", 7) == 0)
8676 sprintf(cp1, "nuttcp-%c%s%s",
8677 tmpbuf[7], ident, tmpbuf + 8);
8678 if ((strstr(cp1, "Warning") ||
8679 strstr(cp1, "Error") ||
8680 strstr(cp1, "Debug"))
8681 && (brief > 0)) {
8682 fputs(cp1, stdout);
8683 fflush(stdout);
8684 }
8685 cp1 += strlen(cp1);
8686 }
8687 itimer.it_value.tv_sec = 0;
8688 itimer.it_value.tv_usec = 0;
8689 setitimer(ITIMER_REAL, &itimer, 0);
8690 got_srvr_output = 1;
8691 if (!udp && !trans) {
8692 if (!got_srvr_retrans)
8693 retransinfo = -1;
8694 if (!got_srvr_cwnd)
8695 cwndinfo = 0;
8696 }
8697 }
8698
8699 if (!udp && trans) {
8700 if (retransinfo > 0) {
8701 total_retrans = 0;
8702 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) {
8703 total_retrans += nretrans[stream_idx];
8704 }
8705 }
8706 if (cwndinfo) {
8707 total_snd_cwnd = 0;
8708 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) {
8709 total_snd_cwnd += cwnd[stream_idx];
8710 }
8711 }
8712 }
8713
8714 if (brief <= 0) {
8715 strcpy(fmt, "nuttcp%s%s: ");
8716 if (format & PARSE)
8717 strcat(fmt, P_PERF_FMT_OUT);
8718 else
8719 strcat(fmt, PERF_FMT_OUT);
8720 fprintf(stdout, fmt, trans?"-t":"-r", ident,
8721 (double)nbytes/(1024*1024), realt,
8722 (double)nbytes/realt/1024,
8723 (double)nbytes/realt/125000);
8724 if (clientserver && client && !trans && udp) {
8725 fprintf(stdout, "nuttcp-r%s:", ident);
8726 if (format & PARSE)
8727 strcpy(fmt, P_DROP_FMT);
8728 else
8729 strcpy(fmt, DROP_FMT);
8730 fprintf(stdout, fmt,
8731 (int64_t)(((srvr_MB - MB)*1024*1024)
8732 /buflen + 0.5),
8733 (uint64_t)((srvr_MB*1024*1024)/buflen + 0.5));
8734 fractloss = ((srvr_MB != 0.0) ? 1 - MB/srvr_MB : 0.0);
8735 if (format & PARSE)
8736 strcpy(fmt, P_LOSS_FMT);
8737 else if ((fractloss != 0.0) && (fractloss < 0.001))
8738 strcpy(fmt, LOSS_FMT5);
8739 else
8740 strcpy(fmt, LOSS_FMT);
8741 fprintf(stdout, fmt, fractloss * 100);
8742 fprintf(stdout, "\n");
8743 }
8744 if (clientserver && udp && !trans && do_jitter && njitter) {
8745 strcpy(fmt, "nuttcp%s%s: ");
8746 if (format & PARSE)
8747 strcat(fmt, P_JITTER_FMT);
8748 else
8749 strcat(fmt, JITTER_FMT);
8750 fprintf(stdout, fmt, trans?"-t":"-r", ident,
8751 jitter_min, jitter_avg/njitter, jitter_max);
8752 fprintf(stdout, "\n");
8753 }
8754 if (clientserver && !trans && do_owd && nowd) {
8755 strcpy(fmt, "nuttcp%s%s: ");
8756 if (format & PARSE)
8757 strcat(fmt, P_OWD_FMT);
8758 else
8759 strcat(fmt, OWD_FMT);
8760 fprintf(stdout, fmt, trans?"-t":"-r", ident,
8761 owd_min, owd_avg/nowd, owd_max);
8762 fprintf(stdout, "\n");
8763 }
8764 if (verbose) {
8765 strcpy(fmt, "nuttcp%s%s: ");
8766 if (format & PARSE)
8767 strcat(fmt, "megabytes=%.4f cpu_seconds=%.2f KB_per_cpu_second=%.2f\n");
8768 else
8769 strcat(fmt, "%.4f MB in %.2f CPU seconds = %.2f KB/cpu sec\n");
8770 fprintf(stdout, fmt,
8771 trans?"-t":"-r", ident,
8772 (double)nbytes/(1024*1024), cput,
8773 (double)nbytes/cput/1024);
8774 }
8775 if (!udp && trans && (retransinfo > 0)) {
8776 fprintf(stdout, "nuttcp%s%s: ",
8777 trans ? "-t" : "-r", ident);
8778 if (format & PARSE)
8779 strcpy(fmt, P_RETRANS_FMT);
8780 else
8781 strcpy(fmt, RETRANS_FMT);
8782 fprintf(stdout, fmt,
8783 retransinfo == 1 ? "" : "host-", total_retrans);
8784 if ((nstream > 1) && (retransinfo == 1) &&
8785 total_retrans) {
8786 if (format & PARSE)
8787 fprintf(stdout, P_RETRANS_FMT_STREAMS,
8788 nretrans[1]);
8789 else
8790 fprintf(stdout, " ( %d", nretrans[1]);
8791 for ( stream_idx = 2; stream_idx <= nstream;
8792 stream_idx++ ) {
8793 fprintf(stdout, "+%d",
8794 nretrans[stream_idx]);
8795 }
8796 if (!(format & PARSE))
8797 fprintf(stdout, " )");
8798 }
8799 #if defined(linux)
8800 if (cwndinfo) {
8801 if (format & PARSE)
8802 strcpy(fmt, P_CWND_FMT);
8803 else
8804 strcpy(fmt, CWND_FMT);
8805 fprintf(stdout, fmt, total_snd_cwnd);
8806 if ((nstream > 1) && (retransinfo == 1) &&
8807 total_snd_cwnd) {
8808 if (format & PARSE)
8809 fprintf(stdout, P_CWND_FMT_STREAMS,
8810 cwnd[1]);
8811 else
8812 fprintf(stdout, " ( %d", cwnd[1]);
8813 for ( stream_idx = 2; stream_idx <= nstream;
8814 stream_idx++ ) {
8815 fprintf(stdout, "+%d",
8816 cwnd[stream_idx]);
8817 }
8818 if (!(format & PARSE))
8819 fprintf(stdout, " )");
8820 }
8821 }
8822 #endif
8823 fprintf(stdout, "\n");
8824 }
8825
8826 strcpy(fmt, "nuttcp%s%s: ");
8827 if (format & PARSE)
8828 strcat(fmt, "io_calls=%d msec_per_call=%.2f calls_per_sec=%.2f\n");
8829 else
8830 strcat(fmt, "%d I/O calls, msec/call = %.2f, calls/sec = %.2f\n");
8831 fprintf(stdout, fmt,
8832 trans?"-t":"-r", ident,
8833 numCalls,
8834 1024.0 * realt/((double)numCalls),
8835 ((double)numCalls)/realt);
8836
8837 strcpy(fmt, "nuttcp%s%s: ");
8838 if (format & PARSE)
8839 strcat(fmt, "stats=cpu %s\n");
8840 else
8841 strcat(fmt, "%s\n");
8842 fprintf(stdout, fmt, trans?"-t":"-r", ident, stats);
8843 }
8844
8845 if (format & PARSE)
8846 strcpy(fmt, P_CPU_STATS_FMT_IN2);
8847 else
8848 strcpy(fmt, CPU_STATS_FMT_IN2);
8849 if (sscanf(stats, fmt, &cpu_util) != 6) {
8850 if (format & PARSE)
8851 strcpy(fmt, P_CPU_STATS_FMT_IN);
8852 else
8853 strcpy(fmt, CPU_STATS_FMT_IN);
8854 sscanf(stats, fmt, &cpu_util);
8855 }
8856
8857 if (brief && clientserver && client) {
8858 if ((brief < 0) || interval)
8859 fprintf(stdout, "\n");
8860 if (udp) {
8861 if (trans) {
8862 if (*ident)
8863 fprintf(stdout, "%s: ", ident + 1);
8864 if (format & PARSE)
8865 strcpy(fmt, P_PERF_FMT_BRIEF);
8866 else
8867 strcpy(fmt, PERF_FMT_BRIEF);
8868 fprintf(stdout, fmt,
8869 srvr_MB, srvr_realt, srvr_Mbps,
8870 cpu_util, srvr_cpu_util);
8871 if (!(format & NODROPS)) {
8872 if (format & PARSE)
8873 strcpy(fmt, P_DROP_FMT_BRIEF);
8874 else
8875 strcpy(fmt, DROP_FMT_BRIEF);
8876 fprintf(stdout, fmt,
8877 (int64_t)(((MB - srvr_MB)
8878 *1024*1024)
8879 /buflen + 0.5),
8880 (uint64_t)((MB*1024*1024)
8881 /buflen + 0.5));
8882 }
8883 if (!(format & NOPERCENTLOSS)) {
8884 fractloss = ((MB != 0.0) ?
8885 1 - srvr_MB/MB : 0.0);
8886 if (format & PARSE)
8887 strcpy(fmt, P_LOSS_FMT_BRIEF);
8888 else if ((fractloss != 0.0) &&
8889 (fractloss < 0.001))
8890 strcpy(fmt, LOSS_FMT_BRIEF5);
8891 else
8892 strcpy(fmt, LOSS_FMT_BRIEF);
8893 fprintf(stdout, fmt, fractloss * 100);
8894 }
8895 if (format & XMITSTATS) {
8896 if (format & PARSE)
8897 strcpy(fmt, P_PERF_FMT_BRIEF3);
8898 else
8899 strcpy(fmt, PERF_FMT_BRIEF3);
8900 fprintf(stdout, fmt, MB);
8901 }
8902 if ((do_jitter & JITTER_MIN) && njitter) {
8903 if (format & PARSE)
8904 strcpy(fmt,
8905 P_JITTER_MIN_FMT_BRIEF);
8906 else
8907 strcpy(fmt,
8908 JITTER_MIN_FMT_BRIEF);
8909 fprintf(stdout, fmt, jitter_min);
8910 }
8911 if ((do_jitter & JITTER_AVG) && njitter) {
8912 if (format & PARSE)
8913 strcpy(fmt,
8914 P_JITTER_AVG_FMT_BRIEF);
8915 else
8916 strcpy(fmt,
8917 JITTER_AVG_FMT_BRIEF);
8918 fprintf(stdout, fmt,
8919 jitter_avg/njitter);
8920 }
8921 if ((do_jitter & JITTER_MAX) && njitter) {
8922 if (format & PARSE)
8923 strcpy(fmt,
8924 P_JITTER_MAX_FMT_BRIEF);
8925 else
8926 strcpy(fmt,
8927 JITTER_MAX_FMT_BRIEF);
8928 fprintf(stdout, fmt, jitter_max);
8929 }
8930 if ((do_owd & OWD_MIN) && nowd) {
8931 if (format & PARSE)
8932 strcpy(fmt,
8933 P_OWD_MIN_FMT_BRIEF);
8934 else
8935 strcpy(fmt, OWD_MIN_FMT_BRIEF);
8936 fprintf(stdout, fmt, owd_min);
8937 }
8938 if ((do_owd & OWD_AVG) && nowd) {
8939 if (format & PARSE)
8940 strcpy(fmt,
8941 P_OWD_AVG_FMT_BRIEF);
8942 else
8943 strcpy(fmt, OWD_AVG_FMT_BRIEF);
8944 fprintf(stdout, fmt, owd_avg/nowd);
8945 }
8946 if ((do_owd & OWD_MAX) && nowd) {
8947 if (format & PARSE)
8948 strcpy(fmt,
8949 P_OWD_MAX_FMT_BRIEF);
8950 else
8951 strcpy(fmt, OWD_MAX_FMT_BRIEF);
8952 fprintf(stdout, fmt, owd_max);
8953 }
8954 }
8955 else {
8956 if (*ident)
8957 fprintf(stdout, "%s: ", ident + 1);
8958 if (format & PARSE)
8959 strcpy(fmt, P_PERF_FMT_BRIEF);
8960 else
8961 strcpy(fmt, PERF_FMT_BRIEF);
8962 fprintf(stdout, fmt,
8963 MB, realt, (double)nbytes/realt/125000,
8964 srvr_cpu_util, cpu_util);
8965 if (!(format & NODROPS)) {
8966 if (format & PARSE)
8967 strcpy(fmt, P_DROP_FMT_BRIEF);
8968 else
8969 strcpy(fmt, DROP_FMT_BRIEF);
8970 fprintf(stdout, fmt,
8971 (int64_t)(((srvr_MB - MB)
8972 *1024*1024)
8973 /buflen + 0.5),
8974 (uint64_t)((srvr_MB*1024*1024)
8975 /buflen + 0.5));
8976 }
8977 if (!(format & NOPERCENTLOSS)) {
8978 fractloss = ((srvr_MB != 0.0) ?
8979 1 - MB/srvr_MB : 0.0);
8980 if (format & PARSE)
8981 strcpy(fmt, P_LOSS_FMT_BRIEF);
8982 else if ((fractloss != 0.0) &&
8983 (fractloss < 0.001))
8984 strcpy(fmt, LOSS_FMT_BRIEF5);
8985 else
8986 strcpy(fmt, LOSS_FMT_BRIEF);
8987 fprintf(stdout, fmt, fractloss * 100);
8988 }
8989 if (format & XMITSTATS) {
8990 if (format & PARSE)
8991 strcpy(fmt, P_PERF_FMT_BRIEF3);
8992 else
8993 strcpy(fmt, PERF_FMT_BRIEF3);
8994 fprintf(stdout, fmt, srvr_MB);
8995 }
8996 if ((do_jitter & JITTER_MIN) && njitter) {
8997 if (format & PARSE)
8998 strcpy(fmt,
8999 P_JITTER_MIN_FMT_BRIEF);
9000 else
9001 strcpy(fmt,
9002 JITTER_MIN_FMT_BRIEF);
9003 fprintf(stdout, fmt, jitter_min);
9004 }
9005 if ((do_jitter & JITTER_AVG) && njitter) {
9006 if (format & PARSE)
9007 strcpy(fmt,
9008 P_JITTER_AVG_FMT_BRIEF);
9009 else
9010 strcpy(fmt,
9011 JITTER_AVG_FMT_BRIEF);
9012 fprintf(stdout, fmt,
9013 jitter_avg/njitter);
9014 }
9015 if ((do_jitter & JITTER_MAX) && njitter) {
9016 if (format & PARSE)
9017 strcpy(fmt,
9018 P_JITTER_MAX_FMT_BRIEF);
9019 else
9020 strcpy(fmt,
9021 JITTER_MAX_FMT_BRIEF);
9022 fprintf(stdout, fmt, jitter_max);
9023 }
9024 if ((do_owd & OWD_MIN) && nowd) {
9025 if (format & PARSE)
9026 strcpy(fmt,
9027 P_OWD_MIN_FMT_BRIEF);
9028 else
9029 strcpy(fmt, OWD_MIN_FMT_BRIEF);
9030 fprintf(stdout, fmt, owd_min);
9031 }
9032 if ((do_owd & OWD_AVG) && nowd) {
9033 if (format & PARSE)
9034 strcpy(fmt,
9035 P_OWD_AVG_FMT_BRIEF);
9036 else
9037 strcpy(fmt, OWD_AVG_FMT_BRIEF);
9038 fprintf(stdout, fmt, owd_avg/nowd);
9039 }
9040 if ((do_owd & OWD_MAX) && nowd) {
9041 if (format & PARSE)
9042 strcpy(fmt,
9043 P_OWD_MAX_FMT_BRIEF);
9044 else
9045 strcpy(fmt, OWD_MAX_FMT_BRIEF);
9046 fprintf(stdout, fmt, owd_max);
9047 }
9048 }
9049 fprintf(stdout, "\n");
9050 }
9051 else
9052 if (trans) {
9053 if ((retransinfo > 0) &&
9054 (!(format & NORETRANS))) {
9055 if (format & DEBUGRETRANS) {
9056 sretrans = get_retrans(-1, &tcpinf);
9057 fprintf(stdout,
9058 "report system retrans = %d\n",
9059 sretrans);
9060 }
9061 }
9062 if (*ident)
9063 fprintf(stdout, "%s: ", ident + 1);
9064 if (format & PARSE)
9065 strcpy(fmt, P_PERF_FMT_BRIEF);
9066 else
9067 strcpy(fmt, PERF_FMT_BRIEF);
9068 fprintf(stdout, fmt,
9069 srvr_MB, srvr_realt, srvr_Mbps,
9070 cpu_util, srvr_cpu_util);
9071 if ((nstream > 1) && (retransinfo == 1) &&
9072 total_retrans && !(format & NORETRANS) &&
9073 (brief & BRIEF_RETRANS_STREAMS)) {
9074 if (format & PARSE) {
9075 fprintf(stdout, P_RETRANS_FMT_BRIEF,
9076 "", total_retrans);
9077 fprintf(stdout,
9078 P_RETRANS_FMT_STREAMS,
9079 nretrans[1]);
9080 }
9081 else {
9082 fprintf(stdout,
9083 RETRANS_FMT_BRIEF_STR1,
9084 total_retrans,
9085 nretrans[1]);
9086 }
9087 for ( stream_idx = 2;
9088 stream_idx <= nstream;
9089 stream_idx++ ) {
9090 fprintf(stdout, "+%d",
9091 nretrans[stream_idx]);
9092 }
9093 if (!(format & PARSE))
9094 fprintf(stdout,
9095 RETRANS_FMT_BRIEF_STR2);
9096 }
9097 else if ((retransinfo > 0) &&
9098 (!(format & NORETRANS))) {
9099 if (format & PARSE)
9100 fprintf(stdout,
9101 P_RETRANS_FMT_BRIEF,
9102 retransinfo == 1 ?
9103 "" : "host-",
9104 total_retrans);
9105 else
9106 fprintf(stdout,
9107 RETRANS_FMT_BRIEF,
9108 total_retrans,
9109 retransinfo == 1 ?
9110 "" : "host-");
9111 }
9112 #if defined(linux)
9113 if ((nstream > 1) && cwndinfo &&
9114 (retransinfo == 1) &&
9115 total_snd_cwnd && !(format & NOCWND) &&
9116 (brief & BRIEF_CWND_STREAMS)) {
9117 if (format & PARSE) {
9118 fprintf(stdout, P_CWND_FMT_BRIEF,
9119 total_snd_cwnd);
9120 fprintf(stdout,
9121 P_CWND_FMT_STREAMS,
9122 cwnd[1]);
9123 }
9124 else {
9125 fprintf(stdout,
9126 CWND_FMT_BRIEF_STR1,
9127 total_snd_cwnd,
9128 cwnd[1]);
9129 }
9130 for ( stream_idx = 2;
9131 stream_idx <= nstream;
9132 stream_idx++ ) {
9133 fprintf(stdout, "+%d",
9134 cwnd[stream_idx]);
9135 }
9136 if (!(format & PARSE))
9137 fprintf(stdout,
9138 CWND_FMT_BRIEF_STR2);
9139 }
9140 else if (cwndinfo && (!(format & NOCWND))) {
9141 if (format & PARSE)
9142 fprintf(stdout,
9143 P_CWND_FMT_BRIEF,
9144 total_snd_cwnd);
9145 else
9146 fprintf(stdout,
9147 CWND_FMT_BRIEF,
9148 total_snd_cwnd);
9149 }
9150 #endif
9151 if (rtt && (format & WANTRTT)) {
9152 if (format & PARSE)
9153 strcpy(fmt, P_RTT_FMT_BRIEF);
9154 else
9155 strcpy(fmt, RTT_FMT_BRIEF);
9156 fprintf(stdout, fmt, rtt);
9157 }
9158 if ((do_owd & OWD_MIN) && nowd) {
9159 if (format & PARSE)
9160 strcpy(fmt,
9161 P_OWD_MIN_FMT_BRIEF);
9162 else
9163 strcpy(fmt, OWD_MIN_FMT_BRIEF);
9164 fprintf(stdout, fmt, owd_min);
9165 }
9166 if ((do_owd & OWD_AVG) && nowd) {
9167 if (format & PARSE)
9168 strcpy(fmt,
9169 P_OWD_AVG_FMT_BRIEF);
9170 else
9171 strcpy(fmt, OWD_AVG_FMT_BRIEF);
9172 fprintf(stdout, fmt, owd_avg/nowd);
9173 }
9174 if ((do_owd & OWD_MAX) && nowd) {
9175 if (format & PARSE)
9176 strcpy(fmt,
9177 P_OWD_MAX_FMT_BRIEF);
9178 else
9179 strcpy(fmt, OWD_MAX_FMT_BRIEF);
9180 fprintf(stdout, fmt, owd_max);
9181 }
9182 fprintf(stdout, "\n");
9183 }
9184 else {
9185 if (*ident)
9186 fprintf(stdout, "%s: ", ident + 1);
9187 if (format & PARSE)
9188 strcpy(fmt, P_PERF_FMT_BRIEF);
9189 else
9190 strcpy(fmt, PERF_FMT_BRIEF);
9191 fprintf(stdout, fmt,
9192 MB, realt, (double)nbytes/realt/125000,
9193 srvr_cpu_util, cpu_util);
9194 if ((nstream > 1) && (retransinfo == 1) &&
9195 total_retrans && !(format & NORETRANS) &&
9196 (brief & BRIEF_RETRANS_STREAMS) &&
9197 (irvers >= 70101)) {
9198 if (format & PARSE) {
9199 fprintf(stdout, P_RETRANS_FMT_BRIEF,
9200 "", total_retrans);
9201 fprintf(stdout,
9202 P_RETRANS_FMT_STREAMS,
9203 nretrans[1]);
9204 }
9205 else {
9206 fprintf(stdout,
9207 RETRANS_FMT_BRIEF_STR1,
9208 total_retrans,
9209 nretrans[1]);
9210 }
9211 for ( stream_idx = 2;
9212 stream_idx <= nstream;
9213 stream_idx++ ) {
9214 fprintf(stdout, "+%d",
9215 nretrans[stream_idx]);
9216 }
9217 if (!(format & PARSE))
9218 fprintf(stdout,
9219 RETRANS_FMT_BRIEF_STR2);
9220 }
9221 else if ((retransinfo > 0) &&
9222 (!(format & NORETRANS))) {
9223 if (format & PARSE)
9224 fprintf(stdout,
9225 P_RETRANS_FMT_BRIEF,
9226 retransinfo == 1 ?
9227 "" : "host-",
9228 total_retrans);
9229 else
9230 fprintf(stdout,
9231 RETRANS_FMT_BRIEF,
9232 total_retrans,
9233 retransinfo == 1 ?
9234 "" : "host-");
9235 }
9236 if ((nstream > 1) && cwndinfo &&
9237 (retransinfo == 1) &&
9238 total_snd_cwnd && !(format & NOCWND) &&
9239 (brief & BRIEF_CWND_STREAMS) &&
9240 (irvers >= 80001)) {
9241 if (format & PARSE) {
9242 fprintf(stdout, P_CWND_FMT_BRIEF,
9243 total_snd_cwnd);
9244 fprintf(stdout,
9245 P_CWND_FMT_STREAMS,
9246 cwnd[1]);
9247 }
9248 else {
9249 fprintf(stdout,
9250 CWND_FMT_BRIEF_STR1,
9251 total_snd_cwnd,
9252 cwnd[1]);
9253 }
9254 for ( stream_idx = 2;
9255 stream_idx <= nstream;
9256 stream_idx++ ) {
9257 fprintf(stdout, "+%d",
9258 cwnd[stream_idx]);
9259 }
9260 if (!(format & PARSE))
9261 fprintf(stdout,
9262 CWND_FMT_BRIEF_STR2);
9263 }
9264 else if (cwndinfo && (!(format & NOCWND))) {
9265 if (format & PARSE)
9266 fprintf(stdout,
9267 P_CWND_FMT_BRIEF,
9268 total_snd_cwnd);
9269 else
9270 fprintf(stdout,
9271 CWND_FMT_BRIEF,
9272 total_snd_cwnd);
9273 }
9274 if (rtt && (format & WANTRTT)) {
9275 if (format & PARSE)
9276 strcpy(fmt, P_RTT_FMT_BRIEF);
9277 else
9278 strcpy(fmt, RTT_FMT_BRIEF);
9279 fprintf(stdout, fmt, rtt);
9280 }
9281 if ((do_owd & OWD_MIN) && nowd) {
9282 if (format & PARSE)
9283 strcpy(fmt,
9284 P_OWD_MIN_FMT_BRIEF);
9285 else
9286 strcpy(fmt, OWD_MIN_FMT_BRIEF);
9287 fprintf(stdout, fmt, owd_min);
9288 }
9289 if ((do_owd & OWD_AVG) && nowd) {
9290 if (format & PARSE)
9291 strcpy(fmt,
9292 P_OWD_AVG_FMT_BRIEF);
9293 else
9294 strcpy(fmt, OWD_AVG_FMT_BRIEF);
9295 fprintf(stdout, fmt, owd_avg/nowd);
9296 }
9297 if ((do_owd & OWD_MAX) && nowd) {
9298 if (format & PARSE)
9299 strcpy(fmt,
9300 P_OWD_MAX_FMT_BRIEF);
9301 else
9302 strcpy(fmt, OWD_MAX_FMT_BRIEF);
9303 fprintf(stdout, fmt, owd_max);
9304 }
9305 fprintf(stdout, "\n");
9306 }
9307 }
9308 else {
9309 if (brief && !clientserver) {
9310 if (brief < 0)
9311 fprintf(stdout, "\n");
9312 if (*ident)
9313 fprintf(stdout, "%s: ", ident + 1);
9314 fprintf(stdout, PERF_FMT_BRIEF2 "\n", MB,
9315 realt, (double)nbytes/realt/125000, cpu_util,
9316 trans?"TX":"RX");
9317 }
9318 }
9319
9320 cleanup:
9321 if (clientserver) {
9322 if (client) {
9323 itimer.it_value.tv_sec = SRVR_INFO_TIMEOUT;
9324 itimer.it_value.tv_usec = 0;
9325 setitimer(ITIMER_REAL, &itimer, 0);
9326 if (brief <= 0)
9327 fputs("\n", stdout);
9328 if (brief <= 0) {
9329 if (got_srvr_output) {
9330 fputs(srvrbuf, stdout);
9331 }
9332 }
9333 else {
9334 while (fgets(buf, mallocsize, stdin)) {
9335 setitimer(ITIMER_REAL, &itimer, 0);
9336 fputs(buf, stdout);
9337 }
9338 }
9339 itimer.it_value.tv_sec = 0;
9340 itimer.it_value.tv_usec = 0;
9341 setitimer(ITIMER_REAL, &itimer, 0);
9342 fflush(stdout);
9343 close(0);
9344 }
9345 else {
9346 fflush(stdout);
9347 close(1);
9348 if (!inetd) {
9349 dup(savestdout);
9350 close(savestdout);
9351 fflush(stderr);
9352 if (!nofork) {
9353 close(2);
9354 dup(1);
9355 }
9356 }
9357 }
9358 fclose(ctlconn);
9359 #ifdef DEBUG
9360 if (irate && (format & DEBUGIRATE))
9361 if (debugout) {
9362 fprintf(debugout, "END nuttcp debug output\n");
9363 fclose(debugout);
9364 }
9365 #endif
9366 if (!inetd)
9367 close(fd[0]);
9368 if (!udp && trans && (retransinfo > 0)) {
9369 if (format & DEBUGRETRANS) {
9370 sretrans = get_retrans(-1, &tcpinf);
9371 fprintf(stdout, "final system retrans = %d\n",
9372 sretrans);
9373 }
9374 }
9375 }
9376 if (clientserver && !client) {
9377 for ( stream_idx = 1; stream_idx <= nstream; stream_idx++ ) {
9378 fd[stream_idx] = -1;
9379 }
9380 if (multilink &&
9381 ((trans && !reverse) || (!trans && reverse)) && !udp) {
9382 for ( stream_idx = 2; stream_idx <= nstream;
9383 stream_idx++ ) {
9384 res[stream_idx] = NULL;
9385 }
9386 }
9387 itimer.it_value.tv_sec = 0;
9388 itimer.it_value.tv_usec = 0;
9389 itimer.it_interval.tv_sec = 0;
9390 itimer.it_interval.tv_usec = 0;
9391 setitimer(ITIMER_REAL, &itimer, 0);
9392 signal(SIGALRM, SIG_DFL);
9393 bzero((char *)&frominet, sizeof(frominet));
9394 bzero((char *)&clientaddr, sizeof(clientaddr));
9395 #ifdef AF_INET6
9396 bzero((char *)&clientaddr6, sizeof(clientaddr6));
9397 clientscope6 = 0;
9398 #endif
9399 cput = 0.000001;
9400 realt = 0.000001;
9401 nbytes = 0;
9402 ntbytes = 0;
9403 ntbytesc = 0;
9404 chk_nbytes = 0;
9405 numCalls = 0;
9406 /* Don't re-initialize buflen since it's used to */
9407 /* determine if we need to change the buffer memory */
9408 /* allocation for the next client data stream request */
9409 /* buflen = 64 * 1024; */
9410 /* if (udp) buflen = DEFAULTUDPBUFLEN; */
9411 nbuf = 0;
9412 sendwin = origsendwin;
9413 rcvwin = origrcvwin;
9414 b_flag = 1;
9415 rate = MAXRATE;
9416 maxburst = 1;
9417 nburst = 1;
9418 irate = 0;
9419 iratesss = 0;
9420 irate_cum_nsec = 0.0;
9421 af3 = 0;
9422 timeout = 0.0;
9423 interval = 0.0;
9424 chk_interval = 0.0;
9425 chk_idle_data = 0.0;
9426 datamss = 0;
9427 tos = 0;
9428 nodelay = 0;
9429 do_poll = 0;
9430 pbytes = 0;
9431 ptbytes = 0;
9432 ident[0] = '\0';
9433 intr = 0;
9434 abortconn = 0;
9435 ipad_stride.ip32 = 0;
9436 port = 5101;
9437 srcport = 0;
9438 trans = 0;
9439 braindead = 0;
9440 udp = 0;
9441 udplossinfo = 0;
9442 do_jitter = 0;
9443 do_owd = 0;
9444 retransinfo = 0;
9445 init_pkt_cwnd = 0;
9446 sss_pkt_cwnd = 0;
9447 cwndinfo = 0;
9448 force_retrans = 0;
9449 rtt = 0.0;
9450 which_rt = 1;
9451 pretrans = 0;
9452 sretrans = 0;
9453 got_srvr_output = 0;
9454 reading_srvr_info = 0;
9455 reverse = 0;
9456 format = 0;
9457 traceroute = 0;
9458 multicast = 0;
9459 mc_addr = NULL;
9460 ssm = -1;
9461 skip_data = 0;
9462 host3 = NULL;
9463 thirdparty = 0;
9464 ctlport3 = 0;
9465 nbuf_bytes = 0;
9466 rate_pps = 0;
9467 brief = 0;
9468 done = 0;
9469 got_begin = 0;
9470 two_bod = 0;
9471 handle_urg = 0;
9472 for ( stream_idx = 0; stream_idx <= nstream; stream_idx++ ) {
9473 if (res[stream_idx]) {
9474 freeaddrinfo(res[stream_idx]);
9475 res[stream_idx] = NULL;
9476 }
9477 nretrans[stream_idx] = 0;
9478 iretrans[stream_idx] = 0;
9479 cwnd[stream_idx] = 0;
9480 }
9481 nstream = 1;
9482 multilink = 0;
9483 if (!oneshot)
9484 goto doit;
9485 exit(0);
9486 }
9487
9488 if (multilink) {
9489 for ( stream_idx = 2; stream_idx <= nstream; stream_idx++ ) {
9490 res[stream_idx] = NULL;
9491 }
9492 }
9493 for ( stream_idx = 0; stream_idx <= nstream; stream_idx++ ) {
9494 if (res[stream_idx]) {
9495 freeaddrinfo(res[stream_idx]);
9496 res[stream_idx] = NULL;
9497 }
9498 }
9499
9500 exit(0);
9501
9502 usage:
9503 fprintf(stdout, Usage);
9504 exit(1);
9505 }
9506
9507 static void
err(char * s)9508 err( char *s )
9509 {
9510 long flags, saveflags;
9511
9512 fprintf(stderr, "nuttcp%s%s: v%d.%d.%d%s: Error: ", trans?"-t":"-r",
9513 ident, vers_major, vers_minor, vers_delta,
9514 beta ? BETA_STR : "");
9515 perror(s);
9516 fprintf(stderr, "errno=%d\n", errno);
9517 fflush(stderr);
9518 if ((stream_idx > 0) && !done &&
9519 clientserver && !client && !trans && handle_urg) {
9520 /* send 'A' for ABORT as urgent TCP data
9521 * on control connection (don't block) */
9522 saveflags = fcntl(fd[0], F_GETFL, 0);
9523 if (saveflags != -1) {
9524 flags = saveflags | O_NONBLOCK;
9525 fcntl(fd[0], F_SETFL, flags);
9526 }
9527 send(fd[0], "A", 1, MSG_OOB);
9528 if (saveflags != -1) {
9529 flags = saveflags;
9530 fcntl(fd[0], F_SETFL, flags);
9531 }
9532 }
9533 exit(1);
9534 }
9535
9536 static void
mes(char * s)9537 mes( char *s )
9538 {
9539 fprintf(stdout, "nuttcp%s%s: v%d.%d.%d%s: %s\n", trans?"-t":"-r", ident,
9540 vers_major, vers_minor, vers_delta,
9541 beta ? BETA_STR : "", s);
9542 }
9543
9544 static void
errmes(char * s)9545 errmes( char *s )
9546 {
9547 fprintf(stderr, "nuttcp%s%s: v%d.%d.%d%s: Error: ", trans?"-t":"-r",
9548 ident, vers_major, vers_minor, vers_delta,
9549 beta ? BETA_STR : "");
9550 perror(s);
9551 fprintf(stderr, "errno=%d\n", errno);
9552 fflush(stderr);
9553 }
9554
9555 void
pattern(register char * cp,register int cnt)9556 pattern( register char *cp, register int cnt )
9557 {
9558 register char c;
9559 c = 0;
9560 while (cnt-- > 0) {
9561 while (!isprint((c&0x7F))) c++;
9562 *cp++ = (c++&0x7F);
9563 }
9564 }
9565
9566 void
get_timeofday(struct timeval * tv,struct timezone * tz)9567 get_timeofday( struct timeval *tv, struct timezone *tz )
9568 {
9569 #ifdef HAVE_CLOCK_GETTIME
9570 struct timespec tod;
9571 clockid_t clk_id;
9572
9573 #if defined(_POSIX_MONOTONIC_CLOCK) || defined(__CYGWIN__)
9574 if (do_owd) {
9575 clk_id = CLOCK_REALTIME;
9576 }
9577 else {
9578 clk_id = CLOCK_MONOTONIC;
9579 }
9580 #else /* !(defined(_POSIX_MONOTONIC_CLOCK) || defined(__CYGWIN__)) */
9581 clk_id = CLOCK_REALTIME;
9582 #endif /* defined(_POSIX_MONOTONIC_CLOCK) || defined(__CYGWIN__) */
9583
9584 clock_gettime( clk_id, &tod );
9585 tv->tv_sec = tod.tv_sec;
9586 tv->tv_usec = tod.tv_nsec / 1000;
9587
9588 #else /* !HAVE_CLOCK_GETTIME */
9589 gettimeofday( tv, tz );
9590 #endif /* HAVE_CLOCK_GETTIME */
9591
9592 return;
9593 }
9594
9595 /*
9596 * P R E P _ T I M E R
9597 */
9598 void
prep_timer()9599 prep_timer()
9600 {
9601 get_timeofday(&time0, (struct timezone *)0);
9602 timep.tv_sec = time0.tv_sec;
9603 timep.tv_usec = time0.tv_usec;
9604 timepk.tv_sec = time0.tv_sec;
9605 timepk.tv_usec = time0.tv_usec;
9606 getrusage(RUSAGE_SELF, &ru0);
9607 }
9608
9609 /*
9610 * R E A D _ T I M E R
9611 *
9612 */
9613 double
read_timer(char * str,int len)9614 read_timer( char *str, int len )
9615 {
9616 struct timeval timedol;
9617 struct rusage ru1;
9618 struct timeval td;
9619 struct timeval tend, tstart;
9620 char line[132];
9621
9622 getrusage(RUSAGE_SELF, &ru1);
9623 get_timeofday(&timedol, (struct timezone *)0);
9624 prusage(&ru0, &ru1, &timedol, &time0, line);
9625 (void)strncpy( str, line, len );
9626
9627 /* Get real time */
9628 tvsub( &td, &timedol, &time0 );
9629 realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
9630
9631 /* Get CPU time (user+sys) */
9632 tvadd( &tend, &ru1.ru_utime, &ru1.ru_stime );
9633 tvadd( &tstart, &ru0.ru_utime, &ru0.ru_stime );
9634 tvsub( &td, &tend, &tstart );
9635 cput = td.tv_sec + ((double)td.tv_usec) / 1000000;
9636 if (cput < 0.00001) cput = 0.00001;
9637 return( cput );
9638 }
9639
9640 static void
prusage(register struct rusage * r0,register struct rusage * r1,struct timeval * e,struct timeval * b,char * outp)9641 prusage( register struct rusage *r0, register struct rusage *r1, struct timeval *e, struct timeval *b, char *outp )
9642 {
9643 struct timeval tdiff;
9644 register time_t t;
9645 register char *cp;
9646 register int i;
9647 int ms;
9648
9649 t = (r1->ru_utime.tv_sec-r0->ru_utime.tv_sec)*100+
9650 (r1->ru_utime.tv_usec-r0->ru_utime.tv_usec)/10000+
9651 (r1->ru_stime.tv_sec-r0->ru_stime.tv_sec)*100+
9652 (r1->ru_stime.tv_usec-r0->ru_stime.tv_usec)/10000;
9653 ms = (e->tv_sec-b->tv_sec)*100 + (e->tv_usec-b->tv_usec)/10000;
9654
9655 #define END(x) { while (*x) x++; }
9656
9657 if (format & PARSE)
9658 cp = "user=%U system=%S elapsed=%E cpu=%P memory=%Xi+%Dd-%Mmaxrss io=%F+%Rpf swaps=%Ccsw";
9659 else
9660 cp = "%Uuser %Ssys %Ereal %P %Xi+%Dd %Mmaxrss %F+%Rpf %Ccsw";
9661
9662 for ( ; *cp; cp++ ) {
9663 if (*cp != '%')
9664 *outp++ = *cp;
9665 else if (cp[1]) switch(*++cp) {
9666
9667 case 'U':
9668 tvsub(&tdiff, &r1->ru_utime, &r0->ru_utime);
9669 sprintf(outp, "%ld.%01ld", (long)tdiff.tv_sec, (long)tdiff.tv_usec/100000);
9670 END(outp);
9671 break;
9672
9673 case 'S':
9674 tvsub(&tdiff, &r1->ru_stime, &r0->ru_stime);
9675 sprintf(outp, "%ld.%01ld", (long)tdiff.tv_sec, (long)tdiff.tv_usec/100000);
9676 END(outp);
9677 break;
9678
9679 case 'E':
9680 psecs(ms / 100, outp);
9681 END(outp);
9682 break;
9683
9684 case 'P':
9685 sprintf(outp, "%d%%", (int) (t*100 / ((ms ? ms : 1))));
9686 END(outp);
9687 break;
9688
9689 case 'W':
9690 i = r1->ru_nswap - r0->ru_nswap;
9691 sprintf(outp, "%d", i);
9692 END(outp);
9693 break;
9694
9695 case 'X':
9696 sprintf(outp, "%ld", t == 0 ? 0 : (r1->ru_ixrss-r0->ru_ixrss)/t);
9697 END(outp);
9698 break;
9699
9700 case 'D':
9701 sprintf(outp, "%ld", t == 0 ? 0 :
9702 (r1->ru_idrss+r1->ru_isrss-(r0->ru_idrss+r0->ru_isrss))/t);
9703 END(outp);
9704 break;
9705
9706 case 'K':
9707 sprintf(outp, "%ld", t == 0 ? 0 :
9708 ((r1->ru_ixrss+r1->ru_isrss+r1->ru_idrss) -
9709 (r0->ru_ixrss+r0->ru_idrss+r0->ru_isrss))/t);
9710 END(outp);
9711 break;
9712
9713 case 'M':
9714 sprintf(outp, "%ld", r1->ru_maxrss/2);
9715 END(outp);
9716 break;
9717
9718 case 'F':
9719 sprintf(outp, "%ld", r1->ru_majflt-r0->ru_majflt);
9720 END(outp);
9721 break;
9722
9723 case 'R':
9724 sprintf(outp, "%ld", r1->ru_minflt-r0->ru_minflt);
9725 END(outp);
9726 break;
9727
9728 case 'I':
9729 sprintf(outp, "%ld", r1->ru_inblock-r0->ru_inblock);
9730 END(outp);
9731 break;
9732
9733 case 'O':
9734 sprintf(outp, "%ld", r1->ru_oublock-r0->ru_oublock);
9735 END(outp);
9736 break;
9737 case 'C':
9738 sprintf(outp, "%ld+%ld", r1->ru_nvcsw-r0->ru_nvcsw,
9739 r1->ru_nivcsw-r0->ru_nivcsw);
9740 END(outp);
9741 break;
9742 }
9743 }
9744 *outp = '\0';
9745 }
9746
9747 static void
tvadd(struct timeval * tsum,struct timeval * t0,struct timeval * t1)9748 tvadd( struct timeval *tsum, struct timeval *t0, struct timeval *t1 )
9749 {
9750
9751 tsum->tv_sec = t0->tv_sec + t1->tv_sec;
9752 tsum->tv_usec = t0->tv_usec + t1->tv_usec;
9753 if (tsum->tv_usec > 1000000)
9754 tsum->tv_sec++, tsum->tv_usec -= 1000000;
9755 }
9756
9757 static void
tvsub(struct timeval * tdiff,struct timeval * t1,struct timeval * t0)9758 tvsub( struct timeval *tdiff, struct timeval *t1, struct timeval *t0 )
9759 {
9760
9761 tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
9762 tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
9763 if (tdiff->tv_usec < 0)
9764 tdiff->tv_sec--, tdiff->tv_usec += 1000000;
9765 }
9766
9767 static void
psecs(long l,register char * cp)9768 psecs( long l, register char *cp )
9769 {
9770 register int i;
9771
9772 i = l / 3600;
9773 if (i) {
9774 sprintf(cp, "%d:", i);
9775 END(cp);
9776 i = l % 3600;
9777 sprintf(cp, "%d%d", (i/60) / 10, (i/60) % 10);
9778 END(cp);
9779 }
9780 else {
9781 i = l;
9782 sprintf(cp, "%d", i / 60);
9783 END(cp);
9784 }
9785 i %= 60;
9786 *cp++ = ':';
9787 sprintf(cp, "%d%d", i / 10, i % 10);
9788 }
9789
9790 /*
9791 * N R E A D
9792 */
9793 int
Nread(int fd,char * buf,int count)9794 Nread( int fd, char *buf, int count )
9795 {
9796 struct sockaddr_storage from;
9797 socklen_t len = sizeof(from);
9798 struct timeval timed; /* time delta */
9799 register int cnt;
9800 if (udp) {
9801 cnt = recvfrom( fd, buf, count, 0, (struct sockaddr *)&from, &len );
9802 numCalls++;
9803 }
9804 else {
9805 if (b_flag)
9806 cnt = mread( fd, buf, count ); /* fill buf */
9807 else {
9808 cnt = read( fd, buf, count );
9809 numCalls++;
9810 }
9811 }
9812 if (do_owd && (cnt > 4)) {
9813 uint32_t secs, usecs;
9814
9815 /* get transmitter timestamp */
9816 bcopy(buf + 8, &secs, 4);
9817 bcopy(buf + 12, &usecs, 4);
9818 timetx.tv_sec = ntohl(secs);
9819 timetx.tv_usec = ntohl(usecs);
9820 get_timeofday(&timerx, (struct timezone *)0);
9821 tvsub( &timed, &timerx, &timetx );
9822 owd = timed.tv_sec*1000 + ((double)timed.tv_usec)/1000;
9823 nowd++;
9824 if (owd < owd_min)
9825 owd_min = owd;
9826 if (owd > owd_max)
9827 owd_max = owd;
9828 owd_avg += owd;
9829 nowdi++;
9830 if (owd < owd_mini)
9831 owd_mini = owd;
9832 if (owd > owd_maxi)
9833 owd_maxi = owd;
9834 owd_avgi += owd;
9835 }
9836 return(cnt);
9837 }
9838
9839 /*
9840 * N W R I T E
9841 */
9842 int
Nwrite(int fd,char * buf,int count)9843 Nwrite( int fd, char *buf, int count )
9844 {
9845 struct timeval timedol;
9846 struct timeval td;
9847 register int cnt = 0;
9848 double deltat, delta0;
9849 double pktdelay = 0;
9850 int pktdelay_sec, pktdelay_usec, sssdelay;
9851
9852 if (irate) {
9853 sssdelay = 0;
9854 /* Get real time */
9855 get_timeofday(&timedol, (struct timezone *)0);
9856 tvsub( &td, &timedol, &timepk );
9857 deltat = td.tv_sec + ((double)td.tv_usec) / 1000000;
9858
9859 if (deltat >= (1 + maxburst)*pkt_time) {
9860 timepk.tv_sec = timedol.tv_sec;
9861 timepk.tv_usec = timedol.tv_usec;
9862 irate_cum_nsec = 0;
9863 deltat = 0.0;
9864 nburst = 1;
9865 }
9866
9867 if (nburst++ >= maxburst) {
9868 if (iratesss && cwndinfo) {
9869 /* note iratesss only supported for 1 stream */
9870 tvsub( &td, &timedol, &time0 );
9871 delta0 = td.tv_sec + ((double)td.tv_usec)
9872 / 1000000;
9873 if (delta0 > which_rt*rtt/1000) {
9874 which_rt++;
9875 sss_pkt_cwnd = (cwnd[1] + 1)*1024/datamss;
9876 sss_pkt_cwnd *= 2;
9877 }
9878 pktdelay = rtt/1000/sss_pkt_cwnd*count/datamss;
9879 if (pktdelay <
9880 maxburst*(double)count/rate/125) {
9881 pktdelay =
9882 maxburst*(double)count/rate/125;
9883 iratesss = 0;
9884 }
9885 else {
9886 sssdelay = 1;
9887 }
9888 }
9889 else {
9890 pktdelay = maxburst*(double)count/rate/125;
9891 }
9892 while ((pktdelay > deltat) && !intr) {
9893 /* Get real time */
9894 get_timeofday(&timedol, (struct timezone *)0);
9895 tvsub( &td, &timedol, &timepk );
9896 deltat = td.tv_sec + ((double)td.tv_usec)
9897 / 1000000;
9898 }
9899 }
9900
9901 if (nburst > maxburst) {
9902 if (sssdelay) {
9903 pktdelay_sec = pktdelay;
9904 pktdelay_usec = (pktdelay - pktdelay_sec)
9905 *1000000;
9906 timepk.tv_usec += pktdelay_usec;
9907 if (timepk.tv_usec >= 1000000) {
9908 timepk.tv_usec -= 1000000;
9909 timepk.tv_sec += 1;
9910 }
9911 timepk.tv_sec += pktdelay_sec;
9912 }
9913 else {
9914 irate_cum_nsec += maxburst*irate_pk_nsec;
9915 while (irate_cum_nsec >= 1000.0) {
9916 irate_cum_nsec -= 1000.0;
9917 timepk.tv_usec++;
9918 }
9919 timepk.tv_usec += maxburst*irate_pk_usec;
9920 while (timepk.tv_usec >= 1000000) {
9921 timepk.tv_usec -= 1000000;
9922 timepk.tv_sec++;
9923 }
9924 }
9925 nburst = 1;
9926 }
9927 if (intr && (!udp || (count != 4))) return(0);
9928 }
9929 else {
9930 while ((double)nbytes/realt/125 > rate) {
9931 /* Get real time */
9932 get_timeofday(&timedol, (struct timezone *)0);
9933 tvsub( &td, &timedol, &time0 );
9934 realt = td.tv_sec + ((double)td.tv_usec) / 1000000;
9935 if (realt <= 0.0) realt = 0.000001;
9936 }
9937 }
9938 if (do_owd && (count > 4)) {
9939 uint32_t secs, usecs;
9940
9941 /* record transmitter timestamp in packet */
9942 get_timeofday(&timedol, (struct timezone *)0);
9943 secs = htonl(timedol.tv_sec);
9944 usecs = htonl(timedol.tv_usec);
9945 bcopy(&secs, buf + 8, 4);
9946 bcopy(&usecs, buf + 12, 4);
9947 }
9948 if (udp) {
9949 again:
9950 if (af == AF_INET) {
9951 cnt = sendto( fd, buf, count, 0, (struct sockaddr *)&sinhim[stream_idx + 1], sizeof(sinhim[stream_idx + 1]) );
9952 }
9953 #ifdef AF_INET6
9954 else if (af == AF_INET6) {
9955 cnt = sendto( fd, buf, count, 0, (struct sockaddr *)&sinhim6[stream_idx + 1], sizeof(sinhim6[stream_idx + 1]) );
9956 }
9957 #endif
9958 else {
9959 err("unsupported AF");
9960 }
9961 numCalls++;
9962 if (cnt<0 && errno == ENOBUFS) {
9963 delay(18000);
9964 errno = 0;
9965 goto again;
9966 }
9967 }
9968 else {
9969 #if defined(linux) && defined(DEBUG)
9970 if (irate && (format & DEBUGIRATE) && debugout) {
9971 struct timeval timewr;
9972 double pktwrtime;
9973 static int cnt = 0;
9974
9975 cnt++;
9976 if (cnt == 1) {
9977 fprintf(debugout, "count = %d, datamss = %d, "
9978 "pktxmit = %.8f, "
9979 "rtt = %.6f, maxburst = %d\n",
9980 count, datamss,
9981 (double)count/rate/125,
9982 rtt/1000, maxburst);
9983 }
9984 get_timeofday(&timewr, (struct timezone *)0);
9985 tvsub( &td, &timewr, &time0 );
9986 pktwrtime = td.tv_sec + (double)td.tv_usec/1000000;
9987 fprintf(debugout, "pktwrtime = %.6f, pktdelay = %.6f, "
9988 "sss_pkt_cwnd = %d, "
9989 "cur_pkt_cwnd = %d, iratesss = %d, "
9990 "which_rt = %d\n",
9991 pktwrtime, pktdelay,
9992 sss_pkt_cwnd,
9993 (cwnd[1] + 1)*1024/datamss, iratesss,
9994 which_rt);
9995 }
9996 #endif
9997 cnt = write( fd, buf, count );
9998 numCalls++;
9999 }
10000 return(cnt);
10001 }
10002
10003 int
delay(int us)10004 delay( int us )
10005 {
10006 struct timeval tv;
10007
10008 tv.tv_sec = 0;
10009 tv.tv_usec = us;
10010 (void)select( 1, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
10011 return(1);
10012 }
10013
10014 /*
10015 * M R E A D
10016 *
10017 * This function performs the function of a read(II) but will
10018 * call read(II) multiple times in order to get the requested
10019 * number of characters. This can be necessary because
10020 * network connections don't deliver data with the same
10021 * grouping as it is written with. Written by Robert S. Miles, BRL.
10022 */
10023 int
mread(int fd,register char * bufp,unsigned n)10024 mread( int fd, register char *bufp, unsigned n )
10025 {
10026 register unsigned count = 0;
10027 register int nread;
10028
10029 do {
10030 nread = read(fd, bufp, n-count);
10031 numCalls++;
10032 if (nread < 0) {
10033 if (errno != EINTR)
10034 perror("nuttcp_mread");
10035 return(-1);
10036 }
10037 if (nread == 0)
10038 return((int)count);
10039 count += (unsigned)nread;
10040 bufp += nread;
10041 } while (count < n);
10042
10043 return((int)count);
10044 }
10045
10046 /*
10047 * M W R I T E
10048 *
10049 * This function performs the function of a write(II) but will
10050 * call write(II) multiple times in order to put the requested
10051 * number of characters. This can be necessary because
10052 * piped connections may not be able to deliver data with
10053 * the full requested count.
10054 */
10055 int
mwrite(int fd,register char * bufp,unsigned n,int last_write)10056 mwrite( int fd, register char *bufp, unsigned n, int last_write )
10057 {
10058 register unsigned count = 0;
10059 register int nwrite;
10060 #if defined(linux)
10061 long flags;
10062
10063 if (directio && last_write) {
10064 flags = fcntl(savestdout, F_GETFL, 0);
10065 if (flags < 0)
10066 errmes("fcntl get O_DIRECT");
10067 else {
10068 flags &= ~O_DIRECT;
10069 if (fcntl(savestdout, F_SETFL, flags) < 0)
10070 errmes("fcntl set O_DIRECT");
10071 }
10072 }
10073 #endif
10074 do {
10075 nwrite = write(fd, bufp, n-count);
10076 numCalls++;
10077 if (nwrite < 0) {
10078 if (errno != EINTR)
10079 perror("nuttcp_mwrite");
10080 return(-1);
10081 }
10082 count += (unsigned)nwrite;
10083 bufp += nwrite;
10084 } while (count < n);
10085
10086 return((int)count);
10087 }
10088
10089 /*
10090 * G E T O P T V A L P
10091 *
10092 * This function returns a character pointer to the option value
10093 * pointed at by argv and sets skiparg to 1 if the option and its
10094 * value were passed as separate arguments (otherwise it sets
10095 * skiparg to 0). index is the position within argv where the
10096 * option value resides if the option was specified as a single
10097 * argument. reqval indicates whether or not the option requires
10098 * a value
10099 */
10100 char *
getoptvalp(char ** argv,int index,int reqval,int * skiparg)10101 getoptvalp( char **argv, int index, int reqval, int *skiparg )
10102 {
10103 struct sockaddr_storage dummy;
10104 char **nextarg;
10105
10106 *skiparg = 0;
10107 nextarg = argv + 1;
10108
10109 /* if there is a value in the current arg return it */
10110 if (argv[0][index])
10111 return(&argv[0][index]);
10112
10113 /* if there isn't a next arg return a pointer to the
10114 current arg value (which will be an empty string) */
10115 if (*nextarg == NULL)
10116 return(&argv[0][index]);
10117
10118 /* if the next arg is another option, and a value isn't
10119 * required, return a pointer to the current arg value
10120 * (which will be an empty string) */
10121 if ((**nextarg == '-') && !reqval)
10122 return(&argv[0][index]);
10123
10124 /* if there is an arg after the next arg and it is another
10125 option, return the next arg as the option value */
10126 if (*(nextarg + 1) && (**(nextarg + 1) == '-')) {
10127 *skiparg = 1;
10128 return(*nextarg);
10129 }
10130
10131 /* if the option requires a value, return the next arg
10132 as the option value */
10133 if (reqval) {
10134 *skiparg = 1;
10135 return(*nextarg);
10136 }
10137
10138 /* if the next arg is an Ipv4 address, return a pointer to the
10139 current arg value (which will be an empty string) */
10140 if (inet_pton(AF_INET, *nextarg, &dummy) > 0)
10141 return(&argv[0][index]);
10142
10143 #ifdef AF_INET6
10144 /* if the next arg is an Ipv6 address, return a pointer to the
10145 current arg value (which will be an empty string) */
10146 if (inet_pton(AF_INET6, *nextarg, &dummy) > 0)
10147 return(&argv[0][index]);
10148 #endif
10149
10150 /* if the next arg begins with an alphabetic character,
10151 assume it is a hostname and thus return a pointer to the
10152 current arg value (which will be an empty string).
10153 note all current options which don't require a value
10154 have numeric values (start with a digit) */
10155 if (isalpha((int)(**nextarg)))
10156 return(&argv[0][index]);
10157
10158 /* assume the next arg is the option value */
10159 *skiparg = 1;
10160
10161 return(*nextarg);
10162 }
10163
10164 #define PROC_SNMP "/proc/net/snmp"
10165 #define PROC_BUF_LEN 256
10166 #define PROC_BUF_LEN2 128
10167 #define NETSTAT "netstat"
10168
10169 #if defined(linux)
10170 #define RETRANS "segments retransmited"
10171 #define NETSTAT_DIR "/bin/"
10172 #define NRETRANS_BEFORE
10173 #elif defined(__FreeBSD__)
10174 #define RETRANS "retransmitted"
10175 #define NETSTAT_DIR "/usr/bin/"
10176 #define NRETRANS_BEFORE
10177 #elif defined(__APPLE__) && defined(__MACH__)
10178 #define RETRANS "retransmitted"
10179 #define NETSTAT_DIR "/usr/sbin/"
10180 #define NRETRANS_BEFORE
10181 #elif defined(sparc)
10182 #define RETRANS "tcpRetransSegs"
10183 #define NETSTAT_DIR "/usr/bin/"
10184 #elif defined(sgi)
10185 #define RETRANS "retransmitted"
10186 #define NETSTAT_DIR "/usr/etc/"
10187 #define NRETRANS_BEFORE
10188 #elif defined(__CYGWIN__) || defined(_WIN32)
10189 #define RETRANS "Segments Retransmitted"
10190 #define NETSTAT_DIR ""
10191 #else
10192 #define RETRANS "retransmitted"
10193 #define NETSTAT_DIR "/usr/bin/"
10194 #define NRETRANS_BEFORE
10195 #endif
10196
10197 char proc_buf[PROC_BUF_LEN];
10198 char proc_buf2[PROC_BUF_LEN2];
10199
get_retrans(int sockfd,struct STRUCT_TCPINFO * tcpinfo)10200 int get_retrans( int sockfd, struct STRUCT_TCPINFO *tcpinfo )
10201 {
10202 FILE *proc_snmp;
10203 char *cp, *cp2;
10204 int num_retrans;
10205 int pipefd[2];
10206 int pidstat;
10207 pid_t pid = 0;
10208 pid_t wait_pid;
10209
10210 if (retransinfo < 0)
10211 return(0);
10212
10213 #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS)
10214 if ((retransinfo <= 1) && (sockfd >= 0)) {
10215 optlen = sizeof(*tcpinfo);
10216 if (getsockopt(sockfd, SOL_TCP, TCP_INFO, (void *)tcpinfo,
10217 &optlen) == 0) {
10218 if (optlen >= SIZEOF_TCP_INFO_RETRANS) {
10219 retransinfo = 1;
10220 cwndinfo = 1;
10221 b_flag = 1;
10222 return(tcpinfo->tcpi_total_retrans);
10223 }
10224 }
10225 if (retransinfo == 1) {
10226 retransinfo = -1;
10227 cwndinfo = 0;
10228 return(0);
10229 }
10230 retransinfo = 2;
10231 cwndinfo = 0;
10232 }
10233 #else
10234 retransinfo = 2;
10235 cwndinfo = 0;
10236 #endif
10237
10238 if ((retransinfo == 3) || (!(proc_snmp = fopen(PROC_SNMP, "r")))) {
10239 retransinfo = 3;
10240 cwndinfo = 0;
10241 if (pipe(pipefd) != 0) {
10242 retransinfo = -1;
10243 cwndinfo = 0;
10244 return(0);
10245 }
10246 if ((pid = fork()) == (pid_t)-1) {
10247 perror("can't fork");
10248 close(pipefd[0]);
10249 close(pipefd[1]);
10250 retransinfo = -1;
10251 cwndinfo = 0;
10252 return(0);
10253 }
10254 if (pid == 0) {
10255 signal(SIGINT, SIG_DFL);
10256 close(1);
10257 close(2);
10258 dup(pipefd[1]);
10259 dup(pipefd[1]);
10260 close(pipefd[0]);
10261 close(pipefd[1]);
10262 execl(NETSTAT_DIR NETSTAT, NETSTAT, "-s", NULL);
10263 perror("execl failed");
10264 fprintf(stderr, "failed to execute %s%s -s\n",
10265 NETSTAT_DIR, NETSTAT);
10266 fflush(stdout);
10267 fflush(stderr);
10268 exit(0);
10269 }
10270 close(pipefd[1]);
10271 if (!(proc_snmp = fdopen(pipefd[0], "r"))) {
10272 close(pipefd[0]);
10273 retransinfo = -1;
10274 cwndinfo = 0;
10275 return(0);
10276 }
10277 }
10278
10279 errno = 0;
10280 num_retrans = -1;
10281 while (fgets(proc_buf, sizeof(proc_buf), proc_snmp)) {
10282 if (retransinfo == 2) {
10283 if (strncmp(proc_buf, "Tcp:", 4) != 0)
10284 continue;
10285 if ((!fgets(proc_buf2, sizeof(proc_buf2), proc_snmp))
10286 || (strncmp(proc_buf2, "Tcp:", 4) != 0))
10287 break;
10288 cp = proc_buf;
10289 cp2 = proc_buf2;
10290 while ((cp = strchr(cp, ' '))) {
10291 while (*++cp == ' ')
10292 ;
10293 if (!(*cp))
10294 goto close;
10295 if (!(cp2 = strchr(cp2, ' ')))
10296 goto close;
10297 while (*++cp2 == ' ')
10298 ;
10299 if (!(*cp2))
10300 goto close;
10301 if (strncmp(cp, "RetransSegs", 11) == 0) {
10302 if (!isdigit((int)(*cp2)))
10303 goto close;
10304 num_retrans = atoi(cp2);
10305 goto close;
10306 }
10307 else
10308 continue;
10309 }
10310 }
10311 else {
10312 if ((cp = strstr(proc_buf, RETRANS))) {
10313 #ifdef NRETRANS_BEFORE
10314 num_retrans = atoi(proc_buf);
10315 #else
10316 cp2 = strchr(cp, '=');
10317 cp2++;
10318 num_retrans = atoi(cp2);
10319 #endif
10320 break;
10321 }
10322 }
10323 }
10324
10325 close:
10326 fclose(proc_snmp);
10327 if (retransinfo == 3) {
10328 while ((wait_pid = wait(&pidstat)) != pid) {
10329 if (wait_pid == (pid_t)-1) {
10330 if (errno == ECHILD)
10331 break;
10332 err("wait failed");
10333 }
10334 }
10335 }
10336
10337 if (num_retrans < 0) {
10338 retransinfo = -1;
10339 cwndinfo = 0;
10340 return(0);
10341 }
10342
10343 return(num_retrans);
10344 }
10345
10346 #if defined(linux) && defined(TCPI_OPT_TIMESTAMPS)
10347
10348 void
print_tcpinfo()10349 print_tcpinfo()
10350 {
10351 fprintf(stdout, "state = %d, ca_state = %d, retransmits = %d, "
10352 "unacked = %d, sacked = %d\n",
10353 tcpinf.tcpinfo_state, tcpinf.tcpinfo_ca_state,
10354 tcpinf.tcpinfo_retransmits, tcpinf.tcpinfo_unacked,
10355 tcpinf.tcpinfo_sacked);
10356 fprintf(stdout, " lost = %d, retrans = %d, fackets = %d, "
10357 "rtt = %d, rttvar = %d\n",
10358 tcpinf.tcpinfo_lost, tcpinf.tcpinfo_retrans,
10359 tcpinf.tcpinfo_fackets, tcpinf.tcpinfo_rtt,
10360 tcpinf.tcpinfo_rttvar);
10361 fprintf(stdout, " snd_ssthresh = %d, snd_cwnd = %d, "
10362 "total_retrans = %d\n",
10363 tcpinf.tcpinfo_snd_ssthresh, tcpinf.tcpinfo_snd_cwnd,
10364 tcpinf.tcpi_total_retrans);
10365 return;
10366 }
10367
10368 #endif
10369
10370