From 4da89266b889b7a1677e7c6c64d4d1af8d4492a2 Mon Sep 17 00:00:00 2001 From: Andrey Dodonov Date: Thu, 4 Jul 2024 16:50:15 +0200 Subject: [PATCH] net: lib: http: call socket poll for http_client send If we couldn't send all (or any data) via the socket, invoke poll instead of blindly retrying and flooding the socket. Respect timeout through http_client_req Signed-off-by: Andrey Dodonov --- subsys/net/lib/http/http_client.c | 73 ++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/subsys/net/lib/http/http_client.c b/subsys/net/lib/http/http_client.c index 58ff1389b47b48e..d746e3e68c72b33 100644 --- a/subsys/net/lib/http/http_client.c +++ b/subsys/net/lib/http/http_client.c @@ -29,12 +29,32 @@ LOG_MODULE_REGISTER(net_http_client, CONFIG_NET_HTTP_LOG_LEVEL); #define HTTP_CONTENT_LEN_SIZE 11 #define MAX_SEND_BUF_LEN 192 -static int sendall(int sock, const void *buf, size_t len) +static int sendall(int sock, const void *buf, size_t len, int32_t *timeout) { + int64_t timestamp = k_uptime_get(); + while (len) { ssize_t out_len = zsock_send(sock, buf, len, 0); - if (out_len < 0) { + if ((out_len == 0) || (out_len < 0 && errno == EAGAIN)) { + struct zsock_pollfd pfd; + int pollres; + + *timeout -= (int32_t)k_uptime_delta(×tamp); + if (*timeout < 0) { + /* timeout, make poll return immediately */ + *timeout = 0; + } + + pfd.fd = sock; + pfd.events = ZSOCK_POLLOUT; + pollres = zsock_poll(&pfd, 1, *timeout); + if (pollres >= 0) { + continue; + } else { + return -errno; + } + } else if (out_len < 0) { return -errno; } @@ -47,6 +67,7 @@ static int sendall(int sock, const void *buf, size_t len) static int http_send_data(int sock, char *send_buf, size_t send_buf_max_len, size_t *send_buf_pos, + int32_t *timeout, ...) { const char *data; @@ -55,7 +76,7 @@ static int http_send_data(int sock, char *send_buf, int end_of_data, remaining_len; int sent = 0; - va_start(va, send_buf_pos); + va_start(va, timeout); data = va_arg(va, const char *); @@ -80,7 +101,7 @@ static int http_send_data(int sock, char *send_buf, LOG_HEXDUMP_DBG(send_buf, end_of_send, "Data to send"); - ret = sendall(sock, send_buf, end_of_send); + ret = sendall(sock, send_buf, end_of_send, timeout); if (ret < 0) { NET_DBG("Cannot send %d bytes (%d)", end_of_send, ret); @@ -119,13 +140,13 @@ static int http_send_data(int sock, char *send_buf, return ret; } -static int http_flush_data(int sock, const char *send_buf, size_t send_buf_len) +static int http_flush_data(int sock, const char *send_buf, size_t send_buf_len, int32_t *timeout) { int ret; LOG_HEXDUMP_DBG(send_buf, send_buf_len, "Data to send"); - ret = sendall(sock, send_buf, send_buf_len); + ret = sendall(sock, send_buf, send_buf_len, timeout); if (ret < 0) { return ret; } @@ -439,29 +460,26 @@ static void http_report_progress(struct http_request *req) } } -static int http_wait_data(int sock, struct http_request *req, int32_t timeout) +static int http_wait_data(int sock, struct http_request *req, int32_t *timeout) { int total_received = 0; size_t offset = 0; int received, ret; struct zsock_pollfd fds[1]; int nfds = 1; - int32_t remaining_time = timeout; int64_t timestamp = k_uptime_get(); fds[0].fd = sock; fds[0].events = ZSOCK_POLLIN; do { - if (timeout > 0) { - remaining_time -= (int32_t)k_uptime_delta(×tamp); - if (remaining_time < 0) { - /* timeout, make poll return immediately */ - remaining_time = 0; - } + *timeout -= (int32_t)k_uptime_delta(×tamp); + if (*timeout < 0) { + /* timeout, make poll return immediately */ + *timeout = 0; } - ret = zsock_poll(fds, nfds, remaining_time); + ret = zsock_poll(fds, nfds, *timeout); if (ret == 0) { LOG_DBG("Timeout"); ret = -ETIMEDOUT; @@ -566,6 +584,7 @@ int http_client_req(int sock, struct http_request *req, method = http_method_str(req->method); ret = http_send_data(sock, send_buf, send_buf_max_len, &send_buf_pos, + &timeout, method, " ", req->url, " ", req->protocol, HTTP_CRLF, NULL); if (ret < 0) { @@ -576,7 +595,7 @@ int http_client_req(int sock, struct http_request *req, if (req->port) { ret = http_send_data(sock, send_buf, send_buf_max_len, - &send_buf_pos, "Host", ": ", req->host, + &send_buf_pos, &timeout, "Host", ": ", req->host, ":", req->port, HTTP_CRLF, NULL); if (ret < 0) { @@ -586,7 +605,7 @@ int http_client_req(int sock, struct http_request *req, total_sent += ret; } else { ret = http_send_data(sock, send_buf, send_buf_max_len, - &send_buf_pos, "Host", ": ", req->host, + &send_buf_pos, &timeout, "Host", ": ", req->host, HTTP_CRLF, NULL); if (ret < 0) { @@ -597,7 +616,7 @@ int http_client_req(int sock, struct http_request *req, } if (req->optional_headers_cb) { - ret = http_flush_data(sock, send_buf, send_buf_pos); + ret = http_flush_data(sock, send_buf, send_buf_pos, &timeout); if (ret < 0) { goto out; } @@ -616,6 +635,7 @@ int http_client_req(int sock, struct http_request *req, i++) { ret = http_send_data(sock, send_buf, send_buf_max_len, &send_buf_pos, + &timeout, req->optional_headers[i], NULL); if (ret < 0) { goto out; @@ -627,7 +647,7 @@ int http_client_req(int sock, struct http_request *req, for (i = 0; req->header_fields && req->header_fields[i]; i++) { ret = http_send_data(sock, send_buf, send_buf_max_len, - &send_buf_pos, req->header_fields[i], + &send_buf_pos, &timeout, req->header_fields[i], NULL); if (ret < 0) { goto out; @@ -638,7 +658,7 @@ int http_client_req(int sock, struct http_request *req, if (req->content_type_value) { ret = http_send_data(sock, send_buf, send_buf_max_len, - &send_buf_pos, "Content-Type", ": ", + &send_buf_pos, &timeout, "Content-Type", ": ", req->content_type_value, HTTP_CRLF, NULL); if (ret < 0) { goto out; @@ -659,11 +679,12 @@ int http_client_req(int sock, struct http_request *req, } ret = http_send_data(sock, send_buf, send_buf_max_len, - &send_buf_pos, "Content-Length", ": ", + &send_buf_pos, &timeout, "Content-Length", ": ", content_len_str, HTTP_CRLF, HTTP_CRLF, NULL); } else { ret = http_send_data(sock, send_buf, send_buf_max_len, + &timeout, &send_buf_pos, HTTP_CRLF, NULL); } @@ -673,7 +694,7 @@ int http_client_req(int sock, struct http_request *req, total_sent += ret; - ret = http_flush_data(sock, send_buf, send_buf_pos); + ret = http_flush_data(sock, send_buf, send_buf_pos, &timeout); if (ret < 0) { goto out; } @@ -697,7 +718,7 @@ int http_client_req(int sock, struct http_request *req, length = req->payload_len; } - ret = sendall(sock, req->payload, length); + ret = sendall(sock, req->payload, length, &timeout); if (ret < 0) { goto out; } @@ -706,7 +727,7 @@ int http_client_req(int sock, struct http_request *req, } } else { ret = http_send_data(sock, send_buf, send_buf_max_len, - &send_buf_pos, HTTP_CRLF, NULL); + &send_buf_pos, &timeout, HTTP_CRLF, NULL); if (ret < 0) { goto out; } @@ -715,7 +736,7 @@ int http_client_req(int sock, struct http_request *req, } if (send_buf_pos > 0) { - ret = http_flush_data(sock, send_buf, send_buf_pos); + ret = http_flush_data(sock, send_buf, send_buf_pos, &timeout); if (ret < 0) { goto out; } @@ -729,7 +750,7 @@ int http_client_req(int sock, struct http_request *req, &req->internal.parser_settings); /* Request is sent, now wait data to be received */ - total_recv = http_wait_data(sock, req, timeout); + total_recv = http_wait_data(sock, req, &timeout); if (total_recv < 0) { NET_DBG("Wait data failure (%d)", total_recv); ret = total_recv;