From 001b7ab714533f7c5ff9355f118abbb39921cc0b Mon Sep 17 00:00:00 2001
From: Jeromy <jeromyj@gmail.com>
Date: Wed, 22 Apr 2015 00:55:31 -0700
Subject: [PATCH] implement a config option for mdns

---
 core/core.go             | 31 ++++++++++++++++-----
 p2p/discovery/mdns.go    | 58 +++++++++++++++++++++++++---------------
 repo/config/config.go    |  1 +
 repo/config/discovery.go | 12 +++++++++
 repo/config/init.go      |  4 +++
 5 files changed, 77 insertions(+), 29 deletions(-)
 create mode 100644 repo/config/discovery.go

diff --git a/core/core.go b/core/core.go
index 6ab1d2ffc..25ca7a04e 100644
--- a/core/core.go
+++ b/core/core.go
@@ -220,7 +220,8 @@ func standardWithRouting(r repo.Repo, online bool, routingOption RoutingOption,
 		}
 
 		if online {
-			if err := n.startOnlineServices(ctx, routingOption, hostOption); err != nil {
+			do := setupDiscoveryOption(n.Repo.Config().Discovery)
+			if err := n.startOnlineServices(ctx, routingOption, hostOption, do); err != nil {
 				return nil, err
 			}
 		} else {
@@ -232,7 +233,7 @@ func standardWithRouting(r repo.Repo, online bool, routingOption RoutingOption,
 	}
 }
 
-func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption) error {
+func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption, do DiscoveryOption) error {
 
 	if n.PeerHost != nil { // already online.
 		return errors.New("node already online")
@@ -264,16 +265,30 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin
 	go n.Reprovider.ProvideEvery(ctx, kReprovideFrequency)
 
 	// setup local discovery
-	service, err := discovery.NewMdnsService(n.PeerHost)
-	if err != nil {
-		return err
+	if do != nil {
+		service, err := do(n.PeerHost)
+		if err != nil {
+			return err
+		}
+		service.RegisterNotifee(n)
+		n.Discovery = service
 	}
-	service.RegisterNotifee(n)
-	n.Discovery = service
 
 	return n.Bootstrap(DefaultBootstrapConfig)
 }
 
+func setupDiscoveryOption(d config.Discovery) DiscoveryOption {
+	if d.MDNS.Enabled {
+		return func(h p2phost.Host) (discovery.Service, error) {
+			if d.MDNS.Interval == 0 {
+				d.MDNS.Interval = 5
+			}
+			return discovery.NewMdnsService(h, time.Duration(d.MDNS.Interval)*time.Second)
+		}
+	}
+	return nil
+}
+
 func (n *IpfsNode) HandlePeerFound(p peer.PeerInfo) {
 	log.Warning("trying peer info: ", p)
 	ctx, _ := context.WithTimeout(n.Context(), time.Second*10)
@@ -540,4 +555,6 @@ func constructDHTRouting(ctx context.Context, host p2phost.Host, dstore ds.Threa
 
 type RoutingOption func(context.Context, p2phost.Host, ds.ThreadSafeDatastore) (routing.IpfsRouting, error)
 
+type DiscoveryOption func(p2phost.Host) (discovery.Service, error)
+
 var DHTOption RoutingOption = constructDHTRouting
diff --git a/p2p/discovery/mdns.go b/p2p/discovery/mdns.go
index 5d57b21cd..234ef5f6b 100644
--- a/p2p/discovery/mdns.go
+++ b/p2p/discovery/mdns.go
@@ -1,13 +1,14 @@
 package discovery
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"io/ioutil"
 	golog "log"
 	"net"
-	"strconv"
-	"strings"
+	//"strconv"
+	//"strings"
 	"sync"
 	"time"
 
@@ -22,7 +23,6 @@ import (
 
 var log = u.Logger("mdns")
 
-const LookupFrequency = time.Second * 5
 const ServiceTag = "discovery.ipfs.io"
 
 type Service interface {
@@ -42,33 +42,45 @@ type mdnsService struct {
 
 	lk       sync.Mutex
 	notifees []Notifee
+	interval time.Duration
 }
 
-func NewMdnsService(peerhost host.Host) (Service, error) {
+func getDialableListenAddr(ph host.Host) (*net.TCPAddr, error) {
+	for _, addr := range ph.Addrs() {
+		na, err := manet.ToNetAddr(addr)
+		if err != nil {
+			continue
+		}
+		tcp, ok := na.(*net.TCPAddr)
+		if ok {
+			return tcp, nil
+		}
+	}
+	return nil, errors.New("failed to find good external addr from peerhost")
+}
+
+func NewMdnsService(peerhost host.Host, interval time.Duration) (Service, error) {
 
 	// TODO: dont let mdns use logging...
 	golog.SetOutput(ioutil.Discard)
 
-	// determine my local swarm port
+	var ipaddrs []net.IP
 	port := 4001
-	for _, addr := range peerhost.Addrs() {
-		parts := strings.Split(addr.String(), "/")
-		fmt.Println("parts len: ", len(parts))
-		if len(parts) == 5 && parts[3] == "tcp" {
-			n, err := strconv.Atoi(parts[4])
-			if err != nil {
-				return nil, err
-			}
-			port = n
-			break
-		}
+
+	addr, err := getDialableListenAddr(peerhost)
+	if err != nil {
+		log.Warning(err)
+	} else {
+		ipaddrs = []net.IP{addr.IP}
+		port = addr.Port
 	}
+
 	fmt.Println("using port: ", port)
 
 	myid := peerhost.ID().Pretty()
 
 	info := []string{myid}
-	service, err := mdns.NewMDNSService(myid, ServiceTag, "", "", port, nil, info)
+	service, err := mdns.NewMDNSService(myid, ServiceTag, "", "", port, ipaddrs, info)
 	if err != nil {
 		return nil, err
 	}
@@ -80,9 +92,10 @@ func NewMdnsService(peerhost host.Host) (Service, error) {
 	}
 
 	s := &mdnsService{
-		server:  server,
-		service: service,
-		host:    peerhost,
+		server:   server,
+		service:  service,
+		host:     peerhost,
+		interval: interval,
 	}
 
 	go s.pollForEntries()
@@ -95,7 +108,7 @@ func (m *mdnsService) Close() error {
 }
 
 func (m *mdnsService) pollForEntries() {
-	ticker := time.NewTicker(LookupFrequency)
+	ticker := time.NewTicker(m.interval)
 	for {
 		select {
 		case <-ticker.C:
@@ -110,7 +123,7 @@ func (m *mdnsService) pollForEntries() {
 			qp.Domain = "local"
 			qp.Entries = entriesCh
 			qp.Service = ServiceTag
-			qp.Timeout = time.Second * 3
+			qp.Timeout = time.Second * 5
 
 			err := mdns.Query(&qp)
 			if err != nil {
@@ -122,6 +135,7 @@ func (m *mdnsService) pollForEntries() {
 }
 
 func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) {
+	fmt.Println("handling entry!")
 	mpeer, err := peer.IDB58Decode(e.Info)
 	if err != nil {
 		log.Warning("Error parsing peer ID from mdns entry: ", err)
diff --git a/repo/config/config.go b/repo/config/config.go
index 83cd2abb9..1d2fa87ad 100644
--- a/repo/config/config.go
+++ b/repo/config/config.go
@@ -21,6 +21,7 @@ type Config struct {
 	Addresses        Addresses             // local node's addresses
 	Mounts           Mounts                // local node's mount points
 	Version          Version               // local node's version management
+	Discovery        Discovery             // local node's discovery mechanisms
 	Bootstrap        []string              // local nodes's bootstrap peer addresses
 	Tour             Tour                  // local node's tour position
 	Gateway          Gateway               // local node's gateway server options
diff --git a/repo/config/discovery.go b/repo/config/discovery.go
new file mode 100644
index 000000000..4fb8508f0
--- /dev/null
+++ b/repo/config/discovery.go
@@ -0,0 +1,12 @@
+package config
+
+type Discovery struct {
+	MDNS MDNS
+}
+
+type MDNS struct {
+	Enabled bool
+
+	// Time in seconds between discovery rounds
+	Interval int
+}
diff --git a/repo/config/init.go b/repo/config/init.go
index 2b4bf2a08..76ee1fdc1 100644
--- a/repo/config/init.go
+++ b/repo/config/init.go
@@ -48,6 +48,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) {
 		SupernodeRouting: *snr,
 		Datastore:        *ds,
 		Identity:         identity,
+		Discovery: Discovery{MDNS{
+			Enabled:  true,
+			Interval: 10,
+		}},
 		Log: Log{
 			MaxSizeMB:  250,
 			MaxBackups: 1,
-- 
GitLab