1/*
2 * lws-minimal-raw-fallback http-server
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 * This demonstrates the most minimal http server you can make with lws.
10 *
11 * To keep it simple, it serves stuff from the subdirectory
12 * "./mount-origin" of the directory it was started in.
13 * You can change that by changing mount.origin below.
14 *
15 * In addition, if the connection does to seem to be talking http, then it
16 * falls back to a raw echo protocol.
17 */
18
19#include <libwebsockets.h>
20#include <string.h>
21#include <signal.h>
22
23struct pss__raw_echo {
24	uint8_t buf[2048];
25	int len;
26};
27
28static int interrupted;
29
30static const struct lws_http_mount mount = {
31	/* .mount_next */		NULL,		/* linked-list "next" */
32	/* .mountpoint */		"/",		/* mountpoint URL */
33	/* .origin */			"./mount-origin", /* serve from dir */
34	/* .def */			"index.html",	/* default filename */
35	/* .protocol */			NULL,
36	/* .cgienv */			NULL,
37	/* .extra_mimetypes */		NULL,
38	/* .interpret */		NULL,
39	/* .cgi_timeout */		0,
40	/* .cache_max_age */		0,
41	/* .auth_mask */		0,
42	/* .cache_reusable */		0,
43	/* .cache_revalidate */		0,
44	/* .cache_intermediaries */	0,
45	/* .origin_protocol */		LWSMPRO_FILE,	/* files in a dir */
46	/* .mountpoint_len */		1,		/* char count */
47	/* .basic_auth_login_file */	NULL,
48};
49
50static int
51callback_raw_echo(struct lws *wsi, enum lws_callback_reasons reason, void *user,
52		  void *in, size_t len)
53{
54	struct pss__raw_echo *pss = (struct pss__raw_echo *)user;
55
56	switch (reason) {
57	case LWS_CALLBACK_RAW_ADOPT:
58		lwsl_notice("LWS_CALLBACK_RAW_ADOPT\n");
59		break;
60
61	case LWS_CALLBACK_RAW_RX:
62		lwsl_notice("LWS_CALLBACK_RAW_RX %ld\n", (long)len);
63		if (len > sizeof(pss->buf))
64			len = sizeof(pss->buf);
65		memcpy(pss->buf, in, len);
66		pss->len = (int)len;
67		lws_callback_on_writable(wsi);
68		break;
69
70	case LWS_CALLBACK_RAW_CLOSE:
71		lwsl_notice("LWS_CALLBACK_RAW_CLOSE\n");
72		break;
73
74	case LWS_CALLBACK_RAW_WRITEABLE:
75		lwsl_notice("LWS_CALLBACK_RAW_WRITEABLE\n");
76		lws_write(wsi, pss->buf, (unsigned int)pss->len, LWS_WRITE_HTTP);
77		break;
78	default:
79		break;
80	}
81
82	return lws_callback_http_dummy(wsi, reason, user, in, len);
83}
84
85static const struct lws_protocols protocols[] = {
86	{ "raw-echo", callback_raw_echo, sizeof(struct pss__raw_echo), 2048, 0, NULL, 0 },
87	LWS_PROTOCOL_LIST_TERM
88};
89
90void sigint_handler(int sig)
91{
92	interrupted = 1;
93}
94
95int main(int argc, const char **argv)
96{
97	struct lws_context_creation_info info;
98	struct lws_context *context;
99	const char *p;
100	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
101
102	signal(SIGINT, sigint_handler);
103
104	if ((p = lws_cmdline_option(argc, argv, "-d")))
105		logs = atoi(p);
106
107	lws_set_log_level(logs, NULL);
108	lwsl_user("LWS minimal raw fallback http server | "
109		  "visit http://localhost:7681\n");
110
111	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
112	info.port = 7681;
113	info.protocols = protocols;
114	info.mounts = &mount;
115	info.error_document_404 = "/404.html";
116	info.options =
117		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE |
118		LWS_SERVER_OPTION_FALLBACK_TO_APPLY_LISTEN_ACCEPT_CONFIG;
119	info.listen_accept_role = "raw-skt";
120	info.listen_accept_protocol = "raw-echo";
121
122#if defined(LWS_WITH_TLS)
123	if (lws_cmdline_option(argc, argv, "-s")) {
124		info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
125				LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
126		info.ssl_cert_filepath = "localhost-100y.cert";
127		info.ssl_private_key_filepath = "localhost-100y.key";
128
129		if (lws_cmdline_option(argc, argv, "-u"))
130			info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS;
131
132		if (lws_cmdline_option(argc, argv, "-h"))
133			info.options |= LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER;
134	}
135#endif
136
137	context = lws_create_context(&info);
138	if (!context) {
139		lwsl_err("lws init failed\n");
140		return 1;
141	}
142
143	while (n >= 0 && !interrupted)
144		n = lws_service(context, 0);
145
146	lws_context_destroy(context);
147
148	return 0;
149}
150