-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
discovery: swap mdns lib for grandcat/zeroconf #285
Changes from 5 commits
7f7b97b
c5a5cf3
f498105
528f157
da471d9
6651bb9
aaa7f87
a7e8c11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,16 +7,17 @@ import ( | |
"io/ioutil" | ||
golog "log" | ||
"net" | ||
"strings" | ||
"sync" | ||
"time" | ||
|
||
mdns "github.com/grandcat/zeroconf" | ||
logging "github.com/ipfs/go-log" | ||
"github.com/libp2p/go-libp2p-host" | ||
"github.com/libp2p/go-libp2p-peer" | ||
pstore "github.com/libp2p/go-libp2p-peerstore" | ||
ma "github.com/multiformats/go-multiaddr" | ||
manet "github.com/multiformats/go-multiaddr-net" | ||
"github.com/whyrusleeping/mdns" | ||
) | ||
|
||
var log = logging.Logger("mdns") | ||
|
@@ -35,7 +36,7 @@ type Notifee interface { | |
|
||
type mdnsService struct { | ||
server *mdns.Server | ||
service *mdns.MDNSService | ||
service *mdns.Resolver | ||
host host.Host | ||
tag string | ||
|
||
|
@@ -44,62 +45,76 @@ type mdnsService struct { | |
interval time.Duration | ||
} | ||
|
||
func getDialableListenAddrs(ph host.Host) ([]*net.TCPAddr, error) { | ||
var out []*net.TCPAddr | ||
for _, addr := range ph.Addrs() { | ||
// Tries to pick the best port. | ||
func getBestPort(addrs []ma.Multiaddr) (int, error) { | ||
var best *net.TCPAddr | ||
for _, addr := range addrs { | ||
na, err := manet.ToNetAddr(addr) | ||
if err != nil { | ||
continue | ||
} | ||
tcp, ok := na.(*net.TCPAddr) | ||
if ok { | ||
out = append(out, tcp) | ||
if !ok { | ||
continue | ||
} | ||
// Don't bother with multicast and | ||
if tcp.IP.IsMulticast() { | ||
continue | ||
} | ||
// We don't yet support link-local | ||
if tcp.IP.IsLinkLocalUnicast() { | ||
continue | ||
} | ||
// Unspecified listeners are *always* the best choice. | ||
if tcp.IP.IsUnspecified() { | ||
return tcp.Port, nil | ||
} | ||
// If we don't have a best choice, use this addr. | ||
if best == nil { | ||
best = tcp | ||
continue | ||
} | ||
// If the best choice is a loopback address, replace it. | ||
if best.IP.IsLoopback() { | ||
best = tcp | ||
} | ||
} | ||
if len(out) == 0 { | ||
return nil, errors.New("failed to find good external addr from peerhost") | ||
if best == nil { | ||
return 0, errors.New("failed to find good external addr from peerhost") | ||
} | ||
return out, nil | ||
return best.Port, nil | ||
} | ||
|
||
func NewMdnsService(ctx context.Context, peerhost host.Host, interval time.Duration, serviceTag string) (Service, error) { | ||
|
||
// TODO: dont let mdns use logging... | ||
golog.SetOutput(ioutil.Discard) | ||
|
||
var ipaddrs []net.IP | ||
port := 4001 | ||
|
||
addrs, err := getDialableListenAddrs(peerhost) | ||
port, err := getBestPort(peerhost.Network().ListenAddresses()) | ||
if err != nil { | ||
log.Warning(err) | ||
} else { | ||
port = addrs[0].Port | ||
for _, a := range addrs { | ||
ipaddrs = append(ipaddrs, a.IP) | ||
} | ||
return nil, err | ||
} | ||
|
||
myid := peerhost.ID().Pretty() | ||
|
||
info := []string{myid} | ||
if serviceTag == "" { | ||
serviceTag = ServiceTag | ||
} | ||
service, err := mdns.NewMDNSService(myid, serviceTag, "", "", port, ipaddrs, info) | ||
|
||
resolver, err := mdns.NewResolver(nil) | ||
if err != nil { | ||
return nil, err | ||
log.Error("Failed to initialize resolver:", err) | ||
} | ||
|
||
// Create the mDNS server, defer shutdown | ||
server, err := mdns.NewServer(&mdns.Config{Zone: service}) | ||
server, err := mdns.Register(myid, serviceTag, "", port, info, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
s := &mdnsService{ | ||
server: server, | ||
service: service, | ||
service: resolver, | ||
host: peerhost, | ||
interval: interval, | ||
tag: serviceTag, | ||
|
@@ -111,34 +126,32 @@ func NewMdnsService(ctx context.Context, peerhost host.Host, interval time.Durat | |
} | ||
|
||
func (m *mdnsService) Close() error { | ||
return m.server.Shutdown() | ||
m.server.Shutdown() | ||
// grandcat/zerconf swallows error, satisfy interface | ||
return nil | ||
} | ||
|
||
func (m *mdnsService) pollForEntries(ctx context.Context) { | ||
|
||
ticker := time.NewTicker(m.interval) | ||
for { | ||
//execute mdns query right away at method call and then with every tick | ||
entriesCh := make(chan *mdns.ServiceEntry, 16) | ||
go func() { | ||
for entry := range entriesCh { | ||
go func(results <-chan *mdns.ServiceEntry) { | ||
for entry := range results { | ||
m.handleEntry(entry) | ||
} | ||
}() | ||
}(entriesCh) | ||
|
||
log.Debug("starting mdns query") | ||
qp := &mdns.QueryParam{ | ||
Domain: "local", | ||
Entries: entriesCh, | ||
Service: m.tag, | ||
Timeout: time.Second * 5, | ||
} | ||
|
||
err := mdns.Query(qp) | ||
if err != nil { | ||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) | ||
defer cancel() | ||
|
||
if err := m.service.Browse(ctx, m.tag, "local", entriesCh); err != nil { | ||
log.Error("mdns lookup error: ", err) | ||
} | ||
close(entriesCh) | ||
|
||
log.Debug("mdns query complete") | ||
|
||
select { | ||
|
@@ -152,8 +165,10 @@ func (m *mdnsService) pollForEntries(ctx context.Context) { | |
} | ||
|
||
func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) { | ||
log.Debugf("Handling MDNS entry: %s:%d %s", e.AddrV4, e.Port, e.Info) | ||
mpeer, err := peer.IDB58Decode(e.Info) | ||
// pull out the txt | ||
info := strings.Join(e.Text, "|") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this designed to fail if there are less than or more than one entry? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to be clear, because of the decoding afterwards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm. Yeah, that looks wrong. We should just take the first entry and ignore the rest. |
||
|
||
mpeer, err := peer.IDB58Decode(info) | ||
if err != nil { | ||
log.Warning("Error parsing peer ID from mdns entry: ", err) | ||
return | ||
|
@@ -164,25 +179,29 @@ func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) { | |
return | ||
} | ||
|
||
maddr, err := manet.FromNetAddr(&net.TCPAddr{ | ||
IP: e.AddrV4, | ||
Port: e.Port, | ||
}) | ||
if err != nil { | ||
log.Warning("Error parsing multiaddr from mdns entry: ", err) | ||
return | ||
} | ||
for _, ipv4 := range e.AddrIPv4 { | ||
log.Debugf("Handling MDNS entry: %s:%d %s", ipv4, e.Port, info) | ||
|
||
pi := pstore.PeerInfo{ | ||
ID: mpeer, | ||
Addrs: []ma.Multiaddr{maddr}, | ||
} | ||
maddr, err := manet.FromNetAddr(&net.TCPAddr{ | ||
IP: ipv4, | ||
Port: e.Port, | ||
}) | ||
if err != nil { | ||
log.Warning("Error parsing multiaddr from mdns entry: ", err) | ||
return | ||
} | ||
|
||
m.lk.Lock() | ||
for _, n := range m.notifees { | ||
go n.HandlePeerFound(pi) | ||
pi := pstore.PeerInfo{ | ||
ID: mpeer, | ||
Addrs: []ma.Multiaddr{maddr}, | ||
} | ||
|
||
m.lk.Lock() | ||
for _, n := range m.notifees { | ||
go n.HandlePeerFound(pi) | ||
} | ||
m.lk.Unlock() | ||
} | ||
m.lk.Unlock() | ||
} | ||
|
||
func (m *mdnsService) RegisterNotifee(n Notifee) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fixed by #376