veyron/profiles/net: initial pass at dhcp support.

Change-Id: I1ab0b9bcc7e1cb239d608995ca687e1e19c2375a
diff --git a/profiles/net/gce_linux.go b/profiles/net/gce_linux.go
index fa09109..d350880 100644
--- a/profiles/net/gce_linux.go
+++ b/profiles/net/gce_linux.go
@@ -31,7 +31,7 @@
 		if _, err := publisher.CreateStream(StreamName, "network configuration", ch); err != nil {
 			return false
 		}
-		publishInitialSettings(ch, listen_protocol, listen_addr.IP.String(), pub)
+		publishInitialSettings(ch, listenProtocolFlag.Protocol, listenSpecFlag.String(), pub)
 		return true
 	}
 	return false
diff --git a/profiles/net/init.go b/profiles/net/init.go
index 34f577d..e38a6f5 100644
--- a/profiles/net/init.go
+++ b/profiles/net/init.go
@@ -38,13 +38,13 @@
 )
 
 var (
-	listen_protocol string
-	listen_addr     config.IPFlag
+	listenProtocolFlag = config.TCPProtocolFlag{"tcp4"}
+	listenSpecFlag     = config.IPHostPortFlag{Port: ":0"}
 )
 
 func init() {
-	flag.StringVar(&listen_protocol, "veyron.protocol", "tcp4", "protocol to listen with")
-	flag.Var(&listen_addr, "veyron.address", "address to listen on")
+	flag.Var(&listenProtocolFlag, "veyron.tcpprotocol", "protocol to listen with")
+	flag.Var(&listenSpecFlag, "veyron.tcpaddress", "address to listen on")
 	rt.RegisterProfile(New())
 }
 
@@ -99,7 +99,7 @@
 		log.Errorf("failed to create publisher: %s", err)
 		return
 	}
-	go monitorAndPublishNetworkSettings(rt, stop, ch, listen_protocol, listen_addr.IP.String())
+	go monitorAndPublishNetworkSettings(rt, stop, ch, listenProtocolFlag.Protocol, listenSpecFlag)
 }
 
 func publishInitialSettings(ch chan<- config.Setting, protocol, listenSpec string, addr net.IP) {
@@ -118,19 +118,24 @@
 // RmPublishAddressSetting without first sending an AddPublishAddressSetting.
 func monitorAndPublishNetworkSettings(rt veyron2.Runtime, stop <-chan struct{},
 	ch chan<- config.Setting,
-	listenProtocol string, listenSpec string) {
+	listenProtocol string, listenSpec config.IPHostPortFlag) {
 	defer close(ch)
 
 	log := rt.Logger()
+
 	prev4, _, prevAddr := firstUsableIPv4()
+	// TODO(cnicolaou): check that prev4 is one of the IPs that a hostname
+	// resolved to, if we used a hostname in the listenspec.
+
 	// prevAddr may be nil if we are currently offline.
 
-	publishInitialSettings(ch, listenProtocol, listenSpec, prevAddr)
+	log.Infof("Initial Settings: %s %s publish %s", listenProtocol, listenSpec, prevAddr)
+	publishInitialSettings(ch, listenProtocol, listenSpec.String(), prevAddr)
 
 	// Start the dhcp watcher.
 	watcher, err := netconfig.NewNetConfigWatcher()
 	if err != nil {
-		log.VI(1).Infof("Failed to get new config watcher: %s", err)
+		log.VI(2).Infof("Failed to get new config watcher: %s", err)
 		<-stop
 		return
 	}
@@ -139,16 +144,40 @@
 		select {
 		case <-watcher.Channel():
 			cur4, _, _ := ipState()
-			added := findAdded(prev4, cur4)
-			ifc, newAddr := added.first()
-			log.VI(1).Infof("new address found: %s:%s", ifc, newAddr)
 			removed := findRemoved(prev4, cur4)
-			if prevAddr == nil || (removed.has(prevAddr) && newAddr != nil) {
-				log.VI(1).Infof("address change from %s to %s:%s",
+			added := findAdded(prev4, cur4)
+			log.VI(2).Infof("Previous: %d: %s", len(prev4), prev4)
+			log.VI(2).Infof("Current : %d: %s", len(cur4), cur4)
+			log.VI(2).Infof("Added   : %d: %s", len(added), added)
+			log.VI(2).Infof("Removed : %d: %s", len(removed), removed)
+			if len(removed) == 0 && len(added) == 0 {
+				log.VI(2).Infof("Network event that lead to no address changes since our last 'baseline'")
+				continue
+			}
+			if len(added) == 0 {
+				// Nothing has been added, but something has been removed.
+				if !removed.has(prevAddr) {
+					log.VI(1).Infof("An address we were not using was removed")
+					continue
+				}
+				log.Infof("Publish address is no longer available: %s", prevAddr)
+				// Our currently published address has been removed and
+				// a new one has not been added.
+				// TODO(cnicolaou): look for a new address to use right now.
+				prevAddr = nil
+				continue
+			}
+			log.Infof("At least one address has been added and zero or more removed")
+			// something has been added, and maybe something has been removed
+			ifc, newAddr := added.first()
+			if newAddr != nil && (prevAddr == nil || removed.has(prevAddr)) {
+				log.Infof("Address being changed from %s to %s:%s",
 					prevAddr, ifc, newAddr)
 				ch <- config.NewIP(AddPublishAddressSetting, "new dhcp address to publish", newAddr)
 				ch <- config.NewIP(RmPublishAddressSetting, "remove address", prevAddr)
 				prevAddr = newAddr
+				prev4 = cur4
+				log.VI(2).Infof("Network baseline set to %s", cur4)
 			}
 		case <-stop:
 			return
diff --git a/profiles/net/net_test.go b/profiles/net/net_test.go
index ef862dc..31b88a8 100644
--- a/profiles/net/net_test.go
+++ b/profiles/net/net_test.go
@@ -56,7 +56,7 @@
 	}
 
 	// missing interfaces
-	got, want = findRemoved(aif, bif), ipAndIf{"eth0": nil, "eth1": nil}
+	got, want = findRemoved(aif, bif), aif
 	if !reflect.DeepEqual(got, want) {
 		t.Errorf("got %s, want %s", got, want)
 	}
@@ -65,7 +65,7 @@
 	bif["eth0"] = []net.IP{a, b, a6, b6}
 	got, want = findRemoved(aif, bif), ipAndIf{
 		"eth0": []net.IP{c, c6},
-		"eth1": nil,
+		"eth1": aif["eth1"],
 	}
 	if !reflect.DeepEqual(got, want) {
 		t.Errorf("got %s, want %s", got, want)
diff --git a/profiles/net/main.go b/profiles/net/net_watcher.go
similarity index 100%
rename from profiles/net/main.go
rename to profiles/net/net_watcher.go
diff --git a/profiles/net/util.go b/profiles/net/util.go
index cee7e63..721ed29 100644
--- a/profiles/net/util.go
+++ b/profiles/net/util.go
@@ -65,10 +65,11 @@
 			continue
 		}
 		for _, addr := range addrs {
-			if _, ok := addr.(*net.IPAddr); ok {
+			ipn, ok := addr.(*net.IPNet)
+			if !ok {
 				continue
 			}
-			ip := net.ParseIP(addr.String())
+			ip := ipn.IP
 			if ip == nil || ip.IsLoopback() {
 				continue
 			}
@@ -114,15 +115,11 @@
 	return netconfig.IsGloballyRoutable(ip)
 }
 
-func diffAB(a, b ipAndIf, added bool) ipAndIf {
+func diffAB(a, b ipAndIf) ipAndIf {
 	diff := make(ipAndIf)
 	for ak, av := range a {
 		if b[ak] == nil {
-			if added {
-				diff[ak] = av
-			} else {
-				diff[ak] = nil
-			}
+			diff[ak] = av
 			continue
 		}
 		for _, v := range av {
@@ -144,11 +141,11 @@
 // findAdded returns the set of interfaces and/or addresses that are
 // present in b, but not in a - i.e. have been added.
 func findAdded(a, b ipAndIf) ipAndIf {
-	return diffAB(b, a, true)
+	return diffAB(b, a)
 }
 
 // findRemoved returns the set of interfaces and/or addresses that
 // are present in a, but not in b - i.e. have been removed.
 func findRemoved(a, b ipAndIf) ipAndIf {
-	return diffAB(a, b, false)
+	return diffAB(a, b)
 }