Skip to content
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

Second mdns instance cannot be started #7213

Closed
BbIKTOP opened this issue Apr 14, 2020 · 32 comments · Fixed by #7217
Closed

Second mdns instance cannot be started #7213

BbIKTOP opened this issue Apr 14, 2020 · 32 comments · Fixed by #7217
Assignees
Milestone

Comments

@BbIKTOP
Copy link
Contributor

BbIKTOP commented Apr 14, 2020

Second mdns instance cannot be created becuase listening sockel listen on inaddr_any (0)
To be able to create second instance you'd probably need to replace
lib/ESP8266mDNS/src/LEAmDNS_Helpers.cpp

if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT))
to something like

if (m_pUDPContext->listen(ip_2_ip4(&m_netif->ip_addr), DNS_MQUERY_PORT))
To prevent err -8 ERR_USE on second instance

@d-a-v
Copy link
Collaborator

d-a-v commented Apr 15, 2020

@BbIKTOP Thanks for the hint !
Did you modify your sources and checked if you can have both instances running with such fix ?

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Apr 15, 2020

@d-a-v yes, sure, I changed this single line and now i have 2 instances running. Also i connected 2 computers, one to the esp ap and another one to the same wifi that esp sta connected to, and observe esp mdns via dns-sd and tcpdump on both computers

@lorol
Copy link

lorol commented Apr 21, 2020

Hi @BbIKTOP there is a little side effect, probably only for me :) . I use a 2nd interface (an extra WiFI adapter) to get all OTA ports populated to Arduino IDE Win10. The LAN (current iface) has troubles (because I use WoL, I guess) so now the ESPs cannot find their way. Just FYI.

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Apr 21, 2020

@lorol Sorry, could you explain further? I can't see how is it related - I mean, what is the influence to the OTA, when mDNS listens on it's interface only? And what exact troubles do you have?

@lorol
Copy link

lorol commented Apr 22, 2020

@BbIKTOP it is my particular problem of having 2x network adapters (2x IPs) on same subnet - on the PC I run ArduinoIDE from. I guess, your implementation is fully correct it just doesn't work for me and I will hold on it. My problem is in PC setup somewhere that makes original LAN adapter inconsistently "seeing" the ESPs on my network. I just plugged an extra WiFi USB stick (no time to fix why the LAN adapter have issues) and all was OK until this change.
Anyway ... again this is another problem but before it worked now it doesn't. That's all.

You can disregard it, no problem. Hope no one else will have weird needs :)

Just from curiosity, why the original code several years was exposing IP4_ADDR_ANY - any reason (other than your testing convenience) to be not limited to &m_netif->ip_addr?

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Apr 22, 2020

Didn’t get it but ok. I suppose, nobody tried to use it on both interfaces simultaneously, i mean on sta and ap. I. e. nobody tried to run 2 instances yet. Have no another versions

@d-a-v d-a-v reopened this May 3, 2020
@d-a-v d-a-v added this to the 2.7.1 milestone May 3, 2020
@lorol
Copy link

lorol commented May 4, 2020

Hi @BbIKTOP FYI, you may be interested to follow these:
#7262
#7266

@devyte devyte modified the milestones: 2.7.1, 2.7.2 May 11, 2020
@d-a-v d-a-v self-assigned this May 11, 2020
@d-a-v
Copy link
Collaborator

d-a-v commented May 11, 2020

@BbIKTOP Have you noticed #7281 ?
Do you think you can try it with your two-interface environment ?
It still offers current LEAmDNS(v1) by default but you can enable the new version by commenting the right ligne in ESP8266mDNS.h.

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented May 11, 2020

Sorry, Dave, bad people want me to do my job. Again. I noticed that and definitely return to it this week. Will let you know, surely. Thank you!

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented May 21, 2020

@BbIKTOP Have you noticed #7281 ?
Do you think you can try it with your two-interface environment ?
It still offers current LEAmDNS(v1) by default but you can enable the new version by commenting the right ligne in ESP8266mDNS.h.

Sorry for delay, still have a lot to do (
Just tested it and it does not work. I observe it on both ifaces only if it has been [re]started after wifi sta got ip number from the network, which is almost ok. But also, it reports the same IP number it has got as a sta, to their clients connected toit as a soft ap, which is obviously wrong.

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented May 21, 2020

@BbIKTOP Have you noticed #7281 ?
Do you think you can try it with your two-interface environment ?
It still offers current LEAmDNS(v1) by default but you can enable the new version by commenting the right ligne in ESP8266mDNS.h.

Let me explain it a bit further (just in case)
I have wifi network with dhcp ip numbers range 172.16.5.0/24
ESP is configured as WIFI_AP_STA, softAP is configured as 10.1.1.0/24 with 10.1.1.1 assigned to softAP itself.
When connected to the WiFi and after it obtained an ip number, for example 172.16.5.99, it is accessible by it's mdns name ok.
Then, I connect a client to it, this client has an ip number 10.1.1.2 assigned by ESP. And this client still receive 172.16.5.99 as a ESP ip number, which is wrong because this network is not reachable
by the client and it shall get 10.1.1.1.
That's it.

@d-a-v
Copy link
Collaborator

d-a-v commented May 22, 2020

By default this PR does not change anything.
There are two testing paths:

First one is to test v2 with Legacy-compatibility:

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder;                // Legacy
//using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder;         // LEA
using MDNSResponder = esp8266::MDNSImplementation::clsLEAMDNSHost_Legacy;   // LEAv2Compat
//using MDNSResponder = clsMDNSHost;                                        // LEAv2

extern MDNSResponder MDNS;
#endif

Second one is the new API. That may or may not compile with your application.
If it doesn't, you may or may not update it for the test.

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder;                // Legacy
//using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder;         // LEA
//using MDNSResponder = esp8266::MDNSImplementation::clsLEAMDNSHost_Legacy; // LEAv2Compat
using MDNSResponder = clsMDNSHost;                                          // LEAv2

extern MDNSResponder MDNS;
#endif

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented May 22, 2020

By default this PR does not change anything.
There are two testing paths:

First one is to test v2 with Legacy-compatibility:

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder;                // Legacy
//using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder;         // LEA
using MDNSResponder = esp8266::MDNSImplementation::clsLEAMDNSHost_Legacy;   // LEAv2Compat
//using MDNSResponder = clsMDNSHost;                                        // LEAv2

extern MDNSResponder MDNS;
#endif

Second one is the new API. That may or may not compile with your application.
If it doesn't, you may or may not update it for the test.

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
// Maps the implementation to use to the global namespace type
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder;                // Legacy
//using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder;         // LEA
//using MDNSResponder = esp8266::MDNSImplementation::clsLEAMDNSHost_Legacy; // LEAv2Compat
using MDNSResponder = clsMDNSHost;                                          // LEAv2

extern MDNSResponder MDNS;
#endif

Please help me understand - do I need to uncomment that? What shall I change in order to test? I have not defined either NO_GLOBAL_INSTANCES nor NO_GLOBAL_MDNS. I wrongly supposed there's some #define that switch new functionality on and off
Shall I uncomment LEAv2 for the new one and LEA for the new compatible one?

@d-a-v
Copy link
Collaborator

d-a-v commented May 22, 2020

By default LEA is uncommented.
LEAv2Legacy is the new one compatible with current one.
You can comment all of them except LEAv2Legacy for a start.

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented May 23, 2020

Tried leav2compat - it is working as supposed, thank you!

Tried leav2 - cannot get it working since there’s no ::registerService(char*,char*,unsigned short), just ::registerService(char*,char*,char*,unsigned short)
Tried both registerService(0,...) and registerService(“someHostname”,...) but cannot see it via bonjour on both softap and wifi networks in any case

@d-a-v
Copy link
Collaborator

d-a-v commented May 23, 2020

@BbIKTOP LEAv2Compat is using LEAv2 and has the same API as LEAv1.

Tried leav2compat - it is working as supposed, thank you!

Thanks for the report !

@ramiws
Copy link

ramiws commented May 24, 2020

I am so lost... so it used to be one instance that works on all interfaces. Then it was restricted, and need to have one instance for each interface. Now the plan is to bring back one instance for all interfaces? In my opinion it should be one instance for all interfaces. It should work smoothly at least for AP_STA. Not sure how it would work for multiple IP interfaces on STA mode. But that seems to be the rare case.

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented May 24, 2020

I am so lost... so it used to be one instance that works on all interfaces. Then it was restricted, and need to have one instance for each interface. Now the plan is to bring back one instance for all interfaces? In my opinion it should be one instance for all interfaces. It should work smoothly at least for AP_STA. Not sure how it would work for multiple IP interfaces on STA mode. But that seems to be the rare case.
It’s a rare case for simple kindergarten apps, school apps and so on use ap_sta mode and 2 ip numbers.

Actually, single instance never worked. I asked for assistance and I’ve been told to use 2 instances. It sounded strange to use different instances on different ifaces, i never heard about such an implementation, also it’s even more strange to have 2 instances on such a resources poor device, but ok, who am i to object.
I tried to run second instance and found then, that running multiple instances is not possible due to inaddr_any binding of listening socket (it is usually not possible to bind multiple listening sockets to the same ip number:port) I started to study sources, they are... let say, a bit overcomplicated, so my first wish was to write my own implementation, bonjour is quite simple protocol, to be honest. But then I found the place in code and thought that I have to complete my project first. So, i changed sources to make each instance bound to it’s interface only. Tested it and it was working.
Then people started to complain they have problems with it. And then project owners decided to “repair” original version to make single instance working on all interfaces, as I asked at the very beginning and how it’s done in all other implementations I know (only 2 really, lol)

@d-a-v
Copy link
Collaborator

d-a-v commented May 24, 2020

@ramiws,

Like @BbIKTOP is telling, a single instance was not properly working under all circumstances with both interface at the same time. There have been several attempts to fix this and the original author @LaborEtArs ended up with providing an updated version in #7281 (not enabled by default) that works with an instance per interface (at least confirmed to be working by @BbIKTOP and me). We may merge it for the soon-to-be-released version 2.7.2 of this core.

I am currently working on stripping this new version to make it working with a single instance for all interfaces (even ethernet interfaces) but it will not be ready for 2.7.2.

@devyte
Copy link
Collaborator

devyte commented Jul 6, 2020

The updated MDNS code is still showing issues and requires more work. Per internal discussions, pushing back to v3.

@devyte devyte modified the milestones: 2.7.2, 3.0.0 Jul 6, 2020
@d-a-v
Copy link
Collaborator

d-a-v commented Oct 15, 2020

In git version, a single mDNS instance will now work on all interfaces. Can you try it ?

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 16, 2020

Sorry, was a bit busy working. Please remind me, is it enough to add lib_deps=https://github.com/esp8266/Arduino in pio to test?

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 16, 2020

Tried it, and looks like it's working. Have esp8266 12e on my custom board, running in WiFi.mode(WIFI_AP_STA); mode, connected to the wifi. Successfully pinging it by .local name from another computer, connected to the same wifi/net. Also, have connected a phone to the esp's wifi sta, and able to ping it by the same name simultaneously.

Didn't I forget to test anything?

@d-a-v
Copy link
Collaborator

d-a-v commented Oct 16, 2020

I believe than you need to use the "stage" configuration in PIO (if that points to the current git master branch).

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 16, 2020

Simply added lib_deps=https://github.com/esp8266/Arduino, because I supposed that it adds current master to the project. To be honest, I am not too familiar with pio. Since it is working, may I assume it uses master and everything is working fine?

@d-a-v
Copy link
Collaborator

d-a-v commented Oct 16, 2020

Didn't I forget to test anything?
may I assume it uses master and everything is working fine?

If you are able to see the advertisement from both networks, then I think this is fine !

Edit: You'll close this issue when you are conviced it is now OK :)

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 16, 2020

Using this code, and ESP hostname 'box':

#include <Arduino.h>

#include <ESP8266mDNS.h>
#include <ESP8266WiFi.h>

#define dPrintf(...)            \
  {                             \
    Serial.printf(__VA_ARGS__); \
    delay(500);                 \
  }

extern char *wifiNet;
extern char *wifiPassword;

char *apName = (char *)"box";
char *apPassword = (char *)"box-12345";
char *apIp = (char *)"10.1.1.1";
char *apMask = (char *)"255.255.255.0";

// MDNSResponder mdnsInt, mdnsExt;

void setup()
{
  int res;

  Serial.begin(115200);
  delay(1000);
  Serial.println("\nStarting mDNS test");

  WiFi.persistent(false);
  WiFi.disconnect();

  WiFi.mode(WIFI_AP_STA);

  IPAddress localIp;
  IPAddress localMask;
  IPAddress localGw;

  localIp.fromString(apIp);
  localMask.fromString(apMask);
  localGw.fromString(apIp);

  res = WiFi.softAP(apName, apPassword); //, 2, false, 20);
  Serial.printf("After softAP: [%s] res=%d, [%s]\n", apName, res, WiFi.localIP().toString().c_str());

  res = WiFi.softAPConfig(localIp, localGw, localMask);
  Serial.printf("After softAPConfig: %d\n", res);

  Serial.printf("After softAP IP: %s\n", WiFi.softAPIP().toString().c_str());

  WiFi.hostname(apName);
  WiFi.setAutoReconnect(true);
  WiFi.begin();

  Serial.printf("Local ip is %s\n", WiFi.softAPIP().toString().c_str());

  if (!MDNS.begin(apName))
  {
    Serial.printf("Cannot start internal mDNS responder\n");
  }
  else
  {
    Serial.printf("Internal mDNS responder started\n");
  }
  MDNS.addService("http", "tcp", 80);
  //MDNS.addService(0, "http", "tcp", 80);

  Serial.println("Started");
}

#define WAIT_COUNT 20
void loop()
{
  static int counter = 0;
  static int counter2 = 0;

  static int lastStatus = WiFi.status();

  dPrintf("Updating MDNS\n");
  MDNS.update();

  Serial.printf("Wifi status=%d, previous status=%d, ip=%s, local ip=%s\n",
                (int)WiFi.status(), lastStatus,
                WiFi.localIP().toString().c_str(),
                WiFi.softAPIP().toString().c_str());

  if (counter++ > WAIT_COUNT)
  {
    if (WiFi.status() == WL_IDLE_STATUS)
    {
      Serial.println("Reconnecting...");
      WiFi.begin(wifiNet, wifiPassword);
      // MDNS.end();
      // MDNS.begin(apName);
      //WiFi.reconnect();
    }

    if (WiFi.status() == WL_CONNECTED && lastStatus != WL_CONNECTED)
    {
      Serial.printf("!!!!!!!!!! Connected, IP is: %s\n", WiFi.localIP().toString().c_str());
      counter = 0;

      //MDNS.end();
      //MDNS.begin(apName);
    }
    lastStatus = WiFi.status();
  }
  if (lastStatus == WL_CONNECTED && WiFi.status() != WL_CONNECTED)
  {
    lastStatus = WiFi.status();
    // MDNS.end();
    // MDNS.begin(apName);
  }

  if (counter2++ > WAIT_COUNT)
  {
    dPrintf("Querying services for int\n");
    // int scInt = MDNS.queryService("http", "tcp");
    //MDNS.notifyAPChange();
  }

  delay(1000);
}

I observe:

  1. From the computer on the same Wi-Fi/IP network, to which ESP is connected as a client:
viktor@Work:~ $ dns-sd -B
Browsing for _http._tcp
DATE: ---Fri 16 Oct 2020---
11:15:33.183  ...STARTING...
Timestamp     A/R    Flags  if Domain               Service Type         Instance Name
11:15:33.183  Add        3   5 local.               _http._tcp.          HIKVISION DS-2CD2363G0-I - C73529589
11:15:33.183  Add        3   5 local.               _http._tcp.          HIKVISION DS-2CD2363G0-I - C73529699
11:15:33.183  Add        2   5 local.               _http._tcp.          PRO-10S
11:16:24.877  Add        2   5 local.               _http._tcp.          box
^C
viktor@Work:~ $ ping box.local
PING box.local (172.16.5.249): 56 data bytes
64 bytes from 172.16.5.249: icmp_seq=0 ttl=255 time=88.192 ms
64 bytes from 172.16.5.249: icmp_seq=1 ttl=255 time=2.854 ms
64 bytes from 172.16.5.249: icmp_seq=2 ttl=255 time=2.167 ms
^C
--- box.local ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 2.167/31.071/88.192/40.392 ms
  1. Phone has been successfully connected to the ESP's Wi-Fi AP, I was able to ping ESP by its name (box.local in this case), and ping utility shows me correct IP from the 10/8 network:
    IMG_4966

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 16, 2020

Please confirm I didn't miss anything, before I close it. Thank you so much!

@d-a-v
Copy link
Collaborator

d-a-v commented Oct 16, 2020

I think nothing is missed !
That's the kind of test we were doing with @hreintke.

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 16, 2020

Well, I'm closing the issue then. Thank you!

@BbIKTOP BbIKTOP closed this as completed Oct 16, 2020
@mcspr
Copy link
Collaborator

mcspr commented Oct 16, 2020

Just to summarize, the correct setup right now is to call MDNS.begin() only once? re. commented out blocks in the example above. I have only tested this briefly, but can also confirm that everything works as expected.

OT, on the same commented out blocks. Needs a new issue I suppose
Looking at the new ::begin() though, I have to assume it would install multiple lwipcb's after calling it more than once? It also never removes those callbacks as it seems, so we end up doing ::_restart() even after ::close() / ::end() was called, allocating UDP all over again?

@BbIKTOP
Copy link
Contributor Author

BbIKTOP commented Oct 17, 2020

These commented out blocks left from the previous testing, but I didn't try ::begin() ::end() in loop() yet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants