API no longer ignore send() status
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
diff --git a/api.c b/api.c
index d9a1b35..96c087a 100644
--- a/api.c
+++ b/api.c
@@ -3616,8 +3616,7 @@ static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, c
static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
{
char buf[SOCKBUFSIZ + sizeof(JSON_CLOSE) + sizeof(JSON_END)];
- int len;
- int n;
+ int count, res, tosend, len, n;
strcpy(buf, io_data->ptr);
@@ -3632,16 +3631,48 @@ static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
}
len = strlen(buf);
+ tosend = len+1;
- applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", len+1, buf, len > 10 ? "..." : BLANK);
+ applog(LOG_DEBUG, "API: send reply: (%d) '%.10s%s'", tosend, buf, len > 10 ? "..." : BLANK);
- // ignore failure - it's closed immediately anyway
- n = send(c, buf, len+1, 0);
+ count = 0;
+ while (count++ < 5 && tosend > 0) {
+ // allow 50ms per attempt
+ struct timeval timeout = {0, 50000};
+ fd_set wd;
+
+ FD_ZERO(&wd);
+ FD_SET(c, &wd);
+ if ((res = select(c + 1, NULL, &wd, NULL, &timeout)) < 1) {
+ applog(LOG_WARNING, "API: send select failed (%d)", res);
+ return;
+ }
- if (SOCKETFAIL(n))
- applog(LOG_WARNING, "API: send failed: %s", SOCKERRMSG);
- else
- applog(LOG_DEBUG, "API: sent %d", n);
+ n = send(c, buf, tosend, 0);
+
+ if (SOCKETFAIL(n)) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ continue;
+
+ applog(LOG_WARNING, "API: send (%d) failed: %s", tosend, SOCKERRMSG);
+
+ return;
+ } else {
+ if (count <= 1) {
+ if (n == tosend)
+ applog(LOG_DEBUG, "API: sent all of %d first go", tosend);
+ else
+ applog(LOG_DEBUG, "API: sent %d of %d first go", n, tosend);
+ } else {
+ if (n == tosend)
+ applog(LOG_DEBUG, "API: sent all of remaining %d (count=%d)", tosend, count);
+ else
+ applog(LOG_DEBUG, "API: sent %d of remaining %d (count=%d)", n, tosend, count);
+ }
+
+ tosend -= n;
+ }
+ }
}
static void tidyup(__maybe_unused void *arg)
@@ -4066,18 +4097,18 @@ void api(int api_thr_id)
}
if (opt_api_allow)
- applog(LOG_WARNING, "API running in IP access mode on port %d", port);
+ applog(LOG_WARNING, "API running in IP access mode on port %d (%d)", port, *apisock);
else {
if (opt_api_network)
- applog(LOG_WARNING, "API running in UNRESTRICTED read access mode on port %d", port);
+ applog(LOG_WARNING, "API running in UNRESTRICTED read access mode on port %d (%d)", port, *apisock);
else
- applog(LOG_WARNING, "API running in local read access mode on port %d", port);
+ applog(LOG_WARNING, "API running in local read access mode on port %d (%d)", port, *apisock);
}
while (!bye) {
clisiz = sizeof(cli);
if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) {
- applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
+ applog(LOG_ERR, "API failed (%s)%s (%d)", SOCKERRMSG, UNAVAILABLE, *apisock);
goto die;
}