← index #12842Issue #4029
Related · high · value 2.908
QUERY · ISSUE

esp32: UDP sendto causes memory leaks/ENOMEM error for most IP addresses

openby tangentmongeropened 2023-10-31updated 2024-02-17
bug

I'm trying to send UDP packets using socket.sendto(). I would expect this to succeed regardless of the destination IP address, but for most addresses this fails after exactly four packets with OSError ENOMEM. I do not see this exception when sending to the board's own IP or the broadcast address.

Hardware: ESP32 on an Olimex ESP32-PoE-ISO board, connected to a switch that has nothing else connected to it (as a minimal test setup).

ESPtool identifies the chip as ESP32D0WDQ5 (revision 3).

Firmware: OLIMEX_ESP32_POE-20231005-v1.21.0.bin

Version in REPL: MicroPython v1.21.0 on 2023-10-06; Olimex ESP32 ETH with ESP32

#4029 is a similar issue but uses WiFi and instead affects broadcast only. I'm seeing the opposite behavior.

This code example attempts to send 100 packets to IPs from 192.168.4.0 through to 192.168.4.255. This succeeds for IPs 192.168.4.250 (the board's own IP) and 192.168.4.255 (broadcast) but fails for every other address after the fourth attempt with OSError 12, ENOMEM.

import socket
import network
import machine
import time

lan = network.LAN(mdc=machine.Pin(23), mdio=machine.Pin(18), power=machine.Pin(12),
                  phy_type=network.PHY_LAN8720, phy_addr=0)
try:
    lan.active(True)
except OSError as ex:
    if ex.value == "ethernet enable failed":
        print("Failed to enable ethernet - waiting a few seconds and doing a hardware reset.")
        time.sleep(2)
        machine.reset()
    raise

my_ip = '192.168.4.250'
lan.ifconfig((my_ip, '255.255.255.0', '192.168.4.1', '192.168.4.1'))

sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock1.bind((my_ip, 10005))

buf = "hello"
port = 10000

for x in range(0, 256):
    try:
        for test in range(0, 100):
            sock1.sendto(buf, (f"192.168.4.{x}", port))
        print(f"192.168.4.{x}:{port}: PASS")
    except OSError as e:
        print(f"192.168.4.{x}:{port}: FAIL after {test+1} attempts with {e}")

Output:

192.168.4.0:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.1:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.2:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.3:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.4:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
...
192.168.4.248:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.249:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.250:10000: PASS
192.168.4.251:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.252:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.253:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.254:10000: FAIL after 4 attempts with [Errno 12] ENOMEM
192.168.4.255:10000: PASS

My next step is to dig into the MicroPython and IDF code, would appreciate any advice on tests to try.

CANDIDATE · ISSUE

esp32: UDP broadcast via sendto causes memory leaks/ENOMEM error

openby dir-abletonopened 2018-08-06updated 2020-06-11
port-esp32

I described this in the uP forum:

https://forum.micropython.org/viewtopic.php?f=18&t=5063&p=28953#p28953

on further investigation, I found that commenting out

https://github.com/micropython/micropython/blob/master/ports/esp32/modsocket.c#L485

made the problem disappear - by disabling the actual functionality of course. To my uninitiated eye, this looks like a SDK issue, but at the same time there seems to be some dependency to the gc calls as documented in the forum post. Any suggestions on to get to the bottom of this?

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied