@@ -56,6 +56,9 @@ StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
56
56
#define FDSTATE_CLOSING 2
57
57
STATIC uint8_t socket_fd_state [CONFIG_LWIP_MAX_SOCKETS ];
58
58
59
+ // How long to wait between checks for a socket to connect.
60
+ #define SOCKET_CONNECT_POLL_INTERVAL_MS 100
61
+
59
62
STATIC socketpool_socket_obj_t * user_socket [CONFIG_LWIP_MAX_SOCKETS ];
60
63
StaticTask_t socket_select_task_buffer ;
61
64
TaskHandle_t socket_select_task_handle ;
@@ -412,25 +415,75 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
412
415
413
416
// Replace above with function call -----
414
417
415
- // Switch to blocking mode for this one call
416
- int opts ;
417
- opts = lwip_fcntl (self -> num , F_GETFL , 0 );
418
- opts = opts & (~O_NONBLOCK );
419
- lwip_fcntl (self -> num , F_SETFL , opts );
418
+ // Emulate SO_CONTIMEO, which is not implemented by lwip.
419
+ // All our sockets are non-blocking, so we check the timeout ourselves.
420
420
421
421
int result = -1 ;
422
422
result = lwip_connect (self -> num , (struct sockaddr * )& dest_addr , sizeof (struct sockaddr_in ));
423
423
424
- // Switch back once complete
425
- opts = opts | O_NONBLOCK ;
426
- lwip_fcntl (self -> num , F_SETFL , opts );
427
-
428
- if (result >= 0 ) {
424
+ if (result == 0 ) {
425
+ // Connected immediately.
429
426
self -> connected = true;
430
427
return ;
431
- } else {
428
+ }
429
+
430
+ if (result < 0 && errno != EINPROGRESS ) {
431
+ // Some error happened; error is in errno.
432
432
mp_raise_OSError (errno );
433
+ return ;
433
434
}
435
+
436
+ struct timeval timeout = {
437
+ .tv_sec = 0 ,
438
+ .tv_usec = SOCKET_CONNECT_POLL_INTERVAL_MS * 1000 ,
439
+ };
440
+
441
+ // Keep checking, using select(), until timeout expires, at short intervals.
442
+ // This allows ctrl-C interrupts to be detected and background tasks to run.
443
+ mp_uint_t timeout_left = self -> timeout_ms ;
444
+
445
+ while (timeout_left > 0 ) {
446
+ RUN_BACKGROUND_TASKS ;
447
+ // Allow ctrl-C interrupt
448
+ if (mp_hal_is_interrupted ()) {
449
+ return ;
450
+ }
451
+
452
+ fd_set fds ;
453
+ FD_ZERO (& fds );
454
+ FD_SET (self -> num , & fds );
455
+
456
+ result = select (self -> num + 1 , NULL , & fds , NULL , & timeout );
457
+ if (result == 0 ) {
458
+ // No change to fd's after waiting for timeout, so try again if some time is still left.
459
+ // Don't wrap below 0, because we're using a uint.
460
+ if (timeout_left < SOCKET_CONNECT_POLL_INTERVAL_MS ) {
461
+ timeout_left = 0 ;
462
+ } else {
463
+ timeout_left -= SOCKET_CONNECT_POLL_INTERVAL_MS ;
464
+ }
465
+ continue ;
466
+ }
467
+
468
+ if (result < 0 ) {
469
+ // Some error happened when doing select(); error is in errno.
470
+ mp_raise_OSError (errno );
471
+ }
472
+
473
+ // select() indicated the socket is writable. Check if any connection error occurred.
474
+ int error_code = 0 ;
475
+ socklen_t socklen = sizeof (error_code );
476
+ result = getsockopt (self -> num , SOL_SOCKET , SO_ERROR , & error_code , & socklen );
477
+ if (result < 0 || error_code != 0 ) {
478
+ mp_raise_OSError (errno );
479
+ }
480
+ self -> connected = true;
481
+ return ;
482
+ }
483
+
484
+ // No connection after timeout. The connection attempt is not stopped.
485
+ // This imitates what happens in Python.
486
+ mp_raise_OSError (ETIMEDOUT );
434
487
}
435
488
436
489
bool common_hal_socketpool_socket_get_closed (socketpool_socket_obj_t * self ) {
0 commit comments