mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-16 00:00:07 +01:00

Refactor everything around ping / pong handling in ws and h2, so there is instead a protocol-independent validity lws_sul tracking how long it has been since the last exchange that confirms the operation of the network connection in both directions. Clean out periodic role callback and replace the last two role users with discrete lws_sul for each pt.
157 lines
3.9 KiB
C
157 lines
3.9 KiB
C
/*
|
|
* lws-minimal-http-server-h2-long-poll
|
|
*
|
|
* Written in 2010-2019 by Andy Green <andy@warmcat.com>
|
|
*
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
* Universal Public Domain Dedication.
|
|
*
|
|
* This demonstrates an h2 server that supports "long poll"
|
|
* immortal client connections. For simplicity it doesn't serve
|
|
* any regular files, you can add a mount to do it if you want.
|
|
*
|
|
* The protocol keeps the long poll h2 stream open, and sends
|
|
* the time on the stream once per minute. Normally idle h2
|
|
* connections are closed by default within 30s, so this demonstrates
|
|
* the stream and network connection are operating as "immortal"
|
|
* on both sides.
|
|
*
|
|
* See http-client/minimal-http-client-h2-long-poll for the
|
|
* client example that connects and transitions the stream to the
|
|
* immortal long poll mode.
|
|
*/
|
|
|
|
#include <libwebsockets.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
|
|
static int interrupted;
|
|
|
|
struct pss {
|
|
struct lws *wsi;
|
|
lws_sorted_usec_list_t sul;
|
|
char pending;
|
|
};
|
|
|
|
static const lws_retry_bo_t retry = {
|
|
.secs_since_valid_ping = 5,
|
|
.secs_since_valid_hangup = 10,
|
|
};
|
|
|
|
static void
|
|
sul_cb(lws_sorted_usec_list_t *sul)
|
|
{
|
|
struct pss *pss = (struct pss *)lws_container_of(sul, struct pss, sul);
|
|
|
|
pss->pending = 1;
|
|
lws_callback_on_writable(pss->wsi);
|
|
/* interval 1min... longer than any normal timeout */
|
|
lws_sul_schedule(lws_get_context(pss->wsi), 0, &pss->sul, sul_cb,
|
|
60 * LWS_US_PER_SEC);
|
|
}
|
|
|
|
static int
|
|
callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|
void *in, size_t len)
|
|
{
|
|
struct pss * pss = (struct pss *)user;
|
|
uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE],
|
|
*start = &buf[LWS_PRE], *p = start,
|
|
*end = p + sizeof(buf) - LWS_PRE;
|
|
int m, n;
|
|
|
|
switch (reason) {
|
|
case LWS_CALLBACK_HTTP:
|
|
lwsl_user("%s: connect\n", __func__);
|
|
pss->wsi = wsi;
|
|
|
|
if (lws_add_http_common_headers(wsi, HTTP_STATUS_OK,
|
|
"text/html",
|
|
LWS_ILLEGAL_HTTP_CONTENT_LEN, /* no content len */
|
|
&p, end))
|
|
return 1;
|
|
if (lws_finalize_write_http_header(wsi, start, &p, end))
|
|
return 1;
|
|
|
|
sul_cb(&pss->sul);
|
|
return 0;
|
|
|
|
case LWS_CALLBACK_CLOSED_HTTP:
|
|
if (!pss)
|
|
break;
|
|
lws_sul_schedule(lws_get_context(wsi), 0, &pss->sul, sul_cb,
|
|
LWS_SET_TIMER_USEC_CANCEL);
|
|
break;
|
|
|
|
case LWS_CALLBACK_HTTP_WRITEABLE:
|
|
if (!pss->pending)
|
|
break;
|
|
n = lws_snprintf((char *)p, sizeof(buf) - LWS_PRE, "%llu",
|
|
(unsigned long long)lws_now_usecs());
|
|
m = lws_write(wsi, p, n, LWS_WRITE_HTTP);
|
|
if (m < n) {
|
|
lwsl_err("ERROR %d writing to socket\n", n);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return lws_callback_http_dummy(wsi, reason, user, in, len);
|
|
}
|
|
|
|
static struct lws_protocols protocols[] = {
|
|
{ "http", callback_http, sizeof(struct pss), 0 },
|
|
{ NULL, NULL, 0, 0 } /* terminator */
|
|
};
|
|
|
|
|
|
void sigint_handler(int sig)
|
|
{
|
|
interrupted = 1;
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
struct lws_context_creation_info info;
|
|
struct lws_context *context;
|
|
const char *p;
|
|
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
|
|
|
signal(SIGINT, sigint_handler);
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
|
logs = atoi(p);
|
|
|
|
lws_set_log_level(logs, NULL);
|
|
lwsl_user("LWS minimal http server h2 long poll\n");
|
|
|
|
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
|
info.port = 7681;
|
|
info.ssl_cert_filepath = "localhost-100y.cert";
|
|
info.ssl_private_key_filepath = "localhost-100y.key";
|
|
info.protocols = protocols;
|
|
info.options =
|
|
LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
|
|
LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL |
|
|
LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
|
|
|
|
/* the default validity check is 5m / 5m10s... -v = 5s / 10s */
|
|
|
|
if (lws_cmdline_option(argc, argv, "-v"))
|
|
info.retry_and_idle_policy = &retry;
|
|
|
|
context = lws_create_context(&info);
|
|
if (!context) {
|
|
lwsl_err("lws init failed\n");
|
|
return 1;
|
|
}
|
|
|
|
while (n >= 0 && !interrupted)
|
|
n = lws_service(context, 0);
|
|
|
|
lws_context_destroy(context);
|
|
|
|
return 0;
|
|
}
|