package main import ( "fmt" "io/ioutil" "net" "os" "path/filepath" "strings" "sync" ) var wg sync.WaitGroup func Emit(pt Point) { if pt == nil { return } fmt.Println(pt) } func DoHostfile(fname string) { defer wg.Done() hostname := filepath.Base(fname) cfg, err := readConfigFile(fname) if err != nil { Emit(NewPoint("public", map[string]string{"host": hostname}, map[string]interface{}{"error": err.Error()})) return } for _, address := range getAddresses(cfg) { wg.Add(2) go Emit(DoAddress(hostname, "tcp4", address)) go Emit(DoAddress(hostname, "tcp6", address)) } } func DoAddress(host, network, address string) Point { defer wg.Done() tags := map[string]string{ "host": host, "network": network, "address": address, } addr, err := net.ResolveTCPAddr(network, address) if err != nil { if ae, ok := err.(*net.AddrError); ok && ae.Err == "no suitable address found" { return nil } return NewPoint("public", tags, map[string]interface{}{"error": err.Error()}) } conn, err := net.DialTCP(network, nil, addr) if err != nil { return NewPoint("public", tags, map[string]interface{}{"error": err.Error()}) } conn.CloseWrite() all, _ := ioutil.ReadAll(conn) line := strings.TrimRight(string(all), "\n") parts := strings.Split(line, " ") if len(parts) != 3 { return NewPoint("public", tags, map[string]interface{}{"error": fmt.Sprintf("malformed ID line: %q", line)}) } return NewPoint("public", tags, map[string]interface{}{ "name": parts[1], "version": parts[2], }) } func main() { for _, fname := range os.Args[1:] { wg.Add(1) go DoHostfile(fname) } wg.Wait() }