1
0

ping.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. // Defines a wrapper around the system ping binary.
  2. //
  3. // NOTE(os): may fail with non-unix compliant system ping binaries.
  4. package pingo
  5. import (
  6. "errors"
  7. "os/exec"
  8. "strconv"
  9. "strings"
  10. )
  11. // runPing returns the byte array as returned by [exec.Command]
  12. //
  13. // NOTE(os): this function may fail on non-unix compliant implementations of the Ping spec.
  14. func runPing(address string) (delay *[]byte, err error) {
  15. out, err := exec.Command("ping", address, "-c 1").Output()
  16. if err != nil {
  17. return nil, err
  18. }
  19. return &out, err
  20. }
  21. // splitBytesToLines splits bytes as returned by [pingstats.runPing] into an
  22. // array of strings by newline
  23. func splitBytesToLines(bytes *[]byte) (lines []string) {
  24. return strings.Split(strings.ReplaceAll(string(*bytes), "\r\n", "\n"), "\n")
  25. }
  26. // Ping returns the delay of a single Ping as reported by the system Ping binary.
  27. //
  28. // If the function is unable to resolve the system binary output or fails to
  29. // successfully resolve a Ping, it will always return -1.
  30. //
  31. // NOTE(os): this function may fail on non-unix compliant implementations of the Ping spec.
  32. func Ping(address string) (delay float64, err error) {
  33. out, err := runPing(address)
  34. if err != nil {
  35. return -1, err
  36. }
  37. lines := splitBytesToLines(out)
  38. for i := 0; i < len(lines); i++ {
  39. if strings.Contains(lines[i], "bytes from") {
  40. position := strings.Index(lines[i], "time=")
  41. before, _, success := strings.Cut(lines[i][position:], " ")
  42. if !success {
  43. return -1, errors.New("Line does not match pattern!")
  44. }
  45. _, after, success := strings.Cut(before, "=")
  46. if !success {
  47. return -1, errors.New("Line does not match pattern!")
  48. }
  49. delay, _ := strconv.ParseFloat(after, 64)
  50. return delay, nil
  51. }
  52. }
  53. return -1, errors.New("could not resolve host: " + address)
  54. }