libwebsockets
Lightweight C library for HTML5 websockets
lws-system.h
Go to the documentation of this file.
1  /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * This provides a clean way to interface lws user code to be able to
25  * work unchanged on different systems for fetching common system information,
26  * and performing common system operations like reboot.
27  */
28 
29 /*
30  * Types of system blob that can be set and retreived
31  */
32 
33 typedef enum {
44 
45 #if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
46  /* extend 4 more auth blobs, each has 2 slots */
47  LWS_SYSBLOB_TYPE_EXT_AUTH1,
48  LWS_SYSBLOB_TYPE_EXT_AUTH2 = LWS_SYSBLOB_TYPE_EXT_AUTH1 + 2,
49  LWS_SYSBLOB_TYPE_EXT_AUTH3 = LWS_SYSBLOB_TYPE_EXT_AUTH2 + 2,
50  LWS_SYSBLOB_TYPE_EXT_AUTH4 = LWS_SYSBLOB_TYPE_EXT_AUTH3 + 2,
51  LWS_SYSBLOB_TYPE_EXT_AUTH4_1,
52 #endif
53 
54  LWS_SYSBLOB_TYPE_COUNT /* ... always last */
55 } lws_system_blob_item_t;
56 
57 /* opaque generic blob whose content may be on-the-heap or pointed-to
58  * directly case by case. When it's on the heap, it can be produced by
59  * appending (it's a buflist underneath). Either way, it can be consumed by
60  * copying out a given length from a given offset.
61  */
62 
63 typedef struct lws_system_blob lws_system_blob_t;
64 
65 LWS_EXTERN LWS_VISIBLE void
66 lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
67 
68 LWS_EXTERN LWS_VISIBLE void
70 
71 LWS_EXTERN LWS_VISIBLE int
72 lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *ptr, size_t len);
73 
74 LWS_EXTERN LWS_VISIBLE size_t
75 lws_system_blob_get_size(lws_system_blob_t *b);
76 
77 /* return 0 and sets *ptr to point to blob data if possible, nonzero = fail */
78 LWS_EXTERN LWS_VISIBLE int
80 
81 LWS_EXTERN LWS_VISIBLE int
82 lws_system_blob_get(lws_system_blob_t *b, uint8_t *ptr, size_t *len, size_t ofs);
83 
84 LWS_EXTERN LWS_VISIBLE void
86 
87 /*
88  * Get the opaque blob for index idx of various system blobs. Returns 0 if
89  * *b was set otherwise nonzero means out of range
90  */
91 
92 LWS_EXTERN LWS_VISIBLE lws_system_blob_t *
93 lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type,
94  int idx);
95 
96 /*
97  * Lws view of system state... normal operation from user code perspective is
98  * dependent on implicit (eg, knowing the date for cert validation) and
99  * explicit dependencies.
100  *
101  * Bit of lws and user code can register notification handlers that can enforce
102  * dependent operations before state transitions can complete.
103  */
104 
105 typedef enum { /* keep system_state_names[] in sync in context.c */
107 
108  LWS_SYSTATE_CONTEXT_CREATED, /* context was just created */
109  LWS_SYSTATE_INITIALIZED, /* protocols initialized. Lws itself
110  * can operate normally */
111  LWS_SYSTATE_IFACE_COLDPLUG, /* existing net ifaces iterated */
112  LWS_SYSTATE_DHCP, /* at least one net iface configured */
113  LWS_SYSTATE_CPD_PRE_TIME, /* Captive portal detect without valid
114  * time, good for non-https tests... if
115  * you care about it, implement and
116  * call lws_system_ops_t
117  * .captive_portal_detect_request()
118  * and move the state forward according
119  * to the result. */
120  LWS_SYSTATE_TIME_VALID, /* ntpclient ran, or hw time valid...
121  * tls cannot work until we reach here
122  */
123  LWS_SYSTATE_CPD_POST_TIME, /* Captive portal detect after time was
124  * time, good for https tests... if
125  * you care about it, implement and
126  * call lws_system_ops_t
127  * .captive_portal_detect_request()
128  * and move the state forward according
129  * to the result. */
130 
131  LWS_SYSTATE_POLICY_VALID, /* user code knows how to operate... */
132  LWS_SYSTATE_REGISTERED, /* device has an identity... */
133  LWS_SYSTATE_AUTH1, /* identity used for main auth token */
134  LWS_SYSTATE_AUTH2, /* identity used for optional auth */
135 
136  LWS_SYSTATE_ONE_TIME_UPDATES, /* pre-OPERATIONAL one-time updates,
137  * when a firmware needs to perform
138  * one-time upgrades to state before
139  * OPERATIONAL */
140 
141  LWS_SYSTATE_OPERATIONAL, /* user code can operate normally */
142 
143  LWS_SYSTATE_POLICY_INVALID, /* user code is changing its policies
144  * drop everything done with old
145  * policy, switch to new then enter
146  * LWS_SYSTATE_POLICY_VALID */
147  LWS_SYSTATE_CONTEXT_DESTROYING, /* Context is being destroyed */
148  LWS_SYSTATE_AWAITING_MODAL_UPDATING, /* We're negotiating with the
149  * user code for update mode */
150  LWS_SYSTATE_MODAL_UPDATING, /* We're updating the firmware */
151 } lws_system_states_t;
152 
153 /* Captive Portal Detect -related */
154 
155 typedef enum {
156  LWS_CPD_UNKNOWN = 0, /* test didn't happen ince last DHCP acq yet */
157  LWS_CPD_INTERNET_OK, /* no captive portal: our CPD test passed OK,
158  * we can go out on the internet */
159  LWS_CPD_CAPTIVE_PORTAL, /* we inferred we're behind a captive portal */
160  LWS_CPD_NO_INTERNET, /* we couldn't touch anything */
161 } lws_cpd_result_t;
162 
163 typedef void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
164 struct lws_attach_item;
165 
166 LWS_EXTERN LWS_VISIBLE int
167 lws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque,
168  const uint8_t *skid, size_t skid_len,
169  const uint8_t *der, size_t der_len);
170 
171 typedef struct lws_system_ops {
172  int (*reboot)(void);
173  int (*set_clock)(lws_usec_t us);
174  int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
175  lws_system_states_t state, void *opaque,
176  struct lws_attach_item **get);
177  /**< if \p get is NULL, add an attach callback request to the pt for
178  * \p cb with arg \p opaque, that should be called when we're at or past
179  * system state \p state.
180  *
181  * If \p get is non-NULL, look for the first listed item on the pt whose
182  * state situation is ready, and set *get to point to it. If no items,
183  * or none where the system state is right, set *get to NULL.
184  *
185  * It's done like this so (*attach) can perform system-specific
186  * locking outside of lws core, for both getting and adding items the
187  * same so it is thread-safe. A non-threadsafe helper
188  * __lws_system_attach() is provided to do the actual work inside the
189  * system-specific locking.
190  */
191  int (*captive_portal_detect_request)(struct lws_context *context);
192  /**< Check if we can go out on the internet cleanly, or if we are being
193  * redirected or intercepted by a captive portal.
194  * Start the check that proceeds asynchronously, and report the results
195  * by calling lws_captive_portal_detect_result() api
196  */
197 
198 #if defined(LWS_WITH_NETWORK)
200  /**< metric \p item is reporting an event of kind \p rpt,
201  * held in \p mdata... return 0 to leave the metric object as it is,
202  * or nonzero to reset it. */
203 #endif
204  int (*jit_trust_query)(struct lws_context *cx, const uint8_t *skid,
205  size_t skid_len, void *got_opaque);
206  /**< user defined trust store search, if we do trust a cert with SKID
207  * matching skid / skid_len, then it should get hold of the DER for the
208  * matching root CA and call
209  * lws_tls_jit_trust_got_cert_cb(..., got_opaque) before cleaning up and
210  * returning. The DER should be destroyed if in heap before returning.
211  */
212 
213 #if defined(LWS_WITH_OTA)
215  /**< Platform OTA interface to lws_ota, see lws-ota.h */
216 #endif
217 
219  /**< time taken for this device to wake from suspend, in us
220  */
221 } lws_system_ops_t;
222 
223 #if defined(LWS_WITH_SYS_STATE)
224 
225 /**
226  * lws_system_get_state_manager() - return the state mgr object for system state
227  *
228  * \param context: the lws_context
229  *
230  * The returned pointer can be used with the lws_state_ apis
231  */
232 
233 LWS_EXTERN LWS_VISIBLE lws_state_manager_t *
234 lws_system_get_state_manager(struct lws_context *context);
235 
236 #endif
237 
238 /* wrappers handle NULL members or no ops struct set at all cleanly */
239 
240 #define LWSSYSGAUTH_HEX (1 << 0)
241 
242 /**
243  * lws_system_get_ops() - get ahold of the system ops struct from the context
244  *
245  * \param context: the lws_context
246  *
247  * Returns the system ops struct. It may return NULL and if not, anything in
248  * there may be NULL.
249  */
250 LWS_EXTERN LWS_VISIBLE const lws_system_ops_t *
251 lws_system_get_ops(struct lws_context *context);
252 
253 #if defined(LWS_WITH_SYS_STATE)
254 
255 /**
256  * lws_system_context_from_system_mgr() - return context from system state mgr
257  *
258  * \param mgr: pointer to specifically the system state mgr
259  *
260  * Returns the context from the system state mgr. Helper since the lws_context
261  * is opaque.
262  */
263 LWS_EXTERN LWS_VISIBLE struct lws_context *
264 lws_system_context_from_system_mgr(lws_state_manager_t *mgr);
265 
266 #endif
267 
268 /**
269  * __lws_system_attach() - get and set items on context attach list
270  *
271  * \param context: context to get or set attach items to
272  * \param tsi: thread service index (normally 0)
273  * \param cb: callback to call from context event loop thread
274  * \param state: the lws_system state we have to be in or have passed through
275  * \param opaque: optional pointer to user specific info given to callback
276  * \param get: NULL, or pointer to pointer to take detached tail item on exit
277  *
278  * This allows other threads to enqueue callback requests to happen from a pt's
279  * event loop thread safely. The callback gets the context pointer and a user
280  * opaque pointer that can be optionally given when the item is added to the
281  * attach list.
282  *
283  * This api is the no-locking core function for getting and setting items on the
284  * pt's attach list. The lws_system operation (*attach) is the actual
285  * api that user and internal code calls for this feature, it should perform
286  * system-specific locking, call this helper, release the locking and then
287  * return the result. This api is public only so it can be used in the locked
288  * implementation of (*attach).
289  *
290  * If get is NULL, then the call adds to the head of the pt attach list using
291  * cb, state, and opaque; if get is non-NULL, then *get is set to the first
292  * waiting attached item that meets the state criteria and that item is removed
293  * from the list.
294  *
295  * This is a non-threadsafe helper only designed to be called from
296  * implementations of struct lws_system's (*attach) operation where system-
297  * specific locking has been applied around it, making it threadsafe.
298  */
299 LWS_EXTERN LWS_VISIBLE int
300 __lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
301  lws_system_states_t state, void *opaque,
302  struct lws_attach_item **get);
303 
304 
305 enum {
311 
313 
322 
324 };
325 
326 #if defined(LWS_WITH_NETWORK)
327 typedef struct lws_dhcpc_ifstate {
328  char ifname[16];
329  char domain[64];
330  uint8_t mac[6];
331  uint32_t nums[_LWSDH_NUMS_COUNT];
332  lws_sockaddr46 sa46[_LWSDH_SA46_COUNT];
333 } lws_dhcpc_ifstate_t;
334 
335 typedef int (*dhcpc_cb_t)(void *opaque, lws_dhcpc_ifstate_t *is);
336 
337 /**
338  * lws_dhcpc_request() - add a network interface to dhcpc management
339  *
340  * \param c: the lws_context
341  * \param i: the interface name, like "eth0"
342  * \param af: address family
343  * \param cb: the change callback
344  * \param opaque: opaque pointer given to the callback
345  *
346  * Register a network interface as being managed by DHCP. lws will proceed to
347  * try to acquire an IP. Requires LWS_WITH_SYS_DHCP_CLIENT at cmake.
348  */
349 LWS_EXTERN LWS_VISIBLE int
350 lws_dhcpc_request(struct lws_context *c, const char *i, int af, dhcpc_cb_t cb,
351  void *opaque);
352 
353 /**
354  * lws_dhcpc_remove() - remove a network interface to dhcpc management
355  *
356  * \param context: the lws_context
357  * \param iface: the interface name, like "eth0"
358  *
359  * Remove handling of the network interface from dhcp.
360  */
361 LWS_EXTERN LWS_VISIBLE int
362 lws_dhcpc_remove(struct lws_context *context, const char *iface);
363 
364 /**
365  * lws_dhcpc_status() - has any interface reached BOUND state
366  *
367  * \param context: the lws_context
368  * \param sa46: set to a DNS server from a bound interface, or NULL
369  *
370  * Returns 1 if any network interface managed by dhcpc has reached the BOUND
371  * state (has acquired an IP, gateway and DNS server), otherwise 0.
372  */
373 LWS_EXTERN LWS_VISIBLE int
374 lws_dhcpc_status(struct lws_context *context, lws_sockaddr46 *sa46);
375 
376 /**
377  * lws_system_cpd_start() - helper to initiate captive portal detection
378  *
379  * \param context: the lws_context
380  *
381  * Resets the context's captive portal state to LWS_CPD_UNKNOWN and calls the
382  * lws_system_ops_t captive_portal_detect_request() implementation to begin
383  * testing the captive portal state.
384  */
385 LWS_EXTERN LWS_VISIBLE int
386 lws_system_cpd_start(struct lws_context *context);
387 
388 LWS_EXTERN LWS_VISIBLE void
389 lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us);
390 
391 
392 /**
393  * lws_system_cpd_set() - report the result of the captive portal detection
394  *
395  * \param context: the lws_context
396  * \param result: one of the LWS_CPD_ constants representing captive portal state
397  *
398  * Sets the context's captive portal detection state to result. User captive
399  * portal detection code would call this once it had a result from its test.
400  */
401 LWS_EXTERN LWS_VISIBLE void
402 lws_system_cpd_set(struct lws_context *context, lws_cpd_result_t result);
403 
404 
405 /**
406  * lws_system_cpd_state_get() - returns the last tested captive portal state
407  *
408  * \param context: the lws_context
409  *
410  * Returns one of the LWS_CPD_ constants indicating the system's understanding
411  * of the current captive portal situation.
412  */
413 LWS_EXTERN LWS_VISIBLE lws_cpd_result_t
414 lws_system_cpd_state_get(struct lws_context *context);
415 
416 #endif