Signal network changes.

Change-Id: I990aebd73b9fd353fbae12712bb3dcb62a66a130
diff --git a/examples/netconfigwatcher/main.go b/examples/netconfigwatcher/main.go
new file mode 100644
index 0000000..b935883
--- /dev/null
+++ b/examples/netconfigwatcher/main.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"veyron/runtimes/google/lib/netconfig"
+)
+
+func main() {
+	w, err := netconfig.NewNetConfigWatcher()
+	if err != nil {
+		log.Fatalf("oops: %s", err)
+	}
+	fmt.Println("Do something to your network. You should see one or more dings.")
+	for {
+		<-w.Channel()
+		fmt.Println("ding")
+	}
+}
diff --git a/runtimes/google/lib/netconfig/example_test.go b/runtimes/google/lib/netconfig/example_test.go
new file mode 100644
index 0000000..0acef69
--- /dev/null
+++ b/runtimes/google/lib/netconfig/example_test.go
@@ -0,0 +1,20 @@
+package netconfig_test
+
+import (
+	"fmt"
+	"log"
+
+	"veyron/runtimes/google/lib/netconfig"
+)
+
+func ExampleNetConfigWatcher() {
+	w, err := netconfig.NewNetConfigWatcher()
+	if err != nil {
+		log.Fatalf("oops: %s", err)
+	}
+	fmt.Println("Do something to your network. You should see one or more dings.")
+	for {
+		<-w.Channel()
+		fmt.Println("ding")
+	}
+}
diff --git a/runtimes/google/lib/netconfig/ipaux.go b/runtimes/google/lib/netconfig/ipaux.go
new file mode 100644
index 0000000..ffade53
--- /dev/null
+++ b/runtimes/google/lib/netconfig/ipaux.go
@@ -0,0 +1,47 @@
+// +build plan9 windows
+
+package netconfig
+
+// Code to signal a network change every 2 minutes.   We use
+// this for systems where we don't yet have a good way to
+// watch for network changes.
+
+import (
+	"time"
+)
+
+type timerNetConfigWatcher struct {
+	c    chan struct{} // channel to signal confg changes
+	stop chan struct{} // channel to tell the watcher to stop
+}
+
+// Stop any waiter
+func (w *timerNetConfigWatcher) Stop() {
+	w.stop <- struct{}{}
+}
+
+func (w *timerNetConfigWatcher) Channel() chan struct{} {
+	return w.c
+}
+
+func (w *timerNetConfigWatcher) watcher() {
+	for {
+		select {
+		case <-w.stop:
+			close(w.c)
+			return
+		case <-time.NewTimer(2 * time.Minute).C:
+			select {
+			case w.c <- struct{}{}:
+			default:
+			}
+		}
+	}
+}
+
+func NewNetConfigWatcher() (NetConfigWatcher, error) {
+	w.c = make(chan struct{})
+	w.stop = make(chan struct{}, 1)
+	go w.watcher()
+	return w, nil
+}
diff --git a/runtimes/google/lib/netconfig/ipaux_bsd.go b/runtimes/google/lib/netconfig/ipaux_bsd.go
new file mode 100644
index 0000000..aedeb81
--- /dev/null
+++ b/runtimes/google/lib/netconfig/ipaux_bsd.go
@@ -0,0 +1,121 @@
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package netconfig
+
+// We connect to the Route socket and parse messages to
+// look for network configuration changes.  This is generic
+// to all BSD based systems (including MacOS).  The net
+// library already has code to parse the messages so all
+// we need to do is look for message types.
+
+import (
+	"sync"
+	"syscall"
+	"time"
+	"veyron2/vlog"
+)
+
+/*
+#include <sys/socket.h>
+*/
+import "C"
+
+type bsdNetConfigWatcher struct {
+	sync.Mutex
+	t       *time.Timer
+	c       chan struct{}
+	s       int
+	stopped bool
+}
+
+func (w *bsdNetConfigWatcher) Stop() {
+	w.Lock()
+	defer w.Unlock()
+	if w.stopped {
+		return
+	}
+	w.stopped = true
+	syscall.Close(w.s)
+}
+
+func (w *bsdNetConfigWatcher) Channel() chan struct{} {
+	return w.c
+}
+
+// NewNetConfigWatcher returns a watcher that sends a message
+// on the Channel() whenever the config changes.
+func NewNetConfigWatcher() (NetConfigWatcher, error) {
+	s, err := syscall.Socket(C.PF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
+	if err != nil {
+		vlog.Infof("socket failed: %s", err)
+		return nil, err
+	}
+	w := &bsdNetConfigWatcher{c: make(chan struct{}, 1), s: s}
+	go w.watcher()
+	return w, nil
+}
+
+func (w *bsdNetConfigWatcher) ding() {
+	w.Lock()
+	defer w.Unlock()
+	w.t = nil
+	if w.stopped {
+		return
+	}
+	// Don't let us hang in the lock.  The default is safe because the requirement
+	// is that the client get a message after the last config change.  Since this is
+	// a queued chan, we really don't have to stuff anything in it if there's already
+	// something there.
+	select {
+	case w.c <- struct{}{}:
+	default:
+	}
+}
+
+func (w *bsdNetConfigWatcher) watcher() {
+	defer w.Stop()
+
+	// Loop waiting for messages.
+	for {
+		b := make([]byte, 4096)
+		nr, err := syscall.Read(w.s, b)
+		if err != nil {
+			return
+		}
+		msgs, err := syscall.ParseRoutingMessage(b[:nr])
+		if err != nil {
+			vlog.Infof("Couldn't parse: %s", err)
+			continue
+		}
+
+		// Decode the addresses.
+		for _, m := range msgs {
+			switch m.(type) {
+			case *syscall.InterfaceMessage:
+			case *syscall.InterfaceAddrMessage:
+			default:
+				continue
+			}
+			// Changing networks usually spans many seconds and involves
+			// multiple network config changes.  We add histeresis by
+			// setting an alarm when the first change is detected and
+			// not informing the client till the alarm goes off.
+			// NOTE(p): I chose 3 seconds because that covers all the
+			// events involved in moving from one wifi network to another.
+			w.Lock()
+			if w.t == nil {
+				w.t = time.AfterFunc(3*time.Second, w.ding)
+			}
+			w.Unlock()
+		}
+	}
+
+
+	w.Stop()
+	w.Lock()
+	close(w.c)
+	if w.t != nil {
+		w.t.Stop()
+	}
+	w.Unlock()
+}
diff --git a/runtimes/google/lib/netconfig/ipaux_linux.go b/runtimes/google/lib/netconfig/ipaux_linux.go
new file mode 100644
index 0000000..9e90003
--- /dev/null
+++ b/runtimes/google/lib/netconfig/ipaux_linux.go
@@ -0,0 +1,371 @@
+package netconfig
+
+// We connect to the Netlink Route socket and parse messages to
+// look for network configuration changes.  This is very Linux
+// specific, hence the file name.
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"sync"
+	"syscall"
+	"time"
+	"unsafe"
+	"veyron2/vlog"
+)
+
+/*
+#include <linux/rtnetlink.h>
+*/
+import "C"
+
+// All rtnetlink attributes start with this header.
+type rtAttrHdr C.struct_rtattr
+
+const rtAttrHdrLen = C.sizeof_struct_rtattr
+
+// The address change messages (RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR).
+type ifaddrMsgHdr C.struct_ifaddrmsg
+
+const ifaddrMsgHdrLen = C.sizeof_struct_ifaddrmsg
+
+type rtAttribute fmt.Stringer
+
+type rtAddressMessage struct {
+	name       string
+	hdr        ifaddrMsgHdr
+	attributes []rtAttribute
+}
+
+// Attribute types (see rtnetlink(7))
+type ifaAddress net.IP
+type ifaLocal net.IP
+type ifaBroadcast net.IP
+type ifaAnycast net.IP
+type ifaMulticast net.IP
+type ifaLabel string
+type ifaCacheInfo C.struct_ifa_cacheinfo
+
+const ifaCacheInfoLen = C.sizeof_struct_ifa_cacheinfo
+
+// String routines to make debugging easier.
+func (a ifaAddress) String() string   { return "Address=" + net.IP(a).String() }
+func (a ifaLocal) String() string     { return "Local=" + net.IP(a).String() }
+func (a ifaBroadcast) String() string { return "Braodcast=" + net.IP(a).String() }
+func (a ifaAnycast) String() string   { return "Anycast=" + net.IP(a).String() }
+func (a ifaMulticast) String() string { return "Anycast=" + net.IP(a).String() }
+func (a ifaLabel) String() string     { return "Label=" + string(a) }
+func (a ifaCacheInfo) String() string {
+	return fmt.Sprintf("CacheInfo[preferred %d valid %d cstamp %d tstamp %d]", a.ifa_prefered, a.ifa_valid, a.cstamp, a.tstamp)
+}
+func (m *rtAddressMessage) String() string {
+	return fmt.Sprintf("%s: index %d %v", m.name, m.hdr.ifa_index, m.attributes)
+}
+
+// Address looks for the address attribute in an rtAddressMessage.  If it isn't there, just assume the null address.
+func (m *rtAddressMessage) Address() net.IP {
+	for _, a := range m.attributes {
+		switch a.(type) {
+		case ifaAddress:
+			return net.IP(a.(ifaAddress))
+		}
+	}
+	return net.IPv4zero
+}
+
+func parsertAddressAttribute(b []byte) (rtAttribute, []byte, error) {
+	if len(b) == 0 {
+		return nil, nil, nil
+	}
+	if len(b) < rtAttrHdrLen {
+		return nil, nil, errors.New("attribute too short")
+	}
+	ahdr := (*rtAttrHdr)(unsafe.Pointer(&b[0]))
+	rounded := ((ahdr.rta_len + 3) / 4) * 4
+	if len(b) < int(rounded) {
+		return nil, nil, errors.New("attribute too short")
+	}
+	remaining := b[rounded:]
+	b = b[rtAttrHdrLen:ahdr.rta_len]
+	switch ahdr.rta_type {
+	case C.IFA_ADDRESS:
+		return rtAttribute(ifaAddress(net.IP(b))), remaining, nil
+	case C.IFA_LOCAL:
+		return rtAttribute(ifaLocal(b)), remaining, nil
+	case C.IFA_LABEL:
+		return rtAttribute(ifaLabel(b)), remaining, nil
+	case C.IFA_BROADCAST:
+		return rtAttribute(ifaBroadcast(b)), remaining, nil
+	case C.IFA_ANYCAST:
+		return rtAttribute(ifaAnycast(b)), remaining, nil
+	case C.IFA_CACHEINFO:
+		if len(b) < ifaCacheInfoLen {
+			return nil, nil, errors.New("attribute too short")
+		}
+		return rtAttribute(ifaCacheInfo(*(*C.struct_ifa_cacheinfo)(unsafe.Pointer(&b[0])))), remaining, nil
+	case C.IFA_MULTICAST:
+		return rtAttribute(ifaMulticast(b)), remaining, nil
+	}
+	return nil, remaining, errors.New("unknown attribute")
+}
+
+func parsertAddressMessage(nlm syscall.NetlinkMessage) (*rtAddressMessage, error) {
+	var name string
+	switch nlm.Header.Type {
+	case C.RTM_NEWADDR:
+		name = "RTM_NEWADDR"
+	case C.RTM_DELADDR:
+		name = "RTM_DELADDR"
+	case C.RTM_GETADDR:
+		name = "RTM_GETADDR"
+	default:
+		return nil, fmt.Errorf("unknown message type")
+	}
+	if len(nlm.Data) < ifaddrMsgHdrLen {
+		return nil, errors.New("bad length")
+	}
+	m := &rtAddressMessage{name: name, hdr: *(*ifaddrMsgHdr)(unsafe.Pointer(&nlm.Data[0]))}
+	b := nlm.Data[ifaddrMsgHdrLen:]
+	for {
+		var a rtAttribute
+		var err error
+		a, b, err = parsertAddressAttribute(b)
+		if b == nil {
+			break
+		}
+		if err == nil {
+			m.attributes = append(m.attributes, a)
+		}
+	}
+	return m, nil
+}
+
+// The link change messages (RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK).
+type ifInfoMsgHdr C.struct_ifinfomsg
+
+const ifInfoMsgHdrLen = C.sizeof_struct_ifinfomsg
+
+type rtLinkMessage struct {
+	name       string
+	hdr        ifInfoMsgHdr
+	attributes []rtAttribute
+}
+
+// Attribute types (see rtnetlink(7))
+type iflaAddress []byte
+type iflaBroadcast []byte
+type iflaIFName string
+type iflaMTU uint32
+type iflaLink int
+type iflaQDisc string
+type iflaOperstate int
+type iflaStats C.struct_rtnl_link_stats
+
+const iflaStatsLen = C.sizeof_struct_rtnl_link_stats
+
+// String routines to make debugging easier.
+func (a iflaAddress) String() string   { return fmt.Sprintf("HWAddress=%v", []byte(a)) }
+func (a iflaBroadcast) String() string { return fmt.Sprintf("HWBroadcast=%v", []byte(a)) }
+func (a iflaIFName) String() string    { return "Name=" + string(a) }
+func (a iflaMTU) String() string       { return fmt.Sprintf("MTU=%d", uint32(a)) }
+func (a iflaLink) String() string      { return fmt.Sprintf("Type=%d", int(a)) }
+func (a iflaQDisc) String() string     { return "Qdisc=" + string(a) }
+func (a iflaStats) String() string {
+	return fmt.Sprintf("Stats[rx %d tx %d ...]", a.rx_packets, a.tx_packets)
+}
+func (a iflaOperstate) String() string { return fmt.Sprintf("Operstate=%d", int(a)) }
+func (m *rtLinkMessage) String() string {
+	return fmt.Sprintf("%s: index %d %v", m.name, m.hdr.ifi_index, m.attributes)
+}
+
+func parseRTLinkAttribute(b []byte) (rtAttribute, []byte, error) {
+	if len(b) == 0 {
+		return nil, nil, nil
+	}
+	if len(b) < rtAttrHdrLen {
+		return nil, nil, errors.New("attribute too short")
+	}
+	ahdr := (*rtAttrHdr)(unsafe.Pointer(&b[0]))
+	rounded := ((ahdr.rta_len + 3) / 4) * 4
+	if len(b) < int(rounded) {
+		return nil, nil, errors.New("attribute too short")
+	}
+	remaining := b[rounded:]
+	b = b[rtAttrHdrLen:ahdr.rta_len]
+	switch ahdr.rta_type {
+	case C.IFLA_ADDRESS:
+		return rtAttribute(iflaAddress(b)), remaining, nil
+	case C.IFLA_BROADCAST:
+		return rtAttribute(iflaBroadcast(b)), remaining, nil
+	case C.IFLA_IFNAME:
+		return rtAttribute(iflaIFName(string(b))), remaining, nil
+	case C.IFLA_MTU:
+		return rtAttribute(iflaMTU(*(*C.uint)(unsafe.Pointer(&b[0])))), remaining, nil
+	case C.IFLA_LINK:
+		return rtAttribute(iflaMTU(*(*C.int)(unsafe.Pointer(&b[0])))), remaining, nil
+	case C.IFLA_QDISC:
+		return rtAttribute(iflaQDisc(string(b))), remaining, nil
+	case C.IFLA_STATS:
+		if len(b) < iflaStatsLen {
+			return nil, remaining, errors.New("attribute too short")
+		}
+		return rtAttribute(iflaStats(*(*C.struct_rtnl_link_stats)(unsafe.Pointer(&b[0])))), remaining, nil
+	case C.IFLA_OPERSTATE:
+		return rtAttribute(iflaOperstate(*(*C.int)(unsafe.Pointer(&b[0])))), remaining, nil
+	}
+	return nil, remaining, errors.New("unknown attribute")
+}
+
+func parsertLinkMessage(nlm syscall.NetlinkMessage) (*rtLinkMessage, error) {
+	var name string
+	switch nlm.Header.Type {
+	case C.RTM_NEWLINK:
+		name = "RTM_NEWLINK"
+	case C.RTM_DELLINK:
+		name = "RTM_DELLINK"
+	case C.RTM_GETLINK:
+		name = "RTM_GETLINK"
+	default:
+		return nil, fmt.Errorf("unknown message type")
+	}
+	if len(nlm.Data) < ifInfoMsgHdrLen {
+		return nil, errors.New("bad length")
+	}
+	m := &rtLinkMessage{name: name, hdr: *(*ifInfoMsgHdr)(unsafe.Pointer(&nlm.Data[0]))}
+	b := nlm.Data[ifInfoMsgHdrLen:]
+	for {
+		var a rtAttribute
+		var err error
+		a, b, err = parseRTLinkAttribute(b)
+		if b == nil {
+			break
+		}
+		if err == nil {
+			m.attributes = append(m.attributes, a)
+		}
+	}
+	return m, nil
+}
+
+type rtnetlinkWatcher struct {
+	sync.Mutex
+	t       *time.Timer
+	c       chan struct{}
+	s       int
+	stopped bool
+}
+
+func (w *rtnetlinkWatcher) Stop() {
+	w.Lock()
+	defer w.Unlock()
+	if w.stopped {
+		return
+	}
+	w.stopped = true
+	syscall.Close(w.s)
+}
+
+func (w *rtnetlinkWatcher) Channel() chan struct{} {
+	return w.c
+}
+
+const (
+	GROUPS = C.RTMGRP_LINK | C.RTMGRP_IPV4_IFADDR | C.RTMGRP_IPV6_IFADDR | C.RTMGRP_NOTIFY
+)
+
+// NewNetConfigWatcher returns a watcher that wakes up anyone
+// calling the Wait routine whenever the configuration changes.
+func NewNetConfigWatcher() (NetConfigWatcher, error) {
+	s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE)
+	if err != nil {
+		vlog.Infof("netconfig socket failed: %s", err)
+		return nil, err
+	}
+
+	lsa := &syscall.SockaddrNetlink{Family: syscall.AF_NETLINK, Groups: GROUPS}
+	if err := syscall.Bind(s, lsa); err != nil {
+		vlog.Infof("netconfig bind failed: %s", err)
+		return nil, err
+	}
+
+	w := &rtnetlinkWatcher{c: make(chan struct{}, 1), s: s}
+	go w.watcher()
+	return w, nil
+}
+
+func (w *rtnetlinkWatcher) ding() {
+	w.Lock()
+	defer w.Unlock()
+	w.t = nil
+	if w.stopped {
+		return
+	}
+	// Don't let us hang in the lock.  The default is safe because the requirement
+	// is that the client get a message after the last config change.  Since this is
+	// a queued chan, we really don't have to stuff anything in it if there's already
+	// something there.
+	select {
+	case w.c <- struct{}{}:
+	default:
+	}
+}
+
+func (w *rtnetlinkWatcher) watcher() {
+	var newAddrs []net.IP
+	for {
+		rb := make([]byte, 4096)
+		nr, _, err := syscall.Recvfrom(w.s, rb, 0)
+		if err != nil {
+			break
+		}
+		rb = rb[:nr]
+		msgs, err := syscall.ParseNetlinkMessage(rb)
+		if err != nil {
+			vlog.Infof("ParseNetlinkMessage failed: %s", err)
+			continue
+		}
+	L:
+		for _, m := range msgs {
+			if am, err := parsertAddressMessage(m); err == nil {
+				// NOTE(p): We get continuous NEWADDR messages about some
+				// IPv6 addresses in Google corp.  Just ignore duplicate back
+				// to back NEWADDRs about the same addresses.
+				if am.name == "RTM_NEWADDR" {
+					addr := am.Address()
+					for _, a := range newAddrs {
+						if addr.Equal(a) {
+							break L
+						}
+					}
+					newAddrs = append(newAddrs, addr)
+				} else {
+					newAddrs = nil
+				}
+			} else if _, err := parsertLinkMessage(m); err == nil {
+				newAddrs = nil
+			} else {
+				continue
+			}
+			// Changing networks usually spans many seconds and involves
+			// multiple network config changes.  We add histeresis by
+			// setting an alarm when the first change is detected and
+			// not informing the client till the alarm goes off.
+			// NOTE(p): I chose 3 seconds because that covers all the
+			// events involved in moving from one wifi network to another.
+			w.Lock()
+			if w.t == nil {
+				w.t = time.AfterFunc(3*time.Second, w.ding)
+			}
+			w.Unlock()
+		}
+	}
+
+	w.Stop()
+	w.Lock()
+	close(w.c)
+	if w.t != nil {
+		w.t.Stop()
+	}
+	w.Unlock()
+}
diff --git a/runtimes/google/lib/netconfig/model.go b/runtimes/google/lib/netconfig/model.go
new file mode 100644
index 0000000..c65afb6
--- /dev/null
+++ b/runtimes/google/lib/netconfig/model.go
@@ -0,0 +1,17 @@
+// package netconfig implements a network configuration watcher.
+// NOTE(p): This is also where we should put any code that changes
+//          network configuration.
+
+package netconfig
+
+// NetConfigWatcher sends on channel whenever an interface or interface address
+// is added or deleted.
+type NetConfigWatcher interface {
+	// Stop watching.
+	Stop()
+
+	// A channel that returns an item whenever the network addresses or
+	// interfaces have changed. It is up to the caller to reread the
+	// network configuration in such cases.
+	Channel() chan struct{}
+}