Skip to content

Commit

Permalink
net: lib: http: call socket poll for http_client send
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
AndreyDodonov-EH committed Jul 4, 2024
1 parent 2457f73 commit 4da8926
Showing 1 changed file with 47 additions and 26 deletions.
73 changes: 47 additions & 26 deletions subsys/net/lib/http/http_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&timestamp);
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;
}

Expand All @@ -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;
Expand All @@ -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 *);

Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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(&timestamp);
if (remaining_time < 0) {
/* timeout, make poll return immediately */
remaining_time = 0;
}
*timeout -= (int32_t)k_uptime_delta(&timestamp);
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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
}

Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down

0 comments on commit 4da8926

Please sign in to comment.