mirror of https://github.com/perkeep/perkeep.git
netutil additions
Adds ListenOnLocalRandomPort and make Localhost more robust. Change-Id: Id6416f7ae5c35fb247035ecb0021f3978ff3480e
This commit is contained in:
parent
3374899d40
commit
87e6815d62
|
@ -273,16 +273,3 @@ func uidFromProcReader(lip net.IP, lport int, rip net.IP, rport int, r io.Reader
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Localhost returns the first address found when
|
|
||||||
// doing a lookup of "localhost".
|
|
||||||
func Localhost() (net.IP, error) {
|
|
||||||
ips, err := net.LookupIP("localhost")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(ips) < 1 {
|
|
||||||
return nil, errors.New("IP lookup for localhost returned no result")
|
|
||||||
}
|
|
||||||
return ips[0], nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -67,3 +68,62 @@ func HostPort(urlStr string) (string, error) {
|
||||||
}
|
}
|
||||||
return hostPort, nil
|
return hostPort, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListenOnLocalRandomPort returns a tcp listener on a local (see LoopbackIP) random port.
|
||||||
|
func ListenOnLocalRandomPort() (net.Listener, error) {
|
||||||
|
ip, err := Localhost()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: ip, Port: 0})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Localhost returns the first address found when
|
||||||
|
// doing a lookup of "localhost". If not successful,
|
||||||
|
// it looks for an ip on the loopback interfaces.
|
||||||
|
func Localhost() (net.IP, error) {
|
||||||
|
if ip := localhostLookup(); ip != nil {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
if ip := loopbackIP(); ip != nil {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("No loopback ip found.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// localhostLookup looks for a loopback IP by resolving localhost.
|
||||||
|
func localhostLookup() net.IP {
|
||||||
|
if ips, err := net.LookupIP("localhost"); err == nil && len(ips) > 0 {
|
||||||
|
return ips[0]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const flagUpLoopback = net.FlagUp | net.FlagLoopback
|
||||||
|
|
||||||
|
// loopbackIP finds the first loopback IP address sniffing network interfaces.
|
||||||
|
func loopbackIP() net.IP {
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, inf := range interfaces {
|
||||||
|
if inf.Flags&flagUpLoopback == flagUpLoopback {
|
||||||
|
addrs, err := inf.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ip, _, err := net.ParseCIDR(addr.String())
|
||||||
|
if err == nil && ip.IsLoopback() {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
||||||
package netutil
|
package netutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -120,3 +122,60 @@ func TestHostPort(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testLocalhostResolver(t *testing.T, resolve func() net.IP) {
|
||||||
|
ip := resolve()
|
||||||
|
if ip == nil {
|
||||||
|
t.Fatal("no ip found.")
|
||||||
|
}
|
||||||
|
if !ip.IsLoopback() {
|
||||||
|
t.Errorf("expected a loopback address: %s", ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLocalhost(t *testing.T) {
|
||||||
|
testLocalhostResolver(t, localhostLookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLoopbackIp(t *testing.T) {
|
||||||
|
testLocalhostResolver(t, loopbackIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocalhost(t *testing.T) {
|
||||||
|
_, err := Localhost()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListenOnLocalRandomPort(t *testing.T) {
|
||||||
|
l, err := ListenOnLocalRandomPort()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error %v", err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
|
||||||
|
_, port, err := net.SplitHostPort(l.Addr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if p, _ := strconv.Atoi(port); p < 1 {
|
||||||
|
t.Fatalf("expected port(%d) to be > 0", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLocalhostLookup(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if ip := localhostLookup(); ip == nil {
|
||||||
|
b.Fatal("no ip found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLoopbackIP(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if ip := loopbackIP(); ip == nil {
|
||||||
|
b.Fatal("no ip found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue