• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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