mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
lws_state and system state
Introduce a generic lws_state object with notification handlers that may be registered in a chain. Implement one of those in the context to manage the "system state". Allow other pieces of lws and user code to register notification handlers on a context list. Handlers can object to or take over responsibility to move forward and retry system state changes if they know that some dependent action must succeed first. For example if the system time is invalid, we cannot move on to a state where anything can do tls until that has been corrected.
This commit is contained in:
parent
6a6f365ce7
commit
bce1f01370
23 changed files with 1197 additions and 514 deletions
|
@ -1013,6 +1013,7 @@ if (LWS_WITH_NETWORK)
|
|||
lib/core-net/pollfd.c
|
||||
lib/core-net/service.c
|
||||
lib/core-net/sorted-usec-list.c
|
||||
lib/core-net/state.c
|
||||
lib/core-net/stats.c
|
||||
lib/core-net/wsi.c
|
||||
lib/core-net/wsi-timeout.c
|
||||
|
|
34
README.md
34
README.md
|
@ -16,6 +16,36 @@ various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to
|
|||
News
|
||||
----
|
||||
|
||||
## `lws_system`: system state and notification handlers
|
||||
|
||||
Lws now has the concept of systemwide state held in the context... this is to
|
||||
manage that there may be multiple steps that need the network before it's possible
|
||||
for the user code to operate normally. The steps defined are
|
||||
|
||||
`CONTEXT_CREATED`, `INITIALIZED`, `IFACE_COLDPLUG`, `DHCP`, `TIME_VALID`, `POLICY_VALID`,
|
||||
`REGISTERED`, `AUTH1`, `AUTH2`, `OPERATIONAL` and `POLICY_INVALID`. OPERATIONAL is the
|
||||
state where user code can run normally.
|
||||
|
||||
User and other parts of lws can hook notifier callbacks to receive and be able to
|
||||
veto system state changes, either definitively or because they have been triggered
|
||||
to perform a step asynchronously and will move the state on themselves when it
|
||||
completes.
|
||||
|
||||
By default just after context creation, lws attempts to move straight to OPERATIONAL.
|
||||
If no notifier interecepts it, it will succeed to do that and operate in a
|
||||
backwards-compatible way.
|
||||
|
||||
See `READMEs/README.lws_system.md` for details.
|
||||
|
||||
## `lws_system`: HAL ops struct
|
||||
|
||||
Lws allows you to define a standardized ops struct at context creation time so your
|
||||
user code can get various information like device serial number without embedding
|
||||
system-specific code throughout the user code. It can also perform some generic
|
||||
functions like requesting a device reboot.
|
||||
|
||||
See `READMEs/README.lws_system.md` for details.
|
||||
|
||||
## Connection Validity tracking
|
||||
|
||||
Lws now allows you to apply a policy for how long a network connection may go
|
||||
|
@ -30,10 +60,10 @@ 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
|
||||
## `lws_system`: Async DNS support
|
||||
|
||||
Master now provides optional Asynchronous (ie, nonblocking) DNS resolving. Enable
|
||||
with `-DLWS_WITH_ASYNC_DNS=1` at cmake. This provides a quite sophisticated
|
||||
with `-DLWS_WITH_SYS_ASYNC_DNS=1` at cmake. This provides a quite sophisticated
|
||||
ipv4 + ipv6 capable resolver that autodetects the dns server on several platforms
|
||||
and operates a UDP socket to its port 53 to produce and parse DNS packets
|
||||
from the event loop. And of course, it's extremely compact.
|
||||
|
|
76
READMEs/README.lws_system.md
Normal file
76
READMEs/README.lws_system.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
# `lws_system`
|
||||
|
||||
See `include/libwebsockets/lws-system.h` for function and object prototypes.
|
||||
|
||||
## System integration api
|
||||
|
||||
`lws_system` allows you to set a `system_ops` struct at context creation time,
|
||||
which can write up some function callbacks for system integration. The goal
|
||||
is the user code calls these by getting the ops struct pointer from the
|
||||
context using `lws_system_get_ops(context)` or `lws_system_get_info()` and
|
||||
so does not spread system dependencies around the user code.
|
||||
|
||||
```
|
||||
typedef struct lws_system_ops {
|
||||
int (*get_info)(lws_system_item_t i, lws_system_arg_t *arg);
|
||||
int (*reboot)(void);
|
||||
int (*set_clock)(lws_usec_t us);
|
||||
} lws_system_ops_t;
|
||||
```
|
||||
|
||||
### `get_info`
|
||||
|
||||
This allows the user code to query some common system values without introducing
|
||||
any system dependencies in the code itself. The defined item numbers are
|
||||
|
||||
|Item|Meaning|
|
||||
|---|---|
|
||||
|`LWS_SYSI_HRS_DEVICE_MODEL`|String describing device model|
|
||||
|`LWS_SYSI_HRS_DEVICE_SERIAL`|String for the device serial number|
|
||||
|`LWS_SYSI_HRS_FIRMWARE_VERSION`|String describing the current firmware version|
|
||||
|`LWS_SYSI_HRS_NTP_SERVER`|String with the ntp server address (defaults to pool.ntp.org)|
|
||||
|
||||
### `reboot`
|
||||
|
||||
Reboots the device
|
||||
|
||||
### `set_clock`
|
||||
|
||||
Set the system clock to us-resolution Unix time in seconds
|
||||
|
||||
## System state and notifiers
|
||||
|
||||
Lws implements a state in the context that reflects the readiness of the system
|
||||
for various steps leading up to normal operation. By default it acts in a
|
||||
backwards-compatible way and directly reaches the OPERATIONAL state just after
|
||||
the context is created.
|
||||
|
||||
However other pieces of lws, and user, code may define notification handlers
|
||||
that get called back when the state changes incrementally, and may veto or delay
|
||||
the changes until work necessary for the new state has completed asynchronously.
|
||||
|
||||
The generic states defined are:
|
||||
|
||||
|State|Meaning|
|
||||
|---|---|
|
||||
|`LWS_SYSTATE_CONTEXT_CREATED`|The context was just created.|
|
||||
|`LWS_SYSTATE_INITIALIZED`|The vhost protocols have been initialized|
|
||||
|`LWS_SYSTATE_IFACE_COLDPLUG`|Existing network interfaces have been iterated|
|
||||
|`LWS_SYSTATE_DHCP`|Network identity is available|
|
||||
|`LWS_SYSTATE_TIME_VALID`|The system knows the time|
|
||||
|`LWS_SYSTATE_POLICY_VALID`|If the system needs information about how to act from the net, it has it|
|
||||
|`LWS_SYSTATE_REGISTERED`|The device has a registered identity|
|
||||
|`LWS_SYSTATE_AUTH1`|The device identity has produced a time-limited access token|
|
||||
|`LWS_SYSTATE_AUTH2`|Optional second access token for different services|
|
||||
|`LWS_SYSTATE_OPERATIONAL`|The system is ready for user code to work normally|
|
||||
|`LWS_SYSTATE_POLICY_INVALID`|All connections are being dropped because policy information is changing. It will transition back to `LWS_SYSTATE_INITIALIZED` and onward to `OPERATIONAL` again afterwards with the new policy|
|
||||
|
||||
### Inserting a notifier
|
||||
|
||||
You should create an object `lws_system_notify_link_t` in non-const memory and zero it down.
|
||||
Set the `notify_cb` member and the `name` member and then register it using either
|
||||
`lws_system_reg_notifier()` or the `.register_notifier_list`
|
||||
member of the context creation info struct to make sure it will exist early
|
||||
enough to see all events. The context creation info method takes a list of
|
||||
pointers to notify_link structs ending with a NULL entry.
|
||||
|
|
@ -524,11 +524,15 @@ struct lws_pollargs {
|
|||
|
||||
struct lws_extension; /* needed even with ws exts disabled for create context */
|
||||
struct lws_token_limits;
|
||||
struct lws_protocols;
|
||||
struct lws_context;
|
||||
struct lws_tokens;
|
||||
struct lws_vhost;
|
||||
struct lws;
|
||||
|
||||
#include <libwebsockets/lws-dll2.h>
|
||||
#include <libwebsockets/lws-timeout-timer.h>
|
||||
#include <libwebsockets/lws-state.h>
|
||||
#include <libwebsockets/lws-retry.h>
|
||||
#include <libwebsockets/lws-system.h>
|
||||
#include <libwebsockets/lws-detailed-latency.h>
|
||||
|
@ -545,7 +549,6 @@ struct lws;
|
|||
#include <libwebsockets/lws-purify.h>
|
||||
#include <libwebsockets/lws-misc.h>
|
||||
#include <libwebsockets/lws-dsh.h>
|
||||
#include <libwebsockets/lws-timeout-timer.h>
|
||||
#include <libwebsockets/lws-service.h>
|
||||
#include <libwebsockets/lws-write.h>
|
||||
#include <libwebsockets/lws-writeable.h>
|
||||
|
|
|
@ -225,6 +225,8 @@
|
|||
|
||||
struct lws_plat_file_ops;
|
||||
|
||||
typedef int (*lws_context_ready_cb_t)(struct lws_context *context);
|
||||
|
||||
/** struct lws_context_creation_info - parameters to create context and /or vhost with
|
||||
*
|
||||
* This is also used to create vhosts.... if LWS_SERVER_OPTION_EXPLICIT_VHOSTS
|
||||
|
@ -692,6 +694,10 @@ struct lws_context_creation_info {
|
|||
/**< VHOST: optional retry and idle policy to apply to this vhost.
|
||||
* Currently only the idle parts are applied to the connections.
|
||||
*/
|
||||
lws_state_notify_link_t **register_notifier_list;
|
||||
/**< CONTEXT: NULL, or pointer to an array of notifiers that should
|
||||
* be registered during context creation, so they can see state change
|
||||
* events from very early on. The array should end with a NULL. */
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
|
341
include/libwebsockets/lws-dll2.h
Normal file
341
include/libwebsockets/lws-dll2.h
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/** \defgroup ll linked-lists
|
||||
* ##Linked list apis
|
||||
*
|
||||
* simple single and doubly-linked lists
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* lws_start_foreach_ll(): linkedlist iterator helper start
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz *
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at start and
|
||||
* ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_start_foreach_ll().
|
||||
*/
|
||||
#define lws_start_foreach_ll(type, it, start)\
|
||||
{ \
|
||||
type it = start; \
|
||||
while (it) {
|
||||
|
||||
/**
|
||||
* lws_end_foreach_ll(): linkedlist iterator helper end
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_ll() that ends the
|
||||
* while loop.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_ll(it, nxt) \
|
||||
it = it->nxt; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_start_foreach_ll_safe(): linkedlist iterator helper start safe against delete
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz *
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at start and
|
||||
* ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_end_foreach_ll_safe().
|
||||
* Performs storage of next increment for situations where iterator can become invalidated
|
||||
* during iteration.
|
||||
*/
|
||||
#define lws_start_foreach_ll_safe(type, it, start, nxt)\
|
||||
{ \
|
||||
type it = start; \
|
||||
while (it) { \
|
||||
type next_##it = it->nxt;
|
||||
|
||||
/**
|
||||
* lws_end_foreach_ll_safe(): linkedlist iterator helper end (pre increment storage)
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_ll_safe() that ends the
|
||||
* while loop. It uses the precreated next_ variable already stored during
|
||||
* start.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_ll_safe(it) \
|
||||
it = next_##it; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_start_foreach_llp(): linkedlist pointer iterator helper start
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz **
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at the
|
||||
* address of start and ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_start_foreach_llp().
|
||||
*
|
||||
* This helper variant iterates using a pointer to the previous linked-list
|
||||
* element. That allows you to easily delete list members by rewriting the
|
||||
* previous pointer to the element's next pointer.
|
||||
*/
|
||||
#define lws_start_foreach_llp(type, it, start)\
|
||||
{ \
|
||||
type it = &(start); \
|
||||
while (*(it)) {
|
||||
|
||||
#define lws_start_foreach_llp_safe(type, it, start, nxt)\
|
||||
{ \
|
||||
type it = &(start); \
|
||||
type next; \
|
||||
while (*(it)) { \
|
||||
next = &((*(it))->nxt); \
|
||||
|
||||
/**
|
||||
* lws_end_foreach_llp(): linkedlist pointer iterator helper end
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_llp() that ends the
|
||||
* while loop.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_llp(it, nxt) \
|
||||
it = &(*(it))->nxt; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define lws_end_foreach_llp_safe(it) \
|
||||
it = next; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define lws_ll_fwd_insert(\
|
||||
___new_object, /* pointer to new object */ \
|
||||
___m_list, /* member for next list object ptr */ \
|
||||
___list_head /* list head */ \
|
||||
) {\
|
||||
___new_object->___m_list = ___list_head; \
|
||||
___list_head = ___new_object; \
|
||||
}
|
||||
|
||||
#define lws_ll_fwd_remove(\
|
||||
___type, /* type of listed object */ \
|
||||
___m_list, /* member for next list object ptr */ \
|
||||
___target, /* object to remove from list */ \
|
||||
___list_head /* list head */ \
|
||||
) { \
|
||||
lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
|
||||
if (*___ppss == ___target) { \
|
||||
*___ppss = ___target->___m_list; \
|
||||
break; \
|
||||
} \
|
||||
} lws_end_foreach_llp(___ppss, ___m_list); \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* doubly linked-list
|
||||
*/
|
||||
|
||||
#if defined (LWS_WITH_DEPRECATED_LWS_DLL)
|
||||
|
||||
/*
|
||||
* This is going away in v4.1. You can set the cmake option above to keep it
|
||||
* around temporarily. Migrate your stuff to the more capable and robust
|
||||
* lws_dll2 below
|
||||
*/
|
||||
|
||||
struct lws_dll {
|
||||
struct lws_dll *prev;
|
||||
struct lws_dll *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* these all point to the composed list objects... you have to use the
|
||||
* lws_container_of() helper to recover the start of the containing struct
|
||||
*/
|
||||
|
||||
#define lws_dll_add_front lws_dll_add_head
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_insert(struct lws_dll *d, struct lws_dll *target,
|
||||
struct lws_dll *phead, int before);
|
||||
|
||||
static LWS_INLINE struct lws_dll *
|
||||
lws_dll_get_head(struct lws_dll *phead) { return phead->next; }
|
||||
|
||||
static LWS_INLINE struct lws_dll *
|
||||
lws_dll_get_tail(struct lws_dll *phead) { return phead->prev; }
|
||||
|
||||
/*
|
||||
* caution, this doesn't track the tail in the head struct. Use
|
||||
* lws_dll_remove_track_tail() instead of this if you want tail tracking. Using
|
||||
* this means you can't use lws_dll_add_tail() amd
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_remove(struct lws_dll *d) LWS_WARN_DEPRECATED;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead);
|
||||
|
||||
/* another way to do lws_start_foreach_dll_safe() on a list via a cb */
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_dll_foreach_safe(struct lws_dll *phead, void *user,
|
||||
int (*cb)(struct lws_dll *d, void *user));
|
||||
|
||||
#define lws_dll_is_detached(___dll, __head) \
|
||||
(!(___dll)->prev && !(___dll)->next && (__head)->prev != (___dll))
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lws_dll2_owner / lws_dll2 : more capable version of lws_dll. Differences:
|
||||
*
|
||||
* - there's an explicit lws_dll2_owner struct which holds head, tail and
|
||||
* count of members.
|
||||
*
|
||||
* - list members all hold a pointer to their owner. So user code does not
|
||||
* have to track anything about exactly what lws_dll2_owner list the object
|
||||
* is a member of.
|
||||
*
|
||||
* - you can use lws_dll unless you want the member count or the ability to
|
||||
* not track exactly which list it's on.
|
||||
*
|
||||
* - layout is compatible with lws_dll (but lws_dll apis will not update the
|
||||
* new stuff)
|
||||
*/
|
||||
|
||||
|
||||
struct lws_dll2;
|
||||
struct lws_dll2_owner;
|
||||
|
||||
typedef struct lws_dll2 {
|
||||
struct lws_dll2 *prev;
|
||||
struct lws_dll2 *next;
|
||||
struct lws_dll2_owner *owner;
|
||||
} lws_dll2_t;
|
||||
|
||||
typedef struct lws_dll2_owner {
|
||||
struct lws_dll2 *tail;
|
||||
struct lws_dll2 *head;
|
||||
|
||||
uint32_t count;
|
||||
} lws_dll2_owner_t;
|
||||
|
||||
static LWS_INLINE int
|
||||
lws_dll2_is_detached(const struct lws_dll2 *d) { return !d->owner; }
|
||||
|
||||
static LWS_INLINE const struct lws_dll2_owner *
|
||||
lws_dll2_owner(const struct lws_dll2 *d) { return d->owner; }
|
||||
|
||||
static LWS_INLINE struct lws_dll2 *
|
||||
lws_dll2_get_head(struct lws_dll2_owner *owner) { return owner->head; }
|
||||
|
||||
static LWS_INLINE struct lws_dll2 *
|
||||
lws_dll2_get_tail(struct lws_dll2_owner *owner) { return owner->tail; }
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_remove(struct lws_dll2 *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
|
||||
int (*cb)(struct lws_dll2 *d, void *user));
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_clear(struct lws_dll2 *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_owner_clear(struct lws_dll2_owner *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
|
||||
int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i));
|
||||
|
||||
#if defined(_DEBUG)
|
||||
void
|
||||
lws_dll2_describe(struct lws_dll2_owner *owner, const char *desc);
|
||||
#else
|
||||
#define lws_dll2_describe(x, y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* these are safe against the current container object getting deleted,
|
||||
* since the hold his next in a temp and go to that next. ___tmp is
|
||||
* the temp.
|
||||
*/
|
||||
|
||||
#define lws_start_foreach_dll_safe(___type, ___it, ___tmp, ___start) \
|
||||
{ \
|
||||
___type ___it = ___start; \
|
||||
while (___it) { \
|
||||
___type ___tmp = (___it)->next;
|
||||
|
||||
#define lws_end_foreach_dll_safe(___it, ___tmp) \
|
||||
___it = ___tmp; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define lws_start_foreach_dll(___type, ___it, ___start) \
|
||||
{ \
|
||||
___type ___it = ___start; \
|
||||
while (___it) {
|
||||
|
||||
#define lws_end_foreach_dll(___it) \
|
||||
___it = (___it)->next; \
|
||||
} \
|
||||
}
|
||||
|
||||
///@}
|
||||
|
|
@ -29,313 +29,6 @@
|
|||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* lws_start_foreach_ll(): linkedlist iterator helper start
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz *
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at start and
|
||||
* ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_start_foreach_ll().
|
||||
*/
|
||||
#define lws_start_foreach_ll(type, it, start)\
|
||||
{ \
|
||||
type it = start; \
|
||||
while (it) {
|
||||
|
||||
/**
|
||||
* lws_end_foreach_ll(): linkedlist iterator helper end
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_ll() that ends the
|
||||
* while loop.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_ll(it, nxt) \
|
||||
it = it->nxt; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_start_foreach_ll_safe(): linkedlist iterator helper start safe against delete
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz *
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at start and
|
||||
* ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_end_foreach_ll_safe().
|
||||
* Performs storage of next increment for situations where iterator can become invalidated
|
||||
* during iteration.
|
||||
*/
|
||||
#define lws_start_foreach_ll_safe(type, it, start, nxt)\
|
||||
{ \
|
||||
type it = start; \
|
||||
while (it) { \
|
||||
type next_##it = it->nxt;
|
||||
|
||||
/**
|
||||
* lws_end_foreach_ll_safe(): linkedlist iterator helper end (pre increment storage)
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_ll_safe() that ends the
|
||||
* while loop. It uses the precreated next_ variable already stored during
|
||||
* start.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_ll_safe(it) \
|
||||
it = next_##it; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_start_foreach_llp(): linkedlist pointer iterator helper start
|
||||
*
|
||||
* \param type: type of iteration, eg, struct xyz **
|
||||
* \param it: iterator var name to create
|
||||
* \param start: start of list
|
||||
*
|
||||
* This helper creates an iterator and starts a while (it) {
|
||||
* loop. The iterator runs through the linked list starting at the
|
||||
* address of start and ends when it gets a NULL.
|
||||
* The while loop should be terminated using lws_start_foreach_llp().
|
||||
*
|
||||
* This helper variant iterates using a pointer to the previous linked-list
|
||||
* element. That allows you to easily delete list members by rewriting the
|
||||
* previous pointer to the element's next pointer.
|
||||
*/
|
||||
#define lws_start_foreach_llp(type, it, start)\
|
||||
{ \
|
||||
type it = &(start); \
|
||||
while (*(it)) {
|
||||
|
||||
#define lws_start_foreach_llp_safe(type, it, start, nxt)\
|
||||
{ \
|
||||
type it = &(start); \
|
||||
type next; \
|
||||
while (*(it)) { \
|
||||
next = &((*(it))->nxt); \
|
||||
|
||||
/**
|
||||
* lws_end_foreach_llp(): linkedlist pointer iterator helper end
|
||||
*
|
||||
* \param it: same iterator var name given when starting
|
||||
* \param nxt: member name in the iterator pointing to next list element
|
||||
*
|
||||
* This helper is the partner for lws_start_foreach_llp() that ends the
|
||||
* while loop.
|
||||
*/
|
||||
|
||||
#define lws_end_foreach_llp(it, nxt) \
|
||||
it = &(*(it))->nxt; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define lws_end_foreach_llp_safe(it) \
|
||||
it = next; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define lws_ll_fwd_insert(\
|
||||
___new_object, /* pointer to new object */ \
|
||||
___m_list, /* member for next list object ptr */ \
|
||||
___list_head /* list head */ \
|
||||
) {\
|
||||
___new_object->___m_list = ___list_head; \
|
||||
___list_head = ___new_object; \
|
||||
}
|
||||
|
||||
#define lws_ll_fwd_remove(\
|
||||
___type, /* type of listed object */ \
|
||||
___m_list, /* member for next list object ptr */ \
|
||||
___target, /* object to remove from list */ \
|
||||
___list_head /* list head */ \
|
||||
) { \
|
||||
lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
|
||||
if (*___ppss == ___target) { \
|
||||
*___ppss = ___target->___m_list; \
|
||||
break; \
|
||||
} \
|
||||
} lws_end_foreach_llp(___ppss, ___m_list); \
|
||||
}
|
||||
|
||||
/*
|
||||
* doubly linked-list
|
||||
*/
|
||||
|
||||
#if defined (LWS_WITH_DEPRECATED_LWS_DLL)
|
||||
|
||||
/*
|
||||
* This is going away in v4.1. You can set the cmake option above to keep it
|
||||
* around temporarily. Migrate your stuff to the more capable and robust
|
||||
* lws_dll2 below
|
||||
*/
|
||||
|
||||
struct lws_dll {
|
||||
struct lws_dll *prev;
|
||||
struct lws_dll *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* these all point to the composed list objects... you have to use the
|
||||
* lws_container_of() helper to recover the start of the containing struct
|
||||
*/
|
||||
|
||||
#define lws_dll_add_front lws_dll_add_head
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_insert(struct lws_dll *d, struct lws_dll *target,
|
||||
struct lws_dll *phead, int before);
|
||||
|
||||
static LWS_INLINE struct lws_dll *
|
||||
lws_dll_get_head(struct lws_dll *phead) { return phead->next; }
|
||||
|
||||
static LWS_INLINE struct lws_dll *
|
||||
lws_dll_get_tail(struct lws_dll *phead) { return phead->prev; }
|
||||
|
||||
/*
|
||||
* caution, this doesn't track the tail in the head struct. Use
|
||||
* lws_dll_remove_track_tail() instead of this if you want tail tracking. Using
|
||||
* this means you can't use lws_dll_add_tail() amd
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_remove(struct lws_dll *d) LWS_WARN_DEPRECATED;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead);
|
||||
|
||||
/* another way to do lws_start_foreach_dll_safe() on a list via a cb */
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_dll_foreach_safe(struct lws_dll *phead, void *user,
|
||||
int (*cb)(struct lws_dll *d, void *user));
|
||||
|
||||
#define lws_dll_is_detached(___dll, __head) \
|
||||
(!(___dll)->prev && !(___dll)->next && (__head)->prev != (___dll))
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lws_dll2_owner / lws_dll2 : more capable version of lws_dll. Differences:
|
||||
*
|
||||
* - there's an explicit lws_dll2_owner struct which holds head, tail and
|
||||
* count of members.
|
||||
*
|
||||
* - list members all hold a pointer to their owner. So user code does not
|
||||
* have to track anything about exactly what lws_dll2_owner list the object
|
||||
* is a member of.
|
||||
*
|
||||
* - you can use lws_dll unless you want the member count or the ability to
|
||||
* not track exactly which list it's on.
|
||||
*
|
||||
* - layout is compatible with lws_dll (but lws_dll apis will not update the
|
||||
* new stuff)
|
||||
*/
|
||||
|
||||
|
||||
struct lws_dll2;
|
||||
struct lws_dll2_owner;
|
||||
|
||||
typedef struct lws_dll2 {
|
||||
struct lws_dll2 *prev;
|
||||
struct lws_dll2 *next;
|
||||
struct lws_dll2_owner *owner;
|
||||
} lws_dll2_t;
|
||||
|
||||
typedef struct lws_dll2_owner {
|
||||
struct lws_dll2 *tail;
|
||||
struct lws_dll2 *head;
|
||||
|
||||
uint32_t count;
|
||||
} lws_dll2_owner_t;
|
||||
|
||||
static LWS_INLINE int
|
||||
lws_dll2_is_detached(const struct lws_dll2 *d) { return !d->owner; }
|
||||
|
||||
static LWS_INLINE const struct lws_dll2_owner *
|
||||
lws_dll2_owner(const struct lws_dll2 *d) { return d->owner; }
|
||||
|
||||
static LWS_INLINE struct lws_dll2 *
|
||||
lws_dll2_get_head(struct lws_dll2_owner *owner) { return owner->head; }
|
||||
|
||||
static LWS_INLINE struct lws_dll2 *
|
||||
lws_dll2_get_tail(struct lws_dll2_owner *owner) { return owner->tail; }
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_remove(struct lws_dll2 *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
|
||||
int (*cb)(struct lws_dll2 *d, void *user));
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_clear(struct lws_dll2 *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_owner_clear(struct lws_dll2_owner *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
|
||||
int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i));
|
||||
|
||||
#if defined(_DEBUG)
|
||||
void
|
||||
lws_dll2_describe(struct lws_dll2_owner *owner, const char *desc);
|
||||
#else
|
||||
#define lws_dll2_describe(x, y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* these are safe against the current container object getting deleted,
|
||||
* since the hold his next in a temp and go to that next. ___tmp is
|
||||
* the temp.
|
||||
*/
|
||||
|
||||
#define lws_start_foreach_dll_safe(___type, ___it, ___tmp, ___start) \
|
||||
{ \
|
||||
___type ___it = ___start; \
|
||||
while (___it) { \
|
||||
___type ___tmp = (___it)->next;
|
||||
|
||||
#define lws_end_foreach_dll_safe(___it, ___tmp) \
|
||||
___it = ___tmp; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define lws_start_foreach_dll(___type, ___it, ___start) \
|
||||
{ \
|
||||
___type ___it = ___start; \
|
||||
while (___it) {
|
||||
|
||||
#define lws_end_foreach_dll(___it) \
|
||||
___it = (___it)->next; \
|
||||
} \
|
||||
}
|
||||
|
||||
struct lws_buflist;
|
||||
|
||||
/**
|
||||
|
|
|
@ -54,3 +54,20 @@ LWS_VISIBLE LWS_EXTERN unsigned int
|
|||
lws_retry_get_delay_ms(struct lws_context *context, const lws_retry_bo_t *retry,
|
||||
uint16_t *ctry, char *conceal);
|
||||
|
||||
/**
|
||||
* lws_retry_sul_schedule() - schedule a sul according to the backoff table
|
||||
*
|
||||
* \param lws_context: the lws context (used for getting random)
|
||||
* \param sul: pointer to the sul to schedule
|
||||
* \param retry: the retry backoff table we are using, or NULL for default
|
||||
* \param cb: the callback for when the sul schedule time arrives
|
||||
* \param ctry: pointer to the try counter
|
||||
*
|
||||
* Helper that combines interpreting the retry table with scheduling a sul to
|
||||
* the computed delay. If conceal is not set, it will not schedule the sul
|
||||
* and return 1. Otherwise the sul is scheduled and it returns 0.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_retry_sul_schedule(struct lws_context *context, int tid,
|
||||
lws_sorted_usec_list_t *sul, const lws_retry_bo_t *retry,
|
||||
sul_cb_t cb, uint16_t *ctry);
|
||||
|
|
97
include/libwebsockets/lws-state.h
Normal file
97
include/libwebsockets/lws-state.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
struct lws_state_notify_link;
|
||||
struct lws_state_manager;
|
||||
|
||||
typedef int (*lws_state_notify_t)(struct lws_state_manager *mgr,
|
||||
struct lws_state_notify_link *link,
|
||||
int current, int target);
|
||||
|
||||
typedef struct lws_state_notify_link {
|
||||
lws_dll2_t list;
|
||||
lws_state_notify_t notify_cb;
|
||||
const char *name;
|
||||
} lws_state_notify_link_t;
|
||||
|
||||
typedef struct lws_state_manager {
|
||||
lws_dll2_owner_t notify_list;
|
||||
void *parent;
|
||||
/**< optional opaque pointer to owning object... useful to make such
|
||||
* a pointer available to a notification callback. Ignored by lws */
|
||||
const char **state_names; /* may be NULL */
|
||||
const char *name;
|
||||
int state;
|
||||
} lws_state_manager_t;
|
||||
|
||||
/**
|
||||
* lws_state_reg_notifier() - add dep handler for state notifications
|
||||
*
|
||||
* \param context: the lws_context
|
||||
* \param nl: the handler to add to the notifier linked-list
|
||||
*
|
||||
* Add \p notify_link to the context's list of notification handlers for system
|
||||
* state changes. The handlers can defeat or take over responsibility for
|
||||
* retrying the change after they have initiated some dependency.
|
||||
*/
|
||||
|
||||
LWS_EXTERN LWS_VISIBLE void
|
||||
lws_state_reg_notifier(lws_state_manager_t *mgr, lws_state_notify_link_t *nl);
|
||||
|
||||
/**
|
||||
* lws_state_reg_notifier_list() - add dep handlers for state notifications
|
||||
*
|
||||
* \param context: the lws_context
|
||||
* \param nl: list of notification handlers
|
||||
*
|
||||
* Add a NULL-terminated list of notification handler pointers to a notification
|
||||
* manager object
|
||||
*/
|
||||
|
||||
LWS_EXTERN LWS_VISIBLE void
|
||||
lws_state_reg_notifier_list(lws_state_manager_t *mgr, lws_state_notify_link_t **nl);
|
||||
|
||||
/**
|
||||
* lws_state_transition_steps() - move to state via starting any deps
|
||||
*
|
||||
* \param mgr: the state manager object
|
||||
* \param target: the state we wish to move to
|
||||
*
|
||||
* Advance state by state towards state \p target. At each state, notifiers
|
||||
* may veto the change and be triggered to perform dependencies, stopping the
|
||||
* advance towards the target state.
|
||||
*/
|
||||
LWS_EXTERN LWS_VISIBLE int
|
||||
lws_state_transition_steps(lws_state_manager_t *mgr, int target);
|
||||
|
||||
/**
|
||||
* lws_state_transition() - move to state via starting any deps
|
||||
*
|
||||
* \param mgr: the state manager object
|
||||
* \param target: the state we wish to move to
|
||||
*
|
||||
* Jump to state target atomically. Notifiers may veto it.
|
||||
*/
|
||||
LWS_EXTERN LWS_VISIBLE int
|
||||
lws_state_transition(lws_state_manager_t *mgr, int target);
|
|
@ -34,21 +34,72 @@ typedef enum {
|
|||
LWS_SYSI_HRS_DEVICE_MODEL = 1,
|
||||
LWS_SYSI_HRS_DEVICE_SERIAL,
|
||||
LWS_SYSI_HRS_FIRMWARE_VERSION,
|
||||
LWS_SYSI_HRS_NTP_SERVER,
|
||||
|
||||
LWS_SYSI_USER_BASE = 100
|
||||
} lws_system_item_t;
|
||||
|
||||
typedef union {
|
||||
const char *hrs; /* human readable string */
|
||||
void *data;
|
||||
time_t t;
|
||||
typedef struct lws_system_arg {
|
||||
union {
|
||||
const char *hrs; /* human readable string */
|
||||
void *data;
|
||||
time_t t;
|
||||
} u;
|
||||
size_t len;
|
||||
} lws_system_arg_t;
|
||||
|
||||
/*
|
||||
* Lws view of system state... normal operation from user code perspective is
|
||||
* dependent on implicit (eg, knowing the date for cert validation) and
|
||||
* explicit dependencies.
|
||||
*
|
||||
* Bit of lws and user code can register notification handlers that can enforce
|
||||
* dependent operations before state transitions can complete.
|
||||
*/
|
||||
|
||||
typedef enum { /* keep system_state_names[] in sync in context.c */
|
||||
LWS_SYSTATE_UNKNOWN,
|
||||
|
||||
LWS_SYSTATE_CONTEXT_CREATED, /* context was just created */
|
||||
LWS_SYSTATE_INITIALIZED, /* protocols initialized. Lws itself
|
||||
* can operate normally */
|
||||
LWS_SYSTATE_IFACE_COLDPLUG, /* existing net ifaces iterated */
|
||||
LWS_SYSTATE_DHCP, /* at least one net iface configured */
|
||||
LWS_SYSTATE_TIME_VALID, /* ntpclient ran, or hw time valid...
|
||||
* tls cannot work until we reach here
|
||||
*/
|
||||
LWS_SYSTATE_POLICY_VALID, /* user code knows how to operate... */
|
||||
LWS_SYSTATE_REGISTERED, /* device has an identity... */
|
||||
LWS_SYSTATE_AUTH1, /* identity used for main auth token */
|
||||
LWS_SYSTATE_AUTH2, /* identity used for optional auth */
|
||||
|
||||
LWS_SYSTATE_OPERATIONAL, /* user code can operate normally */
|
||||
|
||||
LWS_SYSTATE_POLICY_INVALID, /* user code is changing its policies
|
||||
* drop everything done with old
|
||||
* policy, switch to new then enter
|
||||
* LWS_SYSTATE_POLICY_VALID */
|
||||
} lws_system_states_t;
|
||||
|
||||
typedef struct lws_system_ops {
|
||||
int (*get_info)(lws_system_item_t i, lws_system_arg_t arg, size_t *len);
|
||||
int (*get_info)(lws_system_item_t i, lws_system_arg_t *arg);
|
||||
int (*reboot)(void);
|
||||
int (*set_clock)(lws_usec_t us);
|
||||
} lws_system_ops_t;
|
||||
|
||||
/**
|
||||
* lws_system_get_state_manager() - return the state mgr object for system state
|
||||
*
|
||||
* \param context: the lws_context
|
||||
*
|
||||
* The returned pointer can be used with the lws_state_ apis
|
||||
*/
|
||||
|
||||
LWS_EXTERN LWS_VISIBLE lws_state_manager_t *
|
||||
lws_system_get_state_manager(struct lws_context *context);
|
||||
|
||||
|
||||
|
||||
/* wrappers handle NULL members or no ops struct set at all cleanly */
|
||||
|
||||
/**
|
||||
|
@ -57,29 +108,28 @@ typedef struct lws_system_ops {
|
|||
* \param context: the lws_context
|
||||
* \param item: which information to fetch
|
||||
* \param arg: where to place the result
|
||||
* \param len: incoming: max length of result, outgoing: used length of result
|
||||
*
|
||||
* This queries a standardized information-fetching ops struct that can be
|
||||
* applied to the context... the advantage is it allows you to get common items
|
||||
* of information like a device serial number writing the code once, even if the
|
||||
* actual serial number muse be fetched in wildly different ways depending on
|
||||
* actual serial number must be fetched in wildly different ways depending on
|
||||
* the exact platform it's running on.
|
||||
*
|
||||
* Set arg and *len on entry to be the result location and the max length that
|
||||
* can be used there, on seccessful exit *len is set to the actual length and
|
||||
* 0 is returned. On error, 1 is returned.
|
||||
* Point arg to your lws_system_arg_t, on return it will be set. It doesn't
|
||||
* copy the content just sets pointer and length.
|
||||
*/
|
||||
LWS_EXTERN LWS_VISIBLE int
|
||||
lws_system_get_info(struct lws_context *context, lws_system_item_t item,
|
||||
lws_system_arg_t arg, size_t *len);
|
||||
lws_system_arg_t *arg);
|
||||
|
||||
|
||||
/**
|
||||
* lws_system_reboot() - if provided, use the lws_system ops to reboot
|
||||
* lws_system_get_ops() - get ahold of the system ops struct from the context
|
||||
*
|
||||
* \param context: the lws_context
|
||||
*
|
||||
* If possible, the system will reboot. Otherwise returns 1.
|
||||
* Returns the system ops struct. It may return NULL and if not, anything in
|
||||
* there may be NULL.
|
||||
*/
|
||||
LWS_EXTERN LWS_VISIBLE int
|
||||
lws_system_reboot(struct lws_context *context);
|
||||
LWS_EXTERN LWS_VISIBLE const lws_system_ops_t *
|
||||
lws_system_get_ops(struct lws_context *context);
|
||||
|
|
|
@ -31,6 +31,7 @@ lws_get_idlest_tsi(struct lws_context *context)
|
|||
int n = 0, hit = -1;
|
||||
|
||||
for (; n < context->count_threads; n++) {
|
||||
lwsl_notice("%s: %d %d\n", __func__, context->pt[n].fds_count, context->fd_limit_per_thread - 1);
|
||||
if ((unsigned int)context->pt[n].fds_count !=
|
||||
context->fd_limit_per_thread - 1 &&
|
||||
(unsigned int)context->pt[n].fds_count < lowest) {
|
||||
|
@ -540,7 +541,8 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
lwsl_info("%s: getaddrinfo error: %s\n", __func__,
|
||||
gai_strerror(n));
|
||||
#else
|
||||
lwsl_info("%s: getaddrinfo error: %s\n", __func__, strerror(n));
|
||||
lwsl_info("%s: getaddrinfo error: %s\n", __func__,
|
||||
strerror(n));
|
||||
#endif
|
||||
freeaddrinfo(r);
|
||||
goto bail1;
|
||||
|
@ -566,7 +568,12 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
lws_create_adopt_udp2, wsi, NULL) ==
|
||||
LADNS_RET_FAILED) {
|
||||
lwsl_err("%s: async dns failed\n", __func__);
|
||||
goto bail1;
|
||||
wsi = NULL;
|
||||
/*
|
||||
* It was already closed by calling callback with error
|
||||
* from lws_async_dns_query()
|
||||
*/
|
||||
goto bail;
|
||||
}
|
||||
} else
|
||||
wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, NULL);
|
||||
|
@ -575,10 +582,10 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
|
|||
|
||||
return wsi;
|
||||
#endif
|
||||
|
||||
#if !defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
bail1:
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "udp create fail");
|
||||
wsi = NULL;
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "adopt udp2 fail");
|
||||
#endif
|
||||
bail:
|
||||
return wsi;
|
||||
#else
|
||||
|
|
|
@ -88,7 +88,7 @@ __lws_reset_wsi(struct lws *wsi)
|
|||
lws_dll2_remove(&wsi->dll_cli_active_conns);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_ASYNC_DNS)
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
lws_async_dns_cancel(wsi);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -71,9 +71,12 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
#endif
|
||||
|
||||
wsi->vhost = NULL;
|
||||
if (!i->vhost)
|
||||
lws_vhost_bind_wsi(i->context->vhost_list, wsi);
|
||||
else
|
||||
if (!i->vhost) {
|
||||
struct lws_vhost *v = i->context->vhost_list;
|
||||
if (v && !strcmp(v->name, "system"))
|
||||
v = v->vhost_next;
|
||||
lws_vhost_bind_wsi(v, wsi);
|
||||
} else
|
||||
lws_vhost_bind_wsi(i->vhost, wsi);
|
||||
|
||||
if (!wsi->vhost) {
|
||||
|
|
|
@ -415,6 +415,22 @@ lws_retry_get_delay_ms(struct lws_context *context,
|
|||
return ms;
|
||||
}
|
||||
|
||||
int
|
||||
lws_retry_sul_schedule(struct lws_context *context, int tid,
|
||||
lws_sorted_usec_list_t *sul,
|
||||
const lws_retry_bo_t *retry, sul_cb_t cb, uint16_t *ctry)
|
||||
{
|
||||
char conceal;
|
||||
uint64_t ms = lws_retry_get_delay_ms(context, retry, ctry, &conceal);
|
||||
|
||||
if (!conceal)
|
||||
return 1;
|
||||
|
||||
lws_sul_schedule(context, tid, sul, cb, ms * 1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_IPV6)
|
||||
LWS_EXTERN unsigned long
|
||||
lws_get_addr_scope(const char *ipaddr)
|
||||
|
@ -812,3 +828,9 @@ lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
|
|||
|
||||
return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
lws_state_manager_t *
|
||||
lws_system_get_state_manager(struct lws_context *context)
|
||||
{
|
||||
return &context->mgr_system;
|
||||
}
|
||||
|
|
|
@ -1235,6 +1235,9 @@ void
|
|||
lws_async_dns_deinit(lws_async_dns_t *dns);
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_protocol_init_vhost(struct lws_vhost *vh, int *any);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -695,12 +695,6 @@ handled:
|
|||
#endif
|
||||
pollfd->revents = 0;
|
||||
|
||||
if (!context->protocol_init_done)
|
||||
if (lws_protocol_init(context)) {
|
||||
lwsl_err("%s: lws_protocol_init failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
134
lib/core-net/state.c
Normal file
134
lib/core-net/state.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "private-lib-core.h"
|
||||
|
||||
void
|
||||
lws_state_reg_notifier(lws_state_manager_t *mgr,
|
||||
lws_state_notify_link_t *notify_link)
|
||||
{
|
||||
lws_dll2_add_head(¬ify_link->list, &mgr->notify_list);
|
||||
}
|
||||
|
||||
void
|
||||
lws_state_reg_notifier_list(lws_state_manager_t *mgr,
|
||||
lws_state_notify_link_t **notify_link_array)
|
||||
{
|
||||
if (notify_link_array)
|
||||
while (*notify_link_array)
|
||||
lws_state_reg_notifier(mgr, *notify_link_array++);
|
||||
}
|
||||
|
||||
#if defined(_DEBUG)
|
||||
static const char *
|
||||
_systnm(lws_state_manager_t *mgr, int state, char *temp8)
|
||||
{
|
||||
if (!mgr->state_names) {
|
||||
lws_snprintf(temp8, 8, "%d", state);
|
||||
return temp8;
|
||||
}
|
||||
|
||||
return mgr->state_names[state];
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
_report(lws_state_manager_t *mgr, int a, int b)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
char temp8[8];
|
||||
#endif
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, d, mgr->notify_list.head) {
|
||||
lws_state_notify_link_t *l =
|
||||
lws_container_of(d, lws_state_notify_link_t, list);
|
||||
|
||||
if (l->notify_cb(mgr, l, a, b)) {
|
||||
/* a dependency took responsibility for retry */
|
||||
#if defined(_DEBUG)
|
||||
lwsl_info("%s: %s: %s: rejected '%s' -> '%s'\n",
|
||||
__func__, mgr->name, l->name,
|
||||
_systnm(mgr, a, temp8),
|
||||
_systnm(mgr, b, temp8));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
} lws_end_foreach_dll(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_state_transition(lws_state_manager_t *mgr, int target)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
char temp8[8];
|
||||
#endif
|
||||
|
||||
if (_report(mgr, mgr->state, target))
|
||||
return 1;
|
||||
|
||||
#if defined(_DEBUG)
|
||||
lwsl_debug("%s: %s: changed %d '%s' -> %d '%s'\n", __func__, mgr->name,
|
||||
mgr->state, _systnm(mgr, mgr->state, temp8), target,
|
||||
_systnm(mgr, target, temp8));
|
||||
#endif
|
||||
|
||||
mgr->state = target;
|
||||
|
||||
/* Indicate success by calling the notifers again with both args same */
|
||||
_report(mgr, target, target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_state_transition_steps(lws_state_manager_t *mgr, int target)
|
||||
{
|
||||
int n = 0;
|
||||
#if defined(_DEBUG)
|
||||
int i = mgr->state;
|
||||
char temp8[8];
|
||||
#endif
|
||||
|
||||
while (!n && mgr->state != target)
|
||||
n = _lws_state_transition(mgr, mgr->state + 1);
|
||||
|
||||
#if defined(_DEBUG)
|
||||
lwsl_info("%s: %s -> %s\n", __func__, _systnm(mgr, i, temp8),
|
||||
_systnm(mgr, mgr->state, temp8));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_state_transition(lws_state_manager_t *mgr, int target)
|
||||
{
|
||||
if (mgr->state != target)
|
||||
_lws_state_transition(mgr, target);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -280,6 +280,91 @@ lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_protocol_init_vhost(struct lws_vhost *vh, int *any)
|
||||
{
|
||||
const struct lws_protocol_vhost_options *pvo, *pvo1;
|
||||
struct lws *wsi = vh->context->pt[0].fake_wsi;
|
||||
int n;
|
||||
|
||||
wsi->context = vh->context;
|
||||
wsi->vhost = vh;
|
||||
|
||||
/* initialize supported protocols on this vhost */
|
||||
|
||||
for (n = 0; n < vh->count_protocols; n++) {
|
||||
wsi->protocol = &vh->protocols[n];
|
||||
if (!vh->protocols[n].name)
|
||||
continue;
|
||||
pvo = lws_vhost_protocol_options(vh, vh->protocols[n].name);
|
||||
if (pvo) {
|
||||
/*
|
||||
* linked list of options specific to
|
||||
* vh + protocol
|
||||
*/
|
||||
pvo1 = pvo;
|
||||
pvo = pvo1->options;
|
||||
|
||||
while (pvo) {
|
||||
lwsl_debug(
|
||||
" vhost \"%s\", "
|
||||
"protocol \"%s\", "
|
||||
"option \"%s\"\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name,
|
||||
pvo->name);
|
||||
|
||||
if (!strcmp(pvo->name, "default")) {
|
||||
lwsl_info("Setting default "
|
||||
"protocol for vh %s to %s\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name);
|
||||
vh->default_protocol_index = n;
|
||||
}
|
||||
if (!strcmp(pvo->name, "raw")) {
|
||||
lwsl_info("Setting raw "
|
||||
"protocol for vh %s to %s\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name);
|
||||
vh->raw_protocol_index = n;
|
||||
}
|
||||
pvo = pvo->next;
|
||||
}
|
||||
|
||||
pvo = pvo1->options;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (any)
|
||||
*any |= !!vh->tls.ssl_ctx;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are doing their
|
||||
* one-time initialization if they want to.
|
||||
*
|
||||
* NOTE the wsi is all zeros except for the context, vh
|
||||
* + protocol ptrs so lws_get_context(wsi) etc can work
|
||||
*/
|
||||
if (vh->protocols[n].callback(wsi,
|
||||
LWS_CALLBACK_PROTOCOL_INIT, NULL,
|
||||
(void *)pvo, 0)) {
|
||||
if (vh->protocol_vh_privs[n]) {
|
||||
lws_free(vh->protocol_vh_privs[n]);
|
||||
vh->protocol_vh_privs[n] = NULL;
|
||||
}
|
||||
lwsl_err("%s: protocol %s failed init\n",
|
||||
__func__, vh->protocols[n].name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
vh->created_vhost_protocols = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* inform every vhost that hasn't already done it, that
|
||||
* his protocols are initializing
|
||||
|
@ -288,98 +373,24 @@ LWS_VISIBLE int
|
|||
lws_protocol_init(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
const struct lws_protocol_vhost_options *pvo, *pvo1;
|
||||
struct lws *wsi = context->pt[0].fake_wsi;
|
||||
int n, any = 0;
|
||||
int any = 0;
|
||||
|
||||
if (context->doing_protocol_init)
|
||||
return 0;
|
||||
|
||||
context->doing_protocol_init = 1;
|
||||
|
||||
wsi->context = context;
|
||||
|
||||
lwsl_info("%s\n", __func__);
|
||||
|
||||
while (vh) {
|
||||
wsi->vhost = vh;
|
||||
|
||||
/* only do the protocol init once for a given vhost */
|
||||
if (vh->created_vhost_protocols ||
|
||||
(lws_check_opt(vh->options, LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT)))
|
||||
goto next;
|
||||
|
||||
/* initialize supported protocols on this vhost */
|
||||
|
||||
for (n = 0; n < vh->count_protocols; n++) {
|
||||
wsi->protocol = &vh->protocols[n];
|
||||
if (!vh->protocols[n].name)
|
||||
continue;
|
||||
pvo = lws_vhost_protocol_options(vh,
|
||||
vh->protocols[n].name);
|
||||
if (pvo) {
|
||||
/*
|
||||
* linked list of options specific to
|
||||
* vh + protocol
|
||||
*/
|
||||
pvo1 = pvo;
|
||||
pvo = pvo1->options;
|
||||
|
||||
while (pvo) {
|
||||
lwsl_debug(
|
||||
" vhost \"%s\", "
|
||||
"protocol \"%s\", "
|
||||
"option \"%s\"\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name,
|
||||
pvo->name);
|
||||
|
||||
if (!strcmp(pvo->name, "default")) {
|
||||
lwsl_info("Setting default "
|
||||
"protocol for vh %s to %s\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name);
|
||||
vh->default_protocol_index = n;
|
||||
}
|
||||
if (!strcmp(pvo->name, "raw")) {
|
||||
lwsl_info("Setting raw "
|
||||
"protocol for vh %s to %s\n",
|
||||
vh->name,
|
||||
vh->protocols[n].name);
|
||||
vh->raw_protocol_index = n;
|
||||
}
|
||||
pvo = pvo->next;
|
||||
}
|
||||
|
||||
pvo = pvo1->options;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
any |= !!vh->tls.ssl_ctx;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are doing their
|
||||
* one-time initialization if they want to.
|
||||
*
|
||||
* NOTE the wsi is all zeros except for the context, vh
|
||||
* + protocol ptrs so lws_get_context(wsi) etc can work
|
||||
*/
|
||||
if (vh->protocols[n].callback(wsi,
|
||||
LWS_CALLBACK_PROTOCOL_INIT, NULL,
|
||||
(void *)pvo, 0)) {
|
||||
if (vh->protocol_vh_privs[n]) {
|
||||
lws_free(vh->protocol_vh_privs[n]);
|
||||
vh->protocol_vh_privs[n] = NULL;
|
||||
}
|
||||
lwsl_err("%s: protocol %s failed init\n",
|
||||
__func__, vh->protocols[n].name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
vh->created_vhost_protocols = 1;
|
||||
if (lws_protocol_init_vhost(vh, &any))
|
||||
return 1;
|
||||
next:
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
|
|
@ -73,6 +73,60 @@ lws_sul_peer_limits_cb(lws_sorted_usec_list_t *sul)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
||||
#if defined(_DEBUG)
|
||||
static const char * system_state_names[] = {
|
||||
"undef",
|
||||
"CONTEXT_CREATED",
|
||||
"INITIALIZED",
|
||||
"IFACE_COLDPLUG",
|
||||
"DHCP",
|
||||
"TIME_VALID",
|
||||
"POLICY_VALID",
|
||||
"REGISTERED",
|
||||
"AUTH1",
|
||||
"AUTH2",
|
||||
"OPERATIONAL",
|
||||
"POLICY_INVALID"
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle provoking protocol init when we pass through the right system state
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_state_notify_protocol_init(struct lws_state_manager *mgr,
|
||||
struct lws_state_notify_link *link, int current,
|
||||
int target)
|
||||
{
|
||||
struct lws_context *context = lws_container_of(mgr, struct lws_context,
|
||||
mgr_system);
|
||||
|
||||
if (context->protocol_init_done)
|
||||
return 0;
|
||||
|
||||
if (target != LWS_SYSTATE_POLICY_VALID)
|
||||
return 0;
|
||||
|
||||
lwsl_info("%s: doing protocol init on POLICY_VALID\n", __func__);
|
||||
lws_protocol_init(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_context_creation_completion_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
struct lws_context *context = lws_container_of(sul, struct lws_context,
|
||||
sul_system_state);
|
||||
|
||||
/* if nothing is there to intercept anything, go all the way */
|
||||
lws_state_transition_steps(&context->mgr_system,
|
||||
LWS_SYSTATE_OPERATIONAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
LWS_VISIBLE struct lws_context *
|
||||
lws_create_context(const struct lws_context_creation_info *info)
|
||||
|
@ -92,6 +146,16 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
struct rlimit rt;
|
||||
#endif
|
||||
size_t s1 = 4096, size = sizeof(struct lws_context);
|
||||
int lpf = info->fd_limit_per_thread;
|
||||
|
||||
if (lpf) {
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
lpf++;
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_NTPCLIENT)
|
||||
lpf++;
|
||||
#endif
|
||||
}
|
||||
|
||||
lwsl_info("Initial logging level %d\n", log_level);
|
||||
lwsl_info("Libwebsockets version: %s\n", library_version);
|
||||
|
@ -264,7 +328,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
* figure out what if this is something it can deal with.
|
||||
*/
|
||||
if (info->fd_limit_per_thread) {
|
||||
int mf = info->fd_limit_per_thread * context->count_threads;
|
||||
int mf = lpf * context->count_threads;
|
||||
|
||||
if (mf < context->max_fds) {
|
||||
context->max_fds_unrelated_to_ulimit = 1;
|
||||
|
@ -366,7 +430,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->max_http_header_pool = context->max_fds;
|
||||
|
||||
if (info->fd_limit_per_thread)
|
||||
context->fd_limit_per_thread = info->fd_limit_per_thread;
|
||||
context->fd_limit_per_thread = lpf;
|
||||
else
|
||||
context->fd_limit_per_thread = context->max_fds /
|
||||
context->count_threads;
|
||||
|
@ -514,29 +578,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
lws_context_init_ssl_library(info);
|
||||
|
||||
context->user_space = info->user;
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
/*
|
||||
* if he's not saying he'll make his own vhosts later then act
|
||||
* compatibly and make a default vhost using the data in the info
|
||||
*/
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
if (!lws_create_vhost(context, info)) {
|
||||
lwsl_err("Failed to create default vhost\n");
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
lws_free_set_NULL(context->pl_hash_table);
|
||||
#endif
|
||||
lws_free_set_NULL(context->pt[0].fds);
|
||||
lws_plat_context_late_destroy(context);
|
||||
lws_free_set_NULL(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_context_init_extensions(info, context);
|
||||
|
||||
lwsl_info(" mem: per-conn: %5lu bytes + protocol rx buf\n",
|
||||
(unsigned long)sizeof(struct lws));
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
strcpy(context->canonical_hostname, "unknown");
|
||||
|
@ -561,6 +603,104 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->count_caps = info->count_caps;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS) || defined(LWS_WITH_SYS_NTPCLIENT)
|
||||
{
|
||||
/*
|
||||
* system vhost
|
||||
*/
|
||||
|
||||
struct lws_context_creation_info ii;
|
||||
const struct lws_protocols *pp[3];
|
||||
struct lws_vhost *vh;
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
extern const struct lws_protocols lws_async_dns_protocol;
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_NTPCLIENT)
|
||||
extern const struct lws_protocols lws_system_protocol_ntpc;
|
||||
#endif
|
||||
|
||||
n = 0;
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
pp[n++] = &lws_async_dns_protocol;
|
||||
#endif
|
||||
#if defined(LWS_WITH_SYS_NTPCLIENT)
|
||||
pp[n++] = &lws_system_protocol_ntpc;
|
||||
#endif
|
||||
pp[n] = NULL;
|
||||
|
||||
memset(&ii, 0, sizeof(ii));
|
||||
ii.vhost_name = "system";
|
||||
ii.pprotocols = pp;
|
||||
|
||||
vh = lws_create_vhost(context, &ii);
|
||||
if (!vh) {
|
||||
lwsl_err("%s: failed to create system vhost\n",
|
||||
__func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
context->vhost_system = vh;
|
||||
|
||||
if (lws_protocol_init_vhost(vh, NULL)) {
|
||||
lwsl_err("%s: failed to init system vhost\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
#if defined(LWS_WITH_SYS_ASYNC_DNS)
|
||||
if (lws_async_dns_init(context))
|
||||
goto bail;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* init the lws_state mgr for the system state
|
||||
*/
|
||||
#if defined(_DEBUG)
|
||||
context->mgr_system.state_names = system_state_names;
|
||||
#endif
|
||||
context->mgr_system.name = "system";
|
||||
context->mgr_system.state = LWS_SYSTATE_CONTEXT_CREATED;
|
||||
context->mgr_system.parent = context;
|
||||
|
||||
context->protocols_notify.name = "prot_init";
|
||||
context->protocols_notify.notify_cb = lws_state_notify_protocol_init;
|
||||
|
||||
lws_state_reg_notifier(&context->mgr_system, &context->protocols_notify);
|
||||
|
||||
/*
|
||||
* insert user notifiers here so they can participate with vetoing us
|
||||
* trying to jump straight to operational, or at least observe us
|
||||
* reaching 'operational', before we returned from context creation.
|
||||
*/
|
||||
|
||||
lws_state_reg_notifier_list(&context->mgr_system,
|
||||
info->register_notifier_list);
|
||||
|
||||
/*
|
||||
* if he's not saying he'll make his own vhosts later then act
|
||||
* compatibly and make a default vhost using the data in the info
|
||||
*/
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
if (!lws_create_vhost(context, info)) {
|
||||
lwsl_err("Failed to create default vhost\n");
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
lws_free_set_NULL(context->pl_hash_table);
|
||||
#endif
|
||||
lws_free_set_NULL(context->pt[0].fds);
|
||||
lws_plat_context_late_destroy(context);
|
||||
lws_free_set_NULL(context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_context_init_extensions(info, context);
|
||||
|
||||
lwsl_info(" mem: per-conn: %5lu bytes + protocol rx buf\n",
|
||||
(unsigned long)sizeof(struct lws));
|
||||
|
||||
/*
|
||||
* drop any root privs for this process
|
||||
* to listen on port < 1023 we would have needed root, but now we are
|
||||
|
@ -570,7 +710,18 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
if (lws_plat_drop_app_privileges(context, 1))
|
||||
goto bail;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
/*
|
||||
* We want to move on the syste, state as far as it can go towards
|
||||
* OPERATIONAL now. But we have to return from here first so the user
|
||||
* code that called us can set its copy of context, which it may be
|
||||
* relying on to perform operations triggered by the state change.
|
||||
*
|
||||
* We set up a sul to come back immediately and do the state change.
|
||||
*/
|
||||
|
||||
lws_sul_schedule(context, 0, &context->sul_system_state,
|
||||
lws_context_creation_completion_cb, 1);
|
||||
|
||||
/* expedite post-context init (eg, protocols) */
|
||||
lws_cancel_service(context);
|
||||
#endif
|
||||
|
@ -826,6 +977,7 @@ lws_context_destroy(struct lws_context *context)
|
|||
context->requested_kill = 1;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
lws_state_transition(&context->mgr_system, LWS_SYSTATE_POLICY_INVALID);
|
||||
m = context->count_threads;
|
||||
|
||||
while (m--) {
|
||||
|
@ -910,4 +1062,3 @@ lws_context_destroy(struct lws_context *context)
|
|||
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
|
||||
|
|
|
@ -1041,19 +1041,16 @@ lws_humanize(char *p, int len, uint64_t v, const lws_humanize_unit_t *schema)
|
|||
|
||||
int
|
||||
lws_system_get_info(struct lws_context *context, lws_system_item_t item,
|
||||
lws_system_arg_t arg, size_t *len)
|
||||
lws_system_arg_t *arg)
|
||||
{
|
||||
if (!context->system_ops || !context->system_ops->get_info)
|
||||
return 1;
|
||||
|
||||
return context->system_ops->get_info(item, arg, len);
|
||||
return context->system_ops->get_info(item, arg);
|
||||
}
|
||||
|
||||
int
|
||||
lws_system_reboot(struct lws_context *context)
|
||||
const lws_system_ops_t *
|
||||
lws_system_get_ops(struct lws_context *context)
|
||||
{
|
||||
if (!context->system_ops || !context->system_ops->reboot)
|
||||
return 1;
|
||||
|
||||
return context->system_ops->reboot();
|
||||
return context->system_ops;
|
||||
}
|
||||
|
|
|
@ -275,9 +275,9 @@ struct lws_context {
|
|||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
|
||||
struct lws_context_per_thread pt[LWS_MAX_SMP];
|
||||
lws_retry_bo_t default_retry;
|
||||
lws_sorted_usec_list_t sul_system_state;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
struct http2_settings set;
|
||||
|
@ -309,11 +309,17 @@ struct lws_context {
|
|||
lws_async_dns_t async_dns;
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
lws_state_manager_t mgr_system;
|
||||
lws_state_notify_link_t protocols_notify;
|
||||
#endif
|
||||
|
||||
/* pointers */
|
||||
|
||||
struct lws_vhost *vhost_list;
|
||||
struct lws_vhost *no_listener_vhost_list;
|
||||
struct lws_vhost *vhost_pending_destruction_list;
|
||||
struct lws_vhost *vhost_system;
|
||||
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
const char *server_string;
|
||||
|
|
13
lib/system/README.md
Normal file
13
lib/system/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# LWS System Helpers
|
||||
|
||||
Lws now has a little collection of helper utilities for common network-based
|
||||
functions necessary for normal device operation, eg, async DNS, ntpclient
|
||||
(necessary for tls validation), and DHCP client.
|
||||
|
||||
## Conventions
|
||||
|
||||
If any system helper is enabled for build, lws creates an additional vhost
|
||||
"system" at Context Creation time. Wsi that are created for the system
|
||||
features are bound to this. In the context object, this is available as
|
||||
`.vhost_system`.
|
||||
|
|
@ -37,7 +37,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",
|
||||
in ? (char *)in : "(null)");
|
||||
client_wsi = NULL;
|
||||
interrupted = 1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
||||
|
@ -86,13 +86,13 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
|
||||
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
||||
lwsl_user("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n");
|
||||
client_wsi = NULL;
|
||||
interrupted = 1;
|
||||
bad = status != 200;
|
||||
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
|
||||
client_wsi = NULL;
|
||||
interrupted = 1;
|
||||
bad = status != 200;
|
||||
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
|
||||
break;
|
||||
|
@ -120,12 +120,92 @@ sigint_handler(int sig)
|
|||
interrupted = 1;
|
||||
}
|
||||
|
||||
struct args {
|
||||
int argc;
|
||||
const char **argv;
|
||||
};
|
||||
|
||||
static int
|
||||
system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
|
||||
int current, int target)
|
||||
{
|
||||
struct lws_context *context = mgr->parent;
|
||||
struct lws_client_connect_info i;
|
||||
struct args *a = lws_context_user(context);
|
||||
const char *p;
|
||||
|
||||
if (current != LWS_SYSTATE_OPERATIONAL || target != LWS_SYSTATE_OPERATIONAL)
|
||||
return 0;
|
||||
|
||||
lwsl_info("%s: operational\n", __func__);
|
||||
|
||||
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
|
||||
i.context = context;
|
||||
if (!lws_cmdline_option(a->argc, a->argv, "-n")) {
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
/* requires h2 */
|
||||
if (lws_cmdline_option(a->argc, a->argv, "--long-poll")) {
|
||||
lwsl_user("%s: long poll mode\n", __func__);
|
||||
long_poll = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-l")) {
|
||||
i.port = 7681;
|
||||
i.address = "localhost";
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
} else {
|
||||
i.port = 443;
|
||||
i.address = "warmcat.com";
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "--h1"))
|
||||
i.alpn = "http/1.1";
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "-p")))
|
||||
i.port = atoi(p);
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-j"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-k"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_INSECURE;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-m"))
|
||||
i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-e"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_EXPIRED;
|
||||
|
||||
/* the default validity check is 5m / 5m10s... -v = 3s / 10s */
|
||||
|
||||
if (lws_cmdline_option(a->argc, a->argv, "-v"))
|
||||
i.retry_and_idle_policy = &retry;
|
||||
|
||||
if ((p = lws_cmdline_option(a->argc, a->argv, "--server")))
|
||||
i.address = p;
|
||||
|
||||
i.path = "/";
|
||||
i.host = i.address;
|
||||
i.origin = i.address;
|
||||
i.method = "GET";
|
||||
|
||||
i.protocol = protocols[0].name;
|
||||
i.pwsi = &client_wsi;
|
||||
|
||||
return !lws_client_connect_via_info(&i);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
lws_state_notify_link_t notifier = { {}, system_notify_cb, "app" };
|
||||
lws_state_notify_link_t *na[] = { ¬ifier, NULL };
|
||||
struct lws_context_creation_info info;
|
||||
struct lws_client_connect_info i;
|
||||
struct lws_context *context;
|
||||
const char *p;
|
||||
struct args args;
|
||||
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/*
|
||||
* For LLL_ verbosity above NOTICE to be built into lws,
|
||||
|
@ -136,6 +216,9 @@ int main(int argc, const char **argv)
|
|||
* LLL_CLIENT | LLL_LATENCY | LLL_DEBUG
|
||||
*/ ;
|
||||
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
|
@ -148,6 +231,8 @@ int main(int argc, const char **argv)
|
|||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
|
||||
info.protocols = protocols;
|
||||
info.user = &args;
|
||||
info.register_notifier_list = na;
|
||||
|
||||
/*
|
||||
* since we know this lws context is only ever going to be used with
|
||||
|
@ -172,64 +257,7 @@ int main(int argc, const char **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
|
||||
i.context = context;
|
||||
if (!lws_cmdline_option(argc, argv, "-n")) {
|
||||
i.ssl_connection = LCCSCF_USE_SSL;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
/* requires h2 */
|
||||
if (lws_cmdline_option(argc, argv, "--long-poll")) {
|
||||
lwsl_user("%s: long poll mode\n", __func__);
|
||||
long_poll = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-l")) {
|
||||
i.port = 7681;
|
||||
i.address = "localhost";
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
} else {
|
||||
i.port = 443;
|
||||
i.address = "warmcat.com";
|
||||
}
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "--h1"))
|
||||
i.alpn = "http/1.1";
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-p")))
|
||||
i.port = atoi(p);
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-j"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_SELFSIGNED;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-k"))
|
||||
i.ssl_connection |= LCCSCF_ALLOW_INSECURE;
|
||||
|
||||
if (lws_cmdline_option(argc, argv, "-m"))
|
||||
i.ssl_connection |= LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||
|
||||
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;
|
||||
|
||||
i.path = "/";
|
||||
i.host = i.address;
|
||||
i.origin = i.address;
|
||||
i.method = "GET";
|
||||
|
||||
i.protocol = protocols[0].name;
|
||||
i.pwsi = &client_wsi;
|
||||
lws_client_connect_via_info(&i);
|
||||
|
||||
while (n >= 0 && client_wsi && !interrupted)
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 0);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
|
Loading…
Add table
Reference in a new issue