44
44
#include "py/mperrno.h"
45
45
#include "py/mphal.h"
46
46
#include "py/stream.h"
47
+ #include "py/mperrno.h"
47
48
#include "lib/netutils/netutils.h"
48
49
#include "tcpip_adapter.h"
49
50
52
53
#include "lwip/ip4.h"
53
54
#include "esp_log.h"
54
55
56
+ #define SOCKET_POLL_US (100000)
57
+
55
58
typedef struct _socket_obj_t {
56
59
mp_obj_base_t base ;
57
60
int fd ;
58
61
uint8_t domain ;
59
62
uint8_t type ;
60
63
uint8_t proto ;
64
+ unsigned int retries ;
61
65
} socket_obj_t ;
62
66
63
67
NORETURN static void exception_from_errno (int _errno ) {
@@ -68,6 +72,14 @@ NORETURN static void exception_from_errno(int _errno) {
68
72
mp_raise_OSError (_errno );
69
73
}
70
74
75
+ void check_for_exceptions () {
76
+ mp_obj_t exc = MP_STATE_VM (mp_pending_exception );
77
+ if (exc != MP_OBJ_NULL ) {
78
+ MP_STATE_VM (mp_pending_exception ) = MP_OBJ_NULL ;
79
+ nlr_raise (exc );
80
+ }
81
+ }
82
+
71
83
STATIC mp_obj_t socket_close (const mp_obj_t arg0 ) {
72
84
socket_obj_t * self = MP_OBJ_TO_PTR (arg0 );
73
85
if (self -> fd >= 0 ) {
@@ -115,15 +127,17 @@ STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) {
115
127
_socket_getaddrinfo (arg1 , & res );
116
128
int r = lwip_bind_r (self -> fd , res -> ai_addr , res -> ai_addrlen );
117
129
lwip_freeaddrinfo (res );
118
- return mp_obj_new_int (r );
130
+ if (r < 0 ) exception_from_errno (errno );
131
+ return mp_const_none ;
119
132
}
120
133
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_bind_obj , socket_bind );
121
134
122
135
STATIC mp_obj_t socket_listen (const mp_obj_t arg0 , const mp_obj_t arg1 ) {
123
136
socket_obj_t * self = MP_OBJ_TO_PTR (arg0 );
124
137
int backlog = mp_obj_get_int (arg1 );
125
- int x = lwip_listen_r (self -> fd , backlog );
126
- return (x == 0 ) ? mp_const_true : mp_const_false ;
138
+ int r = lwip_listen_r (self -> fd , backlog );
139
+ if (r < 0 ) exception_from_errno (errno );
140
+ return mp_const_none ;
127
141
}
128
142
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_listen_obj , socket_listen );
129
143
@@ -132,15 +146,20 @@ STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
132
146
133
147
struct sockaddr addr ;
134
148
socklen_t addr_len = sizeof (addr );
135
- int x = lwip_accept_r (self -> fd , & addr , & addr_len );
136
- if (x < 0 ) {
137
- exception_from_errno (errno );
149
+
150
+ int new_fd = -1 ;
151
+ for (int i = 0 ; i <=self -> retries ; i ++ ) {
152
+ new_fd = lwip_accept_r (self -> fd , & addr , & addr_len );
153
+ if (new_fd >= 0 ) break ;
154
+ if (errno != EAGAIN ) exception_from_errno (errno );
155
+ check_for_exceptions ();
138
156
}
157
+ if (new_fd < 0 ) mp_raise_OSError (MP_ETIMEDOUT );
139
158
140
159
// create new socket object
141
160
socket_obj_t * sock = m_new_obj_with_finaliser (socket_obj_t );
142
161
sock -> base .type = self -> base .type ;
143
- sock -> fd = x ;
162
+ sock -> fd = new_fd ;
144
163
sock -> domain = self -> domain ;
145
164
sock -> type = self -> type ;
146
165
sock -> proto = self -> proto ;
@@ -165,6 +184,7 @@ STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {
165
184
if (r != 0 ) {
166
185
exception_from_errno (errno );
167
186
}
187
+
168
188
return mp_const_none ;
169
189
}
170
190
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_connect_obj , socket_connect );
@@ -191,83 +211,63 @@ STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
191
211
}
192
212
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (socket_setsockopt_obj , 4 , 4 , socket_setsockopt );
193
213
194
- static void _socket_settimeout (int fd , unsigned long timeout_us ) {
214
+ void _socket_settimeout (socket_obj_t * sock , uint64_t timeout_ms ) {
215
+ sock -> retries = timeout_ms * 1000 / SOCKET_POLL_US ;
216
+
195
217
struct timeval timeout = {
196
- .tv_sec = timeout_us / 1000000 ,
197
- .tv_usec = timeout_us % 1000000
218
+ .tv_sec = 0 ,
219
+ .tv_usec = timeout_ms ? SOCKET_POLL_US : 0
198
220
};
199
- lwip_setsockopt_r (fd , SOL_SOCKET , SO_SNDTIMEO , (const void * )& timeout , sizeof (timeout ));
200
- lwip_setsockopt_r (fd , SOL_SOCKET , SO_RCVTIMEO , (const void * )& timeout , sizeof (timeout ));
201
- lwip_fcntl_r (fd , F_SETFL , 0 );
202
- }
203
-
204
- static void _socket_setnonblock (int fd ) {
205
- struct timeval timeout = { .tv_sec = 0 , .tv_usec = 0 };
206
- lwip_setsockopt_r (fd , SOL_SOCKET , SO_SNDTIMEO , (const void * )& timeout , sizeof (timeout ));
207
- lwip_setsockopt_r (fd , SOL_SOCKET , SO_RCVTIMEO , (const void * )& timeout , sizeof (timeout ));
208
- lwip_fcntl_r (fd , F_SETFL , O_NONBLOCK );
221
+ lwip_setsockopt_r (sock -> fd , SOL_SOCKET , SO_SNDTIMEO , (const void * )& timeout , sizeof (timeout ));
222
+ lwip_setsockopt_r (sock -> fd , SOL_SOCKET , SO_RCVTIMEO , (const void * )& timeout , sizeof (timeout ));
223
+ lwip_fcntl_r (sock -> fd , F_SETFL , timeout_ms ? 0 : O_NONBLOCK );
209
224
}
210
225
211
226
STATIC mp_obj_t socket_settimeout (const mp_obj_t arg0 , const mp_obj_t arg1 ) {
212
227
socket_obj_t * self = MP_OBJ_TO_PTR (arg0 );
213
- if (arg1 == mp_const_none ) {
214
- _socket_settimeout (self -> fd , 0 );
215
- } else {
216
- unsigned long timeout_us = (unsigned long )(mp_obj_get_float (arg1 ) * 1000000 );
217
- if (timeout_us == 0 ) _socket_setnonblock (self -> fd );
218
- else _socket_settimeout (self -> fd , timeout_us );
219
- }
228
+ if (arg1 == mp_const_none ) _socket_settimeout (self , UINT_MAX );
229
+ else _socket_settimeout (self , mp_obj_get_float (arg1 ) * 1000L );
220
230
return mp_const_none ;
221
231
}
222
232
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_settimeout_obj , socket_settimeout );
223
233
224
234
STATIC mp_obj_t socket_setblocking (const mp_obj_t arg0 , const mp_obj_t arg1 ) {
225
235
socket_obj_t * self = MP_OBJ_TO_PTR (arg0 );
226
- if (mp_obj_is_true (arg1 )) _socket_settimeout (self -> fd , 0 );
227
- else _socket_setnonblock (self -> fd );
236
+ if (mp_obj_is_true (arg1 )) _socket_settimeout (self , UINT_MAX );
237
+ else _socket_settimeout (self , 0 );
228
238
return mp_const_none ;
229
239
}
230
240
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_setblocking_obj , socket_setblocking );
231
-
232
- STATIC mp_obj_t socket_recv (mp_obj_t self_in , mp_obj_t len_in ) {
233
- socket_obj_t * self = MP_OBJ_TO_PTR (self_in );
241
+
242
+ mp_obj_t _socket_recvfrom (mp_obj_t self_in , mp_obj_t len_in ,
243
+ struct sockaddr * from , socklen_t * from_len ) {
244
+ socket_obj_t * sock = MP_OBJ_TO_PTR (self_in );
234
245
size_t len = mp_obj_get_int (len_in );
235
246
vstr_t vstr ;
236
247
vstr_init_len (& vstr , len );
237
- int x = lwip_recvfrom_r (self -> fd , vstr .buf , len , 0 , NULL , NULL );
238
- if (x >= 0 ) {
239
- vstr .len = x ;
240
- return mp_obj_new_str_from_vstr (& mp_type_bytes , & vstr );
248
+
249
+ // XXX Would be nicer to use RTC to handle timeouts
250
+ for (int i = 0 ; i <=sock -> retries ; i ++ ) {
251
+ int r = lwip_recvfrom_r (sock -> fd , vstr .buf , len , 0 , from , from_len );
252
+ if (r >= 0 ) { vstr .len = r ; return mp_obj_new_str_from_vstr (& mp_type_bytes , & vstr ); }
253
+ if (errno != EWOULDBLOCK ) exception_from_errno (errno );
254
+ check_for_exceptions ();
241
255
}
242
- if (errno == EWOULDBLOCK ) return mp_const_empty_bytes ;
243
- exception_from_errno (errno );
256
+ mp_raise_OSError (MP_ETIMEDOUT );
257
+ }
258
+
259
+ STATIC mp_obj_t socket_recv (mp_obj_t self_in , mp_obj_t len_in ) {
260
+ return _socket_recvfrom (self_in , len_in , NULL , NULL );
244
261
}
245
262
STATIC MP_DEFINE_CONST_FUN_OBJ_2 (socket_recv_obj , socket_recv );
246
263
247
264
STATIC mp_obj_t socket_recvfrom (mp_obj_t self_in , mp_obj_t len_in ) {
248
- socket_obj_t * self = MP_OBJ_TO_PTR (self_in );
249
-
250
- // create the destination buffer
251
- mp_int_t len = mp_obj_get_int (len_in );
252
- vstr_t vstr ;
253
- vstr_init_len (& vstr , len );
254
-
255
- // do the receive
256
265
struct sockaddr from ;
257
266
socklen_t fromlen = sizeof (from );
258
- int ret = lwip_recvfrom_r (self -> fd , vstr .buf , len , 0 , & from , & fromlen );
259
- if (ret == -1 ) {
260
- exception_from_errno (errno );
261
- }
262
267
263
- // make the return value
264
268
mp_obj_t tuple [2 ];
265
- if (ret == 0 ) {
266
- tuple [0 ] = mp_const_empty_bytes ;
267
- } else {
268
- vstr .len = ret ;
269
- tuple [0 ] = mp_obj_new_str_from_vstr (& mp_type_bytes , & vstr );
270
- }
269
+ tuple [0 ] = _socket_recvfrom (self_in , len_in , & from , & fromlen );
270
+
271
271
uint8_t * ip = (uint8_t * )& ((struct sockaddr_in * )& from )-> sin_addr ;
272
272
mp_uint_t port = lwip_ntohs (((struct sockaddr_in * )& from )-> sin_port );
273
273
tuple [1 ] = netutils_format_inet_addr (ip , port , NETUTILS_BIG );
@@ -338,13 +338,22 @@ STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
338
338
}
339
339
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (socket_makefile_obj , 1 , 3 , socket_makefile );
340
340
341
+
342
+ // XXX this can end up waiting a very long time if the content is dribbled in one character
343
+ // at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not
344
+ // good behaviour.
345
+
341
346
STATIC mp_uint_t socket_stream_read (mp_obj_t self_in , void * buf , mp_uint_t size , int * errcode ) {
342
- socket_obj_t * socket = self_in ;
343
- int x = lwip_recvfrom_r (socket -> fd , buf , size , 0 , NULL , NULL );
344
- if (x >= 0 ) return x ;
345
- if (errno == EWOULDBLOCK ) return 0 ;
346
- * errcode = MP_EIO ;
347
- return MP_STREAM_ERROR ;
347
+ socket_obj_t * sock = self_in ;
348
+
349
+ // XXX Would be nicer to use RTC to handle timeouts
350
+ for (int i = 0 ; i <=sock -> retries ; i ++ ) {
351
+ int x = lwip_recvfrom_r (sock -> fd , buf , size , 0 , NULL , NULL );
352
+ if (x > 0 ) return x ;
353
+ if (x < 0 && errno != EWOULDBLOCK ) { * errcode = errno ; return MP_STREAM_ERROR ; }
354
+ check_for_exceptions ();
355
+ }
356
+ return 0 ; // causes a timeout error to be raised.
348
357
}
349
358
350
359
STATIC mp_uint_t socket_stream_write (mp_obj_t self_in , const void * buf , mp_uint_t size , int * errcode ) {
@@ -437,10 +446,13 @@ STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) {
437
446
}
438
447
}
439
448
}
449
+
440
450
sock -> fd = lwip_socket (sock -> domain , sock -> type , sock -> proto );
441
451
if (sock -> fd < 0 ) {
442
452
exception_from_errno (errno );
443
453
}
454
+ _socket_settimeout (sock , UINT_MAX );
455
+
444
456
return MP_OBJ_FROM_PTR (sock );
445
457
}
446
458
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (get_socket_obj , 0 , 3 , get_socket );
0 commit comments