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