|
|
@ -125,7 +125,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"; |
|
|
@ -3617,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) |
|
|
|
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 count, res, tosend, len, n; |
|
|
|
int n; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
strcpy(buf, io_data->ptr); |
|
|
|
strcpy(buf, io_data->ptr); |
|
|
|
|
|
|
|
|
|
|
@ -3633,28 +3631,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
|
|
|
|
count = 0; |
|
|
|
n = send(c, buf, len+1, 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)) |
|
|
|
n = send(c, buf, tosend, 0); |
|
|
|
applog(LOG_WARNING, "API: send failed: %s", SOCKERRMSG); |
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
else |
|
|
|
applog(LOG_DEBUG, "API: sent %d", n); |
|
|
|
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) { |
|
|
|
if (*apisock != INVSOCK) { |
|
|
|
shutdown(sock, SHUT_RDWR); |
|
|
|
shutdown(*apisock, SHUT_RDWR); |
|
|
|
CLOSESOCKET(sock); |
|
|
|
CLOSESOCKET(*apisock); |
|
|
|
sock = INVSOCK; |
|
|
|
*apisock = INVSOCK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (ipaccess != NULL) { |
|
|
|
if (ipaccess != NULL) { |
|
|
@ -3971,6 +4003,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; |
|
|
@ -3980,7 +4017,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(); |
|
|
@ -3998,8 +4035,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); |
|
|
|
*apisock = socket(AF_INET, SOCK_STREAM, 0); |
|
|
|
if (sock == INVSOCK) { |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
@ -4024,7 +4061,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
|
|
|
@ -4036,7 +4073,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; |
|
|
@ -4053,25 +4090,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))) { |
|
|
|
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; |
|
|
|
goto die; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|