mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
lws_system generic blobs
Remove the auth lws_system stuff and redo it using generic blobs with separate namespaces. Support pointing to already-in-memory blobs without using heap as well as multi-fragment appened blobs eg, parsed out of JSON chunk by chunk and chained in heap. Support auth the new way, along with client cert + key in DER namespaces.
This commit is contained in:
parent
fdbfafd1b5
commit
c1a3defb88
4 changed files with 158 additions and 178 deletions
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -24,19 +24,10 @@
|
|||
|
||||
#include <private-lib-core.h>
|
||||
|
||||
#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];
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue