blob: 6c1d52be45c9e78a3f63e97eb908b5a95453c819 [file] [log] [blame]
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "private-lib-core.h"
#if defined(LWS_WITH_SERVER_STATUS)
void
lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs)
{
const struct lws_vhost *vh = ctx->vhost_list;
while (vh) {
cs->rx += vh->conn_stats.rx;
cs->tx += vh->conn_stats.tx;
cs->h1_conn += vh->conn_stats.h1_conn;
cs->h1_trans += vh->conn_stats.h1_trans;
cs->h2_trans += vh->conn_stats.h2_trans;
cs->ws_upg += vh->conn_stats.ws_upg;
cs->h2_upg += vh->conn_stats.h2_upg;
cs->h2_alpn += vh->conn_stats.h2_alpn;
cs->h2_subs += vh->conn_stats.h2_subs;
cs->rejected += vh->conn_stats.rejected;
vh = vh->vhost_next;
}
}
int
lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
{
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
static const char * const prots[] = {
"http://",
"https://",
"file://",
"cgi://",
">http://",
">https://",
"callback://"
};
#endif
char *orig = buf, *end = buf + len - 1, first;
int n;
if (len < 100)
return 0;
buf += lws_snprintf(buf, end - buf,
"{\n \"name\":\"%s\",\n"
" \"port\":\"%d\",\n"
" \"use_ssl\":\"%d\",\n"
" \"sts\":\"%d\",\n"
" \"rx\":\"%llu\",\n"
" \"tx\":\"%llu\",\n"
" \"h1_conn\":\"%lu\",\n"
" \"h1_trans\":\"%lu\",\n"
" \"h2_trans\":\"%lu\",\n"
" \"ws_upg\":\"%lu\",\n"
" \"rejected\":\"%lu\",\n"
" \"h2_upg\":\"%lu\",\n"
" \"h2_alpn\":\"%lu\",\n"
" \"h2_subs\":\"%lu\""
,
vh->name, vh->listen_port,
#if defined(LWS_WITH_TLS)
vh->tls.use_ssl & LCCSCF_USE_SSL,
#else
0,
#endif
!!(vh->options & LWS_SERVER_OPTION_STS),
vh->conn_stats.rx, vh->conn_stats.tx,
vh->conn_stats.h1_conn,
vh->conn_stats.h1_trans,
vh->conn_stats.h2_trans,
vh->conn_stats.ws_upg,
vh->conn_stats.rejected,
vh->conn_stats.h2_upg,
vh->conn_stats.h2_alpn,
vh->conn_stats.h2_subs
);
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
if (vh->http.mount_list) {
const struct lws_http_mount *m = vh->http.mount_list;
buf += lws_snprintf(buf, end - buf, ",\n \"mounts\":[");
first = 1;
while (m) {
if (!first)
buf += lws_snprintf(buf, end - buf, ",");
buf += lws_snprintf(buf, end - buf,
"\n {\n \"mountpoint\":\"%s\",\n"
" \"origin\":\"%s%s\",\n"
" \"cache_max_age\":\"%d\",\n"
" \"cache_reuse\":\"%d\",\n"
" \"cache_revalidate\":\"%d\",\n"
" \"cache_intermediaries\":\"%d\"\n"
,
m->mountpoint,
prots[m->origin_protocol],
m->origin,
m->cache_max_age,
m->cache_reusable,
m->cache_revalidate,
m->cache_intermediaries);
if (m->def)
buf += lws_snprintf(buf, end - buf,
",\n \"default\":\"%s\"",
m->def);
buf += lws_snprintf(buf, end - buf, "\n }");
first = 0;
m = m->mount_next;
}
buf += lws_snprintf(buf, end - buf, "\n ]");
}
#endif
if (vh->protocols) {
n = 0;
first = 1;
buf += lws_snprintf(buf, end - buf, ",\n \"ws-protocols\":[");
while (n < vh->count_protocols) {
if (!first)
buf += lws_snprintf(buf, end - buf, ",");
buf += lws_snprintf(buf, end - buf,
"\n {\n \"%s\":{\n"
" \"status\":\"ok\"\n }\n }"
,
vh->protocols[n].name);
first = 0;
n++;
}
buf += lws_snprintf(buf, end - buf, "\n ]");
}
buf += lws_snprintf(buf, end - buf, "\n}");
return buf - orig;
}
int
lws_json_dump_context(const struct lws_context *context, char *buf, int len,
int hide_vhosts)
{
char *orig = buf, *end = buf + len - 1, first = 1;
const struct lws_vhost *vh = context->vhost_list;
const struct lws_context_per_thread *pt;
int n, listening = 0, cgi_count = 0, fd;
struct lws_conn_stats cs;
double d = 0;
#ifdef LWS_WITH_CGI
struct lws_cgi * const *pcgi;
#endif
#ifdef LWS_WITH_LIBUV
uv_uptime(&d);
#endif
buf += lws_snprintf(buf, end - buf, "{ "
"\"version\":\"%s\",\n"
"\"uptime\":\"%ld\",\n",
lws_get_library_version(),
(long)d);
#ifdef LWS_HAVE_GETLOADAVG
#if defined(__sun)
#include <sys/loadavg.h>
#endif
{
double d[3];
int m;
m = getloadavg(d, 3);
for (n = 0; n < m; n++) {
buf += lws_snprintf(buf, end - buf,
"\"l%d\":\"%.2f\",\n",
n + 1, d[n]);
}
}
#endif
fd = lws_open("/proc/self/statm", LWS_O_RDONLY);
if (fd >= 0) {
char contents[96], pure[96];
n = read(fd, contents, sizeof(contents) - 1);
if (n > 0) {
contents[n] = '\0';
if (contents[n - 1] == '\n')
contents[--n] = '\0';
lws_json_purify(pure, contents, sizeof(pure), NULL);
buf += lws_snprintf(buf, end - buf,
"\"statm\": \"%s\",\n", pure);
}
close(fd);
}
buf += lws_snprintf(buf, end - buf, "\"heap\":%lld,\n\"contexts\":[\n",
(long long)lws_get_allocated_heap());
buf += lws_snprintf(buf, end - buf, "{ "
"\"context_uptime\":\"%llu\",\n"
"\"cgi_spawned\":\"%d\",\n"
"\"pt_fd_max\":\"%d\",\n"
"\"ah_pool_max\":\"%d\",\n"
"\"deprecated\":\"%d\",\n"
"\"wsi_alive\":\"%d\",\n",
(unsigned long long)(lws_now_usecs() - context->time_up) /
LWS_US_PER_SEC,
context->count_cgi_spawned,
context->fd_limit_per_thread,
context->max_http_header_pool,
context->deprecated,
context->count_wsi_allocated);
buf += lws_snprintf(buf, end - buf, "\"pt\":[\n ");
for (n = 0; n < context->count_threads; n++) {
pt = &context->pt[n];
if (n)
buf += lws_snprintf(buf, end - buf, ",");
buf += lws_snprintf(buf, end - buf,
"\n {\n"
" \"fds_count\":\"%d\",\n"
" \"ah_pool_inuse\":\"%d\",\n"
" \"ah_wait_list\":\"%d\"\n"
" }",
pt->fds_count,
pt->http.ah_count_in_use,
pt->http.ah_wait_list_length);
}
buf += lws_snprintf(buf, end - buf, "]");
buf += lws_snprintf(buf, end - buf, ", \"vhosts\":[\n ");
first = 1;
vh = context->vhost_list;
listening = 0;
cs = context->conn_stats;
lws_sum_stats(context, &cs);
while (vh) {
if (!hide_vhosts) {
if (!first)
if(buf != end)
*buf++ = ',';
buf += lws_json_dump_vhost(vh, buf, end - buf);
first = 0;
}
if (vh->lserv_wsi)
listening++;
vh = vh->vhost_next;
}
buf += lws_snprintf(buf, end - buf,
"],\n\"listen_wsi\":\"%d\",\n"
" \"rx\":\"%llu\",\n"
" \"tx\":\"%llu\",\n"
" \"h1_conn\":\"%lu\",\n"
" \"h1_trans\":\"%lu\",\n"
" \"h2_trans\":\"%lu\",\n"
" \"ws_upg\":\"%lu\",\n"
" \"rejected\":\"%lu\",\n"
" \"h2_alpn\":\"%lu\",\n"
" \"h2_subs\":\"%lu\",\n"
" \"h2_upg\":\"%lu\"",
listening, cs.rx, cs.tx,
cs.h1_conn,
cs.h1_trans,
cs.h2_trans,
cs.ws_upg,
cs.rejected,
cs.h2_alpn,
cs.h2_subs,
cs.h2_upg);
#ifdef LWS_WITH_CGI
for (n = 0; n < context->count_threads; n++) {
pt = &context->pt[n];
pcgi = &pt->http.cgi_list;
while (*pcgi) {
pcgi = &(*pcgi)->cgi_list;
cgi_count++;
}
}
#endif
buf += lws_snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ",
cgi_count);
buf += lws_snprintf(buf, end - buf, "}");
buf += lws_snprintf(buf, end - buf, "]}\n ");
return buf - orig;
}
#endif