• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets-test-server - libwebsockets test implementation
3  *
4  * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  *
9  * The person who associated a work with this deed has dedicated
10  * the work to the public domain by waiving all of his or her rights
11  * to the work worldwide under copyright law, including all related
12  * and neighboring rights, to the extent allowed by law. You can copy,
13  * modify, distribute and perform the work, even for commercial purposes,
14  * all without asking permission.
15  *
16  * The test apps are intended to be adapted for use in your code, which
17  * may be proprietary.  So unlike the library itself, they are licensed
18  * Public Domain.
19  */
20 
21 #define LWS_DLL
22 #define LWS_INTERNAL
23 #include <libwebsockets.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 
31 struct lws_ss_filepath {
32 	struct lws_ss_filepath *next;
33 	char filepath[128];
34 };
35 
36 struct lws_ss_dumps {
37 	char buf[32768];
38 	int length;
39 };
40 
41 struct pss {
42 	int ver;
43 	int pos;
44 };
45 
46 struct vhd {
47 	struct lws_context *context;
48 	struct lws_vhost *vhost;
49 	const struct lws_protocols *protocol;
50 	int hide_vhosts;
51 	int tow_flag;
52 	int period_s;
53 	int clients;
54 	struct lws_ss_dumps d;
55 	struct lws_ss_filepath *fp;
56 };
57 
58 static const struct lws_protocols protocols[1];
59 
60 static void
update(struct vhd * v)61 update(struct vhd *v)
62 {
63 	struct lws_ss_filepath *fp;
64 	char contents[256], pure[256], *p = v->d.buf + LWS_PRE,
65 	     *end = v->d.buf + sizeof(v->d.buf) - LWS_PRE - 1;
66 	int n, first = 1, fd;
67 
68 	p += lws_snprintf(p, lws_ptr_diff(end, p), "{\"i\":");
69 	p += lws_json_dump_context(v->context, p, lws_ptr_diff(end, p),
70 				   v->hide_vhosts);
71 	p += lws_snprintf(p, lws_ptr_diff(end, p), ", \"files\": [");
72 
73 	fp = v->fp;
74 	while (fp) {
75 		if (!first)
76 			p += lws_snprintf(p, lws_ptr_diff(end, p), ",");
77 
78 		strcpy(pure, "(unknown)");
79 		fd = lws_open(fp->filepath, LWS_O_RDONLY);
80 		if (fd >= 0) {
81 			n = read(fd, contents, sizeof(contents) - 1);
82 			close(fd);
83 			if (n >= 0) {
84 				contents[n] = '\0';
85 				lws_json_purify(pure, contents, sizeof(pure), NULL);
86 			}
87 		}
88 
89 		p += lws_snprintf(p, lws_ptr_diff(end, p),
90 				"{\"path\":\"%s\",\"val\":\"%s\"}",
91 					fp->filepath, pure);
92 		first = 0;
93 
94 		fp = fp->next;
95 	}
96 	p += lws_snprintf(p, lws_ptr_diff(end, p), "]}");
97 	v->d.length = p - (v->d.buf + LWS_PRE);
98 
99 	lws_callback_on_writable_all_protocol(v->context, &protocols[0]);
100 }
101 
102 static int
callback_lws_server_status(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)103 callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
104 			   void *user, void *in, size_t len)
105 {
106 	const struct lws_protocol_vhost_options *pvo =
107 			(const struct lws_protocol_vhost_options *)in;
108 	struct vhd *v = (struct vhd *)
109 			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
110 					lws_get_protocol(wsi));
111 	struct lws_ss_filepath *fp, *fp1, **fp_old;
112 	int m;
113 
114 	switch (reason) {
115 
116 	case LWS_CALLBACK_ESTABLISHED:
117 		lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
118 		if (!v->clients++) {
119 			lws_timed_callback_vh_protocol(v->vhost, v->protocol,
120 						       LWS_CALLBACK_USER, v->period_s);
121 			lwsl_info("%s: starting updates\n", __func__);
122 		}
123 		update(v);
124 
125 		break;
126 
127 	case LWS_CALLBACK_CLOSED:
128 		if (!--v->clients)
129 			lwsl_notice("%s: stopping updates\n", __func__);
130 
131 		break;
132 
133 	case LWS_CALLBACK_USER:
134 		update(v);
135 		if (v->clients)
136 			lws_timed_callback_vh_protocol(v->vhost, v->protocol,
137 						       LWS_CALLBACK_USER, v->period_s);
138 		break;
139 
140 	case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
141 		if (v)
142 			break;
143 
144 		lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
145 					    lws_get_protocol(wsi),
146 					    sizeof(struct vhd));
147 		v = (struct vhd *)lws_protocol_vh_priv_get(lws_get_vhost(wsi),
148 							   lws_get_protocol(wsi));
149 
150 		fp_old = &v->fp;
151 
152 		while (pvo) {
153 			if (!strcmp(pvo->name, "hide-vhosts"))
154 				v->hide_vhosts = atoi(pvo->value);
155 			if (!strcmp(pvo->name, "update-ms"))
156 				v->period_s = (atoi(pvo->value) + 500) / 1000;
157 			else
158 				v->period_s = 5;
159 			if (!strcmp(pvo->name, "filepath")) {
160 				fp = malloc(sizeof(*fp));
161 				fp->next = NULL;
162 				lws_snprintf(&fp->filepath[0],
163 					     sizeof(fp->filepath), "%s",
164 					     pvo->value);
165 				*fp_old = fp;
166 				fp_old = &fp->next;
167 			}
168 			pvo = pvo->next;
169 		}
170 		v->context = lws_get_context(wsi);
171 		v->vhost = lws_get_vhost(wsi);
172 		v->protocol = lws_get_protocol(wsi);
173 
174 		/* get the initial data */
175 		update(v);
176 		break;
177 
178 	case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
179 		if (!v)
180 			break;
181 		fp = v->fp;
182 		while (fp) {
183 			fp1= fp->next;
184 			free(fp);
185 			fp = fp1;
186 		}
187 		break;
188 
189 	case LWS_CALLBACK_SERVER_WRITEABLE:
190 		m = lws_write(wsi, (unsigned char *)v->d.buf + LWS_PRE,
191 			      v->d.length, LWS_WRITE_TEXT);
192 		if (m < 0)
193 			return -1;
194 		break;
195 
196 	default:
197 		break;
198 	}
199 
200 	return 0;
201 }
202 
203 static const struct lws_protocols protocols[] = {
204 	{
205 		"lws-server-status",
206 		callback_lws_server_status,
207 		sizeof(struct pss),
208 		1024,
209 	},
210 };
211 
212 LWS_VISIBLE int
init_protocol_lws_server_status(struct lws_context * context,struct lws_plugin_capability * c)213 init_protocol_lws_server_status(struct lws_context *context,
214 				struct lws_plugin_capability *c)
215 {
216 	if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
217 		lwsl_err("Plugin API %d, library API %d",
218 			 LWS_PLUGIN_API_MAGIC, c->api_magic);
219 		return 1;
220 	}
221 
222 	c->protocols = protocols;
223 	c->count_protocols = LWS_ARRAY_SIZE(protocols);
224 	c->extensions = NULL;
225 	c->count_extensions = 0;
226 
227 	return 0;
228 }
229 
230 LWS_VISIBLE int
destroy_protocol_lws_server_status(struct lws_context * context)231 destroy_protocol_lws_server_status(struct lws_context *context)
232 {
233 	return 0;
234 }
235