66 lines
1.5 KiB
Go
66 lines
1.5 KiB
Go
// 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])
|
|
}
|