32
32
#include <stdlib.h>
33
33
#include <string.h>
34
34
35
+ #include "py/runtime0.h"
35
36
#include "py/nlr.h"
36
37
#include "py/objlist.h"
38
+ #include "py/objstr.h"
37
39
#include "py/runtime.h"
38
40
#include "py/mphal.h"
39
41
#include "py/stream.h"
40
42
41
43
#include "lwip/sockets.h"
42
44
#include "lwip/netdb.h"
45
+ #include "lwip/ip4.h"
43
46
#include "esp_log.h"
44
47
45
48
typedef struct _socket_obj_t {
@@ -57,35 +60,41 @@ STATIC mp_obj_t socket_close(const mp_obj_t arg0) {
57
60
}
58
61
STATIC MP_DEFINE_CONST_FUN_OBJ_1 (socket_close_obj , socket_close );
59
62
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 ) {
67
64
const struct addrinfo hints = {
68
65
.ai_family = AF_INET ,
69
66
.ai_socktype = SOCK_STREAM ,
70
67
};
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 );
73
81
}
74
82
75
83
int _socket_getaddrinfo (const mp_obj_t addrtuple , struct addrinfo * * resp ) {
76
84
mp_uint_t len = 0 ;
77
85
mp_obj_t * elem ;
78
86
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 ) ;
81
89
}
82
90
83
91
STATIC mp_obj_t socket_bind (const mp_obj_t arg0 , const mp_obj_t arg1 ) {
84
92
socket_obj_t * self = MP_OBJ_TO_PTR (arg0 );
85
93
struct addrinfo * res ;
86
94
_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 );
89
98
}
90
99
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_bind_obj , socket_bind );
91
100
@@ -120,18 +129,44 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {
120
129
}
121
130
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_connect_obj , socket_connect );
122
131
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 ) {
125
133
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
128
136
};
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
+ }
131
158
return mp_const_none ;
132
159
}
133
160
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_settimeout_obj , socket_settimeout );
134
161
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
+
135
170
STATIC mp_obj_t socket_recv (const mp_obj_t arg0 ) {
136
171
byte buf [1024 ];
137
172
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,
160
195
socket_obj_t * socket = self_in ;
161
196
int x = lwip_recvfrom (socket -> fd , buf , size , 0 , NULL , NULL );
162
197
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 ;
165
201
}
166
202
167
203
STATIC mp_uint_t socket_stream_write (mp_obj_t self_in , const void * buf , mp_uint_t size , int * errcode ) {
168
204
socket_obj_t * socket = self_in ;
169
205
int x = lwip_write (socket -> fd , buf , size );
170
206
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 ;
173
210
}
174
211
175
212
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 ;
178
240
}
179
241
180
242
// XXX TODO missing methods ...
@@ -193,7 +255,7 @@ STATIC const mp_map_elem_t socket_locals_dict_table[] = {
193
255
{ MP_OBJ_NEW_QSTR (MP_QSTR_recvfrom ), mp_const_none },
194
256
{ MP_OBJ_NEW_QSTR (MP_QSTR_setsockopt ), mp_const_none },
195
257
{ 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 },
197
259
{ MP_OBJ_NEW_QSTR (MP_QSTR_makefile ), mp_const_none },
198
260
{ MP_OBJ_NEW_QSTR (MP_QSTR_fileno ), (mp_obj_t )& socket_fileno_obj },
199
261
@@ -229,9 +291,36 @@ STATIC mp_obj_t get_socket(mp_uint_t n_args, const mp_obj_t *args) {
229
291
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (get_socket_obj , 0 , 3 , get_socket );
230
292
231
293
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 ;
233
295
_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 ;
235
324
}
236
325
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (esp_socket_getaddrinfo_obj , esp_socket_getaddrinfo );
237
326
0 commit comments