Skip to content

Commit 0ab7e96

Browse files
committed
esp32/modsocket.c: support for ioctl, settimeout, setblocking, getaddrinfo
1 parent f645428 commit 0ab7e96

File tree

1 file changed

+117
-28
lines changed

1 file changed

+117
-28
lines changed

esp32/modsocket.c

Lines changed: 117 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,17 @@
3232
#include <stdlib.h>
3333
#include <string.h>
3434

35+
#include "py/runtime0.h"
3536
#include "py/nlr.h"
3637
#include "py/objlist.h"
38+
#include "py/objstr.h"
3739
#include "py/runtime.h"
3840
#include "py/mphal.h"
3941
#include "py/stream.h"
4042

4143
#include "lwip/sockets.h"
4244
#include "lwip/netdb.h"
45+
#include "lwip/ip4.h"
4346
#include "esp_log.h"
4447

4548
typedef struct _socket_obj_t {
@@ -57,35 +60,41 @@ STATIC mp_obj_t socket_close(const mp_obj_t arg0) {
5760
}
5861
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
5962

60-
// XXX TODO change calls for bind and connect to work the same as ESP8266
61-
// micropython
62-
63-
int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t port, struct addrinfo **resp) {
64-
mp_uint_t hostlen, portlen;
65-
const char *shost = mp_obj_str_get_data(host, &hostlen);
66-
const char *sport = mp_obj_str_get_data(port, &portlen);
63+
static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) {
6764
const struct addrinfo hints = {
6865
.ai_family = AF_INET,
6966
.ai_socktype = SOCK_STREAM,
7067
};
71-
lwip_getaddrinfo(shost, sport, &hints, resp);
72-
return 0;
68+
69+
mp_obj_t port = portx;
70+
if (MP_OBJ_IS_SMALL_INT(port)) {
71+
// This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but
72+
// that's the API we have to work with ...
73+
port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str("%s", 2, true), port);
74+
}
75+
76+
mp_uint_t host_len, port_len;
77+
const char *host_str = mp_obj_str_get_data(host, &host_len);
78+
const char *port_str = mp_obj_str_get_data(port, &port_len);
79+
80+
return lwip_getaddrinfo(host_str, port_str, &hints, resp);
7381
}
7482

7583
int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) {
7684
mp_uint_t len = 0;
7785
mp_obj_t *elem;
7886
mp_obj_get_array(addrtuple, &len, &elem);
79-
if (len == 2) return _socket_getaddrinfo2(elem[0], elem[1], resp);
80-
else return -1;
87+
if (len != 2) return -1;
88+
return _socket_getaddrinfo2(elem[0], elem[1], resp);
8189
}
8290

8391
STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) {
8492
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
8593
struct addrinfo *res;
8694
_socket_getaddrinfo(arg1, &res);
87-
lwip_bind(self->fd, res->ai_addr, res->ai_addrlen);
88-
return mp_const_none;
95+
int r = lwip_bind(self->fd, res->ai_addr, res->ai_addrlen);
96+
lwip_freeaddrinfo(res);
97+
return mp_obj_new_int(r);
8998
}
9099
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
91100

@@ -120,18 +129,44 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {
120129
}
121130
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
122131

123-
STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) {
124-
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
132+
static void _socket_settimeout(int fd, unsigned long timeout_us) {
125133
struct timeval timeout = {
126-
.tv_sec = mp_obj_get_int(arg1),
127-
.tv_usec = 0
134+
.tv_sec = timeout_us / 1000000,
135+
.tv_usec = timeout_us % 1000000
128136
};
129-
lwip_setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout));
130-
lwip_setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout));
137+
lwip_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout));
138+
lwip_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout));
139+
lwip_fcntl(fd, F_SETFL, 0);
140+
}
141+
142+
static void _socket_setnonblock(int fd) {
143+
struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
144+
lwip_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout));
145+
lwip_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout));
146+
lwip_fcntl(fd, F_SETFL, O_NONBLOCK);
147+
}
148+
149+
STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) {
150+
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
151+
if (arg1 == mp_const_none) {
152+
_socket_settimeout(self->fd, 0);
153+
} else {
154+
unsigned long timeout_us = (unsigned long)(mp_obj_get_float(arg1) * 1000000);
155+
if (timeout_us == 0) _socket_setnonblock(self->fd);
156+
else _socket_settimeout(self->fd, timeout_us);
157+
}
131158
return mp_const_none;
132159
}
133160
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
134161

162+
STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) {
163+
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
164+
if (mp_obj_is_true(arg1)) _socket_settimeout(self->fd, 0);
165+
else _socket_setnonblock(self->fd);
166+
return mp_const_none;
167+
}
168+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
169+
135170
STATIC mp_obj_t socket_recv(const mp_obj_t arg0) {
136171
byte buf[1024];
137172
socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
@@ -160,21 +195,48 @@ STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size,
160195
socket_obj_t *socket = self_in;
161196
int x = lwip_recvfrom(socket->fd, buf, size, 0, NULL, NULL);
162197
if (x >= 0) return x;
163-
*errcode = x;
164-
return 0;
198+
if (errno == EWOULDBLOCK) return 0;
199+
*errcode = MP_EIO;
200+
return MP_STREAM_ERROR;
165201
}
166202

167203
STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
168204
socket_obj_t *socket = self_in;
169205
int x = lwip_write(socket->fd, buf, size);
170206
if (x >= 0) return x;
171-
*errcode = x;
172-
return 0;
207+
if (errno == EWOULDBLOCK) return 0;
208+
*errcode = MP_EIO;
209+
return MP_STREAM_ERROR;
173210
}
174211

175212
STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
176-
// XXX TODO support MP_STREAM_POLL at least.
177-
return 0;
213+
socket_obj_t * socket = self_in;
214+
if (request == MP_STREAM_POLL) {
215+
char buf[1];
216+
mp_uint_t ret = 0;
217+
if (arg & MP_STREAM_POLL_RD) {
218+
int r = lwip_recvfrom(socket->fd, buf, 1, MSG_DONTWAIT | MSG_PEEK, NULL, NULL);
219+
if (r > 0) ret |= MP_STREAM_POLL_RD;
220+
}
221+
if (arg & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP)) {
222+
fd_set wfds; FD_ZERO(&wfds);
223+
fd_set efds; FD_ZERO(&efds);
224+
struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
225+
if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds);
226+
if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds);
227+
int r = select((socket->fd)+1, NULL, &wfds, &efds, &timeout);
228+
if (r < 0) {
229+
*errcode = MP_EIO;
230+
return MP_STREAM_ERROR;
231+
}
232+
if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR;
233+
if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP;
234+
}
235+
return ret;
236+
}
237+
238+
*errcode = MP_EINVAL;
239+
return MP_STREAM_ERROR;
178240
}
179241

180242
// XXX TODO missing methods ...
@@ -193,7 +255,7 @@ STATIC const mp_map_elem_t socket_locals_dict_table[] = {
193255
{ MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), mp_const_none },
194256
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), mp_const_none },
195257
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
196-
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), mp_const_none },
258+
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
197259
{ MP_OBJ_NEW_QSTR(MP_QSTR_makefile), mp_const_none },
198260
{ MP_OBJ_NEW_QSTR(MP_QSTR_fileno), (mp_obj_t)&socket_fileno_obj },
199261

@@ -229,9 +291,36 @@ STATIC mp_obj_t get_socket(mp_uint_t n_args, const mp_obj_t *args) {
229291
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket);
230292

231293
STATIC mp_obj_t esp_socket_getaddrinfo(const mp_obj_t host, const mp_obj_t port) {
232-
struct addrinfo *res;
294+
struct addrinfo *res = NULL;
233295
_socket_getaddrinfo2(host, port, &res);
234-
return mp_obj_new_bytes((const byte *)res->ai_addr, res->ai_addrlen);
296+
mp_obj_t ret_list = mp_obj_new_list(0, NULL);
297+
298+
for (struct addrinfo *resi = res; resi; resi = resi->ai_next) {
299+
mp_obj_t addrinfo_objs[5] = {
300+
mp_obj_new_int(resi->ai_family),
301+
mp_obj_new_int(resi->ai_socktype),
302+
mp_obj_new_int(resi->ai_protocol),
303+
mp_obj_new_str(resi->ai_canonname, strlen(resi->ai_canonname), false),
304+
mp_const_none
305+
};
306+
307+
if (resi->ai_family == AF_INET) {
308+
struct sockaddr_in *addr = (struct sockaddr_in *)resi->ai_addr;
309+
// This looks odd, but it's really just a u32_t
310+
ip4_addr_t ip4_addr = { .addr = addr->sin_addr.s_addr };
311+
char buf[16];
312+
ip4addr_ntoa_r(&ip4_addr, buf, sizeof(buf));
313+
mp_obj_t inaddr_objs[2] = {
314+
mp_obj_new_str(buf, strlen(buf), false),
315+
mp_obj_new_int(ntohs(addr->sin_port))
316+
};
317+
addrinfo_objs[4] = mp_obj_new_tuple(2, inaddr_objs);
318+
}
319+
mp_obj_list_append(ret_list, mp_obj_new_tuple(5, addrinfo_objs));
320+
}
321+
322+
if (res) lwip_freeaddrinfo(res);
323+
return ret_list;
235324
}
236325
STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_getaddrinfo_obj, esp_socket_getaddrinfo);
237326

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy