fix: WiFiClientSecure connection timeout (#5398) (#5418)

Closes #5398

Using the same non-blocking socket connect pattern for respecting connection timeout, copied from WiFiClient::connect.

WiFiClient::connect uses lwip_connect_r, whereas start_ssl_client uses lwip_connect. I haven't found what is the difference between them. I tested both, both work ok, so I kept lwip_connect.
This commit is contained in:
Vlasta Hajek 2021-07-21 12:20:23 +02:00 committed by GitHub
parent 4ada3f5804
commit e12d8c8ff1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -76,30 +76,67 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
return -1; return -1;
} }
fcntl( ssl_client->socket, F_SETFL, fcntl( ssl_client->socket, F_GETFL, 0 ) | O_NONBLOCK );
struct sockaddr_in serv_addr; struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET; serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = srv; serv_addr.sin_addr.s_addr = srv;
serv_addr.sin_port = htons(port); serv_addr.sin_port = htons(port);
if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) {
if(timeout <= 0){ if(timeout <= 0){
timeout = 30000; // Milli seconds. timeout = 30000; // Milli seconds.
} }
timeval so_timeout = { .tv_sec = timeout / 1000, .tv_usec = (timeout % 1000) * 1000 };
#define ROE(x,msg) { if (((x)<0)) { log_e("LWIP Socket config of " msg " failed."); return -1; }} fd_set fdset;
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &so_timeout, sizeof(so_timeout)),"SO_RCVTIMEO"); struct timeval tv;
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &so_timeout, sizeof(so_timeout)),"SO_SNDTIMEO"); FD_ZERO(&fdset);
FD_SET(ssl_client->socket, &fdset);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
ROE(lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY"); int res = lwip_connect(ssl_client->socket, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE"); if (res < 0 && errno != EINPROGRESS) {
} else { log_e("connect on fd %d, errno: %d, \"%s\"", ssl_client->socket, errno, strerror(errno));
log_e("Connect to Server failed!"); close(ssl_client->socket);
return -1; return -1;
} }
fcntl( ssl_client->socket, F_SETFL, fcntl( ssl_client->socket, F_GETFL, 0 ) | O_NONBLOCK ); res = select(ssl_client->socket + 1, nullptr, &fdset, nullptr, timeout<0 ? nullptr : &tv);
if (res < 0) {
log_e("select on fd %d, errno: %d, \"%s\"", ssl_client->socket, errno, strerror(errno));
close(ssl_client->socket);
return -1;
} else if (res == 0) {
log_i("select returned due to timeout %d ms for fd %d", timeout, ssl_client->socket);
close(ssl_client->socket);
return -1;
} else {
int sockerr;
socklen_t len = (socklen_t)sizeof(int);
res = getsockopt(ssl_client->socket, SOL_SOCKET, SO_ERROR, &sockerr, &len);
if (res < 0) {
log_e("getsockopt on fd %d, errno: %d, \"%s\"", ssl_client->socket, errno, strerror(errno));
close(ssl_client->socket);
return -1;
}
if (sockerr != 0) {
log_e("socket error on fd %d, errno: %d, \"%s\"", ssl_client->socket, sockerr, strerror(sockerr));
close(ssl_client->socket);
return -1;
}
}
#define ROE(x,msg) { if (((x)<0)) { log_e("LWIP Socket config of " msg " failed."); return -1; }}
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),"SO_RCVTIMEO");
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)),"SO_SNDTIMEO");
ROE(lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY");
ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE");
log_v("Seeding the random number generator"); log_v("Seeding the random number generator");
mbedtls_entropy_init(&ssl_client->entropy_ctx); mbedtls_entropy_init(&ssl_client->entropy_ctx);