@@ -56,6 +56,9 @@ StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
5656#define FDSTATE_CLOSING 2
5757STATIC uint8_t socket_fd_state [CONFIG_LWIP_MAX_SOCKETS ];
5858
59+ // How long to wait between checks for a socket to connect.
60+ #define SOCKET_CONNECT_POLL_INTERVAL_MS 100
61+
5962STATIC socketpool_socket_obj_t * user_socket [CONFIG_LWIP_MAX_SOCKETS ];
6063StaticTask_t socket_select_task_buffer ;
6164TaskHandle_t socket_select_task_handle ;
@@ -412,25 +415,75 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
412415
413416 // Replace above with function call -----
414417
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.
420420
421421 int result = -1 ;
422422 result = lwip_connect (self -> num , (struct sockaddr * )& dest_addr , sizeof (struct sockaddr_in ));
423423
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.
429426 self -> connected = true;
430427 return ;
431- } else {
428+ }
429+
430+ if (result < 0 && errno != EINPROGRESS ) {
431+ // Some error happened; error is in errno.
432432 mp_raise_OSError (errno );
433+ return ;
433434 }
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 );
434487}
435488
436489bool common_hal_socketpool_socket_get_closed (socketpool_socket_obj_t * self ) {
0 commit comments