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