Skip to content

Commit ab4e197

Browse files
tvedpgeorge
authored andcommitted
esp32/modsocket: Fix getaddrinfo to raise on error.
This commit fixes the behaviour of socket.getaddrinfo on the ESP32 so it raises an OSError when the name resolution fails instead of returning a [] or a resolution for 0.0.0.0. Tests are added (generic and ESP32-specific) to verify behaviour consistent with CPython, modulo the different types of exceptions per MicroPython documentation.
1 parent adb6733 commit ab4e197

File tree

3 files changed

+123
-7
lines changed

3 files changed

+123
-7
lines changed

ports/esp32/modsocket.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,19 +244,24 @@ static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struc
244244
int res = _socket_getaddrinfo3(host_str, port_str, &hints, resp);
245245
MP_THREAD_GIL_ENTER();
246246

247+
// Per docs: instead of raising gaierror getaddrinfo raises negative error number
248+
if (res != 0) {
249+
mp_raise_OSError(res > 0 ? -res : res);
250+
}
251+
// Somehow LwIP returns a resolution of 0.0.0.0 for failed lookups, traced it as far back
252+
// as netconn_gethostbyname_addrtype returning OK instead of error.
253+
if (*resp == NULL ||
254+
(strcmp(resp[0]->ai_canonname, "0.0.0.0") == 0 && strcmp(host_str, "0.0.0.0") != 0)) {
255+
mp_raise_OSError(-2); // name or service not known
256+
}
257+
247258
return res;
248259
}
249260

250261
STATIC void _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) {
251262
mp_obj_t *elem;
252263
mp_obj_get_array_fixed_n(addrtuple, 2, &elem);
253-
int res = _socket_getaddrinfo2(elem[0], elem[1], resp);
254-
if (res != 0) {
255-
mp_raise_OSError(res);
256-
}
257-
if (*resp == NULL) {
258-
mp_raise_OSError(-2); // name or service not known
259-
}
264+
_socket_getaddrinfo2(elem[0], elem[1], resp);
260265
}
261266

262267
STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {

tests/esp32/resolve_on_connect.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Test that the esp32's socket module performs DNS resolutions on bind and connect
2+
import sys
3+
4+
if sys.implementation.name == "micropython" and sys.platform != "esp32":
5+
print("SKIP")
6+
raise SystemExit
7+
8+
try:
9+
import usocket as socket, sys
10+
except:
11+
import socket, sys
12+
13+
14+
def test_bind_resolves_0_0_0_0():
15+
s = socket.socket()
16+
try:
17+
s.bind(("0.0.0.0", 31245))
18+
print("bind actually bound")
19+
s.close()
20+
except Exception as e:
21+
print("bind raised", e)
22+
23+
24+
def test_bind_resolves_localhost():
25+
s = socket.socket()
26+
try:
27+
s.bind(("localhost", 31245))
28+
print("bind actually bound")
29+
s.close()
30+
except Exception as e:
31+
print("bind raised", e)
32+
33+
34+
def test_connect_resolves():
35+
s = socket.socket()
36+
try:
37+
s.connect(("micropython.org", 80))
38+
print("connect actually connected")
39+
s.close()
40+
except Exception as e:
41+
print("connect raised", e)
42+
43+
44+
def test_connect_non_existent():
45+
s = socket.socket()
46+
try:
47+
s.connect(("nonexistent.example.com", 80))
48+
print("connect actually connected")
49+
s.close()
50+
except OSError as e:
51+
print("connect raised OSError")
52+
except Exception as e:
53+
print("connect raised", e)
54+
55+
56+
test_funs = [n for n in dir() if n.startswith("test_")]
57+
for f in sorted(test_funs):
58+
print("--", f, end=": ")
59+
eval(f + "()")

tests/net_inet/getaddrinfo.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
try:
2+
import usocket as socket, sys
3+
except:
4+
import socket, sys
5+
6+
7+
def test_non_existent():
8+
try:
9+
res = socket.getaddrinfo("nonexistent.example.com", 80)
10+
print("getaddrinfo returned", res)
11+
except OSError as e:
12+
print("getaddrinfo raised")
13+
14+
15+
def test_bogus():
16+
try:
17+
res = socket.getaddrinfo("hey.!!$$", 80)
18+
print("getaddrinfo returned", res)
19+
except OSError as e:
20+
print("getaddrinfo raised")
21+
except Exception as e:
22+
print("getaddrinfo raised") # CPython raises UnicodeError!?
23+
24+
25+
def test_ip_addr():
26+
try:
27+
res = socket.getaddrinfo("10.10.10.10", 80)
28+
print("getaddrinfo returned resolutions")
29+
except Exception as e:
30+
print("getaddrinfo raised", e)
31+
32+
33+
def test_0_0_0_0():
34+
try:
35+
res = socket.getaddrinfo("0.0.0.0", 80)
36+
print("getaddrinfo returned resolutions")
37+
except Exception as e:
38+
print("getaddrinfo raised", e)
39+
40+
41+
def test_valid():
42+
try:
43+
res = socket.getaddrinfo("micropython.org", 80)
44+
print("getaddrinfo returned resolutions")
45+
except Exception as e:
46+
print("getaddrinfo raised", e)
47+
48+
49+
test_funs = [n for n in dir() if n.startswith("test_")]
50+
for f in sorted(test_funs):
51+
print("--", f, end=": ")
52+
eval(f + "()")

0 commit comments

Comments
 (0)