[dev_finder] sends requests to multiple addresses
Due to a netstack bug, multiple sockets can't join the same multicast
address. As a temporary workaround, sends mDNS requests to multiple
addresses.
Adds 224.0.0.250 in addition to the current default value 224.0.0.251.
Bug: DX-1453 #comment
Change-Id: I783959100f9abf0fc797215c2dc71e32931b7622
diff --git a/cmd/dev_finder/common.go b/cmd/dev_finder/common.go
index 1a3288e..e74d408 100644
--- a/cmd/dev_finder/common.go
+++ b/cmd/dev_finder/common.go
@@ -58,12 +58,14 @@
Start(ctx context.Context, port int) error
}
-type newMDNSFunc func() mdnsInterface
+type newMDNSFunc func(address string) mdnsInterface
// Contains common command information for embedding in other dev_finder commands.
type devFinderCmd struct {
// Outputs in JSON format if true.
json bool
+ // The mDNS addresses to connect to.
+ mdnsAddrs string
// The mDNS ports to connect to.
mdnsPorts string
// The timeout in ms to either give up or to exit the program after finding at least one
@@ -91,6 +93,7 @@
func (cmd *devFinderCmd) SetCommonFlags(f *flag.FlagSet) {
f.BoolVar(&cmd.json, "json", false, "Outputs in JSON format.")
+ f.StringVar(&cmd.mdnsAddrs, "addr", "224.0.0.251,224.0.0.250", "Comma separated list of addresses to issue mDNS queries to.")
f.StringVar(&cmd.mdnsPorts, "port", "5353,5356", "Comma separated list of ports to issue mDNS queries to.")
f.IntVar(&cmd.timeout, "timeout", 2000, "The number of milliseconds before declaring a timeout.")
f.BoolVar(&cmd.localResolve, "local", false, "Returns the address of the interface to the host when doing service lookup/domain resolution.")
@@ -117,11 +120,11 @@
return nil, errors.New("unsupported address type")
}
-func (cmd *devFinderCmd) newMDNS() mdnsInterface {
+func (cmd *devFinderCmd) newMDNS(address string) mdnsInterface {
if cmd.newMDNSFunc != nil {
- return cmd.newMDNSFunc()
+ return cmd.newMDNSFunc(address)
}
- return &mdns.MDNS{}
+ return &mdns.MDNS{Address: address}
}
func (cmd *devFinderCmd) sendMDNSPacket(ctx context.Context, packet mdns.Packet) ([]*fuchsiaDevice, error) {
@@ -132,30 +135,38 @@
return nil, fmt.Errorf("invalid timeout value: %v", cmd.timeout)
}
+ addrs := strings.Split(cmd.mdnsAddrs, ",")
+ var ports []int
+ for _, s := range strings.Split(cmd.mdnsPorts, ",") {
+ p, err := strconv.ParseUint(s, 10, 16)
+ if err != nil {
+ return nil, fmt.Errorf("Could not parse port number %v: %v\n", s, err)
+ }
+ ports = append(ports, int(p))
+ }
+
ctx, cancel := context.WithTimeout(ctx, time.Duration(cmd.timeout)*time.Millisecond)
defer cancel()
errChan := make(chan error)
devChan := make(chan *fuchsiaDevice)
- for _, p := range strings.Split(cmd.mdnsPorts, ",") {
- m := cmd.newMDNS()
- m.AddHandler(func(recv net.Interface, addr net.Addr, rxPacket mdns.Packet) {
- response := mDNSResponse{recv, addr, rxPacket}
- cmd.mdnsHandler(response, cmd.localResolve, devChan, errChan)
- })
- m.AddErrorHandler(func(err error) {
- errChan <- err
- })
- m.AddWarningHandler(func(addr net.Addr, err error) {
- log.Printf("from: %v warn: %v\n", addr, err)
- })
- i, err := strconv.ParseUint(p, 10, 16)
- if err != nil {
- return nil, fmt.Errorf("Could not parse port number %v: %v\n", p, err)
+ for _, addr := range addrs {
+ for _, p := range ports {
+ m := cmd.newMDNS(addr)
+ m.AddHandler(func(recv net.Interface, addr net.Addr, rxPacket mdns.Packet) {
+ response := mDNSResponse{recv, addr, rxPacket}
+ cmd.mdnsHandler(response, cmd.localResolve, devChan, errChan)
+ })
+ m.AddErrorHandler(func(err error) {
+ errChan <- err
+ })
+ m.AddWarningHandler(func(addr net.Addr, err error) {
+ log.Printf("from: %v warn: %v\n", addr, err)
+ })
+ if err := m.Start(ctx, p); err != nil {
+ return nil, fmt.Errorf("starting mdns: %v", err)
+ }
+ m.Send(packet)
}
- if err := m.Start(ctx, int(i)); err != nil {
- return nil, fmt.Errorf("starting mdns: %v", err)
- }
- m.Send(packet)
}
devices := make([]*fuchsiaDevice, 0)
diff --git a/cmd/dev_finder/dev_finder_test.go b/cmd/dev_finder/dev_finder_test.go
index 6487491..283a86b 100644
--- a/cmd/dev_finder/dev_finder_test.go
+++ b/cmd/dev_finder/dev_finder_test.go
@@ -77,6 +77,35 @@
}
func (m *fakeMDNS) Start(context.Context, int) error { return nil }
+func newDevFinderCmd(handler mDNSHandler, answerDomains []string) devFinderCmd {
+ // Because mdnsAddrs have two addresses specified and mdnsPorts have
+ // two ports specified, four MDNS objects are created. To emulate the
+ // case where only one of them responds, create only one fake MDNS
+ // object with answers. The others wouldn't respond at all. See the
+ // Send() method above.
+ mdnsCount := 0
+ return devFinderCmd{
+ mdnsHandler: handler,
+ mdnsAddrs: "224.0.0.251,224.0.0.250",
+ mdnsPorts: "5353,5356",
+ timeout: 10,
+ newMDNSFunc: func(addr string) mdnsInterface {
+ mdnsCount++
+ switch mdnsCount {
+ case 1:
+ return &fakeMDNS{
+ answer: &fakeAnswer{
+ ip: "192.168.0.42",
+ domains: answerDomains,
+ },
+ }
+ default:
+ return &fakeMDNS{}
+ }
+ },
+ }
+}
+
func compareFuchsiaDevices(d1, d2 *fuchsiaDevice) bool {
return cmp.Equal(d1.addr, d2.addr) && cmp.Equal(d1.domain, d2.domain)
}
@@ -84,34 +113,13 @@
//// Tests for the `list` command.
func TestListDevices(t *testing.T) {
- // Because mdnsPorts have two ports specified, two MDNS objects are
- // created. To emulate the case where only one port responds, create
- // only one fake MDNS object with answers. The other one wouldn't
- // respond at all. See the Start() method above.
- mdnsCount := 0
cmd := listCmd{
- devFinderCmd: devFinderCmd{
- mdnsHandler: listMDNSHandler,
- mdnsPorts: "5353,5356",
- timeout: 10,
- newMDNSFunc: func() mdnsInterface {
- mdnsCount++
- switch mdnsCount {
- case 1:
- return &fakeMDNS{
- answer: &fakeAnswer{
- ip: "192.168.0.42",
- domains: []string{
- "some.domain",
- "another.domain",
- },
- },
- }
- default:
- return &fakeMDNS{}
- }
- },
- },
+ devFinderCmd: newDevFinderCmd(
+ listMDNSHandler,
+ []string{
+ "some.domain",
+ "another.domain",
+ }),
}
got, err := cmd.listDevices(context.Background())
@@ -135,34 +143,13 @@
}
func TestListDevices_domainFilter(t *testing.T) {
- // Because mdnsPorts have two ports specified, two MDNS objects are
- // created. To emulate the case where only one port responds, create
- // only one fake MDNS object with answers. The other one wouldn't
- // respond at all. See the Start() method above.
- mdnsCount := 0
cmd := listCmd{
- devFinderCmd: devFinderCmd{
- mdnsHandler: listMDNSHandler,
- mdnsPorts: "5353,5356",
- timeout: 10,
- newMDNSFunc: func() mdnsInterface {
- mdnsCount++
- switch mdnsCount {
- case 1:
- return &fakeMDNS{
- answer: &fakeAnswer{
- ip: "192.168.0.42",
- domains: []string{
- "some.domain",
- "another.domain",
- },
- },
- }
- default:
- return &fakeMDNS{}
- }
- },
- },
+ devFinderCmd: newDevFinderCmd(
+ listMDNSHandler,
+ []string{
+ "some.domain",
+ "another.domain",
+ }),
domainFilter: "some",
}
@@ -185,34 +172,13 @@
//// Tests for the `resolve` command.
func TestResolveDevices(t *testing.T) {
- // Because mdnsPorts have two ports specified, two MDNS objects are
- // created. To emulate the case where only one port responds, create
- // only one fake MDNS object with answers. The other one wouldn't
- // respond at all. See the Start() method above.
- mdnsCount := 0
cmd := resolveCmd{
- devFinderCmd: devFinderCmd{
- mdnsHandler: resolveMDNSHandler,
- mdnsPorts: "5353,5356",
- timeout: 10,
- newMDNSFunc: func() mdnsInterface {
- mdnsCount++
- switch mdnsCount {
- case 1:
- return &fakeMDNS{
- answer: &fakeAnswer{
- ip: "192.168.0.42",
- domains: []string{
- "some.domain.local",
- "another.domain.local",
- },
- },
- }
- default:
- return &fakeMDNS{}
- }
- },
- },
+ devFinderCmd: newDevFinderCmd(
+ resolveMDNSHandler,
+ []string{
+ "some.domain.local",
+ "another.domain.local",
+ }),
}
got, err := cmd.resolveDevices(context.Background(), "some.domain")