1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26
27 #if defined(LWS_WITH_SERVER_STATUS)
28
29 void
lws_sum_stats(const struct lws_context * ctx,struct lws_conn_stats * cs)30 lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs)
31 {
32 const struct lws_vhost *vh = ctx->vhost_list;
33
34 while (vh) {
35
36 cs->rx += vh->conn_stats.rx;
37 cs->tx += vh->conn_stats.tx;
38 cs->h1_conn += vh->conn_stats.h1_conn;
39 cs->h1_trans += vh->conn_stats.h1_trans;
40 cs->h2_trans += vh->conn_stats.h2_trans;
41 cs->ws_upg += vh->conn_stats.ws_upg;
42 cs->h2_upg += vh->conn_stats.h2_upg;
43 cs->h2_alpn += vh->conn_stats.h2_alpn;
44 cs->h2_subs += vh->conn_stats.h2_subs;
45 cs->rejected += vh->conn_stats.rejected;
46
47 vh = vh->vhost_next;
48 }
49 }
50
51 int
lws_json_dump_vhost(const struct lws_vhost * vh,char * buf,int len)52 lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
53 {
54 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
55 static const char * const prots[] = {
56 "http://",
57 "https://",
58 "file://",
59 "cgi://",
60 ">http://",
61 ">https://",
62 "callback://"
63 };
64 #endif
65 char *orig = buf, *end = buf + len - 1, first;
66 int n;
67
68 if (len < 100)
69 return 0;
70
71 buf += lws_snprintf(buf, end - buf,
72 "{\n \"name\":\"%s\",\n"
73 " \"port\":\"%d\",\n"
74 " \"use_ssl\":\"%d\",\n"
75 " \"sts\":\"%d\",\n"
76 " \"rx\":\"%llu\",\n"
77 " \"tx\":\"%llu\",\n"
78 " \"h1_conn\":\"%lu\",\n"
79 " \"h1_trans\":\"%lu\",\n"
80 " \"h2_trans\":\"%lu\",\n"
81 " \"ws_upg\":\"%lu\",\n"
82 " \"rejected\":\"%lu\",\n"
83 " \"h2_upg\":\"%lu\",\n"
84 " \"h2_alpn\":\"%lu\",\n"
85 " \"h2_subs\":\"%lu\""
86 ,
87 vh->name, vh->listen_port,
88 #if defined(LWS_WITH_TLS)
89 vh->tls.use_ssl & LCCSCF_USE_SSL,
90 #else
91 0,
92 #endif
93 !!(vh->options & LWS_SERVER_OPTION_STS),
94 vh->conn_stats.rx, vh->conn_stats.tx,
95 vh->conn_stats.h1_conn,
96 vh->conn_stats.h1_trans,
97 vh->conn_stats.h2_trans,
98 vh->conn_stats.ws_upg,
99 vh->conn_stats.rejected,
100 vh->conn_stats.h2_upg,
101 vh->conn_stats.h2_alpn,
102 vh->conn_stats.h2_subs
103 );
104 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
105 if (vh->http.mount_list) {
106 const struct lws_http_mount *m = vh->http.mount_list;
107
108 buf += lws_snprintf(buf, end - buf, ",\n \"mounts\":[");
109 first = 1;
110 while (m) {
111 if (!first)
112 buf += lws_snprintf(buf, end - buf, ",");
113 buf += lws_snprintf(buf, end - buf,
114 "\n {\n \"mountpoint\":\"%s\",\n"
115 " \"origin\":\"%s%s\",\n"
116 " \"cache_max_age\":\"%d\",\n"
117 " \"cache_reuse\":\"%d\",\n"
118 " \"cache_revalidate\":\"%d\",\n"
119 " \"cache_intermediaries\":\"%d\"\n"
120 ,
121 m->mountpoint,
122 prots[m->origin_protocol],
123 m->origin,
124 m->cache_max_age,
125 m->cache_reusable,
126 m->cache_revalidate,
127 m->cache_intermediaries);
128 if (m->def)
129 buf += lws_snprintf(buf, end - buf,
130 ",\n \"default\":\"%s\"",
131 m->def);
132 buf += lws_snprintf(buf, end - buf, "\n }");
133 first = 0;
134 m = m->mount_next;
135 }
136 buf += lws_snprintf(buf, end - buf, "\n ]");
137 }
138 #endif
139 if (vh->protocols) {
140 n = 0;
141 first = 1;
142
143 buf += lws_snprintf(buf, end - buf, ",\n \"ws-protocols\":[");
144 while (n < vh->count_protocols) {
145 if (!first)
146 buf += lws_snprintf(buf, end - buf, ",");
147 buf += lws_snprintf(buf, end - buf,
148 "\n {\n \"%s\":{\n"
149 " \"status\":\"ok\"\n }\n }"
150 ,
151 vh->protocols[n].name);
152 first = 0;
153 n++;
154 }
155 buf += lws_snprintf(buf, end - buf, "\n ]");
156 }
157
158 buf += lws_snprintf(buf, end - buf, "\n}");
159
160 return buf - orig;
161 }
162
163
164 int
lws_json_dump_context(const struct lws_context * context,char * buf,int len,int hide_vhosts)165 lws_json_dump_context(const struct lws_context *context, char *buf, int len,
166 int hide_vhosts)
167 {
168 char *orig = buf, *end = buf + len - 1, first = 1;
169 const struct lws_vhost *vh = context->vhost_list;
170 const struct lws_context_per_thread *pt;
171 int n, listening = 0, cgi_count = 0, fd;
172 struct lws_conn_stats cs;
173 double d = 0;
174 #ifdef LWS_WITH_CGI
175 struct lws_cgi * const *pcgi;
176 #endif
177
178 #ifdef LWS_WITH_LIBUV
179 uv_uptime(&d);
180 #endif
181
182 buf += lws_snprintf(buf, end - buf, "{ "
183 "\"version\":\"%s\",\n"
184 "\"uptime\":\"%ld\",\n",
185 lws_get_library_version(),
186 (long)d);
187
188 #ifdef LWS_HAVE_GETLOADAVG
189 #if defined(__sun)
190 #include <sys/loadavg.h>
191 #endif
192 {
193 double d[3];
194 int m;
195
196 m = getloadavg(d, 3);
197 for (n = 0; n < m; n++) {
198 buf += lws_snprintf(buf, end - buf,
199 "\"l%d\":\"%.2f\",\n",
200 n + 1, d[n]);
201 }
202 }
203 #endif
204
205 fd = lws_open("/proc/self/statm", LWS_O_RDONLY);
206 if (fd >= 0) {
207 char contents[96], pure[96];
208 n = read(fd, contents, sizeof(contents) - 1);
209 if (n > 0) {
210 contents[n] = '\0';
211 if (contents[n - 1] == '\n')
212 contents[--n] = '\0';
213 lws_json_purify(pure, contents, sizeof(pure), NULL);
214
215 buf += lws_snprintf(buf, end - buf,
216 "\"statm\": \"%s\",\n", pure);
217 }
218 close(fd);
219 }
220
221 buf += lws_snprintf(buf, end - buf, "\"heap\":%lld,\n\"contexts\":[\n",
222 (long long)lws_get_allocated_heap());
223
224 buf += lws_snprintf(buf, end - buf, "{ "
225 "\"context_uptime\":\"%llu\",\n"
226 "\"cgi_spawned\":\"%d\",\n"
227 "\"pt_fd_max\":\"%d\",\n"
228 "\"ah_pool_max\":\"%d\",\n"
229 "\"deprecated\":\"%d\",\n"
230 "\"wsi_alive\":\"%d\",\n",
231 (unsigned long long)(lws_now_usecs() - context->time_up) /
232 LWS_US_PER_SEC,
233 context->count_cgi_spawned,
234 context->fd_limit_per_thread,
235 context->max_http_header_pool,
236 context->deprecated,
237 context->count_wsi_allocated);
238
239 buf += lws_snprintf(buf, end - buf, "\"pt\":[\n ");
240 for (n = 0; n < context->count_threads; n++) {
241 pt = &context->pt[n];
242 if (n)
243 buf += lws_snprintf(buf, end - buf, ",");
244 buf += lws_snprintf(buf, end - buf,
245 "\n {\n"
246 " \"fds_count\":\"%d\",\n"
247 " \"ah_pool_inuse\":\"%d\",\n"
248 " \"ah_wait_list\":\"%d\"\n"
249 " }",
250 pt->fds_count,
251 pt->http.ah_count_in_use,
252 pt->http.ah_wait_list_length);
253 }
254
255 buf += lws_snprintf(buf, end - buf, "]");
256
257 buf += lws_snprintf(buf, end - buf, ", \"vhosts\":[\n ");
258
259 first = 1;
260 vh = context->vhost_list;
261 listening = 0;
262 cs = context->conn_stats;
263 lws_sum_stats(context, &cs);
264 while (vh) {
265
266 if (!hide_vhosts) {
267 if (!first)
268 if(buf != end)
269 *buf++ = ',';
270 buf += lws_json_dump_vhost(vh, buf, end - buf);
271 first = 0;
272 }
273 if (vh->lserv_wsi)
274 listening++;
275 vh = vh->vhost_next;
276 }
277
278 buf += lws_snprintf(buf, end - buf,
279 "],\n\"listen_wsi\":\"%d\",\n"
280 " \"rx\":\"%llu\",\n"
281 " \"tx\":\"%llu\",\n"
282 " \"h1_conn\":\"%lu\",\n"
283 " \"h1_trans\":\"%lu\",\n"
284 " \"h2_trans\":\"%lu\",\n"
285 " \"ws_upg\":\"%lu\",\n"
286 " \"rejected\":\"%lu\",\n"
287 " \"h2_alpn\":\"%lu\",\n"
288 " \"h2_subs\":\"%lu\",\n"
289 " \"h2_upg\":\"%lu\"",
290 listening, cs.rx, cs.tx,
291 cs.h1_conn,
292 cs.h1_trans,
293 cs.h2_trans,
294 cs.ws_upg,
295 cs.rejected,
296 cs.h2_alpn,
297 cs.h2_subs,
298 cs.h2_upg);
299
300 #ifdef LWS_WITH_CGI
301 for (n = 0; n < context->count_threads; n++) {
302 pt = &context->pt[n];
303 pcgi = &pt->http.cgi_list;
304
305 while (*pcgi) {
306 pcgi = &(*pcgi)->cgi_list;
307
308 cgi_count++;
309 }
310 }
311 #endif
312 buf += lws_snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ",
313 cgi_count);
314
315 buf += lws_snprintf(buf, end - buf, "}");
316
317
318 buf += lws_snprintf(buf, end - buf, "]}\n ");
319
320 return buf - orig;
321 }
322
323 #endif
324