131 lines
3.0 KiB
Go
131 lines
3.0 KiB
Go
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")
|
|
}
|