]> sjero.net Git - iperf/blob - src/Settings.cpp
Original 2.0.2 iperf sources
[iperf] / src / Settings.cpp
1 /*--------------------------------------------------------------- 
2  * Copyright (c) 1999,2000,2001,2002,2003                              
3  * The Board of Trustees of the University of Illinois            
4  * All Rights Reserved.                                           
5  *--------------------------------------------------------------- 
6  * Permission is hereby granted, free of charge, to any person    
7  * obtaining a copy of this software (Iperf) and associated       
8  * documentation files (the "Software"), to deal in the Software  
9  * without restriction, including without limitation the          
10  * rights to use, copy, modify, merge, publish, distribute,        
11  * sublicense, and/or sell copies of the Software, and to permit     
12  * persons to whom the Software is furnished to do
13  * so, subject to the following conditions: 
14  *
15  *     
16  * Redistributions of source code must retain the above 
17  * copyright notice, this list of conditions and 
18  * the following disclaimers. 
19  *
20  *     
21  * Redistributions in binary form must reproduce the above 
22  * copyright notice, this list of conditions and the following 
23  * disclaimers in the documentation and/or other materials 
24  * provided with the distribution. 
25  * 
26  *     
27  * Neither the names of the University of Illinois, NCSA, 
28  * nor the names of its contributors may be used to endorse 
29  * or promote products derived from this Software without
30  * specific prior written permission. 
31  * 
32  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
33  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
34  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
35  * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT 
36  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
37  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
38  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
40  * ________________________________________________________________
41  * National Laboratory for Applied Network Research 
42  * National Center for Supercomputing Applications 
43  * University of Illinois at Urbana-Champaign 
44  * http://www.ncsa.uiuc.edu
45  * ________________________________________________________________ 
46  *
47  * Settings.cpp
48  * by Mark Gates <mgates@nlanr.net>
49  * & Ajay Tirumala <tirumala@ncsa.uiuc.edu>
50  * -------------------------------------------------------------------
51  * Stores and parses the initial values for all the global variables.
52  * -------------------------------------------------------------------
53  * headers
54  * uses
55  *   <stdlib.h>
56  *   <stdio.h>
57  *   <string.h>
58  *
59  *   <unistd.h>
60  * ------------------------------------------------------------------- */
61
62 #define HEADERS()
63
64 #include "headers.h"
65
66 #include "Settings.hpp"
67 #include "Locale.h"
68 #include "SocketAddr.h"
69
70 #include "util.h"
71
72 #include "gnu_getopt.h"
73
74 void Settings_Interpret( char option, const char *optarg, thread_Settings *mExtSettings );
75
76 /* -------------------------------------------------------------------
77  * command line options
78  *
79  * The option struct essentially maps a long option name (--foobar)
80  * or environment variable ($FOOBAR) to its short option char (f).
81  * ------------------------------------------------------------------- */
82 #define LONG_OPTIONS()
83
84 const struct option long_options[] =
85 {
86 {"singleclient",     no_argument, NULL, '1'},
87 {"bandwidth",  required_argument, NULL, 'b'},
88 {"client",     required_argument, NULL, 'c'},
89 {"dualtest",         no_argument, NULL, 'd'},
90 {"format",     required_argument, NULL, 'f'},
91 {"help",             no_argument, NULL, 'h'},
92 {"interval",   required_argument, NULL, 'i'},
93 {"len",        required_argument, NULL, 'l'},
94 {"print_mss",        no_argument, NULL, 'm'},
95 {"num",        required_argument, NULL, 'n'},
96 {"output",     required_argument, NULL, 'o'},
97 {"port",       required_argument, NULL, 'p'},
98 {"tradeoff",         no_argument, NULL, 'r'},
99 {"server",           no_argument, NULL, 's'},
100 {"time",       required_argument, NULL, 't'},
101 {"udp",              no_argument, NULL, 'u'},
102 {"version",          no_argument, NULL, 'v'},
103 {"window",     required_argument, NULL, 'w'},
104 {"reportexclude", required_argument, NULL, 'x'},
105 {"reportstyle",required_argument, NULL, 'y'},
106
107 // more esoteric options
108 {"bind",       required_argument, NULL, 'B'},
109 {"compatibility",    no_argument, NULL, 'C'},
110 {"daemon",           no_argument, NULL, 'D'},
111 {"file_input", required_argument, NULL, 'F'},
112 {"stdin_input",      no_argument, NULL, 'I'},
113 {"mss",        required_argument, NULL, 'M'},
114 {"nodelay",          no_argument, NULL, 'N'},
115 {"listenport", required_argument, NULL, 'L'},
116 {"parallel",   required_argument, NULL, 'P'},
117 {"remove",           no_argument, NULL, 'R'},
118 {"tos",        required_argument, NULL, 'S'},
119 {"ttl",        required_argument, NULL, 'T'},
120 {"single_udp",       no_argument, NULL, 'U'},
121 {"ipv6_domian",      no_argument, NULL, 'V'},
122 {"suggest_win_size", no_argument, NULL, 'W'},
123 {0, 0, 0, 0}
124 };
125
126 #define ENV_OPTIONS()
127
128 const struct option env_options[] =
129 {
130 {"IPERF_SINGLECLIENT",     no_argument, NULL, '1'},
131 {"IPERF_BANDWIDTH",  required_argument, NULL, 'b'},
132 {"IPERF_CLIENT",     required_argument, NULL, 'c'},
133 {"IPERF_DUALTEST",         no_argument, NULL, 'd'},
134 {"IPERF_FORMAT",     required_argument, NULL, 'f'},
135 // skip help
136 {"IPERF_INTERVAL",   required_argument, NULL, 'i'},
137 {"IPERF_LEN",        required_argument, NULL, 'l'},
138 {"IPERF_PRINT_MSS",        no_argument, NULL, 'm'},
139 {"IPERF_NUM",        required_argument, NULL, 'n'},
140 {"IPERF_PORT",       required_argument, NULL, 'p'},
141 {"IPERF_TRADEOFF",         no_argument, NULL, 'r'},
142 {"IPERF_SERVER",           no_argument, NULL, 's'},
143 {"IPERF_TIME",       required_argument, NULL, 't'},
144 {"IPERF_UDP",              no_argument, NULL, 'u'},
145 // skip version
146 {"TCP_WINDOW_SIZE",  required_argument, NULL, 'w'},
147 {"IPERF_REPORTEXCLUDE", required_argument, NULL, 'x'},
148 {"IPERF_REPORTSTYLE",required_argument, NULL, 'y'},
149
150 // more esoteric options
151 {"IPERF_BIND",       required_argument, NULL, 'B'},
152 {"IPERF_COMPAT",           no_argument, NULL, 'C'},
153 {"IPERF_DAEMON",           no_argument, NULL, 'D'},
154 {"IPERF_FILE_INPUT", required_argument, NULL, 'F'},
155 {"IPERF_STDIN_INPUT",      no_argument, NULL, 'I'},
156 {"IPERF_MSS",        required_argument, NULL, 'M'},
157 {"IPERF_NODELAY",          no_argument, NULL, 'N'},
158 {"IPERF_LISTENPORT", required_argument, NULL, 'L'},
159 {"IPERF_PARALLEL",   required_argument, NULL, 'P'},
160 {"IPERF_TOS",        required_argument, NULL, 'S'},
161 {"IPERF_TTL",        required_argument, NULL, 'T'},
162 {"IPERF_SINGLE_UDP",       no_argument, NULL, 'U'},
163 {"IPERF_IPV6_DOMAIN",      no_argument, NULL, 'V'},
164 {"IPERF_SUGGEST_WIN_SIZE", required_argument, NULL, 'W'},
165 {0, 0, 0, 0}
166 };
167
168 #define SHORT_OPTIONS()
169
170 const char short_options[] = "1b:c:df:hi:l:mn:o:p:rst:uvw:x:y:B:CDF:IL:M:NP:RS:T:UVW";
171
172 /* -------------------------------------------------------------------
173  * defaults
174  * ------------------------------------------------------------------- */
175 #define DEFAULTS()
176
177 const long kDefault_UDPRate = 1024 * 1024; // -u  if set, 1 Mbit/sec
178 const int  kDefault_UDPBufLen = 1470;      // -u  if set, read/write 1470 bytes
179 // 1470 bytes is small enough to be sending one packet per datagram on ethernet
180
181 // 1450 bytes is small enough to be sending one packet per datagram on ethernet
182 //  **** with IPv6 ****
183
184 /* -------------------------------------------------------------------
185  * Initialize all settings to defaults.
186  * ------------------------------------------------------------------- */
187
188 void Settings_Initialize( thread_Settings *main ) {
189     // Everything defaults to zero or NULL with
190     // this memset. Only need to set non-zero values
191     // below.
192     memset( main, 0, sizeof(thread_Settings) );
193     main->mSock = INVALID_SOCKET;
194     main->mReportMode = kReport_Default;
195     // option, defaults
196     main->flags         = FLAG_MODETIME | FLAG_STDOUT; // Default time and stdout
197     //main->mUDPRate      = 0;           // -b,  ie. TCP mode
198     //main->mHost         = NULL;        // -c,  none, required for client
199     main->mMode         = kTest_Normal;  // -d,  mMode == kTest_DualTest
200     main->mFormat       = 'a';           // -f,  adaptive bits
201     // skip help                         // -h,
202     //main->mBufLenSet  = false;         // -l, 
203     main->mBufLen       = 8 * 1024;      // -l,  8 Kbyte
204     //main->mInterval     = 0;           // -i,  ie. no periodic bw reports
205     //main->mPrintMSS   = false;         // -m,  don't print MSS
206     // mAmount is time also              // -n,  N/A
207     //main->mOutputFileName = NULL;      // -o,  filename
208     main->mPort         = 5001;          // -p,  ttcp port
209     // mMode    = kTest_Normal;          // -r,  mMode == kTest_TradeOff
210     main->mThreadMode   = kMode_Unknown; // -s,  or -c, none
211     main->mAmount       = 1000;          // -t,  10 seconds
212     // mUDPRate > 0 means UDP            // -u,  N/A, see kDefault_UDPRate
213     // skip version                      // -v,
214     //main->mTCPWin       = 0;           // -w,  ie. don't set window
215
216     // more esoteric options
217     //main->mLocalhost    = NULL;        // -B,  none
218     //main->mCompat     = false;         // -C,  run in Compatibility mode
219     //main->mDaemon     = false;         // -D,  run as a daemon
220     //main->mFileInput  = false;         // -F,
221     //main->mFileName     = NULL;        // -F,  filename 
222     //main->mStdin      = false;         // -I,  default not stdin
223     //main->mListenPort   = 0;           // -L,  listen port
224     //main->mMSS          = 0;           // -M,  ie. don't set MSS
225     //main->mNodelay    = false;         // -N,  don't set nodelay
226     //main->mThreads      = 0;           // -P,
227     //main->mRemoveService = false;      // -R,
228     //main->mTOS          = 0;           // -S,  ie. don't set type of service
229     main->mTTL          = 1;             // -T,  link-local TTL
230     //main->mDomain     = kMode_IPv4;    // -V,
231     //main->mSuggestWin = false;         // -W,  Suggest the window size.
232
233 } // end Settings
234
235 void Settings_Copy( thread_Settings *from, thread_Settings **into ) {
236     *into = new thread_Settings;
237     memcpy( *into, from, sizeof(thread_Settings) );
238     if ( from->mHost != NULL ) {
239         (*into)->mHost = new char[ strlen(from->mHost) + 1];
240         strcpy( (*into)->mHost, from->mHost );
241     }
242     if ( from->mOutputFileName != NULL ) {
243         (*into)->mOutputFileName = new char[ strlen(from->mOutputFileName) + 1];
244         strcpy( (*into)->mOutputFileName, from->mOutputFileName );
245     }
246     if ( from->mLocalhost != NULL ) {
247         (*into)->mLocalhost = new char[ strlen(from->mLocalhost) + 1];
248         strcpy( (*into)->mLocalhost, from->mLocalhost );
249     }
250     if ( from->mFileName != NULL ) {
251         (*into)->mFileName = new char[ strlen(from->mFileName) + 1];
252         strcpy( (*into)->mFileName, from->mFileName );
253     }
254     // Zero out certain entries
255     (*into)->mTID = thread_zeroid();
256     (*into)->runNext = NULL;
257     (*into)->runNow = NULL;
258 }
259
260 /* -------------------------------------------------------------------
261  * Delete memory: Does not clean up open file pointers or ptr_parents
262  * ------------------------------------------------------------------- */
263
264 void Settings_Destroy( thread_Settings *mSettings) {
265     DELETE_ARRAY( mSettings->mHost      );
266     DELETE_ARRAY( mSettings->mLocalhost );
267     DELETE_ARRAY( mSettings->mFileName  );
268     DELETE_ARRAY( mSettings->mOutputFileName );
269     DELETE_PTR( mSettings );
270 } // end ~Settings
271
272 /* -------------------------------------------------------------------
273  * Parses settings from user's environment variables.
274  * ------------------------------------------------------------------- */
275 void Settings_ParseEnvironment( thread_Settings *mSettings ) {
276     char *theVariable;
277
278     int i = 0;
279     while ( env_options[i].name != NULL ) {
280         theVariable = getenv( env_options[i].name );
281         if ( theVariable != NULL ) {
282             Settings_Interpret( env_options[i].val, theVariable, mSettings );
283         }
284         i++;
285     }
286 } // end ParseEnvironment
287
288 /* -------------------------------------------------------------------
289  * Parse settings from app's command line.
290  * ------------------------------------------------------------------- */
291
292 void Settings_ParseCommandLine( int argc, char **argv, thread_Settings *mSettings ) {
293     int option;
294     while ( (option =
295              gnu_getopt_long( argc, argv, short_options,
296                               long_options, NULL )) != EOF ) {
297         Settings_Interpret( option, gnu_optarg, mSettings );
298     }
299
300     for ( int i = gnu_optind; i < argc; i++ ) {
301         fprintf( stderr, "%s: ignoring extra argument -- %s\n", argv[0], argv[i] );
302     }
303 } // end ParseCommandLine
304
305 /* -------------------------------------------------------------------
306  * Interpret individual options, either from the command line
307  * or from environment variables.
308  * ------------------------------------------------------------------- */
309
310 void Settings_Interpret( char option, const char *optarg, thread_Settings *mExtSettings ) {
311     char outarg[100];
312
313     switch ( option ) {
314         case '1': // Single Client
315             setSingleClient( mExtSettings );
316             break;
317         case 'b': // UDP bandwidth
318             if ( !isUDP( mExtSettings ) ) {
319                 fprintf( stderr, warn_implied_udp, option );
320             }
321
322             if ( mExtSettings->mThreadMode != kMode_Client ) {
323                 fprintf( stderr, warn_invalid_server_option, option );
324                 break;
325             }
326
327             Settings_GetLowerCaseArg(optarg,outarg);
328             mExtSettings->mUDPRate = byte_atoi(outarg);
329             setUDP( mExtSettings );
330
331             // if -l has already been processed, mBufLenSet is true
332             // so don't overwrite that value.
333             if ( !isBuflenSet( mExtSettings ) ) {
334                 mExtSettings->mBufLen = kDefault_UDPBufLen;
335             }
336             break;
337
338         case 'c': // client mode w/ server host to connect to
339             mExtSettings->mHost = new char[ strlen( optarg ) + 1 ];
340             strcpy( mExtSettings->mHost, optarg );
341
342             if ( mExtSettings->mThreadMode == kMode_Unknown ) {
343                 // Test for Multicast
344                 iperf_sockaddr temp;
345                 SockAddr_setHostname( mExtSettings->mHost, &temp,
346                                       (isIPV6( mExtSettings ) ? 1 : 0 ));
347                 if ( SockAddr_isMulticast( &temp ) ) {
348                     setMulticast( mExtSettings );
349                 }
350                 mExtSettings->mThreadMode = kMode_Client;
351                 mExtSettings->mThreads = 1;
352             }
353             break;
354
355         case 'd': // Dual-test Mode
356             if ( mExtSettings->mThreadMode != kMode_Client ) {
357                 fprintf( stderr, warn_invalid_server_option, option );
358                 break;
359             }
360             if ( isCompat( mExtSettings ) ) {
361                 fprintf( stderr, warn_invalid_compatibility_option, option );
362             }
363 #ifdef HAVE_THREAD
364             mExtSettings->mMode = kTest_DualTest;
365 #else
366             fprintf( stderr, warn_invalid_single_threaded, option );
367             mExtSettings->mMode = kTest_TradeOff;
368 #endif
369             break;
370
371         case 'f': // format to print in
372             mExtSettings->mFormat = (*optarg);
373             break;
374
375         case 'h': // print help and exit
376 #ifndef WIN32
377             fprintf( stderr, usage_long );
378 #else
379             fprintf(stderr, usage_long1);
380             fprintf(stderr, usage_long2);
381 #endif
382             exit(1);
383             break;
384
385         case 'i': // specify interval between periodic bw reports
386             mExtSettings->mInterval = atof( optarg );
387             if ( mExtSettings->mInterval < 0.5 ) {
388                 fprintf (stderr, report_interval_small, mExtSettings->mInterval);
389                 mExtSettings->mInterval = 0.5;
390             }
391             break;
392
393         case 'l': // length of each buffer
394             Settings_GetUpperCaseArg(optarg,outarg);
395             mExtSettings->mBufLen = byte_atoi( outarg );
396             setBuflenSet( mExtSettings );
397             if ( !isUDP( mExtSettings ) ) {
398                  if ( mExtSettings->mBufLen < (int) sizeof( client_hdr ) &&
399                       !isCompat( mExtSettings ) ) {
400                     setCompat( mExtSettings );
401                     fprintf( stderr, warn_implied_compatibility, option );
402                  }
403             } else {
404                 if ( mExtSettings->mBufLen < (int) sizeof( UDP_datagram ) ) {
405                     mExtSettings->mBufLen = sizeof( UDP_datagram );
406                     fprintf( stderr, warn_buffer_too_small, mExtSettings->mBufLen );
407                 }
408                 if ( !isCompat( mExtSettings ) &&
409                             mExtSettings->mBufLen < (int) ( sizeof( UDP_datagram )
410                             + sizeof( client_hdr ) ) ) {
411                     setCompat( mExtSettings );
412                     fprintf( stderr, warn_implied_compatibility, option );
413                 }
414             }
415
416             break;
417
418         case 'm': // print TCP MSS
419             setPrintMSS( mExtSettings );
420             break;
421
422         case 'n': // bytes of data
423             // amount mode (instead of time mode)
424             unsetModeTime( mExtSettings );
425             Settings_GetUpperCaseArg(optarg,outarg);
426             mExtSettings->mAmount = byte_atoi( outarg );
427             break;
428
429         case 'o' : // output the report and other messages into the file
430             unsetSTDOUT( mExtSettings );
431             mExtSettings->mOutputFileName = new char[strlen(optarg)+1];
432             strcpy( mExtSettings->mOutputFileName, optarg);
433             break;
434
435         case 'p': // server port
436             mExtSettings->mPort = atoi( optarg );
437             break;
438
439         case 'r': // test mode tradeoff
440             if ( mExtSettings->mThreadMode != kMode_Client ) {
441                 fprintf( stderr, warn_invalid_server_option, option );
442                 break;
443             }
444             if ( isCompat( mExtSettings ) ) {
445                 fprintf( stderr, warn_invalid_compatibility_option, option );
446             }
447
448             mExtSettings->mMode = kTest_TradeOff;
449             break;
450
451         case 's': // server mode
452             if ( mExtSettings->mThreadMode != kMode_Unknown ) {
453                 fprintf( stderr, warn_invalid_client_option, option );
454                 break;
455             }
456
457             mExtSettings->mThreadMode = kMode_Listener;
458             break;
459
460         case 't': // seconds to write for
461             // time mode (instead of amount mode)
462             setModeTime( mExtSettings );
463             mExtSettings->mAmount = (int) (atof( optarg ) * 100.0);
464             break;
465
466         case 'u': // UDP instead of TCP
467             // if -b has already been processed, UDP rate will
468             // already be non-zero, so don't overwrite that value
469             if ( !isUDP( mExtSettings ) ) {
470                 setUDP( mExtSettings );
471                 mExtSettings->mUDPRate = kDefault_UDPRate;
472             }
473
474             // if -l has already been processed, mBufLenSet is true
475             // so don't overwrite that value.
476             if ( !isBuflenSet( mExtSettings ) ) {
477                 mExtSettings->mBufLen = kDefault_UDPBufLen;
478             } else if ( mExtSettings->mBufLen < (int) ( sizeof( UDP_datagram ) 
479                         + sizeof( client_hdr ) ) &&
480                         !isCompat( mExtSettings ) ) {
481                 setCompat( mExtSettings );
482                 fprintf( stderr, warn_implied_compatibility, option );
483             }
484             break;
485
486         case 'v': // print version and exit
487             fprintf( stderr, version );
488             exit(1);
489             break;
490
491         case 'w': // TCP window size (socket buffer size)
492             Settings_GetUpperCaseArg(optarg,outarg);
493             mExtSettings->mTCPWin = byte_atoi(outarg);
494
495             if ( mExtSettings->mTCPWin < 2048 ) {
496                 fprintf( stderr, warn_window_small, mExtSettings->mTCPWin );
497             }
498             break;
499
500         case 'x': // Limit Reports
501             while ( *optarg != '\0' ) {
502                 switch ( *optarg ) {
503                     case 's':
504                     case 'S':
505                         setNoSettReport( mExtSettings );
506                         break;
507                     case 'c':
508                     case 'C':
509                         setNoConnReport( mExtSettings );
510                         break;
511                     case 'd':
512                     case 'D':
513                         setNoDataReport( mExtSettings );
514                         break;
515                     case 'v':
516                     case 'V':
517                         setNoServReport( mExtSettings );
518                         break;
519                     case 'm':
520                     case 'M':
521                         setNoMultReport( mExtSettings );
522                         break;
523                     default:
524                         fprintf(stderr, warn_invalid_report, *optarg);
525                 }
526                 optarg++;
527             }
528             break;
529
530         case 'y': // Reporting Style
531             switch ( *optarg ) {
532                 case 'c':
533                 case 'C':
534                     mExtSettings->mReportMode = kReport_CSV;
535                     break;
536                 default:
537                     fprintf( stderr, warn_invalid_report_style, optarg );
538             }
539             break;
540
541
542             // more esoteric options
543         case 'B': // specify bind address
544             mExtSettings->mLocalhost = new char[ strlen( optarg ) + 1 ];
545             strcpy( mExtSettings->mLocalhost, optarg );
546             // Test for Multicast
547             iperf_sockaddr temp;
548             SockAddr_setHostname( mExtSettings->mLocalhost, &temp,
549                                   (isIPV6( mExtSettings ) ? 1 : 0 ));
550             if ( SockAddr_isMulticast( &temp ) ) {
551                 setMulticast( mExtSettings );
552             }
553             break;
554
555         case 'C': // Run in Compatibility Mode
556             setCompat( mExtSettings );
557             if ( mExtSettings->mMode != kTest_Normal ) {
558                 fprintf( stderr, warn_invalid_compatibility_option,
559                         ( mExtSettings->mMode == kTest_DualTest ?
560                           'd' : 'r' ) );
561                 mExtSettings->mMode = kTest_Normal;
562             }
563             break;
564
565         case 'D': // Run as a daemon
566             setDaemon( mExtSettings );
567             break;
568
569         case 'F' : // Get the input for the data stream from a file
570             if ( mExtSettings->mThreadMode != kMode_Client ) {
571                 fprintf( stderr, warn_invalid_server_option, option );
572                 break;
573             }
574
575             setFileInput( mExtSettings );
576             mExtSettings->mFileName = new char[strlen(optarg)+1];
577             strcpy( mExtSettings->mFileName, optarg);
578             break;
579
580         case 'I' : // Set the stdin as the input source
581             if ( mExtSettings->mThreadMode != kMode_Client ) {
582                 fprintf( stderr, warn_invalid_server_option, option );
583                 break;
584             }
585
586             setFileInput( mExtSettings );
587             setSTDIN( mExtSettings );
588             mExtSettings->mFileName = new char[strlen("<stdin>")+1];
589             strcpy( mExtSettings->mFileName,"<stdin>");
590             break;
591
592         case 'L': // Listen Port (bidirectional testing client-side)
593             if ( mExtSettings->mThreadMode != kMode_Client ) {
594                 fprintf( stderr, warn_invalid_server_option, option );
595                 break;
596             }
597
598             mExtSettings->mListenPort = atoi( optarg );
599             break;
600
601         case 'M': // specify TCP MSS (maximum segment size)
602             Settings_GetUpperCaseArg(optarg,outarg);
603
604             mExtSettings->mMSS = byte_atoi( outarg );
605             break;
606
607         case 'N': // specify TCP nodelay option (disable Jacobson's Algorithm)
608             setNoDelay( mExtSettings );
609             break;
610
611         case 'P': // number of client threads
612 #ifdef HAVE_THREAD
613             mExtSettings->mThreads = atoi( optarg );
614 #else
615             if ( mExtSettings->mThreadMode != kMode_Server ) {
616                 fprintf( stderr, warn_invalid_single_threaded, option );
617             } else {
618                 mExtSettings->mThreads = atoi( optarg );
619             }
620 #endif
621             break;
622
623         case 'R':
624             setRemoveService( mExtSettings );
625             break;
626
627         case 'S': // IP type-of-service
628             // TODO use a function that understands base-2
629             // the zero base here allows the user to specify
630             // "0x#" hex, "0#" octal, and "#" decimal numbers
631             mExtSettings->mTOS = strtol( optarg, NULL, 0 );
632             break;
633
634         case 'T': // time-to-live for multicast
635             mExtSettings->mTTL = atoi( optarg );
636             break;
637
638         case 'U': // single threaded UDP server
639             setSingleUDP( mExtSettings );
640             break;
641
642         case 'V': // IPv6 Domain
643             setIPV6( mExtSettings );
644             if ( mExtSettings->mThreadMode == kMode_Server 
645                  && mExtSettings->mLocalhost != NULL ) {
646                 // Test for Multicast
647                 iperf_sockaddr temp;
648                 SockAddr_setHostname( mExtSettings->mLocalhost, &temp, 1);
649                 if ( SockAddr_isMulticast( &temp ) ) {
650                     setMulticast( mExtSettings );
651                 }
652             } else if ( mExtSettings->mThreadMode == kMode_Client ) {
653                 // Test for Multicast
654                 iperf_sockaddr temp;
655                 SockAddr_setHostname( mExtSettings->mHost, &temp, 1 );
656                 if ( SockAddr_isMulticast( &temp ) ) {
657                     setMulticast( mExtSettings );
658                 }
659             }
660             break;
661
662         case 'W' :
663             setSuggestWin( mExtSettings );
664             fprintf( stderr, "The -W option is not available in this release\n");
665             break;
666
667         default: // ignore unknown
668             break;
669     }
670 } // end Interpret
671
672 void Settings_GetUpperCaseArg(const char *inarg, char *outarg) {
673
674     int len = strlen(inarg);
675     strcpy(outarg,inarg);
676
677     if ( (len > 0) && (inarg[len-1] >='a') 
678          && (inarg[len-1] <= 'z') )
679         outarg[len-1]= outarg[len-1]+'A'-'a';
680 }
681
682 void Settings_GetLowerCaseArg(const char *inarg, char *outarg) {
683
684     int len = strlen(inarg);
685     strcpy(outarg,inarg);
686
687     if ( (len > 0) && (inarg[len-1] >='A') 
688          && (inarg[len-1] <= 'Z') )
689         outarg[len-1]= outarg[len-1]-'A'+'a';
690 }
691
692 /*
693  * Settings_GenerateListenerSettings
694  * Called to generate the settings to be passed to the Listener
695  * instance that will handle dual testings from the client side
696  * this should only return an instance if it was called on 
697  * the thread_Settings instance generated from the command line 
698  * for client side execution 
699  */
700 void Settings_GenerateListenerSettings( thread_Settings *client, thread_Settings **listener ) {
701     if ( !isCompat( client ) && 
702          (client->mMode == kTest_DualTest || client->mMode == kTest_TradeOff) ) {
703         *listener = new thread_Settings;
704         memcpy(*listener, client, sizeof( thread_Settings ));
705         setCompat( (*listener) );
706         unsetDaemon( (*listener) );
707         if ( client->mListenPort != 0 ) {
708             (*listener)->mPort   = client->mListenPort;
709         } else {
710             (*listener)->mPort   = client->mPort;
711         }
712         (*listener)->mFileName   = NULL;
713         (*listener)->mHost       = NULL;
714         (*listener)->mLocalhost  = NULL;
715         (*listener)->mOutputFileName = NULL;
716         (*listener)->mMode       = kTest_Normal;
717         (*listener)->mThreadMode = kMode_Listener;
718         if ( client->mHost != NULL ) {
719             (*listener)->mHost = new char[strlen( client->mHost ) + 1];
720             strcpy( (*listener)->mHost, client->mHost );
721         }
722         if ( client->mLocalhost != NULL ) {
723             (*listener)->mLocalhost = new char[strlen( client->mLocalhost ) + 1];
724             strcpy( (*listener)->mLocalhost, client->mLocalhost );
725         }
726     } else {
727         *listener = NULL;
728     }
729 }
730
731 /*
732  * Settings_GenerateSpeakerSettings
733  * Called to generate the settings to be passed to the Speaker
734  * instance that will handle dual testings from the server side
735  * this should only return an instance if it was called on 
736  * the thread_Settings instance generated from the command line 
737  * for server side execution. This should be an inverse operation
738  * of GenerateClientHdr. 
739  */
740 void Settings_GenerateClientSettings( thread_Settings *server, 
741                                       thread_Settings **client,
742                                       client_hdr *hdr ) {
743     int flags = ntohl(hdr->flags);
744     if ( (flags & HEADER_VERSION1) != 0 ) {
745         *client = new thread_Settings;
746         memcpy(*client, server, sizeof( thread_Settings ));
747         setCompat( (*client) );
748         (*client)->mTID = thread_zeroid();
749         (*client)->mPort       = (unsigned short) ntohl(hdr->mPort);
750         (*client)->mThreads    = ntohl(hdr->numThreads);
751         if ( hdr->bufferlen != 0 ) {
752             (*client)->mBufLen = ntohl(hdr->bufferlen);
753         }
754         if ( hdr->mWinBand != 0 ) {
755             if ( isUDP( server ) ) {
756                 (*client)->mUDPRate = ntohl(hdr->mWinBand);
757             } else {
758                 (*client)->mTCPWin = ntohl(hdr->mWinBand);
759             }
760         }
761         (*client)->mAmount     = ntohl(hdr->mAmount);
762         if ( ((*client)->mAmount & 0x80000000) > 0 ) {
763             setModeTime( (*client) );
764 #ifndef WIN32
765             (*client)->mAmount |= 0xFFFFFFFF00000000LL;
766 #else
767             (*client)->mAmount |= 0xFFFFFFFF00000000;
768 #endif
769             (*client)->mAmount = -(*client)->mAmount;
770         }
771         (*client)->mFileName   = NULL;
772         (*client)->mHost       = NULL;
773         (*client)->mLocalhost  = NULL;
774         (*client)->mOutputFileName = NULL;
775         (*client)->mMode       = ((flags & RUN_NOW) == 0 ?
776                                    kTest_TradeOff : kTest_DualTest);
777         (*client)->mThreadMode = kMode_Client;
778         if ( server->mLocalhost != NULL ) {
779             (*client)->mLocalhost = new char[strlen( server->mLocalhost ) + 1];
780             strcpy( (*client)->mLocalhost, server->mLocalhost );
781         }
782         (*client)->mHost = new char[REPORT_ADDRLEN];
783         if ( ((sockaddr*)&server->peer)->sa_family == AF_INET ) {
784             inet_ntop( AF_INET, &((sockaddr_in*)&server->peer)->sin_addr, 
785                        (*client)->mHost, REPORT_ADDRLEN);
786         }
787 #ifdef HAVE_IPV6
788           else {
789             inet_ntop( AF_INET6, &((sockaddr_in6*)&server->peer)->sin6_addr, 
790                        (*client)->mHost, REPORT_ADDRLEN);
791         }
792 #endif
793     } else {
794         *client = NULL;
795     }
796 }
797
798 /*
799  * Settings_GenerateClientHdr
800  * Called to generate the client header to be passed to the
801  * server that will handle dual testings from the server side
802  * This should be an inverse operation of GenerateSpeakerSettings
803  */
804 void Settings_GenerateClientHdr( thread_Settings *client, client_hdr *hdr ) {
805     if ( client->mMode != kTest_Normal ) {
806         hdr->flags  = htonl(HEADER_VERSION1);
807     } else {
808         hdr->flags  = 0;
809     }
810     if ( isBuflenSet( client ) ) {
811         hdr->bufferlen = htonl(client->mBufLen);
812     } else {
813         hdr->bufferlen = 0;
814     }
815     if ( isUDP( client ) ) {
816         hdr->mWinBand  = htonl(client->mUDPRate);
817     } else {
818         hdr->mWinBand  = htonl(client->mTCPWin);
819     }
820     if ( client->mListenPort != 0 ) {
821         hdr->mPort  = htonl(client->mListenPort);
822     } else {
823         hdr->mPort  = htonl(client->mPort);
824     }
825     hdr->numThreads = htonl(client->mThreads);
826     if ( isModeTime( client ) ) {
827         hdr->mAmount    = htonl(-(long)client->mAmount);
828     } else {
829         hdr->mAmount    = htonl((long)client->mAmount);
830         hdr->mAmount &= htonl( 0x7FFFFFFF );
831     }
832     if ( client->mMode == kTest_DualTest ) {
833         hdr->flags |= htonl(RUN_NOW);
834     }
835 }