package powerdns_recursor import ( "errors" "fmt" "net" "strconv" "strings" "github.com/influxdata/telegraf/internal" ) func parseResponse(metrics string) map[string]interface{} { values := make(map[string]interface{}) s := strings.Split(metrics, "\n") if len(s) < 1 { return values } for _, metric := range s[:len(s)-1] { m := strings.Split(metric, "\t") if len(m) < 2 { continue } i, err := strconv.ParseInt(m[1], 10, 64) if err != nil { continue } values[m[0]] = i } return values } // This below is generally unsafe but necessary in this case // since the powerdns protocol encoding is host dependent. // The C implementation uses size_t as the size type for the // command length. The size and endianness of size_t change // depending on the platform the program is being run on. // Using the target architecture endianness and the known // integer size, we can "recreate" the corresponding C // behavior in an effort to maintain compatibility. Of course // in cases where one program is compiled for i386 and the // other for amd64 (and similar), this method will fail. const uintSizeInBytes = strconv.IntSize / 8 func writeNativeUIntToConn(conn net.Conn, value uint) error { intData := make([]byte, uintSizeInBytes) switch uintSizeInBytes { case 4: internal.HostEndianness.PutUint32(intData, uint32(value)) case 8: internal.HostEndianness.PutUint64(intData, uint64(value)) default: return errors.New("unsupported system configuration") } _, err := conn.Write(intData) return err } func readNativeUIntFromConn(conn net.Conn) (uint, error) { intData := make([]byte, uintSizeInBytes) n, err := conn.Read(intData) if err != nil { return 0, err } if n != uintSizeInBytes { return 0, fmt.Errorf("did not read enough data for native uint: read '%v' bytes, expected '%v'", n, uintSizeInBytes) } switch uintSizeInBytes { case 4: return uint(internal.HostEndianness.Uint32(intData)), nil case 8: return uint(internal.HostEndianness.Uint64(intData)), nil default: return 0, errors.New("unsupported system configuration") } }