Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update process user input #149

Merged
178 changes: 101 additions & 77 deletions tcping.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,124 +215,148 @@ func usage() {
os.Exit(1)
}

// processUserInput gets and validate user input
func processUserInput(tcpStats *stats) {
useIPv4 := flag.Bool("4", false, "only use IPv4.")
useIPv6 := flag.Bool("6", false, "only use IPv6.")
retryHostnameResolveAfter := flag.Uint("r", 0, "retry resolving target's hostname after <n> number of failed probes. e.g. -r 10 to retry after 10 failed probes.")
probesBeforeQuit := flag.Uint("c", 0, "stop after <n> probes, regardless of the result. By default, no limit will be applied.")
outputJSON := flag.Bool("j", false, "output in JSON format.")
prettyJSON := flag.Bool("pretty", false, "use indentation when using json output format. No effect without the '-j' flag.")
showVersion := flag.Bool("v", false, "show version.")
shouldCheckUpdates := flag.Bool("u", false, "check for updates.")
secondsBetweenProbes := flag.Float64("i", 1, "interval between sending probes. Real number allowed with dot as a decimal separator. The default is one second")
timeout := flag.Float64("t", 1, "time to wait for a response, in seconds. Real number allowed. 0 means infinite timeout.")
outputDb := flag.String("db", "", "path and file name to store tcping output to sqlite database.")
interfaceName := flag.String("I", "", "interface name or address")

flag.CommandLine.Usage = usage

permuteArgs(os.Args[1:])
flag.Parse()

// validation for flag and args
args := flag.Args()
nFlag := flag.NFlag()

// we need to set printers first, because they're used for
// errors reporting and other output.
if *outputJSON {
tcpStats.printer = newJSONPrinter(*prettyJSON)
func checkSetPrinters(tcpstats *stats, outputtoJSON, prettyJSON *bool, outputDb *string, args []string) {
// check if prettyjson an outputtojson are true, if so printError and exit
if *prettyJSON && !*outputtoJSON {
colorRed("--pretty has no effect without the -j flag.")
usage()
}
if *outputtoJSON {
tcpstats.printer = newJSONPrinter(*prettyJSON)
} else if *outputDb != "" {
tcpStats.printer = newDb(args, *outputDb)
tcpstats.printer = newDb(args, *outputDb)
} else {
tcpStats.printer = &planePrinter{}
tcpstats.printer = &planePrinter{}
}
}

func checkUpdateVersion(update, version *bool, args []string, nflags int, tcpstats *stats) {
// -u works on its own
if *shouldCheckUpdates {
if len(args) == 0 && nFlag == 1 {
checkLatestVersion(tcpStats.printer)
if *update {
if len(args) == 0 && nflags == 1 {
checkLatestVersion(tcpstats.printer)
} else {
usage()
}
}

if *showVersion {
tcpStats.printer.printVersion()
if *version {
tcpstats.printer.printVersion()
os.Exit(0)
}
}

// host and port must be specified
if len(args) != 2 {
usage()
}

if *prettyJSON && !*outputJSON {
tcpStats.printer.printError("--pretty has no effect without the -j flag.")
usage()
}

if *useIPv4 && *useIPv6 {
tcpStats.printer.printError("Only one IP version can be specified")
func checkSetIPFlags(tcpstats *stats, ip4, ip6 *bool) {
// check if ip4 or ip6 are true, if so printError and exit
if *ip4 && *ip6 {
tcpstats.printer.printError("Only one IP version can be specified")
usage()
}
if *ip4 {
tcpstats.userInput.useIPv4 = true
}
if *ip6 {
tcpstats.userInput.useIPv6 = true
}

if *retryHostnameResolveAfter > 0 {
tcpStats.userInput.retryHostnameLookupAfter = *retryHostnameResolveAfter
}

if *useIPv4 {
tcpStats.userInput.useIPv4 = true
}

if *useIPv6 {
tcpStats.userInput.useIPv6 = true
}
}

func checkPort(tcpstats *stats, args []string) {
// the non-flag command-line arguments
port, err := strconv.ParseUint(args[1], 10, 16)
if err != nil {
tcpStats.printer.printError("Invalid port number: %s", args[1])
tcpstats.printer.printError("Invalid port number: %s", args[1])
os.Exit(1)
}

if port < 1 || port > 65535 {
tcpStats.printer.printError("Port should be in 1..65535 range")
tcpstats.printer.printError("Port should be in 1..65535 range")
os.Exit(1)
}
tcpstats.userInput.port = uint16(port)

tcpStats.userInput.hostname = args[0]
tcpStats.userInput.port = uint16(port)
tcpStats.userInput.ip = resolveHostname(tcpStats)
tcpStats.startTime = time.Now()
tcpStats.userInput.probesBeforeQuit = *probesBeforeQuit
tcpStats.userInput.timeout = secondsToDuration(*timeout)
}

func setGenericArgs(tcpstats *stats, args []string, retryResolve, probesbfrquit *uint, timeout, secbtwprobes *float64, intName *string) {
if *retryResolve > 0 {
tcpstats.userInput.retryHostnameLookupAfter = *retryResolve
}

tcpStats.userInput.intervalBetweenProbes = secondsToDuration(*secondsBetweenProbes)
if tcpStats.userInput.intervalBetweenProbes < 2*time.Millisecond {
tcpStats.printer.printError("Wait interval should be more than 2 ms")
tcpstats.userInput.hostname = args[0]
tcpstats.userInput.ip = resolveHostname(tcpstats)
tcpstats.startTime = time.Now()
tcpstats.userInput.probesBeforeQuit = *probesbfrquit
tcpstats.userInput.timeout = secondsToDuration(*timeout)

tcpstats.userInput.intervalBetweenProbes = secondsToDuration(*secbtwprobes)
if tcpstats.userInput.intervalBetweenProbes < 2*time.Millisecond {
tcpstats.printer.printError("Wait interval should be more than 2 ms")
os.Exit(1)
}

// this serves as a default starting value for tracking changes.
tcpStats.hostnameChanges = []hostnameChange{
{tcpStats.userInput.ip, time.Now()},
tcpstats.hostnameChanges = []hostnameChange{
{tcpstats.userInput.ip, time.Now()},
}

if tcpStats.userInput.hostname == tcpStats.userInput.ip.String() {
tcpStats.isIP = true
if tcpstats.userInput.hostname == tcpstats.userInput.ip.String() {
tcpstats.isIP = true
}

if tcpStats.userInput.retryHostnameLookupAfter > 0 && !tcpStats.isIP {
tcpStats.userInput.shouldRetryResolve = true
if tcpstats.userInput.retryHostnameLookupAfter > 0 && !tcpstats.isIP {
tcpstats.userInput.shouldRetryResolve = true
}

if *interfaceName != "" {
tcpStats.userInput.networkInterface = newNetworkInterface(tcpStats, *interfaceName)
if *intName != "" {
tcpstats.userInput.networkInterface = newNetworkInterface(tcpstats, *intName)
}
}

// processUserInput gets and validate user input
func processUserInput(tcpStats *stats) {
useIPv4 := flag.Bool("4", false, "only use IPv4.")
useIPv6 := flag.Bool("6", false, "only use IPv6.")
retryHostnameResolveAfter := flag.Uint("r", 0, "retry resolving target's hostname after <n> number of failed probes. e.g. -r 10 to retry after 10 failed probes.")
probesBeforeQuit := flag.Uint("c", 0, "stop after <n> probes, regardless of the result. By default, no limit will be applied.")
outputJSON := flag.Bool("j", false, "output in JSON format.")
prettyJSON := flag.Bool("pretty", false, "use indentation when using json output format. No effect without the '-j' flag.")
showVersion := flag.Bool("v", false, "show version.")
shouldCheckUpdates := flag.Bool("u", false, "check for updates.")
secondsBetweenProbes := flag.Float64("i", 1, "interval between sending probes. Real number allowed with dot as a decimal separator. The default is one second")
timeout := flag.Float64("t", 1, "time to wait for a response, in seconds. Real number allowed. 0 means infinite timeout.")
outputDb := flag.String("db", "", "path and file name to store tcping output to sqlite database.")
interfaceName := flag.String("I", "", "interface name or address")

flag.CommandLine.Usage = usage

permuteArgs(os.Args[1:])
flag.Parse()

// validation for flag and args
args := flag.Args()
nFlag := flag.NFlag()

// we need to set printers first, because they're used for
// errors reporting and other output.
checkSetPrinters(tcpStats, outputJSON, prettyJSON, outputDb, args)
// Check if admin command passed in an render respons.
checkUpdateVersion(shouldCheckUpdates, showVersion, args, nFlag, tcpStats)

// host and port must be specified
if len(args) != 2 {
usage()
}

// Check whether both the ipv4 and ipv6 flags are attempted set if ony one, error otherwise.
checkSetIPFlags(tcpStats, useIPv4, useIPv6)
// Check if the port is valid and set it.
checkPort(tcpStats, args)
// set generic args
setGenericArgs(tcpStats, args, retryHostnameResolveAfter,
probesBeforeQuit, timeout, secondsBetweenProbes,
interfaceName)
}

/*
permuteArgs permute args for flag parsing stops just before the first non-flag argument.

Expand Down