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