khoih-prog / EthernetWebServer

This is simple yet complete WebServer library for AVR, AVR Dx, Portenta_H7, Teensy, SAM DUE, SAMD21/SAMD51, nRF52, STM32, RP2040-based, etc. boards running Ethernet shields. The functions are similar and compatible to ESP8266/ESP32 WebServer libraries to make life much easier to port sketches from ESP8266/ESP32. Coexisting now with `ESP32 WebServer` and `ESP8266 ESP8266WebServer` libraries. Ethernet_Generic library is used as default for W5x00 with custom SPI
MIT License
178 stars 49 forks source link

Udp Multicast #53

Closed kbssa closed 2 years ago

kbssa commented 2 years ago

Hello,

I am trying to make the UdpSendReceive example work in Multicast mode, it receive all the packets I send, but it never sends the reply message.

The unicast mode works as it should.

I just changed the line Udp.begin(localPort); to Udp.beginMulticast(IPAddress(23,255,255,250),1900);

#include "defines.h"

unsigned int localPort = 1900;    //10002;  // local port to listen on

char packetBuffer[255];          // buffer to hold incoming packet
char ReplyBuffer[] = "ACK";      // a string to send back

// A UDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

void setup()
{
    Serial.begin(115200);
    while (!Serial);

    Serial.print("\nStart UDPSendReceive on "); Serial.print(BOARD_NAME);
    Serial.print(F(" with ")); Serial.println(SHIELD_TYPE);
    Serial.println(ETHERNET_WEBSERVER_VERSION);

    Ethernet.init(5);

    // start the ethernet connection and the server:
    // Use DHCP dynamic IP and random mac
    uint16_t index = millis() % NUMBER_OF_MAC;
    // Use Static IP
    //Ethernet.begin(mac[index], ip);
    Ethernet.begin(mac[index]);

    if (Ethernet.hardwareStatus() == EthernetNoHardware)
    {
        Serial.println("No Ethernet found. Stay here forever");

        while (true)
        {
            delay(1); // do nothing, no point running without Ethernet hardware
        }
    }

    if (Ethernet.linkStatus() == LinkOFF)
    {
        Serial.println("Not connected Ethernet cable");
    }

    Serial.print(F("Using mac index = "));
    Serial.println(index);

    Serial.print(F("Connected! IP address: "));
    Serial.println(Ethernet.localIP());

    Serial.println(F("\nStarting connection to server..."));
    // if you get a connection, report back via serial:
    Udp.beginMulticast(IPAddress(23,255,255,250),1900);

    Serial.print(F("Listening on port "));
    Serial.println(localPort);
}

void loop()
{
    // if there's data available, read a packet
    int packetSize = Udp.parsePacket();

    if (packetSize)
    {
        Serial.print(F("Received packet of size "));
        Serial.println(packetSize);
        Serial.print(F("From "));
        IPAddress remoteIp = Udp.remoteIP();
        Serial.print(remoteIp);
        Serial.print(F(", port "));
        Serial.println(Udp.remotePort());

        // read the packet into packetBufffer
        int len = Udp.read(packetBuffer, 255);

        if (len > 0)
        {
            packetBuffer[len] = 0;
        }

        Serial.println(F("Contents:"));
        Serial.println(packetBuffer);

        // send a reply, to the IP address and port that sent us the packet we received
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write(ReplyBuffer, strlen(ReplyBuffer));
        Udp.endPacket();
    }
}

Is there something missing in the code to make the multicast works ?

khoih-prog commented 2 years ago

First, you have to understand Multicast and Multicast addresses by reading

  1. Multicast_address
  2. FAQ for Multicasting
  3. ClassD Multicast Address

Local subnetwork Addresses in the range of 224.0.0.0 to 224.0.0.255 are individually assigned by IANA and designated for multicasting on the local subnetwork only. For example, the Routing Information Protocol (RIPv2) uses 224.0.0.9, Open Shortest Path First (OSPF) uses 224.0.0.5 and 224.0.0.6, and Multicast DNS uses 224.0.0.251. Routers must not forward these messages outside the subnet from which they originate.

Some more examples how to use UDP Multicast can be found in MDNS_Generic library

#define  MDNS_SERVER_PORT        (5353)
...
static IPAddress mdnsMulticastIPAddr = IPAddress(224, 0, 0, 251);
...
statusCode = this->_udp->beginMulticast(mdnsMulticastIPAddr, MDNS_SERVER_PORT);

Second, you have to at least follow the instructions when creating an issue, with critical information such as

because some Ethernet boards and libraries are not supporting Multicast at all.

Check UDP Multicast supported Ethernet modules / libraries

Without the necessary information, the vague issue will be ignored and deleted next time.

Good Luck,

kbssa commented 2 years ago

Thanks for your fast reply.

Sorry about not providing the necessary information.

Board name and type - esp32 devkit v1 Ethernet board - W5500 Ethernet library - Ethernet

I made a mistake when I was typing the code here, the multicast address I placed is wrong, it is not 23,255,255,250, the correct is 239,255,255,250.

As I mentioned before, the multicast server is receiving all the packets, the problem is that it doesn't reply any message.

I have no idea on why it isn't working.

khoih-prog commented 2 years ago

If you'd like to use UPnP / SSDP, try my UPnP_Generic library to be sure your system (router, network, etc.) is working OK.

https://github.com/khoih-prog/UPnP_Generic/blob/master/src/UPnP_Generic_Impl.h#L805-L852

#define UPNP_SSDP_PORT                    1900
...
IPAddress ipMulti(239, 255, 255, 250);            // multicast address for SSDP
...

bool UPnP::connectUDP()
{

#if UPNP_USING_ETHERNET
  #if USE_BUILTIN_ETHERNET
    #warning Using LAN8742A Ethernet and STM32Ethernet Lib in UPnP
    // For STM32 built-in LAN8742A Ethernet using STM32Ethernet Lib
    // initialize, start listening on specified port. IPAddress here must be local, not ipMulti address
    // virtual uint8_t beginMulticast(IPAddress, uint16_t);
    if (_udpClient.beginMulticast(Ethernet.localIP(), UPNP_SSDP_PORT))
    {
      return true;
    }
  #else
    // initialize, start listening on specified port.
    // virtual uint8_t beginMulticast(IPAddress, uint16_t);
    if (_udpClient.beginMulticast(ipMulti, UPNP_SSDP_PORT))
    {
      return true;
    }
  #endif

#elif UPNP_USING_WT32_ETH01
  if (_udpClient.beginMulticast(ipMulti, UPNP_SSDP_PORT))
  {
    return true;
  }
#else

  #if defined(ESP8266)
    if (_udpClient.beginMulticast(WiFi.localIP(), ipMulti, UPNP_SSDP_PORT))
    {
      return true;
    }
  #else
    if (_udpClient.beginMulticast(ipMulti, UPNP_SSDP_PORT))
    {
      return true;
    }
  #endif

#endif    //UPNP_USING_ETHERNET

  //UPNP_LOGINFO(F("UDP connection failed"));
  UPNP_LOGINFO0(F("F"));

  return false;
}