Skip to content

Commit eaa6f99

Browse files
committed
Add v6 address support to SocketPool.getaddrinfo (on espressif)
1 parent 2f62612 commit eaa6f99

File tree

5 files changed

+122
-18
lines changed

5 files changed

+122
-18
lines changed

ports/espressif/common-hal/socketpool/SocketPool.c

Lines changed: 103 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,37 +22,122 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel
2222

2323
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
2424

25-
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
26-
const char *host) {
27-
25+
static int getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) {
2826
// As of 2022, the version of lwip in esp-idf does not handle the
2927
// trailing-dot syntax of domain names, so emulate it.
3028
// Remove this once https://github.com/espressif/esp-idf/issues/10013 has
3129
// been implemented
32-
size_t strlen_host = strlen(host);
33-
if (strlen_host && host[strlen_host - 1] == '.') {
34-
mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1);
35-
host = mp_obj_str_get_str(nodot);
30+
if (host) {
31+
size_t strlen_host = strlen(host);
32+
if (strlen_host && host[strlen_host - 1] == '.') {
33+
mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1);
34+
host = mp_obj_str_get_str(nodot);
35+
}
36+
}
37+
38+
char service_buf[6];
39+
snprintf(service_buf, sizeof(service_buf), "%d", service);
40+
41+
return lwip_getaddrinfo(host, service_buf, hints, res);
42+
}
43+
44+
static mp_obj_t format_address(const struct sockaddr *addr, int family) {
45+
char ip_str[IPADDR_STRLEN_MAX]; // big enough for any supported address type
46+
const struct sockaddr_in *a = (void *)addr;
47+
48+
switch (family) {
49+
#if CIRCUITPY_SOCKETPOOL_IPV6
50+
case AF_INET6:
51+
inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str));
52+
break;
53+
#endif
54+
default:
55+
case AF_INET:
56+
inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str));
57+
break;
3658
}
59+
return mp_obj_new_str(ip_str, strlen(ip_str));
60+
}
61+
62+
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
63+
const char *host) {
3764

3865
const struct addrinfo hints = {
3966
.ai_family = AF_INET,
4067
.ai_socktype = SOCK_STREAM,
4168
};
42-
struct addrinfo *res;
43-
int err = lwip_getaddrinfo(host, NULL, &hints, &res);
69+
struct addrinfo *res = NULL;
70+
int err = getaddrinfo_common(host, 0, &hints, &res);
4471
if (err != 0 || res == NULL) {
4572
return mp_const_none;
4673
}
4774

48-
#pragma GCC diagnostic push
49-
#pragma GCC diagnostic ignored "-Wcast-align"
50-
struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
51-
#pragma GCC diagnostic pop
52-
char ip_str[IP4ADDR_STRLEN_MAX];
53-
inet_ntoa_r(*addr, ip_str, IP4ADDR_STRLEN_MAX);
54-
mp_obj_t ip_obj = mp_obj_new_str(ip_str, strlen(ip_str));
55-
lwip_freeaddrinfo(res);
75+
nlr_buf_t nlr;
76+
if (nlr_push(&nlr) == 0) {
77+
mp_obj_t result = format_address(res->ai_addr, res->ai_family);
78+
nlr_pop();
79+
lwip_freeaddrinfo(res);
80+
return result;
81+
} else {
82+
lwip_freeaddrinfo(res);
83+
nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
84+
};
85+
}
86+
87+
#if CIRCUITPY_SOCKETPOOL_IPV6
88+
static mp_obj_t convert_sockaddr(const struct addrinfo *ai, int port) {
89+
mp_int_t n_tuple = ai->ai_family == AF_INET6 ? 4 : 2;
90+
mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_tuple, NULL));
91+
result->items[0] = format_address(ai->ai_addr, ai->ai_family);
92+
result->items[1] = MP_OBJ_NEW_SMALL_INT(port);
93+
if (ai->ai_family == AF_INET6) {
94+
const struct sockaddr_in6 *ai6 = (void *)ai->ai_addr;
95+
result->items[2] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_flowinfo);
96+
result->items[3] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_scope_id);
97+
}
98+
return result;
99+
}
56100

57-
return ip_obj;
101+
static mp_obj_t convert_addrinfo(const struct addrinfo *ai, int port) {
102+
MP_STATIC_ASSERT(AF_INET == SOCKETPOOL_AF_INET);
103+
MP_STATIC_ASSERT(AF_INET6 == SOCKETPOOL_AF_INET6);
104+
// MP_STATIC_ASSERT(AF_UNSPEC == SOCKETPOOL_AF_UNSPEC);
105+
mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
106+
result->items[0] = MP_OBJ_NEW_SMALL_INT(ai->ai_family);
107+
result->items[1] = MP_OBJ_NEW_SMALL_INT(ai->ai_socktype);
108+
result->items[2] = MP_OBJ_NEW_SMALL_INT(ai->ai_protocol);
109+
result->items[3] = ai->ai_canonname ? mp_obj_new_str(ai->ai_canonname, strlen(ai->ai_canonname)) : MP_OBJ_NEW_QSTR(MP_QSTR_);
110+
result->items[4] = convert_sockaddr(ai, port);
111+
return result;
112+
}
113+
114+
mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags) {
115+
MP_STATIC_ASSERT(LWIP_IPV6);
116+
const struct addrinfo hints = {
117+
.ai_flags = flags,
118+
.ai_family = family,
119+
.ai_protocol = proto,
120+
.ai_socktype = type,
121+
};
122+
123+
struct addrinfo *res = NULL;
124+
int err = getaddrinfo_common(host, port, &hints, &res);
125+
if (err != 0 || res == NULL) {
126+
common_hal_socketpool_socketpool_raise_gaierror_noname();
127+
}
128+
129+
nlr_buf_t nlr;
130+
if (nlr_push(&nlr) == 0) {
131+
mp_obj_t result = mp_obj_new_list(0, NULL);
132+
for (struct addrinfo *ai = res; ai; ai = ai->ai_next) {
133+
mp_obj_list_append(result, convert_addrinfo(ai, port));
134+
}
135+
nlr_pop();
136+
lwip_freeaddrinfo(res);
137+
return result;
138+
} else {
139+
lwip_freeaddrinfo(res);
140+
nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val));
141+
}
58142
}
143+
#endif

ports/espressif/mpconfigport.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ CIRCUITPY_SYNTHIO_MAX_CHANNELS ?= 12
4949
CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1
5050
CIRCUITPY_WATCHDOG ?= 1
5151
CIRCUITPY_WIFI ?= 1
52+
CIRCUITPY_SOCKETPOOL_IPV6 ?= 1
5253

5354
# Enable _eve module
5455
CIRCUITPY__EVE ?= 1

py/circuitpy_mpconfig.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@ CFLAGS += -DCIRCUITPY_SKIP_SAFE_MODE_WAIT=$(CIRCUITPY_SKIP_SAFE_MODE_WAIT)
496496
CIRCUITPY_SOCKETPOOL ?= $(CIRCUITPY_WIFI)
497497
CFLAGS += -DCIRCUITPY_SOCKETPOOL=$(CIRCUITPY_SOCKETPOOL)
498498

499+
CIRCUITPY_SOCKETPOOL_IPV6 ?= 0
500+
CFLAGS += -DCIRCUITPY_SOCKETPOOL_IPV6=$(CIRCUITPY_SOCKETPOOL_IPV6)
501+
499502
CIRCUITPY_SSL ?= $(CIRCUITPY_WIFI)
500503
CFLAGS += -DCIRCUITPY_SSL=$(CIRCUITPY_SSL)
501504

shared-bindings/socketpool/SocketPool.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,16 @@ static mp_obj_t socketpool_socketpool_getaddrinfo(size_t n_args, const mp_obj_t
142142
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
143143
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
144144

145+
#if CIRCUITPY_SOCKETPOOL_IPV6
146+
return common_hal_socketpool_getaddrinfo_raise(
147+
self,
148+
mp_obj_str_get_str(args[ARG_host].u_obj),
149+
args[ARG_port].u_int,
150+
args[ARG_family].u_int,
151+
args[ARG_type].u_int,
152+
args[ARG_proto].u_int,
153+
args[ARG_flags].u_int);
154+
#else
145155
const char *host = mp_obj_str_get_str(args[ARG_host].u_obj);
146156
mp_int_t port = args[ARG_port].u_int;
147157
mp_obj_t ip_str = mp_const_none;
@@ -164,6 +174,7 @@ static mp_obj_t socketpool_socketpool_getaddrinfo(size_t n_args, const mp_obj_t
164174
sockaddr->items[1] = MP_OBJ_NEW_SMALL_INT(port);
165175
tuple->items[4] = MP_OBJ_FROM_PTR(sockaddr);
166176
return mp_obj_new_list(1, (mp_obj_t *)&tuple);
177+
#endif
167178
}
168179
static MP_DEFINE_CONST_FUN_OBJ_KW(socketpool_socketpool_getaddrinfo_obj, 1, socketpool_socketpool_getaddrinfo);
169180

shared-bindings/socketpool/SocketPool.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self,
3232
int proto, socketpool_socket_obj_t *sock);
3333

3434
NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void);
35+
36+
#if CIRCUITPY_SOCKETPOOL_IPV6
37+
mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags);
38+
#endif

0 commit comments

Comments
 (0)