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