2 * libwebsockets web server application
4 * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 static const char * const paths_global[] = {
28 "global.count-threads",
32 enum lejp_global_paths {
40 static const char * const paths_vhosts[] = {
45 "vhosts[].host-ssl-key",
46 "vhosts[].host-ssl-cert",
47 "vhosts[].host-ssl-ca",
48 "vhosts[].mounts[].mountpoint",
49 "vhosts[].mounts[].origin",
50 "vhosts[].mounts[].default",
51 "vhosts[].ws-protocols[].*.*",
52 "vhosts[].ws-protocols[].*",
53 "vhosts[].ws-protocols[]",
56 enum lejp_vhost_paths {
67 LEJPVP_PROTOCOL_NAME_OPT,
73 struct lws_context_creation_info *info;
74 struct lws_context *context;
75 const struct lws_protocols *protocols;
76 const struct lws_extension *extensions;
78 struct lws_http_mount *head, *last;
79 char *mountpoint, *origin, *def;
80 struct lws_protocol_vhost_options *pvo;
84 lwsws_align(struct jpargs *a)
86 if ((unsigned long)(a->p) & 15)
87 a->p += 16 - ((unsigned long)(a->p) & 15);
92 static int arg_to_bool(const char *s)
94 static const char * const on[] = { "on", "yes", "true" };
100 for (n = 0; n < ARRAY_SIZE(on); n++)
101 if (!strcasecmp(s, on[n]))
108 lejp_globals_cb(struct lejp_ctx *ctx, char reason)
110 struct jpargs *a = (struct jpargs *)ctx->user;
112 /* we only match on the prepared path strings */
113 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
116 switch (ctx->path_match - 1) {
118 a->info->uid = atoi(ctx->buf);
121 a->info->gid = atoi(ctx->buf);
123 case LEJPGP_INTERFACE:
124 a->info->iface = a->p;
126 case LEJPGP_COUNT_THREADS:
127 a->info->count_threads = atoi(ctx->buf);
129 case LWJPGP_INIT_SSL:
130 if (arg_to_bool(ctx->buf))
131 a->info->options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
138 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
144 lejp_vhosts_cb(struct lejp_ctx *ctx, char reason)
146 struct jpargs *a = (struct jpargs *)ctx->user;
147 struct lws_protocol_vhost_options *pvo;
148 struct lws_http_mount *m;
151 // lwsl_notice(" %d: %s (%d)\n", reason, ctx->path, ctx->path_match);
152 // for (n = 0; n < ctx->wildcount; n++)
153 // lwsl_notice(" %d\n", ctx->wild[n]);
155 if (reason == LEJPCB_OBJECT_START && ctx->path_match == LEJPVP + 1) {
156 /* set the defaults for this vhost */
161 a->info->iface = NULL;
162 a->info->protocols = a->protocols;
163 a->info->extensions = a->extensions;
164 a->info->ssl_cert_filepath = NULL;
165 a->info->ssl_private_key_filepath = NULL;
166 a->info->ssl_ca_filepath = NULL;
167 a->info->timeout_secs = 5;
168 a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:"
169 "ECDHE-RSA-AES256-GCM-SHA384:"
170 "DHE-RSA-AES256-GCM-SHA384:"
171 "ECDHE-RSA-AES256-SHA384:"
172 "HIGH:!aNULL:!eNULL:!EXPORT:"
173 "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:"
174 "!SHA1:!DHE-RSA-AES128-GCM-SHA256:"
175 "!DHE-RSA-AES128-SHA256:"
176 "!AES128-GCM-SHA256:"
178 "!DHE-RSA-AES256-SHA256:"
179 "!AES256-GCM-SHA384:"
184 if (reason == LEJPCB_OBJECT_START &&
185 ctx->path_match == LEJPVP_MOUNTS + 1) {
186 a->mountpoint = NULL;
191 /* this catches, eg, vhosts[].ws-protocols[].xxx-protocol */
192 if (reason == LEJPCB_OBJECT_START &&
193 ctx->path_match == LEJPVP_PROTOCOL_NAME + 1) {
194 a->pvo = lwsws_align(a);
195 a->p += sizeof(*a->pvo);
197 n = lejp_get_wildcard(ctx, 0, a->p, a->end - a->p);
198 /* ie, enable this protocol, no options yet */
199 a->pvo->next = a->info->pvo;
200 a->info->pvo = a->pvo;
202 lwsl_err("adding %s\n", a->p);
204 a->pvo->value = a->p;
205 a->pvo->options = NULL;
206 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
210 if (reason == LEJPCB_OBJECT_END &&
211 (ctx->path_match == LEJPVP + 1 || !ctx->path[0]) &&
214 //lwsl_notice("%s\n", ctx->path);
215 if (!a->info->port) {
216 lwsl_err("Port required (eg, 443)");
221 if (!lws_create_vhost(a->context, a->info, a->head)) {
222 lwsl_err("Failed to create vhost %s\n",
223 a->info->vhost_name);
230 if (reason == LEJPCB_OBJECT_END &&
231 ctx->path_match == LEJPVP_MOUNTS + 1) {
232 if (!a->mountpoint || !a->origin) {
233 lwsl_err("mountpoint and origin required\n");
237 n = lws_write_http_mount(a->last, &m, a->p, a->mountpoint,
248 /* we only match on the prepared path strings */
249 if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
252 switch (ctx->path_match - 1) {
254 a->info->vhost_name = a->p;
257 a->info->port = atoi(ctx->buf);
259 case LEJPVP_HOST_SSL_KEY:
260 a->info->ssl_private_key_filepath = a->p;
262 case LEJPVP_HOST_SSL_CERT:
263 a->info->ssl_cert_filepath = a->p;
265 case LEJPVP_HOST_SSL_CA:
266 a->info->ssl_ca_filepath = a->p;
268 case LEJPVP_MOUNTPOINT:
269 a->mountpoint = a->p;
278 case LEJPVP_PROTOCOL_NAME_OPT:
280 * vhosts[].ws-protocols[].xxx-protocol.yyy-option
281 * ie, these are options attached to a protocol with { }
283 pvo = lwsws_align(a);
284 a->p += sizeof(*a->pvo);
286 n = lejp_get_wildcard(ctx, 1, a->p, a->end - a->p);
287 /* ie, enable this protocol, no options yet */
288 pvo->next = a->pvo->options;
289 a->pvo->options = pvo;
294 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
302 a->p += snprintf(a->p, a->end - a->p, "%s", ctx->buf);
309 * returns 0 = OK, 1 = can't open, 2 = parsing error
313 lwsws_get_config(void *user, const char *f, const char * const *paths,
314 int count_paths, lejp_callback cb)
316 unsigned char buf[128];
320 fd = open(f, O_RDONLY);
322 lwsl_err("Cannot open %s\n", f);
325 lwsl_info("%s: %s\n", __func__, f);
326 lejp_construct(&ctx, cb, user, paths, count_paths);
329 n = read(fd, buf, sizeof(buf));
333 m = (int)(char)lejp_parse(&ctx, buf, n);
334 } while (m == LEJP_CONTINUE);
341 lwsl_err("%s(%u): parsing error %d\n", f, n, m);
349 static int filter(const struct dirent *ent)
351 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
359 lwsws_get_config_d(void *user, const char *d, const char * const *paths,
360 int count_paths, lejp_callback cb)
363 struct dirent **namelist;
367 n = scandir(d, &namelist, filter, alphasort);
369 lwsl_err("Scandir on %d failed\n", d);
372 for (i = 0; i < n; i++) {
373 snprintf(path, sizeof(path) - 1, "%s/%s", d,
374 namelist[i]->d_name);
375 ret = lwsws_get_config(user, path, paths, count_paths, cb);
394 lwsws_get_config_globals(struct lws_context_creation_info *info, const char *d,
404 if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_global,
405 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
407 if (lwsws_get_config_d(&a, d, paths_global,
408 ARRAY_SIZE(paths_global), lejp_globals_cb) > 1)
418 lwsws_get_config_vhosts(struct lws_context *context,
419 struct lws_context_creation_info *info, const char *d,
429 a.protocols = info->protocols;
430 a.extensions = info->extensions;
432 if (lwsws_get_config(&a, "/etc/lwsws/conf", paths_vhosts,
433 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
435 if (lwsws_get_config_d(&a, d, paths_vhosts,
436 ARRAY_SIZE(paths_vhosts), lejp_vhosts_cb) > 1)
442 lws_finalize_startup(context);