Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49954d8

Browse files
authored
Merge pull request #9210 from dhalbert/socket-timeout
espressif: add user-specified socket connect() timeout
2 parents 126a1a4 + 0e21529 commit 49954d8

File tree

1 file changed

+64
-11
lines changed
  • ports/espressif/common-hal/socketpool

1 file changed

+64
-11
lines changed

ports/espressif/common-hal/socketpool/Socket.c

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
5656
#define FDSTATE_CLOSING 2
5757
STATIC 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+
5962
STATIC socketpool_socket_obj_t *user_socket[CONFIG_LWIP_MAX_SOCKETS];
6063
StaticTask_t socket_select_task_buffer;
6164
TaskHandle_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

436489
bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t *self) {

0 commit comments

Comments
 (0)