AlCalzone / node-tradfri-client

Library to talk to IKEA Trådfri Gateways without external binaries
MIT License
264 stars 30 forks source link

discoverGateway returns null when used across vlans(using a mdns reflector) #663

Open HasseJohansen opened 4 months ago

HasseJohansen commented 4 months ago

Hi

After moving my program using node-tradfri-client to another vlan/subnet. It is not able to discover the ikea gateway anymore(it still works when program and gateway are on the same subnet)

I have done some tests with mdns-server used by node-tradfri-client and I think there is some race in that which are causing this issue:

When I just do the same thing as node-tradfri-client does for the discoverGateway function. I never see the answer to the query _coap._udp.local

If I let my test program run still listening for response packets and then do a avahi-browse _coap._udp -d local (after setting up avahi) I can see that mdns-server actually gets the response packet and print it out (with the conditions that you use in node-tradfri-client - that the name should match _coap._udp.local)

I then put in some console.logs in the response part and in the query part. I can then see that we are inside the query part before the response/listening part. So I think mdns-server in some circumstances doesn't listen when the query is sent

Also when using the same testprogram on the same subnet it seems that mdns-server doesn't see all the response packages(I am not quite sure of this, but I think I saw fewer responses than when doing the query via avahi-browse)

I am not a very experienced with development in javascript, but I tried moving the 'ready' event around in mdns-server, but not with great success

This is the small test program I used for mdns-server:

var mdns = require('mdns-server')({
  reuseAddr: true, // in case other mdns service is running
  loopback: false,  // receive our own mdns messages
  noInit: true     // do not initialize on creation
})

domain = '_coap._udp.local'

mdns.on("response", (resp) => {
            console.log("In response");
            const allAnswers = [...resp.answers, ...resp.additionals];
            const result = allAnswers.find(a => a.name === domain);
            if (result != null)
              console.log(result);
});

mdns.on("ready", () => {
            console.log("In query");
            mdns.query([
                { name: domain, type: "A" },
                { name: domain, type: "AAAA" },
                { name: domain, type: "PTR" },
                { name: domain, type: "SRV" },
                { name: domain, type: "TXT" },
            ]);
        });

mdns.initServer();

I then tried to do a test with another mdns npm package bonjour-discovery. That finds the ikea gateway right away when it is run from another subnet. I noticed that it has a referer field in it (maybe mdns-server doesn't handle that this is present). This is the output running from another subnet:

> client = require('bonjour-service');
{
  Bonjour: [class Bonjour],
  Service: [class Service extends EventEmitter],
  Browser: [class Browser extends EventEmitter],
  default: [class Bonjour]
}
> bonjour = new client.Bonjour();
Bonjour {
  server: Server {
    registry: {},
    mdns: EventEmitter {
      _events: [Object: null prototype],
      _eventsCount: 1,
      _maxListeners: 0,
      send: [Function],
      respond: [Function],
      response: [Function],
      query: [Function],
      destroy: [Function],
      update: [Function],
      [Symbol(kCapture)]: false
    },
    errorCallback: [Function]
  },
  registry: Registry {
    services: [],
    server: Server {
      registry: {},
      mdns: [EventEmitter],
      errorCallback: [Function]
    }
  }
}
> bonjour.find({type:'coap',protocol:'udp'}, function (service) {
... console.log('Found an coap gateway:', service)
... })
Browser {
  _events: [Object: null prototype] { up: [Function] },
  _eventsCount: 1,
  _maxListeners: undefined,
  onresponse: [Function],
  serviceMap: {},
  wildcard: false,
  _services: [],
  mdns: EventEmitter {
    _events: [Object: null prototype] {
      query: [Function: bound respondToQuery],
      response: [Function]
    },
    _eventsCount: 2,
    _maxListeners: 0,
    send: [Function],
    respond: [Function],
    response: [Function],
    query: [Function],
    destroy: [Function],
    update: [Function],
    [Symbol(kCapture)]: false
  },
  txt: DnsTxt { binary: undefined },
  name: '_coap._udp.local',
  [Symbol(kCapture)]: false
}
> Found an coap gateway: {
  addresses: [ '192.168.0.27' ],
  subtypes: [],
  rawTxt: [ <Buffer 76 65 72 73 69 6f 6e 3d 31 2e 32 31 2e 33 31> ],
  txt: { version: '1.21.31' },
  name: 'gw-4491602ba33d',
  fqdn: 'gw-4491602ba33d._coap._udp.local',
  host: 'TRADFRI-Gateway-4491602ba33d.local',
  referer: { address: '192.168.8.1', family: 'IPv4', port: 5353, size: 151 },
  port: 5684,
  type: 'coap',
  protocol: 'udp'
}

I am not sure how to proceed(probably a bug report at the mdns-server project), but it seems mdns-server doesn't handle the mdns between different subnets usecase

My current focus is trying to change the discoverGateway part og node-trafri-client to use bonjour-service instead - so I can get my program working (a plugin for the root music server to turn on/off an ikea switch when music plays/doesn't play)

HasseJohansen commented 4 months ago

I probably wasn't thinking straight. Of course the response will be later than the query as it reacts on received packets. Sorry for the confusion