Reply to IP of device that broadcast UDP?

Morning.
I have a project on ESP32s that successfully has a single ESP32 that sends a UDP packet of JSON to a broadcast IP. I am using the AsycUDP library.
Multiple receiving ESP32 are DHCP addressed, and successfully receive the packet.

I wish to occasionally reply to the received packet sender, to show connection status.
I tried simply using packet.print(..) in the .onPacket() section of code, but the reply is send to address (0.0.0.0), so obviously the sender IP of the broadcast message has not been correctly extracted, probably because its using the broadcast address ( in this case, 192168.4.255).
I do see the source IP in the sent UDP message using wireshark, so I know its in there somewhere.

Is the actual sending IP included in the packet, and if so, is there a simple way to extract and reply to it?

Thanks, Jim
PS, code samples are available, but the project is very large and I will need to extract the relevant portions of code

using UDP multicast if I transmit from localIP 192.168.4.2 using

  // Multicast UDP -  IPAddress broadcast;
  IPAddress broadcast = IPAddress(224, 0, 0, 1);
  udp.beginPacket(broadcast.toString().c_str(), UDP_PORT);
  int len = udp.write((const uint8_t *)&udpDatagram, sizeof(udpDatagram));
  udp.endPacket();

server uses udp.remoteIP();

  if (udp.parsePacket()) {           // Receive packet and display it
    int len = udp.read((unsigned char*)&udpDatagram, sizeof(udpDatagram));
    Serial.print("UDP datagram received length ");
    Serial.print(len);
    Serial.print(" From ");
    IPAddress remote = udp.remoteIP();
    Serial.print(remote);

server displays the remoteIP 192.168.4.2

ESP32 WiFi AP UDP server - receive UDP datagrams from client
Setting AP (Access Point)…
AP IP address: 192.168.4.1
Listening on UDP port 4210
UDP datagram received length 264 From 192.168.4.2 seq 0
Data 203 78 62 164 0 48 157 171 101 109 141 191 
received crc = 32517

Hi Horace,

I have printed the remote IP as you show, and I too get the correct IP of the sending device.
Why when I use packet.print(....) does it send to (0.0.0.0) and not the correct remote IP?

Jim

This is the sender

void broadcastMsg(String message)
{
  repeatLastMessage.cancel(); // Stop any pending repeats of previous message
#ifdef DEBUG_PRINT
  Serial.printf("Sending Message %s, length=%d (Repeats = %d)\n",message.c_str(), message.length(),repeatCount);
#endif

  uint16_t length = message.length()+1;
  uint8_t buffer[length+2];             // +1 cos its 0 based, +2 for the terminator

  message.getBytes(buffer,length);
  buffer[length+2] = '\0';

  //This initializes udp and transfer buffer
  txUdp.beginPacket(txIp, txPort);
  txUdp.write(buffer, length+1);
  txUdp.endPacket();
  memset(buffer, 0, length+2);
}

and this is the receiver...

void setup()
{
  WiFi.disconnect(true);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid,password);
  //wifiConnect();
    
  if(rxUdp.listen(RX_PORT))
  {
    Serial.printf("Listening for UDP on Port %04d, IP:",RX_PORT);
    Serial.print(WiFi.localIP());
    Serial.print(" MAC: ");
    Serial.println(WiFi.macAddress());

    rxUdp.onPacket([](AsyncUDPPacket packet)
    {
      Serial.print("UDP Packet Type: ");
      Serial.print(packet.isBroadcast()?"Broadcast":packet.isMulticast()?"Multicast":"Unicast");
      Serial.print(", From: ");
      Serial.print(packet.remoteIP().toString().c_str());
      Serial.print(":");
      Serial.print(packet.localPort());
      Serial.print(", To: ");
      Serial.print(packet.localIP());
      Serial.print(":");
      Serial.print(packet.localPort());
      Serial.print(", Length: ");
      Serial.print(packet.length());
      //Serial.print(", Data: ");
      //Serial.write(packet.data(), packet.length());
      Serial.println();
      

      char* tempStr = (char*) malloc (packet.length()+1);
      memcpy (tempStr, packet.data(), packet.length());
      tempStr[packet.length()] = '\0';

      String message = String(tempStr);
      free(tempStr);
      // Serial.println(message);

      handleRxUdp(message);
      
      if (millis() >= (lastMs + REPLY_MS))
      {
        packet.printf("Hello from %s\n",WiFi.macAddress().c_str());
        lastMs = millis();
      }
      
    });
  }

It is the line packet.printf("....") that is sending to IP 0,0,0,0

I also wrote an alternate sending funtction...

void sendUDP(String message, IPAddress sendIP)
{
  Serial.printf("Sending Message %s, length=%d to IP %s\n",message.c_str(), message.length(),sendIP.toString().c_str());

  uint16_t length = message.length()+1;
  uint8_t buffer[length+2];             // +1 cos its 0 based, +2 for the terminator

  message.getBytes(buffer,length);
  buffer[length+2] = '\0';

  //This initializes udp and transfer buffer
  if(txUdp.beginPacket(sendIP.toString().c_str(), txPort)==0)
    Serial.println("Error on beginPacket");
  if(txUdp.write(buffer, length+1)==0)
    Serial.println("Error on writePacket");
  if(txUdp.endPacket()==0)
    Serial.println("Error on endPacket");
  memset(buffer, 0, length+2);
}

but this results in no message being sent from the receiver at all.

How do you check that it is not sent?

server code receives UDP datagrams and transmit a acknowledgement

// ESP32 WiFi AP UDP server - receive UDP datagrams from client

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com
*********/

// Load Wi-Fi library
#include <WiFi.h>
#include <AsyncUDP.h>

// Replace with your network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

#define UDP_PORT 4210
//create UDP instance
WiFiUDP udp;

// UDP Datagram
struct UDPDatagram {
  unsigned long int seq;  // sequence number
  char data[256];         // data
  unsigned short crc;     // crc check
} udpDatagram;

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  delay(1000);
  Serial.println();
  Serial.println("ESP32 WiFi AP UDP server - receive UDP datagrams from client");
  Serial.print("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("\nAP IP address: ");
  Serial.println(IP);
  udp.begin(UDP_PORT);  // Begin listening to UDP port
  Serial.print("Listening on UDP port ");
  Serial.println(UDP_PORT);
}

// receive datagram and check and display contents
void loop() {
  static unsigned long int seq = 0;  // to force seq error check set this none zero
  if (udp.parsePacket()) {           // Receive packet and display it
    int len = udp.read((unsigned char*)&udpDatagram, sizeof(udpDatagram));
    Serial.print("UDP datagram received length ");
    Serial.print(len);
    Serial.print(" From ");
    IPAddress remote = udp.remoteIP();
    Serial.print(remote);
    Serial.print(" seq ");
    Serial.print((int)udpDatagram.seq);
    if (seq != udpDatagram.seq) {
      Serial.print(" Sequence ERROR! expected ");
      Serial.print(seq);
    }
    seq = ++udpDatagram.seq;
    Serial.print("\nData ");
    unsigned short crc = 0;  // to force crc error check set this none zero
    for (int i = 0; i < sizeof(udpDatagram.data); i++) {
      Serial.print((int)udpDatagram.data[i]);
      Serial.print(' ');
      crc += udpDatagram.data[i];
    }
    Serial.print("\nreceived crc = ");
    Serial.print(udpDatagram.crc);
    if (crc != udpDatagram.crc) {
      Serial.print(" CRC ERROR! calculated ");
      Serial.println(crc);
    }
    Serial.println();
    // send reply
    udp.beginPacket(udp.remoteIP(), UDP_PORT);
    // Send Packet to UDP server running on Gateway
    // udp.beginPacket(WiFi.gatewayIP().toString().c_str(), UDP_PORT);
    char reply[100];
    snprintf(reply, 100,  "seq %d received OK\n",  udpDatagram.seq );;
    udp.write((const uint8_t*)reply, strlen(reply)+1);
    udp.endPacket();
  }
}

client code multicasts UDP packets

// Arduino TCP server listen for connection and display messages

//  from https://github.com/evothings/evothings-examples/blob/master/examples/arduino-led-onoff-tcp/arduinowifi/arduinowifi/arduinowifi.ino

// ESP32 WiFi UDP client - send UDP datagrams to server

#include <WiFi.h>
#include <AsyncUDP.h>

// Remove this line once you've entered WiFi SSID and password below.
//#error "WiFi SSID and password required!"

// network SSID (network name). and network password.
char ssid[] = "ESP32-Access-Point";
char pass[] = "123456789";

// network key Index number (needed only for WEP).
int keyIndex = 0;

// UDP information
#define UDP_PORT 4210
WiFiUDP udp;

// UDP Datagram
struct UDPDatagram {
  long int seq;        // sequence number
  char data[256];      // data
  unsigned short crc;  // crc check
} udpDatagram;

void setup() {
  Serial.begin(115200);
  // Wait for serial port to connect. Needed for Leonardo only
  while (!Serial)
    ;
  delay(1000);
  Serial.println();
  Serial.println("ESP32 WiFi UDP client - send UDP datagrams to server");
  WiFi.mode(WIFI_STA);  // Connect to Wifi network.
  WiFi.begin(ssid, pass);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nGateway IP address: ");
  Serial.println(WiFi.gatewayIP());
  Serial.print("local IP address: ");
  Serial.println(WiFi.localIP());
  // Begin udp port
  udp.begin(UDP_PORT);
  Serial.print("Opening udp port ");
  Serial.println(UDP_PORT);
}

void loop() {
  // generate crc check
  Serial.print("\ntransitting Datagram data ");
  udpDatagram.crc = 0;
  for (int i = 0; i < sizeof(udpDatagram.data); i++) {
    udpDatagram.data[i] = rand() % 255;
    Serial.print((int)udpDatagram.data[i]);
    Serial.print(' ');
    udpDatagram.crc += udpDatagram.data[i];
  }
  // Multicast UDP -  IPAddress broadcast;
  IPAddress broadcast = IPAddress(224, 0, 0, 1);
  udp.beginPacket(broadcast.toString().c_str(), UDP_PORT);
  // Send Packet to UDP server running on Gateway
  // udp.beginPacket(WiFi.gatewayIP().toString().c_str(), UDP_PORT);
  int len = udp.write((const uint8_t *)&udpDatagram, sizeof(udpDatagram));
  udp.endPacket();
  Serial.print("\nudp datagram transmitted length ");
  Serial.print(len);
  Serial.print(" seq ");
  Serial.print(udpDatagram.seq++);
  Serial.print(" crc = ");
  Serial.println(udpDatagram.crc);
  // check for replay from server
  if (udp.parsePacket()) {  // Receive packet and display it
    char data[200] = { 0 };
    int len = udp.read((unsigned char *)&data, sizeof(data));
    Serial.print("UDP datagram received length ");
    Serial.print(len);
    Serial.print(" From ");
    IPAddress remote = udp.remoteIP();
    Serial.print(remote);
    Serial.print(" data  ");
    Serial.print(data);
  }
  delay(5000);
}

server output

ESP32 WiFi AP UDP server - receive UDP datagrams from client
Setting AP (Access Point)…
AP IP address: 192.168.4.1
Listening on UDP port 4210
UDP datagram received length 264 From 192.168.4.2 seq 0
Data 203 78 62 164 0 48 157 171 101 109 141 191 228 185 63 53 75 201 224 212 232 107 77 248 130 43 24 102 24 244 246 242 250 204 30 80 74 170 37 89 198 156 90 36 61 156 129 157 130 36 140 174 129 100 144 60 72 221 78 19 174 40 164 185 106 32 127 8 10 89 164 135 240 224 27 34 152 224 66 249 131 254 18 180 7 56 119 44 142 80 233 198 211 115 60 217 70 46 113 56 72 22 11 158 157 6 20 140 193 171 201 89 187 154 57 120 228 186 63 117 156 52 108 254 165 45 140 113 127 254 238 152 76 225 125 177 253 46 153 152 78 108 148 248 130 3 48 120 11 221 252 155 4 247 88 18 248 45 134 170 188 52 100 217 187 235 210 240 240 191 162 175 15 192 119 86 93 26 104 60 235 225 172 34 61 206 217 173 25 195 38 63 14 101 164 35 235 147 143 24 80 250 203 160 190 100 0 45 199 3 218 123 214 50 221 46 99 63 175 237 254 10 4 254 140 42 102 0 172 73 216 125 147 122 0 48 208 3 87 80 217 216 2 86 224 89 8 242 1 150 195 51 139 236 45 210 
received crc = 32517
UDP datagram received length 264 From 192.168.4.2 seq 1
Data 139 111 19 72 169 29 247 75 163 157 106 237 153 7 162 38 150 217 26 31 94 213 176 127 251 115 148 193 189 120 2 18 75 154 139 200 84 240 93 111 191 34 41 82 167 227 114 5 211 103 65 193 21 72 242 3 142 37 24 73 155 14 72 236 92 247 105 173 110 238 181 96 237 192 217 123 120 64 90 175 1 81 183 169 113 238 185 24 233 204 8 36 177 71 69 169 118 130 119 150 47 218 161 173 93 29 180 24 74 98 139 168 231 201 81 39 252 222 235 241 72 107 77 223 36 14 44 172 7 119 163 191 153 60 251 159 251 41 74 68 78 192 24 22 151 168 120 254 139 54 245 143 183 239 232 17 47 201 174 247 243 219 193 228 147 119 222 193 151 116 195 117 63 113 148 193 200 244 184 78 241 149 121 126 50 112 30 154 55 51 41 89 246 190 151 153 63 65 198 181 10 169 72 12 201 52 72 22 204 131 222 24 10 221 236 87 113 65 20 141 62 36 164 225 207 7 155 128 203 25 12 154 209 236 22 100 15 226 124 92 21 165 151 200 65 146 192 88 248 141 78 206 163 14 233 133 
received crc = 33192
UDP datagram received length 264 From 192.168.4.2 seq 2
Data 77 251 48 118 42 121 129 7 67 162 230 53 213 59 37 197 193 141 52 182 213 227 199 46 75 85 150 223 234 241 65 135 39 219 58 83 239 156 159 52 64 66 239 191 122 98 60 199 129 185 108 152 250 218 96 27 50 214 58 247 41 119 207 176 186 52 56 62 79 76 197 17 88 190 13 135 198 70 177 124 143 241 122 176 198 99 220 29 182 13 31 131 76 173 165 245 129 217 66 208 6 178 196 192 57 13 157 152 163 234 140 73 79 19 194 41 54 136 181 253 115 33 57 178 136 234 159 188 203 14 205 21 13 254 6 202 28 179 30 250 87 106 45 159 70 243 18 67 224 127 190 231 11 180 143 232 163 135 141 77 119 220 191 167 37 237 163 111 135 134 186 0 37 69 40 247 152 45 147 208 57 167 229 190 212 82 173 178 23 78 10 225 34 24 103 125 82 89 180 138 83 43 108 204 1 180 182 78 50 62 39 230 49 230 4 79 142 155 222 75 177 10 103 83 245 43 104 205 159 246 51 225 75 181 8 122 18 101 135 52 119 226 181 205 174 133 65 90 149 229 183 84 117 102 44 121 
received crc = 32674

client output

ESP32 WiFi UDP client - send UDP datagrams to server

.
Gateway IP address: 192.168.4.1
local IP address: 192.168.4.2
Opening udp port 4210

transitting Datagram data 203 78 62 164 0 48 157 171 101 109 141 191 228 185 63 53 75 201 224 212 232 107 77 248 130 43 24 102 24 244 246 242 250 204 30 80 74 170 37 89 198 156 90 36 61 156 129 157 130 36 140 174 129 100 144 60 72 221 78 19 174 40 164 185 106 32 127 8 10 89 164 135 240 224 27 34 152 224 66 249 131 254 18 180 7 56 119 44 142 80 233 198 211 115 60 217 70 46 113 56 72 22 11 158 157 6 20 140 193 171 201 89 187 154 57 120 228 186 63 117 156 52 108 254 165 45 140 113 127 254 238 152 76 225 125 177 253 46 153 152 78 108 148 248 130 3 48 120 11 221 252 155 4 247 88 18 248 45 134 170 188 52 100 217 187 235 210 240 240 191 162 175 15 192 119 86 93 26 104 60 235 225 172 34 61 206 217 173 25 195 38 63 14 101 164 35 235 147 143 24 80 250 203 160 190 100 0 45 199 3 218 123 214 50 221 46 99 63 175 237 254 10 4 254 140 42 102 0 172 73 216 125 147 122 0 48 208 3 87 80 217 216 2 86 224 89 8 242 1 150 195 51 139 236 45 210 
udp datagram transmitted length 264 seq 0 crc = 32517

transitting Datagram data 139 111 19 72 169 29 247 75 163 157 106 237 153 7 162 38 150 217 26 31 94 213 176 127 251 115 148 193 189 120 2 18 75 154 139 200 84 240 93 111 191 34 41 82 167 227 114 5 211 103 65 193 21 72 242 3 142 37 24 73 155 14 72 236 92 247 105 173 110 238 181 96 237 192 217 123 120 64 90 175 1 81 183 169 113 238 185 24 233 204 8 36 177 71 69 169 118 130 119 150 47 218 161 173 93 29 180 24 74 98 139 168 231 201 81 39 252 222 235 241 72 107 77 223 36 14 44 172 7 119 163 191 153 60 251 159 251 41 74 68 78 192 24 22 151 168 120 254 139 54 245 143 183 239 232 17 47 201 174 247 243 219 193 228 147 119 222 193 151 116 195 117 63 113 148 193 200 244 184 78 241 149 121 126 50 112 30 154 55 51 41 89 246 190 151 153 63 65 198 181 10 169 72 12 201 52 72 22 204 131 222 24 10 221 236 87 113 65 20 141 62 36 164 225 207 7 155 128 203 25 12 154 209 236 22 100 15 226 124 92 21 165 151 200 65 146 192 88 248 141 78 206 163 14 233 133 
udp datagram transmitted length 264 seq 1 crc = 33192
UDP datagram received length 19 From 192.168.4.1 data  seq 1 received OK

transitting Datagram data 77 251 48 118 42 121 129 7 67 162 230 53 213 59 37 197 193 141 52 182 213 227 199 46 75 85 150 223 234 241 65 135 39 219 58 83 239 156 159 52 64 66 239 191 122 98 60 199 129 185 108 152 250 218 96 27 50 214 58 247 41 119 207 176 186 52 56 62 79 76 197 17 88 190 13 135 198 70 177 124 143 241 122 176 198 99 220 29 182 13 31 131 76 173 165 245 129 217 66 208 6 178 196 192 57 13 157 152 163 234 140 73 79 19 194 41 54 136 181 253 115 33 57 178 136 234 159 188 203 14 205 21 13 254 6 202 28 179 30 250 87 106 45 159 70 243 18 67 224 127 190 231 11 180 143 232 163 135 141 77 119 220 191 167 37 237 163 111 135 134 186 0 37 69 40 247 152 45 147 208 57 167 229 190 212 82 173 178 23 78 10 225 34 24 103 125 82 89 180 138 83 43 108 204 1 180 182 78 50 62 39 230 49 230 4 79 142 155 222 75 177 10 103 83 245 43 104 205 159 246 51 225 75 181 8 122 18 101 135 52 119 226 181 205 174 133 65 90 149 229 183 84 117 102 44 121 
udp datagram transmitted length 264 seq 2 crc = 32674
UDP datagram received length 19 From 192.168.4.1 data  seq 2 received OK

transitting Datagram data 18 108 20 117 23 203 174 89 150 60 71 4 85 70 124 197 155 201 59 114 223 21 203 155 143 147 181 143 61 67 36 191 118 219 169 20 242 132 200 97 56 58 2 129 213 206 239 223 12 17 163 215 103 139 247 1 89 215 105 159 43 9 17 191 15 220 205 156 75 154 139 177 143 133 6 44 108 151 37 13 24 226 218 160 194 210 187 201 214 198 249 123 224 209 249 182 253 228 71 59 127 134 76 137 183 44 253 94 100 80 77 77 96 157 123 193 75 235 35 247 189 229 116 244 168 211 98 249 238 143 131 73 127 71 254 50 216 78 93 222 247 41 213 188 41 47 212 55 144 154 242 83 163 197 25 203 24 10 191 172 62 67 15 75 195 15 64 211 71 228 110 188 79 49 50 158 67 250 110 213 113 55 146 56 73 71 173 53 131 117 199 1 222 163 196 39 153 56 254 18 83 201 113 243 39 37 124 225 36 62 7 105 235 82 183 219 251 79 223 98 175 147 58 195 26 36 100 177 39 109 141 69 145 18 48 53 138 167 100 109 121 192 27 198 147 179 117 20 237 225 101 26 111 203 157 55 
udp datagram transmitted length 264 seq 3 crc = 32888
UDP datagram received length 19 From 192.168.4.1 data  seq 3 received OK

the client appears to receive acknowledgements for server OK

I look for the messages in wireshark

Do I need to set up a udplisten() in the sender for it to be able to make the initial connection back to the sender?

Please use AsyncUDP.h, that library actually works.

UDP is a connectionless protocol you just transmit packets to an IP address - they may get there may not

I have this in my code:

//-------------------------------------------------------
// UDPHANDLER - RECEIVER + SENDER
//-------------------------------------------------------
void init_udphandler() {
  static bool listening = false;
  if (listening) {
    udphandler.close();
  }
  IPAddress ip;
  if ((strlen(eeprom.multicast) > 4) && (ip.fromString(eeprom.multicast))) {
    udphandler.listenMulticast(ip, eeprom.port);
  } else {
    udphandler.listen(eeprom.port);
  }
  udphandler.onPacket(udp_receiver);
  listening = true;
}

Thats what I thought...

I am using AsyncUDP.h for the listener, and it is working fine, except that when I receive a packet, to send a reply, if I do

packet.print(".....")

it sends to IP 0.0.0.0 instead of the received from IP.

updated code of post 5 to use AsyncUDP.h - program output same

I see that you are both using multicast and not broadcast... I wonder if this is making the difference.

I might just broadcast the reply (BroadcstTo is working) but with a different port number.

There is no big difference, it just helps to keep things seperate. My code uses both and you can configure what to use.

But in my code iside the udp:receiver function I set a global variable and save the senders IP:

sender = packet.remoteIP();

And inside the loop() after some logic:

if (WiFi.status() == WL_CONNECTED) {
  if (sender) {
    static char s[1024];
    snprintf(s, sizeof(s), "%s %d", eeprom.name, 100 + WiFi.RSSI());
    udphandler.writeTo((uint8_t*)s, strlen(s) + 1, sender, eeprom.port);
  }
}

Well Ive solved my problem with a workaround, but I still dont know why the original isn't working.

For the reply, I simply use udp.BroadcastTo(message,port)
I have specified a different port to all the messages going in the other direction so that the receivers don't have to process all the replies, regardless that they are to the broadcast IP.

It works, but it irks me that I couldn't simply reply to the incoming packet with the received IP.
I'm sort of suspicious that its a problem with the sent IP being the broadcast address...

Thanks for the ideas,
Jim

How did you manage to send the packages from the broadcasting address? IMO you send it to the broadcasting address.

I sent the UDP to aqddress (in this case) 192.168.4.255
All ESPs on subnet 192.168.4.x receive the message correctly, and I can decode packet.remoteIp correctly. (192.168.4.2)
I try and write a UDP message using packet.printf and it is sent to IP 0.0.0,0 and not packet.remoteIp

How do you specify the recerivers address and port in your code?

I had some issues with this as well, one thing that is important is to remember that an IPaddress is a pointer to an array. So when copying an IPaddress, you need to copy the fields of the array.

on an ESP32 IPAddress is a class with several operator overloads. There is also an overload for the =.
Hence you can copy a IPaddress with a simple assignment.

void setup() {
  Serial.begin(115200);
  delay(100);
  IPAddress server {192, 168, 1, 1};
  IPAddress copy;
  copy = server;
  Serial.println(copy);
}

void loop(){
  delay(10);
}

see also: