mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
lws_validity: unified connection validity tracking
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.
This commit is contained in:
parent
503bb8f8c9
commit
f9f6bb66fe
41 changed files with 559 additions and 219 deletions
14
README.md
14
README.md
|
@ -16,6 +16,20 @@ various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to
|
|||
News
|
||||
----
|
||||
|
||||
## Connection Validity tracking
|
||||
|
||||
Lws now allows you to apply a policy for how long a network connection may go
|
||||
without seeing something on it that confirms it's still valid in the sense of
|
||||
passing traffic cohernetly both ways. There's a global policy in the context
|
||||
which defaults to 5m before it produces a PING if possible, and 5m10 before
|
||||
the connection will be hung up, user code can override this in the context,
|
||||
vhost (for server) and client connection info (for client).
|
||||
|
||||
An api `lws_validity_confirmed(wsi)` is provided so user code can indicate
|
||||
that it observed traffic that must mean the connection is passing traffic in
|
||||
both directions to and from the peer. In the absence of these confirmations
|
||||
lws will generate PINGs and take PONGs as the indication of validity.
|
||||
|
||||
## Async DNS support
|
||||
|
||||
Master now provides optional Asynchronous (ie, nonblocking) DNS resolving. Enable
|
||||
|
|
98
READMEs/README.lws_retry.md
Normal file
98
READMEs/README.lws_retry.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
# `lws_retry_bo_t` client connection management
|
||||
|
||||
This struct sets the policy for delays between retries, and for
|
||||
how long a connection may be 'idle' before it first tries to
|
||||
ping / pong on it to confirm it's up, or drops the connection
|
||||
if still idle.
|
||||
|
||||
## Retry rate limiting
|
||||
|
||||
You can define a table of ms-resolution delays indexed by which
|
||||
connection attempt number is ongoing, this is pointed to by
|
||||
`.retry_ms_table` with `.retry_ms_table_count` containing the
|
||||
count of table entries.
|
||||
|
||||
`.conceal_count` is the number of retries that should be allowed
|
||||
before informing the parent that the connection has failed. If it's
|
||||
greater than the number of entries in the table, the last entry is
|
||||
reused for the additional attempts.
|
||||
|
||||
`.jitter_percent` controls how much additional random delay is
|
||||
added to the actual interval to be used... this stops a lot of
|
||||
devices all synchronizing when they try to connect after a single
|
||||
trigger event and DDoS-ing the server.
|
||||
|
||||
The struct and apis are provided for user implementations, lws does
|
||||
not offer reconnection itself.
|
||||
|
||||
## Connection validity management
|
||||
|
||||
Lws has a sophisticated idea of connection validity and the need to
|
||||
reconfirm that a connection is still operable if proof of validity
|
||||
has not been seen for some time. It concerns itself only with network
|
||||
connections rather than streams, for example, it only checks h2
|
||||
network connections rather than the individual streams inside (which
|
||||
is consistent with h2 PING frames only working at the network stream
|
||||
level itself).
|
||||
|
||||
Connections may fail in a variety of ways, these include that no traffic
|
||||
at all is passing, or, eg, incoming traffic may be received but no
|
||||
outbound traffic is making it to the network, and vice versa. In the
|
||||
case that tx is not failing at any point but just isn't getting sent,
|
||||
endpoints can potentially kid themselves that since "they are sending"
|
||||
and they are seeing RX, the combination means the connection is valid.
|
||||
This can potentially continue for a long time if the peer is not
|
||||
performing keepalives.
|
||||
|
||||
"Connection validity" is proven when one side sends something and later
|
||||
receives a response that can only have been generated by the peer
|
||||
receiving what was just sent. This can happen for some kinds of user
|
||||
transactions on any stream using the connection, or by sending PING /
|
||||
PONG protocol packets where the PONG is only returned for a received PING.
|
||||
|
||||
To ensure that the generated traffic is only sent when necessary, user
|
||||
code can report for any stream that it has observed a transaction amounting
|
||||
to a proof of connection validity using an api. This resets the timer for
|
||||
the associated network connection before the validity is considered
|
||||
expired.
|
||||
|
||||
`.secs_since_valid_ping` in the retry struct sets the number of seconds since
|
||||
the last validity after which lws will issue a protocol-specific PING of some
|
||||
kind on the connection. `.secs_since_valid_hangup` specifies how long lws
|
||||
will allow the connection to go without a confirmation of validity before
|
||||
simply hanging up on it.
|
||||
|
||||
## Defaults
|
||||
|
||||
The context defaults to having a 5m valid ping interval and 5m10s hangup interval,
|
||||
ie, it'll send a ping at 5m idle if the protocol supports it, and if no response
|
||||
validating the connection arrives in another 10s, hang up the connection.
|
||||
|
||||
User code can set this in the context creation info and can individually set the
|
||||
retry policy per vhost for server connections. Client connections can set it
|
||||
per connection in the client creation info `.retry_and_idle_policy`.
|
||||
|
||||
## Checking for h2 and ws
|
||||
|
||||
Check using paired minimal examples with the -v flag on one or both sides to get a
|
||||
small validity check period set of 3s / 10s
|
||||
|
||||
Also give, eg, -d1039 to see info level debug logging
|
||||
|
||||
### h2
|
||||
|
||||
```
|
||||
$ lws-minimal-http-server-h2-long-poll -v
|
||||
|
||||
$ lws-minimal-http-client -l -v
|
||||
```
|
||||
|
||||
### ws
|
||||
|
||||
```
|
||||
$ lws-minimal-ws-server-h2 -s -v
|
||||
|
||||
$ lws-minimal-ws-client-ping -n --server 127.0.0.1 --port 7681 -v
|
||||
```
|
||||
|
||||
|
|
@ -529,6 +529,7 @@ struct lws_tokens;
|
|||
struct lws_vhost;
|
||||
struct lws;
|
||||
|
||||
#include <libwebsockets/lws-retry.h>
|
||||
#include <libwebsockets/lws-system.h>
|
||||
#include <libwebsockets/lws-detailed-latency.h>
|
||||
#include <libwebsockets/lws-ws-close.h>
|
||||
|
@ -565,7 +566,6 @@ struct lws;
|
|||
#include <libwebsockets/lws-lwsac.h>
|
||||
#include <libwebsockets/lws-fts.h>
|
||||
#include <libwebsockets/lws-diskcache.h>
|
||||
#include <libwebsockets/lws-retry.h>
|
||||
#include <libwebsockets/lws-sequencer.h>
|
||||
|
||||
#include <libwebsockets/abstract/abstract.h>
|
||||
|
|
|
@ -133,6 +133,11 @@ struct lws_client_connect_info {
|
|||
* an lws_seq_t.
|
||||
*/
|
||||
|
||||
const lws_retry_bo_t *retry_and_idle_policy;
|
||||
/**< optional retry and idle policy to apply to this connection.
|
||||
* Currently only the idle parts are applied to the connection.
|
||||
*/
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
*
|
||||
|
|
|
@ -688,6 +688,10 @@ struct lws_context_creation_info {
|
|||
* collected for each read and write */
|
||||
const char *detailed_latency_filepath;
|
||||
/**< CONTEXT: NULL, or filepath to put latency data into */
|
||||
const lws_retry_bo_t *retry_and_idle_policy;
|
||||
/**< VHOST: optional retry and idle policy to apply to this vhost.
|
||||
* Currently only the idle parts are applied to the connections.
|
||||
*/
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
|
|
@ -23,10 +23,12 @@
|
|||
*/
|
||||
|
||||
typedef struct lws_retry_bo {
|
||||
const uint32_t *retry_ms_table; /* base delay in ms */
|
||||
uint16_t retry_ms_table_count; /* entries in table */
|
||||
uint16_t conceal_count; /* max retries to conceal */
|
||||
uint8_t jitter_percent; /* % additional random jitter */
|
||||
const uint32_t *retry_ms_table; /* base delay in ms */
|
||||
uint16_t retry_ms_table_count; /* entries in table */
|
||||
uint16_t conceal_count; /* max retries to conceal */
|
||||
uint16_t secs_since_valid_ping; /* idle before PING issued */
|
||||
uint16_t secs_since_valid_hangup; /* idle before hangup conn */
|
||||
uint8_t jitter_percent; /* % additional random jitter */
|
||||
} lws_retry_bo_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -229,4 +229,26 @@ LWS_VISIBLE LWS_EXTERN void
|
|||
lws_sul_schedule(struct lws_context *context, int tsi,
|
||||
lws_sorted_usec_list_t *sul, sul_cb_t cb, lws_usec_t us);
|
||||
|
||||
/*
|
||||
* lws_validity_confirmed() - reset the validity timer for a network connection
|
||||
*
|
||||
* \param wsi: the connection that saw traffic proving the connection valid
|
||||
*
|
||||
* Network connections are subject to intervals defined by the context, the
|
||||
* vhost if server connections, or the client connect info if a client
|
||||
* connection. If the connection goes longer than the specified time since
|
||||
* last observing traffic that can only happen if traffic is passing in both
|
||||
* directions, then lws will try to create a PING transaction on the network
|
||||
* connection.
|
||||
*
|
||||
* If the connection reaches the specified `.secs_since_valid_hangup` time
|
||||
* still without any proof of validity, the connection will be closed.
|
||||
*
|
||||
* If the PONG comes, or user code observes traffic that satisfies the proof
|
||||
* that both directions are passing traffic to the peer and calls this api,
|
||||
* the connection validity timer is reset and the scheme repeats.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_validity_confirmed(struct lws *wsi);
|
||||
|
||||
///@}
|
||||
|
|
|
@ -71,6 +71,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
|
|||
new_wsi->context = vhost->context;
|
||||
new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
|
||||
new_wsi->retry_policy = vhost->retry_policy;
|
||||
|
||||
#if defined(LWS_WITH_DETAILED_LATENCY)
|
||||
if (vhost->context->detailed_latency_cb)
|
||||
|
|
|
@ -60,6 +60,10 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
wsi->context = i->context;
|
||||
wsi->desc.sockfd = LWS_SOCK_INVALID;
|
||||
wsi->seq = i->seq;
|
||||
if (i->retry_and_idle_policy)
|
||||
wsi->retry_policy = i->retry_and_idle_policy;
|
||||
else
|
||||
wsi->retry_policy = &i->context->default_retry;
|
||||
|
||||
#if defined(LWS_WITH_DETAILED_LATENCY)
|
||||
if (i->context->detailed_latency_cb)
|
||||
|
|
|
@ -354,6 +354,9 @@ struct lws_context_per_thread {
|
|||
#if defined(LWS_PLAT_UNIX)
|
||||
lws_sorted_usec_list_t sul_plat;
|
||||
#endif
|
||||
#if defined(LWS_ROLE_CGI)
|
||||
lws_sorted_usec_list_t sul_cgi;
|
||||
#endif
|
||||
#if defined(LWS_WITH_STATS)
|
||||
uint64_t lws_stats[LWSSTATS_SIZE];
|
||||
int updated;
|
||||
|
@ -508,6 +511,8 @@ struct lws_vhost {
|
|||
struct lws_context *context;
|
||||
struct lws_vhost *vhost_next;
|
||||
|
||||
const lws_retry_bo_t *retry_policy;
|
||||
|
||||
struct lws *lserv_wsi;
|
||||
const char *name;
|
||||
const char *iface;
|
||||
|
@ -584,7 +589,6 @@ struct lws {
|
|||
#endif
|
||||
#if defined(LWS_ROLE_WS)
|
||||
struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */
|
||||
lws_sorted_usec_list_t sul_ping;
|
||||
#endif
|
||||
#if defined(LWS_ROLE_DBUS)
|
||||
struct _lws_dbus_mode_related dbus;
|
||||
|
@ -606,6 +610,8 @@ struct lws {
|
|||
|
||||
lws_sorted_usec_list_t sul_timeout;
|
||||
lws_sorted_usec_list_t sul_hrtimer;
|
||||
lws_sorted_usec_list_t sul_validity;
|
||||
|
||||
struct lws_dll2 dll_buflist; /* guys with pending rxflow */
|
||||
struct lws_dll2 same_vh_protocol;
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
|
@ -627,6 +633,7 @@ struct lws {
|
|||
const struct lws_role_ops *role_ops;
|
||||
const struct lws_protocols *protocol;
|
||||
struct lws_sequencer *seq; /* associated sequencer if any */
|
||||
const lws_retry_bo_t *retry_policy;
|
||||
|
||||
#if defined(LWS_WITH_THREADPOOL)
|
||||
struct lws_threadpool_task *tp_task;
|
||||
|
@ -710,6 +717,7 @@ struct lws {
|
|||
unsigned int proxied_ws_parent:1;
|
||||
unsigned int do_bind:1;
|
||||
unsigned int oom4:1;
|
||||
unsigned int validity_hup:1;
|
||||
|
||||
unsigned int could_have_pending:1; /* detect back-to-back writes */
|
||||
unsigned int outer_will_close:1;
|
||||
|
@ -961,9 +969,6 @@ lws_plat_plugins_init(struct lws_context * context, const char * const *d);
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_plat_plugins_destroy(struct lws_context * context);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_restart_ws_ping_pong_timer(struct lws *wsi);
|
||||
|
||||
struct lws *
|
||||
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
|
||||
|
||||
|
@ -1197,6 +1202,11 @@ lws_threadpool_tsi_context(struct lws_context *context, int tsi);
|
|||
void
|
||||
__lws_wsi_remove_from_sul(struct lws *wsi);
|
||||
|
||||
void
|
||||
lws_validity_confirmed(struct lws *wsi);
|
||||
void
|
||||
_lws_validity_confirmed_role(struct lws *wsi);
|
||||
|
||||
int
|
||||
lws_seq_pt_init(struct lws_context_per_thread *pt);
|
||||
|
||||
|
|
|
@ -475,6 +475,12 @@ lws_create_vhost(struct lws_context *context,
|
|||
#if !defined(LWS_PLAT_FREERTOS) && !defined(OPTEE_TA) && !defined(WIN32)
|
||||
vh->bind_iface = info->bind_iface;
|
||||
#endif
|
||||
/* apply the context default lws_retry */
|
||||
|
||||
if (info->retry_and_idle_policy)
|
||||
vh->retry_policy = info->retry_and_idle_policy;
|
||||
else
|
||||
vh->retry_policy = &context->default_retry;
|
||||
|
||||
/*
|
||||
* let's figure out how many protocols the user is handing us, using the
|
||||
|
|
|
@ -35,9 +35,7 @@ __lws_wsi_remove_from_sul(struct lws *wsi)
|
|||
// lws_dll2_describe(&pt->pt_sul_owner, "pre-remove");
|
||||
lws_dll2_remove(&wsi->sul_timeout.list);
|
||||
lws_dll2_remove(&wsi->sul_hrtimer.list);
|
||||
#if defined(LWS_ROLE_WS)
|
||||
lws_dll2_remove(&wsi->sul_ping.list);
|
||||
#endif
|
||||
lws_dll2_remove(&wsi->sul_validity.list);
|
||||
// lws_dll2_describe(&pt->pt_sul_owner, "post-remove");
|
||||
}
|
||||
|
||||
|
@ -227,7 +225,7 @@ lws_sul_timed_callback_vh_protocol_cb(lws_sorted_usec_list_t *sul)
|
|||
__lws_timed_callback_remove(tvp->vhost, tvp);
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
int
|
||||
lws_timed_callback_vh_protocol_us(struct lws_vhost *vh,
|
||||
const struct lws_protocols *prot, int reason,
|
||||
lws_usec_t us)
|
||||
|
@ -267,7 +265,7 @@ lws_timed_callback_vh_protocol_us(struct lws_vhost *vh,
|
|||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
int
|
||||
lws_timed_callback_vh_protocol(struct lws_vhost *vh,
|
||||
const struct lws_protocols *prot, int reason,
|
||||
int secs)
|
||||
|
@ -275,3 +273,84 @@ lws_timed_callback_vh_protocol(struct lws_vhost *vh,
|
|||
return lws_timed_callback_vh_protocol_us(vh, prot, reason,
|
||||
((lws_usec_t)secs) * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_validity_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws *wsi = lws_container_of(sul, struct lws, sul_validity);
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
const lws_retry_bo_t *rbo = wsi->retry_policy;
|
||||
|
||||
/* one of either the ping or hangup validity threshold was crossed */
|
||||
|
||||
if (wsi->validity_hup) {
|
||||
lwsl_info("%s: wsi %p: validity too old\n", __func__, wsi);
|
||||
__lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"validity timeout");
|
||||
return;
|
||||
}
|
||||
|
||||
/* schedule a protocol-dependent ping */
|
||||
|
||||
lwsl_info("%s: wsi %p: scheduling validity check\n", __func__, wsi);
|
||||
|
||||
if (wsi->role_ops && wsi->role_ops->issue_keepalive)
|
||||
wsi->role_ops->issue_keepalive(wsi, 0);
|
||||
|
||||
/*
|
||||
* We arrange to come back here after the additional ping to hangup time
|
||||
* and do the hangup, unless we get validated (by, eg, a PONG) and
|
||||
* reset the timer
|
||||
*/
|
||||
|
||||
assert(rbo->secs_since_valid_hangup > rbo->secs_since_valid_ping);
|
||||
|
||||
wsi->validity_hup = 1;
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_validity,
|
||||
((uint64_t)rbo->secs_since_valid_hangup -
|
||||
rbo->secs_since_valid_ping) * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* The role calls this back to actually confirm validity on a particular wsi
|
||||
* (which may not be the original wsi)
|
||||
*/
|
||||
|
||||
void
|
||||
_lws_validity_confirmed_role(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
const lws_retry_bo_t *rbo = wsi->retry_policy;
|
||||
|
||||
if (!rbo || !rbo->secs_since_valid_hangup)
|
||||
return;
|
||||
|
||||
wsi->validity_hup = 0;
|
||||
wsi->sul_validity.cb = lws_validity_cb;
|
||||
|
||||
wsi->validity_hup = rbo->secs_since_valid_ping >=
|
||||
rbo->secs_since_valid_hangup;
|
||||
|
||||
lwsl_info("%s: wsi %p: setting validity timer %ds (hup %d)\n",
|
||||
__func__, wsi,
|
||||
wsi->validity_hup ? rbo->secs_since_valid_hangup :
|
||||
rbo->secs_since_valid_ping,
|
||||
wsi->validity_hup);
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_validity,
|
||||
((uint64_t)(wsi->validity_hup ?
|
||||
rbo->secs_since_valid_hangup :
|
||||
rbo->secs_since_valid_ping)) * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
void
|
||||
lws_validity_confirmed(struct lws *wsi)
|
||||
{
|
||||
/*
|
||||
* This may be a stream inside a muxed network connection... leave it
|
||||
* to the role to figure out who actually needs to understand their
|
||||
* validity was confirmed.
|
||||
*/
|
||||
if (wsi->role_ops && wsi->role_ops->issue_keepalive)
|
||||
wsi->role_ops->issue_keepalive(wsi, 1);
|
||||
}
|
||||
|
|
|
@ -28,9 +28,13 @@
|
|||
#define LWS_BUILD_HASH "unknown-build-hash"
|
||||
#endif
|
||||
|
||||
|
||||
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
/* in ms */
|
||||
static uint32_t default_backoff_table[] = { 1000, 3000, 9000, 17000 };
|
||||
#endif
|
||||
|
||||
/**
|
||||
* lws_get_library_version: get version and git hash library built from
|
||||
*
|
||||
|
@ -164,11 +168,6 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LWS_ROLE_H2)
|
||||
role_ops_h2.init_context(context, info);
|
||||
#endif
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
lws_mutex_refcount_init(&context->mr);
|
||||
#endif
|
||||
|
@ -373,6 +372,15 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->count_threads;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
||||
context->default_retry.retry_ms_table = default_backoff_table;
|
||||
context->default_retry.conceal_count =
|
||||
context->default_retry.retry_ms_table_count =
|
||||
LWS_ARRAY_SIZE(default_backoff_table);
|
||||
context->default_retry.jitter_percent = 20;
|
||||
context->default_retry.secs_since_valid_ping = 300;
|
||||
context->default_retry.secs_since_valid_hangup = 310;
|
||||
|
||||
/*
|
||||
* Allocate the per-thread storage for scratchpad buffers,
|
||||
* and header data pool
|
||||
|
@ -405,6 +413,12 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
#if defined(LWS_WITH_SEQUENCER)
|
||||
lws_seq_pt_init(&context->pt[n]);
|
||||
#endif
|
||||
|
||||
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
|
||||
if (ar->pt_init_destroy)
|
||||
ar->pt_init_destroy(context, info,
|
||||
&context->pt[n], 0);
|
||||
} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
||||
}
|
||||
|
||||
lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
|
||||
|
@ -634,6 +648,10 @@ lws_context_destroy3(struct lws_context *context)
|
|||
#if defined(LWS_WITH_SEQUENCER)
|
||||
lws_seq_destroy_all_on_pt(pt);
|
||||
#endif
|
||||
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
|
||||
if (ar->pt_init_destroy)
|
||||
ar->pt_init_destroy(context, NULL, pt, 1);
|
||||
} LWS_FOR_EVERY_AVAILABLE_ROLE_END;
|
||||
|
||||
if (context->event_loop_ops->destroy_pt)
|
||||
context->event_loop_ops->destroy_pt(context, n);
|
||||
|
|
|
@ -274,6 +274,7 @@ struct lws_context {
|
|||
#if defined(LWS_WITH_NETWORK)
|
||||
|
||||
struct lws_context_per_thread pt[LWS_MAX_SMP];
|
||||
lws_retry_bo_t default_retry;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
struct http2_settings set;
|
||||
|
|
|
@ -44,9 +44,6 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
|
|||
struct lws_context_per_thread *pt =
|
||||
lws_container_of(sul, struct lws_context_per_thread, sul_plat);
|
||||
struct lws_context *context = pt->context;
|
||||
#if defined(LWS_ROLE_CGI) || defined(LWS_ROLE_DBUS)
|
||||
time_t now = time(NULL);
|
||||
#endif
|
||||
|
||||
#if !defined(LWS_NO_DAEMONIZE)
|
||||
/* if our parent went down, don't linger around */
|
||||
|
@ -83,13 +80,6 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul)
|
|||
lws_context_unlock(context);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_CGI)
|
||||
role_ops_cgi.periodic_checks(context, 0, now);
|
||||
#endif
|
||||
#if defined(LWS_ROLE_DBUS)
|
||||
role_ops_dbus.periodic_checks(context, 0, now);
|
||||
#endif
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_plat, 30 * LWS_US_PER_SEC);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1064,7 +1064,7 @@ handled:
|
|||
return 0;
|
||||
}
|
||||
|
||||
LWS_EXTERN int
|
||||
int
|
||||
lws_cgi_kill_terminated(struct lws_context_per_thread *pt)
|
||||
{
|
||||
struct lws_cgi **pcgi, *cgi = NULL;
|
||||
|
|
|
@ -68,16 +68,6 @@ rops_handle_POLLOUT_cgi(struct lws *wsi)
|
|||
return LWS_HP_RET_USER_SERVICE;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_periodic_checks_cgi(struct lws_context *context, int tsi, time_t now)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
|
||||
lws_cgi_kill_terminated(pt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_destroy_role_cgi(struct lws *wsi)
|
||||
{
|
||||
|
@ -94,14 +84,43 @@ rops_destroy_role_cgi(struct lws *wsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_cgi_sul_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws_context_per_thread *pt = lws_container_of(sul,
|
||||
struct lws_context_per_thread, sul_cgi);
|
||||
|
||||
lws_cgi_kill_terminated(pt);
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_cgi,
|
||||
3 * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
static int
|
||||
rops_pt_init_destroy_cgi(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info,
|
||||
struct lws_context_per_thread *pt, int destroy)
|
||||
{
|
||||
if (!destroy) {
|
||||
|
||||
pt->sul_cgi.cb = lws_cgi_sul_cb;
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_cgi,
|
||||
3 * LWS_US_PER_SEC);
|
||||
} else
|
||||
lws_dll2_remove(&pt->sul_cgi.list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct lws_role_ops role_ops_cgi = {
|
||||
/* role name */ "cgi",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ rops_pt_init_destroy_cgi,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ rops_periodic_checks_cgi,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_cgi,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_cgi,
|
||||
|
@ -117,6 +136,7 @@ struct lws_role_ops role_ops_cgi = {
|
|||
/* destroy_role */ rops_destroy_role_cgi,
|
||||
/* adoption_bind */ NULL,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { 0, 0 },
|
||||
/* rx_cb clnt, srv */ { 0, 0 },
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
|
|
|
@ -472,23 +472,18 @@ rops_handle_POLLIN_dbus(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
return LWS_HPI_RET_HANDLED;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_periodic_checks_dbus(struct lws_context *context, int tsi, time_t now)
|
||||
static void
|
||||
lws_dbus_sul_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
|
||||
/*
|
||||
* locking shouldn't be needed here, because periodic_checks is called
|
||||
* from the tsi-specific service thread context, and only the same
|
||||
* service thread can modify stuff on the same pt.
|
||||
*/
|
||||
struct lws_context_per_thread *pt = lws_container_of(sul,
|
||||
struct lws_context_per_thread, dbus.sul);
|
||||
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, rdt, nx,
|
||||
lws_dll2_get_head(&pt->dbus.timer_list_owner)) {
|
||||
struct lws_role_dbus_timer *r = lws_container_of(rdt,
|
||||
struct lws_role_dbus_timer, timer_list);
|
||||
|
||||
if (now > r->fire) {
|
||||
if (time(NULL) > r->fire) {
|
||||
lwsl_notice("%s: firing timer\n", __func__);
|
||||
dbus_timeout_handle(r->data);
|
||||
lws_dll2_remove(rdt);
|
||||
|
@ -496,6 +491,24 @@ rops_periodic_checks_dbus(struct lws_context *context, int tsi, time_t now)
|
|||
}
|
||||
} lws_end_foreach_dll_safe(rdt, nx);
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->dbus.sul,
|
||||
3 * LWS_US_PER_SEC);
|
||||
}
|
||||
|
||||
static int
|
||||
rops_pt_init_destroy_dbus(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info,
|
||||
struct lws_context_per_thread *pt, int destroy)
|
||||
{
|
||||
if (!destroy) {
|
||||
|
||||
pt->dbus.sul.cb = lws_dbus_sul_cb;
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->dbus.sul,
|
||||
3 * LWS_US_PER_SEC);
|
||||
} else
|
||||
lws_dll2_remove(&pt->dbus.sul.list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -503,10 +516,9 @@ struct lws_role_ops role_ops_dbus = {
|
|||
/* role name */ "dbus",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ rops_pt_init_destroy_dbus,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ rops_periodic_checks_dbus,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_dbus,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
|
@ -522,6 +534,7 @@ struct lws_role_ops role_ops_dbus = {
|
|||
/* destroy_role */ NULL,
|
||||
/* adoption_bind */ NULL,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { 0, 0 },
|
||||
/* rx_cb clnt, srv */ { 0, 0 },
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
|
|
|
@ -38,6 +38,7 @@ struct lws_role_dbus_timer {
|
|||
|
||||
struct lws_pt_role_dbus {
|
||||
struct lws_dll2_owner timer_list_owner;
|
||||
lws_sorted_usec_list_t sul;
|
||||
};
|
||||
|
||||
struct _lws_dbus_mode_related {
|
||||
|
|
|
@ -1105,24 +1105,23 @@ rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason)
|
|||
}
|
||||
|
||||
int
|
||||
rops_init_context_h1(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
rops_pt_init_destroy_h1(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info,
|
||||
struct lws_context_per_thread *pt, int destroy)
|
||||
{
|
||||
/*
|
||||
* We only want to do this once... we will do it if no h2 support
|
||||
* otherwise let h2 ops do it.
|
||||
*/
|
||||
#if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
|
||||
int n;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
struct lws_context_per_thread *pt = &context->pt[n];
|
||||
if (!destroy) {
|
||||
|
||||
pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_ah_lifecheck,
|
||||
30 * LWS_US_PER_SEC);
|
||||
}
|
||||
} else
|
||||
lws_dll2_remove(&pt->sul_ah_lifecheck.list);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -1132,10 +1131,9 @@ struct lws_role_ops role_ops_h1 = {
|
|||
/* role name */ "h1",
|
||||
/* alpn id */ "http/1.1",
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ rops_init_context_h1,
|
||||
/* pt_init_destroy */ rops_pt_init_destroy_h1,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_h1,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_h1,
|
||||
|
@ -1159,6 +1157,7 @@ struct lws_role_ops role_ops_h1 = {
|
|||
#else
|
||||
NULL,
|
||||
#endif
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
|
||||
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
||||
|
|
|
@ -120,7 +120,7 @@ lws_h2_dump_settings(struct http2_settings *set)
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct lws_h2_protocol_send *
|
||||
struct lws_h2_protocol_send *
|
||||
lws_h2_new_pps(enum lws_h2_protocol_send_type type)
|
||||
{
|
||||
struct lws_h2_protocol_send *pps = lws_malloc(sizeof(*pps), "pps");
|
||||
|
@ -212,6 +212,9 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi,
|
|||
wsi->vhost->conn_stats.h2_subs++;
|
||||
#endif
|
||||
|
||||
/* get the ball rolling */
|
||||
lws_validity_confirmed(wsi);
|
||||
|
||||
lwsl_info("%s: %p new ch %p, sid %d, usersp=%p, tx cr %d, "
|
||||
"peer_credit %d (nwsi tx_cr %d)\n",
|
||||
__func__, parent_wsi, wsi, sid, wsi->user_space,
|
||||
|
@ -727,17 +730,27 @@ int lws_h2_do_pps_send(struct lws *wsi)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* h2 only has PING... ACK = 0 = ping, ACK = 1 = pong
|
||||
*/
|
||||
|
||||
case LWS_H2_PPS_PING:
|
||||
case LWS_H2_PPS_PONG:
|
||||
lwsl_debug("sending PONG\n");
|
||||
if (pps->type == LWS_H2_PPS_PING)
|
||||
lwsl_info("sending PING\n");
|
||||
else {
|
||||
lwsl_info("sending PONG\n");
|
||||
flags = LWS_H2_FLAG_SETTINGS_ACK;
|
||||
}
|
||||
|
||||
memcpy(&set[LWS_PRE], pps->u.ping.ping_payload, 8);
|
||||
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING,
|
||||
LWS_H2_FLAG_SETTINGS_ACK,
|
||||
n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING, flags,
|
||||
LWS_H2_STREAM_ID_MASTER, 8,
|
||||
&set[LWS_PRE]);
|
||||
if (n != 8) {
|
||||
lwsl_info("send %d %d\n", n, m);
|
||||
if (n != 8)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LWS_H2_PPS_GOAWAY:
|
||||
|
@ -1599,6 +1612,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
|
||||
case LWS_H2_FRAME_TYPE_PING:
|
||||
if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) { // ack
|
||||
lws_validity_confirmed(wsi);
|
||||
} else {/* they're sending us a ping request */
|
||||
struct lws_h2_protocol_send *pps =
|
||||
lws_h2_new_pps(LWS_H2_PPS_PONG);
|
||||
|
@ -1737,6 +1751,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|||
|
||||
lwsl_info("http2: %p: established\n", wsi);
|
||||
lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS);
|
||||
lws_validity_confirmed(wsi);
|
||||
h2n->count = 0;
|
||||
wsi->h2.tx_cr = 65535;
|
||||
|
||||
|
@ -2339,6 +2354,8 @@ lws_h2_ws_handshake(struct lws *wsi)
|
|||
(void *)hit->cgienv, 0))
|
||||
return 1;
|
||||
|
||||
lws_validity_confirmed(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -538,33 +538,32 @@ rops_init_vhost_h2(struct lws_vhost *vh,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_init_context_h2(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
int
|
||||
rops_pt_init_destroy_h2(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info,
|
||||
struct lws_context_per_thread *pt, int destroy)
|
||||
{
|
||||
int n;
|
||||
|
||||
context->set = lws_h2_stock_settings;
|
||||
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
/*
|
||||
* We only want to do this once... we will do it if we are built
|
||||
* otherwise h1 ops will do it (or nobody if no http at all)
|
||||
*/
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
struct lws_context_per_thread *pt = &context->pt[n];
|
||||
#if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER)
|
||||
if (!destroy) {
|
||||
|
||||
pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck;
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &pt->sul_ah_lifecheck,
|
||||
30 * LWS_US_PER_SEC);
|
||||
}
|
||||
} else
|
||||
lws_dll2_remove(&pt->sul_ah_lifecheck.list);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static lws_fileofs_t
|
||||
rops_tx_credit_h2(struct lws *wsi)
|
||||
{
|
||||
|
@ -1242,14 +1241,51 @@ rops_alpn_negotiated_h2(struct lws *wsi, const char *alpn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_issue_keepalive_h2(struct lws *wsi, int isvalid)
|
||||
{
|
||||
struct lws *nwsi = lws_get_network_wsi(wsi);
|
||||
struct lws_h2_protocol_send *pps;
|
||||
uint64_t us = lws_now_usecs();
|
||||
|
||||
if (isvalid) {
|
||||
_lws_validity_confirmed_role(nwsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can only send these frames on the network connection itself...
|
||||
* we shouldn't be tracking validity on anything else
|
||||
*/
|
||||
|
||||
assert(wsi == nwsi);
|
||||
|
||||
pps = lws_h2_new_pps(LWS_H2_PPS_PING);
|
||||
if (!pps)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* The peer is defined to copy us back the unchanged payload in another
|
||||
* PING frame this time with ACK set. So by sending that out with the
|
||||
* current time, it's an interesting opportunity to learn the effective
|
||||
* RTT on the link when the PONG comes in, plus or minus the time to
|
||||
* schedule the PPS.
|
||||
*/
|
||||
|
||||
memcpy(pps->u.ping.ping_payload, &us, 8);
|
||||
lws_pps_schedule(nwsi, pps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_h2 = {
|
||||
/* role name */ "h2",
|
||||
/* alpn id */ "h2",
|
||||
/* check_upgrades */ rops_check_upgrades_h2,
|
||||
/* init_context */ rops_init_context_h2,
|
||||
/* pt_init_destroy */ rops_pt_init_destroy_h2,
|
||||
/* init_vhost */ rops_init_vhost_h2,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_h2,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_h2,
|
||||
|
@ -1265,6 +1301,7 @@ struct lws_role_ops role_ops_h2 = {
|
|||
/* destroy_role */ rops_destroy_role_h2,
|
||||
/* adoption_bind */ NULL,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ rops_issue_keepalive_h2,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
|
||||
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
|
||||
/* rx cb clnt, srv */ { LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
||||
|
|
|
@ -211,6 +211,7 @@ enum lws_h2_protocol_send_type {
|
|||
LWS_PPS_NONE,
|
||||
LWS_H2_PPS_MY_SETTINGS,
|
||||
LWS_H2_PPS_ACK_SETTINGS,
|
||||
LWS_H2_PPS_PING,
|
||||
LWS_H2_PPS_PONG,
|
||||
LWS_H2_PPS_GOAWAY,
|
||||
LWS_H2_PPS_RST_STREAM,
|
||||
|
@ -406,3 +407,5 @@ int
|
|||
lws_handle_POLLOUT_event_h2(struct lws *wsi);
|
||||
int
|
||||
lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
|
||||
struct lws_h2_protocol_send *
|
||||
lws_h2_new_pps(enum lws_h2_protocol_send_type type);
|
||||
|
|
|
@ -176,10 +176,9 @@ struct lws_role_ops role_ops_listen = {
|
|||
/* role name */ "listen",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_listen,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_listen,
|
||||
|
@ -195,6 +194,7 @@ struct lws_role_ops role_ops_listen = {
|
|||
/* destroy_role */ NULL,
|
||||
/* adoption_bind */ NULL,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { 0, 0 },
|
||||
/* rx_cb clnt, srv */ { 0, 0 },
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
|
|
|
@ -72,10 +72,9 @@ struct lws_role_ops role_ops_pipe = {
|
|||
/* role name */ "pipe",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_pipe,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
|
@ -91,6 +90,7 @@ struct lws_role_ops role_ops_pipe = {
|
|||
/* destroy_role */ NULL,
|
||||
/* adoption_bind */ NULL,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { 0, 0 },
|
||||
/* rx_cb clnt, srv */ { 0, 0 },
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
|
|
|
@ -180,16 +180,14 @@ struct lws_role_ops {
|
|||
*/
|
||||
int (*check_upgrades)(struct lws *wsi);
|
||||
/* role-specific context init during context creation */
|
||||
int (*init_context)(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info);
|
||||
int (*pt_init_destroy)(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info,
|
||||
struct lws_context_per_thread *pt, int destroy);
|
||||
/* role-specific per-vhost init during vhost creation */
|
||||
int (*init_vhost)(struct lws_vhost *vh,
|
||||
const struct lws_context_creation_info *info);
|
||||
/* role-specific per-vhost destructor during vhost destroy */
|
||||
int (*destroy_vhost)(struct lws_vhost *vh);
|
||||
/* generic 1Hz callback for the role itself */
|
||||
int (*periodic_checks)(struct lws_context *context, int tsi,
|
||||
time_t now);
|
||||
/* chance for the role to force POLLIN without network activity */
|
||||
int (*service_flag_pending)(struct lws_context *context, int tsi);
|
||||
/* an fd using this role has POLLIN signalled */
|
||||
|
@ -233,6 +231,9 @@ struct lws_role_ops {
|
|||
* case ret 0 = OK, 1 = fail, wsi needs freeing, -1 = fail, wsi freed */
|
||||
int (*client_bind)(struct lws *wsi,
|
||||
const struct lws_client_connect_info *i);
|
||||
/* isvalid = 0: request a role-specific keepalive (PING etc)
|
||||
* = 1: reset any related validity timer */
|
||||
int (*issue_keepalive)(struct lws *wsi, int isvalid);
|
||||
|
||||
/*
|
||||
* the callback reasons for adoption for client, server
|
||||
|
|
|
@ -81,10 +81,9 @@ struct lws_role_ops role_ops_raw_file = {
|
|||
/* role name */ "raw-file",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_raw_file,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
|
@ -100,6 +99,7 @@ struct lws_role_ops role_ops_raw_file = {
|
|||
/* destroy_role */ NULL,
|
||||
/* adoption_bind */ rops_adoption_bind_raw_file,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_RAW_ADOPT_FILE,
|
||||
LWS_CALLBACK_RAW_ADOPT_FILE },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_RAW_RX_FILE,
|
||||
|
|
|
@ -188,10 +188,9 @@ struct lws_role_ops role_ops_raw_proxy = {
|
|||
/* role name */ "raw-proxy",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_raw_proxy,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_raw_proxy,
|
||||
|
@ -207,6 +206,7 @@ struct lws_role_ops role_ops_raw_proxy = {
|
|||
/* destroy_role */ NULL,
|
||||
/* adoption_bind */ rops_adoption_bind_raw_proxy,
|
||||
/* client_bind */ rops_client_bind_raw_proxy,
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_RAW_PROXY_CLI_ADOPT,
|
||||
LWS_CALLBACK_RAW_PROXY_SRV_ADOPT },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_RAW_PROXY_CLI_RX,
|
||||
|
|
|
@ -219,10 +219,9 @@ struct lws_role_ops role_ops_raw_skt = {
|
|||
/* role name */ "raw-skt",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ NULL,
|
||||
/* init_vhost */ NULL,
|
||||
/* destroy_vhost */ NULL,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ NULL,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_raw_skt,
|
||||
/* handle_POLLOUT */ NULL,
|
||||
|
@ -246,6 +245,7 @@ struct lws_role_ops role_ops_raw_skt = {
|
|||
#else
|
||||
NULL,
|
||||
#endif
|
||||
/* issue_keepalive */ NULL,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_RAW_CONNECTED,
|
||||
LWS_CALLBACK_RAW_ADOPT },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_RAW_RX,
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
int lws_ws_client_rx_sm(struct lws *wsi, unsigned char c)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
|
||||
struct lws_ext_pm_deflate_rx_ebufs pmdrx;
|
||||
unsigned short close_code;
|
||||
|
@ -488,20 +487,7 @@ ping_drop:
|
|||
lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
|
||||
wsi->ws->rx_ubuf_head);
|
||||
|
||||
if (wsi->ws->await_pong) {
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
wsi->ws->await_pong = 0;
|
||||
|
||||
/*
|
||||
* prepare to send the ping again if nothing
|
||||
* sent to countermand it
|
||||
*/
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner,
|
||||
&wsi->sul_ping,
|
||||
(lws_usec_t)wsi->context->ws_ping_pong_interval *
|
||||
LWS_USEC_PER_SEC);
|
||||
}
|
||||
lws_validity_confirmed(wsi);
|
||||
/* issue it */
|
||||
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
|
||||
break;
|
||||
|
|
|
@ -234,7 +234,6 @@ lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1)
|
|||
int
|
||||
lws_client_ws_upgrade(struct lws *wsi, const char **cce)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct lws_context *context = wsi->context;
|
||||
struct lws_tokenize ts;
|
||||
int n, len, okay = 0;
|
||||
|
@ -242,6 +241,7 @@ lws_client_ws_upgrade(struct lws *wsi, const char **cce)
|
|||
char *p, buf[64];
|
||||
const char *pc;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char *sb = (char *)&pt->serv_buf[0];
|
||||
const struct lws_ext_options *opts;
|
||||
const struct lws_extension *ext;
|
||||
|
@ -630,15 +630,8 @@ check_accept:
|
|||
/* free up his parsing allocations */
|
||||
lws_header_table_detach(wsi, 0);
|
||||
|
||||
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
|
||||
&role_ops_ws);
|
||||
|
||||
if (wsi->context->ws_ping_pong_interval && !wsi->http2_substream ) {
|
||||
wsi->sul_ping.cb = lws_sul_wsping_cb;
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
|
||||
(lws_usec_t)wsi->context->ws_ping_pong_interval *
|
||||
LWS_USEC_PER_SEC);
|
||||
}
|
||||
lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED, &role_ops_ws);
|
||||
lws_validity_confirmed(wsi);
|
||||
|
||||
wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
int
|
||||
lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int callback_action = LWS_CALLBACK_RECEIVE;
|
||||
struct lws_ext_pm_deflate_rx_ebufs pmdrx;
|
||||
unsigned short close_code;
|
||||
|
@ -550,22 +549,7 @@ ping_drop:
|
|||
lwsl_hexdump(&wsi->ws->rx_ubuf[LWS_PRE],
|
||||
wsi->ws->rx_ubuf_head);
|
||||
|
||||
if (wsi->ws->await_pong) {
|
||||
lwsl_info("received expected PONG on wsi %p\n",
|
||||
wsi);
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
wsi->ws->await_pong = 0;
|
||||
|
||||
/*
|
||||
* prepare to send the ping again if nothing
|
||||
* sent to countermand it
|
||||
*/
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner,
|
||||
&wsi->sul_ping,
|
||||
(lws_usec_t)wsi->context->ws_ping_pong_interval *
|
||||
LWS_USEC_PER_SEC);
|
||||
}
|
||||
lws_validity_confirmed(wsi);
|
||||
|
||||
/* issue it */
|
||||
callback_action = LWS_CALLBACK_RECEIVE_PONG;
|
||||
|
@ -839,52 +823,13 @@ lws_0405_frame_mask_generate(struct lws *wsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_sul_wsping_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws *wsi = lws_container_of(sul, struct lws, sul_ping);
|
||||
|
||||
/*
|
||||
* The sul_ping timer came up... either it's time to send a PING
|
||||
* (!wsi->ws->send_check_ping), or we didn't get the PONG in time
|
||||
* (wsi->ws->send_check_ping)
|
||||
*/
|
||||
|
||||
if (!wsi->ws->send_check_ping) {
|
||||
lwsl_info("%s: req pp on wsi %p\n", __func__, wsi);
|
||||
|
||||
wsi->ws->send_check_ping = 1;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING,
|
||||
wsi->context->timeout_secs);
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (wsi->ws->await_pong) {
|
||||
/* it didn't return the PONG in time */
|
||||
|
||||
lwsl_info("%s: wsi %p: failed to send PONG\n", __func__, wsi);
|
||||
__lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"PONG timeout");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
lws_server_init_wsi_for_ws(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int n;
|
||||
|
||||
lwsi_set_state(wsi, LRS_ESTABLISHED);
|
||||
|
||||
if (wsi->context->ws_ping_pong_interval && !wsi->http2_substream ) {
|
||||
wsi->sul_ping.cb = lws_sul_wsping_cb;
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
|
||||
(lws_usec_t)wsi->context->ws_ping_pong_interval *
|
||||
LWS_USEC_PER_SEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, use
|
||||
|
@ -925,6 +870,7 @@ lws_server_init_wsi_for_ws(struct lws *wsi)
|
|||
wsi->h2_stream_carries_ws))
|
||||
return 1;
|
||||
|
||||
lws_validity_confirmed(wsi);
|
||||
lwsl_debug("ws established\n");
|
||||
|
||||
return 0;
|
||||
|
@ -1302,7 +1248,6 @@ drain:
|
|||
|
||||
int rops_handle_POLLOUT_ws(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
int write_type = LWS_WRITE_PONG;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
struct lws_ext_pm_deflate_rx_ebufs pmdrx;
|
||||
|
@ -1380,24 +1325,17 @@ int rops_handle_POLLOUT_ws(struct lws *wsi)
|
|||
}
|
||||
|
||||
if (!wsi->socket_is_permanently_unusable &&
|
||||
wsi->ws->send_check_ping && wsi->context->ws_ping_pong_interval) {
|
||||
wsi->ws->send_check_ping) {
|
||||
|
||||
lwsl_info("%s: issuing ping on wsi %p: %s %s h2: %d\n", __func__, wsi,
|
||||
wsi->role_ops->name, wsi->protocol->name,
|
||||
wsi->http2_substream);
|
||||
wsi->ws->send_check_ping = 0;
|
||||
wsi->ws->await_pong = 1;
|
||||
n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE],
|
||||
0, LWS_WRITE_PING);
|
||||
if (n < 0)
|
||||
return LWS_HP_RET_BAIL_DIE;
|
||||
|
||||
/* give it a few seconds to respond with the PONG */
|
||||
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
|
||||
(lws_usec_t)wsi->context->timeout_secs *
|
||||
LWS_USEC_PER_SEC);
|
||||
|
||||
return LWS_HP_RET_BAIL_OK;
|
||||
}
|
||||
|
||||
|
@ -1634,8 +1572,8 @@ static int
|
|||
rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
|
||||
enum lws_write_protocol *wp)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
enum lws_write_protocol wpt;
|
||||
#endif
|
||||
struct lws_ext_pm_deflate_rx_ebufs pmdrx;
|
||||
|
@ -1682,13 +1620,7 @@ rops_write_role_protocol_ws(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
// assert(0);
|
||||
}
|
||||
#endif
|
||||
/* reset the ping wait */
|
||||
if (wsi->context->ws_ping_pong_interval) {
|
||||
wsi->sul_ping.cb = lws_sul_wsping_cb;
|
||||
__lws_sul_insert(&pt->pt_sul_owner, &wsi->sul_ping,
|
||||
(lws_usec_t)wsi->context->ws_ping_pong_interval *
|
||||
LWS_USEC_PER_SEC);
|
||||
}
|
||||
|
||||
if (((*wp) & 0x1f) == LWS_WRITE_HTTP ||
|
||||
((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL ||
|
||||
((*wp) & 0x1f) == LWS_WRITE_HTTP_HEADERS_CONTINUATION ||
|
||||
|
@ -1980,7 +1912,6 @@ send_raw:
|
|||
static int
|
||||
rops_close_kill_connection_ws(struct lws *wsi, enum lws_close_status reason)
|
||||
{
|
||||
lws_dll2_remove(&wsi->sul_ping.list);
|
||||
/* deal with ws encapsulation in h2 */
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->http2_substream && wsi->h2_stream_carries_ws)
|
||||
|
@ -2087,14 +2018,41 @@ rops_destroy_role_ws(struct lws *wsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_issue_keepalive_ws(struct lws *wsi, int isvalid)
|
||||
{
|
||||
uint64_t us;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (lwsi_role_h2_ENCAPSULATION(wsi)) {
|
||||
/* we know then that it has an h2 parent */
|
||||
struct lws *enc = role_ops_h2.encapsulation_parent(wsi);
|
||||
|
||||
assert(enc);
|
||||
if (enc->role_ops->issue_keepalive(wsi, isvalid))
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isvalid)
|
||||
_lws_validity_confirmed_role(wsi);
|
||||
else {
|
||||
us = lws_now_usecs();
|
||||
memcpy(&wsi->ws->ping_payload_buf[LWS_PRE], &us, 8);
|
||||
wsi->ws->send_check_ping = 1;
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_ws = {
|
||||
/* role name */ "ws",
|
||||
/* alpn id */ NULL,
|
||||
/* check_upgrades */ NULL,
|
||||
/* init_context */ NULL,
|
||||
/* pt_init_destroy */ NULL,
|
||||
/* init_vhost */ rops_init_vhost_ws,
|
||||
/* destroy_vhost */ rops_destroy_vhost_ws,
|
||||
/* periodic_checks */ NULL,
|
||||
/* service_flag_pending */ rops_service_flag_pending_ws,
|
||||
/* handle_POLLIN */ rops_handle_POLLIN_ws,
|
||||
/* handle_POLLOUT */ rops_handle_POLLOUT_ws,
|
||||
|
@ -2110,6 +2068,7 @@ struct lws_role_ops role_ops_ws = {
|
|||
/* destroy_role */ rops_destroy_role_ws,
|
||||
/* adoption_bind */ NULL,
|
||||
/* client_bind */ NULL,
|
||||
/* issue_keepalive */ rops_issue_keepalive_ws,
|
||||
/* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED,
|
||||
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED },
|
||||
/* rx_cb clnt, srv */ { LWS_CALLBACK_CLIENT_RECEIVE,
|
||||
|
|
|
@ -104,23 +104,6 @@ struct _lws_websocket_related {
|
|||
|
||||
/* Also used for close content... control opcode == < 128 */
|
||||
uint8_t ping_payload_buf[128 - 3 + LWS_PRE];
|
||||
uint8_t mask[4];
|
||||
|
||||
size_t rx_packet_length;
|
||||
uint32_t rx_ubuf_head;
|
||||
uint32_t rx_ubuf_alloc;
|
||||
|
||||
uint8_t ping_payload_len;
|
||||
uint8_t mask_idx;
|
||||
uint8_t opcode;
|
||||
uint8_t rsv;
|
||||
uint8_t rsv_first_msg;
|
||||
/* zero if no info, or length including 2-byte close code */
|
||||
uint8_t close_in_ping_buffer_len;
|
||||
uint8_t utf8;
|
||||
uint8_t stashed_write_type;
|
||||
uint8_t tx_draining_stashed_wp;
|
||||
uint8_t ietf_spec_revision;
|
||||
|
||||
unsigned int final:1;
|
||||
unsigned int frame_is_binary:1;
|
||||
|
@ -138,13 +121,31 @@ struct _lws_websocket_related {
|
|||
unsigned int send_check_ping:1;
|
||||
unsigned int first_fragment:1;
|
||||
unsigned int peer_has_sent_close:1;
|
||||
unsigned int await_pong;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
unsigned int extension_data_pending:1;
|
||||
unsigned int rx_draining_ext:1;
|
||||
unsigned int tx_draining_ext:1;
|
||||
unsigned int pmd_trailer_application:1;
|
||||
#endif
|
||||
|
||||
uint8_t mask[4];
|
||||
|
||||
size_t rx_packet_length;
|
||||
uint32_t rx_ubuf_head;
|
||||
uint32_t rx_ubuf_alloc;
|
||||
|
||||
uint8_t ping_payload_len;
|
||||
uint8_t mask_idx;
|
||||
uint8_t opcode;
|
||||
uint8_t rsv;
|
||||
uint8_t rsv_first_msg;
|
||||
/* zero if no info, or length including 2-byte close code */
|
||||
uint8_t close_in_ping_buffer_len;
|
||||
uint8_t utf8;
|
||||
uint8_t stashed_write_type;
|
||||
uint8_t tx_draining_stashed_wp;
|
||||
uint8_t ietf_spec_revision;
|
||||
#if !defined(LWS_WITHOUT_EXTENSIONS)
|
||||
uint8_t count_act_ext;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@ Commandline option|Meaning
|
|||
-j|Apply tls option LCCSCF_ALLOW_SELFSIGNED
|
||||
-m|Apply tls option LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
|
||||
-e|Apply tls option LCCSCF_ALLOW_EXPIRED
|
||||
-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
|
||||
|
||||
```
|
||||
$ ./lws-minimal-http-client
|
||||
|
|
|
@ -22,6 +22,11 @@ static int long_poll;
|
|||
#endif
|
||||
static struct lws *client_wsi;
|
||||
|
||||
static const lws_retry_bo_t retry = {
|
||||
.secs_since_valid_ping = 3,
|
||||
.secs_since_valid_hangup = 10,
|
||||
};
|
||||
|
||||
static int
|
||||
callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
|
@ -207,6 +212,11 @@ int main(int argc, const char **argv)
|
|||
if (lws_cmdline_option(argc, argv, "-e"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_EXPIRED;
|
||||
|
||||
/* the default validity check is 5m / 5m10s... -v = 3s / 10s */
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-v"))
|
||||
i.retry_and_idle_policy = &retry;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--server")))
|
||||
i.address = p;
|
||||
|
||||
|
|
|
@ -5,6 +5,13 @@
|
|||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
## Commandline Options
|
||||
|
||||
Option|Meaning
|
||||
---|---
|
||||
-d|Set logging verbosity
|
||||
-s|Serve using TLS selfsigned cert (ie, connect to it with https://...)
|
||||
-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
|
||||
|
||||
## usage
|
||||
|
||||
|
|
|
@ -33,6 +33,11 @@ struct pss {
|
|||
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)
|
||||
{
|
||||
|
@ -132,6 +137,11 @@ int main(int argc, const char **argv)
|
|||
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");
|
||||
|
|
|
@ -19,6 +19,8 @@ Option|Meaning
|
|||
--port|Use a specific port instead of 443, eg `--port 7681`
|
||||
-z|Send zero-length pings for testing
|
||||
--protocol|Use a specific ws subprotocol rather than lws-mirror-protocol, eg, `--protocol myprotocol`
|
||||
-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
|
||||
|
||||
|
||||
## usage
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
static struct lws_context *context;
|
||||
static struct lws *client_wsi;
|
||||
static int interrupted, zero_length_ping, port = 443,
|
||||
static int interrupted, zero_length_ping, port = 443, quick_pings, no_user_ping,
|
||||
ssl_connection = LCCSCF_USE_SSL;
|
||||
static const char *server_address = "libwebsockets.org", *pro = "lws-mirror-protocol";
|
||||
|
||||
|
@ -25,6 +25,11 @@ struct pss {
|
|||
int send_a_ping;
|
||||
};
|
||||
|
||||
static const lws_retry_bo_t retry = {
|
||||
.secs_since_valid_ping = 3,
|
||||
.secs_since_valid_hangup = 10,
|
||||
};
|
||||
|
||||
static int
|
||||
connect_client(void)
|
||||
{
|
||||
|
@ -42,6 +47,8 @@ connect_client(void)
|
|||
i.protocol = pro;
|
||||
i.local_protocol_name = "lws-ping-test";
|
||||
i.pwsi = &client_wsi;
|
||||
if (quick_pings)
|
||||
i.retry_and_idle_policy = &retry;
|
||||
|
||||
return !lws_client_connect_via_info(&i);
|
||||
}
|
||||
|
@ -110,10 +117,12 @@ callback_minimal_broker(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_TIMER:
|
||||
if (no_user_ping)
|
||||
break;
|
||||
/* we want to send a ws PING every few seconds */
|
||||
pss->send_a_ping = 1;
|
||||
lws_callback_on_writable(wsi);
|
||||
lws_set_timer_usecs(wsi, 5 * LWS_USEC_PER_SEC);
|
||||
lws_set_timer_usecs(wsi, 10 * LWS_USEC_PER_SEC);
|
||||
break;
|
||||
|
||||
/* rate-limited client connect retries */
|
||||
|
@ -185,6 +194,9 @@ int main(int argc, const char **argv)
|
|||
if (lws_cmdline_option(argc, argv, "-z"))
|
||||
zero_length_ping = 1;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-n"))
|
||||
no_user_ping = 1;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--protocol")))
|
||||
pro = p;
|
||||
|
||||
|
@ -197,6 +209,11 @@ int main(int argc, const char **argv)
|
|||
if ((p = lws_cmdline_option(argc, argv, "--port")))
|
||||
port = atoi(p);
|
||||
|
||||
/* the default validity check is 5m / 5m10s... -v = 5s / 10s */
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-v"))
|
||||
quick_pings = 1;
|
||||
|
||||
/*
|
||||
* since we know this lws context is only ever going to be used with
|
||||
* one client wsis / fds / sockets at a time, let lws know it doesn't
|
||||
|
|
|
@ -13,6 +13,7 @@ Option|Meaning
|
|||
-d|Set logging verbosity
|
||||
-s|Serve using TLS selfsigned cert (ie, connect to it with https://...)
|
||||
-h|Strict Host: header checking against vhost name (localhost) and port
|
||||
-v|Connection validity use 3s / 10s instead of default 5m / 5m10s
|
||||
|
||||
## usage
|
||||
|
||||
|
|
|
@ -27,6 +27,11 @@ static struct lws_protocols protocols[] = {
|
|||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
static const lws_retry_bo_t retry = {
|
||||
.secs_since_valid_ping = 3,
|
||||
.secs_since_valid_hangup = 10,
|
||||
};
|
||||
|
||||
static int interrupted;
|
||||
|
||||
static const struct lws_http_mount mount = {
|
||||
|
@ -94,6 +99,9 @@ int main(int argc, const char **argv)
|
|||
if (lws_cmdline_option(argc, argv, "-h"))
|
||||
info.options |= LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK;
|
||||
|
||||
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");
|
||||
|
|
Loading…
Add table
Reference in a new issue