]> sjero.net Git - iperf/blob - src/Settings.cpp
2b71693c70c132b6fd49554908107a00ab069d4c
[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             fprintf( stderr, usage_long );
377             exit(1);
378             break;
379
380         case 'i': // specify interval between periodic bw reports
381             mExtSettings->mInterval = atof( optarg );
382             if ( mExtSettings->mInterval < 0.5 ) {
383                 fprintf (stderr, report_interval_small, mExtSettings->mInterval);
384                 mExtSettings->mInterval = 0.5;
385             }
386             break;
387
388         case 'l': // length of each buffer
389             Settings_GetUpperCaseArg(optarg,outarg);
390             mExtSettings->mBufLen = byte_atoi( outarg );
391             setBuflenSet( mExtSettings );
392             if ( !isUDP( mExtSettings ) ) {
393                  if ( mExtSettings->mBufLen < (int) sizeof( client_hdr ) &&
394                       !isCompat( mExtSettings ) ) {
395                     setCompat( mExtSettings );
396                     fprintf( stderr, warn_implied_compatibility, option );
397                  }
398             } else {
399                 if ( mExtSettings->mBufLen < (int) sizeof( UDP_datagram ) ) {
400                     mExtSettings->mBufLen = sizeof( UDP_datagram );
401                     fprintf( stderr, warn_buffer_too_small, mExtSettings->mBufLen );
402                 }
403                 if ( !isCompat( mExtSettings ) &&
404                             mExtSettings->mBufLen < (int) ( sizeof( UDP_datagram )
405                             + sizeof( client_hdr ) ) ) {
406                     setCompat( mExtSettings );
407                     fprintf( stderr, warn_implied_compatibility, option );
408                 }
409             }
410
411             break;
412
413         case 'm': // print TCP MSS
414             setPrintMSS( mExtSettings );
415             break;
416
417         case 'n': // bytes of data
418             // amount mode (instead of time mode)
419             unsetModeTime( mExtSettings );
420             Settings_GetUpperCaseArg(optarg,outarg);
421             mExtSettings->mAmount = byte_atoi( outarg );
422             break;
423
424         case 'o' : // output the report and other messages into the file
425             unsetSTDOUT( mExtSettings );
426             mExtSettings->mOutputFileName = new char[strlen(optarg)+1];
427             strcpy( mExtSettings->mOutputFileName, optarg);
428             break;
429
430         case 'p': // server port
431             mExtSettings->mPort = atoi( optarg );
432             break;
433
434         case 'r': // test mode tradeoff
435             if ( mExtSettings->mThreadMode != kMode_Client ) {
436                 fprintf( stderr, warn_invalid_server_option, option );
437                 break;
438             }
439             if ( isCompat( mExtSettings ) ) {
440                 fprintf( stderr, warn_invalid_compatibility_option, option );
441             }
442
443             mExtSettings->mMode = kTest_TradeOff;
444             break;
445
446         case 's': // server mode
447             if ( mExtSettings->mThreadMode != kMode_Unknown ) {
448                 fprintf( stderr, warn_invalid_client_option, option );
449                 break;
450             }
451
452             mExtSettings->mThreadMode = kMode_Listener;
453             break;
454
455         case 't': // seconds to write for
456             // time mode (instead of amount mode)
457             setModeTime( mExtSettings );
458             mExtSettings->mAmount = (int) (atof( optarg ) * 100.0);
459             break;
460
461         case 'u': // UDP instead of TCP
462             // if -b has already been processed, UDP rate will
463             // already be non-zero, so don't overwrite that value
464             if ( !isUDP( mExtSettings ) ) {
465                 setUDP( mExtSettings );
466                 mExtSettings->mUDPRate = kDefault_UDPRate;
467             }
468
469             // if -l has already been processed, mBufLenSet is true
470             // so don't overwrite that value.
471             if ( !isBuflenSet( mExtSettings ) ) {
472                 mExtSettings->mBufLen = kDefault_UDPBufLen;
473             } else if ( mExtSettings->mBufLen < (int) ( sizeof( UDP_datagram ) 
474                         + sizeof( client_hdr ) ) &&
475                         !isCompat( mExtSettings ) ) {
476                 setCompat( mExtSettings );
477                 fprintf( stderr, warn_implied_compatibility, option );
478             }
479             break;
480
481         case 'v': // print version and exit
482             fprintf( stderr, version );
483             exit(1);
484             break;
485
486         case 'w': // TCP window size (socket buffer size)
487             Settings_GetUpperCaseArg(optarg,outarg);
488             mExtSettings->mTCPWin = byte_atoi(outarg);
489
490             if ( mExtSettings->mTCPWin < 2048 ) {
491                 fprintf( stderr, warn_window_small, mExtSettings->mTCPWin );
492             }
493             break;
494
495         case 'x': // Limit Reports
496             while ( *optarg != '\0' ) {
497                 switch ( *optarg ) {
498                     case 's':
499                     case 'S':
500                         setNoSettReport( mExtSettings );
501                         break;
502                     case 'c':
503                     case 'C':
504                         setNoConnReport( mExtSettings );
505                         break;
506                     case 'd':
507                     case 'D':
508                         setNoDataReport( mExtSettings );
509                         break;
510                     case 'v':
511                     case 'V':
512                         setNoServReport( mExtSettings );
513                         break;
514                     case 'm':
515                     case 'M':
516                         setNoMultReport( mExtSettings );
517                         break;
518                     default:
519                         fprintf(stderr, warn_invalid_report, *optarg);
520                 }
521                 optarg++;
522             }
523             break;
524
525         case 'y': // Reporting Style
526             switch ( *optarg ) {
527                 case 'c':
528                 case 'C':
529                     mExtSettings->mReportMode = kReport_CSV;
530                     break;
531                 default:
532                     fprintf( stderr, warn_invalid_report_style, optarg );
533             }
534             break;
535
536
537             // more esoteric options
538         case 'B': // specify bind address
539             mExtSettings->mLocalhost = new char[ strlen( optarg ) + 1 ];
540             strcpy( mExtSettings->mLocalhost, optarg );
541             // Test for Multicast
542             iperf_sockaddr temp;
543             SockAddr_setHostname( mExtSettings->mLocalhost, &temp,
544                                   (isIPV6( mExtSettings ) ? 1 : 0 ));
545             if ( SockAddr_isMulticast( &temp ) ) {
546                 setMulticast( mExtSettings );
547             }
548             break;
549
550         case 'C': // Run in Compatibility Mode
551             setCompat( mExtSettings );
552             if ( mExtSettings->mMode != kTest_Normal ) {
553                 fprintf( stderr, warn_invalid_compatibility_option,
554                         ( mExtSettings->mMode == kTest_DualTest ?
555                           'd' : 'r' ) );
556                 mExtSettings->mMode = kTest_Normal;
557             }
558             break;
559
560         case 'D': // Run as a daemon
561             setDaemon( mExtSettings );
562             break;
563
564         case 'F' : // Get the input for the data stream from a file
565             if ( mExtSettings->mThreadMode != kMode_Client ) {
566                 fprintf( stderr, warn_invalid_server_option, option );
567                 break;
568             }
569
570             setFileInput( mExtSettings );
571             mExtSettings->mFileName = new char[strlen(optarg)+1];
572             strcpy( mExtSettings->mFileName, optarg);
573             break;
574
575         case 'I' : // Set the stdin as the input source
576             if ( mExtSettings->mThreadMode != kMode_Client ) {
577                 fprintf( stderr, warn_invalid_server_option, option );
578                 break;
579             }
580
581             setFileInput( mExtSettings );
582             setSTDIN( mExtSettings );
583             mExtSettings->mFileName = new char[strlen("<stdin>")+1];
584             strcpy( mExtSettings->mFileName,"<stdin>");
585             break;
586
587         case 'L': // Listen Port (bidirectional testing client-side)
588             if ( mExtSettings->mThreadMode != kMode_Client ) {
589                 fprintf( stderr, warn_invalid_server_option, option );
590                 break;
591             }
592
593             mExtSettings->mListenPort = atoi( optarg );
594             break;
595
596         case 'M': // specify TCP MSS (maximum segment size)
597             Settings_GetUpperCaseArg(optarg,outarg);
598
599             mExtSettings->mMSS = byte_atoi( outarg );
600             break;
601
602         case 'N': // specify TCP nodelay option (disable Jacobson's Algorithm)
603             setNoDelay( mExtSettings );
604             break;
605
606         case 'P': // number of client threads
607 #ifdef HAVE_THREAD
608             mExtSettings->mThreads = atoi( optarg );
609 #else
610             if ( mExtSettings->mThreadMode != kMode_Server ) {
611                 fprintf( stderr, warn_invalid_single_threaded, option );
612             } else {
613                 mExtSettings->mThreads = atoi( optarg );
614             }
615 #endif
616             break;
617
618         case 'R':
619             setRemoveService( mExtSettings );
620             break;
621
622         case 'S': // IP type-of-service
623             // TODO use a function that understands base-2
624             // the zero base here allows the user to specify
625             // "0x#" hex, "0#" octal, and "#" decimal numbers
626             mExtSettings->mTOS = strtol( optarg, NULL, 0 );
627             break;
628
629         case 'T': // time-to-live for multicast
630             mExtSettings->mTTL = atoi( optarg );
631             break;
632
633         case 'U': // single threaded UDP server
634             setSingleUDP( mExtSettings );
635             break;
636
637         case 'V': // IPv6 Domain
638             setIPV6( mExtSettings );
639             if ( mExtSettings->mThreadMode == kMode_Server 
640                  && mExtSettings->mLocalhost != NULL ) {
641                 // Test for Multicast
642                 iperf_sockaddr temp;
643                 SockAddr_setHostname( mExtSettings->mLocalhost, &temp, 1);
644                 if ( SockAddr_isMulticast( &temp ) ) {
645                     setMulticast( mExtSettings );
646                 }
647             } else if ( mExtSettings->mThreadMode == kMode_Client ) {
648                 // Test for Multicast
649                 iperf_sockaddr temp;
650                 SockAddr_setHostname( mExtSettings->mHost, &temp, 1 );
651                 if ( SockAddr_isMulticast( &temp ) ) {
652                     setMulticast( mExtSettings );
653                 }
654             }
655             break;
656
657         case 'W' :
658             setSuggestWin( mExtSettings );
659             fprintf( stderr, "The -W option is not available in this release\n");
660             break;
661
662         default: // ignore unknown
663             break;
664     }
665 } // end Interpret
666
667 void Settings_GetUpperCaseArg(const char *inarg, char *outarg) {
668
669     int len = strlen(inarg);
670     strcpy(outarg,inarg);
671
672     if ( (len > 0) && (inarg[len-1] >='a') 
673          && (inarg[len-1] <= 'z') )
674         outarg[len-1]= outarg[len-1]+'A'-'a';
675 }
676
677 void Settings_GetLowerCaseArg(const char *inarg, char *outarg) {
678
679     int len = strlen(inarg);
680     strcpy(outarg,inarg);
681
682     if ( (len > 0) && (inarg[len-1] >='A') 
683          && (inarg[len-1] <= 'Z') )
684         outarg[len-1]= outarg[len-1]-'A'+'a';
685 }
686
687 /*
688  * Settings_GenerateListenerSettings
689  * Called to generate the settings to be passed to the Listener
690  * instance that will handle dual testings from the client side
691  * this should only return an instance if it was called on 
692  * the thread_Settings instance generated from the command line 
693  * for client side execution 
694  */
695 void Settings_GenerateListenerSettings( thread_Settings *client, thread_Settings **listener ) {
696     if ( !isCompat( client ) && 
697          (client->mMode == kTest_DualTest || client->mMode == kTest_TradeOff) ) {
698         *listener = new thread_Settings;
699         memcpy(*listener, client, sizeof( thread_Settings ));
700         setCompat( (*listener) );
701         unsetDaemon( (*listener) );
702         if ( client->mListenPort != 0 ) {
703             (*listener)->mPort   = client->mListenPort;
704         } else {
705             (*listener)->mPort   = client->mPort;
706         }
707         (*listener)->mFileName   = NULL;
708         (*listener)->mHost       = NULL;
709         (*listener)->mLocalhost  = NULL;
710         (*listener)->mOutputFileName = NULL;
711         (*listener)->mMode       = kTest_Normal;
712         (*listener)->mThreadMode = kMode_Listener;
713         if ( client->mHost != NULL ) {
714             (*listener)->mHost = new char[strlen( client->mHost ) + 1];
715             strcpy( (*listener)->mHost, client->mHost );
716         }
717         if ( client->mLocalhost != NULL ) {
718             (*listener)->mLocalhost = new char[strlen( client->mLocalhost ) + 1];
719             strcpy( (*listener)->mLocalhost, client->mLocalhost );
720         }
721     } else {
722         *listener = NULL;
723     }
724 }
725
726 /*
727  * Settings_GenerateSpeakerSettings
728  * Called to generate the settings to be passed to the Speaker
729  * instance that will handle dual testings from the server side
730  * this should only return an instance if it was called on 
731  * the thread_Settings instance generated from the command line 
732  * for server side execution. This should be an inverse operation
733  * of GenerateClientHdr. 
734  */
735 void Settings_GenerateClientSettings( thread_Settings *server, 
736                                       thread_Settings **client,
737                                       client_hdr *hdr ) {
738     int flags = ntohl(hdr->flags);
739     if ( (flags & HEADER_VERSION1) != 0 ) {
740         *client = new thread_Settings;
741         memcpy(*client, server, sizeof( thread_Settings ));
742         setCompat( (*client) );
743         (*client)->mTID = thread_zeroid();
744         (*client)->mPort       = (unsigned short) ntohl(hdr->mPort);
745         (*client)->mThreads    = ntohl(hdr->numThreads);
746         if ( hdr->bufferlen != 0 ) {
747             (*client)->mBufLen = ntohl(hdr->bufferlen);
748         }
749         if ( hdr->mWinBand != 0 ) {
750             if ( isUDP( server ) ) {
751                 (*client)->mUDPRate = ntohl(hdr->mWinBand);
752             } else {
753                 (*client)->mTCPWin = ntohl(hdr->mWinBand);
754             }
755         }
756         (*client)->mAmount     = ntohl(hdr->mAmount);
757         if ( ((*client)->mAmount & 0x80000000) > 0 ) {
758             setModeTime( (*client) );
759             (*client)->mAmount |= 0xFFFFFFFF00000000LL;
760             (*client)->mAmount = -(*client)->mAmount;
761         }
762         (*client)->mFileName   = NULL;
763         (*client)->mHost       = NULL;
764         (*client)->mLocalhost  = NULL;
765         (*client)->mOutputFileName = NULL;
766         (*client)->mMode       = ((flags & RUN_NOW) == 0 ?
767                                    kTest_TradeOff : kTest_DualTest);
768         (*client)->mThreadMode = kMode_Client;
769         if ( server->mLocalhost != NULL ) {
770             (*client)->mLocalhost = new char[strlen( server->mLocalhost ) + 1];
771             strcpy( (*client)->mLocalhost, server->mLocalhost );
772         }
773         (*client)->mHost = new char[REPORT_ADDRLEN];
774         if ( ((sockaddr*)&server->peer)->sa_family == AF_INET ) {
775             inet_ntop( AF_INET, &((sockaddr_in*)&server->peer)->sin_addr, 
776                        (*client)->mHost, REPORT_ADDRLEN);
777         }
778 #ifdef HAVE_IPV6
779           else {
780             inet_ntop( AF_INET6, &((sockaddr_in6*)&server->peer)->sin6_addr, 
781                        (*client)->mHost, REPORT_ADDRLEN);
782         }
783 #endif
784     } else {
785         *client = NULL;
786     }
787 }
788
789 /*
790  * Settings_GenerateClientHdr
791  * Called to generate the client header to be passed to the
792  * server that will handle dual testings from the server side
793  * This should be an inverse operation of GenerateSpeakerSettings
794  */
795 void Settings_GenerateClientHdr( thread_Settings *client, client_hdr *hdr ) {
796     if ( client->mMode != kTest_Normal ) {
797         hdr->flags  = htonl(HEADER_VERSION1);
798     } else {
799         hdr->flags  = 0;
800     }
801     if ( isBuflenSet( client ) ) {
802         hdr->bufferlen = htonl(client->mBufLen);
803     } else {
804         hdr->bufferlen = 0;
805     }
806     if ( isUDP( client ) ) {
807         hdr->mWinBand  = htonl(client->mUDPRate);
808     } else {
809         hdr->mWinBand  = htonl(client->mTCPWin);
810     }
811     if ( client->mListenPort != 0 ) {
812         hdr->mPort  = htonl(client->mListenPort);
813     } else {
814         hdr->mPort  = htonl(client->mPort);
815     }
816     hdr->numThreads = htonl(client->mThreads);
817     if ( isModeTime( client ) ) {
818         hdr->mAmount    = htonl(-(long)client->mAmount);
819     } else {
820         hdr->mAmount    = htonl((long)client->mAmount);
821         hdr->mAmount &= htonl( 0x7FFFFFFF );
822     }
823     if ( client->mMode == kTest_DualTest ) {
824         hdr->flags |= htonl(RUN_NOW);
825     }
826 }