diff --git a/ethr.go b/ethr.go index 79d4279..78726cf 100644 --- a/ethr.go +++ b/ethr.go @@ -8,193 +8,17 @@ package main import ( "flag" "fmt" - "os" "runtime" "strings" "time" + + "github.com/microsoft/ethr/internal/cmd" ) const defaultLogFileName = "./ethrs.log for server, ./ethrc.log for client" var gVersion string -func printFlagUsage(flag, info string, helptext ...string) { - fmt.Printf("\t-%s %s\n", flag, info) - for _, help := range helptext { - fmt.Printf("\t\t%s\n", help) - } -} - -func printServerUsage() { - printFlagUsage("s", "", "Run in server mode.") -} - -func printClientUsage() { - printFlagUsage("c", "", "Run in client mode and connect to .", - "Server is specified using name, FQDN or IP address.") -} - -func printExtClientUsage() { - printFlagUsage("c", "", "Run in external client mode and connect to .", - " is specified using host:port format.", - "Example: www.microsoft.com:443 or 10.1.0.4:22 etc.") -} - -func printPortUsage() { - printFlagUsage("ports", "", "Use custom port numbers instead of default ones.", - "A comma separated list of key=value pair is used.", - "Key specifies the protocol, and value specifies base port.", - "Ports used for various tests are calculated from base port.", - "Example: For TCP, Bw: 9999, CPS: 9998, PPS: 9997, Latency: 9996", - "Control is used for control channel communication for ethr.", - "Note: Same configuration must be used on both client & server.", - "Default: 'control=8888,tcp=9999,udp=9999,http=9899,https=9799'") -} - -func printExtPortUsage() { - printFlagUsage("ports", "", "Use custom port numbers instead of default ones.", - "A comma separated list of key=value pair is used.", - "Key specifies the protocol, and value specifies the port.", - "Default: 'tcp=9999,http=9899,https=9799'") -} - -func printTestType() { - printFlagUsage("t", "", "Test to run (\"b\", \"c\", \"p\", or \"l\")", - "b: Bandwidth", - "c: Connections/s or Requests/s", - "p: Packets/s", - "l: Latency, Loss & Jitter", - "Default: b - Bandwidth measurement.") -} - -func printExtTestType() { - printFlagUsage("t", "", "Test to run (\"b\", \"c\", or \"cl\")", - "b: Bandwidth", - "c: Connections/s or Requests/s", - "cl: TCP connection setup latency", - "Default: cl - TCP connection setup latency.") -} - -func printThreadUsage() { - printFlagUsage("n", "", "Number of Parallel Sessions (and Threads).", - "0: Equal to number of CPUs", - "Default: 1") -} - -func printDurationUsage() { - printFlagUsage("d", "", - "Duration for the test (format: [ms | s | m | h]", - "0: Run forever", - "Default: 10s") -} - -func printGapUsage() { - printFlagUsage("g", "", - "Time interval between successive measurements (format: [ms | s | m | h]", - "0: No gap", - "Default: 1s") -} - -func printBufLenUsage() { - printFlagUsage("l", "", - "Length of buffer to use (format: [KB | MB | GB])", - "Only valid for Bandwidth tests. Max 1GB.", - "Default: 16KB") -} - -func printProtocolUsage() { - printFlagUsage("p", "", - "Protocol (\"tcp\", \"udp\", \"http\", \"https\", or \"icmp\")", - "Default: tcp") -} - -func printExtProtocolUsage() { - printFlagUsage("p", "", - "Protocol (\"tcp\", \"http\", \"https\", or \"icmp\")", - "Default: tcp") -} - -func printIterationUsage() { - printFlagUsage("i", "", - "Number of round trip iterations for each latency measurement.", - "Default: 1000") -} - -func printModeUsage() { - printFlagUsage("m", "", - "'-m x' MUST be specified for external mode.") -} - -func printNoConnStatUsage() { - printFlagUsage("ncs", "", - "No per Connection Stats would be printed if this flag is specified.", - "This is useful to suppress verbose logging when large number of", - "connections are used as specified by -n option for Bandwidth tests.") -} - -func printIgnoreCertUsage() { - printFlagUsage("ic", "", - "Ignore Certificate is useful for HTTPS tests, for cases where a", - "middle box like a proxy is not able to supply a valid Ethr cert.") -} - -func ethrUsage() { - fmt.Println("\nEthr - A comprehensive network performance measurement tool.") - fmt.Println("Version: " + gVersion) - fmt.Println("It supports 4 modes. Usage of each mode is described below:") - - fmt.Println("\nCommon Parameters") - fmt.Println("================================================================================") - printFlagUsage("h", "", "Help") - printFlagUsage("no", "", "Disable logging to file. Logging to file is enabled by default.") - printFlagUsage("o", "", "Name of log file. By default, following file names are used:", - "Server mode: 'ethrs.log'", - "Client mode: 'ethrc.log'", - "External server mode: 'ethrxs.log'", - "External client mode: 'ethrxc.log'") - printFlagUsage("debug", "", "Enable debug information in logging output.") - printFlagUsage("4", "", "Use only IP v4 version") - printFlagUsage("6", "", "Use only IP v6 version") - - fmt.Println("\nMode: Server") - fmt.Println("================================================================================") - printServerUsage() - printFlagUsage("ui", "", "Show output in text UI.") - printPortUsage() - - fmt.Println("\nMode: Client") - fmt.Println("================================================================================") - printClientUsage() - printFlagUsage("r", "", "For Bandwidth tests, send data from server to client.") - printDurationUsage() - printThreadUsage() - printNoConnStatUsage() - printBufLenUsage() - printProtocolUsage() - printIgnoreCertUsage() - printPortUsage() - printTestType() - printIterationUsage() - - fmt.Println("\nMode: External Server") - fmt.Println("================================================================================") - printModeUsage() - printServerUsage() - printExtPortUsage() - - fmt.Println("\nMode: External Client") - fmt.Println("================================================================================") - printModeUsage() - printExtClientUsage() - printDurationUsage() - printThreadUsage() - printNoConnStatUsage() - printBufLenUsage() - printExtProtocolUsage() - printExtTestType() - printGapUsage() -} - func main() { // // If version is not set via ldflags, then default to UNKNOWN @@ -211,7 +35,7 @@ func main() { // runtime.GOMAXPROCS(1024) - flag.Usage = ethrUsage + flag.Usage = func() { cmd.EthrUsage(gVersion) } isServer := flag.Bool("s", false, "") clientDest := flag.String("c", "", "") testTypePtr := flag.String("t", "", "") @@ -257,13 +81,13 @@ func main() { case "x": xMode = true default: - printUsageError("Invalid value for execution mode (-m).") + cmd.PrintUsageError("Invalid value for execution mode (-m).") } mode := ethrModeInv if *isServer { if *clientDest != "" { - printUsageError("Invalid arguments, \"-c\" cannot be used with \"-s\".") + cmd.PrintUsageError("Invalid arguments, \"-c\" cannot be used with \"-s\".") } if xMode { mode = ethrModeExtServer @@ -277,11 +101,11 @@ func main() { mode = ethrModeClient } } else { - printUsageError("Invalid arguments, use either \"-s\" or \"-c\".") + cmd.PrintUsageError("Invalid arguments, use either \"-s\" or \"-c\".") } if *reverse && mode != ethrModeClient { - printUsageError("Invalid arguments, \"-r\" can only be used in client mode.") + cmd.PrintUsageError("Invalid arguments, \"-r\" can only be used in client mode.") } if *use4 && !*use6 { @@ -292,11 +116,11 @@ func main() { bufLen := unitToNumber(*bufLenStr) if bufLen == 0 { - printUsageError(fmt.Sprintf("Invalid length specified: %s" + *bufLenStr)) + cmd.PrintUsageError(fmt.Sprintf("Invalid length specified: %s" + *bufLenStr)) } if *rttCount <= 0 { - printUsageError(fmt.Sprintf("Invalid RTT count for latency test: %d", *rttCount)) + cmd.PrintUsageError(fmt.Sprintf("Invalid RTT count for latency test: %d", *rttCount)) } var testType EthrTestType @@ -323,7 +147,7 @@ func main() { case "cl": testType = ConnLatency default: - printUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-t\".\n"+ + cmd.PrintUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-t\".\n"+ "Valid parameters and values are:\n", *testTypePtr)) } @@ -341,7 +165,7 @@ func main() { case "ICMP": proto = ICMP default: - printUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-p\".\n"+ + cmd.PrintUsageError(fmt.Sprintf("Invalid value \"%s\" specified for parameter \"-p\".\n"+ "Valid parameters and values are:\n", *protocol)) } @@ -400,12 +224,12 @@ func main() { } func emitUnsupportedTest(testParam EthrTestParam) { - printUsageError(fmt.Sprintf("\"%s\" test for \"%s\" is not supported.\n", + cmd.PrintUsageError(fmt.Sprintf("\"%s\" test for \"%s\" is not supported.\n", testToString(testParam.TestID.Type), protoToString(testParam.TestID.Protocol))) } func printReverseModeError() { - printUsageError("Reverse mode (-r) is only supported for TCP Bandwidth tests.") + cmd.PrintUsageError("Reverse mode (-r) is only supported for TCP Bandwidth tests.") } func validateTestParam(mode ethrMode, testParam EthrTestParam) { @@ -430,7 +254,7 @@ func validateTestParam(mode ethrMode, testParam EthrTestParam) { } if testType == Bandwidth { if testParam.BufferSize > (64 * 1024) { - printUsageError("Maximum supported buffer size for UDP is 64K\n") + cmd.PrintUsageError("Maximum supported buffer size for UDP is 64K\n") } } if testParam.Reverse { @@ -459,9 +283,3 @@ func validateTestParam(mode ethrMode, testParam EthrTestParam) { } } } - -func printUsageError(s string) { - fmt.Printf("Error: %s\n", s) - fmt.Printf("Please use \"ethr -h\" for ethr command line arguments.\n") - os.Exit(1) -} diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 0000000..279620c --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,61 @@ +package cmd + +import "fmt" + +// EthrUsage prints the command-line usage text +func EthrUsage(gVersion string) { + fmt.Println("\nEthr - A comprehensive network performance measurement tool.") + fmt.Println("Version: " + gVersion) + fmt.Println("It supports 4 modes. Usage of each mode is described below:") + + fmt.Println("\nCommon Parameters") + fmt.Println("================================================================================") + PrintFlagUsage("h", "", "Help") + PrintFlagUsage("no", "", "Disable logging to file. Logging to file is enabled by default.") + PrintFlagUsage("o", "", "Name of log file. By default, following file names are used:", + "Server mode: 'ethrs.log'", + "Client mode: 'ethrc.log'", + "External server mode: 'ethrxs.log'", + "External client mode: 'ethrxc.log'") + PrintFlagUsage("debug", "", "Enable debug information in logging output.") + PrintFlagUsage("4", "", "Use only IP v4 version") + PrintFlagUsage("6", "", "Use only IP v6 version") + + fmt.Println("\nMode: Server") + fmt.Println("================================================================================") + PrintServerUsage() + PrintFlagUsage("ui", "", "Show output in text UI.") + PrintPortUsage() + + fmt.Println("\nMode: Client") + fmt.Println("================================================================================") + PrintClientUsage() + PrintFlagUsage("r", "", "For Bandwidth tests, send data from server to client.") + PrintDurationUsage() + PrintThreadUsage() + PrintNoConnStatUsage() + PrintBufLenUsage() + PrintProtocolUsage() + PrintIgnoreCertUsage() + PrintPortUsage() + PrintTestType() + PrintIterationUsage() + + fmt.Println("\nMode: External Server") + fmt.Println("================================================================================") + PrintModeUsage() + PrintServerUsage() + PrintExtPortUsage() + + fmt.Println("\nMode: External Client") + fmt.Println("================================================================================") + PrintModeUsage() + PrintExtClientUsage() + PrintDurationUsage() + PrintThreadUsage() + PrintNoConnStatUsage() + PrintBufLenUsage() + PrintExtProtocolUsage() + PrintExtTestType() + PrintGapUsage() +} diff --git a/internal/cmd/usage_helpers.go b/internal/cmd/usage_helpers.go new file mode 100644 index 0000000..bdb9431 --- /dev/null +++ b/internal/cmd/usage_helpers.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "fmt" + "os" +) + +func PrintFlagUsage(flag, info string, helptext ...string) { + fmt.Printf("\t-%s %s\n", flag, info) + for _, help := range helptext { + fmt.Printf("\t\t%s\n", help) + } +} + +func PrintServerUsage() { + PrintFlagUsage("s", "", "Run in server mode.") +} + +func PrintClientUsage() { + PrintFlagUsage("c", "", "Run in client mode and connect to .", + "Server is specified using name, FQDN or IP address.") +} + +func PrintExtClientUsage() { + PrintFlagUsage("c", "", "Run in external client mode and connect to .", + " is specified using host:port format.", + "Example: www.microsoft.com:443 or 10.1.0.4:22 etc.") +} + +func PrintPortUsage() { + PrintFlagUsage("ports", "", "Use custom port numbers instead of default ones.", + "A comma separated list of key=value pair is used.", + "Key specifies the protocol, and value specifies base port.", + "Ports used for various tests are calculated from base port.", + "Example: For TCP, Bw: 9999, CPS: 9998, PPS: 9997, Latency: 9996", + "Control is used for control channel communication for ethr.", + "Note: Same configuration must be used on both client & server.", + "Default: 'control=8888,tcp=9999,udp=9999,http=9899,https=9799'") +} + +func PrintExtPortUsage() { + PrintFlagUsage("ports", "", "Use custom port numbers instead of default ones.", + "A comma separated list of key=value pair is used.", + "Key specifies the protocol, and value specifies the port.", + "Default: 'tcp=9999,http=9899,https=9799'") +} + +func PrintTestType() { + PrintFlagUsage("t", "", "Test to run (\"b\", \"c\", \"p\", or \"l\")", + "b: Bandwidth", + "c: Connections/s or Requests/s", + "p: Packets/s", + "l: Latency, Loss & Jitter", + "Default: b - Bandwidth measurement.") +} + +func PrintExtTestType() { + PrintFlagUsage("t", "", "Test to run (\"b\", \"c\", or \"cl\")", + "b: Bandwidth", + "c: Connections/s or Requests/s", + "cl: TCP connection setup latency", + "Default: cl - TCP connection setup latency.") +} + +func PrintThreadUsage() { + PrintFlagUsage("n", "", "Number of Parallel Sessions (and Threads).", + "0: Equal to number of CPUs", + "Default: 1") +} + +func PrintDurationUsage() { + PrintFlagUsage("d", "", + "Duration for the test (format: [ms | s | m | h]", + "0: Run forever", + "Default: 10s") +} + +func PrintGapUsage() { + PrintFlagUsage("g", "", + "Time interval between successive measurements (format: [ms | s | m | h]", + "0: No gap", + "Default: 1s") +} + +func PrintBufLenUsage() { + PrintFlagUsage("l", "", + "Length of buffer to use (format: [KB | MB | GB])", + "Only valid for Bandwidth tests. Max 1GB.", + "Default: 16KB") +} + +func PrintProtocolUsage() { + PrintFlagUsage("p", "", + "Protocol (\"tcp\", \"udp\", \"http\", \"https\", or \"icmp\")", + "Default: tcp") +} + +func PrintExtProtocolUsage() { + PrintFlagUsage("p", "", + "Protocol (\"tcp\", \"http\", \"https\", or \"icmp\")", + "Default: tcp") +} + +func PrintIterationUsage() { + PrintFlagUsage("i", "", + "Number of round trip iterations for each latency measurement.", + "Default: 1000") +} + +func PrintModeUsage() { + PrintFlagUsage("m", "", + "'-m x' MUST be specified for external mode.") +} + +func PrintNoConnStatUsage() { + PrintFlagUsage("ncs", "", + "No per Connection Stats would be printed if this flag is specified.", + "This is useful to suppress verbose logging when large number of", + "connections are used as specified by -n option for Bandwidth tests.") +} + +func PrintIgnoreCertUsage() { + PrintFlagUsage("ic", "", + "Ignore Certificate is useful for HTTPS tests, for cases where a", + "middle box like a proxy is not able to supply a valid Ethr cert.") +} + +func PrintUsageError(s string) { + fmt.Printf("Error: %s\n", s) + fmt.Printf("Please use \"ethr -h\" for ethr command line arguments.\n") + os.Exit(1) +}