diff --git a/include/libwebsockets/lws-system.h b/include/libwebsockets/lws-system.h index 9578df455..884bee7d4 100644 --- a/include/libwebsockets/lws-system.h +++ b/include/libwebsockets/lws-system.h @@ -24,30 +24,62 @@ * This provides a clean way to interface lws user code to be able to * work unchanged on different systems for fetching common system information, * and performing common system operations like reboot. - * - * An ops struct with the system-specific implementations is set at - * context creation time, and apis are provided that call through to - * those where they exist. + */ + +/* + * Types of system blob that can be set and retreived */ 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_HRS_CLIENT_CERT_DER, + LWS_SYSBLOB_TYPE_AUTH, + LWS_SYSBLOB_TYPE_CLIENT_CERT_DER = LWS_SYSBLOB_TYPE_AUTH + 2, + LWS_SYSBLOB_TYPE_CLIENT_KEY_DER, + LWS_SYSBLOB_TYPE_DEVICE_SERIAL, + LWS_SYSBLOB_TYPE_DEVICE_FW_VERSION, + LWS_SYSBLOB_TYPE_DEVICE_TYPE, + LWS_SYSBLOB_TYPE_NTP_SERVER, - LWS_SYSI_USER_BASE = 100 -} lws_system_item_t; + LWS_SYSBLOB_TYPE_COUNT /* ... always last */ +} lws_system_blob_item_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; +/* opaque generic blob whose content may be on-the-heap or pointed-to + * directly case by case. When it's on the heap, it can be produced by + * appending (it's a buflist underneath). Either way, it can be consumed by + * copying out a given length from a given offset. + */ + +typedef struct lws_system_blob lws_system_blob_t; + +LWS_EXTERN LWS_VISIBLE void +lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len); + +LWS_EXTERN LWS_VISIBLE void +lws_system_blob_heap_empty(lws_system_blob_t *b); + +LWS_EXTERN LWS_VISIBLE int +lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *ptr, size_t len); + +LWS_EXTERN LWS_VISIBLE size_t +lws_system_blob_get_size(lws_system_blob_t *b); + +/* return 0 and sets *ptr to point to blob data if possible, nonzero = fail */ +LWS_EXTERN LWS_VISIBLE int +lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr); + +LWS_EXTERN LWS_VISIBLE int +lws_system_blob_get(lws_system_blob_t *b, uint8_t *ptr, size_t *len, size_t ofs); + +LWS_EXTERN LWS_VISIBLE void +lws_system_blob_destroy(lws_system_blob_t *b); + +/* + * Get the opaque blob for index idx of various system blobs. Returns 0 if + * *b was set otherwise nonzero means out of range + */ + +LWS_EXTERN LWS_VISIBLE lws_system_blob_t * +lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type, + int idx); /* * Lws view of system state... normal operation from user code perspective is @@ -82,25 +114,9 @@ typedef enum { /* keep system_state_names[] in sync in context.c */ * LWS_SYSTATE_POLICY_VALID */ } lws_system_states_t; -typedef enum { - LWSSYS_AUTH_GET, - LWSSYS_AUTH_TOTAL_LENGTH, - LWSSYS_AUTH_APPEND, - LWSSYS_AUTH_FREE, -} lws_system_auth_op_t; - -typedef int (*lws_system_auth_cb_t)(struct lws_context *context, int idx, - size_t ofs, uint8_t *buf, size_t *plen, - lws_system_auth_op_t set); - 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_auth_cb_t auth; - /**< Systemwide auth token management. For set, content may be appended - * incrementally safely. For get, content may be read out in arbitrary - * fragments using \p ofs. */ } lws_system_ops_t; /** @@ -118,50 +134,9 @@ lws_system_get_state_manager(struct lws_context *context); /* wrappers handle NULL members or no ops struct set at all cleanly */ -/** - * lws_system_get_info() - get standardized system information - * - * \param context: the lws_context - * \param item: which information to fetch - * \param arg: where to place the 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 must be fetched in wildly different ways depending on - * the exact platform it's running on. - * - * 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); - #define LWSSYSGAUTH_HEX (1 << 0) -/** - * lws_system_get_auth() - retreive system auth token helper - * - * \param context: the lws_context - * \param idx: which auth token - * \param ofs: offset in source to copy from - * \param buf: where to store result, or NULL - * \param buflen: size of buf - * \param flags: how to write the result - * - * Attempts to fill buf with the requested system auth token. If flags has - * LWSSYSGAUTH_HEX set, then the auth token is written as pairs of hex chars - * for each byte. If not set, written as 1 byte per byte binary. - * - * If buf is NULL, returns <= 0 if auth token is not set or > 0 if set, without - * writing anything. *buflen is still set to the size of the auth token. - */ -LWS_EXTERN LWS_VISIBLE int -lws_system_get_auth(struct lws_context *context, int idx, size_t ofs, - uint8_t *buf, size_t buflen, int flags); - /** * lws_system_get_ops() - get ahold of the system ops struct from the context * diff --git a/lib/core/private-lib-core.h b/lib/core/private-lib-core.h index 2883a3e54..2b5b959f8 100644 --- a/lib/core/private-lib-core.h +++ b/lib/core/private-lib-core.h @@ -254,6 +254,17 @@ struct lws_deferred_free void *payload; }; +typedef struct lws_system_blob { + union { + struct lws_buflist *bl; + struct { + const uint8_t *ptr; + size_t len; + } direct; + } u; + char is_direct; +} lws_system_blob_t; + /* * the rest is managed per-context, that includes * @@ -274,6 +285,8 @@ struct lws_context { struct lws_plat_file_ops fops_zip; #endif + lws_system_blob_t system_blobs[LWS_SYSBLOB_TYPE_COUNT]; + #if defined(LWS_WITH_NETWORK) struct lws_context_per_thread pt[LWS_MAX_SMP]; lws_retry_bo_t default_retry; @@ -309,15 +322,11 @@ struct lws_context { lws_async_dns_t async_dns; #endif - struct lws_buflist *auth_token[2]; - -#if defined(LWS_WITH_NETWORK) lws_state_manager_t mgr_system; lws_state_notify_link_t protocols_notify; #if defined (LWS_WITH_SYS_DHCP_CLIENT) lws_dll2_owner_t dhcpc_owner; /**< list of ifaces with dhcpc */ -#endif #endif /* pointers */ diff --git a/lib/system/ntpclient/ntpclient.c b/lib/system/ntpclient/ntpclient.c index 8a64bacef..46236acf1 100644 --- a/lib/system/ntpclient/ntpclient.c +++ b/lib/system/ntpclient/ntpclient.c @@ -125,7 +125,6 @@ callback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user, lws_protocol_vh_priv_get(lws_get_vhost(wsi), lws_get_protocol(wsi)); uint8_t pkt[LWS_PRE + 48]; - lws_system_arg_t arg; uint64_t ns; switch (reason) { @@ -157,11 +156,10 @@ callback_ntpc(struct lws *wsi, enum lws_callback_reasons reason, void *user, v->notify_link.name = "ntpclient"; lws_state_reg_notifier(&wsi->context->mgr_system, &v->notify_link); - if (lws_system_get_info(wsi->context, LWS_SYSI_HRS_NTP_SERVER, - &arg)) - v->ntp_server_ads = "pool.ntp.org"; - else - v->ntp_server_ads = arg.u.hrs; + v->ntp_server_ads = "pool.ntp.org"; + lws_system_blob_get_single_ptr(lws_system_get_blob( + v->context, LWS_SYSBLOB_TYPE_NTP_SERVER, 0), + (const uint8_t **)&v->ntp_server_ads); lws_ntpc_retry_conn(&v->sul_conn); break; diff --git a/lib/system/system.c b/lib/system/system.c index 349b20f1f..61dbfa440 100644 --- a/lib/system/system.c +++ b/lib/system/system.c @@ -24,19 +24,10 @@ #include -#if defined(LWS_WITH_NETWORK) -static const char *hex = "0123456789ABCDEF"; -#endif - -int -lws_system_get_info(struct lws_context *context, lws_system_item_t item, - lws_system_arg_t *arg) -{ - if (!context->system_ops || !context->system_ops->get_info) - return 1; - - return context->system_ops->get_info(item, arg); -} +/* + * It's either a buflist (.is_direct = 0) or + * a direct pointer + len (.is_direct = 1) + */ const lws_system_ops_t * lws_system_get_ops(struct lws_context *context) @@ -44,102 +35,109 @@ lws_system_get_ops(struct lws_context *context) return context->system_ops; } -#if defined(LWS_WITH_NETWORK) -int -lws_system_auth_default_cb(struct lws_context *context, int idx, size_t ofs, - uint8_t *buf, size_t *plen, lws_system_auth_op_t op) -{ - int n; - if (idx >= (int)LWS_ARRAY_SIZE(context->auth_token)) +void +lws_system_blob_direct_set(lws_system_blob_t *b, const uint8_t *ptr, size_t len) +{ + b->is_direct = 1; + b->u.direct.ptr = ptr; + b->u.direct.len = len; +} + +void +lws_system_blob_heap_empty(lws_system_blob_t *b) +{ + b->is_direct = 0; + lws_buflist_destroy_all_segments(&b->u.bl); +} + +int +lws_system_blob_heap_append(lws_system_blob_t *b, const uint8_t *buf, size_t len) +{ + assert(!b->is_direct); + + if (lws_buflist_append_segment(&b->u.bl, buf, len) < 0) return -1; - switch (op) { - case LWSSYS_AUTH_GET: - if (!context->auth_token[idx]) { - lwsl_notice("%s: token %d not set\n", __func__, idx); - return -1; - } + return 0; +} - if (!buf) /* we just need to tell him that it exists */ - return -2; +size_t +lws_system_blob_get_size(lws_system_blob_t *b) +{ + if (b->is_direct) + return b->u.direct.len; - n = lws_buflist_linear_copy(&context->auth_token[idx], ofs, buf, - *plen); - if (n < 0) - return -2; - - *plen = (size_t)n; - - return 0; - - case LWSSYS_AUTH_TOTAL_LENGTH: - *plen = lws_buflist_total_len(&context->auth_token[idx]); - return 0; - - case LWSSYS_AUTH_APPEND: - if (lws_buflist_append_segment(&context->auth_token[idx], buf, - *plen) < 0) - return -1; - - return 0; - - case LWSSYS_AUTH_FREE: - lws_buflist_destroy_all_segments(&context->auth_token[idx]); - return 0; - - default: - break; - } - - return -1; + return lws_buflist_total_len(&b->u.bl); } int -lws_system_get_auth(struct lws_context *context, int idx, size_t ofs, - uint8_t *buf, size_t buflen, int flags) +lws_system_blob_get(lws_system_blob_t *b, uint8_t *buf, size_t *len, size_t ofs) { - size_t bl = buflen; - uint8_t *p, b; int n; - if (!context->system_ops || !context->system_ops->auth) - n = lws_system_auth_default_cb(context, idx, ofs, buf, &buflen, - LWSSYS_AUTH_GET); - else - n = context->system_ops->auth(context, idx, ofs, buf, &buflen, - LWSSYS_AUTH_GET); + if (b->is_direct) { - if (n < 0) { - if (buf) - lwsl_err("%s: auth %d get failed %d, space %d\n", - __func__, idx, n, (int)bl); - return n; - } + assert(b->u.direct.ptr); - if (buf && (flags & LWSSYSGAUTH_HEX)) { - if (bl < (buflen * 2) + 1) { - lwsl_err("%s: auth in hex oversize %d\n", __func__, - (int)bl); - - return -1; + if (ofs >= b->u.direct.len) { + *len = 0; + return 1; } - /* convert to ascii hex inplace, backwards */ + if (*len > b->u.direct.len - ofs) + *len = b->u.direct.len - ofs; - p = buf + (buflen * 2); - *p = '\0'; /* terminating NUL */ + memcpy(buf, b->u.direct.ptr + ofs, *len); - for (n = (int)buflen - 1; n >= 0; n--) { - p -= 2; - b = buf[n]; - p[0] = hex[(b >> 4) & 0xf]; - p[1] = hex[b & 0xf]; - } - - buflen = (buflen * 2); + return 0; } - return (int)buflen; + n = lws_buflist_linear_copy(&b->u.bl, ofs, buf, *len); + if (n < 0) + return -2; + + *len = n; + + return 0; } -#endif + +int +lws_system_blob_get_single_ptr(lws_system_blob_t *b, const uint8_t **ptr) +{ + if (b->is_direct) { + *ptr = b->u.direct.ptr; + return 0; + } + + if (!b->u.bl) + return -1; + + if (b->u.bl->next) + return -1; /* multipart buflist, no single pointer to it all */ + + *ptr = (const uint8_t *)&b->u.bl[1]; + + return 0; +} + +void +lws_system_blob_destroy(lws_system_blob_t *b) +{ + if (!b) + return; + if (!b->is_direct) + lws_buflist_destroy_all_segments(&b->u.bl); +} + +lws_system_blob_t * +lws_system_get_blob(struct lws_context *context, lws_system_blob_item_t type, + int idx) +{ + if (idx < 0 || + idx >= (int)LWS_ARRAY_SIZE(context->system_blobs)) + return NULL; + + return &context->system_blobs[type + idx]; +} +