1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * lws-minimal-http-server-h2-long-poll
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0
7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication.
8d4afb5ceSopenharmony_ci *
9d4afb5ceSopenharmony_ci * This demonstrates an h2 server that supports "long poll"
10d4afb5ceSopenharmony_ci * immortal client connections.  For simplicity it doesn't serve
11d4afb5ceSopenharmony_ci * any regular files, you can add a mount to do it if you want.
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The protocol keeps the long poll h2 stream open, and sends
14d4afb5ceSopenharmony_ci * the time on the stream once per minute.  Normally idle h2
15d4afb5ceSopenharmony_ci * connections are closed by default within 30s, so this demonstrates
16d4afb5ceSopenharmony_ci * the stream and network connection are operating as "immortal"
17d4afb5ceSopenharmony_ci * on both sides.
18d4afb5ceSopenharmony_ci *
19d4afb5ceSopenharmony_ci * See http-client/minimal-http-client-h2-long-poll for the
20d4afb5ceSopenharmony_ci * client example that connects and transitions the stream to the
21d4afb5ceSopenharmony_ci * immortal long poll mode.
22d4afb5ceSopenharmony_ci */
23d4afb5ceSopenharmony_ci
24d4afb5ceSopenharmony_ci#include <libwebsockets.h>
25d4afb5ceSopenharmony_ci#include <string.h>
26d4afb5ceSopenharmony_ci#include <signal.h>
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_cistatic int interrupted;
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_cistruct pss {
31d4afb5ceSopenharmony_ci	struct lws *wsi;
32d4afb5ceSopenharmony_ci	lws_sorted_usec_list_t sul;
33d4afb5ceSopenharmony_ci	char pending;
34d4afb5ceSopenharmony_ci};
35d4afb5ceSopenharmony_ci
36d4afb5ceSopenharmony_cistatic const lws_retry_bo_t retry = {
37d4afb5ceSopenharmony_ci	.secs_since_valid_ping = 5,
38d4afb5ceSopenharmony_ci	.secs_since_valid_hangup = 10,
39d4afb5ceSopenharmony_ci};
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_cistatic void
42d4afb5ceSopenharmony_cisul_cb(lws_sorted_usec_list_t *sul)
43d4afb5ceSopenharmony_ci{
44d4afb5ceSopenharmony_ci	struct pss *pss = (struct pss *)lws_container_of(sul, struct pss, sul);
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	pss->pending = 1;
47d4afb5ceSopenharmony_ci	lws_callback_on_writable(pss->wsi);
48d4afb5ceSopenharmony_ci	/* interval 1min... longer than any normal timeout */
49d4afb5ceSopenharmony_ci	lws_sul_schedule(lws_get_context(pss->wsi), 0, &pss->sul, sul_cb,
50d4afb5ceSopenharmony_ci				60 * LWS_US_PER_SEC);
51d4afb5ceSopenharmony_ci}
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_cistatic int
54d4afb5ceSopenharmony_cicallback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
55d4afb5ceSopenharmony_ci	      void *in, size_t len)
56d4afb5ceSopenharmony_ci{
57d4afb5ceSopenharmony_ci	struct pss * pss = (struct pss *)user;
58d4afb5ceSopenharmony_ci	uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE],
59d4afb5ceSopenharmony_ci		*start = &buf[LWS_PRE], *p = start,
60d4afb5ceSopenharmony_ci		*end = buf + sizeof(buf) - 1;
61d4afb5ceSopenharmony_ci	int m, n;
62d4afb5ceSopenharmony_ci
63d4afb5ceSopenharmony_ci	switch (reason) {
64d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP:
65d4afb5ceSopenharmony_ci		lwsl_user("%s: connect\n", __func__);
66d4afb5ceSopenharmony_ci		pss->wsi = wsi;
67d4afb5ceSopenharmony_ci
68d4afb5ceSopenharmony_ci		if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
69d4afb5ceSopenharmony_ci				"text/html",
70d4afb5ceSopenharmony_ci				LWS_ILLEGAL_HTTP_CONTENT_LEN, /* no content len */
71d4afb5ceSopenharmony_ci				&p, end))
72d4afb5ceSopenharmony_ci			return 1;
73d4afb5ceSopenharmony_ci		if (lws_finalize_write_http_header(wsi, start, &p, end))
74d4afb5ceSopenharmony_ci			return 1;
75d4afb5ceSopenharmony_ci
76d4afb5ceSopenharmony_ci		sul_cb(&pss->sul);
77d4afb5ceSopenharmony_ci		return 0;
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CLOSED_HTTP:
80d4afb5ceSopenharmony_ci		if (!pss)
81d4afb5ceSopenharmony_ci			break;
82d4afb5ceSopenharmony_ci		lws_sul_cancel(&pss->sul);
83d4afb5ceSopenharmony_ci		break;
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci	case LWS_CALLBACK_HTTP_WRITEABLE:
86d4afb5ceSopenharmony_ci		if (!pss->pending)
87d4afb5ceSopenharmony_ci			break;
88d4afb5ceSopenharmony_ci		n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%llu",
89d4afb5ceSopenharmony_ci				 (unsigned long long)lws_now_usecs());
90d4afb5ceSopenharmony_ci		m = lws_write(wsi, p, (unsigned int)n, LWS_WRITE_HTTP);
91d4afb5ceSopenharmony_ci		if (m < n) {
92d4afb5ceSopenharmony_ci			lwsl_err("ERROR %d writing to socket\n", n);
93d4afb5ceSopenharmony_ci			return -1;
94d4afb5ceSopenharmony_ci		}
95d4afb5ceSopenharmony_ci		break;
96d4afb5ceSopenharmony_ci	default:
97d4afb5ceSopenharmony_ci		break;
98d4afb5ceSopenharmony_ci	}
99d4afb5ceSopenharmony_ci
100d4afb5ceSopenharmony_ci	return lws_callback_http_dummy(wsi, reason, user, in, len);
101d4afb5ceSopenharmony_ci}
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_cistatic struct lws_protocols protocols[] = {
104d4afb5ceSopenharmony_ci	{ "http", callback_http, sizeof(struct pss), 0, 0, NULL, 0 },
105d4afb5ceSopenharmony_ci	LWS_PROTOCOL_LIST_TERM
106d4afb5ceSopenharmony_ci};
107d4afb5ceSopenharmony_ci
108d4afb5ceSopenharmony_ci
109d4afb5ceSopenharmony_civoid sigint_handler(int sig)
110d4afb5ceSopenharmony_ci{
111d4afb5ceSopenharmony_ci	interrupted = 1;
112d4afb5ceSopenharmony_ci}
113d4afb5ceSopenharmony_ci
114d4afb5ceSopenharmony_ciint main(int argc, const char **argv)
115d4afb5ceSopenharmony_ci{
116d4afb5ceSopenharmony_ci	struct lws_context_creation_info info;
117d4afb5ceSopenharmony_ci	struct lws_context *context;
118d4afb5ceSopenharmony_ci	const char *p;
119d4afb5ceSopenharmony_ci	int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci	signal(SIGINT, sigint_handler);
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci	if ((p = lws_cmdline_option(argc, argv, "-d")))
124d4afb5ceSopenharmony_ci		logs = atoi(p);
125d4afb5ceSopenharmony_ci
126d4afb5ceSopenharmony_ci	lws_set_log_level(logs, NULL);
127d4afb5ceSopenharmony_ci	lwsl_user("LWS minimal http server h2 long poll\n");
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
130d4afb5ceSopenharmony_ci	info.port = 7681;
131d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS)
132d4afb5ceSopenharmony_ci	info.ssl_cert_filepath = "localhost-100y.cert";
133d4afb5ceSopenharmony_ci	info.ssl_private_key_filepath = "localhost-100y.key";
134d4afb5ceSopenharmony_ci#endif
135d4afb5ceSopenharmony_ci	info.protocols = protocols;
136d4afb5ceSopenharmony_ci	info.options =
137d4afb5ceSopenharmony_ci		LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
138d4afb5ceSopenharmony_ci		LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL |
139d4afb5ceSopenharmony_ci		LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
140d4afb5ceSopenharmony_ci
141d4afb5ceSopenharmony_ci	/* the default validity check is 5m / 5m10s... -v = 5s / 10s */
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	if (lws_cmdline_option(argc, argv, "-v"))
144d4afb5ceSopenharmony_ci		info.retry_and_idle_policy = &retry;
145d4afb5ceSopenharmony_ci
146d4afb5ceSopenharmony_ci	context = lws_create_context(&info);
147d4afb5ceSopenharmony_ci	if (!context) {
148d4afb5ceSopenharmony_ci		lwsl_err("lws init failed\n");
149d4afb5ceSopenharmony_ci		return 1;
150d4afb5ceSopenharmony_ci	}
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci	while (n >= 0 && !interrupted)
153d4afb5ceSopenharmony_ci		n = lws_service(context, 0);
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci	lws_context_destroy(context);
156d4afb5ceSopenharmony_ci
157d4afb5ceSopenharmony_ci	return 0;
158d4afb5ceSopenharmony_ci}
159