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