// Package util provides various useful functions for completing the // "Whispering Gophers" code lab. package util import ( "crypto/rand" "errors" "fmt" "net" ) // ListenOnFirstUsableInterface returns a Listener that listens on the first // available port on the first available non-loopback IPv4 network interface. // It may not be the one you want (192.168.nn.128 won't usually be reachable from // outside your machine). func ListenOnFirstUsableInterface() (net.Listener, error) { ip, err := firstExternalIP() if err != nil { return nil, fmt.Errorf("could not find active non-loopback address: %v", err) } return net.Listen("tcp4", ip+":0") } func firstExternalIP() (string, error) { ifaces, err := net.Interfaces() if err != nil { return "", err } for _, iface := range ifaces { if iface.Flags&net.FlagUp == 0 { continue // interface down } if iface.Flags&net.FlagLoopback != 0 { continue // loopback interface } addrs, err := iface.Addrs() if err != nil { return "", err } for _, addr := range addrs { var ip net.IP switch v := addr.(type) { case *net.IPNet: ip = v.IP case *net.IPAddr: ip = v.IP } if ip == nil || ip.IsLoopback() { continue } ip = ip.To4() if ip == nil { continue // not an ipv4 address } return ip.String(), nil } } return "", errors.New("are you connected to the network?") } // RandomID returns an 8 byte random string in hexadecimal. func RandomID() string { b := make([]byte, 8) n, _ := rand.Read(b) return fmt.Sprintf("%x", b[:n]) }