helper.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. // Package util provides various useful functions for completing the
  2. // "Whispering Gophers" code lab.
  3. package util
  4. import (
  5. "crypto/rand"
  6. "errors"
  7. "fmt"
  8. "net"
  9. )
  10. // ListenOnFirstUsableInterface returns a Listener that listens on the first
  11. // available port on the first available non-loopback IPv4 network interface.
  12. // It may not be the one you want (192.168.nn.128 won't usually be reachable from
  13. // outside your machine).
  14. func ListenOnFirstUsableInterface() (net.Listener, error) {
  15. ip, err := firstExternalIP()
  16. if err != nil {
  17. return nil, fmt.Errorf("could not find active non-loopback address: %v", err)
  18. }
  19. return net.Listen("tcp4", ip+":0")
  20. }
  21. func firstExternalIP() (string, error) {
  22. ifaces, err := net.Interfaces()
  23. if err != nil {
  24. return "", err
  25. }
  26. for _, iface := range ifaces {
  27. if iface.Flags&net.FlagUp == 0 {
  28. continue // interface down
  29. }
  30. if iface.Flags&net.FlagLoopback != 0 {
  31. continue // loopback interface
  32. }
  33. addrs, err := iface.Addrs()
  34. if err != nil {
  35. return "", err
  36. }
  37. for _, addr := range addrs {
  38. var ip net.IP
  39. switch v := addr.(type) {
  40. case *net.IPNet:
  41. ip = v.IP
  42. case *net.IPAddr:
  43. ip = v.IP
  44. }
  45. if ip == nil || ip.IsLoopback() {
  46. continue
  47. }
  48. ip = ip.To4()
  49. if ip == nil {
  50. continue // not an ipv4 address
  51. }
  52. return ip.String(), nil
  53. }
  54. }
  55. return "", errors.New("are you connected to the network?")
  56. }
  57. // RandomID returns an 8 byte random string in hexadecimal.
  58. func RandomID() string {
  59. b := make([]byte, 8)
  60. n, _ := rand.Read(b)
  61. return fmt.Sprintf("%x", b[:n])
  62. }