|
@@ -122,7 +122,6 @@ char *WSAErrorMsg(void) {
|
|
|
return &(WSAbuf[0]);
|
|
return &(WSAbuf[0]);
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
-static SOCKETTYPE sock = INVSOCK;
|
|
|
|
|
|
|
|
|
|
static const char *UNAVAILABLE = " - API will not be available";
|
|
static const char *UNAVAILABLE = " - API will not be available";
|
|
|
static const char *INVAPIGROUPS = "Invalid --api-groups parameter";
|
|
static const char *INVAPIGROUPS = "Invalid --api-groups parameter";
|
|
@@ -3243,8 +3242,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)
|
|
static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
|
|
|
{
|
|
{
|
|
|
char buf[SOCKBUFSIZ + sizeof(JSON_CLOSE) + sizeof(JSON_END)];
|
|
char buf[SOCKBUFSIZ + sizeof(JSON_CLOSE) + sizeof(JSON_END)];
|
|
|
- int len;
|
|
|
|
|
- int n;
|
|
|
|
|
|
|
+ int count, res, tosend, len, n;
|
|
|
|
|
|
|
|
strcpy(buf, io_data->ptr);
|
|
strcpy(buf, io_data->ptr);
|
|
|
|
|
|
|
@@ -3259,28 +3257,62 @@ static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
len = strlen(buf);
|
|
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)
|
|
static void tidyup(__maybe_unused void *arg)
|
|
|
{
|
|
{
|
|
|
mutex_lock(&quit_restart_lock);
|
|
mutex_lock(&quit_restart_lock);
|
|
|
|
|
|
|
|
|
|
+ SOCKETTYPE *apisock = (SOCKETTYPE *)arg;
|
|
|
|
|
+
|
|
|
bye = true;
|
|
bye = true;
|
|
|
|
|
|
|
|
- if (sock != INVSOCK) {
|
|
|
|
|
- shutdown(sock, SHUT_RDWR);
|
|
|
|
|
- CLOSESOCKET(sock);
|
|
|
|
|
- sock = INVSOCK;
|
|
|
|
|
|
|
+ if (*apisock != INVSOCK) {
|
|
|
|
|
+ shutdown(*apisock, SHUT_RDWR);
|
|
|
|
|
+ CLOSESOCKET(*apisock);
|
|
|
|
|
+ *apisock = INVSOCK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (ipaccess != NULL) {
|
|
if (ipaccess != NULL) {
|
|
@@ -3601,6 +3633,11 @@ void api(int api_thr_id)
|
|
|
bool did;
|
|
bool did;
|
|
|
int i;
|
|
int i;
|
|
|
|
|
|
|
|
|
|
+ SOCKETTYPE *apisock;
|
|
|
|
|
+
|
|
|
|
|
+ apisock = malloc(sizeof(*apisock));
|
|
|
|
|
+ *apisock = INVSOCK;
|
|
|
|
|
+
|
|
|
if (!opt_api_listen) {
|
|
if (!opt_api_listen) {
|
|
|
applog(LOG_DEBUG, "API not running%s", UNAVAILABLE);
|
|
applog(LOG_DEBUG, "API not running%s", UNAVAILABLE);
|
|
|
return;
|
|
return;
|
|
@@ -3610,7 +3647,7 @@ void api(int api_thr_id)
|
|
|
|
|
|
|
|
mutex_init(&quit_restart_lock);
|
|
mutex_init(&quit_restart_lock);
|
|
|
|
|
|
|
|
- pthread_cleanup_push(tidyup, NULL);
|
|
|
|
|
|
|
+ pthread_cleanup_push(tidyup, (void *)apisock);
|
|
|
my_thr_id = api_thr_id;
|
|
my_thr_id = api_thr_id;
|
|
|
|
|
|
|
|
setup_groups();
|
|
setup_groups();
|
|
@@ -3628,8 +3665,8 @@ void api(int api_thr_id)
|
|
|
* to ensure curl has already called WSAStartup() in windows */
|
|
* to ensure curl has already called WSAStartup() in windows */
|
|
|
nmsleep(opt_log_interval*1000);
|
|
nmsleep(opt_log_interval*1000);
|
|
|
|
|
|
|
|
- sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
- if (sock == INVSOCK) {
|
|
|
|
|
|
|
+ *apisock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
+ if (*apisock == INVSOCK) {
|
|
|
applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
|
|
applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -3654,7 +3691,7 @@ void api(int api_thr_id)
|
|
|
// another program has it open - which is what we want
|
|
// another program has it open - which is what we want
|
|
|
int optval = 1;
|
|
int optval = 1;
|
|
|
// If it doesn't work, we don't really care - just show a debug message
|
|
// If it doesn't work, we don't really care - just show a debug message
|
|
|
- if (SOCKETFAIL(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval))))
|
|
|
|
|
|
|
+ if (SOCKETFAIL(setsockopt(*apisock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval))))
|
|
|
applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG);
|
|
applog(LOG_DEBUG, "API setsockopt SO_REUSEADDR failed (ignored): %s", SOCKERRMSG);
|
|
|
#else
|
|
#else
|
|
|
// On windows a 2nd program can bind to a port>1024 already in use unless
|
|
// On windows a 2nd program can bind to a port>1024 already in use unless
|
|
@@ -3666,7 +3703,7 @@ void api(int api_thr_id)
|
|
|
bound = 0;
|
|
bound = 0;
|
|
|
bindstart = time(NULL);
|
|
bindstart = time(NULL);
|
|
|
while (bound == 0) {
|
|
while (bound == 0) {
|
|
|
- if (SOCKETFAIL(bind(sock, (struct sockaddr *)(&serv), sizeof(serv)))) {
|
|
|
|
|
|
|
+ if (SOCKETFAIL(bind(*apisock, (struct sockaddr *)(&serv), sizeof(serv)))) {
|
|
|
binderror = SOCKERRMSG;
|
|
binderror = SOCKERRMSG;
|
|
|
if ((time(NULL) - bindstart) > 61)
|
|
if ((time(NULL) - bindstart) > 61)
|
|
|
break;
|
|
break;
|
|
@@ -3683,25 +3720,25 @@ void api(int api_thr_id)
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (SOCKETFAIL(listen(sock, QUEUE))) {
|
|
|
|
|
|
|
+ if (SOCKETFAIL(listen(*apisock, QUEUE))) {
|
|
|
applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
|
|
applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
|
|
|
- CLOSESOCKET(sock);
|
|
|
|
|
|
|
+ CLOSESOCKET(*apisock);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (opt_api_allow)
|
|
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 {
|
|
else {
|
|
|
if (opt_api_network)
|
|
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
|
|
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) {
|
|
while (!bye) {
|
|
|
clisiz = sizeof(cli);
|
|
clisiz = sizeof(cli);
|
|
|
- if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
|
|
|
|
|
- applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
|
|
|
|
|
|
|
+ if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) {
|
|
|
|
|
+ applog(LOG_ERR, "API failed (%s)%s (%d)", SOCKERRMSG, UNAVAILABLE, *apisock);
|
|
|
goto die;
|
|
goto die;
|
|
|
}
|
|
}
|
|
|
|
|
|