An update to mDNS (Querries, yay!)

It’s been a week since the last blog post about mDNS and the nodeMCU.
I’ve promised further updates and well here they are.

The bonjour user module can now question other mDNS / bonjour devices for their IP and other info.

A lot has changed in the API, and some more changes will come, but i hope to have covered the major things now. As it is now:

  • requests, responses = bonjour:parse(frame)
    

    will now return request and responses. Some responses are completely parsed (Type A, CNAME and SRV) more types are to come

  • bonjour:create_request({request1, request2, ..})
    

    now generates a mDNS frame containing the requests. A request itself is a table with name, type and class fields. I.e.

    request1 = { name="domain-name.local", type=bonjour.TYPE.A, class=bonjour.CLASS.IN }
    
  • bonjour:create_response({response1, response2, ..})
    

    now generates a mDNS frame containing the requests. A request itself is a table with name, type, class, and ttl filled. I.e.

    response1 = { name="esp-8266.local", type=bonjour.TYPE.A, class=bonjour.CLASS.IN, ttl=64, ip=wifi.sta.getip() }
    
  • Depending on the type, also (A): ip, (CNAME): cname, (SRV): host, port, priority and weight must be present.

  • to fill the fields,
    bonjour.TYPE
    

    and

    bonjour.CLASS
    

    contain the required constants. Named as in RF1035. I.e. bonjour.TYPE.A

  • the field
    bonjour.VERSION
    

    contains a version id (16bit, high byte = mahor, low byte = minor version)

So what?
Querries! 🙂

Want to find other nodeMCU devices running the mDNS responder or your Fruit-Branded Smartphone? Just ask them for their IP now.
mDNS_request_answer

The source file of the bonjour module can be found here.
I have added an extended version of the same mDNS responder lua file for the latest Demo Firmware I had provided with the last demo:

if ((bonjour ~= nil) and (bonjour.VERSION >= 0x0002)) then
  bonjourRequestIP = {}

  if (wifi.sta.getip() == nil) then
    print("mDNS requires an ip address. Please connect to a station.")
  else
    srv = net.createServer(net.UDP)
    conn = net.createConnection(net.UDP, 0)
    conn:connect(5353, "224.0.0.251")
    srv:on("receive", 
    function (s, c)    
      -- get requests from frame
      requests, responses = bonjour:parse(c) 
      if (requests ~= nil) then
      for index, request in pairs(requests) do
        tmr.wdclr() ;
        print("Request mDNS["..index.."]: "..request.name.."(Type: "..request.type..")")
        if ((request.name:lower() == "esp-8266.local") and (request.type == bonjour.TYPE.A)) then
        conn:send (
          bonjour:create_response({{name = request.name, type=bonjour.TYPE.A, class=1, ttl=64, ip=wifi.sta.getip()}})
        )
        end
      end
      end
      if (responses ~= nil) then
      for index, response in pairs(responses) do
        tmr.wdclr() ;
      if (response.type == bonjour.TYPE.A) then
        if (bonjourRequestIP.Name ~= nil) then
          if (bonjourRequestIP.Name:lower() == response.name:lower()) then
            bonjourRequestIP.IP = response.ip
            bonjourRequestIP.Callback(response.ip)
            bonjourRequestIP.Name = nil ;
          else
            print("Response mDNS["..index.."]: "..response.name.."(A: ip="..response.ip..")")
          end
        else
          print("Response mDNS["..index.."]: "..response.name.."(A: ip="..response.ip..")")
        end 
      elseif (response.type == bonjour.TYPE.CNAME) then
        print("Response mDNS["..index.."]: "..response.name.."(CNAME: cname="..response.cname..")")
      else
        print("Response mDNS["..index.."]: "..response.name.."(Type: "..response.type..")")  
      end
      end
      end
    end
    )
    srv:listen(5353)
    net.multicastJoin(wifi.sta.getip(), "224.0.0.251")
  end
  
  
  function RequestBonjourIP(localname, callback)
    bonjourRequestIP.Name = localname
    bonjourRequestIP.Callback = callback
    bonjourRequestIP.IP = ""
          bonjourRequestIP.Retry = 0
    bonjourRequestIP.Done = 0
    conn:send(bonjour:create_request({{name = bonjourRequestIP.Name, type = bonjour.TYPE.A, class=bonjour.CLASS.IN}}))
    tmr.alarm(0,300, 1, 
      function()
        if (bonjourRequestIP.IP == "") then
          if (bonjourRequestIP.Retry > 8) then
            bonjourRequestIP.Done = 1
              bonjourRequestIP.Callback(nil)
            tmr.stop(0)
          end
          conn:send(bonjour:create_request({{name = bonjourRequestIP.Name, type = bonjour.TYPE.A, class=.CLASS.IN}}))
          bonjourRequestIP.Retry = bonjourRequestIP.Retry + 1 ;
        else
          bonjourRequestIP.Done = 1
        end
      end
    )
  end
  
else
  print("mDNS Server requires user module Bonjour v0.02 or higher.") ;
end

A lot of error checking was added and more will be done.
There might be crashes with huge mDNS requests (i.e. a 1010 byte request a local device sends sometimes here seems to trigger a reset) but further investigation is required to rule out that this is simply the watchdog for taking too long or if the request is using up too much memory.

Several mDNS response formats need to be parsed. right now they will be sent and received ignoring their actual payload.

This leaves me to say:
Have fun!

Schreibe einen Kommentar