package main import ( "bufio" "errors" "flag" "fmt" "io" "log" "net" "os" "strconv" "time" ) var PortNotInRange = errors.New("the port number is not in the 0-65535 range") var ServiceNotFound = errors.New("the service is not known") var isDebug bool func init() { isDebug = false } func debug(v ...interface{}) { if isDebug { msg := make([]interface{}, len(v)+1) msg[0] = "[DEBUG]" for i, el := range v { msg[i+1] = el } log.Println(msg...) } } func connect(addr, port string) net.Conn { target := net.JoinHostPort(addr, port) conn, err := net.Dial("tcp", target) if err != nil { log.Fatal(err) } zero := time.Time{} if err = conn.SetDeadline(zero); err != nil { log.Fatal(err) } return conn } func validatePort(port int) error { if port < 1 || port > 65535 { return PortNotInRange } return nil } func getPort(srv string, port int) (string, error) { if port != 0 { return strconv.Itoa(port), nil } return srv, nil } func initLogger(logFile string) (*os.File, error) { f, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { return nil, err } wrt := io.MultiWriter(os.Stdout, f) log.SetOutput(wrt) return f, nil } // TODO: planned function that should do some ping measurement and return // the highest value found. func findLatency(address string) (time.Duration, error) { return time.Second, nil } func main() { var address, srv, logFile string var port int var interval, latency, zero time.Duration flag.StringVar(&address, "addr", "", "The target address or ip") flag.IntVar(&port, "port", 0, "The target port") flag.StringVar(&srv, "srv", "", "The target service (will be translated to default port, if -port not provided)") flag.StringVar(&logFile, "log-file", "", "The file path to log to") flag.DurationVar(&interval, "interval", time.Second, "Internal refresh duration (defaults to 1s)") flag.DurationVar(&latency, "latency", zero, "Internal refresh duration (defaults to 1s)") flag.BoolVar(&isDebug, "debug", false, "Enable debug logging") flag.Parse() if port != 0 { validatePort(port) } if logFile == "" { log.Println("Logging only to stdout") } else if f, err := initLogger(logFile); err != nil { log.Fatalf("error opening file: %v", err) f.Close() } else { defer f.Close() } parsedPort, err := getPort(srv, port) if err != nil { log.Fatal(err) } if latency == zero { latency, err = findLatency(address) if err != nil { log.Fatal(err) } } log.Printf("Logging every %v\n", interval) log.Printf("Latency is %v\n", latency) conn := connect(address, parsedPort) intervalStr := fmt.Sprintf("%v\n", interval) for conn != nil { conn.Write([]byte(intervalStr)) conn.SetReadDeadline(time.Now().Add(latency)) if data, err := bufio.NewReader(conn).ReadString('\n'); err != nil { log.Print(err) conn.Close() conn = nil } else { debug("Data =>", data) conn.SetReadDeadline(time.Now().Add(interval + latency)) } time.Sleep(interval) } log.Println("Connection closed") }