Update Files

This commit is contained in:
2025-01-22 17:22:38 +01:00
parent 89b9349629
commit 4c5e729485
5132 changed files with 1195369 additions and 0 deletions

View File

@ -0,0 +1,279 @@
/*
* 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 sock-adopt Socket adoption helpers
* ##Socket adoption helpers
*
* When integrating with an external app with its own event loop, these can
* be used to accept connections from someone else's listening socket.
*
* When using lws own event loop, these are not needed.
*/
///@{
/**
* lws_adopt_socket() - adopt foreign socket as if listen socket accepted it
* for the default vhost of context.
*
* \param context: lws context
* \param accept_fd: fd of already-accepted socket to adopt
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd);
/**
* lws_adopt_socket_vhost() - adopt foreign socket as if listen socket accepted
* it for vhost
*
* \param vh: lws vhost
* \param accept_fd: fd of already-accepted socket to adopt
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
typedef enum {
LWS_ADOPT_RAW_FILE_DESC = 0, /* convenience constant */
LWS_ADOPT_HTTP = 1, /* flag: absent implies RAW */
LWS_ADOPT_SOCKET = 2, /* flag: absent implies file */
LWS_ADOPT_ALLOW_SSL = 4, /* flag: use tls */
LWS_ADOPT_FLAG_UDP = 16, /* flag: socket is UDP */
LWS_ADOPT_FLAG_RAW_PROXY = 32, /* flag: raw proxy */
LWS_ADOPT_RAW_SOCKET_UDP = LWS_ADOPT_SOCKET | LWS_ADOPT_FLAG_UDP,
} lws_adoption_type;
typedef union {
lws_sockfd_type sockfd;
lws_filefd_type filefd;
} lws_sock_file_fd_type;
#if defined(LWS_ESP_PLATFORM)
#include <lwip/sockets.h>
#endif
typedef union {
#if defined(LWS_WITH_IPV6)
struct sockaddr_in6 sa6;
#else
#if defined(LWS_ESP_PLATFORM)
uint8_t _pad_sa6[28];
#endif
#endif
struct sockaddr_in sa4;
} lws_sockaddr46;
#define sa46_sockaddr(_sa46) ((struct sockaddr *)(_sa46))
#if defined(LWS_WITH_IPV6)
#define sa46_socklen(_sa46) (socklen_t)((_sa46)->sa4.sin_family == AF_INET ? \
sizeof(struct sockaddr_in) : \
sizeof(struct sockaddr_in6))
#define sa46_sockport(_sa46, _sp) { if ((_sa46)->sa4.sin_family == AF_INET) \
(_sa46)->sa4.sin_port = (_sp); else \
(_sa46)->sa6.sin6_port = (_sp); }
#define sa46_address(_sa46) ((uint8_t *)((_sa46)->sa4.sin_family == AF_INET ? \
&_sa46->sa4.sin_addr : &_sa46->sa6.sin6_addr ))
#else
#define sa46_socklen(_sa46) (socklen_t)sizeof(struct sockaddr_in)
#define sa46_sockport(_sa46, _sp) (_sa46)->sa4.sin_port = (_sp)
#define sa46_address(_sa46) (uint8_t *)&_sa46->sa4.sin_addr
#endif
#define sa46_address_len(_sa46) ((_sa46)->sa4.sin_family == AF_INET ? 4 : 16)
#if defined(LWS_WITH_UDP)
struct lws_udp {
lws_sockaddr46 sa46;
lws_sockaddr46 sa46_pending;
uint8_t connected:1;
};
#endif
/**
* lws_adopt_descriptor_vhost() - adopt foreign socket or file descriptor
* if socket descriptor, should already have been accepted from listen socket
*
* \param vh: lws vhost
* \param type: OR-ed combinations of lws_adoption_type flags
* \param fd: union with either .sockfd or .filefd set
* \param vh_prot_name: NULL or vh protocol name to bind raw connection to
* \param parent: NULL or struct lws to attach new_wsi to as a child
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* If LWS_ADOPT_SOCKET is set, LWS adopts the socket in http serving mode, it's
* ready to accept an upgrade to ws or just serve http.
*
* parent may be NULL, if given it should be an existing wsi that will become the
* parent of the new wsi created by this call.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
lws_sock_file_fd_type fd, const char *vh_prot_name,
struct lws *parent);
typedef struct lws_adopt_desc {
struct lws_vhost *vh; /**< vhost the wsi should belong to */
lws_adoption_type type; /**< OR-ed combinations of
* lws_adoption_type flags */
lws_sock_file_fd_type fd; /**< union with either .sockfd
* or .filefd set */
const char *vh_prot_name; /**< NULL or vh protocol name to
* bind raw connection to */
struct lws *parent; /**< NULL or struct lws to
* attach new_wsi to as a child */
void *opaque; /**< opaque pointer to set on
*created wsi */
const char *fi_wsi_name; /**< NULL, or Fault Injection
* inheritence filter for
* wsi=string/ context faults */
} lws_adopt_desc_t;
/**
* lws_adopt_descriptor_vhost_via_info() - adopt foreign socket or file descriptor
* if socket descriptor, should already have been accepted from listen socket
*
* \param info: the struct containing the parameters
*
* - vh: lws vhost
* - type: OR-ed combinations of lws_adoption_type flags
* - fd: union with either .sockfd or .filefd set
* - vh_prot_name: NULL or vh protocol name to bind raw connection to
* - parent: NULL or struct lws to attach new_wsi to as a child
* - opaque: opaque pointer to set on created wsi
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* If LWS_ADOPT_SOCKET is set, LWS adopts the socket in http serving mode, it's
* ready to accept an upgrade to ws or just serve http.
*
* parent may be NULL, if given it should be an existing wsi that will become the
* parent of the new wsi created by this call.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info);
/**
* lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
* for the default vhost of context.
* \param context: lws context
* \param accept_fd: fd of already-accepted socket to adopt
* \param readbuf: NULL or pointer to data that must be drained before reading from
* accept_fd
* \param len: The length of the data held at \p readbuf
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*
* If your external code did not already read from the socket, you can use
* lws_adopt_socket() instead.
*
* This api is guaranteed to use the data at \p readbuf first, before reading from
* the socket.
*
* \p readbuf is limited to the size of the ah rx buf, currently 2048 bytes.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
const char *readbuf, size_t len);
/**
* lws_adopt_socket_vhost_readbuf() - adopt foreign socket and first rx as if listen socket
* accepted it for vhost.
* \param vhost: lws vhost
* \param accept_fd: fd of already-accepted socket to adopt
* \param readbuf: NULL or pointer to data that must be drained before reading from accept_fd
* \param len: The length of the data held at \p readbuf
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
*
* LWS adopts the socket in http serving mode, it's ready to accept an upgrade
* to ws or just serve http.
*
* If your external code did not already read from the socket, you can use
* lws_adopt_socket() instead.
*
* This api is guaranteed to use the data at \p readbuf first, before reading from
* the socket.
*
* \p readbuf is limited to the size of the ah rx buf, currently 2048 bytes.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
lws_sockfd_type accept_fd, const char *readbuf,
size_t len);
#define LWS_CAUDP_BIND (1 << 0)
#define LWS_CAUDP_BROADCAST (1 << 1)
#define LWS_CAUDP_PF_PACKET (1 << 2)
#if defined(LWS_WITH_UDP)
/**
* lws_create_adopt_udp() - create, bind and adopt a UDP socket
*
* \param vhost: lws vhost
* \param ads: NULL or address to do dns lookup on
* \param port: UDP port to bind to, -1 means unbound
* \param flags: 0 or LWS_CAUDP_NO_BIND
* \param protocol_name: Name of protocol on vhost to bind wsi to
* \param ifname: NULL, for network interface name to bind socket to
* \param parent_wsi: NULL or parent wsi new wsi will be a child of
* \param opaque: set created wsi opaque ptr to this
* \param retry_policy: NULL for vhost default policy else wsi specific policy
* \param fi_wsi_name: NULL, or string to inherit Fault Injection rules in
* form "wsi=string/rule". "wsi/rule" faults will be
* automatically applied as well. It's done at creation
* time so the rules can, eg, inject faults related to
* creation.
*
* Either returns new wsi bound to accept_fd, or closes accept_fd and
* returns NULL, having cleaned up any new wsi pieces.
* */
LWS_VISIBLE LWS_EXTERN struct lws *
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
int flags, const char *protocol_name, const char *ifname,
struct lws *parent_wsi, void *opaque,
const lws_retry_bo_t *retry_policy, const char *fi_wsi_name);
#endif
///@}

View File

@ -0,0 +1,130 @@
/*
* 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.
*/
#if defined(LWS_WITH_UDP) && defined(LWS_WITH_NETWORK)
typedef enum dns_query_type {
LWS_ADNS_RECORD_A = 0x01,
LWS_ADNS_RECORD_CNAME = 0x05,
LWS_ADNS_RECORD_MX = 0x0f,
LWS_ADNS_RECORD_AAAA = 0x1c,
} adns_query_type_t;
typedef enum {
LADNS_RET_FAILED_WSI_CLOSED = -4,
LADNS_RET_NXDOMAIN = -3,
LADNS_RET_TIMEDOUT = -2,
LADNS_RET_FAILED = -1,
LADNS_RET_FOUND,
LADNS_RET_CONTINUING
} lws_async_dns_retcode_t;
#define LWS_ADNS_SYNTHETIC 0x10000 /* don't send, synthetic response will
* be injected for testing */
struct addrinfo;
typedef struct lws * (*lws_async_dns_cb_t)(struct lws *wsi, const char *ads,
const struct addrinfo *result, int n, void *opaque);
struct lws_adns_q;
struct lws_async_dns;
/**
* lws_async_dns_query() - perform a dns lookup using async dns
*
* \param context: the lws_context
* \param tsi: thread service index (usually 0)
* \param name: DNS name to look up
* \param qtype: type of query (A, AAAA etc)
* \param cb: query completion callback
* \param wsi: wsi if the query is related to one
* \param pq: NULL, or pointer to lws_adns_q query (used for testing)
*
* Starts an asynchronous DNS lookup, on completion the \p cb callback will
* be called.
*
* The reference count on the cached object is incremented for every callback
* that was called with the cached addrinfo results.
*
* The cached object can't be evicted until the reference count reaches zero...
* use lws_async_dns_freeaddrinfo() to indicate you're finsihed with the
* results for each callback that happened with them.
*/
LWS_VISIBLE LWS_EXTERN lws_async_dns_retcode_t
lws_async_dns_query(struct lws_context *context, int tsi, const char *name,
adns_query_type_t qtype, lws_async_dns_cb_t cb,
struct lws *wsi, void *opaque, struct lws_adns_q **pq);
/**
* lws_async_dns_freeaddrinfo() - decrement refcount on cached addrinfo results
*
* \param pai: a pointert to a pointer to first addrinfo returned as result in the callback
*
* Decrements the cache object's reference count. When it reaches zero, the
* cached object may be reaped subject to LRU rules.
*
* The pointer to the first addrinfo give in the argument is set to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_async_dns_freeaddrinfo(const struct addrinfo **ai);
/**
* lws_async_dns_server_add() - add a DNS server to the lws async DNS list
*
* \param cx: the lws_context
* \param sa46: the ipv4 or ipv6 DNS server address to add
*
* Adds the given DNS server to the lws list of async DNS servers to query.
* If the address is already listed, its refcount is increased, otherwise a new
* entry is made.
*/
LWS_VISIBLE LWS_EXTERN int
lws_async_dns_server_add(struct lws_context *cx, const lws_sockaddr46 *sa46);
/**
* lws_async_dns_server_remove() - remove a DNS server from the lws async DNS list
*
* \param cx: the lws_context
* \param sa46: the ipv4 or ipv6 DNS server address to add
*
* Removes the given DNS server from the lws list of async DNS servers to query.
* If the address does not correspond to an existing entry, no action is taken.
* If it does, the refcount on it is decremented, and if it reaches zero, the
* entry is detached from the list and destroyed.
*/
LWS_VISIBLE LWS_EXTERN void
lws_async_dns_server_remove(struct lws_context *cx, const lws_sockaddr46 *sa46);
/* only needed for testing */
LWS_VISIBLE LWS_EXTERN uint16_t
lws_adns_get_tid(struct lws_adns_q *q);
LWS_VISIBLE LWS_EXTERN struct lws_async_dns *
lws_adns_get_async_dns(struct lws_adns_q *q);
LWS_VISIBLE LWS_EXTERN void
lws_adns_parse_udp(struct lws_async_dns *dns, const uint8_t *pkt, size_t len);
#endif

View File

@ -0,0 +1,280 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2022 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 lws_backtrace generic and compressed backtrace acquisition
* ##Backtrace apis
* \ingroup lwsbacktrace
*
* lws_backtrace
*
* These apis abstract acquisition and optionally compressed on binary back-
* traces, effectively build-specific signatures for where in the code you are
* and how you got there.
*/
//@{
typedef struct {
uintptr_t st[32];
uintptr_t asize;
uint8_t sp;
uint8_t pre;
uint8_t post;
} lws_backtrace_info_t;
typedef struct {
uint8_t *comp;
size_t pos;
size_t len;
} lws_backtrace_comp_t;
/*
* lws_backtrace() - init and fiull a backtrace struct
*
* \param si: the backtrace struct to populate
* \param pre: the number of call levels to snip from the top
* \param post: the number of call levels to snip from the bottom
*
* This describes the call stack into \p si. \p si doesn't need preparing
* before the call. \p pre levels of the call stack at the top will be snipped,
* this will usually want to be 1 or 2 to conceal the helpers that are making
* the call stack, such as lws_backtrace itself.
*
* \p post levels of the call stack at the bottom will be snipped, this is to
* conceal loaders or other machinery that was used to start your application,
* otherwise those entries will bloat all call stacks results on that platform.
*
* Returns 0 for success.
*/
LWS_VISIBLE LWS_EXTERN int
lws_backtrace(lws_backtrace_info_t *si, uint8_t pre, uint8_t post);
/*
* lws_backtrace_compression_stream_init() - init and fiull a backtrace struct
*
* \param c: the backtrace compression struct
* \param comp: the buffer to take the compressed bytes
* \param comp_len: the number of bytes available at \p comp
*
* This initializes the caller's lws_backtrace_comp_t. Because it's expected
* the caller will want to put his own compressed data after the compressed
* backtrace, he is responsible for the compression context.
*/
LWS_VISIBLE LWS_EXTERN void
lws_backtrace_compression_stream_init(lws_backtrace_comp_t *c,
uint8_t *comp, size_t comp_len);
/*
* lws_backtrace_compression_stream() - add bitfields to compression stream
*
* \param c: the backtrace compression context struct
* \param v: the bitfield to add to the stream
* \param bits: the number of bits of v to add
*
* This inserts bits from the LSB end of v to the compression stream.
*
* This is used by the backtrace compression, user code can use this to add
* its own bitfields into the compression stream after the compressed backtrace.
*
* User data should be added after, so that the backtrace can be processed even
* if the additional data is not understood by the processing script.
*
* Returns 0 for success or nonzero if ran out of compression output buffer.
*/
LWS_VISIBLE LWS_EXTERN int
lws_backtrace_compression_stream(lws_backtrace_comp_t *c, uintptr_t v,
unsigned int bits);
/*
* lws_backtrace_compression_destream() - add bitfields to compression stream
*
* \param c: the backtrace compression context struct
* \param _v: pointer to take the bitfield result
* \param bits: the number of bits to bring out into _v
*
* This reads the compression stream and creates a bitfield from it in \p _v.
*
* Returns 0 for success (with \p _v set to the value), or nonzero if ran out
* of compression output buffer.
*/
LWS_VISIBLE LWS_EXTERN int
lws_backtrace_compression_destream(lws_backtrace_comp_t *c, uintptr_t *_v,
unsigned int bits);
/*
* lws_backtrace_compress_backtrace() - compress backtrace si into c
*
* \param si: the backtrace struct to compress
* \param c: the backtrace compression context struct
*
* This compresses backtrace information acquired in \p si into the compression
* context \p c. It compresses first the call stack length and then each IP
* address in turn.
*
* Returns 0 for success.
*/
LWS_VISIBLE LWS_EXTERN int
lws_backtrace_compress_backtrace(lws_backtrace_info_t *si,
lws_backtrace_comp_t *c);
//@}
/** \defgroup lws_alloc_metadata helpers for allocator instrumentation
* ##Alloc Metadata APIs
* \ingroup lwsallocmetadata
*
* lws_alloc_metadata
*
* These helpers let you rapidly instrument your libc or platform memory
* allocator so that you can later dump details, including a backtrace of where
* the allocation was made, for every live heap allocation.
*
* You would use it at peak memory usage, to audit who is using what at that
* time.
*
* Effective compression is used to keep the metadata overhead to ~48 bytes
* per active allocation on 32-bit systems.
*/
//@{
/**
* lws_alloc_metadata_gen() - generate metadata blob (with compressed backtrace)
*
* \param size: the allocation size
* \param comp: buffer for compressed backtrace
* \param comp_len: number of bytes available in the compressed backtrace
* \param adj: takes the count of additional bytes needed for metadata behind
* the allocation we tell the user about
* \param cl: takes the count of bytes used in comp
*
* This helper creates the compressed part of the alloc metadata blob and
* calculates the total overallocation that is needed in \p adj.
*
* This doesn't need any locking.
*
* If \p comp_len is too small for the whole result, or it was not possible to
* get the backtrace information, the compressed part is set to empty (total
* length 2 to carry the 00 00 length).
*
* 6 or 10 (64-bit) bytes per backtrace IP allowed (currently 16) should always
* be enough, typically the compression reduces this very significantly.
*/
LWS_VISIBLE LWS_EXTERN void
lws_alloc_metadata_gen(size_t size, uint8_t *comp, size_t comp_len, size_t *adj,
size_t *cl);
/**
* _lws_alloc_metadata_adjust() - helper to inject metadata and list as active
*
* \param active: the allocation owner
* \param v: Original, true allocation pointer, adjusted on exit
* \param adj: Total size of metadata overallocation
* \param comp: The compressed metadata
* \param cl: takes the count of bytes used in comp
*
* THIS MUST BE LOCKED BY THE CALLER IF YOUR ALLOCATOR MAY BE CALLED BY OTHER
* THREADS. You can call it from an existing mutex or similar -protected
* critical section in your allocator if there is one already, or you will have
* to protect the caller of it with your own mutex so it cannot reenter.
*
* This is a helper that adjusts the allocation past the metadata part so the
* caller of the allocator using this sees what he asked for. The deallocator
* must call _lws_alloc_metadata_trim() to balance this before actual
* deallocation.
*/
LWS_VISIBLE LWS_EXTERN void
_lws_alloc_metadata_adjust(lws_dll2_owner_t *active, void **v, size_t adj, uint8_t *comp, unsigned int cl);
/**
* _lws_alloc_metadata_trim() - helper to trim metadata and remove from active
*
* \param ptr: Adjusted allocation pointer on entry, true allocation ptr on exit
* \param comp: NULL, or set on exit to point to start of compressed area
* \param complen: NULL, or set on exit to length of compressed area in bytes
*
* THIS MUST BE LOCKED BY THE CALLER IF YOUR DEALLOCATOR MAY BE CALLED BY OTHER
* THREADS. You can call it from an existing mutex or similar -protected
* critical section in your deallocator if there is one already, or you will
* have to protect that caller of it with your own mutex so it cannot reenter.
*/
LWS_VISIBLE LWS_EXTERN void
_lws_alloc_metadata_trim(void **ptr, uint8_t **comp, uint16_t *complen);
/**
* lws_alloc_metadata_parse() - parse compressed metadata into struct
*
* \param si: Struct to take the backtrace results from decompression
* \param adjusted_alloc: pointer to adjusted, user allocation start
*
* This api parses and decompresses the blob behind the \p adjusted_alloc
* address into \p si.
*
* Returns 0 for success.
*/
LWS_VISIBLE LWS_EXTERN int
lws_alloc_metadata_parse(lws_backtrace_info_t *si, const uint8_t *adjusted_alloc);
/**
* lws_alloc_metadata_dump_stdout() - helper to print base64 blob on stdout
*
* \param d: the current list item
* \param user: the optional arg given to the dump api (ignored)
*
* Generic helper that can be given to _lws_alloc_metadata_dump() as the
* callback that will emit a standardized base64 blob for the alloc metadata
*/
LWS_VISIBLE LWS_EXTERN int
lws_alloc_metadata_dump_stdout(struct lws_dll2 *d, void *user);
/**
* lws_alloc_metadata_dump_stdout() - dump all live allocs in instrumented heap
*
* \param active: the owner of the active allocation list for this heap
* \param cb: the callback to receive information
* \param arg: optional arg devivered to the callback
*
* THIS MUST BE LOCKED BY THE CALLER IF YOUR ALLOCATOR MAY BE CALLED BY OTHER
* THREADS. You can call it from an existing mutex or similar -protected
* critical section in your allocator if there is one already, or you will have
* to protect the caller of it with your own mutex so it cannot reenter.
*
* Iterates through the list of instrumented allocations calling the given
* callback for each one.
*/
LWS_VISIBLE LWS_EXTERN void
_lws_alloc_metadata_dump(lws_dll2_owner_t *active, lws_dll2_foreach_cb_t cb,
void *arg);
#if defined(LWS_WITH_ALLOC_METADATA_LWS)
/*
* Wrapper for _lws_alloc_metadata_dump() that uses the list owner that tracks
*
*/
LWS_VISIBLE LWS_EXTERN void
_lws_alloc_metadata_dump_lws(lws_dll2_foreach_cb_t cb, void *arg);
#else
#define _lws_alloc_metadata_dump_lws(_a, _b)
#endif
//@}

View File

@ -0,0 +1,66 @@
/*
* I2C - bitbanged generic gpio implementation
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for gpio, a real implementation provides
* functions for the ops that use the underlying OS gpio arrangements.
*/
typedef struct lws_bb_i2c {
lws_i2c_ops_t bb_ops; /* init to lws_bb_i2c_ops */
/* implementation-specific members */
_lws_plat_gpio_t scl;
_lws_plat_gpio_t sda;
const lws_gpio_ops_t *gpio;
void (*delay)(void);
} lws_bb_i2c_t;
#define lws_bb_i2c_ops \
{ \
.init = lws_bb_i2c_init, \
.start = lws_bb_i2c_start, \
.stop = lws_bb_i2c_stop, \
.write = lws_bb_i2c_write, \
.read = lws_bb_i2c_read, \
.set_ack = lws_bb_i2c_set_ack, \
}
int
lws_bb_i2c_init(const lws_i2c_ops_t *octx);
int
lws_bb_i2c_start(const lws_i2c_ops_t *octx);
void
lws_bb_i2c_stop(const lws_i2c_ops_t *octx);
int
lws_bb_i2c_write(const lws_i2c_ops_t *octx, uint8_t data);
int
lws_bb_i2c_read(const lws_i2c_ops_t *octx);
void
lws_bb_i2c_set_ack(const lws_i2c_ops_t *octx, int ack);

View File

@ -0,0 +1,64 @@
/*
* I2C - bitbanged generic gpio implementation
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for gpio, a real implementation provides
* functions for the ops that use the underlying OS gpio arrangements.
*/
#define LWSBBSPI_FLAG_USE_NCMD3 (1 << 7)
#define LWSBBSPI_FLAG_USE_NCMD2 (1 << 6)
#define LWSBBSPI_FLAG_USE_NCMD1 (1 << 5)
#define LWSBBSPI_FLAG_USE_NCMD0 (1 << 4)
#define LWSBBSPI_FLAG_USE_NCS3 (1 << 3)
#define LWSBBSPI_FLAG_USE_NCS2 (1 << 2)
#define LWSBBSPI_FLAG_USE_NCS1 (1 << 1)
#define LWSBBSPI_FLAG_USE_NCS0 (1 << 0)
#define LWS_SPI_BB_MAX_CH 4
typedef struct lws_bb_spi {
lws_spi_ops_t bb_ops; /* init to lws_bb_spi_ops */
/* implementation-specific members */
const lws_gpio_ops_t *gpio;
_lws_plat_gpio_t clk;
_lws_plat_gpio_t ncs[LWS_SPI_BB_MAX_CH];
_lws_plat_gpio_t ncmd[LWS_SPI_BB_MAX_CH];
_lws_plat_gpio_t mosi;
_lws_plat_gpio_t miso;
uint8_t unit;
uint8_t flags;
} lws_bb_spi_t;
#define lws_bb_spi_ops \
.init = lws_bb_spi_init, \
.queue = lws_bb_spi_queue
int
lws_bb_spi_init(const lws_spi_ops_t *octx);
int
lws_bb_spi_queue(const lws_spi_ops_t *octx, const lws_spi_desc_t *desc);

View File

@ -0,0 +1,120 @@
/*
* Generic button ops
*
* Copyright (C) 2019 - 2020 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.
*
* Leverages the lws generic gpio pieces to bind gpio buttons to smd events
*/
#if !defined(__LWS_BUTTON_H__)
#define __LWS_BUTTON_H__
typedef uint16_t lws_button_idx_t;
/* actual minimum may be 1 x RTOS tick depending on platform */
#define LWS_BUTTON_MON_TIMER_MS 5
typedef void (*lws_button_cb_t)(void *opaque, lws_button_idx_t idx, int state);
/* These are specified in ms but the granularity is LWS_BUTTON_MON_TIMER_MS,
* which may have been rounded up to an RTOS tick depending on platform */
enum {
LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK = (1 << 0)
};
typedef struct lws_button_regime {
uint16_t ms_min_down;
uint16_t ms_min_down_longpress;
uint16_t ms_up_settle;
uint16_t ms_doubleclick_grace;
uint16_t ms_repeat_down;
uint8_t flags;
/**< when double-click classification is enabled, clicks are delayed
* by ms_min_down + ms_doubleclick_grace to wait and see if it will
* become a double-click. Set LWSBTNRGMFLAG_CLASSIFY_DOUBLECLICK to
* enable it or leave that bit at 0 to get faster single-click
* classification.
*/
} lws_button_regime_t;
/*
* This is the const part of the button controller, describing the static
* bindings to gpio, and lws_smd event name information
*/
typedef struct lws_button_map {
_lws_plat_gpio_t gpio;
const char *smd_interaction_name;
const lws_button_regime_t *regime;
/**< a default regime is applied if this is left NULL */
} lws_button_map_t;
typedef struct lws_button_controller {
const char *smd_bc_name;
const lws_gpio_ops_t *gpio_ops;
const lws_button_map_t *button_map;
lws_button_idx_t active_state_bitmap;
uint8_t count_buttons;
} lws_button_controller_t;
struct lws_button_state; /* opaque */
/**
* lws_button_controller_create() - instantiate a button controller
*
* \param ctx: the lws_context
* \param controller: the static controller definition
*
* Instantiates a button controller from a static definition of the buttons
* and their smd names, and active levels, and binds it to a gpio implementation
*/
LWS_VISIBLE LWS_EXTERN struct lws_button_state *
lws_button_controller_create(struct lws_context *ctx,
const lws_button_controller_t *controller);
/**
* lws_button_controller_destroy() - destroys a button controller
*
* \param bcs: button controller state previously created
*
* Disables all buttons and then destroys and frees a previously created
* button controller.
*/
LWS_VISIBLE LWS_EXTERN void
lws_button_controller_destroy(struct lws_button_state *bcs);
LWS_VISIBLE LWS_EXTERN lws_button_idx_t
lws_button_get_bit(struct lws_button_state *bcs, const char *name);
/*
* lws_button_enable() - enable and disable buttons
*/
LWS_VISIBLE LWS_EXTERN void
lws_button_enable(struct lws_button_state *bcs,
lws_button_idx_t _reset, lws_button_idx_t _set);
#endif

View File

@ -0,0 +1,348 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 lws_cache_ttl Cache supporting expiry
* ##Cache supporting expiry
*
* These apis let you quickly and reliably implement caches of named objects,
* that have a "destroy-by date" and cache limits that will be observed.
*
* You can instantiate as many caches as you need. The first one must be an
* L1 / heap cache type, it can have parents and grandparents of other types
* which are accessible why writing / looking up and getting from the L1 cache.
* The outer "cache" layer may persistently store items to a backing store.
*
* Allocated object memory is entirely for the use of user code, up to the
* requested size.
*
* The key name for the listed objects may be any string chosen by the user,
* there is no special length limit as it is also allocated.
*
* Both expiry and LRU orderings are kept so it is easy to find out usage
* ordering and when the next object that will expire.
*
* Cached objects may be destroyed any time you go around the event loop, when
* you allocate new objects (to keep the whole cache under the specified limit),
* or when their expiry time arrives. So you shouldn't keep copies of pointers
* to cached objects after returning to the event loop.
*/
///@{
struct lws_cache_ttl_lru;
/**
* lws_cache_write_through() - add a new cache item object in all layers
*
* \param cache: the existing cache to allocate the object in
* \param specific_key: a key string that identifies the item in the cache
* \param source: optional payload for the cached item, NULL means caller will
* write the payload
* \param size: the size of the object to allocate
* \param expiry: the usec time that the object will autodestroy
* \param ppay: NULL, or a pointer to a void * to be set to the L1 payload
*
* If an item with the key already exists, it is destroyed before allocating a
* new one.
*
* Returns 0 if successful. The written entry will be scheduled to be auto-
* destroyed when \p expiry occurs.
*
* Adding or removing cache items may cause invalidation of cached queries.
*/
LWS_VISIBLE LWS_EXTERN int /* only valid until return to event loop */
lws_cache_write_through(struct lws_cache_ttl_lru *cache,
const char *specific_key, const uint8_t *source,
size_t size, lws_usec_t expiry, void **ppay);
typedef struct lws_cache_match {
lws_dll2_t list;
lws_usec_t expiry;
/* earliest expiry amongst results */
size_t payload_size;
/**< the payload is not attached here. This is a hint about what
* (*get)() will return for this tag name.
*/
size_t tag_size;
/* tag name + NUL is overcommitted */
} lws_cache_match_t;
/**
* lws_cache_heap_lookup() - get a list of matching items
*
* \param cache: the cache to search for the key
* \param wildcard_key: the item key string, may contain wildcards
* \param pdata: pointer to pointer to be set to the serialized result list
* \param psize: pointer to size_t to receive length of serialized result list
*
* This finds all unique items in the final cache that match search_key, which
* may contain wildcards. It does not return the payloads for matching items,
* just a list of specific tags in the that match.
*
* If successful, results are provided in a serialized list format, in no
* particular order, each result has the following fields
*
* - BE32: payload size in bytes (payload itself is not included)
* - BE32: specific tag name length in bytes
* - chars: tag name with terminating NUL
*
* These serialized results are themselves cached in L1 cache (only) and the
* result pointers are set pointing into that. If the results are still in L1
* cache next time this api is called, the results will be returned directly
* from that without repeating the expensive lookup on the backup store. That
* is why the results are provided in serialized form.
*
* The cached results list expiry is set to the earliest expiry of any listed
* item. Additionally any cached results are invalidated on addition or
* deletion (update is done as addition + deletion) of any item that would
* match the results' original wildcard_key. For the typical case new items
* are rare compared to lookups, this is efficient.
*
* Lookup matching does not itself affect LRU or cache status of the result
* itsems. Typically user code will get the lookup results, and then perform
* get operations on each item in its desired order, that will bring the items
* to the head of the LRU list and occupy L1 cache.
*
* Returns 0 if proceeded alright, or nonzero if error. If there was an error,
* any partial results set has been deallocated cleanly before returning.
*/
LWS_VISIBLE LWS_EXTERN int
lws_cache_lookup(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
const void **pdata, size_t *psize);
/**
* lws_cache_item_get() - bring a specific item into L1 and get payload info
*
* \param cache: the cache to search for the key
* \param specific_key: the key string of the item to get
* \param pdata: pointer to a void * to be set to the payload in L1 cache
* \param psize: pointer to a size_t to be set to the payload size
*
* If the cache still has an item matching the key string, it will be destroyed.
*
* Adding or removing cache items may cause invalidation of cached queries.
*
* Notice the cache payload is a blob of the given size. If you are storing
* strings, there is no NUL termination unless you stored them with it.
*
* Returns 0 if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_cache_item_get(struct lws_cache_ttl_lru *cache, const char *specific_key,
const void **pdata, size_t *psize);
/**
* lws_cache_item_remove() - remove item from all cache levels
*
* \param cache: the cache to search for the key
* \param wildcard_key: the item key string
*
* Removes any copy of any item matching the \p wildcard_key from any cache
* level in one step.
*
* Adding or removing cache items may cause invalidation of cached queries
* that could refer to the removed item.
*/
LWS_VISIBLE LWS_EXTERN int
lws_cache_item_remove(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
/**
* lws_cache_footprint() - query the amount of storage used by the cache layer
*
* \param cache: cache to query
*
* Returns number of payload bytes stored in cache currently
*/
LWS_VISIBLE LWS_EXTERN uint64_t
lws_cache_footprint(struct lws_cache_ttl_lru *cache);
/**
* lws_cache_debug_dump() - if built in debug mode dump cache contents to log
*
* \param cache: cache to dump
*
* If lws was built in debug mode, dump cache to log, otherwise a NOP.
*/
LWS_VISIBLE LWS_EXTERN void
lws_cache_debug_dump(struct lws_cache_ttl_lru *cache);
typedef struct lws_cache_results {
const uint8_t *ptr; /* set before using walk api */
size_t size; /* set before using walk api */
size_t payload_len;
size_t tag_len;
const uint8_t *tag;
} lws_cache_results_t;
/**
* lws_cache_results_walk() - parse next result
*
* \param walk_ctx: the context of the results blob to walk
*
* Caller must initialize \p walk_ctx.ptr and \p walk_ctx.size before calling.
* These are set to the results returned from a _lookup api call.
*
* The call returns 0 if the struct elements have been set to a result, or 1
* if there where no more results in the blob to walk.
*
* If successful, after the call \p payload_len is set to the length of the
* payload related to this result key (the payload itself is not present),
* \p tag_len is set to the length of the result key name, and \p tag is set
* to the result tag name, with a terminating NUL.
*/
LWS_VISIBLE LWS_EXTERN int
lws_cache_results_walk(lws_cache_results_t *walk_ctx);
typedef void (*lws_cache_item_destroy_cb)(void *item, size_t size);
struct lws_cache_creation_info {
struct lws_context *cx;
/**< Mandatory: the lws_context */
const char *name;
/**< Mandatory: short cache name */
lws_cache_item_destroy_cb cb;
/**< NULL, or a callback that can hook cache item destory */
struct lws_cache_ttl_lru *parent;
/**< NULL, or next cache level */
const struct lws_cache_ops *ops;
/**< NULL for default, heap-based ops, else custom cache storage and
* query implementation */
union {
struct {
const char *filepath;
/**< the filepath to store items in */
} nscookiejar;
} u;
/**< these are extra configuration for specific cache types */
size_t max_footprint;
/**< 0, or the max heap allocation allowed before destroying
* lru items to keep it under the limit */
size_t max_items;
/**< 0, or the max number of items allowed in the cache before
* destroying lru items to keep it under the limit */
size_t max_payload;
/**< 0, or the max allowed payload size for one item */
int tsi;
/**< 0 unless using SMP, then tsi to bind sul to */
};
struct lws_cache_ops {
struct lws_cache_ttl_lru *
(*create)(const struct lws_cache_creation_info *info);
/**< create an instance of the cache type specified in info */
void
(*destroy)(struct lws_cache_ttl_lru **_cache);
/**< destroy the logical cache instance pointed to by *_cache, doesn't
* affect any NV backing storage */
int
(*expunge)(struct lws_cache_ttl_lru *cache);
/**< completely delete any backing storage related to the cache
* instance, eg, delete the backing file */
int
(*write)(struct lws_cache_ttl_lru *cache, const char *specific_key,
const uint8_t *source, size_t size, lws_usec_t expiry,
void **ppvoid);
/**< create an entry in the cache level according to the given info */
int
(*tag_match)(struct lws_cache_ttl_lru *cache, const char *wc,
const char *tag, char lookup_rules);
/**< Just tell us if tag would match wildcard, using whatever special
* rules the backing store might use for tag matching. 0 indicates
* it is a match on wildcard, nonzero means does not match.
*/
int
(*lookup)(struct lws_cache_ttl_lru *cache, const char *wildcard_key,
lws_dll2_owner_t *results_owner);
/**+ add keys for search_key matches not already listed in the results
* owner */
int
(*invalidate)(struct lws_cache_ttl_lru *cache, const char *wildcard_key);
/**< remove matching item(s) from cache level */
int
(*get)(struct lws_cache_ttl_lru *cache, const char *specific_key,
const void **pdata, size_t *psize);
/**< if it has the item, fills L1 with item. updates LRU, and returns
* pointer to payload in L1 */
void
(*debug_dump)(struct lws_cache_ttl_lru *cache);
/**< Helper to dump the whole cache contents to log, useful for debug */
};
/**
* lws_cache_create() - create an empty cache you can allocate items in
*
* \param info: a struct describing the cache to create
*
* Create an empty cache you can allocate items in. The cache will be kept
* below the max_footprint and max_items limits if they are nonzero, by
* destroying least-recently-used items until it remains below the limits.
*
* Items will auto-destroy when their expiry time is reached.
*
* When items are destroyed from the cache, if \p cb is non-NULL, it will be
* called back with the item pointer after it has been removed from the cache,
* but before it is deallocated and destroyed.
*
* context and tsi are used when scheduling expiry callbacks
*/
LWS_VISIBLE LWS_EXTERN struct lws_cache_ttl_lru *
lws_cache_create(const struct lws_cache_creation_info *info);
/**
* lws_cache_destroy() - destroy a previously created cache
*
* \param cache: pointer to the cache
*
* Everything in the cache is destroyed, then the cache itself is destroyed,
* and *cache set to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_cache_destroy(struct lws_cache_ttl_lru **cache);
/**
* lws_cache_expunge() - destroy all items in cache and parents
*
* \param cache: pointer to the cache
*
* Everything in the cache and parents is destroyed, leaving it empty.
* If the cache has a backing store, it is deleted.
*
* Returns 0 if no problems reported at any cache layer, else nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_cache_expunge(struct lws_cache_ttl_lru *cache);
LWS_VISIBLE extern const struct lws_cache_ops lws_cache_ops_heap,
lws_cache_ops_nscookiejar;
///@}

View File

@ -0,0 +1,920 @@
/*
* 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 usercb User Callback
*
* ##User protocol callback
*
* The protocol callback is the primary way lws interacts with
* user code. For one of a list of a few dozen reasons the callback gets
* called at some event to be handled.
*
* All of the events can be ignored, returning 0 is taken as "OK" and returning
* nonzero in most cases indicates that the connection should be closed.
*/
///@{
struct lws_ssl_info {
int where;
int ret;
};
enum lws_cert_update_state {
LWS_CUS_IDLE,
LWS_CUS_STARTING,
LWS_CUS_SUCCESS,
LWS_CUS_FAILED,
LWS_CUS_CREATE_KEYS,
LWS_CUS_REG,
LWS_CUS_AUTH,
LWS_CUS_CHALLENGE,
LWS_CUS_CREATE_REQ,
LWS_CUS_REQ,
LWS_CUS_CONFIRM,
LWS_CUS_ISSUE,
};
enum {
LWS_TLS_REQ_ELEMENT_COUNTRY,
LWS_TLS_REQ_ELEMENT_STATE,
LWS_TLS_REQ_ELEMENT_LOCALITY,
LWS_TLS_REQ_ELEMENT_ORGANIZATION,
LWS_TLS_REQ_ELEMENT_COMMON_NAME,
LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME,
LWS_TLS_REQ_ELEMENT_EMAIL,
LWS_TLS_REQ_ELEMENT_COUNT,
LWS_TLS_SET_DIR_URL = LWS_TLS_REQ_ELEMENT_COUNT,
LWS_TLS_SET_AUTH_PATH,
LWS_TLS_SET_CERT_PATH,
LWS_TLS_SET_KEY_PATH,
LWS_TLS_TOTAL_COUNT
};
struct lws_acme_cert_aging_args {
struct lws_vhost *vh;
const char *element_overrides[LWS_TLS_TOTAL_COUNT]; /* NULL = use pvo */
};
/*
* With LWS_CALLBACK_FILTER_NETWORK_CONNECTION callback, user_data pointer
* points to one of these
*/
struct lws_filter_network_conn_args {
struct sockaddr_storage cli_addr;
socklen_t clilen;
lws_sockfd_type accept_fd;
};
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
*/
/** enum lws_callback_reasons - reason you're getting a protocol callback */
enum lws_callback_reasons {
/* ---------------------------------------------------------------------
* ----- Callbacks related to wsi and protocol binding lifecycle -----
*/
LWS_CALLBACK_PROTOCOL_INIT = 27,
/**< One-time call per protocol, per-vhost using it, so it can
* do initial setup / allocations etc */
LWS_CALLBACK_PROTOCOL_DESTROY = 28,
/**< One-time call per protocol, per-vhost using it, indicating
* this protocol won't get used at all after this callback, the
* vhost is getting destroyed. Take the opportunity to
* deallocate everything that was allocated by the protocol. */
LWS_CALLBACK_WSI_CREATE = 29,
/**< outermost (earliest) wsi create notification to protocols[0] */
LWS_CALLBACK_WSI_DESTROY = 30,
/**< outermost (latest) wsi destroy notification to protocols[0] */
LWS_CALLBACK_WSI_TX_CREDIT_GET = 103,
/**< manually-managed connection received TX credit (len is int32) */
/* ---------------------------------------------------------------------
* ----- Callbacks related to Server TLS -----
*/
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS = 21,
/**< if configured for
* including OpenSSL support, this callback allows your user code
* to perform extra SSL_CTX_load_verify_locations() or similar
* calls to direct OpenSSL where to find certificates the client
* can use to confirm the remote server identity. user is the
* OpenSSL SSL_CTX* */
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS = 22,
/**< if configured for
* including OpenSSL support, this callback allows your user code
* to load extra certificates into the server which allow it to
* verify the validity of certificates returned by clients. user
* is the server's OpenSSL SSL_CTX* and in is the lws_vhost */
LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION = 23,
/**< if the libwebsockets vhost was created with the option
* LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this
* callback is generated during OpenSSL verification of the cert
* sent from the client. It is sent to protocol[0] callback as
* no protocol has been negotiated on the connection yet.
* Notice that the libwebsockets context and wsi are both NULL
* during this callback. See
* http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
* to understand more detail about the OpenSSL callback that
* generates this libwebsockets callback and the meanings of the
* arguments passed. In this callback, user is the x509_ctx,
* in is the ssl pointer and len is preverify_ok
* Notice that this callback maintains libwebsocket return
* conventions, return 0 to mean the cert is OK or 1 to fail it.
* This also means that if you don't handle this callback then
* the default callback action of returning 0 allows the client
* certificates. */
LWS_CALLBACK_SSL_INFO = 67,
/**< SSL connections only. An event you registered an
* interest in at the vhost has occurred on a connection
* using the vhost. in is a pointer to a
* struct lws_ssl_info containing information about the
* event*/
/* ---------------------------------------------------------------------
* ----- Callbacks related to Client TLS -----
*/
LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION = 58,
/**< Similar to LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION
* this callback is called during OpenSSL verification of the cert
* sent from the server to the client. It is sent to protocol[0]
* callback as no protocol has been negotiated on the connection yet.
* Notice that the wsi is set because lws_client_connect_via_info was
* successful.
*
* See http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
* to understand more detail about the OpenSSL callback that
* generates this libwebsockets callback and the meanings of the
* arguments passed. In this callback, user is the x509_ctx,
* in is the ssl pointer and len is preverify_ok.
*
* THIS IS NOT RECOMMENDED BUT if a cert validation error shall be
* overruled and cert shall be accepted as ok,
* X509_STORE_CTX_set_error((X509_STORE_CTX*)user, X509_V_OK); must be
* called and return value must be 0 to mean the cert is OK;
* returning 1 will fail the cert in any case.
*
* This also means that if you don't handle this callback then
* the default callback action of returning 0 will not accept the
* certificate in case of a validation error decided by the SSL lib.
*
* This is expected and secure behaviour when validating certificates.
*
* Note: LCCSCF_ALLOW_SELFSIGNED and
* LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK still work without this
* callback being implemented.
*/
/* ---------------------------------------------------------------------
* ----- Callbacks related to HTTP Server -----
*/
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED = 19,
/**< A new client has been accepted by the ws server. This
* callback allows setting any relevant property to it. Because this
* happens immediately after the instantiation of a new client,
* there's no websocket protocol selected yet so this callback is
* issued only to protocol 0. Only wsi is defined, pointing to the
* new client, and the return value is ignored. */
LWS_CALLBACK_HTTP = 12,
/**< an http request has come from a client that is not
* asking to upgrade the connection to a websocket
* one. This is a chance to serve http content,
* for example, to send a script to the client
* which will then open the websockets connection.
* in points to the URI path requested and
* lws_serve_http_file() makes it very
* simple to send back a file to the client.
* Normally after sending the file you are done
* with the http connection, since the rest of the
* activity will come by websockets from the script
* that was delivered by http, so you will want to
* return 1; to close and free up the connection. */
LWS_CALLBACK_HTTP_BODY = 13,
/**< the next len bytes data from the http
* request body HTTP connection is now available in in. */
LWS_CALLBACK_HTTP_BODY_COMPLETION = 14,
/**< the expected amount of http request body has been delivered */
LWS_CALLBACK_HTTP_FILE_COMPLETION = 15,
/**< a file requested to be sent down http link has completed. */
LWS_CALLBACK_HTTP_WRITEABLE = 16,
/**< you can write more down the http protocol link now. */
LWS_CALLBACK_CLOSED_HTTP = 5,
/**< when a HTTP (non-websocket) session ends */
LWS_CALLBACK_FILTER_HTTP_CONNECTION = 18,
/**< called when the request has
* been received and parsed from the client, but the response is
* not sent yet. Return non-zero to disallow the connection.
* user is a pointer to the connection user space allocation,
* in is the URI, eg, "/"
* In your handler you can use the public APIs
* lws_hdr_total_length() / lws_hdr_copy() to access all of the
* headers using the header enums lws_token_indexes from
* libwebsockets.h to check for and read the supported header
* presence and content before deciding to allow the http
* connection to proceed or to kill the connection. */
LWS_CALLBACK_ADD_HEADERS = 53,
/**< This gives your user code a chance to add headers to a server
* transaction bound to your protocol. `in` points to a
* `struct lws_process_html_args` describing a buffer and length
* you can add headers into using the normal lws apis.
*
* (see LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER to add headers to
* a client transaction)
*
* Only `args->p` and `args->len` are valid, and `args->p` should
* be moved on by the amount of bytes written, if any. Eg
*
* case LWS_CALLBACK_ADD_HEADERS:
*
* struct lws_process_html_args *args =
* (struct lws_process_html_args *)in;
*
* if (lws_add_http_header_by_name(wsi,
* (unsigned char *)"set-cookie:",
* (unsigned char *)cookie, cookie_len,
* (unsigned char **)&args->p,
* (unsigned char *)args->p + args->max_len))
* return 1;
*
* break;
*/
LWS_CALLBACK_VERIFY_BASIC_AUTHORIZATION = 102,
/**< This gives the user code a chance to accept or reject credentials
* provided HTTP to basic authorization. It will only be called if the
* http mount's authentication_mode is set to LWSAUTHM_BASIC_AUTH_CALLBACK
* `in` points to a credential string of the form `username:password` If
* the callback returns zero (the default if unhandled), then the
* transaction ends with HTTP_STATUS_UNAUTHORIZED, otherwise the request
* will be processed */
LWS_CALLBACK_CHECK_ACCESS_RIGHTS = 51,
/**< This gives the user code a chance to forbid an http access.
* `in` points to a `struct lws_process_html_args`, which
* describes the URL, and a bit mask describing the type of
* authentication required. If the callback returns nonzero,
* the transaction ends with HTTP_STATUS_UNAUTHORIZED. */
LWS_CALLBACK_PROCESS_HTML = 52,
/**< This gives your user code a chance to mangle outgoing
* HTML. `in` points to a `struct lws_process_html_args`
* which describes the buffer containing outgoing HTML.
* The buffer may grow up to `.max_len` (currently +128
* bytes per buffer).
*/
LWS_CALLBACK_HTTP_BIND_PROTOCOL = 49,
/**< By default, all HTTP handling is done in protocols[0].
* However you can bind different protocols (by name) to
* different parts of the URL space using callback mounts. This
* callback occurs in the new protocol when a wsi is bound
* to that protocol. Any protocol allocation related to the
* http transaction processing should be created then.
* These specific callbacks are necessary because with HTTP/1.1,
* a single connection may perform at series of different
* transactions at different URLs, thus the lifetime of the
* protocol bind is just for one transaction, not connection. */
LWS_CALLBACK_HTTP_DROP_PROTOCOL = 50,
/**< This is called when a transaction is unbound from a protocol.
* It indicates the connection completed its transaction and may
* do something different now. Any protocol allocation related
* to the http transaction processing should be destroyed. */
LWS_CALLBACK_HTTP_CONFIRM_UPGRADE = 86,
/**< This is your chance to reject an HTTP upgrade action. The
* name of the protocol being upgraded to is in 'in', and the ah
* is still bound to the wsi, so you can look at the headers.
*
* The default of returning 0 (ie, also if not handled) means the
* upgrade may proceed. Return <0 to just hang up the connection,
* or >0 if you have rejected the connection by returning http headers
* and response code yourself.
*
* There is no need for you to call transaction_completed() as the
* caller will take care of it when it sees you returned >0.
*/
/* ---------------------------------------------------------------------
* ----- Callbacks related to HTTP Client -----
*/
LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP = 44,
/**< The HTTP client connection has succeeded, and is now
* connected to the server */
LWS_CALLBACK_CLOSED_CLIENT_HTTP = 45,
/**< The HTTP client connection is closing */
LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ = 48,
/**< This is generated by lws_http_client_read() used to drain
* incoming data. In the case the incoming data was chunked, it will
* be split into multiple smaller callbacks for each chunk block,
* removing the chunk headers. If not chunked, it will appear all in
* one callback. */
LWS_CALLBACK_RECEIVE_CLIENT_HTTP = 46,
/**< This indicates data was received on the HTTP client connection. It
* does NOT actually drain or provide the data, so if you are doing
* http client, you MUST handle this and call lws_http_client_read().
* Failure to deal with it as in the minimal examples may cause spinning
* around the event loop as it's continuously signalled the same data
* is available for read. The related minimal examples show how to
* handle it.
*
* It's possible to defer calling lws_http_client_read() if you use
* rx flow control to stop further rx handling on the connection until
* you did deal with it. But normally you would call it in the handler.
*
* lws_http_client_read() strips any chunked framing and calls back
* with only payload data to LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ. The
* chunking is the reason this is not just all done in one callback for
* http.
*/
LWS_CALLBACK_COMPLETED_CLIENT_HTTP = 47,
/**< The client transaction completed... at the moment this
* is the same as closing since transaction pipelining on
* client side is not yet supported. */
LWS_CALLBACK_CLIENT_HTTP_WRITEABLE = 57,
/**< when doing an HTTP type client connection, you can call
* lws_client_http_body_pending(wsi, 1) from
* LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER to get these callbacks
* sending the HTTP headers.
*
* From this callback, when you have sent everything, you should let
* lws know by calling lws_client_http_body_pending(wsi, 0)
*/
LWS_CALLBACK_CLIENT_HTTP_REDIRECT = 104,
/**< we're handling a 3xx redirect... return nonzero to hang up */
LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL = 85,
LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL = 76,
/* ---------------------------------------------------------------------
* ----- Callbacks related to Websocket Server -----
*/
LWS_CALLBACK_ESTABLISHED = 0,
/**< (VH) after the server completes a handshake with an incoming
* client. If you built the library with ssl support, in is a
* pointer to the ssl struct associated with the connection or NULL.
*
* b0 of len is set if the connection was made using ws-over-h2
*/
LWS_CALLBACK_CLOSED = 4,
/**< when the websocket session ends */
LWS_CALLBACK_SERVER_WRITEABLE = 11,
/**< See LWS_CALLBACK_CLIENT_WRITEABLE */
LWS_CALLBACK_RECEIVE = 6,
/**< data has appeared for this server endpoint from a
* remote client, it can be found at *in and is
* len bytes long */
LWS_CALLBACK_RECEIVE_PONG = 7,
/**< servers receive PONG packets with this callback reason */
LWS_CALLBACK_WS_PEER_INITIATED_CLOSE = 38,
/**< The peer has sent an unsolicited Close WS packet. in and
* len are the optional close code (first 2 bytes, network
* order) and the optional additional information which is not
* defined in the standard, and may be a string or non human-readable
* data.
* If you return 0 lws will echo the close and then close the
* connection. If you return nonzero lws will just close the
* connection. */
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION = 20,
/**< called when the handshake has
* been received and parsed from the client, but the response is
* not sent yet. Return non-zero to disallow the connection.
* user is a pointer to the connection user space allocation,
* in is the requested protocol name
* In your handler you can use the public APIs
* lws_hdr_total_length() / lws_hdr_copy() to access all of the
* headers using the header enums lws_token_indexes from
* libwebsockets.h to check for and read the supported header
* presence and content before deciding to allow the handshake
* to proceed or to kill the connection. */
LWS_CALLBACK_CONFIRM_EXTENSION_OKAY = 25,
/**< When the server handshake code
* sees that it does support a requested extension, before
* accepting the extension by additing to the list sent back to
* the client it gives this callback just to check that it's okay
* to use that extension. It calls back to the requested protocol
* and with in being the extension name, len is 0 and user is
* valid. Note though at this time the ESTABLISHED callback hasn't
* happened yet so if you initialize user content there, user
* content during this callback might not be useful for anything. */
LWS_CALLBACK_WS_SERVER_BIND_PROTOCOL = 77,
LWS_CALLBACK_WS_SERVER_DROP_PROTOCOL = 78,
/* ---------------------------------------------------------------------
* ----- Callbacks related to Websocket Client -----
*/
LWS_CALLBACK_CLIENT_CONNECTION_ERROR = 1,
/**< the request client connection has been unable to complete a
* handshake with the remote server. If in is non-NULL, you can
* find an error string of length len where it points to
*
* Diagnostic strings that may be returned include
*
* "getaddrinfo (ipv6) failed"
* "unknown address family"
* "getaddrinfo (ipv4) failed"
* "set socket opts failed"
* "insert wsi failed"
* "lws_ssl_client_connect1 failed"
* "lws_ssl_client_connect2 failed"
* "Peer hung up"
* "read failed"
* "HS: URI missing"
* "HS: Redirect code but no Location"
* "HS: URI did not parse"
* "HS: Redirect failed"
* "HS: Server did not return 200"
* "HS: OOM"
* "HS: disallowed by client filter"
* "HS: disallowed at ESTABLISHED"
* "HS: ACCEPT missing"
* "HS: ws upgrade response not 101"
* "HS: UPGRADE missing"
* "HS: Upgrade to something other than websocket"
* "HS: CONNECTION missing"
* "HS: UPGRADE malformed"
* "HS: PROTOCOL malformed"
* "HS: Cannot match protocol"
* "HS: EXT: list too big"
* "HS: EXT: failed setting defaults"
* "HS: EXT: failed parsing defaults"
* "HS: EXT: failed parsing options"
* "HS: EXT: Rejects server options"
* "HS: EXT: unknown ext"
* "HS: Accept hash wrong"
* "HS: Rejected by filter cb"
* "HS: OOM"
* "HS: SO_SNDBUF failed"
* "HS: Rejected at CLIENT_ESTABLISHED"
*/
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH = 2,
/**< this is the last chance for the client user code to examine the
* http headers and decide to reject the connection. If the
* content in the headers is interesting to the
* client (url, etc) it needs to copy it out at
* this point since it will be destroyed before
* the CLIENT_ESTABLISHED call */
LWS_CALLBACK_CLIENT_ESTABLISHED = 3,
/**< after your client connection completed the websocket upgrade
* handshake with the remote server */
LWS_CALLBACK_CLIENT_CLOSED = 75,
/**< when a client websocket session ends */
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER = 24,
/**< this callback happens
* when a client handshake is being compiled. user is NULL,
* in is a char **, it's pointing to a char * which holds the
* next location in the header buffer where you can add
* headers, and len is the remaining space in the header buffer,
* which is typically some hundreds of bytes. So, to add a canned
* cookie, your handler code might look similar to:
*
* char **p = (char **)in, *end = (*p) + len;
*
* if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_COOKIE,
* (unsigned char)"a=b", 3, p, end))
* return -1;
*
* See LWS_CALLBACK_ADD_HEADERS for adding headers to server
* transactions.
*/
LWS_CALLBACK_CLIENT_RECEIVE = 8,
/**< data has appeared from the server for the client connection, it
* can be found at *in and is len bytes long */
LWS_CALLBACK_CLIENT_RECEIVE_PONG = 9,
/**< clients receive PONG packets with this callback reason */
LWS_CALLBACK_CLIENT_WRITEABLE = 10,
/**< If you call lws_callback_on_writable() on a connection, you will
* get one of these callbacks coming when the connection socket
* is able to accept another write packet without blocking.
* If it already was able to take another packet without blocking,
* you'll get this callback at the next call to the service loop
* function. Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE
* and servers get LWS_CALLBACK_SERVER_WRITEABLE. */
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED = 26,
/**< When a ws client
* connection is being prepared to start a handshake to a server,
* each supported extension is checked with protocols[0] callback
* with this reason, giving the user code a chance to suppress the
* claim to support that extension by returning non-zero. If
* unhandled, by default 0 will be returned and the extension
* support included in the header to the server. Notice this
* callback comes to protocols[0]. */
LWS_CALLBACK_WS_EXT_DEFAULTS = 39,
/**< Gives client connections an opportunity to adjust negotiated
* extension defaults. `user` is the extension name that was
* negotiated (eg, "permessage-deflate"). `in` points to a
* buffer and `len` is the buffer size. The user callback can
* set the buffer to a string describing options the extension
* should parse. Or just ignore for defaults. */
LWS_CALLBACK_FILTER_NETWORK_CONNECTION = 17,
/**< called when a client connects to
* the server at network level; the connection is accepted but then
* passed to this callback to decide whether to hang up immediately
* or not, based on the client IP.
*
* user_data in the callback points to a
* struct lws_filter_network_conn_args that is prepared with the
* sockfd, and the peer's address information.
*
* in contains the connection socket's descriptor.
*
* Since the client connection information is not available yet,
* wsi still pointing to the main server socket.
*
* Return non-zero to terminate the connection before sending or
* receiving anything. Because this happens immediately after the
* network connection from the client, there's no websocket protocol
* selected yet so this callback is issued only to protocol 0. */
LWS_CALLBACK_WS_CLIENT_BIND_PROTOCOL = 79,
LWS_CALLBACK_WS_CLIENT_DROP_PROTOCOL = 80,
/* ---------------------------------------------------------------------
* ----- Callbacks related to external poll loop integration -----
*/
LWS_CALLBACK_GET_THREAD_ID = 31,
/**< lws can accept callback when writable requests from other
* threads, if you implement this callback and return an opaque
* current thread ID integer. */
/* external poll() management support */
LWS_CALLBACK_ADD_POLL_FD = 32,
/**< lws normally deals with its poll() or other event loop
* internally, but in the case you are integrating with another
* server you will need to have lws sockets share a
* polling array with the other server. This and the other
* POLL_FD related callbacks let you put your specialized
* poll array interface code in the callback for protocol 0, the
* first protocol you support, usually the HTTP protocol in the
* serving case.
* This callback happens when a socket needs to be
* added to the polling loop: in points to a struct
* lws_pollargs; the fd member of the struct is the file
* descriptor, and events contains the active events
*
* If you are using the internal lws polling / event loop
* you can just ignore these callbacks. */
LWS_CALLBACK_DEL_POLL_FD = 33,
/**< This callback happens when a socket descriptor
* needs to be removed from an external polling array. in is
* again the struct lws_pollargs containing the fd member
* to be removed. If you are using the internal polling
* loop, you can just ignore it. */
LWS_CALLBACK_CHANGE_MODE_POLL_FD = 34,
/**< This callback happens when lws wants to modify the events for
* a connection.
* in is the struct lws_pollargs with the fd to change.
* The new event mask is in events member and the old mask is in
* the prev_events member.
* If you are using the internal polling loop, you can just ignore
* it. */
LWS_CALLBACK_LOCK_POLL = 35,
/**< These allow the external poll changes driven
* by lws to participate in an external thread locking
* scheme around the changes, so the whole thing is threadsafe.
* These are called around three activities in the library,
* - inserting a new wsi in the wsi / fd table (len=1)
* - deleting a wsi from the wsi / fd table (len=1)
* - changing a wsi's POLLIN/OUT state (len=0)
* Locking and unlocking external synchronization objects when
* len == 1 allows external threads to be synchronized against
* wsi lifecycle changes if it acquires the same lock for the
* duration of wsi dereference from the other thread context. */
LWS_CALLBACK_UNLOCK_POLL = 36,
/**< See LWS_CALLBACK_LOCK_POLL, ignore if using lws internal poll */
/* ---------------------------------------------------------------------
* ----- Callbacks related to CGI serving -----
*/
LWS_CALLBACK_CGI = 40,
/**< CGI: CGI IO events on stdin / out / err are sent here on
* protocols[0]. The provided `lws_callback_http_dummy()`
* handles this and the callback should be directed there if
* you use CGI. */
LWS_CALLBACK_CGI_TERMINATED = 41,
/**< CGI: The related CGI process ended, this is called before
* the wsi is closed. Used to, eg, terminate chunking.
* The provided `lws_callback_http_dummy()`
* handles this and the callback should be directed there if
* you use CGI. The child PID that terminated is in len. */
LWS_CALLBACK_CGI_STDIN_DATA = 42,
/**< CGI: Data is, to be sent to the CGI process stdin, eg from
* a POST body. The provided `lws_callback_http_dummy()`
* handles this and the callback should be directed there if
* you use CGI. */
LWS_CALLBACK_CGI_STDIN_COMPLETED = 43,
/**< CGI: no more stdin is coming. The provided
* `lws_callback_http_dummy()` handles this and the callback
* should be directed there if you use CGI. */
LWS_CALLBACK_CGI_PROCESS_ATTACH = 70,
/**< CGI: Sent when the CGI process is spawned for the wsi. The
* len parameter is the PID of the child process */
/* ---------------------------------------------------------------------
* ----- Callbacks related to Generic Sessions -----
*/
LWS_CALLBACK_SESSION_INFO = 54,
/**< This is only generated by user code using generic sessions.
* It's used to get a `struct lws_session_info` filled in by
* generic sessions with information about the logged-in user.
* See the messageboard sample for an example of how to use. */
LWS_CALLBACK_GS_EVENT = 55,
/**< Indicates an event happened to the Generic Sessions session.
* `in` contains a `struct lws_gs_event_args` describing the event. */
LWS_CALLBACK_HTTP_PMO = 56,
/**< per-mount options for this connection, called before
* the normal LWS_CALLBACK_HTTP when the mount has per-mount
* options.
*/
/* ---------------------------------------------------------------------
* ----- Callbacks related to RAW PROXY -----
*/
LWS_CALLBACK_RAW_PROXY_CLI_RX = 89,
/**< RAW mode client (outgoing) RX */
LWS_CALLBACK_RAW_PROXY_SRV_RX = 90,
/**< RAW mode server (listening) RX */
LWS_CALLBACK_RAW_PROXY_CLI_CLOSE = 91,
/**< RAW mode client (outgoing) is closing */
LWS_CALLBACK_RAW_PROXY_SRV_CLOSE = 92,
/**< RAW mode server (listening) is closing */
LWS_CALLBACK_RAW_PROXY_CLI_WRITEABLE = 93,
/**< RAW mode client (outgoing) may be written */
LWS_CALLBACK_RAW_PROXY_SRV_WRITEABLE = 94,
/**< RAW mode server (listening) may be written */
LWS_CALLBACK_RAW_PROXY_CLI_ADOPT = 95,
/**< RAW mode client (onward) accepted socket was adopted
* (equivalent to 'wsi created') */
LWS_CALLBACK_RAW_PROXY_SRV_ADOPT = 96,
/**< RAW mode server (listening) accepted socket was adopted
* (equivalent to 'wsi created') */
LWS_CALLBACK_RAW_PROXY_CLI_BIND_PROTOCOL = 97,
LWS_CALLBACK_RAW_PROXY_SRV_BIND_PROTOCOL = 98,
LWS_CALLBACK_RAW_PROXY_CLI_DROP_PROTOCOL = 99,
LWS_CALLBACK_RAW_PROXY_SRV_DROP_PROTOCOL = 100,
/* ---------------------------------------------------------------------
* ----- Callbacks related to RAW sockets -----
*/
LWS_CALLBACK_RAW_RX = 59,
/**< RAW mode connection RX */
LWS_CALLBACK_RAW_CLOSE = 60,
/**< RAW mode connection is closing */
LWS_CALLBACK_RAW_WRITEABLE = 61,
/**< RAW mode connection may be written */
LWS_CALLBACK_RAW_ADOPT = 62,
/**< RAW mode connection was adopted (equivalent to 'wsi created') */
LWS_CALLBACK_RAW_CONNECTED = 101,
/**< outgoing client RAW mode connection was connected */
LWS_CALLBACK_RAW_SKT_BIND_PROTOCOL = 81,
LWS_CALLBACK_RAW_SKT_DROP_PROTOCOL = 82,
/* ---------------------------------------------------------------------
* ----- Callbacks related to RAW file handles -----
*/
LWS_CALLBACK_RAW_ADOPT_FILE = 63,
/**< RAW mode file was adopted (equivalent to 'wsi created') */
LWS_CALLBACK_RAW_RX_FILE = 64,
/**< This is the indication the RAW mode file has something to read.
* This doesn't actually do the read of the file and len is always
* 0... your code should do the read having been informed there is
* something to read now. */
LWS_CALLBACK_RAW_WRITEABLE_FILE = 65,
/**< RAW mode file is writeable */
LWS_CALLBACK_RAW_CLOSE_FILE = 66,
/**< RAW mode wsi that adopted a file is closing */
LWS_CALLBACK_RAW_FILE_BIND_PROTOCOL = 83,
LWS_CALLBACK_RAW_FILE_DROP_PROTOCOL = 84,
/* ---------------------------------------------------------------------
* ----- Callbacks related to generic wsi events -----
*/
LWS_CALLBACK_TIMER = 73,
/**< When the time elapsed after a call to
* lws_set_timer_usecs(wsi, usecs) is up, the wsi will get one of
* these callbacks. The deadline can be continuously extended into the
* future by later calls to lws_set_timer_usecs() before the deadline
* expires, or cancelled by lws_set_timer_usecs(wsi, -1);
*/
LWS_CALLBACK_EVENT_WAIT_CANCELLED = 71,
/**< This is sent to every protocol of every vhost in response
* to lws_cancel_service() or lws_cancel_service_pt(). This
* callback is serialized in the lws event loop normally, even
* if the lws_cancel_service[_pt]() call was from a different
* thread. */
LWS_CALLBACK_CHILD_CLOSING = 69,
/**< Sent to parent to notify them a child is closing / being
* destroyed. in is the child wsi.
*/
LWS_CALLBACK_CONNECTING = 105,
/**< Called before a socketfd is about to connect(). In is the
* socketfd, cast to a (void *), if on a platform where the socketfd
* is an int, recover portably using (lws_sockfd_type)(intptr_t)in.
*
* It's also called in SOCKS5 or http_proxy cases where the socketfd is
* going to try to connect to its proxy.
*/
/* ---------------------------------------------------------------------
* ----- Callbacks related to TLS certificate management -----
*/
LWS_CALLBACK_VHOST_CERT_AGING = 72,
/**< When a vhost TLS cert has its expiry checked, this callback
* is broadcast to every protocol of every vhost in case the
* protocol wants to take some action with this information.
* \p in is a pointer to a struct lws_acme_cert_aging_args,
* and \p len is the number of days left before it expires, as
* a (ssize_t). In the struct lws_acme_cert_aging_args, vh
* points to the vhost the cert aging information applies to,
* and element_overrides[] is an optional way to update information
* from the pvos... NULL in an index means use the information from
* from the pvo for the cert renewal, non-NULL in the array index
* means use that pointer instead for the index. */
LWS_CALLBACK_VHOST_CERT_UPDATE = 74,
/**< When a vhost TLS cert is being updated, progress is
* reported to the vhost in question here, including completion
* and failure. in points to optional JSON, and len represents the
* connection state using enum lws_cert_update_state */
/* ---------------------------------------------------------------------
* ----- Callbacks related to MQTT Client -----
*/
LWS_CALLBACK_MQTT_NEW_CLIENT_INSTANTIATED = 200,
LWS_CALLBACK_MQTT_IDLE = 201,
LWS_CALLBACK_MQTT_CLIENT_ESTABLISHED = 202,
LWS_CALLBACK_MQTT_SUBSCRIBED = 203,
LWS_CALLBACK_MQTT_CLIENT_WRITEABLE = 204,
LWS_CALLBACK_MQTT_CLIENT_RX = 205,
LWS_CALLBACK_MQTT_UNSUBSCRIBED = 206,
LWS_CALLBACK_MQTT_DROP_PROTOCOL = 207,
LWS_CALLBACK_MQTT_CLIENT_CLOSED = 208,
LWS_CALLBACK_MQTT_ACK = 209,
/**< When a message is fully sent, if QoS0 this callback is generated
* to locally "acknowledge" it. For QoS1, this callback is only
* generated when the matching PUBACK is received. Return nonzero to
* close the wsi.
*/
LWS_CALLBACK_MQTT_RESEND = 210,
/**< In QoS1 or QoS2, this callback is generated instead of the _ACK one
* if we timed out waiting for a PUBACK or a PUBREC, and we must resend
* the message. Return nonzero to close the wsi.
*/
LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT = 211,
/**< When a UNSUBSCRIBE is sent, this callback is generated instead of
* the _UNSUBSCRIBED one if we timed out waiting for a UNSUBACK.
* Return nonzero to close the wsi.
*/
LWS_CALLBACK_MQTT_SHADOW_TIMEOUT = 212,
/**< When a Device Shadow is sent, this callback is generated if we
* timed out waiting for a response from AWS IoT.
* Return nonzero to close the wsi.
*/
/****** add new things just above ---^ ******/
LWS_CALLBACK_USER = 1000,
/**< user code can use any including above without fear of clashes */
};
/**
* typedef lws_callback_function() - User server actions
* \param wsi: Opaque websocket instance pointer
* \param reason: The reason for the call
* \param user: Pointer to per-session user data allocated by library
* \param in: Pointer used for some callback reasons
* \param len: Length set for some callback reasons
*
* This callback is the way the user controls what is served. All the
* protocol detail is hidden and handled by the library.
*
* For each connection / session there is user data allocated that is
* pointed to by "user". You set the size of this user data area when
* the library is initialized with lws_create_server.
*/
typedef int
lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
#define LWS_CB_REASON_AUX_BF__CGI 1
#define LWS_CB_REASON_AUX_BF__PROXY 2
#define LWS_CB_REASON_AUX_BF__CGI_CHUNK_END 4
#define LWS_CB_REASON_AUX_BF__CGI_HEADERS 8
#define LWS_CB_REASON_AUX_BF__PROXY_TRANS_END 16
#define LWS_CB_REASON_AUX_BF__PROXY_HEADERS 32
///@}

View File

@ -0,0 +1,104 @@
/*
* 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 cgi cgi handling
*
* ##CGI handling
*
* These functions allow low-level control over stdin/out/err of the cgi.
*
* However for most cases, binding the cgi to http in and out, the default
* lws implementation already does the right thing.
*/
enum lws_enum_stdinouterr {
LWS_STDIN = 0,
LWS_STDOUT = 1,
LWS_STDERR = 2,
};
enum lws_cgi_hdr_state {
LCHS_HEADER,
LCHS_CR1,
LCHS_LF1,
LCHS_CR2,
LCHS_LF2,
LHCS_RESPONSE,
LHCS_DUMP_HEADERS,
LHCS_PAYLOAD,
LCHS_SINGLE_0A,
};
struct lws_cgi_args {
struct lws **stdwsi; /**< get fd with lws_get_socket_fd() */
enum lws_enum_stdinouterr ch; /**< channel index */
unsigned char *data; /**< for messages with payload */
enum lws_cgi_hdr_state hdr_state; /**< track where we are in cgi headers */
int len; /**< length */
};
#ifdef LWS_WITH_CGI
/**
* lws_cgi: spawn network-connected cgi process
*
* \param wsi: connection to own the process
* \param exec_array: array of "exec-name" "arg1" ... "argn" NULL
* \param script_uri_path_len: how many chars on the left of the uri are the
* path to the cgi, or -1 to spawn without URL-related env vars
* \param timeout_secs: seconds script should be allowed to run
* \param mp_cgienv: pvo list with per-vhost cgi options to put in env
*/
LWS_VISIBLE LWS_EXTERN int
lws_cgi(struct lws *wsi, const char * const *exec_array,
int script_uri_path_len, int timeout_secs,
const struct lws_protocol_vhost_options *mp_cgienv);
/**
* lws_cgi_write_split_stdout_headers: write cgi output accounting for header part
*
* \param wsi: connection to own the process
*/
LWS_VISIBLE LWS_EXTERN int
lws_cgi_write_split_stdout_headers(struct lws *wsi);
/**
* lws_cgi_kill: terminate cgi process associated with wsi
*
* \param wsi: connection to own the process
*/
LWS_VISIBLE LWS_EXTERN int
lws_cgi_kill(struct lws *wsi);
/**
* lws_cgi_get_stdwsi: get wsi for stdin, stdout, or stderr
*
* \param wsi: parent wsi that has cgi
* \param ch: which of LWS_STDIN, LWS_STDOUT or LWS_STDERR
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_cgi_get_stdwsi(struct lws *wsi, enum lws_enum_stdinouterr ch);
#endif
///@}

View File

@ -0,0 +1,457 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 client Client related functions
* ##Client releated functions
* \ingroup lwsapi
*
* */
///@{
/** enum lws_client_connect_ssl_connection_flags - flags that may be used
* with struct lws_client_connect_info ssl_connection member to control if
* and how SSL checks apply to the client connection being created
*/
enum lws_client_connect_ssl_connection_flags {
LCCSCF_USE_SSL = (1 << 0),
LCCSCF_ALLOW_SELFSIGNED = (1 << 1),
LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK = (1 << 2),
LCCSCF_ALLOW_EXPIRED = (1 << 3),
LCCSCF_ALLOW_INSECURE = (1 << 4),
LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM = (1 << 5),
LCCSCF_H2_QUIRK_OVERFLOWS_TXCR = (1 << 6),
LCCSCF_H2_AUTH_BEARER = (1 << 7),
LCCSCF_H2_HEXIFY_AUTH_TOKEN = (1 << 8),
LCCSCF_H2_MANUAL_RXFLOW = (1 << 9),
LCCSCF_HTTP_MULTIPART_MIME = (1 << 10),
LCCSCF_HTTP_X_WWW_FORM_URLENCODED = (1 << 11),
LCCSCF_HTTP_NO_FOLLOW_REDIRECT = (1 << 12),
LCCSCF_HTTP_NO_CACHE_CONTROL = (1 << 13),
LCCSCF_ALLOW_REUSE_ADDR = (1 << 14),
/**< allow reuse local addresses in a bind call
* When the listening socket is bound to INADDR_ANY with a specific port
* then it is not possible to bind to this port for any local address
*/
LCCSCF_IPV6_PREFER_PUBLIC_ADDR = (1 << 15),
/**< RFC5014 - For IPv6 systems with SLAAC config, allow for preference
* to bind a socket to public address vs temporary private address
*/
LCCSCF_PIPELINE = (1 << 16),
/**< Serialize / pipeline multiple client connections
* on a single connection where possible.
*
* HTTP/1.0: possible if Keep-Alive: yes sent by server
* HTTP/1.1: always possible... uses pipelining
* HTTP/2: always possible... uses parallel streams
*/
LCCSCF_MUXABLE_STREAM = (1 << 17),
LCCSCF_H2_PRIOR_KNOWLEDGE = (1 << 18),
LCCSCF_WAKE_SUSPEND__VALIDITY = (1 << 19),
/* our validity checks are important enough to wake from suspend */
LCCSCF_PRIORITIZE_READS = (1 << 20),
/**<
* Normally lws balances reads and writes on all connections, so both
* are possible even on busy connections, and we go around the event
* loop more often to facilitate that, even if there is pending data.
*
* This flag indicates that you want to handle any pending reads on this
* connection without yielding the service loop for anything else. This
* means you may block other connection processing in favour of incoming
* data processing on this one if it receives back to back incoming rx.
*/
LCCSCF_SECSTREAM_CLIENT = (1 << 21),
/**< used to mark client wsi as bound to secure stream */
LCCSCF_SECSTREAM_PROXY_LINK = (1 << 22),
/**< client is a link between SS client and SS proxy */
LCCSCF_SECSTREAM_PROXY_ONWARD = (1 << 23),
/**< client the SS proxy's onward connection */
LCCSCF_IP_LOW_LATENCY = (1 << 24),
/**< set the "low delay" bit on the IP packets of this connection */
LCCSCF_IP_HIGH_THROUGHPUT = (1 << 25),
/**< set the "high throughput" bit on the IP packets of this
* connection */
LCCSCF_IP_HIGH_RELIABILITY = (1 << 26),
/**< set the "high reliability" bit on the IP packets of this
* connection */
LCCSCF_IP_LOW_COST = (1 << 27),
/**< set the "minimize monetary cost" bit on the IP packets of this
* connection */
LCCSCF_CONMON = (1 << 28),
/**< If LWS_WITH_CONMON enabled for build, keeps a copy of the
* getaddrinfo results so they can be queried subsequently */
LCCSCF_ACCEPT_TLS_DOWNGRADE_REDIRECTS = (1 << 29),
/**< By default lws rejects https redirecting to http. Set this
* flag on the client connection to allow it. */
LCCSCF_CACHE_COOKIES = (1 << 30),
/**< If built with -DLWS_WITH_CACHE_NSCOOKIEJAR, store and reapply
* http cookies in a Netscape Cookie Jar on this connection */
};
/** struct lws_client_connect_info - parameters to connect with when using
* lws_client_connect_via_info() */
struct lws_client_connect_info {
struct lws_context *context;
/**< lws context to create connection in */
const char *address;
/**< remote address to connect to */
int port;
/**< remote port to connect to */
int ssl_connection;
/**< 0, or a combination of LCCSCF_ flags */
const char *path;
/**< URI path. Prefix with + for a UNIX socket. (+@ for
* a Linux abstract-namespace socket) */
const char *host;
/**< content of host header */
const char *origin;
/**< content of origin header */
const char *protocol;
/**< list of ws protocols we could accept */
int ietf_version_or_minus_one;
/**< deprecated: currently leave at 0 or -1 */
void *userdata;
/**< if non-NULL, use this as wsi user_data instead of malloc it */
const void *client_exts;
/**< UNUSED... provide in info.extensions at context creation time */
const char *method;
/**< if non-NULL, do this http method instead of ws[s] upgrade.
* use "GET" to be a simple http client connection. "RAW" gets
* you a connected socket that lws itself will leave alone once
* connected. */
struct lws *parent_wsi;
/**< if another wsi is responsible for this connection, give it here.
* this is used to make sure if the parent closes so do any
* child connections first. */
const char *uri_replace_from;
/**< if non-NULL, when this string is found in URIs in
* text/html content-encoding, it's replaced with uri_replace_to */
const char *uri_replace_to;
/**< see uri_replace_from */
struct lws_vhost *vhost;
/**< vhost to bind to (used to determine related SSL_CTX) */
struct lws **pwsi;
/**< if not NULL, store the new wsi here early in the connection
* process. Although we return the new wsi, the call to create the
* client connection does progress the connection somewhat and may
* meet an error that will result in the connection being scrubbed and
* NULL returned. While the wsi exists though, he may process a
* callback like CLIENT_CONNECTION_ERROR with his wsi: this gives the
* user callback a way to identify which wsi it is that faced the error
* even before the new wsi is returned and even if ultimately no wsi
* is returned.
*/
const char *iface;
/**< NULL to allow routing on any interface, or interface name or IP
* to bind the socket to */
int local_port;
/**< 0 to pick an ephemeral port, or a specific local port
* to bind the socket to */
const char *local_protocol_name;
/**< NULL: .protocol is used both to select the local protocol handler
* to bind to and as the list of remote ws protocols we could
* accept.
* non-NULL: this protocol name is used to bind the connection to
* the local protocol handler. .protocol is used for the
* list of remote ws protocols we could accept */
const char *alpn;
/**< NULL: allow lws default ALPN list, from vhost if present or from
* list of roles built into lws
* non-NULL: require one from provided comma-separated list of alpn
* tokens
*/
void *opaque_user_data;
/**< This data has no meaning to lws but is applied to the client wsi
* and can be retrieved by user code with lws_get_opaque_user_data().
* It's also provided with sequencer messages if the wsi is bound to
* an lws_seq_t.
*/
const lws_retry_bo_t *retry_and_idle_policy;
/**< optional retry and idle policy to apply to this connection.
* Currently only the idle parts are applied to the connection.
*/
int manual_initial_tx_credit;
/**< if LCCSCF_H2_MANUAL_REFLOW is set, this becomes the initial tx
* credit for the stream.
*/
uint8_t sys_tls_client_cert;
/**< 0 means no client cert. 1+ means apply lws_system client cert 0+
* to the client connection.
*/
uint8_t priority;
/**< 0 means normal priority... otherwise sets the IP priority on
* packets coming from this connection, from 1 - 7. Setting 7
* (network management priority) requires CAP_NET_ADMIN capability but
* the others can be set by anyone.
*/
#if defined(LWS_ROLE_MQTT)
const lws_mqtt_client_connect_param_t *mqtt_cp;
#else
void *mqtt_cp;
#endif
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
lws_fi_ctx_t fic;
/**< Attach external Fault Injection context to the client wsi,
* hierarchy is wsi -> vhost -> context */
#endif
/* for convenience, available when FI disabled in build */
const char *fi_wsi_name;
/**< specific Fault Injection namespace name for wsi created for this
* connection, allows targeting by "wsi=XXX/..." if you give XXX here.
*/
uint16_t keep_warm_secs;
/**< 0 means 5s. If the client connection to the endpoint becomes idle,
* defer closing it for this many seconds in case another outgoing
* connection to the same endpoint turns up.
*/
lws_log_cx_t *log_cx;
/**< NULL to use lws_context log context, else a pointer to a log
* context template to take a copy of for this wsi. Used to isolate
* wsi-specific logs into their own stream or file.
*/
const char *auth_username;
const char *auth_password;
#if defined(LWS_ROLE_WS)
uint8_t allow_reserved_bits;
/**< non-zero to allow reserved bits. You can get it by lws_get_reserved_bits().
* Note: default zero means close the websocket connection for non-zero rsv.
*/
uint8_t allow_unknown_opcode;
/**< non-zero to allow unknown opcode. You can get it by `lws_get_opcode`.
* None: default zero means close the websocket connection for unknown opcode.
*/
#endif
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility
*
* The below is to ensure later library versions with new
* members added above will see 0 (default) even if the app
* was not built against the newer headers.
*/
void *_unused[4]; /**< dummy */
};
/**
* lws_client_connect_via_info() - Connect to another websocket server
* \param ccinfo: pointer to lws_client_connect_info struct
*
* This function creates a connection to a remote server using the
* information provided in ccinfo.
*/
LWS_VISIBLE LWS_EXTERN struct lws *
lws_client_connect_via_info(const struct lws_client_connect_info *ccinfo);
/**
* lws_init_vhost_client_ssl() - also enable client SSL on an existing vhost
*
* \param info: client ssl related info
* \param vhost: which vhost to initialize client ssl operations on
*
* You only need to call this if you plan on using SSL client connections on
* the vhost. For non-SSL client connections, it's not necessary to call this.
*
* The following members of info are used during the call
*
* - options must have LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT set,
* otherwise the call does nothing
* - provided_client_ssl_ctx must be NULL to get a generated client
* ssl context, otherwise you can pass a prepared one in by setting it
* - ssl_cipher_list may be NULL or set to the client valid cipher list
* - ssl_ca_filepath may be NULL or client cert filepath
* - ssl_cert_filepath may be NULL or client cert filepath
* - ssl_private_key_filepath may be NULL or client cert private key
*
* You must create your vhost explicitly if you want to use this, so you have
* a pointer to the vhost. Create the context first with the option flag
* LWS_SERVER_OPTION_EXPLICIT_VHOSTS and then call lws_create_vhost() with
* the same info struct.
*/
LWS_VISIBLE LWS_EXTERN int
lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
struct lws_vhost *vhost);
/**
* lws_http_client_read() - consume waiting received http client data
*
* \param wsi: client connection
* \param buf: pointer to buffer pointer - fill with pointer to your buffer
* \param len: pointer to chunk length - fill with max length of buffer
*
* This is called when the user code is notified client http data has arrived.
* The user code may choose to delay calling it to consume the data, for example
* waiting until an onward connection is writeable.
*
* For non-chunked connections, up to len bytes of buf are filled with the
* received content. len is set to the actual amount filled before return.
*
* For chunked connections, the linear buffer content contains the chunking
* headers and it cannot be passed in one lump. Instead, this function will
* call back LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ with in pointing to the
* chunk start and len set to the chunk length. There will be as many calls
* as there are chunks or partial chunks in the buffer.
*/
LWS_VISIBLE LWS_EXTERN int
lws_http_client_read(struct lws *wsi, char **buf, int *len);
/**
* lws_http_client_http_response() - get last HTTP response code
*
* \param wsi: client connection
*
* Returns the last server response code, eg, 200 for client http connections.
* If there is no valid response, it will return 0.
*
* You should capture this during the LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP
* callback, because after that the memory reserved for storing the related
* headers is freed and this value is lost.
*/
LWS_VISIBLE LWS_EXTERN unsigned int
lws_http_client_http_response(struct lws *wsi);
/**
* lws_tls_client_vhost_extra_cert_mem() - add more certs to vh client tls ctx
*
* \param vh: the vhost to give more client certs to
* \param der: pointer to der format additional cert
* \param der_len: size in bytes of der
*
* After the vhost is created with one cert for client verification, you
* can add additional, eg, intermediate, certs to the client tls context
* of the vhost, for use with validating the incoming server cert(s).
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
const uint8_t *der, size_t der_len);
/**
* lws_client_http_body_pending() - control if client connection needs to send body
*
* \param wsi: client connection
* \param something_left_to_send: nonzero if need to send more body, 0 (default)
* if nothing more to send
*
* If you will send payload data with your HTTP client connection, eg, for POST,
* when you set the related http headers in
* LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER callback you should also call
* this API with something_left_to_send nonzero, and call
* lws_callback_on_writable(wsi);
*
* After sending the headers, lws will call your callback with
* LWS_CALLBACK_CLIENT_HTTP_WRITEABLE reason when writable. You can send the
* next part of the http body payload, calling lws_callback_on_writable(wsi);
* if there is more to come, or lws_client_http_body_pending(wsi, 0); to
* let lws know the last part is sent and the connection can move on.
*/
LWS_VISIBLE LWS_EXTERN void
lws_client_http_body_pending(struct lws *wsi, int something_left_to_send);
/**
* lws_client_http_multipart() - issue appropriate multipart header or trailer
*
* \param wsi: client connection
* \param name: multipart header name field, or NULL if end of multipart
* \param filename: multipart header filename field, or NULL if none
* \param content_type: multipart header content-type part, or NULL if none
* \param p: pointer to position in buffer
* \param end: end of buffer
*
* This issues a multipart mime boundary, or terminator if name = NULL.
*
* Returns 0 if OK or nonzero if couldn't fit in buffer
*/
LWS_VISIBLE LWS_EXTERN int
lws_client_http_multipart(struct lws *wsi, const char *name,
const char *filename, const char *content_type,
char **p, char *end);
/**
* lws_http_basic_auth_gen() - helper to encode client basic auth string
*
* \param user: user name
* \param pw: password
* \param buf: where to store base64 result
* \param len: max usable size of buf
*
* Encodes a username and password in Basic Auth format for use with the
* Authorization header. On return, buf is filled with something like
* "Basic QWxhZGRpbjpPcGVuU2VzYW1l".
*/
LWS_VISIBLE LWS_EXTERN int
lws_http_basic_auth_gen(const char *user, const char *pw, char *buf, size_t len);
/**
* lws_http_basic_auth_gen2() - helper to encode client basic auth string
*
* \param user: user name
* \param pw: password
* \param pwd_len: count of bytes in password
* \param buf: where to store base64 result
* \param len: max usable size of buf
*
* Encodes a username and password in Basic Auth format for use with the
* Authorization header. On return, buf is filled with something like
* "Basic QWxhZGRpbjpPcGVuU2VzYW1l".
*
* This differs from lws_http_baic_auth_gen() in that NUL bytes can
* appear in the password due to an explicit password length argument.
*/
LWS_VISIBLE LWS_EXTERN int
lws_http_basic_auth_gen2(const char *user, const void *pw, size_t pwd_len,
char *buf, size_t len);
/**
* lws_tls_session_is_reused() - returns nonzero if tls session was cached
*
* \param wsi: the wsi
*
* Returns zero if the tls session is fresh, else nonzero if the tls session was
* taken from the cache. If lws is built with LWS_WITH_TLS_SESSIONS and the vhost
* was created with the option LWS_SERVER_OPTION_ENABLE_TLS_SESSION_CACHE, then
* on full tls session establishment of a client connection, the session is added
* to the tls cache.
*
* This lets you find out if your session was new (0) or from the cache (nonzero),
* it'a mainly useful for stats and testing.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_session_is_reused(struct lws *wsi);
///@}

View File

@ -0,0 +1,155 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 conmon Connection Latency information
* ## Connection Latency information
*
* When LWS_WITH_CONMON is enabled at build, collects detailed statistics
* about the client connection setup latency, available to the connection
* itself
*/
///@{
/* enough for 4191s, or just over an hour */
typedef uint32_t lws_conmon_interval_us_t;
/*
* Connection latency information... note that not all wsi actually make
* connections, for example h2 streams after the initial one will have 0
* for everything except ciu_txn_resp.
*
* If represented in JSON, it should look like this
*
* {
* "peer": "46.105.127.147",
* "dns_us": 1234,
* "dns_disp": 1,
* "sockconn_us": 1234,
* "tls_us": 1234,
* "txn_resp_us": 1234,
* "dns":["46.105.127.147", "2001:41d0:2:ee93::1"],
* "prot_specific": {
* "protocol": "http",
* "resp": 200
* }
* }
*
* The indexes in "dns_disp" are declared in lws_conmon_dns_disposition_t
* below.
*
* "prot_specific" may not be present if the protocol doesn't have anything
* to report or is not supported.
*/
typedef enum lws_conmon_pcol {
LWSCONMON_PCOL_NONE,
LWSCONMON_PCOL_HTTP, /* .protocol_specific.http is valid */
} lws_conmon_pcol_t;
typedef enum lws_conmon_dns_disposition {
LWSCONMON_DNS_NONE,
/**< did not attempt DNS */
LWSCONMON_DNS_OK = 1,
/**< DNS lookup did give results */
LWSCONMON_DNS_SERVER_UNREACHABLE = 2,
/**< DNS server was not reachable */
LWSCONMON_DNS_NO_RESULT = 3
/**< DNS server replied but nothing usable */
} lws_conmon_dns_disposition_t;
struct lws_conmon {
lws_sockaddr46 peer46;
/**< The peer we actually connected to, if any. .peer46.sa4.sa_family
* is either 0 if invalid, or the AF_ */
union {
struct {
int response;
/**< h1 http response code */
} http;
} protocol_specific;
/**< possibly-present protocol-specific additional information. This
* is only valid for the first transaction after connection and does
* not capture results for persistent or muxed connections like ws
* messages, mqtt messages, or h2 streams */
struct addrinfo *dns_results_copy;
/**< NULL, or Allocated copy of dns results, owned by this object and
* freed when object destroyed.
* Only set if client flag LCCSCF_CONMON applied */
lws_conmon_interval_us_t ciu_dns;
/**< 0, or if a socket connection, us taken to acquire this DNS response
*
*/
lws_conmon_interval_us_t ciu_sockconn;
/**< 0, or if connection-based, the us interval between the socket
* connect() attempt that succeeded, and the connection setup */
lws_conmon_interval_us_t ciu_tls;
/**< 0 if no tls, or us taken to establish the tls tunnel */
lws_conmon_interval_us_t ciu_txn_resp;
/**< 0, or if the protocol supports transactions, the interval between
* sending the initial transaction request and starting to receive the
* response */
lws_conmon_pcol_t pcol;
/**< indicates which extra protocol_specific info member is valid,
* if any */
lws_conmon_dns_disposition_t dns_disposition;
/**< indicates general disposition of DNS request */
};
/**
* lws_conmon_wsi_take() - create a connection latency object from client wsi
*
* \param context: lws wsi
* \param dest: conmon struct to fill
*
* Copies wsi conmon data into the caller's struct. Passes ownership of
* any allocations in the addrinfo list to the caller, lws will not delete that
* any more on wsi close after this call. The caller must call
* lws_conmon_release() on the struct to destroy any addrinfo in the struct
* that is prepared by this eventually but it can defer it as long as it wants.
*
* Other than the addrinfo list, the contents of the returned object are
* completely selfcontained and don't point outside of the object itself, ie,
* everything else in there remains in scope while the object itself does.
*/
LWS_VISIBLE LWS_EXTERN void
lws_conmon_wsi_take(struct lws *wsi, struct lws_conmon *dest);
/**
* lws_conmon_release() - free any allocations in the conmon struct
*
* \param conmon: pointer to conmon struct
*
* Destroys any allocations in the conmon struct so it can go out of scope.
* It doesn't free \p dest itself, it's designed to clean out a struct that
* is on the stack or embedded in another object.
*/
LWS_VISIBLE LWS_EXTERN void
lws_conmon_release(struct lws_conmon *conmon);
///@}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,511 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 cose COSE apis
* ##COSE related functions
* \ingroup lwsaoi
*
* COSE RFC 8152 relates to signed and encrypted CBOR
*/
//@{
enum {
/* RFC8152: Table 2: Common Header Parameters
* https://www.iana.org/assignments/cose/cose.xhtml#header-parameters
*/
LWSCOSE_WKL_ALG = 1, /* int / tstr */
LWSCOSE_WKL_CRIT, /* [+ label ] */
LWSCOSE_WKL_CONTENT_TYPE, /* tstr / uint */
LWSCOSE_WKL_KID, /* bstr */
LWSCOSE_WKL_IV, /* bstr */
LWSCOSE_WKL_IV_PARTIAL, /* bstr */
LWSCOSE_WKL_COUNTERSIG, /* COSE sig(s) */
LWSCOSE_WKL_COUNTERSIG0 = 9, /* bstr */
LWSCOSE_WKL_KID_CONTEXT, /* bstr */
LWSCOSE_WKL_CUPH_NONCE = 256, /* bstr */
LWSCOSE_WKL_CUPH_OWNER_PUBKEY = 257, /* array */
/* RFC8152: Table 3: key map labels */
LWSCOSE_WKK_KTY = 1, /* int / tstr */
LWSCOSE_WKK_KID, /* bstr */
LWSCOSE_WKK_ALG, /* int / tstr */
LWSCOSE_WKK_KEY_OPS, /* [ + (int / tstr) ] */
LWSCOSE_WKK_BASE_IV, /* bstr */
/* RFC8152: Table 4: Key Operation Values */
LWSCOSE_WKKO_SIGN = 1,
LWSCOSE_WKKO_VERIFY,
LWSCOSE_WKKO_ENCRYPT,
LWSCOSE_WKKO_DECRYPT,
LWSCOSE_WKKO_WRAP_KEY,
LWSCOSE_WKKO_UNWRAP_KEY,
LWSCOSE_WKKO_DERIVE_KEY,
LWSCOSE_WKKO_DERIVE_BITS,
LWSCOSE_WKKO_MAC_CREATE,
LWSCOSE_WKKO_MAC_VERIFY,
/* RFC8152: Table 5: ECDSA algs */
LWSCOSE_WKAECDSA_ALG_ES256 = -7,
LWSCOSE_WKAECDSA_ALG_ES384 = -35,
LWSCOSE_WKAECDSA_ALG_ES512 = -36,
/* RFC8152: Table 6: EDDSA algs */
LWSCOSE_WKAEDDSA_ALG_EDDSA = -8,
/* RFC8152: Table 7: HMAC algs */
LWSCOSE_WKAHMAC_256_64 = 4,
LWSCOSE_WKAHMAC_256_256,
LWSCOSE_WKAHMAC_384_384,
LWSCOSE_WKAHMAC_512_512,
/* RFC8152: Table 8: AES algs */
LWSCOSE_WKAAES_128_64 = 14,
LWSCOSE_WKAAES_256_64,
LWSCOSE_WKAAES_128_128 = 25,
LWSCOSE_WKAAES_256_128,
/* RFC8152: Table 9: AES GCM algs */
LWSCOSE_WKAAESGCM_128 = 1,
LWSCOSE_WKAAESGCM_192,
LWSCOSE_WKAAESGCM_256,
/* RFC8152: Table 10: AES CCM algs */
LWSCOSE_WKAAESCCM_16_64_128 = 10,
LWSCOSE_WKAAESCCM_16_64_256,
LWSCOSE_WKAAESCCM_64_64_128,
LWSCOSE_WKAAESCCM_64_64_256,
LWSCOSE_WKAAESCCM_16_128_128,
LWSCOSE_WKAAESCCM_16_128_256,
LWSCOSE_WKAAESCCM_64_128_128,
LWSCOSE_WKAAESCCM_64_128_256,
/* RFC8152: Table 11: CHACHA20 / Poly1305 */
LWSCOSE_WKACHACHA_POLY1305 = 24,
/* RFC8152: Table 13: HKDF param */
LWSCOSE_WKAPHKDF_SALT = -20,
/* RFC8152: Table 14: Context Algorithm Parameters */
LWSCOSE_WKAPCTX_PARTY_U_IDENTITY = -21,
LWSCOSE_WKAPCTX_PARTY_U_NONCE = -22,
LWSCOSE_WKAPCTX_PARTY_U_OTHER = -23,
LWSCOSE_WKAPCTX_PARTY_V_IDENTITY = -24,
LWSCOSE_WKAPCTX_PARTY_V_NONCE = -25,
LWSCOSE_WKAPCTX_PARTY_V_OTHER = -26,
/* RFC8152: Table 15: Direct key */
LWSCOSE_WKK_DIRECT_CEK = -6,
/* RFC8152: Table 16: Direct key with KDF */
LWSCOSE_WKK_DIRECT_HKDF_SHA_256 = -10,
LWSCOSE_WKK_DIRECT_HKDF_SHA_512 = -11,
LWSCOSE_WKK_DIRECT_HKDF_AES_128 = -12,
LWSCOSE_WKK_DIRECT_HKDF_AES_256 = -13,
/* RFC8152: Table 17: AES Key Wrap Algorithm Values */
LWSCOSE_WKK_DIRECT_HKDFKW_SHA_256 = -3,
LWSCOSE_WKK_DIRECT_HKDFKW_SHA_512 = -4,
LWSCOSE_WKK_DIRECT_HKDFKW_AES_128 = -5,
/* RFC8152: Table 18: ECDH Algorithm Values */
LWSCOSE_WKAECDH_ALG_ES_HKDF_256 = -25,
LWSCOSE_WKAECDH_ALG_ES_HKDF_512 = -26,
LWSCOSE_WKAECDH_ALG_SS_HKDF_256 = -27,
LWSCOSE_WKAECDH_ALG_SS_HKDF_512 = -28,
/* RFC8152: Table 19: ECDH Algorithm Parameters */
LWSCOSE_WKAPECDH_EPHEMERAL_KEY = -1,
LWSCOSE_WKAPECDH_STATIC_KEY = -2,
LWSCOSE_WKAPECDH_STATIC_KEY_ID = -3,
/* RFC8152: Table 20: ECDH Algorithm Parameters with key wrap */
LWSCOSE_WKAPECDH_ES_A128KW = -29,
LWSCOSE_WKAPECDH_ES_A192KW = -30,
LWSCOSE_WKAPECDH_ES_A256KW = -31,
LWSCOSE_WKAPECDH_SS_A128KW = -32,
LWSCOSE_WKAPECDH_SS_A192KW = -33,
LWSCOSE_WKAPECDH_SS_A256KW = -34,
/* RFC8152: Table 21: Key Type Values
* https://www.iana.org/assignments/cose/cose.xhtml#key-type
*/
LWSCOSE_WKKTV_OKP = 1,
LWSCOSE_WKKTV_EC2 = 2,
LWSCOSE_WKKTV_RSA = 3,
LWSCOSE_WKKTV_SYMMETRIC = 4,
LWSCOSE_WKKTV_HSS_LMS = 5,
LWSCOSE_WKKTV_WALNUTDSA = 6,
/* RFC8152: Table 22: Elliptic Curves
* https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
*/
LWSCOSE_WKEC_P256 = 1,
LWSCOSE_WKEC_P384,
LWSCOSE_WKEC_P521,
LWSCOSE_WKEC_X25519,
LWSCOSE_WKEC_X448,
LWSCOSE_WKEC_ED25519,
LWSCOSE_WKEC_ED448,
LWSCOSE_WKEC_SECP256K1,
/* RFC8152: Table 23: EC Key Parameters */
LWSCOSE_WKECKP_CRV = -1,
LWSCOSE_WKECKP_X = -2,
LWSCOSE_WKECKP_Y = -3,
LWSCOSE_WKECKP_D = -4,
/* RFC8152: Table 24: Octet Key Pair (OKP) Parameters */
LWSCOSE_WKOKP_CRV = -1,
LWSCOSE_WKOKP_X = -2,
LWSCOSE_WKOKP_D = -4,
/* Additional from
* https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters
*/
LWSCOSE_WKKPRSA_N = -1,
LWSCOSE_WKKPRSA_E = -2,
LWSCOSE_WKKPRSA_D = -3,
LWSCOSE_WKKPRSA_P = -4,
LWSCOSE_WKKPRSA_Q = -5,
LWSCOSE_WKKPRSA_DP = -6,
LWSCOSE_WKKPRSA_DQ = -7,
LWSCOSE_WKKPRSA_QINV = -8,
LWSCOSE_WKKPRSA_OTHER = -9,
LWSCOSE_WKKPRSA_RI = -10,
LWSCOSE_WKKPRSA_DI = -11,
LWSCOSE_WKKPRSA_TI = -12,
/* RFC8152: Table 25: Symmetric Key Parameters */
LWSCOSE_WKSYMKP_KEY_VALUE = 4,
/* RFC8152: Table 26: CoAP Content-Formats for COSE */
LWSCOAP_CONTENTFORMAT_COSE_SIGN = 98,
LWSCOAP_CONTENTFORMAT_COSE_SIGN1 = 18,
LWSCOAP_CONTENTFORMAT_COSE_ENCRYPT = 96,
LWSCOAP_CONTENTFORMAT_COSE_ENCRYPT0 = 16,
LWSCOAP_CONTENTFORMAT_COSE_MAC = 97,
LWSCOAP_CONTENTFORMAT_COSE_MAC0 = 17,
LWSCOAP_CONTENTFORMAT_COSE_KEY = 101,
LWSCOAP_CONTENTFORMAT_COSE_KEY_SET = 102,
/* RFC8152: Table 27: Header Parameter for CounterSignature0 */
LWSCOSE_WKL_COUNTERSIGNATURE0 = 9, /* bstr */
/* RFC8812: Table 1: RSASSA-PKCS1-v1_5 Algorithm Values */
LWSCOSE_WKARSA_ALG_RS256 = -257, /* + SHA-256 */
LWSCOSE_WKARSA_ALG_RS384 = -258, /* + SHA-384 */
LWSCOSE_WKARSA_ALG_RS512 = -259, /* + SHA-512 */
};
enum enum_cose_key_meta_tok {
COSEKEY_META_KTY,
COSEKEY_META_KID,
COSEKEY_META_KEY_OPS,
COSEKEY_META_BASE_IV,
COSEKEY_META_ALG,
LWS_COUNT_COSE_KEY_ELEMENTS
};
typedef int64_t cose_param_t;
LWS_VISIBLE LWS_EXTERN const char *
lws_cose_alg_to_name(cose_param_t alg);
LWS_VISIBLE LWS_EXTERN cose_param_t
lws_cose_name_to_alg(const char *name);
/*
* cose_key
*/
typedef struct lws_cose_key {
/* key data elements */
struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_MAX_KEYEL_COUNT];
/* generic meta key elements, like KID */
struct lws_gencrypto_keyelem meta[LWS_COUNT_COSE_KEY_ELEMENTS];
lws_dll2_t list; /* used when part of a set */
int gencrypto_kty; /**< one of LWS_GENCRYPTO_KTY_ */
cose_param_t kty;
cose_param_t cose_alg;
cose_param_t cose_curve;
char private_key; /* nonzero = has private key elements */
} lws_cose_key_t;
typedef int (*lws_cose_key_import_callback)(struct lws_cose_key *s, void *user);
/** lws_cose_jwk_import() - Create an lws_cose_key_t object from cose_key CBOR
*
* \param pkey_set: NULL, or a pointer to an lws_dll2_owner_t for a cose_key set
* \param cb: callback for each jwk-processed key, or NULL if importing a single
* key with no parent "keys" JSON
* \param user: pointer to be passed to the callback, otherwise ignored by lws.
* NULL if importing a single key with no parent "keys" JSON
* \param in: a single cose_key
* \param len: the length of the cose_key in bytes
*
* Creates a single lws_cose_key_t if \p pkey_set is NULL or if the incoming
* CBOR doesn't start with an array, otherwise expects a CBOR array containing
* zero or more cose_key CBOR, and adds each to the \p pkey_set
* lws_dll2_owner_t struct. Created lws_cose_key_t are filled with data from
* the COSE representation and can be used with other COSE crypto ops.
*/
LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
lws_cose_key_import(lws_dll2_owner_t *pkey_set, lws_cose_key_import_callback cb,
void *user, const uint8_t *in, size_t len);
/** lws_cose_key_export() - Create cose_key CBOR from an lws_cose_key_t
*
* \param ck: the lws_cose_key_t to export to CBOR
* \param ctx: the CBOR writing context (same as for lws_lec_printf())
* \param flags: 0 to export only public elements, or LWSJWKF_EXPORT_PRIVATE
*
* Creates an lws_jwk struct filled with data from the COSE representation.
*/
LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
lws_cose_key_export(lws_cose_key_t *ck, lws_lec_pctx_t *ctx, int flags);
/**
* lws_cose_key_generate() - generate a fresh key
*
* \param context: the lws_context used to get random
* \param cose_kty: one of LWSCOSE_WKKTV_ indicating the well-known key type
* \param use_mask: 0, or a bitfield where (1 << LWSCOSE_WKKO_...) set means valid for use
* \param bits: key bits for RSA
* \param curve: for EC keys, one of "P-256", "P-384" or "P-521" currently
* \param kid: string describing the key, or NULL
*
* Create an lws_cose_key_t of the specified type and return it
*/
LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
lws_cose_key_generate(struct lws_context *context, cose_param_t cose_kty,
int use_mask, int bits, const char *curve,
const uint8_t *kid, size_t kl);
LWS_VISIBLE LWS_EXTERN lws_cose_key_t *
lws_cose_key_from_set(lws_dll2_owner_t *set, const uint8_t *kid, size_t kl);
LWS_VISIBLE LWS_EXTERN void
lws_cose_key_destroy(lws_cose_key_t **ck);
LWS_VISIBLE LWS_EXTERN void
lws_cose_key_set_destroy(lws_dll2_owner_t *o);
/* only available in _DEBUG build */
LWS_VISIBLE LWS_EXTERN void
lws_cose_key_dump(const lws_cose_key_t *ck);
/*
* cose_sign
*/
struct lws_cose_validate_context;
enum lws_cose_sig_types {
SIGTYPE_UNKNOWN,
SIGTYPE_MULTI,
SIGTYPE_SINGLE,
SIGTYPE_COUNTERSIGNED, /* not yet supported */
SIGTYPE_MAC, /* only supported for validation */
SIGTYPE_MAC0,
};
/* a list of these result objects is the output of the validation process */
typedef struct {
lws_dll2_t list;
const lws_cose_key_t *cose_key;
cose_param_t cose_alg;
int result; /* 0 = validated */
} lws_cose_validate_res_t;
enum {
LCOSESIGEXTCB_RET_FINISHED,
LCOSESIGEXTCB_RET_AGAIN,
LCOSESIGEXTCB_RET_ERROR = -1
};
typedef struct {
struct lws_cose_validate_context *cps;
const uint8_t *ext;
size_t xl;
} lws_cose_sig_ext_pay_t;
typedef int (*lws_cose_sign_ext_pay_cb_t)(lws_cose_sig_ext_pay_t *x);
typedef int (*lws_cose_validate_pay_cb_t)(struct lws_cose_validate_context *cps,
void *opaque, const uint8_t *paychunk,
size_t paychunk_len);
typedef struct lws_cose_validate_create_info {
struct lws_context *cx;
/**< REQUIRED: the lws context */
lws_dll2_owner_t *keyset;
/**< REQUIRED: one or more cose_keys */
enum lws_cose_sig_types sigtype;
/**< 0 if a CBOR tag is in the sig, else one of SIGTYPE_MULTI,
* SIGTYPE_SINGLE, etc*/
lws_cose_validate_pay_cb_t pay_cb;
/**< optional: called back with unvalidated payload pieces */
void *pay_opaque;
/**< optional: passed into pay_cb callback along with payload chunk */
lws_cose_sign_ext_pay_cb_t ext_cb;
/**< optional extra application data provision callback */
void *ext_opaque;
/**< optional extra application data provision callback opaque */
size_t ext_len;
/**< if we have extra app data, this must be set to the length of it */
} lws_cose_validate_create_info_t;
/**
* lws_cose_validate_create() - create a signature validation context
*
* \param info: struct describing the validation context to create
*
* Creates a signature validation context set up as described in \p info.
*
* You can then pass the signature cbor chunks to it using
* lws_cose_validate_chunk(), finialize and get the results list using
* lws_cose_validate_results() and destroy with lws_cose_validate_destroy().
*/
LWS_VISIBLE LWS_EXTERN struct lws_cose_validate_context *
lws_cose_validate_create(const lws_cose_validate_create_info_t *info);
/**
* lws_cose_validate_chunk() - passes chunks of CBOR into the signature validator
*
* \param cps: the validation context
* \param in: the chunk of CBOR (does not have to be logically complete)
* \param in_len: number of bytes available at \p in
*
* Parses signature CBOR to produce a list of result objects.
*
*
*/
LWS_VISIBLE LWS_EXTERN int
lws_cose_validate_chunk(struct lws_cose_validate_context *cps,
const uint8_t *in, size_t in_len, size_t *used_in);
LWS_VISIBLE LWS_EXTERN lws_dll2_owner_t *
lws_cose_validate_results(struct lws_cose_validate_context *cps);
LWS_VISIBLE LWS_EXTERN void
lws_cose_validate_destroy(struct lws_cose_validate_context **cps);
struct lws_cose_sign_context;
#define LCSC_FL_ADD_CBOR_TAG (1 << 0)
#define LCSC_FL_ADD_CBOR_PREFER_MAC0 (1 << 1)
typedef struct lws_cose_sign_create_info {
struct lws_context *cx;
/**< REQUIRED: the lws context */
lws_dll2_owner_t *keyset;
/**< REQUIRED: one or more cose_keys */
lws_lec_pctx_t *lec;
/**< REQUIRED: the cbor output context to emit to, user must
* initialize with lws_lec_init() beforehand */
lws_cose_sign_ext_pay_cb_t ext_cb;
/**< optional extra application data provision callback */
void *ext_opaque;
/**< optional extra application data provision callback opaque */
size_t ext_len;
/**< if we have extra app data, this must be set to the length of it */
size_t inline_payload_len;
/**< REQUIRED: size of the inline payload we will provide */
int flags;
/**< bitmap of LCSC_FL_* */
enum lws_cose_sig_types sigtype;
/**< 0, or sign type hint */
} lws_cose_sign_create_info_t;
/**
* lws_cose_sign_create() - Create a signing context
*
* \param info: a structure describing the signing context you want to create
*
* This allocates and returns a signing context created according to what is in
* the \p info parameter.
*
* \p info must be prepared with the lws_context, a keyset to use, a CBOR
* output context, and the inline payload length.
*
* Returns NULL on failure or the created signing context ready to add alg(s)
* to.
*/
LWS_VISIBLE LWS_EXTERN struct lws_cose_sign_context *
lws_cose_sign_create(const lws_cose_sign_create_info_t *info);
LWS_VISIBLE LWS_EXTERN int
lws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
const lws_cose_key_t *ck);
LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
const uint8_t *in, size_t in_len);
LWS_VISIBLE LWS_EXTERN void
lws_cose_sign_destroy(struct lws_cose_sign_context **csc);
//@}

View File

@ -0,0 +1,94 @@
/*
* 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.
*
* must be included manually as
*
* #include <libwebsockets/lws-dbus.h>
*
* if dbus apis needed
*/
#if !defined(__LWS_DBUS_H__)
#define __LWS_DBUS_H__
#include <dbus/dbus.h>
/* helper type to simplify implementing methods as individual functions */
typedef DBusHandlerResult (*lws_dbus_message_handler)(DBusConnection *conn,
DBusMessage *message, DBusMessage **reply, void *d);
struct lws_dbus_ctx;
typedef void (*lws_dbus_closing_t)(struct lws_dbus_ctx *ctx);
struct lws_dbus_ctx {
struct lws_dll2_owner owner; /* dbusserver ctx: HEAD of accepted list */
struct lws_dll2 next; /* dbusserver ctx: HEAD of accepted list */
struct lws_vhost *vh; /* the vhost we logically bind to in lws */
int tsi; /* the lws thread service index (0 if only one service
thread as is the default */
DBusConnection *conn;
DBusServer *dbs;
DBusWatch *w[4];
DBusPendingCall *pc;
char hup;
char timeouts;
/* cb_closing callback will be called after the connection and this
* related ctx struct have effectively gone out of scope.
*
* The callback should close and clean up the connection and free the
* ctx.
*/
lws_dbus_closing_t cb_closing;
};
/**
* lws_dbus_connection_setup() - bind dbus connection object to lws event loop
*
* \param ctx: additional information about the connection
* \param conn: the DBusConnection object to bind
*
* This configures a DBusConnection object to use lws for watchers and timeout
* operations.
*/
LWS_VISIBLE LWS_EXTERN int
lws_dbus_connection_setup(struct lws_dbus_ctx *ctx, DBusConnection *conn,
lws_dbus_closing_t cb_closing);
/**
* lws_dbus_server_listen() - bind dbus connection object to lws event loop
*
* \param ctx: additional information about the connection
* \param ads: the DBUS address to listen on, eg, "unix:abstract=mysocket"
* \param err: a DBusError object to take any extra error information
* \param new_conn: a callback function to prepare new accepted connections
*
* This creates a DBusServer and binds it to the lws event loop, and your
* callback to accept new connections.
*/
LWS_VISIBLE LWS_EXTERN DBusServer *
lws_dbus_server_listen(struct lws_dbus_ctx *ctx, const char *ads,
DBusError *err, DBusNewConnectionFunction new_conn);
#endif

View File

@ -0,0 +1,187 @@
/*
* 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 diskcache LWS disk cache
* ## Disk cache API
*
* Lws provides helper apis useful if you need a disk cache containing hashed
* files and need to delete files from it on an LRU basis to keep it below some
* size limit.
*
* The API `lws_diskcache_prepare()` deals with creating the cache dir and
* 256 subdirs, which are used according to the first two chars of the hex
* hash of the cache file.
*
* `lws_diskcache_create()` and `lws_diskcache_destroy()` allocate and free
* an opaque struct that represents the disk cache.
*
* `lws_diskcache_trim()` should be called at eg, 1s intervals to perform the
* cache dir monitoring and LRU autodelete in the background lazily. It can
* be done in its own thread or on a timer... it monitors the directories in a
* stateful way that stats one or more file in the cache per call, and keeps
* a list of the oldest files as it goes. When it completes a scan, if the
* aggregate size is over the limit, it will delete oldest files first to try
* to keep it under the limit.
*
* The cache size monitoring is extremely efficient in time and memory even when
* the cache directory becomes huge.
*
* `lws_diskcache_query()` is used to determine if the file already exists in
* the cache, or if it must be created. If it must be created, then the file
* is opened using a temp name that must be converted to a findable name with
* `lws_diskcache_finalize_name()` when the generation of the file contents are
* complete. Aborted cached files that did not complete generation will be
* flushed by the LRU eventually. If the file already exists, it is 'touched'
* to make it new again and the fd returned.
*
*/
///@{
struct lws_diskcache_scan;
/**
* lws_diskcache_create() - creates an opaque struct representing the disk cache
*
* \param cache_dir_base: The cache dir path, eg `/var/cache/mycache`
* \param cache_size_limit: maximum size on disk the cache is allowed to use
*
* This returns an opaque `struct lws_diskcache_scan *` which represents the
* disk cache, the trim scanning state and so on. You should use
* `lws_diskcache_destroy()` to free it to destroy it.
*/
LWS_VISIBLE LWS_EXTERN struct lws_diskcache_scan *
lws_diskcache_create(const char *cache_dir_base, uint64_t cache_size_limit);
/**
* lws_diskcache_destroy() - destroys the pointer returned by ...create()
*
* \param lds: pointer to the pointer returned by lws_diskcache_create()
*
* Frees *lds and any allocations it did, and then sets *lds to NULL and
* returns.
*/
LWS_VISIBLE LWS_EXTERN void
lws_diskcache_destroy(struct lws_diskcache_scan **lds);
/**
* lws_diskcache_prepare() - ensures the cache dir structure exists on disk
*
* \param cache_base_dir: The cache dir path, eg `/var/cache/mycache`
* \param mode: octal dir mode to enforce, like 0700
* \param uid: uid the cache dir should belong to
*
* This should be called while your app is still privileged. It will create
* the cache directory structure on disk as necessary, enforce the given access
* mode on it and set the given uid as the owner. It won't make any trouble
* if the cache already exists.
*
* Typically the mode is 0700 and the owner is the user that your application
* will transition to use when it drops root privileges.
*/
LWS_VISIBLE LWS_EXTERN int
lws_diskcache_prepare(const char *cache_base_dir, int mode, uid_t uid);
#define LWS_DISKCACHE_QUERY_NO_CACHE 0
#define LWS_DISKCACHE_QUERY_EXISTS 1
#define LWS_DISKCACHE_QUERY_CREATING 2
#define LWS_DISKCACHE_QUERY_ONGOING 3 /* something else is creating it */
/**
* lws_diskcache_query() - ensures the cache dir structure exists on disk
*
* \param lds: The opaque struct representing the disk cache
* \param is_bot: nonzero means the request is from a bot. Don't create new cache contents if so.
* \param hash_hex: hex string representation of the cache object hash
* \param _fd: pointer to the fd to be set
* \param cache: destination string to take the cache filepath
* \param cache_len: length of the buffer at `cache`
* \param extant_cache_len: pointer to a size_t to take any extant cached file size
*
* This function is called when you want to find if the hashed name already
* exists in the cache. The possibilities for the return value are
*
* - LWS_DISKCACHE_QUERY_NO_CACHE: It's not in the cache and you can't create
* it in the cache for whatever reason.
* - LWS_DISKCACHE_QUERY_EXISTS: It exists in the cache. It's open RDONLY and
* *_fd has been set to the file descriptor. *extant_cache_len has been set
* to the size of the cached file in bytes. cache has been set to the
* full filepath of the cached file. Closing _fd is your responsibility.
* - LWS_DISKCACHE_QUERY_CREATING: It didn't exist, but a temp file has been
* created in the cache and *_fd set to a file descriptor opened on it RDWR.
* You should create the contents, and call `lws_diskcache_finalize_name()`
* when it is done. Closing _fd is your responsibility.
* - LWS_DISKCACHE_QUERY_ONGOING: not returned by this api, but you may find it
* desirable to make a wrapper function which can handle another asynchronous
* process that is already creating the cached file. This can be used to
* indicate that situation externally... how to determine the same thing is
* already being generated is out of scope of this api.
*/
LWS_VISIBLE LWS_EXTERN int
lws_diskcache_query(struct lws_diskcache_scan *lds, int is_bot,
const char *hash_hex, int *_fd, char *cache, int cache_len,
size_t *extant_cache_len);
/**
* lws_diskcache_query() - ensures the cache dir structure exists on disk
*
* \param cache: The cache file temp name returned with LWS_DISKCACHE_QUERY_CREATING
*
* This renames the cache file you are creating to its final name. It should
* be called on the temp name returned by `lws_diskcache_query()` if it gave a
* LWS_DISKCACHE_QUERY_CREATING return, after you have filled the cache file and
* closed it.
*/
LWS_VISIBLE LWS_EXTERN int
lws_diskcache_finalize_name(char *cache);
/**
* lws_diskcache_trim() - performs one or more file checks in the cache for size management
*
* \param lds: The opaque object representing the cache
*
* This should be called periodically to statefully walk the cache on disk
* collecting the oldest files. When it has visited every file, if the cache
* is oversize it will delete the oldest files until it's back under size again.
*
* Each time it's called, it will look at one or more dir in the cache. If
* called when the cache is oversize, it increases the amount of work done each
* call until it is reduced again. Typically it will take 256 calls before it
* deletes anything, so if called once per second, it will delete files once
* every 4 minutes. Each call is very inexpensive both in memory and time.
*/
LWS_VISIBLE LWS_EXTERN int
lws_diskcache_trim(struct lws_diskcache_scan *lds);
/**
* lws_diskcache_secs_to_idle() - see how long to idle before calling trim
*
* \param lds: The opaque object representing the cache
*
* If the cache is undersize, there's no need to monitor it immediately. This
* suggests how long to "sleep" before calling `lws_diskcache_trim()` again.
*/
LWS_VISIBLE LWS_EXTERN int
lws_diskcache_secs_to_idle(struct lws_diskcache_scan *lds);
///@}

View File

@ -0,0 +1,224 @@
/*
* lws abstract display
*
* Copyright (C) 2019 - 2022 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.
*/
#if !defined(__LWS_DISPLAY_H__)
#define __LWS_DISPLAY_H__
typedef int16_t lws_display_list_coord_t;
typedef uint16_t lws_display_scalar;
typedef uint16_t lws_display_rotation_t;
typedef uint32_t lws_display_colour_t;
typedef uint16_t lws_display_palette_idx_t;
typedef struct lws_box {
lws_fx_t x;
lws_fx_t y;
lws_fx_t w;
lws_fx_t h;
} lws_box_t;
struct lws_display_state;
struct lws_display;
typedef enum {
LWSSURF_TRUECOLOR32,
LWSSURF_565,
LWSSURF_PALETTE,
LWSSURF_QUANTIZED_4BPP
} lws_surface_type_t;
typedef struct lws_surface_info {
lws_fx_t wh_px[2];
lws_fx_t wh_mm[2];
const lws_display_colour_t *palette;
size_t palette_depth;
lws_surface_type_t type;
uint8_t greyscale:1; /* line: 0 = RGBA, 1 = YA */
uint8_t partial:1; /* can handle partial */
uint8_t render_to_rgba:1; /* render to 32-bit RGBA, not 24-bit RGB */
} lws_surface_info_t;
typedef struct lws_greyscale_error {
int16_t rgb[1];
} lws_greyscale_error_t;
typedef struct lws_colour_error {
int16_t rgb[3];
} lws_colour_error_t;
typedef union {
lws_greyscale_error_t grey; /* when ic->greyscale set */
lws_colour_error_t colour; /* when ic->greyscale == 0 */
} lws_surface_error_t;
LWS_VISIBLE LWS_EXTERN void
lws_surface_set_px(const lws_surface_info_t *ic, uint8_t *line, int x,
const lws_display_colour_t *c);
LWS_VISIBLE LWS_EXTERN lws_display_palette_idx_t
lws_display_palettize_grey(const lws_surface_info_t *ic,
const lws_display_colour_t *palette, size_t pdepth,
lws_display_colour_t c, lws_greyscale_error_t *ectx);
LWS_VISIBLE LWS_EXTERN lws_display_palette_idx_t
lws_display_palettize_col(const lws_surface_info_t *ic,
const lws_display_colour_t *palette, size_t pdepth,
lws_display_colour_t c, lws_colour_error_t *ectx);
/*
* This is embedded in the actual display implementation object at the top,
* so a pointer to this can be cast to a pointer to the implementation object
* by any code that is specific to how it was implemented.
*
* Notice for the backlight / display intensity we contain pwm_ops... these can
* be some other pwm_ops like existing gpio pwm ops, or handled in a customized
* way like set oled contrast. Either way, the pwm level is arrived at via a
* full set of lws_led_sequences capable of generic lws transitions
*/
typedef struct lws_display {
int (*init)(struct lws_display_state *lds);
const lws_pwm_ops_t *bl_pwm_ops;
int (*contrast)(struct lws_display_state *lds, uint8_t contrast);
int (*blit)(struct lws_display_state *lds, const uint8_t *src,
lws_box_t *box, lws_dll2_owner_t *ids);
int (*power)(struct lws_display_state *lds, int state);
const lws_led_sequence_def_t *bl_active;
const lws_led_sequence_def_t *bl_dim;
const lws_led_sequence_def_t *bl_transition;
const char *name;
void *variant;
int bl_index;
lws_surface_info_t ic;
uint16_t latency_wake_ms;
/**< ms required after wake from sleep before display usable again...
* delay bringing up the backlight for this amount of time on wake.
* This is managed via a sul on the event loop, not blocking. */
uint16_t latency_update_ms;
/**< nominal update latency in ms */
} lws_display_t;
/*
* This contains dynamic data related to display state
*/
enum lws_display_controller_state {
LWSDISPS_OFF,
LWSDISPS_AUTODIMMED, /* is in pre- blanking static dim mode */
LWSDISPS_BECOMING_ACTIVE, /* waiting for wake latency before active */
LWSDISPS_ACTIVE, /* is active */
LWSDISPS_GOING_OFF /* dimming then off */
};
typedef struct lws_display_state {
lws_sorted_usec_list_t sul_autodim;
char current_url[96];
const lws_display_t *disp;
struct lws_context *ctx;
void *priv; /* subclass driver alloc'd priv */
int autodim_ms;
int off_ms;
struct lws_led_state *bl_lcs;
lws_led_state_chs_t chs;
/* set of sequencer transition channels */
enum lws_display_controller_state state;
char display_busy;
} lws_display_state_t;
/* Used for async display driver events, eg, EPD refresh completion */
typedef int (*lws_display_completion_t)(lws_display_state_t *lds, int a);
/**
* lws_display_state_init() - initialize display states
*
* \param lds: the display state object
* \param ctx: the lws context
* \param autodim_ms: ms since last active report to dim display (<0 = never)
* \param off_ms: ms since dim to turn display off (<0 = never)
* \param bl_lcs: the led controller instance that has the backlight
* \param disp: generic display object we belong to
*
* This initializes a display's state, and sets up the optional screen auto-dim
* and blanking on inactive, and gradual brightness change timer.
*
* - auto-dim then off: set autodim to some ms and off_ms to some ms
* - auto-dim only: set autodim to some ms and off_ms to -1
* - off-only: set autodim to some ms and off_ms to 0
* - neither: set both autodim and off_ms to -1
*/
LWS_VISIBLE LWS_EXTERN void
lws_display_state_init(lws_display_state_t *lds, struct lws_context *ctx,
int autodim_ms, int off_ms, struct lws_led_state *bl_lcs,
const lws_display_t *disp);
/**
* lws_display_state_set_brightness() - gradually change the brightness
*
* \param lds: the display state we are changing
* \param target: the target brightness to transition to
*
* Adjusts the brightness gradually twoards the target at 20Hz
*/
LWS_VISIBLE LWS_EXTERN void
lws_display_state_set_brightness(lws_display_state_t *lds,
const lws_led_sequence_def_t *pwmseq);
/*
* lws_display_state_active() - inform the system the display is active
*
* \param lds: the display state we are marking as active
*
* Resets the auto-dim and auto-off timers and makes sure the display is on and
* at the active brightness level
*/
LWS_VISIBLE LWS_EXTERN void
lws_display_state_active(lws_display_state_t *lds);
/*
* lws_display_state_off() - turns off the related display
*
* \param lds: the display state we are turning off
*
* Turns the display to least power mode or completely off if possible.
* Disables the timers related to dimming and blanking.
*/
LWS_VISIBLE LWS_EXTERN void
lws_display_state_off(lws_display_state_t *lds);
#endif

View File

@ -0,0 +1,308 @@
/*
* 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
*/
/*
* 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;
LWS_VISIBLE LWS_EXTERN int
lws_dll2_is_detached(const struct lws_dll2 *d);
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);
typedef int (*lws_dll2_foreach_cb_t)(struct lws_dll2 *d, void *user);
LWS_VISIBLE LWS_EXTERN int
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
lws_dll2_foreach_cb_t cb);
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_insert(struct lws_dll2 *d, struct lws_dll2 *prev);
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));
LWS_VISIBLE LWS_EXTERN void
lws_dll2_add_sorted_priv(lws_dll2_t *d, lws_dll2_owner_t *own, void *priv,
int (*compare3)(void *priv, const lws_dll2_t *d,
const lws_dll2_t *i));
LWS_VISIBLE LWS_EXTERN void *
_lws_dll2_search_sz_pl(lws_dll2_owner_t *own, const char *name, size_t namelen,
size_t dll2_ofs, size_t ptr_ofs);
/*
* Searches objects in an owner list linearly and returns one with a given
* member C-string matching a supplied length-provided string if it exists, else
* NULL.
*/
#define lws_dll2_search_sz_pl(own, name, namelen, type, membd2list, membptr) \
((type *)_lws_dll2_search_sz_pl(own, name, namelen, \
offsetof(type, membd2list), \
offsetof(type, membptr)))
#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; \
} \
}
///@}

View File

@ -0,0 +1,524 @@
/*
* lws abstract display
*
* Copyright (C) 2019 - 2022 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.
*
* lws display_list and display_list objects (dlo)
*/
#if !defined(__LWS_DLO_H__)
#define __LWS_DLO_H__
#include <stdint.h>
struct lws_display_render_state;
struct lws_surface_info;
struct lws_display_state;
struct lws_display_font;
struct lws_dlo_text;
struct lws_display;
struct lws_dlo_text;
struct lws_dlo;
#define LWSDC_RGBA(_r, _g, _b, _a) (((uint32_t)(_r) & 0xff) | \
(((uint32_t)(_g) & 0xff) << 8) | \
(((uint32_t)(_b) & 0xff) << 16) | \
(((uint32_t)(_a) & 0xff) << 24))
#define LWSDC_R(_c) ((_c) & 0xff)
#define LWSDC_G(_c) ((_c >> 8) & 0xff)
#define LWSDC_B(_c) ((_c >> 16) & 0xff)
#define LWSDC_ALPHA(_c) ((_c >> 24) & 0xff)
#define RGB_TO_Y(_r, _g, _b) ((((_r) * 299) + ((_g) * 587) + ((_b) * 114)) / 1000)
/* stores Y in RGBY */
#define PALETTE_RGBY(_r, _g, _b) LWSDC_RGBA(_r, _g, _b, (RGB_TO_Y(_r, _g, _b)))
typedef struct {
lws_fx_t w;
lws_fx_t h;
} lws_dlo_dim_t;
/*
* When using RGBA to describe native greyscale, R is Y and A is A, GB is ignored
*/
/* composed at start of larger, font-specific glyph struct */
typedef struct lws_font_glyph {
lws_dll2_t list;
lws_fx_t xorg;
lws_fx_t xpx;
lws_fx_t height;
lws_fx_t cwidth;
int8_t x; /* x offset inside the glyph */
} lws_font_glyph_t;
typedef lws_stateful_ret_t (*lws_dlo_renderer_t)(struct lws_display_render_state *rs);
typedef lws_font_glyph_t * (*lws_dlo_image_glyph_t)(
struct lws_dlo_text *text,
uint32_t unicode, char attach);
typedef void (*lws_dlo_destroy_t)(struct lws_dlo *dlo);
typedef struct lws_display_id {
lws_dll2_t list;
char id[16];
lws_box_t box; /* taken from DLO after layout */
void *priv_user;
void *priv_driver;
char exists;
char iframe; /* 1 = render html as if partial
* is the origin, otherwise
* render html with surface
* (0,0) as origin and rs->box
* is a viewport on to that */
} lws_display_id_t;
/*
* Common dlo object that joins the display list, composed into a subclass
* object like lws_dlo_rect_t etc
*/
typedef struct lws_dlo {
lws_dll2_t list;
lws_dll2_t col_list; /* lws_dlo_t: column-mates */
lws_dll2_t row_list; /* lws_dlo_t: row-mates */
/* children are rendered "inside" the parent DLO box after allowing
* for parent padding */
lws_dll2_owner_t children;
/* only used for dlo rect representing whole table */
lws_dll2_owner_t table_cols; /* lhp_table_col_t */
lws_dll2_owner_t table_rows; /* lhp_table_row_t */
/* may point to dlo whose width or height decides our x or y */
struct lws_dlo *abut_x;
struct lws_dlo *abut_y;
lws_dlo_destroy_t _destroy; /* dlo-type specific cb */
lws_dlo_renderer_t render; /* dlo-type specific cb */
lws_fx_t margin[4];
lws_fx_t padding[4]; /* child origin */
lws_display_id_t *id; /* only valid until ids destroyed */
lws_box_t box;
lws_display_colour_t dc;
uint8_t flag_runon:1; /* continues same line */
uint8_t flag_done_align:1;
uint8_t flag_toplevel:1; /* don't scan up with me (different owner) */
/* render-specific members ... */
} lws_dlo_t;
typedef struct lws_circle {
lws_fx_t r;
/* rasterization temps */
lws_fx_t orx; /* abs pixel x for centre */
lws_fx_t ory; /* abs pixel y for centre */
lws_fx_t rsq;
lws_fx_t ys;
} lws_circle_t;
typedef struct lws_dlo_rect {
lws_dlo_t dlo;
lws_circle_t c[4]; /* t-l, t-r, b-l, b-r */
lws_fx_t b[4]; /* border width on t/r/b/l */
lws_display_colour_t dcb; /* border colour */
/* rasterization temps */
lws_fx_t btm;
lws_fx_t right;
lws_box_t db;
uint8_t init;
uint8_t alt;
} lws_dlo_rect_t;
typedef struct lws_dlo_circle {
lws_dlo_t dlo;
} lws_dlo_circle_t;
typedef struct lws_font_choice {
const char *family_name;
const char *generic_name;
uint16_t weight;
uint16_t style; /* normal, italic, oblique */
uint16_t fixed_height;
} lws_font_choice_t;
typedef struct lws_display_font {
lws_dll2_t list;
lws_font_choice_t choice;
const uint8_t *data; /* may be cast to imp struct */
uint8_t *priv; /* only used by implementation */
size_t data_len;
lws_dlo_renderer_t renderer;
lws_dlo_image_glyph_t image_glyph;
lws_fx_t em; /* 1 em in pixels */
lws_fx_t ex; /* 1 ex in pixels */
} lws_display_font_t;
typedef struct lws_dlo_filesystem {
lws_dll2_t list;
const char *name;
const void *data;
size_t len;
} lws_dlo_filesystem_t;
#define LWSDLO_TEXT_FLAG_WRAP (1 << 0)
typedef struct lws_dlo_text {
lws_dlo_t dlo;
const lws_display_font_t *font;
lws_dll2_owner_t glyphs;
lws_box_t bounding_box; /* { 0, 0, w, h } relative
* to and subject to
* clipping by .dlo.box */
/* referred to by glyphs */
const struct lws_surface_info *ic;
struct lwsac *ac_glyphs;
uint8_t *line;
uint16_t curr;
char *text;
uint8_t *kern;
size_t text_len;
lws_display_list_coord_t clkernpx;
lws_display_list_coord_t cwidth;
lws_fx_t indent;
uint32_t flags;
int16_t font_y_baseline;
int16_t font_height;
int16_t font_line_height;
int16_t group_height;
int16_t group_y_baseline;
lws_fx_t _cwidth;
} lws_dlo_text_t;
typedef struct lws_dlo_rasterize {
lws_dll2_owner_t owner; /* lws_flow_t */
lws_sorted_usec_list_t sul;
int lines;
} lws_dlo_rasterize_t;
typedef struct lws_dlo_png {
lws_dlo_t dlo; /* ordering: first */
lws_flow_t flow; /* ordering: second */
lws_upng_t *png;
} lws_dlo_png_t;
typedef struct lws_dlo_jpeg {
lws_dlo_t dlo; /* ordering: first */
lws_flow_t flow; /* ordering: second */
lws_jpeg_t *j;
} lws_dlo_jpeg_t;
typedef enum {
LWSDLOSS_TYPE_JPEG,
LWSDLOSS_TYPE_PNG,
LWSDLOSS_TYPE_CSS,
} lws_dlo_image_type_t;
typedef struct {
union {
lws_dlo_jpeg_t *dlo_jpeg;
lws_dlo_png_t *dlo_png;
} u;
lws_dlo_image_type_t type;
char failed;
} lws_dlo_image_t;
typedef struct lws_displaylist {
lws_dll2_owner_t dl;
struct lws_display_state *ds;
} lws_displaylist_t;
typedef struct lws_dl_rend {
lws_displaylist_t *dl;
int w;
int h;
} lws_dl_rend_t;
typedef struct lws_display_render_stack {
lws_dlo_t *dlo; /* position in dlo owner */
lws_box_t co; /* our origin as parent */
} lws_display_render_stack_t;
typedef struct lws_display_render_state {
lws_sorted_usec_list_t sul; /* return to event loop statefully */
struct lws_display_state *lds; /* optional, if using lws_display */
lws_dll2_owner_t ids;
const struct lws_surface_info *ic; /* display dimensions, palette */
lws_display_render_stack_t st[12]; /* DLO child stack */
int sp; /* DLO child stack level */
uint8_t *line; /* Y or RGB line comp buffer */
lws_displaylist_t displaylist;
lws_display_scalar curr;
lws_display_scalar lowest_id_y;
char html;
} lws_display_render_state_t;
LWS_VISIBLE LWS_EXTERN void
lws_display_render_free_ids(lws_display_render_state_t *rs);
LWS_VISIBLE LWS_EXTERN lws_display_id_t *
lws_display_render_add_id(lws_display_render_state_t *rs, const char *id, void *priv);
LWS_VISIBLE LWS_EXTERN lws_display_id_t *
lws_display_render_get_id(lws_display_render_state_t *rs, const char *id);
LWS_VISIBLE LWS_EXTERN void
lws_display_render_dump_ids(lws_dll2_owner_t *ids);
LWS_VISIBLE LWS_EXTERN void
lws_dlo_contents(lws_dlo_t *parent, lws_dlo_dim_t *dim);
LWS_VISIBLE LWS_EXTERN void
lws_display_dlo_adjust_dims(lws_dlo_t *dlo, lws_dlo_dim_t *dim);
/**
* lws_display_dl_init() - init display list object
*
* \param dl: Pointer to the display list
* \param ds: Lws display state to bind the list to
*
* Initializes the display list \p dl and binds it to the display state \p ds.
*/
LWS_VISIBLE LWS_EXTERN void
lws_display_dl_init(lws_displaylist_t *dl, struct lws_display_state *ds);
//#if defined(_DEBUG)
LWS_VISIBLE LWS_EXTERN void
lws_display_dl_dump(lws_displaylist_t *dl);
//#endif
/**
* lws_display_list_destroy() - destroys display list and objects on it
*
* \param dl: Pointer to the display list
*
* Destroys every DLO on the list.
*/
LWS_VISIBLE LWS_EXTERN void
lws_display_list_destroy(lws_displaylist_t *dl);
LWS_VISIBLE LWS_EXTERN void
lws_display_dlo_destroy(lws_dlo_t **r);
LWS_VISIBLE LWS_EXTERN int
lws_display_dlo_add(lws_displaylist_t *dl, lws_dlo_t *dlo_parent, lws_dlo_t *dlo);
LWS_VISIBLE LWS_EXTERN int
lws_dlo_ensure_err_diff(lws_dlo_t *dlo);
/*
* lws_display_list_render_line() - render a single raster line of the list
*
* \param rs: prepared render state object
*
* Allocates a line pair buffer into ds->line if necessary, and renders the
* current line (set by ds->curr) of the display list rasterization into it
*/
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_list_render_line(lws_display_render_state_t *rs);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_get_ids_boxes(lws_display_render_state_t *rs);
/*
* rect
*/
LWS_VISIBLE LWS_EXTERN lws_dlo_rect_t *
lws_display_dlo_rect_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
lws_box_t *box, const lws_fx_t *radii,
lws_display_colour_t dc);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_render_rect(struct lws_display_render_state *rs);
/*
* dlo text
*/
LWS_VISIBLE LWS_EXTERN lws_dlo_text_t *
lws_display_dlo_text_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
lws_box_t *box, const lws_display_font_t *font);
LWS_VISIBLE LWS_EXTERN int
lws_display_dlo_text_update(lws_dlo_text_t *text, lws_display_colour_t dc,
lws_fx_t indent, const char *utf8, size_t text_len);
LWS_VISIBLE LWS_EXTERN void
lws_display_dlo_text_destroy(struct lws_dlo *dlo);
/*
* PNG
*/
LWS_VISIBLE LWS_EXTERN lws_dlo_png_t *
lws_display_dlo_png_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
lws_box_t *box);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_render_png(struct lws_display_render_state *rs);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_dlo_png_metadata_scan(lws_dlo_png_t *dp);
LWS_VISIBLE LWS_EXTERN void
lws_display_dlo_png_destroy(struct lws_dlo *dlo);
/*
* JPEG
*/
LWS_VISIBLE LWS_EXTERN lws_dlo_jpeg_t *
lws_display_dlo_jpeg_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
lws_box_t *box);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_render_jpeg(struct lws_display_render_state *rs);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_display_dlo_jpeg_metadata_scan(lws_dlo_jpeg_t *dj);
LWS_VISIBLE LWS_EXTERN void
lws_display_dlo_jpeg_destroy(struct lws_dlo *dlo);
/*
* SS / dlo images
*/
struct lhp_ctx;
typedef struct {
struct lws_context *cx;
lws_displaylist_t *dl;
lws_dlo_t *dlo_parent;
lws_box_t *box;
sul_cb_t on_rx;
lws_sorted_usec_list_t *on_rx_sul;
const char *url;
struct lhp_ctx *lhp;
lws_dlo_image_t *u;
int32_t window;
uint8_t type;
} lws_dlo_ss_create_info_t;
LWS_VISIBLE LWS_EXTERN int
lws_dlo_ss_create(lws_dlo_ss_create_info_t *i, lws_dlo_t **pdlo);
LWS_VISIBLE LWS_EXTERN int
lws_dlo_ss_find(struct lws_context *cx, const char *url, lws_dlo_image_t *u);
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lhp_displaylist_layout(struct lhp_ctx *ctx, char reason);
#define lws_dlo_image_width(_u) ((_u)->failed ? -1 : \
((_u)->type == LWSDLOSS_TYPE_JPEG ? \
(int)lws_jpeg_get_width((_u)->u.dlo_jpeg->j) : \
(int)lws_upng_get_width((_u)->u.dlo_png->png)))
#define lws_dlo_image_height(_u) ((_u)->failed ? -1 : \
((_u)->type == LWSDLOSS_TYPE_JPEG ? \
(int)lws_jpeg_get_height((_u)->u.dlo_jpeg->j) : \
(int)lws_upng_get_height((_u)->u.dlo_png->png)))
#define lws_dlo_image_metadata_scan(_u) ((_u)->failed ? LWS_SRET_FATAL : \
((_u)->type == LWSDLOSS_TYPE_JPEG ? \
lws_display_dlo_jpeg_metadata_scan((_u)->u.dlo_jpeg) : \
lws_display_dlo_png_metadata_scan((_u)->u.dlo_png)))
/*
* Font registry
*
* Register fonts (currently, psfu) to the lws_context, and select the closest
* matching. Used to pick fonts from whatever CSS information is available.
*/
LWS_VISIBLE LWS_EXTERN int
lws_font_register(struct lws_context *cx, const uint8_t *data, size_t data_len);
LWS_VISIBLE LWS_EXTERN const lws_display_font_t *
lws_font_choose(struct lws_context *cx, const lws_font_choice_t *hints);
LWS_VISIBLE LWS_EXTERN void
lws_fonts_destroy(struct lws_context *cx);
/*
* Static blob registry (built-in, name-accessible blobs)
*/
LWS_VISIBLE LWS_EXTERN lws_dlo_filesystem_t *
lws_dlo_file_register(struct lws_context *cx, const lws_dlo_filesystem_t *f);
/* only needed if f dynamically heap-allocated... doesn't free data; data
* is typically overallocated after the lws_dlo_filesystem_t and freed when
* that is freed by this. */
LWS_VISIBLE LWS_EXTERN void
lws_dlo_file_unregister(lws_dlo_filesystem_t **f);
LWS_VISIBLE LWS_EXTERN void
lws_dlo_file_unregister_by_name(struct lws_context *cx, const char *name);
LWS_VISIBLE LWS_EXTERN const lws_dlo_filesystem_t *
lws_dlo_file_choose(struct lws_context *cx, const char *name);
LWS_VISIBLE LWS_EXTERN void
lws_dlo_file_destroy(struct lws_context *cx);
LWS_VISIBLE extern const struct lws_plat_file_ops lws_dlo_fops;
#endif

View File

@ -0,0 +1,169 @@
/*
* 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.
*/
/*
* lws_dsh (Disordered Shared Heap) is an opaque abstraction supporting a single
* linear buffer (overallocated at end of the lws_dsh_t) which may contain
* multiple kinds of packets that are retired out of order, and tracked by kind.
*
* Each kind of packet has an lws_dll2 list of its kind of packets and acts as
* a FIFO; packets of a particular type are always retired in order. But there
* is no requirement about the order types are retired matching the original
* order they arrived.
*
* Gaps are tracked as just another kind of "packet" list.
*
* "allocations" (including gaps) are prepended by an lws_dsh_object_t.
*
* dsh may themselves be on an lws_dll2_owner list, and under memory pressure
* allocate into other buffers on the list.
*
* All management structures exist inside the allocated buffer.
*/
enum {
LWS_DSHFLAG_ENABLE_COALESCE = (1u << 24),
LWS_DSHFLAG_ENABLE_SPLIT = (1u << 25),
};
/**
* lws_dsh_create() - Allocate a DSH buffer
*
* \param owner: the owning list this dsh belongs on, or NULL if standalone
* \param buffer_size: the allocation in bytes
* \param count_kinds: how many separately-tracked fifos use the buffer, or-ed
* with optional LWS_DSHFLAGs
*
* This makes a single heap allocation that includes internal tracking objects
* in the buffer. Sub-allocated objects are bound to a "kind" index and
* managed via a FIFO for each kind.
*
* Every "kind" of allocation shares the same buffer space.
*
* Multiple buffers may be bound together in an lws_dll2 list, and if an
* allocation cannot be satisfied by the local buffer, space can be borrowed
* from other dsh in the same list (the local dsh FIFO tracks these "foreign"
* allocations as if they were local).
*
* Returns an opaque pointer to the dsh, or NULL if allocation failed.
*/
LWS_VISIBLE LWS_EXTERN struct lws_dsh *
lws_dsh_create(lws_dll2_owner_t *owner, size_t buffer_size, int count_kinds);
LWS_VISIBLE LWS_EXTERN void
lws_dsh_empty(struct lws_dsh *dsh);
/**
* lws_dsh_destroy() - Destroy a DSH buffer
*
* \param pdsh: pointer to the dsh pointer
*
* Deallocates the DSH and sets *pdsh to NULL.
*
* Before destruction, any foreign buffer usage on the part of this dsh are
* individually freed. All dsh on the same list are walked and checked if they
* have their own foreign allocations on the dsh buffer being destroyed. If so,
* it attempts to migrate the allocation to a dsh that is not currently being
* destroyed. If all else fails (basically the buffer memory is being shrunk)
* unmigratable objects are cleanly destroyed.
*/
LWS_VISIBLE LWS_EXTERN void
lws_dsh_destroy(struct lws_dsh **pdsh);
/**
* lws_dsh_alloc_tail() - make a suballocation inside a dsh
*
* \param dsh: the dsh tracking the allocation
* \param kind: the kind of allocation
* \param src1: the first source data to copy
* \param size1: the size of the first source data
* \param src2: the second source data to copy (after the first), or NULL
* \param size2: the size of the second source data
*
* Allocates size1 + size2 bytes in a dsh (it prefers the given dsh but will
* borrow space from other dsh on the same list if necessary) and copies size1
* bytes into it from src1, followed by size2 bytes from src2 if src2 isn't
* NULL. The actual suballocation is a bit larger because of alignment and a
* prepended management header.
*
* The suballocation is added to the kind-specific FIFO at the tail.
*/
LWS_VISIBLE LWS_EXTERN int
lws_dsh_alloc_tail(struct lws_dsh *dsh, int kind, const void *src1,
size_t size1, const void *src2, size_t size2);
/**
* lws_dsh_free() - free a suballocation from the dsh
*
* \param obj: a pointer to a void * that pointed to the allocated payload
*
* This returns the space used by \p obj in the dsh buffer to the free list
* of the dsh the allocation came from.
*/
LWS_VISIBLE LWS_EXTERN void
lws_dsh_free(void **obj);
/**
* lws_dsh_consume() - partially consume a dsh
*
* \param dsh: the dsh
* \param kind: the kind of allocation (0 +)
* \param len: length to consume
*
* Consume part of a dsh object.
*/
LWS_VISIBLE LWS_EXTERN void
lws_dsh_consume(struct lws_dsh *dsh, int kind, size_t len);
LWS_VISIBLE LWS_EXTERN size_t
lws_dsh_get_size(struct lws_dsh *dsh, int kind);
/**
* lws_dsh_get_head() - get the head allocation inside the dsh
*
* \param dsh: the dsh tracking the allocation
* \param kind: the kind of allocation
* \param obj: pointer to a void * to be set to the payload
* \param size: set to the size of the allocation
*
* This gets the "next" object in the kind FIFO for the dsh, and returns 0 if
* any. If none, returns nonzero.
*
* This is nondestructive of the fifo or the payload. Use lws_dsh_free on
* obj to remove the entry from the kind fifo and return the payload to the
* free list.
*/
LWS_VISIBLE LWS_EXTERN int
lws_dsh_get_head(struct lws_dsh *dsh, int kind, void **obj, size_t *size);
/**
* lws_dsh_describe() - DEBUG BUILDS ONLY dump the dsh to the logs
*
* \param dsh: the dsh to dump
* \param desc: text that appears at the top of the dump
*
* Useful information for debugging lws_dsh
*/
LWS_VISIBLE LWS_EXTERN void
lws_dsh_describe(struct lws_dsh *dsh, const char *desc);

View File

@ -0,0 +1,52 @@
/*
* SPI - esp32 esp-idf api implementation
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for gpio, a real implementation provides
* functions for the ops that use the underlying OS gpio arrangements.
*/
#if defined(ESP_PLATFORM)
#define lws_esp32_spi_ops \
.init = lws_esp32_spi_init, \
.queue = lws_esp32_spi_queue, \
.alloc_dma = lws_esp32_spi_alloc_dma, \
.free_dma = lws_esp32_spi_free_dma, \
.in_flight = lws_esp32_spi_in_flight
LWS_VISIBLE LWS_EXTERN int
lws_esp32_spi_init(const lws_spi_ops_t *spi_ops);
LWS_VISIBLE LWS_EXTERN int
lws_esp32_spi_queue(const lws_spi_ops_t *spi_ops, const lws_spi_desc_t *desc);
LWS_VISIBLE LWS_EXTERN void *
lws_esp32_spi_alloc_dma(const struct lws_spi_ops *ctx, size_t size);
LWS_VISIBLE LWS_EXTERN void
lws_esp32_spi_free_dma(const struct lws_spi_ops *ctx, void **p);
LWS_VISIBLE LWS_EXTERN int
lws_esp32_spi_in_flight(const struct lws_spi_ops *ctx);
#endif

View File

@ -0,0 +1,153 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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.
*
* These are exports needed by event lib plugins.
*/
enum lws_event_lib_ops_flags {
LELOF_ISPOLL = (1 >> 0),
LELOF_DESTROY_FINAL = (1 >> 1),
};
enum {
LWS_EV_READ = (1 << 0),
LWS_EV_WRITE = (1 << 1),
LWS_EV_START = (1 << 2),
LWS_EV_STOP = (1 << 3),
};
struct lws_event_loop_ops {
const char *name;
/* event loop-specific context init during context creation */
int (*init_context)(struct lws_context *context,
const struct lws_context_creation_info *info);
/* called during lws_destroy_context */
int (*destroy_context1)(struct lws_context *context);
/* called during lws_destroy_context2 */
int (*destroy_context2)(struct lws_context *context);
/* init vhost listening wsi */
int (*init_vhost_listen_wsi)(struct lws *wsi);
/* init the event loop for a pt */
int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
/* called at end of first phase of close_free_wsi() */
int (*wsi_logical_close)(struct lws *wsi);
/* return nonzero if client connect not allowed */
int (*check_client_connect_ok)(struct lws *wsi);
/* close handle manually */
void (*close_handle_manually)(struct lws *wsi);
/* event loop accept processing */
int (*sock_accept)(struct lws *wsi);
/* control wsi active events */
void (*io)(struct lws *wsi, unsigned int flags);
/* run the event loop for a pt */
void (*run_pt)(struct lws_context *context, int tsi);
/* called before pt is destroyed */
void (*destroy_pt)(struct lws_context *context, int tsi);
/* called just before wsi is freed */
void (*destroy_wsi)(struct lws *wsi);
/* return nonzero if caller thread is not loop service thread */
int (*foreign_thread)(struct lws_context *context, int tsi);
/* optional: custom implementation for faking POLLIN for buffered.
* return nonzero if any wsi faked */
int (*fake_POLLIN_override)(struct lws_context *context, int tsi);
uint8_t flags;
uint16_t evlib_size_ctx;
uint16_t evlib_size_pt;
uint16_t evlib_size_vh;
uint16_t evlib_size_wsi;
};
LWS_VISIBLE LWS_EXTERN void *
lws_evlib_wsi_to_evlib_pt(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN void *
lws_evlib_tsi_to_evlib_pt(struct lws_context *ctx, int tsi);
/*
* You should consider these opaque for normal user code.
*/
LWS_VISIBLE LWS_EXTERN void *
lws_realloc(void *ptr, size_t size, const char *reason);
LWS_VISIBLE LWS_EXTERN void
lws_vhost_destroy1(struct lws_vhost *vh);
LWS_VISIBLE LWS_EXTERN void
lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
const char *caller);
LWS_VISIBLE LWS_EXTERN int
lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg,
lws_dll2_foreach_cb_t cb);
struct lws_context_per_thread;
LWS_VISIBLE LWS_EXTERN void
lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt);
#if !defined(wsi_from_fd) && !defined(WIN32) && !defined(_WIN32)
struct lws_context;
LWS_VISIBLE LWS_EXTERN struct lws *
wsi_from_fd(const struct lws_context *context, int fd);
#endif
LWS_VISIBLE LWS_EXTERN int
_lws_plat_service_forced_tsi(struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_context_destroy2(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_destroy_event_pipe(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN void
__lws_close_free_wsi_final(struct lws *wsi);
#if LWS_MAX_SMP > 1
struct lws_mutex_refcount {
pthread_mutex_t lock;
pthread_t lock_owner;
const char *last_lock_reason;
char lock_depth;
char metadata;
};
LWS_VISIBLE LWS_EXTERN void
lws_mutex_refcount_assert_held(struct lws_mutex_refcount *mr);
LWS_VISIBLE LWS_EXTERN void
lws_mutex_refcount_init(struct lws_mutex_refcount *mr);
LWS_VISIBLE LWS_EXTERN void
lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr);
LWS_VISIBLE LWS_EXTERN void
lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason);
LWS_VISIBLE LWS_EXTERN void
lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr);
#endif

View File

@ -0,0 +1,251 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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.
*
* Fault injection api if built with LWS_WITH_SYS_FAULT_INJECTION
*/
typedef struct lws_xos {
uint64_t s[4];
} lws_xos_t;
/**
* lws_xos_init() - seed xoshiro256 PRNG
*
* \param xos: the prng state object to initialize
* \param seed: the 64-bit seed
*
* Initialize PRNG \xos with the starting state represented by \p seed
*/
LWS_VISIBLE LWS_EXTERN void
lws_xos_init(struct lws_xos *xos, uint64_t seed);
/**
* lws_xos() - get next xoshiro256 PRNG result and update state
*
* \param xos: the PRNG state to use
*
* Returns next 64-bit PRNG result. These are cheap to get,
* quite a white noise sequence, and completely deterministic
* according to the seed it was initialized with.
*/
LWS_VISIBLE LWS_EXTERN uint64_t LWS_WARN_UNUSED_RESULT
lws_xos(struct lws_xos *xos);
/**
* lws_xos_percent() - return 1 a given percent of the time on average
*
* \param xos: the PRNG state to use
* \param percent: chance in 100 of returning 1
*
* Returns 1 if next random % 100 is < \p percent, such that
* 100 always returns 1, 0 never returns 1, and the chance linearly scales
* inbetween
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_xos_percent(struct lws_xos *xos, int percent);
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
enum {
LWSFI_ALWAYS,
LWSFI_DETERMINISTIC, /* do .count injections after .pre then stop */
LWSFI_PROBABILISTIC, /* .pre % chance of injection */
LWSFI_PATTERN, /* use .count bits in .pattern after .pre */
LWSFI_PATTERN_ALLOC, /* as _PATTERN, but .pattern is malloc'd */
LWSFI_RANGE /* pick a number between pre and count */
};
typedef struct lws_fi {
const char *name;
const uint8_t *pattern;
uint64_t pre;
uint64_t count;
uint64_t times; /* start at 0, tracks usage */
char type; /* LWSFI_* */
} lws_fi_t;
typedef struct lws_fi_ctx {
lws_dll2_owner_t fi_owner;
struct lws_xos xos;
const char *name;
} lws_fi_ctx_t;
/**
* lws_fi() - find out if we should perform the named fault injection this time
*
* \param fic: fault injection tracking context
* \param fi_name: name of fault injection
*
* This checks if the named fault is configured in the fi tracking context
* provided, if it is, then it will make a decision if the named fault should
* be applied this time, using the tracking in the named lws_fi_t.
*
* If the provided context has a parent, that is also checked for the named fi
* item recursively, with the first found being used to determine if to inject
* or not.
*
* If LWS_WITH_SYS_FAULT_INJECTION is not defined, then this always return 0.
*/
LWS_VISIBLE LWS_EXTERN int
lws_fi(const lws_fi_ctx_t *fic, const char *fi_name);
/**
* lws_fi_range() - get a random number from a range
*
* \param fic: fault injection tracking context
* \param fi_name: name of fault injection
* \param result: points to uint64_t to be set to the result
*
* This lets you get a random number from an externally-set range, set using a
* fault injection syntax like "myfault(123..456)". That will cause us to
* return a number between those two inclusive, from the seeded PRNG.
*
* This is useful when you used lws_fi() with its own fault name to decide
* whether to inject the fault, and then the code to cause the fault needs
* additional constrained pseudo-random fuzzing for, eg, delays before issuing
* the fault.
*
* Returns 0 if \p *result is set, else nonzero for failure.
*/
LWS_VISIBLE LWS_EXTERN int
lws_fi_range(const lws_fi_ctx_t *fic, const char *name, uint64_t *result);
/**
* lws_fi_add() - add an allocated copy of fault injection to a context
*
* \param fic: fault injection tracking context
* \param fi: the fault injection details
*
* This allocates a copy of \p fi and attaches it to the fault injection context
* \p fic. \p fi can go out of scope after this safely.
*/
LWS_VISIBLE LWS_EXTERN int
lws_fi_add(lws_fi_ctx_t *fic, const lws_fi_t *fi);
/**
* lws_fi_remove() - remove an allocated copy of fault injection from a context
*
* \param fic: fault injection tracking context
* \param name: the fault injection name to remove
*
* This looks for the named fault injection and removes and destroys it from
* the specified fault injection context
*/
LWS_VISIBLE LWS_EXTERN void
lws_fi_remove(lws_fi_ctx_t *fic, const char *name);
/**
* lws_fi_import() - transfers all the faults from one context to another
*
* \param fic_dest: the fault context to receive the faults
* \param fic_src: the fault context that will be emptied out into \p fic_dest
*
* This is used to initialize created object fault injection contexts from
* the caller.
*/
LWS_VISIBLE LWS_EXTERN void
lws_fi_import(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src);
/**
* lws_fi_inherit_copy() - attach copies of matching fault injection objects to dest
*
* \param fic_dest: destination Fault Injection context
* \param fic_src: parent fault context that may contain matching rules
* \param scope: the name of the path match required, eg, "vh"
* \param value: the dynamic name of our match, eg, "myvhost"
*
* If called with scope "vh" and value "myvhost", then matches faults starting
* "vh=myvhost/", strips that part of the name if it matches and makes a copy
* of the rule with the modified name attached to the destination Fault Injection
* context.
*/
LWS_VISIBLE LWS_EXTERN void
lws_fi_inherit_copy(lws_fi_ctx_t *fic_dest, const lws_fi_ctx_t *fic_src,
const char *scope, const char *value);
/**
* lws_fi_destroy() - removes all allocated fault injection entries
*
* \param fic: fault injection tracking context
*
* This walks any allocated fault injection entries in \p fic and detaches and
* destroys them. It doesn't try to destroc \p fic itself, since this is
* not usually directly allocated.
*/
LWS_VISIBLE LWS_EXTERN void
lws_fi_destroy(const lws_fi_ctx_t *fic);
/**
* lws_fi_deserialize() - adds fault in string form to Fault Injection Context
*
* \p fic: the fault injection context
* \p sers: the string serializing the desired fault details
*
* This turns a string like "ss=captive_portal_detect/wsi/dnsfail(10%)" into
* a fault injection struct added to the fault injection context \p fic
*
* You can prepare the context creation info .fic with these before creating
* the context, and use namespace paths on those to target other objects.
*/
LWS_VISIBLE LWS_EXTERN void
lws_fi_deserialize(lws_fi_ctx_t *fic, const char *sers);
LWS_VISIBLE LWS_EXTERN int
_lws_fi_user_wsi_fi(struct lws *wsi, const char *name);
LWS_VISIBLE LWS_EXTERN int
_lws_fi_user_context_fi(struct lws_context *ctx, const char *name);
#if defined(LWS_WITH_SECURE_STREAMS)
struct lws_ss_handle;
LWS_VISIBLE LWS_EXTERN int
_lws_fi_user_ss_fi(struct lws_ss_handle *h, const char *name);
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
struct lws_sspc_handle;
LWS_VISIBLE LWS_EXTERN int
_lws_fi_user_sspc_fi(struct lws_sspc_handle *h, const char *name);
#endif
#endif
#define lws_fi_user_wsi_fi(_wsi, _name) _lws_fi_user_wsi_fi(_wsi, _name)
#define lws_fi_user_context_fi(_ctx, _name) _lws_fi_user_context_fi(_ctx, _name)
#define lws_fi_user_ss_fi(_h, _name) _lws_fi_user_ss_fi(_h, _name)
#define lws_fi_user_sspc_fi(_h, _name) _lws_fi_user_sspc_fi(_h, _name)
#else
/*
* Helper so we can leave lws_fi() calls embedded in the code being tested,
* if fault injection is not enabled then it just always says "no" at buildtime.
*/
#define lws_fi(_fi_name, _fic) (0)
#define lws_fi_destroy(_x)
#define lws_fi_inherit_copy(_a, _b, _c, _d)
#define lws_fi_deserialize(_x, _y)
#define lws_fi_user_wsi_fi(_wsi, _name) (0)
#define lws_fi_user_context_fi(_wsi, _name) (0)
#define lws_fi_user_ss_fi(_h, _name) (0)
#define lws_fi_user_sspc_fi(_h, _name) (0)
#endif

View File

@ -0,0 +1,87 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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.
*
* This is included from libwebsockets.h if LWS_PLAT_FREERTOS
*/
typedef int lws_sockfd_type;
typedef int lws_filefd_type;
#if defined(LWS_AMAZON_RTOS)
#include <FreeRTOS.h>
#include <event_groups.h>
#include <string.h>
#include "timers.h"
#include <lwip/sockets.h>
/*
* Later lwip (at least 2.1.12) already defines these in its own headers
* protected by the same test as used here... if POLLIN / POLLOUT already exist
* then assume no need to declare those and struct pollfd.
*
* Older lwip needs these declarations done here.
*/
#if !defined(POLLIN) && !defined(POLLOUT)
struct pollfd {
lws_sockfd_type fd; /**< fd related to */
short events; /**< which POLL... events to respond to */
short revents; /**< which POLL... events occurred */
};
#define POLLIN 0x0001
#define POLLPRI 0x0002
#define POLLOUT 0x0004
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
#endif
#else /* LWS_AMAZON_RTOS */
#include <freertos/FreeRTOS.h>
#include <freertos/event_groups.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "esp_event.h"
//#include "esp_event_loop.h"
#include "nvs.h"
#include "driver/gpio.h"
#include "spi_flash_mmap.h"
#include "freertos/timers.h"
#if defined(LWS_ESP_PLATFORM)
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#if defined(LWS_WITH_DRIVERS)
#include "libwebsockets/lws-gpio.h"
extern const lws_gpio_ops_t lws_gpio_plat;
#endif
#endif
#endif /* LWS_AMAZON_RTOS */
#if !defined(CONFIG_FREERTOS_HZ)
#define CONFIG_FREERTOS_HZ 100
#endif

View File

@ -0,0 +1,215 @@
/*
* 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 search Search
*
* ##Full-text search
*
* Lws provides superfast indexing and fulltext searching from index files on
* storage.
*/
///@{
struct lws_fts;
struct lws_fts_file;
/*
* Queries produce their results in an lwsac, using these public API types.
* The first thing in the lwsac is always a struct lws_fts_result (see below)
* containing heads for linked-lists of the other result types.
*/
/* one filepath's results */
struct lws_fts_result_filepath {
struct lws_fts_result_filepath *next;
int matches; /* logical number of matches */
int matches_length; /* bytes in length table (may be zero) */
int lines_in_file;
int filepath_length;
/* - uint32_t line table follows (first for alignment) */
/* - filepath (of filepath_length) follows */
};
/* autocomplete result */
struct lws_fts_result_autocomplete {
struct lws_fts_result_autocomplete *next;
int instances;
int agg_instances;
int ac_length;
char elided; /* children skipped in interest of antecedent children */
char has_children;
/* - autocomplete suggestion (of length ac_length) follows */
};
/*
* The results lwsac always starts with this. If no results and / or no
* autocomplete the members may be NULL. This implies the symbol nor any
* suffix on it exists in the trie file.
*/
struct lws_fts_result {
struct lws_fts_result_filepath *filepath_head;
struct lws_fts_result_autocomplete *autocomplete_head;
int duration_ms;
int effective_flags; /* the search flags that were used */
};
/*
* index creation functions
*/
/**
* lws_fts_create() - Create a new index file
*
* \param fd: The fd opened for write
*
* Inits a new index file, returning a struct lws_fts to represent it
*/
LWS_VISIBLE LWS_EXTERN struct lws_fts *
lws_fts_create(int fd);
/**
* lws_fts_destroy() - Finalize a new index file / destroy the trie lwsac
*
* \param trie: The previously opened index being finalized
*
* Finalizes an index file that was being created, and frees the memory involved
* *trie is set to NULL afterwards.
*/
LWS_VISIBLE LWS_EXTERN void
lws_fts_destroy(struct lws_fts **trie);
/**
* lws_fts_file_index() - Create a new entry in the trie file for an input path
*
* \param t: The previously opened index being written
* \param filepath: The filepath (which may be virtual) associated with this file
* \param filepath_len: The number of chars in the filepath
* \param priority: not used yet
*
* Returns an ordinal that represents this new filepath in the index file.
*/
LWS_VISIBLE LWS_EXTERN int
lws_fts_file_index(struct lws_fts *t, const char *filepath, int filepath_len,
int priority);
/**
* lws_fts_fill() - Process all or a bufferload of input file
*
* \param t: The previously opened index being written
* \param file_index: The ordinal representing this input filepath
* \param buf: A bufferload of data from the input file
* \param len: The number of bytes in buf
*
* Indexes a buffer of data from the input file.
*/
LWS_VISIBLE LWS_EXTERN int
lws_fts_fill(struct lws_fts *t, uint32_t file_index, const char *buf,
size_t len);
/**
* lws_fts_serialize() - Store the in-memory trie into the index file
*
* \param t: The previously opened index being written
*
* The trie is held in memory where it can be added to... after all the input
* filepaths and data have been processed, this is called to serialize /
* write the trie data into the index file.
*/
LWS_VISIBLE LWS_EXTERN int
lws_fts_serialize(struct lws_fts *t);
/*
* index search functions
*/
/**
* lws_fts_open() - Open an existing index file to search it
*
* \param filepath: The filepath to the index file to open
*
* Opening the index file returns an opaque struct lws_fts_file * that is
* used to perform other operations on it, or NULL if it can't be opened.
*/
LWS_VISIBLE LWS_EXTERN struct lws_fts_file *
lws_fts_open(const char *filepath);
#define LWSFTS_F_QUERY_AUTOCOMPLETE (1 << 0)
#define LWSFTS_F_QUERY_FILES (1 << 1)
#define LWSFTS_F_QUERY_FILE_LINES (1 << 2)
#define LWSFTS_F_QUERY_QUOTE_LINE (1 << 3)
struct lws_fts_search_params {
/* the actual search term */
const char *needle;
/* if non-NULL, FILE results for this filepath only */
const char *only_filepath;
/* will be set to the results lwsac */
struct lwsac *results_head;
/* combination of LWSFTS_F_QUERY_* flags */
int flags;
/* maximum number of autocomplete suggestions to return */
int max_autocomplete;
/* maximum number of filepaths to return */
int max_files;
/* maximum number of line number results to return per filepath */
int max_lines;
};
/**
* lws_fts_search() - Perform a search operation on an index
*
* \param jtf: The index file struct returned by lws_fts_open
* \param ftsp: The struct lws_fts_search_params filled in by the caller
*
* The caller should memset the ftsp struct to 0 to ensure members that may be
* introduced in later versions contain known values, then set the related
* members to describe the kind of search action required.
*
* ftsp->results_head is the results lwsac, or NULL. It should be freed with
* lwsac_free() when the results are finished with.
*
* Returns a pointer into the results lwsac that is a struct lws_fts_result
* containing the head pointers into linked-lists of results for autocomplete
* and filepath data, along with some sundry information. This does not need
* to be freed since freeing the lwsac will also remove this and everything it
* points to.
*/
LWS_VISIBLE LWS_EXTERN struct lws_fts_result *
lws_fts_search(struct lws_fts_file *jtf, struct lws_fts_search_params *ftsp);
/**
* lws_fts_close() - Close a previously-opened index file
*
* \param jtf: The pointer returned from the open
*
* Closes the file handle on the index and frees any allocations
*/
LWS_VISIBLE LWS_EXTERN void
lws_fts_close(struct lws_fts_file *jtf);
///@}

View File

@ -0,0 +1,170 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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 generic AES
* ## Generic AES related functions
*
* Lws provides generic AES functions that abstract the ones
* provided by whatever tls library you are linking against.
*
* It lets you use the same code if you build against mbedtls or OpenSSL
* for example.
*/
///@{
#if defined(LWS_WITH_MBEDTLS)
#include <mbedtls/aes.h>
#include <mbedtls/gcm.h>
#endif
enum enum_aes_modes {
LWS_GAESM_CBC,
LWS_GAESM_CFB128,
LWS_GAESM_CFB8,
LWS_GAESM_CTR,
LWS_GAESM_ECB,
LWS_GAESM_OFB,
LWS_GAESM_XTS, /* care... requires double-length key */
LWS_GAESM_GCM,
LWS_GAESM_KW,
};
enum enum_aes_operation {
LWS_GAESO_ENC,
LWS_GAESO_DEC
};
enum enum_aes_padding {
LWS_GAESP_NO_PADDING,
LWS_GAESP_WITH_PADDING
};
/* include/libwebsockets/lws-jwk.h must be included before this */
#define LWS_AES_BLOCKSIZE 128
#define LWS_AES_CBC_BLOCKLEN 16
struct lws_genaes_ctx {
#if defined(LWS_WITH_MBEDTLS)
union {
mbedtls_aes_context ctx;
#if defined(MBEDTLS_CIPHER_MODE_XTS)
mbedtls_aes_xts_context ctx_xts;
#endif
mbedtls_gcm_context ctx_gcm;
} u;
#else
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
ENGINE *engine;
char init;
#endif
unsigned char tag[16];
struct lws_gencrypto_keyelem *k;
enum enum_aes_operation op;
enum enum_aes_modes mode;
enum enum_aes_padding padding;
int taglen;
char underway;
};
/** lws_genaes_create() - Create genaes AES context
*
* \param ctx: your struct lws_genaes_ctx
* \param op: LWS_GAESO_ENC or LWS_GAESO_DEC
* \param mode: one of LWS_GAESM_
* \param el: struct prepared with key element data
* \param padding: 0 = no padding, 1 = padding
* \param engine: if openssl engine used, pass the pointer here
*
* Creates an AES context with a key associated with it, formed from
* the key elements in \p el.
*
* Returns 0 for OK or nonzero for error.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op,
enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el,
enum enum_aes_padding padding, void *engine);
/** lws_genaes_destroy() - Destroy genaes AES context
*
* \param ctx: your struct lws_genaes_ctx
* \param tag: NULL, or, GCM-only: buffer to receive tag
* \param tlen: 0, or, GCM-only: length of tag buffer
*
* Destroys any allocations related to \p ctx.
*
* For GCM only, up to tlen bytes of tag buffer will be set on exit.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen);
/** lws_genaes_crypt() - Encrypt or decrypt
*
* \param ctx: your struct lws_genaes_ctx
* \param in: input plaintext or ciphertext
* \param len: length of input (which is always length of output)
* \param out: output plaintext or ciphertext
* \param iv_or_nonce_ctr_or_data_unit_16: NULL, iv, nonce_ctr16, or data_unit16
* \param stream_block_16: pointer to 16-byte stream block for CTR mode only
* \param nc_or_iv_off: NULL or pointer to nc, or iv_off
* \param taglen: length of tag
*
* Encrypts or decrypts using the AES mode set when the ctx was created.
* The last three arguments have different meanings depending on the mode:
*
* KW CBC CFB128 CFB8 CTR ECB OFB XTS
* iv_or_nonce_ct.._unit_16 : iv iv iv iv nonce NULL iv dataunt
* stream_block_16 : NULL NULL NULL NULL stream NULL NULL NULL
* nc_or_iv_off : NULL NULL iv_off NULL nc_off NULL iv_off NULL
*
* For GCM:
*
* iv_or_nonce_ctr_or_data_unit_16 : iv
* stream_block_16 : pointer to tag
* nc_or_iv_off : set pointed-to size_t to iv length
* in : first call: additional data, subsequently
* : input data
* len : first call: add data length, subsequently
* : input / output length
*
* The length of the optional arg is always 16 if used, regardless of the mode.
*
* Returns 0 for OK or nonzero for error.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len,
uint8_t *out,
uint8_t *iv_or_nonce_ctr_or_data_unit_16,
uint8_t *stream_block_16,
size_t *nc_or_iv_off, int taglen);
///@}

View File

@ -0,0 +1,137 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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.
*/
/*
* These are gencrypto-level constants... they are used by both JOSE and direct
* gencrypto code. However while JWK relies on these, using gencrypto apis has
* no dependency at all on any JOSE type.
*/
enum lws_gencrypto_kty {
LWS_GENCRYPTO_KTY_UNKNOWN,
LWS_GENCRYPTO_KTY_OCT,
LWS_GENCRYPTO_KTY_RSA,
LWS_GENCRYPTO_KTY_EC
};
/*
* Keytypes where the same element name is reused must all agree to put the
* same-named element at the same e[] index. It's because when used with jwk,
* we parse and store in incoming key data, but we may not be informed of the
* definitive keytype until the end.
*/
enum lws_gencrypto_oct_tok {
LWS_GENCRYPTO_OCT_KEYEL_K, /* note... same offset as AES K */
LWS_GENCRYPTO_OCT_KEYEL_COUNT
};
enum lws_gencrypto_rsa_tok {
LWS_GENCRYPTO_RSA_KEYEL_E,
LWS_GENCRYPTO_RSA_KEYEL_N,
LWS_GENCRYPTO_RSA_KEYEL_D, /* note... same offset as EC D */
LWS_GENCRYPTO_RSA_KEYEL_P,
LWS_GENCRYPTO_RSA_KEYEL_Q,
LWS_GENCRYPTO_RSA_KEYEL_DP,
LWS_GENCRYPTO_RSA_KEYEL_DQ,
LWS_GENCRYPTO_RSA_KEYEL_QI,
/* we don't actively use these if given, but may come from COSE */
LWS_GENCRYPTO_RSA_KEYEL_OTHER,
LWS_GENCRYPTO_RSA_KEYEL_RI,
LWS_GENCRYPTO_RSA_KEYEL_DI,
LWS_GENCRYPTO_RSA_KEYEL_TI,
LWS_GENCRYPTO_RSA_KEYEL_COUNT
};
enum lws_gencrypto_ec_tok {
LWS_GENCRYPTO_EC_KEYEL_CRV,
LWS_GENCRYPTO_EC_KEYEL_X,
/* note... same offset as RSA D */
LWS_GENCRYPTO_EC_KEYEL_D = LWS_GENCRYPTO_RSA_KEYEL_D,
LWS_GENCRYPTO_EC_KEYEL_Y,
LWS_GENCRYPTO_EC_KEYEL_COUNT
};
enum lws_gencrypto_aes_tok {
/* note... same offset as OCT K */
LWS_GENCRYPTO_AES_KEYEL_K = LWS_GENCRYPTO_OCT_KEYEL_K,
LWS_GENCRYPTO_AES_KEYEL_COUNT
};
/* largest number of key elements for any algorithm */
#define LWS_GENCRYPTO_MAX_KEYEL_COUNT LWS_GENCRYPTO_RSA_KEYEL_COUNT
/* this "stretchy" type holds individual key element data in binary form.
* It's typcially used in an array with the layout mapping the element index to
* the key element meaning defined by the enums above. An array of these of
* length LWS_GENCRYPTO_MAX_KEYEL_COUNT can define key elements for any key
* type.
*/
typedef struct lws_gencrypto_keyelem {
uint8_t *buf;
uint32_t len;
} lws_gc_elem_t;
/**
* lws_gencrypto_bits_to_bytes() - returns rounded up bytes needed for bits
*
* \param bits
*
* Returns the number of bytes needed to store the given number of bits. If
* a byte is partially used, the byte count is rounded up.
*/
LWS_VISIBLE LWS_EXTERN int
lws_gencrypto_bits_to_bytes(int bits);
/**
* lws_base64_size() - returns estimated size of base64 encoding
*
* \param bytes
*
* Returns a slightly oversize estimate of the size of a base64 encoded version
* of the given amount of unencoded data.
*/
LWS_VISIBLE LWS_EXTERN int
lws_base64_size(int bytes);
/**
* lws_gencrypto_padded_length() - returns PKCS#5/#7 padded length
*
* @param blocksize - blocksize to pad to
* @param len - Length of input to pad
*
* Returns the length of a buffer originally of size len after PKCS#5 or PKCS#7
* padding has been applied to it.
*/
LWS_VISIBLE LWS_EXTERN size_t
lws_gencrypto_padded_length(size_t block_size, size_t len);

View File

@ -0,0 +1,211 @@
/*
* 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.
*/
enum enum_genec_alg {
LEGENEC_UNKNOWN,
LEGENEC_ECDH,
LEGENEC_ECDSA
};
struct lws_genec_ctx {
#if defined(LWS_WITH_MBEDTLS)
union {
mbedtls_ecdh_context *ctx_ecdh;
mbedtls_ecdsa_context *ctx_ecdsa;
} u;
#else
EVP_PKEY_CTX *ctx[2];
#endif
struct lws_context *context;
const struct lws_ec_curves *curve_table;
enum enum_genec_alg genec_alg;
char has_private;
};
#if defined(LWS_WITH_MBEDTLS)
enum enum_lws_dh_side {
LDHS_OURS = MBEDTLS_ECDH_OURS,
LDHS_THEIRS = MBEDTLS_ECDH_THEIRS
};
#else
enum enum_lws_dh_side {
LDHS_OURS,
LDHS_THEIRS
};
#endif
struct lws_ec_curves {
const char *name;
int tls_lib_nid;
uint16_t key_bytes;
};
/* ECDH-specific apis */
/** lws_genecdh_create() - Create a genecdh
*
* \param ctx: your genec context
* \param context: your lws_context (for RNG access)
* \param curve_table: NULL, enabling P-256, P-384 and P-521, or a replacement
* struct lws_ec_curves array, terminated by an entry with
* .name = NULL, of curves you want to allow
*
* Initializes a genecdh
*/
LWS_VISIBLE int
lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context,
const struct lws_ec_curves *curve_table);
/** lws_genecdh_set_key() - Apply an EC key to our or theirs side
*
* \param ctx: your genecdh context
* \param el: your key elements
* \param side: LDHS_OURS or LDHS_THEIRS
*
* Applies an EC key to one side or the other of an ECDH ctx
*/
LWS_VISIBLE LWS_EXTERN int
lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el,
enum enum_lws_dh_side side);
/** lws_genecdh_new_keypair() - Create a genec with a new public / private key
*
* \param ctx: your genec context
* \param side: LDHS_OURS or LDHS_THEIRS
* \param curve_name: an EC curve name, like "P-256"
* \param el: array pf LWS_GENCRYPTO_EC_KEYEL_COUNT key elems to take the new key
*
* Creates a genecdh with a newly minted EC public / private key
*/
LWS_VISIBLE LWS_EXTERN int
lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side,
const char *curve_name, struct lws_gencrypto_keyelem *el);
LWS_VISIBLE LWS_EXTERN int
lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss,
int *ss_len);
/* ECDSA-specific apis */
/** lws_genecdsa_create() - Create a genecdsa and
*
* \param ctx: your genec context
* \param context: your lws_context (for RNG access)
* \param curve_table: NULL, enabling P-256, P-384 and P-521, or a replacement
* struct lws_ec_curves array, terminated by an entry with
* .name = NULL, of curves you want to allow
*
* Initializes a genecdh
*/
LWS_VISIBLE int
lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context,
const struct lws_ec_curves *curve_table);
/** lws_genecdsa_new_keypair() - Create a genecdsa with a new public / private key
*
* \param ctx: your genec context
* \param curve_name: an EC curve name, like "P-256"
* \param el: array pf LWS_GENCRYPTO_EC_KEYEL_COUNT key elements to take the new key
*
* Creates a genecdsa with a newly minted EC public / private key
*/
LWS_VISIBLE LWS_EXTERN int
lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name,
struct lws_gencrypto_keyelem *el);
/** lws_genecdsa_set_key() - Apply an EC key to an ecdsa context
*
* \param ctx: your genecdsa context
* \param el: your key elements
*
* Applies an EC key to an ecdsa context
*/
LWS_VISIBLE LWS_EXTERN int
lws_genecdsa_set_key(struct lws_genec_ctx *ctx,
const struct lws_gencrypto_keyelem *el);
/** lws_genecdsa_hash_sig_verify_jws() - Verifies a JWS ECDSA signature on a given hash
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: unencrypted payload (usually a recomputed hash)
* \param hash_type: one of LWS_GENHASH_TYPE_
* \param keybits: number of bits in the crypto key
* \param sig: pointer to the signature we received with the payload
* \param sig_len: length of the signature we are checking in bytes
*
* This just looks at the signed hash... that's why there's no input length
* parameter, it's decided by the choice of hash. It's up to you to confirm
* separately the actual payload matches the hash that was confirmed by this to
* be validly signed.
*
* Returns <0 for error, or 0 if signature matches the hash + key..
*
* The JWS ECDSA signature verification algorithm differs to generic ECDSA
* signatures and they're not interoperable.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
enum lws_genhash_types hash_type, int keybits,
const uint8_t *sig, size_t sig_len);
/** lws_genecdsa_hash_sign_jws() - Creates a JWS ECDSA signature for a hash you provide
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: precomputed hash
* \param hash_type: one of LWS_GENHASH_TYPE_
* \param keybits: number of bits in the crypto key
* \param sig: pointer to buffer to take signature
* \param sig_len: length of the buffer (must be >= length of key N)
*
* Returns <0 for error, or >=0 for success.
*
* This creates a JWS ECDSA signature for a hash you already computed and provide.
*
* The JWS ECDSA signature generation algorithm differs to generic ECDSA
* signatures and they're not interoperable.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
enum lws_genhash_types hash_type, int keybits,
uint8_t *sig, size_t sig_len);
/* Apis that apply to both ECDH and ECDSA */
LWS_VISIBLE LWS_EXTERN void
lws_genec_destroy(struct lws_genec_ctx *ctx);
LWS_VISIBLE LWS_EXTERN void
lws_genec_destroy_elements(struct lws_gencrypto_keyelem *el);
LWS_VISIBLE LWS_EXTERN int
lws_genec_dump(struct lws_gencrypto_keyelem *el);

View File

@ -0,0 +1,193 @@
/*
* 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 generichash Generic Hash
* ## Generic Hash related functions
*
* Lws provides generic hash / digest accessors that abstract the ones
* provided by whatever tls library you are linking against.
*
* It lets you use the same code if you build against mbedtls or OpenSSL
* for example.
*/
///@{
enum lws_genhash_types {
LWS_GENHASH_TYPE_UNKNOWN,
LWS_GENHASH_TYPE_MD5,
LWS_GENHASH_TYPE_SHA1,
LWS_GENHASH_TYPE_SHA256,
LWS_GENHASH_TYPE_SHA384,
LWS_GENHASH_TYPE_SHA512,
};
enum lws_genhmac_types {
LWS_GENHMAC_TYPE_UNKNOWN,
LWS_GENHMAC_TYPE_SHA256,
LWS_GENHMAC_TYPE_SHA384,
LWS_GENHMAC_TYPE_SHA512,
};
#define LWS_GENHASH_LARGEST 64
#if defined(LWS_WITH_TLS) && defined(LWS_WITH_GENCRYPTO)
struct lws_genhash_ctx {
uint8_t type;
#if defined(LWS_WITH_MBEDTLS)
union {
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
mbedtls_sha256_context sha256;
mbedtls_sha512_context sha512; /* 384 also uses this */
const mbedtls_md_info_t *hmac;
} u;
#else
const EVP_MD *evp_type;
EVP_MD_CTX *mdctx;
#endif
};
struct lws_genhmac_ctx {
uint8_t type;
#if defined(LWS_WITH_MBEDTLS)
const mbedtls_md_info_t *hmac;
mbedtls_md_context_t ctx;
#else
const EVP_MD *evp_type;
#if defined(LWS_HAVE_EVP_PKEY_new_raw_private_key)
EVP_MD_CTX *ctx;
EVP_PKEY *key;
#else
#if defined(LWS_HAVE_HMAC_CTX_new)
HMAC_CTX *ctx;
#else
HMAC_CTX ctx;
#endif
#endif
#endif
};
/** lws_genhash_size() - get hash size in bytes
*
* \param type: one of LWS_GENHASH_TYPE_...
*
* Returns number of bytes in this type of hash, if the hash type is unknown, it
* will return 0.
*/
LWS_VISIBLE LWS_EXTERN size_t LWS_WARN_UNUSED_RESULT
lws_genhash_size(enum lws_genhash_types type);
/** lws_genhmac_size() - get hash size in bytes
*
* \param type: one of LWS_GENHASH_TYPE_...
*
* Returns number of bytes in this type of hmac, if the hmac type is unknown, it
* will return 0.
*/
LWS_VISIBLE LWS_EXTERN size_t LWS_WARN_UNUSED_RESULT
lws_genhmac_size(enum lws_genhmac_types type);
/** lws_genhash_init() - prepare your struct lws_genhash_ctx for use
*
* \param ctx: your struct lws_genhash_ctx
* \param type: one of LWS_GENHASH_TYPE_...
*
* Initializes the hash context for the type you requested
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type);
/** lws_genhash_update() - digest len bytes of the buffer starting at in
*
* \param ctx: your struct lws_genhash_ctx
* \param in: start of the bytes to digest
* \param len: count of bytes to digest
*
* Updates the state of your hash context to reflect digesting len bytes from in
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len);
/** lws_genhash_destroy() - copy out the result digest and destroy the ctx
*
* \param ctx: your struct lws_genhash_ctx
* \param result: NULL, or where to copy the result hash
*
* Finalizes the hash and copies out the digest. Destroys any allocations such
* that ctx can safely go out of scope after calling this.
*
* NULL result is supported so that you can destroy the ctx cleanly on error
* conditions, where there is no valid result.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result);
/** lws_genhmac_init() - prepare your struct lws_genhmac_ctx for use
*
* \param ctx: your struct lws_genhmac_ctx
* \param type: one of LWS_GENHMAC_TYPE_...
* \param key: pointer to the start of the HMAC key
* \param key_len: length of the HMAC key
*
* Initializes the hash context for the type you requested
*
* If the return is nonzero, it failed and there is nothing needing to be
* destroyed.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type,
const uint8_t *key, size_t key_len);
/** lws_genhmac_update() - digest len bytes of the buffer starting at in
*
* \param ctx: your struct lws_genhmac_ctx
* \param in: start of the bytes to digest
* \param len: count of bytes to digest
*
* Updates the state of your hash context to reflect digesting len bytes from in
*
* If the return is nonzero, it failed and needs destroying.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len);
/** lws_genhmac_destroy() - copy out the result digest and destroy the ctx
*
* \param ctx: your struct lws_genhmac_ctx
* \param result: NULL, or where to copy the result hash
*
* Finalizes the hash and copies out the digest. Destroys any allocations such
* that ctx can safely go out of scope after calling this.
*
* NULL result is supported so that you can destroy the ctx cleanly on error
* conditions, where there is no valid result.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result);
#endif
///@}

View File

@ -0,0 +1,255 @@
/*
* 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 genericRSA Generic RSA
* ## Generic RSA related functions
*
* Lws provides generic RSA functions that abstract the ones
* provided by whatever OpenSSL library you are linking against.
*
* It lets you use the same code if you build against mbedtls or OpenSSL
* for example.
*/
///@{
/* include/libwebsockets/lws-jwk.h must be included before this */
enum enum_genrsa_mode {
LGRSAM_PKCS1_1_5,
LGRSAM_PKCS1_OAEP_PSS,
LGRSAM_COUNT
};
struct lws_genrsa_ctx {
#if defined(LWS_WITH_MBEDTLS)
mbedtls_rsa_context *ctx;
#else
BIGNUM *bn[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
EVP_PKEY_CTX *ctx;
RSA *rsa;
#endif
struct lws_context *context;
enum enum_genrsa_mode mode;
};
/** lws_genrsa_public_decrypt_create() - Create RSA public decrypt context
*
* \param ctx: your struct lws_genrsa_ctx
* \param el: struct prepared with key element data
* \param context: lws_context for RNG
* \param mode: RSA mode, one of LGRSAM_ constants
* \param oaep_hashid: the lws genhash id for the hash used in MFG1 hash
* used in OAEP mode - normally, SHA1
*
* Creates an RSA context with a public key associated with it, formed from
* the key elements in \p el.
*
* Mode LGRSAM_PKCS1_1_5 is in widespread use but has weaknesses. It's
* recommended to use LGRSAM_PKCS1_OAEP_PSS for new implementations.
*
* Returns 0 for OK or nonzero for error.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_create(struct lws_genrsa_ctx *ctx,
const struct lws_gencrypto_keyelem *el,
struct lws_context *context, enum enum_genrsa_mode mode,
enum lws_genhash_types oaep_hashid);
/** lws_genrsa_destroy_elements() - Free allocations in genrsa_elements
*
* \param el: your struct lws_gencrypto_keyelem
*
* This is a helper for user code making use of struct lws_gencrypto_keyelem
* where the elements are allocated on the heap, it frees any non-NULL
* buf element and sets the buf to NULL.
*
* NB: lws_genrsa_public_... apis do not need this as they take care of the key
* creation and destruction themselves.
*/
LWS_VISIBLE LWS_EXTERN void
lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el);
/** lws_genrsa_new_keypair() - Create new RSA keypair
*
* \param context: your struct lws_context (may be used for RNG)
* \param ctx: your struct lws_genrsa_ctx
* \param mode: RSA mode, one of LGRSAM_ constants
* \param el: struct to get the new key element data allocated into it
* \param bits: key size, eg, 4096
*
* Creates a new RSA context and generates a new keypair into it, with \p bits
* bits.
*
* Returns 0 for OK or nonzero for error.
*
* Mode LGRSAM_PKCS1_1_5 is in widespread use but has weaknesses. It's
* recommended to use LGRSAM_PKCS1_OAEP_PSS for new implementations.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el,
int bits);
/** lws_genrsa_public_encrypt() - Perform RSA public key encryption
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: plaintext input
* \param in_len: length of plaintext input
* \param out: encrypted output
*
* Performs PKCS1 v1.5 Encryption
*
* Returns <0 for error, or length of decrypted data.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
size_t in_len, uint8_t *out);
/** lws_genrsa_private_encrypt() - Perform RSA private key encryption
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: plaintext input
* \param in_len: length of plaintext input
* \param out: encrypted output
*
* Performs PKCS1 v1.5 Encryption
*
* Returns <0 for error, or length of decrypted data.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
size_t in_len, uint8_t *out);
/** lws_genrsa_public_decrypt() - Perform RSA public key decryption
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: encrypted input
* \param in_len: length of encrypted input
* \param out: decrypted output
* \param out_max: size of output buffer
*
* Performs PKCS1 v1.5 Decryption
*
* Returns <0 for error, or length of decrypted data.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
size_t in_len, uint8_t *out, size_t out_max);
/** lws_genrsa_private_decrypt() - Perform RSA private key decryption
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: encrypted input
* \param in_len: length of encrypted input
* \param out: decrypted output
* \param out_max: size of output buffer
*
* Performs PKCS1 v1.5 Decryption
*
* Returns <0 for error, or length of decrypted data.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
size_t in_len, uint8_t *out, size_t out_max);
/** lws_genrsa_hash_sig_verify() - Verifies RSA signature on a given hash
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: input to be hashed
* \param hash_type: one of LWS_GENHASH_TYPE_
* \param sig: pointer to the signature we received with the payload
* \param sig_len: length of the signature we are checking in bytes
*
* Returns <0 for error, or 0 if signature matches the payload + key.
*
* This just looks at a hash... that's why there's no input length
* parameter, it's decided by the choice of hash. It's up to you to confirm
* separately the actual payload matches the hash that was confirmed by this to
* be validly signed.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in,
enum lws_genhash_types hash_type,
const uint8_t *sig, size_t sig_len);
/** lws_genrsa_hash_sign() - Creates an ECDSA signature for a hash you provide
*
* \param ctx: your struct lws_genrsa_ctx
* \param in: input to be hashed and signed
* \param hash_type: one of LWS_GENHASH_TYPE_
* \param sig: pointer to buffer to take signature
* \param sig_len: length of the buffer (must be >= length of key N)
*
* Returns <0 for error, or \p sig_len for success.
*
* This creates an RSA signature for a hash you already computed and provide.
* You should have created the hash before calling this by iterating over the
* actual payload you need to confirm.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in,
enum lws_genhash_types hash_type,
uint8_t *sig, size_t sig_len);
/** lws_genrsa_public_decrypt_destroy() - Destroy RSA public decrypt context
*
* \param ctx: your struct lws_genrsa_ctx
*
* Destroys any allocations related to \p ctx.
*
* This and related APIs operate identically with OpenSSL or mbedTLS backends.
*/
LWS_VISIBLE LWS_EXTERN void
lws_genrsa_destroy(struct lws_genrsa_ctx *ctx);
/** lws_genrsa_render_pkey_asn1() - Exports public or private key to ASN1/DER
*
* \param ctx: your struct lws_genrsa_ctx
* \param _private: 0 = public part only, 1 = all parts of the key
* \param pkey_asn1: pointer to buffer to take the ASN1
* \param pkey_asn1_len: max size of the pkey_asn1_len
*
* Returns length of pkey_asn1 written, or -1 for error.
*/
LWS_VISIBLE LWS_EXTERN int
lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private,
uint8_t *pkey_asn1, size_t pkey_asn1_len);
///@}

View File

@ -0,0 +1,60 @@
/*
* Generic GPIO ops
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for gpio, a real implementation provides
* functions for the ops that use the underlying OS gpio arrangements.
*/
#if !defined(__LWS_GPIO_H__)
#define __LWS_GPIO_H__
typedef int _lws_plat_gpio_t;
typedef enum {
LWSGGPIO_IRQ_NONE,
LWSGGPIO_IRQ_RISING,
LWSGGPIO_IRQ_FALLING,
LWSGGPIO_IRQ_CHANGE,
LWSGGPIO_IRQ_LOW,
LWSGGPIO_IRQ_HIGH
} lws_gpio_irq_t;
enum {
LWSGGPIO_FL_READ = (1 << 0),
LWSGGPIO_FL_WRITE = (1 << 1),
LWSGGPIO_FL_PULLUP = (1 << 2),
LWSGGPIO_FL_PULLDOWN = (1 << 3),
LWSGGPIO_FL_START_LOW = (1 << 4),
};
typedef void (*lws_gpio_irq_cb_t)(void *arg);
typedef struct lws_gpio_ops {
void (*mode)(_lws_plat_gpio_t gpio, int flags);
int (*read)(_lws_plat_gpio_t gpio);
void (*set)(_lws_plat_gpio_t gpio, int val);
int (*irq_mode)(_lws_plat_gpio_t gpio, lws_gpio_irq_t irq,
lws_gpio_irq_cb_t cb, void *arg);
} lws_gpio_ops_t;
#endif

View File

@ -0,0 +1,717 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2022 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.
*
* Extremely Lightweight HTML5 Stream Parser, same approach as lecp but for
* html5.
*/
#if !defined(LHP_MAX_ELEMS_NEST)
#define LHP_MAX_ELEMS_NEST 32
#endif
#if !defined(LHP_MAX_DEPTH)
#define LHP_MAX_DEPTH 12
#endif
#if !defined(LHP_STRING_CHUNK)
#define LHP_STRING_CHUNK 254
#endif
enum lhp_callbacks {
LHPCB_ERR_ATTRIB_SYNTAX = -5,
LHPCB_ERR_ATTRIB_LEN = -4,
LHPCB_ERR_OOM = -3,
LHPCB_ERR_ELEM_DEPTH = -2,
LHPCB_CONTINUE = -1,
LHPCB_CONSTRUCTED = 0,
LHPCB_DESTRUCTED = 1,
LHPCB_COMPLETE = 2,
LHPCB_FAILED = 3,
LHPCB_ELEMENT_START = 4, /* reported at end of <> */
LHPCB_ELEMENT_END = 5,
LHPCB_CONTENT = 6,
LHPCB_COMMENT = 7,
};
/*
* CSS v2.1 full property set, taken from
*
* https://www.w3.org/TR/CSS21/propidx.html
*/
typedef enum lcsp_props {
LCSP_PROP_AZIMUTH,
LCSP_PROP_BACKGROUND_ATTACHMENT,
LCSP_PROP_BACKGROUND_COLOR,
LCSP_PROP_BACKGROUND_IMAGE,
LCSP_PROP_BACKGROUND_POSITION,
LCSP_PROP_BACKGROUND_REPEAT,
LCSP_PROP_BACKGROUND,
LCSP_PROP_BORDER_COLLAPSE,
LCSP_PROP_BORDER_COLOR,
LCSP_PROP_BORDER_SPACING,
LCSP_PROP_BORDER_STYLE,
LCSP_PROP_BORDER_TOP,
LCSP_PROP_BORDER_RIGHT,
LCSP_PROP_BORDER_BOTTOM,
LCSP_PROP_BORDER_LEFT,
LCSP_PROP_BORDER_TOP_COLOR,
LCSP_PROP_BORDER_RIGHT_COLOR,
LCSP_PROP_BORDER_BOTTOM_COLOR,
LCSP_PROP_BORDER_LEFT_COLOR,
LCSP_PROP_BORDER_TOP_STYLE,
LCSP_PROP_BORDER_RIGHT_STYLE,
LCSP_PROP_BORDER_BOTTOM_STYLE,
LCSP_PROP_BORDER_LEFT_STYLE,
LCSP_PROP_BORDER_TOP_WIDTH,
LCSP_PROP_BORDER_RIGHT_WIDTH,
LCSP_PROP_BORDER_BOTTOM_WIDTH,
LCSP_PROP_BORDER_LEFT_WIDTH,
LCSP_PROP_BORDER_WIDTH,
LCSP_PROP_BORDER_TOP_LEFT_RADIUS,
LCSP_PROP_BORDER_TOP_RIGHT_RADIUS,
LCSP_PROP_BORDER_BOTTOM_LEFT_RADIUS,
LCSP_PROP_BORDER_BOTTOM_RIGHT_RADIUS,
LCSP_PROP_BORDER_RADIUS,
LCSP_PROP_BORDER,
LCSP_PROP_BOTTOM,
LCSP_PROP_CAPTION_SIDE,
LCSP_PROP_CLEAR,
LCSP_PROP_CLIP,
LCSP_PROP_COLOR,
LCSP_PROP_CONTENT,
LCSP_PROP_COUNTER_INCREMENT,
LCSP_PROP_COUNTER_RESET,
LCSP_PROP_CUE_AFTER,
LCSP_PROP_CUE_BEFORE,
LCSP_PROP_CUE,
LCSP_PROP_CURSOR,
LCSP_PROP_DIRECTION,
LCSP_PROP_DISPLAY,
LCSP_PROP_ELEVATION,
LCSP_PROP_EMPTY_CELLS,
LCSP_PROP_FLOAT,
LCSP_PROP_FONT_FAMILY,
LCSP_PROP_FONT_SIZE,
LCSP_PROP_FONT_STYLE,
LCSP_PROP_FONT_VARAIANT,
LCSP_PROP_FONT_WEIGHT,
LCSP_PROP_FONT,
LCSP_PROP_HEIGHT,
LCSP_PROP_LEFT,
LCSP_PROP_LETTER_SPACING,
LCSP_PROP_LINE_HEIGHT,
LCSP_PROP_LIST_STYLE_IMAGE,
LCSP_PROP_LIST_STYLE_POSITION,
LCSP_PROP_LIST_STYLE_TYPE,
LCSP_PROP_LIST_STYLE,
LCSP_PROP_MARGIN_RIGHT,
LCSP_PROP_MARGIN_LEFT,
LCSP_PROP_MARGIN_TOP,
LCSP_PROP_MARGIN_BOTTOM,
LCSP_PROP_MARGIN,
LCSP_PROP_MAX_HEIGHT,
LCSP_PROP_MAX_WIDTH,
LCSP_PROP_MIN_HEIGHT,
LCSP_PROP_MIN_WIDTH,
LCSP_PROP_ORPHANS,
LCSP_PROP_OUTLINE_COLOR,
LCSP_PROP_OUTLINE_STYLE,
LCSP_PROP_OUTLINE_WIDTH,
LCSP_PROP_OUTLINE,
LCSP_PROP_OVERFLOW,
LCSP_PROP_PADDING_TOP,
LCSP_PROP_PADDING_RIGHT,
LCSP_PROP_PADDING_BOTTOM,
LCSP_PROP_PADDING_LEFT,
LCSP_PROP_PADDING,
LCSP_PROP_PAGE_BREAK_AFTER,
LCSP_PROP_PAGE_BREAK_BEFORE,
LCSP_PROP_PAGE_BREAK_INSIDE,
LCSP_PROP_PAUSE_AFTER,
LCSP_PROP_PAUSE_BEFORE,
LCSP_PROP_PAUSE,
LCSP_PROP_PITCH_RANGE,
LCSP_PROP_PITCH,
LCSP_PROP_PLAY_DURING,
LCSP_PROP_POSITION,
LCSP_PROP_QUOTES,
LCSP_PROP_RICHNESS,
LCSP_PROP_RIGHT,
LCSP_PROP_SPEAK_HEADER,
LCSP_PROP_SPEAK_NUMERAL,
LCSP_PROP_SPEAK_PUNCTUATION,
LCSP_PROP_SPEAK,
LCSP_PROP_SPEECH_RATE,
LCSP_PROP_STRESS,
LCSP_PROP_TABLE_LAYOUT,
LCSP_PROP_TEXT_ALIGN,
LCSP_PROP_TEXT_DECORATION,
LCSP_PROP_TEXT_INDENT,
LCSP_PROP_TEXT_TRANSFORM,
LCSP_PROP_TOP,
LCSP_PROP_UNICODE_BIDI,
LCSP_PROP_VERTICAL_ALIGN,
LCSP_PROP_VISIBILITY,
LCSP_PROP_VOICE_FAMILY,
LCSP_PROP_VOLUME,
LCSP_PROP_WHITE_SPACE,
LCSP_PROP_WIDOWS,
LCSP_PROP_WIDTH,
LCSP_PROP_WORD_SPACING,
LCSP_PROP_Z_INDEX,
LCSP_PROP__COUNT /* always last */
} lcsp_props_t;
/*
* Indexes for the well-known property values
*/
typedef enum {
LCSP_PROPVAL_ABOVE,
LCSP_PROPVAL_ABSOLUTE,
LCSP_PROPVAL_ALWAYS,
LCSP_PROPVAL_ARMENIAN,
LCSP_PROPVAL_AUTO,
LCSP_PROPVAL_AVOID,
LCSP_PROPVAL_BASELINE,
LCSP_PROPVAL_BEHIND,
LCSP_PROPVAL_BELOW,
LCSP_PROPVAL_BIDI_OVERRIDE,
LCSP_PROPVAL_BLINK,
LCSP_PROPVAL_BLOCK,
LCSP_PROPVAL_BOLD,
LCSP_PROPVAL_BOLDER,
LCSP_PROPVAL_BOTH,
LCSP_PROPVAL_BOTTOM,
LCSP_PROPVAL_CAPITALIZE,
LCSP_PROPVAL_CAPTION,
LCSP_PROPVAL_CENTER,
LCSP_PROPVAL_CIRCLE,
LCSP_PROPVAL_CLOSE_QUOTE,
LCSP_PROPVAL_CODE,
LCSP_PROPVAL_COLLAPSE,
LCSP_PROPVAL_CONTINUOUS,
LCSP_PROPVAL_CROSSHAIR,
LCSP_PROPVAL_DECIMAL_LEADING_ZERO,
LCSP_PROPVAL_DECIMAL,
LCSP_PROPVAL_DIGITS,
LCSP_PROPVAL_DISC,
LCSP_PROPVAL_EMBED,
LCSP_PROPVAL_E_RESIZE,
LCSP_PROPVAL_FIXED,
LCSP_PROPVAL_GEORGIAN,
LCSP_PROPVAL_HELP,
LCSP_PROPVAL_HIDDEN,
LCSP_PROPVAL_HIDE,
LCSP_PROPVAL_HIGH,
LCSP_PROPVAL_HIGHER,
LCSP_PROPVAL_ICON,
LCSP_PROPVAL_INHERIT,
LCSP_PROPVAL_INLINE,
LCSP_PROPVAL_INLINE_BLOCK,
LCSP_PROPVAL_INLINE_TABLE,
LCSP_PROPVAL_INVERT,
LCSP_PROPVAL_ITALIC,
LCSP_PROPVAL_JUSTIFY,
LCSP_PROPVAL_LEFT,
LCSP_PROPVAL_LIGHTER,
LCSP_PROPVAL_LINE_THROUGH,
LCSP_PROPVAL_LIST_ITEM,
LCSP_PROPVAL_LOW,
LCSP_PROPVAL_LOWER,
LCSP_PROPVAL_LOWER_ALPHA,
LCSP_PROPVAL_LOWERCASE,
LCSP_PROPVAL_LOWER_GREEK,
LCSP_PROPVAL_LOWER_LATIN,
LCSP_PROPVAL_LOWER_ROMAN,
LCSP_PROPVAL_LTR,
LCSP_PROPVAL_MENU,
LCSP_PROPVAL_MESSAGE_BOX,
LCSP_PROPVAL_MIDDLE,
LCSP_PROPVAL_MIX,
LCSP_PROPVAL_MOVE,
LCSP_PROPVAL_NE_RESIZE,
LCSP_PROPVAL_NO_CLOSE_QUOTE,
LCSP_PROPVAL_NONE,
LCSP_PROPVAL_NO_OPEN_QUOTE,
LCSP_PROPVAL_NO_REPEAT,
LCSP_PROPVAL_NORMAL,
LCSP_PROPVAL_NOWRAP,
LCSP_PROPVAL_N_RESIZE,
LCSP_PROPVAL_NW_RESIZE,
LCSP_PROPVAL_OBLIQUE,
LCSP_PROPVAL_ONCE,
LCSP_PROPVAL_OPEN_QUOTE,
LCSP_PROPVAL_OUTSIDE,
LCSP_PROPVAL_OVERLINE,
LCSP_PROPVAL_POINTER,
LCSP_PROPVAL_PRE,
LCSP_PROPVAL_PRE_LINE,
LCSP_PROPVAL_PRE_WRAP,
LCSP_PROPVAL_PROGRESS,
LCSP_PROPVAL_RELATIVE,
LCSP_PROPVAL_REPEAT,
LCSP_PROPVAL_REPEAT_X,
LCSP_PROPVAL_REPEAT_Y,
LCSP_PROPVAL_RIGHT,
LCSP_PROPVAL_RTL,
LCSP_PROPVAL_SCROLL,
LCSP_PROPVAL_SEPARATE,
LCSP_PROPVAL_SE_RESIZE,
LCSP_PROPVAL_SHOW,
LCSP_PROPVAL_SILENT,
LCSP_PROPVAL_SMALL_CAPS,
LCSP_PROPVAL_SMALL_CAPTION,
LCSP_PROPVAL_SPELL_OUT,
LCSP_PROPVAL_SQUARE,
LCSP_PROPVAL_S_RESIZE,
LCSP_PROPVAL_STATIC,
LCSP_PROPVAL_STATUS_BAR,
LCSP_PROPVAL_SUB,
LCSP_PROPVAL_SUPER,
LCSP_PROPVAL_SW_RESIZE,
LCSP_PROPVAL_TABLE,
LCSP_PROPVAL_TABLE_CAPTION,
LCSP_PROPVAL_TABLE_CELL,
LCSP_PROPVAL_TABLE_COLUMN,
LCSP_PROPVAL_TABLE_COLUMN_GROUP,
LCSP_PROPVAL_TABLE_FOOTER_GROUP,
LCSP_PROPVAL_TABLE_HEADER_GROUP,
LCSP_PROPVAL_TABLE_ROW,
LCSP_PROPVAL_TABLE_ROW_GROUP,
LCSP_PROPVAL_TEXT_BOTTOM,
LCSP_PROPVAL_TEXT_TOP,
LCSP_PROPVAL_TEXT,
LCSP_PROPVAL_TOP,
LCSP_PROPVAL_TRANSPARENT,
LCSP_PROPVAL_UNDERLINE,
LCSP_PROPVAL_UPPER_ALPHA,
LCSP_PROPVAL_UPPERCASE,
LCSP_PROPVAL_UPPER_LATIN,
LCSP_PROPVAL_UPPER_ROMAN,
LCSP_PROPVAL_VISIBLE,
LCSP_PROPVAL_WAIT,
LCSP_PROPVAL_W_RESIZE,
LCSP_PROPVAL__COUNT /* always last */
} lcsp_propvals_t;
struct lhp_ctx;
typedef lws_stateful_ret_t (*lhp_callback)(struct lhp_ctx *ctx, char reason);
/* html attribute */
typedef struct lhp_atr {
lws_dll2_t list;
size_t name_len; /* 0 if it is elem tag */
size_t value_len;
/* name+NUL then value+NUL follow */
} lhp_atr_t;
/*
* In order to lay out the table, we have to incrementally adjust all foregoing
* DLOs as newer cells change the situation. So we have to keep track of all
* cell DLOs in a stack of tables until it's all done.
*/
typedef struct {
lws_dll2_t list; /* ps->table_cols */
lws_dll2_owner_t row_dlos; /* lws_dlo_t in column */
lws_fx_t height; /* currently computed row height */
} lhp_table_row_t;
typedef struct {
lws_dll2_t list; /* ps->table_cols */
lws_dll2_owner_t col_dlos; /* lws_dlo_t in column */
lws_fx_t width; /* currently computed column width */
} lhp_table_col_t;
struct lcsp_atr;
#define CCPAS_TOP 0
#define CCPAS_RIGHT 1
#define CCPAS_BOTTOM 2
#define CCPAS_LEFT 3
typedef struct lhp_pstack {
lws_dll2_t list;
void *user; /* private to the stack level */
lhp_callback cb;
/* static: x,y: offset from parent, w,h: surface size of this object */
lws_box_t drt;
/* dynamic cursor inside drt for progressive child placement */
lws_fx_t curx;
lws_fx_t cury;
lws_fx_t widest;
lws_fx_t deepest;
lws_dlo_t *dlo_set_curx;
lws_dlo_t *dlo_set_cury;
lws_dll2_owner_t atr; /* lhp_atr_t */
const lws_display_font_t *f;
const struct lcsp_atr *css_background_color;
const struct lcsp_atr *css_color;
const struct lcsp_atr *css_position;
const struct lcsp_atr *css_display;
const struct lcsp_atr *css_width;
const struct lcsp_atr *css_height;
const struct lcsp_atr *css_border_radius[4];
const struct lcsp_atr *css_pos[4];
const struct lcsp_atr *css_margin[4];
const struct lcsp_atr *css_padding[4];
uint16_t tr_idx; /* in table */
uint16_t td_idx; /* in current tr */
uint8_t is_block:1; /* children use space in our drt */
uint8_t is_table:1;
/* user layout owns these after initial values set */
lws_dlo_t *dlo;
const lws_display_font_t *font;
int oi[4];
int positioned[4];
int rel_layout_cursor[4];
uint8_t runon; /* continues same line */
} lhp_pstack_t;
typedef enum lcsp_css_units {
LCSP_UNIT_NONE,
LCSP_UNIT_NUM, /* u.i */
LCSP_UNIT_LENGTH_EM, /* u.i */
LCSP_UNIT_LENGTH_EX, /* u.i */
LCSP_UNIT_LENGTH_IN, /* u.i */
LCSP_UNIT_LENGTH_CM, /* u.i */
LCSP_UNIT_LENGTH_MM, /* u.i */
LCSP_UNIT_LENGTH_PT, /* u.i */
LCSP_UNIT_LENGTH_PC, /* u.i */
LCSP_UNIT_LENGTH_PX, /* u.i */
LCSP_UNIT_LENGTH_PERCENT, /* u.i */
LCSP_UNIT_ANGLE_ABS_DEG, /* u.i */
LCSP_UNIT_ANGLE_REL_DEG, /* u.i */
LCSP_UNIT_FREQ_HZ, /* u.i */
LCSP_UNIT_RGBA, /* u.rgba */
LCSP_UNIT_URL, /* string at end of atr */
LCSP_UNIT_STRING, /* string at end of atr */
LCSP_UNIT_DATA, /* binary data at end of atr */
} lcsp_css_units_t;
typedef struct lcsp_atr {
lws_dll2_t list;
int propval; /* lcsp_propvals_t LCSP_PROPVAL_ */
size_t value_len; /* for string . url */
lcsp_css_units_t unit;
union {
lws_fx_t i;
uint32_t rgba; /* for colours */
} u;
lws_fx_t r;
uint8_t op;
/* .value_len bytes follow (for strings and blobs) */
} lcsp_atr_t;
/* css definitions like font-weight: */
typedef struct lcsp_defs {
lws_dll2_t list;
lws_dll2_owner_t atrs; /* lcsp_atr_t */
lcsp_props_t prop; /* lcsp_props_t, LCSP_PROP_* */
} lcsp_defs_t;
typedef struct lcsp_names {
lws_dll2_t list;
size_t name_len;
/* name + NUL follow */
} lcsp_names_t;
typedef struct lcsp_stanza { /* css stanza, with names and defs */
lws_dll2_t list;
lws_dll2_owner_t names; /* lcsp_names_t */
lws_dll2_owner_t defs; /* lcsp_defs_t */
} lcsp_stanza_t;
/*
* A list of stanza references can easily have to bring in the same stanza
* multiple times, eg, <div><span class=x><div> won't work unless the div
* stanzas are listed twice at different places in the list. It means we can't
* use dll2 directly since the number of references is open-ended.
*
* lcsp_stanza_ptr provides indirection that allows multiple listings.
*/
typedef struct lcsp_stanza_ptr {
lws_dll2_t list;
lcsp_stanza_t *stz;
} lcsp_stanza_ptr_t;
typedef struct lcsp_atr_ptr {
lws_dll2_t list;
lcsp_atr_t *atr;
} lcsp_atr_ptr_t;
#define LHP_FLAG_DOCUMENT_END (1 << 0)
typedef struct lhp_ctx {
lws_dll2_owner_t stack; /* lhp_pstack_t */
struct lwsac *cssac; /* css allocations all in an ac */
struct lwsac *cascadeac; /* active_stanzas ac */
struct lwsac *propatrac; /* prop atr query results ac */
lws_dll2_owner_t css; /* lcsp_stanza_t (all in ac) */
lws_dll2_owner_t *ids;
lws_fx_t tf;
lcsp_css_units_t unit;
lcsp_stanza_t *stz; /* current stanza getting properties */
lcsp_defs_t *def; /* current property getting values */
lws_dll2_owner_t active_stanzas; /* lcsp_stanza_ptr_t allocated
* in cascadeac */
lws_dll2_owner_t active_atr; /* lcsp_atr_ptr_t allocated in
* propatrac */
lws_surface_info_t ic;
const char *base_url; /* strdup of https://x.com/y.html */
sul_cb_t ssevcb; /* callback for ss events */
lws_sorted_usec_list_t *ssevsul; /* sul to use to resume rz */
sul_cb_t sshtmlevcb; /* callback for more html parse */
lws_sorted_usec_list_t *sshtmlevsul; /* sul for more html parse */
void *user;
void *user1;
const char *tag; /* private */
size_t tag_len; /* private */
int npos;
int state; /* private */
int state_css_comm; /* private */
int nl_temp;
int temp_count;
uint32_t flags;
uint32_t temp;
int32_t window; /* 0, or ss item flow control limit */
union {
uint32_t s;
struct {
uint32_t first:1;
uint32_t closing:1;
uint32_t void_element:1;
uint32_t doctype:1;
uint32_t inq:1;
uint32_t tag_used:1;
uint32_t arg:1;
uint32_t default_css:1;
#define LHP_CSS_PROPVAL_INT_WHOLE 1
#define LHP_CSS_PROPVAL_INT_FRAC 2
#define LHP_CSS_PROPVAL_INT_UNIT 3
uint32_t integer:2;
uint32_t color:2;
} f;
} u;
int prop; /* lcsp_props_t */
int propval; /* lcsp_propvals_t */
int16_t css_state; /* private */
int16_t cssval_state; /* private */
uint8_t in_body:1;
uint8_t finish_css:1;
uint8_t is_css:1;
uint8_t await_css_done:1;
/* at end so we can memset members above it in one go */
char buf[LHP_STRING_CHUNK + 1];
} lhp_ctx_t;
/*
* lws_lhp_construct() - Construct an lhp context
*
* \param ctx: the lhp context to prepare
* \param cb: the stream parsing callback
* \param user: opaque user pointer available from the lhp context
* \param ic: struct with arguments for lhp context
*
* The lhp context is allocated by the caller (the size is known).
* Prepares an lhp context to parse html. Returns 0 for OK, or nonzero if OOM.
*/
LWS_VISIBLE LWS_EXTERN int
lws_lhp_construct(lhp_ctx_t *ctx, lhp_callback cb, void *user,
const lws_surface_info_t *ic);
/*
* lws_lhp_destruct() - Destroy an lhp context
*
* \param ctx: the lhp context to prepare
*
* Destroys an lhp context. The lhp context is allocated by the caller (the
* size is known). But there are suballocations that must be destroyed with
* this.
*/
LWS_VISIBLE LWS_EXTERN void
lws_lhp_destruct(lhp_ctx_t *ctx);
/**
* lws_lhp_ss_browse() - browse url using SS and parse via lhp to DLOs
*
* \param cx: the lws_context
* \param rs: the user's render state object
* \param url: the https://x.com/y.xyz URL to browse
* \param render: the user's linewise render callback (called from \p rs.sul)
*
* High level network fetch via SS and render html via lhp / DLO
*
* rs->ic must be prepared before calling.
*
* Returns nonzero if an early, fatal problem, else returns 0 and continues
* asynchronously.
*
* If rs->box is (0,0,0,0) on entry, it is set to represent the whole display
* surface. Otherwise if not representing the whole display surface, it
* indicates partial mode should be used.
*/
LWS_VISIBLE LWS_EXTERN int
lws_lhp_ss_browse(struct lws_context *cx, lws_display_render_state_t *rs,
const char *url, sul_cb_t render);
/**
* lws_lhp_parse() - parses a chunk of input HTML
*
* \p ctx: the parsing context
* \p buf: pointer to the start of the chunk of html
* \p len: pointer the number of bytes of html available at *\pbuf
*
* Parses up to *len bytes at *buf. On exit, *buf and *len are adjusted
* according to how much data was used. May return before processing all the
* input.
*
* Returns LWS_SRET_WANT_INPUT if the parsing is stalled on some other async
* event (eg, fetch of image to find out the dimensions).
*
* The lws_lhp_ss_browse() api wraps this.
*/
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_lhp_parse(lhp_ctx_t *ctx, const uint8_t **buf, size_t *len);
/**
* lws_css_cascade_get_prop_atr() - create active css atr list for property
*
* \p ctx: the parsing context
* \p prop: the LCSP_PROP_ property to generate the attribute list for
*
* Returns NULL if no atr or OOM.
*
* Otherwise produces a list of active CSS property attributes walkable via
* ctx->active_atr, and returns the tail one. For simple attributes where the
* last definition is the active one, this points to the last definition.
*/
LWS_VISIBLE LWS_EXTERN const lcsp_atr_t *
lws_css_cascade_get_prop_atr(lhp_ctx_t *ctx, lcsp_props_t prop);
/**
* lws_http_rel_to_url() - make absolute url from base and relative
*
* \param dest: place to store the result
* \param len: max length of result including NUL
* \param base: a reference url including a file part
* \param rel: the absolute or relative url or path to apply to base
*
* Copy the url formof rel into dest, using base to fill in missing context
*
* If base is https://x.com/y/z.html
*
* a.html -> https://x.com/y/a/html
* ../b.html -> https://x.com/b.html
* /c.html -> https://x.com/c.html
* https://y.com/a.html -> https://y.com/a.html
*/
LWS_VISIBLE LWS_EXTERN int
lws_http_rel_to_url(char *dest, size_t len, const char *base, const char *rel);
LWS_VISIBLE LWS_EXTERN lhp_pstack_t *
lws_css_get_parent_block(lhp_ctx_t *ctx, lhp_pstack_t *ps);
LWS_VISIBLE LWS_EXTERN const char *
lws_css_pstack_name(lhp_pstack_t *ps);
LWS_VISIBLE LWS_EXTERN const char *
lws_html_get_atr(lhp_pstack_t *ps, const char *aname, size_t aname_len);
LWS_VISIBLE LWS_EXTERN const lws_fx_t *
lws_csp_px(const lcsp_atr_t *a, lhp_pstack_t *ps);
LWS_VISIBLE LWS_EXTERN void
lws_lhp_tag_dlo_id(lhp_ctx_t *ctx, lhp_pstack_t *ps, lws_dlo_t *dlo);
void
lhp_set_dlo_padding_margin(lhp_pstack_t *ps, lws_dlo_t *dlo);
#define LWS_LHPREF_WIDTH 0
#define LWS_LHPREF_HEIGHT 1
#define LWS_LHPREF_NONE 2
LWS_VISIBLE LWS_EXTERN int
lhp_prop_axis(const lcsp_atr_t *a);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/*
* Generic I2C ops
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for i2c, a real implementation provides
* functions for the ops that use the underlying OS arrangements.
*/
#if !defined(__LWS_I2C_H__)
#define __LWS_I2C_H__
#include <stdint.h>
#include <stddef.h>
typedef struct lws_i2c_ops {
int (*init)(const struct lws_i2c_ops *ctx);
int (*start)(const struct lws_i2c_ops *ctx);
void (*stop)(const struct lws_i2c_ops *ctx);
int (*write)(const struct lws_i2c_ops *ctx, uint8_t data);
int (*read)(const struct lws_i2c_ops *ctx);
void (*set_ack)(const struct lws_i2c_ops *octx, int ack);
} lws_i2c_ops_t;
/*
* These are implemented by calling the ops above, and so are generic
*/
LWS_VISIBLE LWS_EXTERN int
lws_i2c_command(const lws_i2c_ops_t *ctx, uint8_t ads7, uint8_t c);
LWS_VISIBLE LWS_EXTERN int
lws_i2c_command_list(const lws_i2c_ops_t *ctx, uint8_t ads7, const uint8_t *buf,
size_t len);
#endif

View File

@ -0,0 +1,54 @@
/*
* lws abstract display implementation for ili9341 on spi
*
* Copyright (C) 2019 - 2022 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.
*/
#if !defined(__LWS_DISPLAY_ILI9341_SPI_H__)
#define __LWS_DISPLAY_ILI9341_SPI_H__
typedef struct lws_display_ili9341 {
lws_display_t disp; /* use lws_display_ili9341_ops to set */
const lws_spi_ops_t *spi; /* spi ops */
lws_display_completion_t cb;
const lws_gpio_ops_t *gpio; /* NULL or gpio ops */
_lws_plat_gpio_t reset_gpio; /* if gpio ops, nReset gpio # */
uint8_t spi_index; /* cs index starting from 0 */
} lws_display_ili9341_t;
int
lws_display_ili9341_spi_init(lws_display_state_t *lds);
int
lws_display_ili9341_spi_blit(lws_display_state_t *lds, const uint8_t *src,
lws_box_t *box, lws_dll2_owner_t *ids);
int
lws_display_ili9341_spi_power(lws_display_state_t *lds, int state);
#define lws_display_ili9341_ops \
.init = lws_display_ili9341_spi_init, \
.blit = lws_display_ili9341_spi_blit, \
.power = lws_display_ili9341_spi_power
#endif

View File

@ -0,0 +1,215 @@
/*
* 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.
*/
enum lws_jws_jose_hdr_indexes {
LJJHI_ALG, /* REQUIRED */
LJJHI_JKU, /* Optional: string */
LJJHI_JWK, /* Optional: jwk JSON object: public key: */
LJJHI_KID, /* Optional: string */
LJJHI_X5U, /* Optional: string: url of public key cert / chain */
LJJHI_X5C, /* Optional: base64 (NOT -url): actual cert */
LJJHI_X5T, /* Optional: base64url: SHA-1 of actual cert */
LJJHI_X5T_S256, /* Optional: base64url: SHA-256 of actual cert */
LJJHI_TYP, /* Optional: string: media type */
LJJHI_CTY, /* Optional: string: content media type */
LJJHI_CRIT, /* Optional for send, REQUIRED: array of strings:
* mustn't contain standardized strings or null set */
LJJHI_RECIPS_HDR,
LJJHI_RECIPS_HDR_ALG,
LJJHI_RECIPS_HDR_KID,
LJJHI_RECIPS_EKEY,
LJJHI_ENC, /* JWE only: Optional: string */
LJJHI_ZIP, /* JWE only: Optional: string ("DEF" = deflate) */
LJJHI_EPK, /* Additional arg for JWE ECDH: ephemeral public key */
LJJHI_APU, /* Additional arg for JWE ECDH: base64url */
LJJHI_APV, /* Additional arg for JWE ECDH: base64url */
LJJHI_IV, /* Additional arg for JWE AES: base64url */
LJJHI_TAG, /* Additional arg for JWE AES: base64url */
LJJHI_P2S, /* Additional arg for JWE PBES2: base64url: salt */
LJJHI_P2C, /* Additional arg for JWE PBES2: integer: count */
LWS_COUNT_JOSE_HDR_ELEMENTS
};
enum lws_jose_algtype {
LWS_JOSE_ENCTYPE_NONE,
LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5,
LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP,
LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS,
LWS_JOSE_ENCTYPE_ECDSA,
LWS_JOSE_ENCTYPE_ECDHES,
LWS_JOSE_ENCTYPE_AES_CBC,
LWS_JOSE_ENCTYPE_AES_CFB128,
LWS_JOSE_ENCTYPE_AES_CFB8,
LWS_JOSE_ENCTYPE_AES_CTR,
LWS_JOSE_ENCTYPE_AES_ECB,
LWS_JOSE_ENCTYPE_AES_OFB,
LWS_JOSE_ENCTYPE_AES_XTS, /* care: requires double-length key */
LWS_JOSE_ENCTYPE_AES_GCM,
};
/* there's a table of these defined in lws-gencrypto-common.c */
struct lws_jose_jwe_alg {
enum lws_genhash_types hash_type;
enum lws_genhmac_types hmac_type;
enum lws_jose_algtype algtype_signing; /* the signing cipher */
enum lws_jose_algtype algtype_crypto; /* the encryption cipher */
const char *alg; /* the JWA enc alg name, eg "ES512" */
const char *curve_name; /* NULL, or, eg, "P-256" */
unsigned short keybits_min, keybits_fixed;
unsigned short ivbits;
};
/*
* For JWS, "JOSE header" is defined to be the union of...
*
* o JWS Protected Header
* o JWS Unprotected Header
*
* For JWE, the "JOSE header" is the union of...
*
* o JWE Protected Header
* o JWE Shared Unprotected Header
* o JWE Per-Recipient Unprotected Header
*/
#define LWS_JWS_MAX_RECIPIENTS 3
struct lws_jws_recpient {
/*
* JOSE per-recipient unprotected header... for JWS this contains
* protected / header / signature
*/
struct lws_gencrypto_keyelem unprot[LWS_COUNT_JOSE_HDR_ELEMENTS];
struct lws_jwk jwk_ephemeral; /* recipient ephemeral key if any */
struct lws_jwk jwk; /* recipient "jwk" key if any */
};
struct lws_jose {
/* JOSE protected and unprotected header elements */
struct lws_gencrypto_keyelem e[LWS_COUNT_JOSE_HDR_ELEMENTS];
struct lws_jws_recpient recipient[LWS_JWS_MAX_RECIPIENTS];
char typ[32];
char edone[LWS_COUNT_JOSE_HDR_ELEMENTS];
/* information from the protected header part */
const struct lws_jose_jwe_alg *alg;
const struct lws_jose_jwe_alg *enc_alg;
int recipients; /* count of used recipient[] entries */
};
/**
* lws_jose_init() - prepare a struct lws_jose for use
*
* \param jose: the jose header struct to prepare
*/
LWS_VISIBLE LWS_EXTERN void
lws_jose_init(struct lws_jose *jose);
/**
* lws_jose_destroy() - retire a struct lws_jose from use
*
* \param jose: the jose header struct to destroy
*/
LWS_VISIBLE LWS_EXTERN void
lws_jose_destroy(struct lws_jose *jose);
/**
* lws_gencrypto_jws_alg_to_definition() - look up a jws alg name
*
* \param alg: the jws alg name
* \param jose: pointer to the pointer to the info struct to set on success
*
* Returns 0 if *jose set, else nonzero for failure
*/
LWS_VISIBLE LWS_EXTERN int
lws_gencrypto_jws_alg_to_definition(const char *alg,
const struct lws_jose_jwe_alg **jose);
/**
* lws_gencrypto_jwe_alg_to_definition() - look up a jwe alg name
*
* \param alg: the jwe alg name
* \param jose: pointer to the pointer to the info struct to set on success
*
* Returns 0 if *jose set, else nonzero for failure
*/
LWS_VISIBLE LWS_EXTERN int
lws_gencrypto_jwe_alg_to_definition(const char *alg,
const struct lws_jose_jwe_alg **jose);
/**
* lws_gencrypto_jwe_enc_to_definition() - look up a jwe enc name
*
* \param alg: the jwe enc name
* \param jose: pointer to the pointer to the info struct to set on success
*
* Returns 0 if *jose set, else nonzero for failure
*/
LWS_VISIBLE LWS_EXTERN int
lws_gencrypto_jwe_enc_to_definition(const char *enc,
const struct lws_jose_jwe_alg **jose);
/**
* lws_jws_parse_jose() - parse a JWS JOSE header
*
* \param jose: the jose struct to set to parsing results
* \param buf: the raw JOSE header
* \param len: the length of the raw JOSE header
* \param temp: parent-owned buffer to "allocate" elements into
* \param temp_len: amount of space available in temp
*
* returns 0 for success, or -1 for error
* *\p temp_len is updated to reflect the amount of \p temp used if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_parse_jose(struct lws_jose *jose,
const char *buf, int len, char *temp, int *temp_len);
/**
* lws_jwe_parse_jose() - parse a JWE JOSE header
*
* \param jose: the jose struct to set to parsing results
* \param buf: the raw JOSE header
* \param len: the length of the raw JOSE header
* \param temp: parent-owned buffer to "allocate" elements into
* \param temp_len: amount of space available in temp
*
* returns 0 for success, or -1 for error
* *\p temp_len is updated to reflect the amount of \p temp used if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwe_parse_jose(struct lws_jose *jose,
const char *buf, int len, char *temp, int *temp_len);

View File

@ -0,0 +1,104 @@
/*
* lws jpeg
*
* Copyright (C) 2019 - 2022 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.
*
* Based on public domain original with notice -->
*
* picojpeg.c v1.1 - Public domain, Rich Geldreich <richgel99@gmail.com>
* Nov. 27, 2010 - Initial release
* Feb. 9, 2013 - Added H1V2/H2V1 support, cleaned up macros, signed shift fixes
* Also integrated and tested changes from Chris Phoenix <cphoenix@gmail.com>.
*
* This version is rewritten for lws, changing the whole approach to decode on
* demand to issue a line of output at a time, statefully. This version is
* licensed MIT to match the rest of lws.
*/
typedef struct lws_jpeg lws_jpeg_t;
/**
* lws_jpeg_new() - Create new JPEG decode object
*
* Returns a new jpeg decoding object, which should be destroyed with
* lws_jpeg_free() when done with, or NULL if OOM.
*/
LWS_VISIBLE LWS_EXTERN lws_jpeg_t *
lws_jpeg_new(void);
/**
* lws_jpeg_free() - Destroy a JPEG decode object
*
* \param j: Pointer to the decode object to destroy and set to NULL
*
* This also frees any sub-allocations in the object.
*/
LWS_VISIBLE LWS_EXTERN void
lws_jpeg_free(lws_jpeg_t **j);
/**
* lws_jpeg_emit_next_line() - deocde the next line
*
* \param j: the decode object
* \param ppix: pointer to a pointer set to the line's decoded pixel data
* \param buf: pointer to a const uint8_t array of jpeg input
* \param size: pointer to the count of bytes available at *buf
* \param hold_at_metadata: true if we should not advance to decode
*
* Make jpeg input available to the decoder so it can issue the next line's
* worth of pixels. If the call consumed any input, *buf and *size are
* adjusted accordingly.
*
* The decoder is stateful so it is not sensitive to the chunk size for the
* input.
*
* If \p hold_at_metadata is set, then the decoder will only go as far as
* picking out the metadata like image dimensions, but not start the decode,
* which requires the >30KB heap allocation. This lets you put off for as long
* as possible committing to the decode allocation... this only helps overall
* if you have flow controlled the incoming PNG data.
*
* Return will be one of LWS_SRET_WANT_INPUT is the decoder is stalled waiting
* for more input to be provided, LWS_SRET_WANT_OUTPUT is the decoder stopped
* because it had produced a whole line of output pixels (which can be found
* starting at *ppix), LWS_SRET_OK is it completed and LWS_SRET_FATAL or larger
* if the decode failed.
*
* The output at *ppix is either 3-byte per pixel RGB, or 1-byte grayscale, you
* can query lws_jpeg_get_components() to find out how many bytes per pixel.
*/
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_jpeg_emit_next_line(lws_jpeg_t *j, const uint8_t **ppix,
const uint8_t **buf, size_t *size, char hold_at_metadata);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_jpeg_get_width(const lws_jpeg_t *j);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_jpeg_get_height(const lws_jpeg_t *j);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_jpeg_get_bpp(const lws_jpeg_t *j);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_jpeg_get_bitdepth(const lws_jpeg_t *j);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_jpeg_get_components(const lws_jpeg_t *j);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_jpeg_get_pixelsize(const lws_jpeg_t *j);

View File

@ -0,0 +1,229 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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.
*
*
* This is a JSON-RPC parser and state management implementation that's:
*
* - Lightweight, it uses lws LEJP JSON stream parser for requests, responses,
* and user-defined parameter objects
*
* - Stateful... you can give it sequential input buffers randomly fragmented
* and it will complete when it has enough
*
* - Asynchronous... response processing can return to the event loop both
* while the RX is still coming and after it's all received before forming
* the response, eg, because it's querying on a remote connection to get the
* response data. Any number of RPCs can be either in flight or waiting for
* response processing to complete before responding.
*
* - Supports "version" extension
*
* - allows binding different method names to different callbacks
*
* - Supports both client and server roles, eg, can parse both requests and
* responses
*
* - No support for batch. Batching is not widely used because it doesn't
* add anything for the vast bulk of cases compared to sending n requests.
*
* This handles client and server RX and transaction state, creating a callback
* when parameters can be parsed and all of the request or notification is
* done.
*
* Producing JSON is usually simpler and more compact than expressing it as an
* object model, ie often a response can be completely formed in a single
* lws_snprintf(). Response JSON must be buffered on heap until the method
* callback is called with NULL / 0 buf len indicating that the incoming request
* has completed parsing.
*
*/
/* these are opaque */
struct lws_jrpc_obj;
struct lws_jrpc;
typedef enum {
LJRPC_CBRET_CONTINUE,
LJRPC_CBRET_WANT_TO_EMIT,
LJRPC_CBRET_FINISHED,
LJRPC_CBRET_FAILED
} lws_jrpc_cb_return_t;
/*
* method name to lejp parsing handler map
*/
typedef struct lws_jrpc_method {
const char *method_name;
const char * const *paths;
lejp_callback cb;
int count_paths;
} lws_jrpc_method_t;
/*
* Boilerplate for forming correct requests
*/
/* Boilerplate to start a request */
#define LWSJRPCBP_REQ_START_S "{\"jsonrpc\":\"2.0\",\"method\":\"%s\""
/* Boilerplate to start parameters (params are left freeform for user) */
#define LWSJRPCBP_REQ_VERSION_S ",\"version\":\"%s\""
/* Boilerplate to start parameters (params are left freeform for user) */
#define LWSJRPCBP_REQ_PARAMS ",\"params\":"
/* Boilerplate to complete the result object */
#define LWSJRPCBP_REQ_NOTIF_END "}"
/* Boilerplate to complete the result object */
#define LWSJRPCBP_REQ_ID_END_S ",\"id\":%s}"
/*
* Boilerplate for forming correct responses
*/
/* Boilerplate to start a result */
#define LWSJRPCBP_RESP_RESULT "{\"jsonrpc\":\"2.0\",\"result\":"
/* Boilerplate to complete the result object */
#define LWSJRPCBP_RESP_ID_END_S ",\"id\":%s}"
/* Boilerplate to form an error */
#define LWSJRPCBP_RESP_ERROR_D "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":%d"
/* optional */
#define LWSJRPCBP_RESP_ERROR_MSG_S ",\"message\":\"%s\""
/* optional */
#define LWSJRPCBP_RESP_ERROR_DATA ",\"data\":"
/* required */
#define LWSJRPCBP_RESP_ERROR_END "}"
/*
* JSONRPC Well-known Errors
*/
enum {
LWSJRPCE__NO_ERROR = 0,
LWSJRPCWKE__PARSE_ERROR = -32700, /* invalid JSON */
LWSJRPCWKE__INVALID_REQUEST = -32600, /* not valid JSONRPC object */
LWSJRPCWKE__METHOD_NOT_FOUND = -32601, /* method not supported */
LWSJRPCWKE__INVALID_PARAMS = -32602, /* parameters are invalid */
LWSJRPCWKE__INTERNAL_ERROR = -32603, /* internal JSONRPC error */
LWSJRPCWKE__SERVER_ERROR_FIRST = -32000, /* implementation-defined...*/
LWSJRPCWKE__SERVER_ERROR_LAST = -32099, /* ... server errors range */
LWSJRPCE__INVALID_MEMBERS = -31000, /* reponse membs in req, vv */
};
enum {
LWSJRPC_PARSE_REQUEST,
LWSJRPC_PARSE_RESPONSE
};
/*
* APIs for the opaque JRPC request object
*/
/**
* lws_jrpc_obj_parse() - parse a request or response
*
* \param jrpc: the jrpc context this belongs to
* \param type: LWSJRPC_PARSE_REQUEST or ..._RESPONSE
* \param opaque: user-defined pointer bound to lws_jrpc, ignored by lws
* \param buf: chunk of JSON-RPC
* \param l: remaining length of JSON (may be under or oversize)
* \param r: NULL to indicate starting new req, already set means continue parse
*
* If necessary creates an opaque req object and starts parsing len bytes of
* buf. This may be undersize (more parts coming) in which case \p req will be
* set on entry next time indicating a continuation.
*
* \p type and \p opaque are ignored if it it's not the first buffer that
* creates the req object.
*
* Return code is >= 0 if completed, representing the amount of unused data in
* the input buffer. -1 indicates more input data needed, <-1 indicates an
* error from the LWSJRPCWKE_ set above, or LEJP_REJECT_UNKNOWN for OOM
*/
LWS_VISIBLE LWS_EXTERN int
lws_jrpc_obj_parse(struct lws_jrpc *jrpc, int type, void *opaque,
const char *buf, size_t l, struct lws_jrpc_obj **r);
/*
* lws_jrpc_obj_destroy() - detach and destroy a JRPC request or response
*
* \param _r: pointer to pointer to JRPC request to detach and free
*
* Detaches the req from its JRPC context and frees it and any internal
* allocations.
*/
LWS_VISIBLE LWS_EXTERN void
lws_jrpc_obj_destroy(struct lws_jrpc_obj **_r);
/*
* lws_jrpc_obj_get_opaque() - retreive the opaque pointer bound to the req
*
* \param r: pointer to pointer to JRPC request
*
* Returns the opaque pointer for a req given when it was parsed / created.
*/
LWS_VISIBLE LWS_EXTERN void *
lws_jrpc_obj_get_opaque(const struct lws_jrpc_obj *r);
/*
* lws_jrpc_obj_id() - retreive the object's id string
*
* \param r: pointer to pointer to JRPC object
*
* Returns a pointer to a correctly-typed id for use in a response; if a string,
* then it is already quoted, if an int or null then it's provided without
* quotes.
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_jrpc_obj_id(const struct lws_jrpc_obj *r);
/*
* APIs for the opaque JRPC context
*/
/**
* lws_jrpc_create() - Allocate and initialize a JRPC context
*
* \param methods: the method callbacks and names we can process
* \param opaque: user-defined pointer bound to lws_jrpc ignored by lws
*
* Allocates an opaque lws_jrpc object and binds it to the given array of
* method names and callbacks
*/
LWS_VISIBLE LWS_EXTERN struct lws_jrpc *
lws_jrpc_create(const lws_jrpc_method_t *methods, void *opaque);
/*
* lws_jrpc_destroy() - destroy an allocated JRPC context
*
* \param jrpc: pointer to pointer to jrpc to destroy
*
* Destroys any ongoing reqs in the JRPC and then destroys the JRPC and sets the
* given pointer to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_jrpc_destroy(struct lws_jrpc **jrpc);

View File

@ -0,0 +1,164 @@
/*
* 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.
*
* JWE Compact Serialization consists of
*
* BASE64URL(UTF8(JWE Protected Header)) || '.' ||
* BASE64URL(JWE Encrypted Key) || '.' ||
* BASE64URL(JWE Initialization Vector) || '.' ||
* BASE64URL(JWE Ciphertext) || '.' ||
* BASE64URL(JWE Authentication Tag)
*/
#define LWS_JWE_RFC3394_OVERHEAD_BYTES 8
#define LWS_JWE_AES_IV_BYTES 16
#define LWS_JWE_LIMIT_RSA_KEY_BITS 4096
#define LWS_JWE_LIMIT_AES_KEY_BITS (512 + 64) /* RFC3394 Key Wrap adds 64b */
#define LWS_JWE_LIMIT_EC_KEY_BITS 528 /* 521 rounded to byte boundary */
#define LWS_JWE_LIMIT_HASH_BITS (LWS_GENHASH_LARGEST * 8)
/* the largest key element for any cipher */
#define LWS_JWE_LIMIT_KEY_ELEMENT_BYTES (LWS_JWE_LIMIT_RSA_KEY_BITS / 8)
struct lws_jwe {
struct lws_jose jose;
struct lws_jws jws;
struct lws_jwk jwk;
/*
* We have to keep a copy of the CEK so we can reuse it with later
* key encryptions for the multiple recipient case.
*/
uint8_t cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
unsigned int cek_valid:1;
int recip;
};
LWS_VISIBLE LWS_EXTERN void
lws_jwe_init(struct lws_jwe *jwe, struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_jwe_destroy(struct lws_jwe *jwe);
LWS_VISIBLE LWS_EXTERN void
lws_jwe_be64(uint64_t c, uint8_t *p8);
/*
* JWE Compact Serialization consists of
*
* BASE64URL(UTF8(JWE Protected Header)) || '.' ||
* BASE64URL(JWE Encrypted Key) || '.' ||
* BASE64URL(JWE Initialization Vector) || '.' ||
* BASE64URL(JWE Ciphertext) || '.' ||
* BASE64URL(JWE Authentication Tag)
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwe_render_compact(struct lws_jwe *jwe, char *out, size_t out_len);
LWS_VISIBLE int
lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len);
LWS_VISIBLE LWS_EXTERN int
lws_jwe_json_parse(struct lws_jwe *jwe, const uint8_t *buf, int len,
char *temp, int *temp_len);
/**
* lws_jwe_auth_and_decrypt() - confirm and decrypt JWE
*
* \param jose: jose context
* \param jws: jws / jwe context... .map and .map_b64 must be filled already
*
* This is a high level JWE decrypt api that takes a jws with the maps
* already processed, and if the authentication passes, returns the decrypted
* plaintext in jws.map.buf[LJWE_CTXT] and its length in jws.map.len[LJWE_CTXT].
*
* In the jws, the following fields must have been set by the caller
*
* .context
* .jwk (the key encryption key)
* .map
* .map_b64
*
* Having the b64 and decoded maps filled externally makes it flexible where
* the data was picked from, eg, from a Complete JWE JSON serialization, a
* flattened one, or a Compact Serialization.
*
* Returns decrypt length, or -1 for failure.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwe_auth_and_decrypt(struct lws_jwe *jwe, char *temp, int *temp_len);
/**
* lws_jwe_encrypt() - perform JWE encryption
*
* \param jose: the JOSE header information (encryption types, etc)
* \param jws: the JWE elements, pointer to jwk etc
* \param temp: parent-owned buffer to "allocate" elements into
* \param temp_len: amount of space available in temp
*
* May be called up to LWS_JWS_MAX_RECIPIENTS times to encrypt the same CEK
* multiple ways on the same JWE payload.
*
* returns the amount of temp used, or -1 for error.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwe_encrypt(struct lws_jwe *jwe, char *temp, int *temp_len);
/**
* lws_jwe_create_packet() - add b64 sig to b64 hdr + payload
*
* \param jwe: the struct lws_jwe we are trying to render
* \param payload: unencoded payload JSON
* \param len: length of unencoded payload JSON
* \param nonce: Nonse string to include in protected header
* \param out: buffer to take signed packet
* \param out_len: size of \p out buffer
* \param conext: lws_context to get random from
*
* This creates a "flattened" JWS packet from the jwk and the plaintext
* payload, and signs it. The packet is written into \p out.
*
* This does the whole packet assembly and signing, calling through to
* lws_jws_sign_from_b64() as part of the process.
*
* Returns the length written to \p out, or -1.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwe_create_packet(struct lws_jwe *jwe,
const char *payload, size_t len, const char *nonce,
char *out, size_t out_len, struct lws_context *context);
/* only exposed because we have test vectors that need it */
LWS_VISIBLE LWS_EXTERN int
lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
uint8_t *aad, int aad_len);
/* only exposed because we have test vectors that need it */
LWS_VISIBLE LWS_EXTERN int
lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct,
uint8_t *out, const uint8_t *shared_secret, int sslen);

View File

@ -0,0 +1,220 @@
/*
* 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 jwk JSON Web Keys
* ## JSON Web Keys API
*
* Lws provides an API to parse JSON Web Keys into a struct lws_gencrypto_keyelem.
*
* "oct" and "RSA" type keys are supported. For "oct" keys, they are held in
* the "e" member of the struct lws_gencrypto_keyelem.
*
* Keys elements are allocated on the heap. You must destroy the allocations
* in the struct lws_gencrypto_keyelem by calling
* lws_genrsa_destroy_elements() when you are finished with it.
*/
///@{
enum enum_jwk_meta_tok {
JWK_META_KTY,
JWK_META_KID,
JWK_META_USE,
JWK_META_KEY_OPS,
JWK_META_X5C,
JWK_META_ALG,
LWS_COUNT_JWK_ELEMENTS
};
struct lws_jwk {
/* key data elements */
struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_MAX_KEYEL_COUNT];
/* generic meta key elements, like KID */
struct lws_gencrypto_keyelem meta[LWS_COUNT_JWK_ELEMENTS];
int kty; /**< one of LWS_GENCRYPTO_KTY_ */
char private_key; /* nonzero = has private key elements */
};
typedef int (*lws_jwk_key_import_callback)(struct lws_jwk *s, void *user);
struct lws_jwk_parse_state {
struct lws_jwk *jwk;
char b64[(((8192 / 8) * 4) / 3) + 1]; /* enough for 8Kb key */
lws_jwk_key_import_callback per_key_cb;
void *user;
int pos;
int cose_state;
int seen;
unsigned short possible;
};
/** lws_jwk_import() - Create a JSON Web key from the textual representation
*
* \param jwk: the JWK object to create
* \param cb: callback for each jwk-processed key, or NULL if importing a single
* key with no parent "keys" JSON
* \param user: pointer to be passed to the callback, otherwise ignored by lws.
* NULL if importing a single key with no parent "keys" JSON
* \param in: a single JWK JSON stanza in utf-8
* \param len: the length of the JWK JSON stanza in bytes
*
* Creates an lws_jwk struct filled with data from the JSON representation.
*
* There are two ways to use this... with some protocols a single jwk is
* delivered with no parent "keys": [] array. If you call this with cb and
* user as NULL, then the input will be interpreted like that and the results
* placed in s.
*
* The second case is that you are dealing with a "keys":[] array with one or
* more keys in it. In this case, the function iterates through the keys using
* s as a temporary jwk, and calls the user-provided callback for each key in
* turn while it return 0 (nonzero return from the callback terminates the
* iteration through any further keys).
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user,
const char *in, size_t len);
/** lws_jwk_destroy() - Destroy a JSON Web key
*
* \param jwk: the JWK object to destroy
*
* All allocations in the lws_jwk are destroyed
*/
LWS_VISIBLE LWS_EXTERN void
lws_jwk_destroy(struct lws_jwk *jwk);
/** lws_jwk_dup_oct() - Set a jwk to a dup'd binary OCT key
*
* \param jwk: the JWK object to set
* \param key: the JWK object to destroy
* \param len: the JWK object to destroy
*
* Sets the kty to OCT, allocates len bytes for K and copies len bytes of key
* into the allocation.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_dup_oct(struct lws_jwk *jwk, const void *key, int len);
#define LWSJWKF_EXPORT_PRIVATE (1 << 0)
#define LWSJWKF_EXPORT_NOCRLF (1 << 1)
/** lws_jwk_export() - Export a JSON Web key to a textual representation
*
* \param jwk: the JWK object to export
* \param flags: control export options
* \param p: the buffer to write the exported JWK to
* \param len: the length of the buffer \p p in bytes... reduced by used amount
*
* Returns length of the used part of the buffer if OK, or -1 for error.
*
* \p flags can be OR-ed together
*
* LWSJWKF_EXPORT_PRIVATE: default is only public part, set this to also export
* the private part
*
* LWSJWKF_EXPORT_NOCRLF: normally adds a CRLF at the end of the export, if
* you need to suppress it, set this flag
*
* Serializes the content of the JWK into a char buffer.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len);
/** lws_jwk_load() - Import a JSON Web key from a file
*
* \param jwk: the JWK object to load into
* \param filename: filename to load from
* \param cb: optional callback for each key
* \param user: opaque user pointer passed to cb if given
*
* Returns 0 for OK or -1 for failure
*
* There are two ways to use this... with some protocols a single jwk is
* delivered with no parent "keys": [] array. If you call this with cb and
* user as NULL, then the input will be interpreted like that and the results
* placed in s.
*
* The second case is that you are dealing with a "keys":[] array with one or
* more keys in it. In this case, the function iterates through the keys using
* s as a temporary jwk, and calls the user-provided callback for each key in
* turn while it return 0 (nonzero return from the callback terminates the
* iteration through any further keys, leaving the last one in s).
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_load(struct lws_jwk *jwk, const char *filename,
lws_jwk_key_import_callback cb, void *user);
/** lws_jwk_save() - Export a JSON Web key to a file
*
* \param jwk: the JWK object to save from
* \param filename: filename to save to
*
* Returns 0 for OK or -1 for failure
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_save(struct lws_jwk *jwk, const char *filename);
/** lws_jwk_rfc7638_fingerprint() - jwk to RFC7638 compliant fingerprint
*
* \param jwk: the JWK object to fingerprint
* \param digest32: buffer to take 32-byte digest
*
* Returns 0 for OK or -1 for failure
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32);
/** lws_jwk_strdup_meta() - allocate a duplicated string meta element
*
* \param jwk: the JWK object to fingerprint
* \param idx: JWK_META_ element index
* \param in: string to copy
* \param len: length of string to copy
*
* Returns 0 for OK or nonzero for failure
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx,
const char *in, int len);
LWS_VISIBLE LWS_EXTERN int
lws_jwk_dump(struct lws_jwk *jwk);
/** lws_jwk_generate() - create a new key of given type and characteristics
*
* \param context: the struct lws_context used for RNG
* \param jwk: the JWK object to fingerprint
* \param kty: One of the LWS_GENCRYPTO_KTY_ key types
* \param bits: for OCT and RSA keys, the number of bits
* \param curve: for EC keys, the name of the curve
*
* Returns 0 for OK or nonzero for failure
*/
LWS_VISIBLE int
lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk,
enum lws_gencrypto_kty kty, int bits, const char *curve);
///@}

View File

@ -0,0 +1,601 @@
/*
* 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 jws JSON Web Signature
* ## JSON Web Signature API
*
* Lws provides an API to check and create RFC7515 JSON Web Signatures
*
* SHA256/384/512 HMAC, and RSA 256/384/512 are supported.
*
* The API uses your TLS library crypto, but works exactly the same no matter
* what your TLS backend is.
*/
///@{
/*
* The maps are built to work with both JWS (LJWS_) and JWE (LJWE_), and are
* sized to the slightly larger JWE case.
*/
enum enum_jws_sig_elements {
/* JWS block namespace */
LJWS_JOSE,
LJWS_PYLD,
LJWS_SIG,
LJWS_UHDR,
/* JWE block namespace */
LJWE_JOSE = 0,
LJWE_EKEY,
LJWE_IV,
LJWE_CTXT,
LJWE_ATAG,
LJWE_AAD,
LWS_JWS_MAX_COMPACT_BLOCKS
};
struct lws_jws_map {
const char *buf[LWS_JWS_MAX_COMPACT_BLOCKS];
uint32_t len[LWS_JWS_MAX_COMPACT_BLOCKS];
};
#define LWS_JWS_MAX_SIGS 3
struct lws_jws {
struct lws_jwk *jwk; /* the struct lws_jwk containing the signing key */
struct lws_context *context; /* the lws context (used to get random) */
struct lws_jws_map map, map_b64;
};
/* jws EC signatures do not have ASN.1 in them, meaning they're incompatible
* with generic signatures.
*/
/**
* lws_jws_init() - initialize a jws for use
*
* \param jws: pointer to the jws to initialize
* \param jwk: the jwk to use with this jws
* \param context: the lws_context to use
*/
LWS_VISIBLE LWS_EXTERN void
lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk,
struct lws_context *context);
/**
* lws_jws_destroy() - scrub a jws
*
* \param jws: pointer to the jws to destroy
*
* Call before the jws goes out of scope.
*
* Elements defined in the jws are zeroed.
*/
LWS_VISIBLE LWS_EXTERN void
lws_jws_destroy(struct lws_jws *jws);
/**
* lws_jws_sig_confirm_compact() - check signature
*
* \param map: pointers and lengths for each of the unencoded JWS elements
* \param jwk: public key
* \param context: lws_context
* \param temp: scratchpad
* \param temp_len: length of scratchpad
*
* Confirms the signature on a JWS. Use if you have non-b64 plain JWS elements
* in a map... it'll make a temp b64 version needed for comparison. See below
* for other variants.
*
* Returns 0 on match, else nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_sig_confirm_compact(struct lws_jws_map *map, struct lws_jwk *jwk,
struct lws_context *context,
char *temp, int *temp_len);
LWS_VISIBLE LWS_EXTERN int
lws_jws_sig_confirm_compact_b64_map(struct lws_jws_map *map_b64,
struct lws_jwk *jwk,
struct lws_context *context,
char *temp, int *temp_len);
/**
* lws_jws_sig_confirm_compact_b64() - check signature on b64 compact JWS
*
* \param in: pointer to b64 jose.payload[.hdr].sig
* \param len: bytes available at \p in
* \param map: map to take decoded non-b64 content
* \param jwk: public key
* \param context: lws_context
* \param temp: scratchpad
* \param temp_len: size of scratchpad
*
* Confirms the signature on a JWS. Use if you have you have b64 compact layout
* (jose.payload.hdr.sig) as an aggregated string... it'll make a temp plain
* version needed for comparison.
*
* Returns 0 on match, else nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_sig_confirm_compact_b64(const char *in, size_t len,
struct lws_jws_map *map,
struct lws_jwk *jwk,
struct lws_context *context,
char *temp, int *temp_len);
/**
* lws_jws_sig_confirm() - check signature on plain + b64 JWS elements
*
* \param map_b64: pointers and lengths for each of the b64-encoded JWS elements
* \param map: pointers and lengths for each of the unencoded JWS elements
* \param jwk: public key
* \param context: lws_context
*
* Confirms the signature on a JWS. Use if you have you already have both b64
* compact layout (jose.payload.hdr.sig) and decoded JWS elements in maps.
*
* If you had the b64 string and called lws_jws_compact_decode() on it, you
* will end up with both maps, and can use this api version, saving needlessly
* regenerating any temp map.
*
* Returns 0 on match, else nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_sig_confirm(struct lws_jws_map *map_b64, /* b64-encoded */
struct lws_jws_map *map, /* non-b64 */
struct lws_jwk *jwk, struct lws_context *context);
/**
* lws_jws_sign_from_b64() - add b64 sig to b64 hdr + payload
*
* \param jose: jose header information
* \param jws: information to include in the signature
* \param b64_sig: output buffer for b64 signature
* \param sig_len: size of \p b64_sig output buffer
*
* This adds a b64-coded JWS signature of the b64-encoded protected header
* and b64-encoded payload, at \p b64_sig. The signature will be as large
* as the N element of the RSA key when the RSA key is used, eg, 512 bytes for
* a 4096-bit key, and then b64-encoding on top.
*
* In some special cases, there is only payload to sign and no header, in that
* case \p b64_hdr may be NULL, and only the payload will be hashed before
* signing.
*
* If successful, returns the length of the encoded signature written to
* \p b64_sig. If the jose signing type is unknown, 0 is returned. Otherwise
* -1 indicates failure.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, char *b64_sig,
size_t sig_len);
/**
* lws_jws_compact_decode() - converts and maps compact serialization b64 sections
*
* \param in: the incoming compact serialized b64
* \param len: the length of the incoming compact serialized b64
* \param map: pointer to the results structure
* \param map_b64: NULL, or pointer to a second results structure taking block
* information about the undecoded b64
* \param out: buffer to hold decoded results
* \param out_len: size of out in bytes
*
* Returns number of sections (2 if "none", else 3), or -1 if illegal.
*
* map is set to point to the start and hold the length of each decoded block.
* If map_b64 is non-NULL, then it's set with information about the input b64
* blocks.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_compact_decode(const char *in, int len, struct lws_jws_map *map,
struct lws_jws_map *map_b64, char *out, int *out_len);
LWS_VISIBLE LWS_EXTERN int
lws_jws_compact_encode(struct lws_jws_map *map_b64, /* b64-encoded */
const struct lws_jws_map *map, /* non-b64 */
char *buf, int *out_len);
LWS_VISIBLE LWS_EXTERN int
lws_jws_sig_confirm_json(const char *in, size_t len,
struct lws_jws *jws, struct lws_jwk *jwk,
struct lws_context *context,
char *temp, int *temp_len);
/**
* lws_jws_write_flattened_json() - create flattened JSON sig
*
* \param jws: information to include in the signature
* \param flattened: output buffer for JSON
* \param len: size of \p flattened output buffer
*
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len);
/**
* lws_jws_write_compact() - create flattened JSON sig
*
* \param jws: information to include in the signature
* \param compact: output buffer for compact format
* \param len: size of \p flattened output buffer
*
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len);
/*
* below apis are not normally needed if dealing with whole JWS... they're
* useful for creating from scratch
*/
/**
* lws_jws_dup_element() - allocate space for an element and copy data into it
*
* \param map: map to create the element in
* \param idx: index of element in the map to create
* \param temp: space to allocate in
* \param temp_len: available space at temp
* \param in: data to duplicate into element
* \param in_len: length of data to duplicate
* \param actual_alloc: 0 for same as in_len, else actual allocation size
*
* Copies in_len from in to temp, if temp_len is sufficient.
*
* Returns 0 or -1 if not enough space in temp / temp_len.
*
* Over-allocation can be acheived by setting actual_alloc to the real
* allocation desired... in_len will be copied into it.
*
* *temp_len is reduced by actual_alloc if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_dup_element(struct lws_jws_map *map, int idx,
char *temp, int *temp_len, const void *in, size_t in_len,
size_t actual_alloc);
/**
* lws_jws_randomize_element() - create an element and fill with random
*
* \param context: lws_context used for random
* \param map: map to create the element in
* \param idx: index of element in the map to create
* \param temp: space to allocate in
* \param temp_len: available space at temp
* \param random_len: length of data to fill with random
* \param actual_alloc: 0 for same as random_len, else actual allocation size
*
* Randomize random_len bytes at temp, if temp_len is sufficient.
*
* Returns 0 or -1 if not enough space in temp / temp_len.
*
* Over-allocation can be acheived by setting actual_alloc to the real
* allocation desired... the first random_len will be filled with random.
*
* *temp_len is reduced by actual_alloc if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_randomize_element(struct lws_context *context,
struct lws_jws_map *map,
int idx, char *temp, int *temp_len, size_t random_len,
size_t actual_alloc);
/**
* lws_jws_alloc_element() - create an element and reserve space for content
*
* \param map: map to create the element in
* \param idx: index of element in the map to create
* \param temp: space to allocate in
* \param temp_len: available space at temp
* \param len: logical length of element
* \param actual_alloc: 0 for same as len, else actual allocation size
*
* Allocate len bytes at temp, if temp_len is sufficient.
*
* Returns 0 or -1 if not enough space in temp / temp_len.
*
* Over-allocation can be acheived by setting actual_alloc to the real
* allocation desired... the element logical length will be set to len.
*
* *temp_len is reduced by actual_alloc if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_alloc_element(struct lws_jws_map *map, int idx, char *temp,
int *temp_len, size_t len, size_t actual_alloc);
/**
* lws_jws_encode_b64_element() - create an b64-encoded element
*
* \param map: map to create the element in
* \param idx: index of element in the map to create
* \param temp: space to allocate in
* \param temp_len: available space at temp
* \param in: pointer to unencoded input
* \param in_len: length of unencoded input
*
* Allocate len bytes at temp, if temp_len is sufficient.
*
* Returns 0 or -1 if not enough space in temp / temp_len.
*
* Over-allocation can be acheived by setting actual_alloc to the real
* allocation desired... the element logical length will be set to len.
*
* *temp_len is reduced by actual_alloc if successful.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_encode_b64_element(struct lws_jws_map *map, int idx,
char *temp, int *temp_len, const void *in,
size_t in_len);
/**
* lws_jws_b64_compact_map() - find block starts and lengths in compact b64
*
* \param in: pointer to b64 jose.payload[.hdr].sig
* \param len: bytes available at \p in
* \param map: output struct with pointers and lengths for each JWS element
*
* Scans a jose.payload[.hdr].sig b64 string and notes where the blocks start
* and their length into \p map.
*
* Returns number of blocks if OK. May return <0 if malformed.
* May not fill all map entries.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_map *map);
/**
* lws_jws_base64_enc() - encode input data into b64url data
*
* \param in: the incoming plaintext
* \param in_len: the length of the incoming plaintext in bytes
* \param out: the buffer to store the b64url encoded data to
* \param out_max: the length of \p out in bytes
*
* Returns either -1 if problems, or the number of bytes written to \p out.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
/**
* lws_jws_encode_section() - encode input data into b64url data,
* prepending . if not first
*
* \param in: the incoming plaintext
* \param in_len: the length of the incoming plaintext in bytes
* \param first: nonzero if the first section
* \param p: the buffer to store the b64url encoded data to
* \param end: just past the end of p
*
* Returns either -1 if problems, or the number of bytes written to \p out.
* If the section is not the first one, '.' is prepended.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,
char *end);
/**
* lws_jwt_signed_validate() - check a compact JWT against a key and alg
*
* \param ctx: the lws_context
* \param jwk: the key for checking the signature
* \param alg_list: the expected alg name, like "ES512"
* \param com: the compact JWT
* \param len: the length of com
* \param temp: a temp scratchpad
* \param tl: available length of temp scratchpad
* \param out: the output buffer to hold the validated plaintext
* \param out_len: on entry, max length of out; on exit, used length of out
*
* Returns nonzero if the JWT cannot be validated or the plaintext can't fit the
* provided output buffer, or 0 if it is validated as being signed by the
* provided jwk.
*
* If validated, the plaintext in the JWT is copied into out and out_len set to
* the used length.
*
* temp can be discarded or reused after the call returned, it's used to hold
* transformations of the B64 JWS in the JWT.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwt_signed_validate(struct lws_context *ctx, struct lws_jwk *jwk,
const char *alg_list, const char *com, size_t len,
char *temp, int tl, char *out, size_t *out_len);
/**
* lws_jwt_sign_compact() - generate a compact JWT using a key and alg
*
* \param ctx: the lws_context
* \param jwk: the signing key
* \param alg: the signing alg name, like "ES512"
* \param out: the output buffer to hold the signed JWT in compact form
* \param out_len: on entry, the length of out; on exit, the used amount of out
* \param temp: a temp scratchpad
* \param tl: available length of temp scratchpad
* \param format: a printf style format specification
* \param ...: zero or more args for the format specification
*
* Creates a JWT in a single step, from the format string and args through to
* outputting a well-formed compact JWT representation in out.
*
* Returns 0 if all is well and *out_len is the amount of data in out, else
* nonzero if failed. Temp must be large enough to hold various intermediate
* representations.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwt_sign_compact(struct lws_context *ctx, struct lws_jwk *jwk,
const char *alg, char *out, size_t *out_len, char *temp,
int tl, const char *format, ...) LWS_FORMAT(8);
struct lws_jwt_sign_info {
const char *alg;
/**< entry: signing alg name, like "RS256" */
const char *jose_hdr;
/**< entry: optional JOSE hdr; if present, alg field is ignored; instead the
* whole claim object has to be provided in this parameter */
size_t jose_hdr_len;
/**< entry: if jose_hdr is not NULL, JOSE header length without terminating '\0' */
char *out;
/**< exit: signed JWT in compact form*/
size_t *out_len;
/**< entry,exit: buffer size of out; actual size of JWT on exit */
char *temp;
/**< exit undefined content, used by the function as a temporary scratchpad; MUST
* be large enogh to store various intermediate representations */
int tl;
/**< entry: size of temp buffer */
};
/**
* lws_jwt_sign_via_info() - generate a compact JWT using a key and JOSE header
*
* \param ctx: the lws_context
* \param jwk: the signing key
* \param info: info describing the JWT's content and output/temp buffers
* \param format: a printf style format specification of the claims object
* \param ...: zero or more args for the format specification
*
* Creates a JWT in a single step, from the format string and args through to
* outputting a well-formed compact JWT representation in out. The provided
* JOSE header's syntax is checked before it is added to the JWT.
*
* Returns 0 if all is well and *out_len is the amount of data in out, else
* nonzero if failed. Temp must be large enough to hold various intermediate
* representations.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwt_sign_via_info(struct lws_context *ctx, struct lws_jwk *jwk,
const struct lws_jwt_sign_info *info, const char *format, ...) LWS_FORMAT(4);
/**
* lws_jwt_token_sanity() - check a validated jwt payload for sanity
*
* \param in: the JWT payload
* \param in_len: the length of the JWT payload
* \param iss: the expected issuer of the token
* \param aud: the expected audience of the token
* \param csrf_in: NULL, or the csrf token that came in on a URL
* \param sub: a buffer to hold the subject name in the JWT (eg, account name)
* \param sub_len: the max length of the sub buffer
* \param secs_left: set to the number of seconds of valid auth left if valid
*
* This performs some generic sanity tests on validated JWT payload...
*
* - the issuer is as expected
* - the audience is us
* - current time is OK for nbf ("not before") in the token
* - current time is OK for exp ("expiry") in the token
* - if csrf_in is not NULL, that the JWK has a csrf and it matches it
* - if sub is not NULL, that the JWK provides a subject (and copies it to sub)
*
* If the tests pass, *secs_left is set to the number of remaining seconds the
* auth is valid.
*
* Returns 0 if no inconsistency, else nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwt_token_sanity(const char *in, size_t in_len,
const char *iss, const char *aud, const char *csrf_in,
char *sub, size_t sub_len, unsigned long *exp_unix_time);
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
struct lws_jwt_sign_set_cookie {
struct lws_jwk *jwk;
/**< entry: required signing key */
const char *alg;
/**< entry: required signing alg, eg, "ES512" */
const char *iss;
/**< entry: issuer name to use */
const char *aud;
/**< entry: audience */
const char *cookie_name;
/**< entry: the name of the cookie */
char sub[33];
/**< sign-entry, validate-exit: subject */
const char *extra_json;
/**< sign-entry, validate-exit:
* optional "ext" JSON object contents for the JWT */
size_t extra_json_len;
/**< validate-exit:
* length of optional "ext" JSON object contents for the JWT */
const char *csrf_in;
/**< validate-entry:
* NULL, or an external CSRF token to check against what is in the JWT */
unsigned long expiry_unix_time;
/**< sign-entry: seconds the JWT and cookie may live,
* validate-exit: expiry unix time */
};
/**
* lws_jwt_sign_token_set_http_cookie() - creates sets a JWT in a wsi cookie
*
* \param wsi: the wsi to create the cookie header on
* \param i: structure describing what should be in the JWT
* \param p: wsi headers area
* \param end: end of wsi headers area
*
* Creates a JWT specified \p i, and attaches it to the outgoing headers on
* wsi. Returns 0 if successful.
*
* Best-practice security restrictions are applied to the cookie set action,
* including forcing httponly, and __Host- prefix. As required by __Host-, the
* cookie Path is set to /. __Host- is applied by the function, the cookie_name
* should just be "xyz" for "__Host-xyz".
*
* \p extra_json should just be the bare JSON, a { } is provided around it by
* the function if it's non-NULL. For example, "\"authorization\": 1".
*
* It's recommended the secs parameter is kept as small as consistent with one
* user session on the site if possible, eg, 10 minutes or 20 minutes. At the
* server, it can determine how much time is left in the auth and inform the
* client; if the JWT validity expires, the page should reload so the UI always
* reflects what's possible to do with the authorization state correctly. If
* the JWT expires, the user can log back in using credentials usually stored in
* the browser and auto-filled-in, so this is not very inconvenient.
*
* This is a helper on top of the other JOSE and JWT apis that somewhat crosses
* over between JWT and HTTP, since it knows about cookies. So it is only built
* if both LWS_WITH_JOSE and one of the http-related roles enabled.
*/
LWS_VISIBLE LWS_EXTERN int
lws_jwt_sign_token_set_http_cookie(struct lws *wsi,
const struct lws_jwt_sign_set_cookie *i,
uint8_t **p, uint8_t *end);
LWS_VISIBLE LWS_EXTERN int
lws_jwt_get_http_cookie_validate_jwt(struct lws *wsi,
struct lws_jwt_sign_set_cookie *i,
char *out, size_t *out_len);
#endif
///@}

View File

@ -0,0 +1,539 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 lecp CBOR parser
* ##CBOR parsing related functions
* \ingroup lwsapi
*
* LECP is an extremely lightweight CBOR stream parser included in lws. It
* is aligned in approach with the LEJP JSON stream parser, with some additional
* things needed for CBOR.
*/
//@{
#ifndef LECP_MAX_PARSING_STACK_DEPTH
#define LECP_MAX_PARSING_STACK_DEPTH 5
#endif
#ifndef LECP_MAX_DEPTH
#define LECP_MAX_DEPTH 12
#endif
#ifndef LECP_MAX_INDEX_DEPTH
#define LECP_MAX_INDEX_DEPTH 8
#endif
#ifndef LECP_MAX_PATH
#define LECP_MAX_PATH 128
#endif
#ifndef LECP_STRING_CHUNK
/* must be >= 30 to assemble floats */
#define LECP_STRING_CHUNK 254
#endif
#define LECP_FLAG_CB_IS_VALUE 64
/*
* CBOR initial byte 3 x MSB bits are these
*/
enum {
LWS_CBOR_MAJTYP_UINT = 0 << 5,
LWS_CBOR_MAJTYP_INT_NEG = 1 << 5,
LWS_CBOR_MAJTYP_BSTR = 2 << 5,
LWS_CBOR_MAJTYP_TSTR = 3 << 5,
LWS_CBOR_MAJTYP_ARRAY = 4 << 5,
LWS_CBOR_MAJTYP_MAP = 5 << 5,
LWS_CBOR_MAJTYP_TAG = 6 << 5,
LWS_CBOR_MAJTYP_FLOAT = 7 << 5, /* also BREAK */
LWS_CBOR_MAJTYP_MASK = 7 << 5,
/*
* For the low 5 bits of the opcode, 0-23 are literals, unless it's
* FLOAT.
*
* 24 = 1 byte; 25 = 2..., 26 = 4... and 27 = 8 bytes following literal.
*/
LWS_CBOR_1 = 24,
LWS_CBOR_2 = 25,
LWS_CBOR_4 = 26,
LWS_CBOR_8 = 27,
LWS_CBOR_RESERVED = 28,
LWS_CBOR_SUBMASK = 0x1f,
/*
* Major type 7 discriminators in low 5 bits
* 0 - 23 is SIMPLE implicit value (like, eg, LWS_CBOR_SWK_TRUE)
*/
LWS_CBOR_SWK_FALSE = 20,
LWS_CBOR_SWK_TRUE = 21,
LWS_CBOR_SWK_NULL = 22,
LWS_CBOR_SWK_UNDEFINED = 23,
LWS_CBOR_M7_SUBTYP_SIMPLE_X8 = 24, /* simple with additional byte */
LWS_CBOR_M7_SUBTYP_FLOAT16 = 25,
LWS_CBOR_M7_SUBTYP_FLOAT32 = 26,
LWS_CBOR_M7_SUBTYP_FLOAT64 = 27,
LWS_CBOR_M7_BREAK = 31,
/* 28, 29, 30 are illegal.
*
* 31 is illegal for UINT, INT_NEG, and TAG;
* for BSTR, TSTR, ARRAY and MAP it means "indefinite length", ie,
* it's made up of an endless amount of determinite-length
* fragments terminated with a BREAK (FLOAT | 31) instead of the
* next determinite-length fragment. The second framing level
* means no need for escapes for BREAK in the data.
*/
LWS_CBOR_INDETERMINITE = 31,
/*
* Well-known tags
*/
LWS_CBOR_WKTAG_DATETIME_STD = 0, /* text */
LWS_CBOR_WKTAG_DATETIME_EPOCH = 1, /* int or float */
LWS_CBOR_WKTAG_BIGNUM_UNSIGNED = 2, /* byte string */
LWS_CBOR_WKTAG_BIGNUM_NEGATIVE = 3, /* byte string */
LWS_CBOR_WKTAG_DECIMAL_FRAC = 4, /* array */
LWS_CBOR_WKTAG_BIGFLOAT = 5, /* array */
LWS_CBOR_WKTAG_COSE_ENC0 = 16,
LWS_CBOR_WKTAG_COSE_MAC0 = 17,
LWS_CBOR_WKTAG_COSE_SIGN1 = 18,
LWS_CBOR_WKTAG_TO_B64U = 21, /* any */
LWS_CBOR_WKTAG_TO_B64 = 22, /* any */
LWS_CBOR_WKTAG_TO_B16 = 23, /* any */
LWS_CBOR_WKTAG_CBOR = 24, /* byte string */
LWS_CBOR_WKTAG_URI = 32, /* text string */
LWS_CBOR_WKTAG_B64U = 33, /* text string */
LWS_CBOR_WKTAG_B64 = 34, /* text string */
LWS_CBOR_WKTAG_MIME = 36, /* text string */
LWS_CBOR_WKTAG_COSE_ENC = 96,
LWS_CBOR_WKTAG_COSE_MAC = 97,
LWS_CBOR_WKTAG_COSE_SIGN = 98,
LWS_CBOR_WKTAG_SELFDESCCBOR = 55799
};
enum lecp_callbacks {
LECPCB_CONSTRUCTED = 0,
LECPCB_DESTRUCTED = 1,
LECPCB_COMPLETE = 3,
LECPCB_FAILED = 4,
LECPCB_PAIR_NAME = 5,
LECPCB_VAL_TRUE = LECP_FLAG_CB_IS_VALUE | 6,
LECPCB_VAL_FALSE = LECP_FLAG_CB_IS_VALUE | 7,
LECPCB_VAL_NULL = LECP_FLAG_CB_IS_VALUE | 8,
LECPCB_VAL_NUM_INT = LECP_FLAG_CB_IS_VALUE | 9,
LECPCB_VAL_RESERVED = LECP_FLAG_CB_IS_VALUE | 10,
LECPCB_VAL_STR_START = 11, /* notice handle separately */
LECPCB_VAL_STR_CHUNK = LECP_FLAG_CB_IS_VALUE | 12,
LECPCB_VAL_STR_END = LECP_FLAG_CB_IS_VALUE | 13,
LECPCB_ARRAY_START = 14,
LECPCB_ARRAY_END = 15,
LECPCB_OBJECT_START = 16,
LECPCB_OBJECT_END = 17,
LECPCB_TAG_START = 18,
LECPCB_TAG_END = 19,
LECPCB_VAL_NUM_UINT = LECP_FLAG_CB_IS_VALUE | 20,
LECPCB_VAL_UNDEFINED = LECP_FLAG_CB_IS_VALUE | 21,
LECPCB_VAL_FLOAT16 = LECP_FLAG_CB_IS_VALUE | 22,
LECPCB_VAL_FLOAT32 = LECP_FLAG_CB_IS_VALUE | 23,
LECPCB_VAL_FLOAT64 = LECP_FLAG_CB_IS_VALUE | 24,
LECPCB_VAL_SIMPLE = LECP_FLAG_CB_IS_VALUE | 25,
LECPCB_VAL_BLOB_START = 26, /* notice handle separately */
LECPCB_VAL_BLOB_CHUNK = LECP_FLAG_CB_IS_VALUE | 27,
LECPCB_VAL_BLOB_END = LECP_FLAG_CB_IS_VALUE | 28,
LECPCB_ARRAY_ITEM_START = 29,
LECPCB_ARRAY_ITEM_END = 30,
LECPCB_LITERAL_CBOR = 31,
};
enum lecp_reasons {
LECP_CONTINUE = -1,
LECP_REJECT_BAD_CODING = -2,
LECP_REJECT_UNKNOWN = -3,
LECP_REJECT_CALLBACK = -4,
LECP_STACK_OVERFLOW = -5,
};
struct lecp_item {
union {
uint64_t u64;
int64_t i64;
uint64_t u32;
uint16_t hf;
#if defined(LWS_WITH_CBOR_FLOAT)
float f;
double d;
#else
uint32_t f;
uint64_t d;
#endif
} u;
uint8_t opcode;
};
struct lecp_ctx;
typedef signed char (*lecp_callback)(struct lecp_ctx *ctx, char reason);
struct _lecp_stack {
char s; /* lejp_state stack*/
uint8_t p; /* path length */
char i; /* index array length */
char indet; /* indeterminite */
char intermediate; /* in middle of string */
char pop_iss;
uint64_t tag;
uint64_t collect_rem;
uint32_t ordinal;
uint8_t opcode;
uint8_t send_new_array_item;
uint8_t barrier;
};
struct _lecp_parsing_stack {
void *user; /* private to the stack level */
lecp_callback cb;
const char * const *paths;
uint8_t count_paths;
uint8_t ppos;
uint8_t path_match;
};
struct lecp_ctx {
/* sorted by type for most compact alignment
*
* pointers
*/
void *user;
uint8_t *collect_tgt;
/* arrays */
struct _lecp_parsing_stack pst[LECP_MAX_PARSING_STACK_DEPTH];
struct _lecp_stack st[LECP_MAX_DEPTH];
uint16_t i[LECP_MAX_INDEX_DEPTH]; /* index array */
uint16_t wild[LECP_MAX_INDEX_DEPTH]; /* index array */
char path[LECP_MAX_PATH];
uint8_t cbor[64]; /* literal cbor capture */
struct lecp_item item;
/* size_t */
size_t path_stride; /* 0 means default ptr size, else
* stride... allows paths to be
* provided composed inside a
* larger user struct instead of a
* duplicated array */
size_t used_in; /* bytes of input consumed */
/* short */
uint16_t uni;
/* char */
uint8_t npos;
uint8_t dcount;
uint8_t f;
uint8_t sp; /* stack head */
uint8_t ipos; /* index stack depth */
uint8_t count_paths;
uint8_t path_match;
uint8_t path_match_len;
uint8_t wildcount;
uint8_t pst_sp; /* parsing stack head */
uint8_t outer_array;
uint8_t cbor_pos;
uint8_t literal_cbor_report;
char present; /* temp for cb reason to use */
uint8_t be; /* big endian */
/* at end so we can memset the rest of it */
char buf[LECP_STRING_CHUNK + 1];
};
enum lws_lec_pctx_ret {
LWS_LECPCTX_RET_FINISHED = 0,
LWS_LECPCTX_RET_AGAIN, /* call again to continue writing buffer */
LWS_LECPCTX_RET_FAIL /* something broken, eg, format string */
};
enum cbp_state {
CBPS_IDLE,
CBPS_PC1,
CBPS_PC2,
CBPS_PC3,
CBPS_STRING_BODY,
CBPS_NUM_LIT,
CBPS_STRING_LIT,
CBPS_CONTYPE,
};
typedef struct lws_lec_pctx {
uint8_t stack[16];
uint8_t vaa[16];
uint8_t indet[16];
uint8_t scratch[24];
uint8_t *start; /* the beginning of the out buf */
uint8_t *buf; /* cur pos in output buf */
uint8_t *end; /* the end of the output buf */
const uint8_t *ongoing_src;
uint64_t ongoing_len;
uint64_t ongoing_done;
struct lecp_item item;
size_t used; /* number of bytes valid from start */
int opaque[4]; /* ignored by lws, caller may use */
enum cbp_state state;
unsigned int fmt_pos;
uint8_t sp;
uint8_t scratch_len;
uint8_t escflag;
uint8_t _long;
uint8_t vaa_pos;
uint8_t dotstar;
} lws_lec_pctx_t;
LWS_VISIBLE LWS_EXTERN void
lws_lec_int(lws_lec_pctx_t *ctx, uint8_t opcode, uint8_t indet, uint64_t num);
LWS_VISIBLE LWS_EXTERN int
lws_lec_scratch(lws_lec_pctx_t *ctx);
/*
* lws_lec_init() - prepare a cbor writing context
*
* \param ctx: the cbor writing context to prepare
* \param buf: the output buffer start
* \param len: the amount of the output buffer we can use
*
* Prepares a cbor writing context so that les_lec_printf can be used to
* write into it.
*/
LWS_VISIBLE LWS_EXTERN void
lws_lec_init(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len);
/*
* lws_lec_setbuf() - update the output buffer for an initialized cbor writing ctx
*
* \param ctx: the cbor writing context to prepare
* \param buf: the output buffer start
* \param len: the amount of the output buffer we can use
*
* Leaves the cbor writing context state as it is, but resets the output buffer
* it writes into as given in \p buf and \p len
*/
LWS_VISIBLE LWS_EXTERN void
lws_lec_setbuf(lws_lec_pctx_t *ctx, uint8_t *buf, size_t len);
/*
* lws_lec_vsprintf() - write into a cbor writing context
*
* \param ctx: the cbor writing context to prepare
* \param format: a printf style argument map
* \param args: the va args
*
* CBOR-aware vsprintf which pauses output when it fills the output buffer. You
* can call it again with the same args and same lws_lex_pctx to resume filling
*
* Returns either LWS_LECPCTX_RET_FINISHED if we have nothing left over that we
* want to put in the buffer, or LWS_LECPCTX_RET_AGAIN if the function should
* be called again with the same arguments (perhaps into a different output
* buffer) to continue emitting output from where it left off.
*
* If LWS_LECPCTX_RET_AGAIN is returned, lws_lec_setbuf() must be used on the
* context to reset or change the output buffer before calling again.
*
* The number of bytes placed in the output buffer is available in ctx->used.
*
* \p format is a printf-type format string that is specialized for CBOR
* generation. It understands the following specifiers
*
* |`123`||unsigned literal number|
* |`-123`||signed literal number|
* |`%u`|`unsigned int`|number|
* |`%lu`|`unsigned long int`|number|
* |`%llu`|`unsigned long long int`|number|
* |`%d`|`signed int`|number|
* |`%ld`|`signed long int`|number|
* |`%lld`|`signed long long int`|number|
* |`%f`|`double`|floating point number|
* |`123(...)`||literal tag and scope|
* |`%t(...)`|`unsigned int`|tag and scope|
* |`%lt(...)`|`unsigned long int`|tag and scope|
* |`%llt(...)`|`unsigned long long int`|tag and scope|
* |`[...]`||Array (fixed len if `]` in same format string)|
* |`{...}`||Map (fixed len if `}` in same format string)|
* |`<t...>`||Container for indeterminite text string frags|
* |`<b...>`||Container for indeterminite binary string frags|
* |`'string'`||Literal text of known length|
* |`%s`|`const char *`|NUL-terminated string|
* |`%.*s`|`int`, `const char *`|length-specified string|
* |`%.*b`|`int`, `const uint8_t *`|length-specified binary|
* |`:`||separator between Map items (a:b)|
* |`,`||separator between Map pairs or array items|
*
* See READMEs/README.cbor-lecp.md for more details.
*/
LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
lws_lec_vsprintf(lws_lec_pctx_t *ctx, const char *format, va_list args);
/*
* lws_lec_printf() - write into a cbor writing context
*
* \param ctx: the cbor writing context to prepare
* \param format: a printf style argument map
* \param ...: format args
*
* See lws_lec_vsprintf() for format details. This is the most common way
* to format the CBOR output.
*
* See READMEs/README.cbor-lecp.md for more details.
*/
LWS_VISIBLE LWS_EXTERN enum lws_lec_pctx_ret
lws_lec_printf(lws_lec_pctx_t *ctx, const char *format, ...);
/**
* lecp_construct() - Construct an LECP parser context
*
* \param ctx: the parser context object to be initialized
* \param cb: the user callback to receive the parsing events
* \param user: an opaque user pointer available at \p cb
* \param paths: an optional array of parsing paths
* \param paths_count: how many paths in \p paths
*
* Prepares an LECP parser context for parsing.
*/
LWS_VISIBLE LWS_EXTERN void
lecp_construct(struct lecp_ctx *ctx, lecp_callback cb, void *user,
const char * const *paths, unsigned char paths_count);
/**
* lecp_destruct() - Destroys an LECP parser context
*
* \param ctx: the parser context object to be destroyed
*/
LWS_VISIBLE LWS_EXTERN void
lecp_destruct(struct lecp_ctx *ctx);
/**
* lecp_parse() - parses a chunk of input CBOR
*
* \p ctx: the parsing context
* \p cbor: the start of the chunk of CBOR
* \p len: the number of bytes of CBOR available at \p cbor
*
* Returns LECP_CONTINUE if more input needed, one of enum lecp_reasons for a
* fatal error, else 0 for successful parsing completion.
*
* On success or _CONTINUE, ctx->used_in is set to the number of input bytes
* consumed.
*/
LWS_VISIBLE LWS_EXTERN int
lecp_parse(struct lecp_ctx *ctx, const uint8_t *cbor, size_t len);
LWS_VISIBLE LWS_EXTERN void
lecp_change_callback(struct lecp_ctx *ctx, lecp_callback cb);
LWS_VISIBLE LWS_EXTERN const char *
lecp_error_to_string(int e);
/**
* lecp_parse_report_raw() - turn cbor raw reporting on and off
*
* \param ctx: the lecp context
* \param on: 0 to disable (defaults disabled), 1 to enable
*
* For cose_sign, it needs access to raw cbor subtrees for the hash input.
* This api causes LECPCB_LITERAL_CBOR parse callbacks when there are
* ctx->cbor_pos bytes of raw cbor available in ctx->cbor[]. the callbacks
* occur when the ctx->cbor[] buffer fills or if it holds anything when this
* spi is used to stop the reports.
*
* The same CBOR that is being captured continues to be passed for parsing.
*/
LWS_VISIBLE LWS_EXTERN void
lecp_parse_report_raw(struct lecp_ctx *ctx, int on);
/**
* lecp_parse_map_is_key() - return nonzero if we're in a map and this is a key
*
* \param ctx: the lwcp context
*
* Checks if the current value is a key in a map, ie, that you are on a "key" in
* a list of "{key: value}" pairs. Zero means you're either not in a map or not
* on the key part, and nonzero means you are in a map and on a key part.
*/
LWS_VISIBLE LWS_EXTERN int
lecp_parse_map_is_key(struct lecp_ctx *ctx);
LWS_VISIBLE LWS_EXTERN int
lecp_parse_subtree(struct lecp_ctx *ctx, const uint8_t *in, size_t len);
/*
* Helpers for half-float
*/
LWS_VISIBLE LWS_EXTERN void
lws_singles2halfp(uint16_t *hp, uint32_t x);
LWS_VISIBLE LWS_EXTERN void
lws_halfp2singles(uint32_t *xp, uint16_t h);
//@}

View File

@ -0,0 +1,146 @@
/*
* Generic LED controller ops
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for leds, a real implementation provides
* functions for the ops that use the underlying, eg, OS gpio arrangements.
*/
/* only b15 significant for GPIO */
typedef uint16_t lws_led_intensity_t;
typedef uint16_t lws_led_seq_phase_t;
/* the normalized max intensity */
#define LWS_LED_MAX_INTENSITY (0xffff)
/* the normalized 360 degree phase count for intensity functions */
#define LWS_LED_FUNC_PHASE 65536
/* used when the sequence doesn't stop by itself and goes around forever */
#define LWS_SEQ_LEDPHASE_TOTAL_ENDLESS (-1)
#define LWS_LED_SEQUENCER_UPDATE_INTERVAL_MS 33
struct lws_led_state; /* opaque */
struct lws_pwm_ops; /* forward ref */
typedef lws_led_intensity_t (*lws_led_lookup_t)(lws_led_seq_phase_t ph);
typedef struct lws_led_sequence_def_t {
lws_led_lookup_t func;
lws_led_seq_phase_t ledphase_offset;
int ledphase_total; /* 65536= one cycle */
uint16_t ms;
uint8_t flags;
} lws_led_sequence_def_t;
enum {
LLSI_CURR,
LLSI_NEXT,
LLSI_TRANS
};
typedef struct lws_led_state_ch
{
const lws_led_sequence_def_t *seq; /* NULL = inactive */
lws_led_seq_phase_t ph;
lws_led_seq_phase_t step;
int phase_budget;
lws_led_intensity_t last;
/**< at the end of the sequence we decouple the sequencer, but leave
* the last computed sample behind for further transitions to base off
*/
} lws_led_state_ch_t;
typedef struct lws_led_state_chs
{
lws_led_state_ch_t seqs[3];
} lws_led_state_chs_t;
/* this should always be first in the subclassed implementation types */
typedef struct lws_led_ops {
void (*intensity)(const struct lws_led_ops *lo, const char *name,
lws_led_intensity_t inten);
/**< for BOOL led control like GPIO, only inten b15 is significant */
struct lws_led_state * (*create)(const struct lws_led_ops *led_ops);
void (*destroy)(struct lws_led_state *);
} lws_led_ops_t;
typedef struct lws_led_gpio_map {
const char *name;
_lws_plat_gpio_t gpio;
lws_led_lookup_t intensity_correction;
/**< May be NULL. If GPIO-based LED, ignored. If pwm_ops provided,
* NULL means use default CIE 100% correction function. If non-NULL,
* use the pointed-to correction function. This is useful to provide
* LED-specific intensity correction / scaling so different types of
* LED can "look the same". */
const struct lws_pwm_ops *pwm_ops;
/**< if NULL, gpio controls the led directly. If set to a pwm_ops,
* the led control is outsourced to the pwm controller. */
uint8_t active_level;
} lws_led_gpio_map_t;
typedef struct lws_led_gpio_controller {
const lws_led_ops_t led_ops;
const lws_gpio_ops_t *gpio_ops;
const lws_led_gpio_map_t *led_map;
uint8_t count_leds;
} lws_led_gpio_controller_t;
/* ops */
LWS_VISIBLE LWS_EXTERN struct lws_led_state *
lws_led_gpio_create(const lws_led_ops_t *led_ops);
LWS_VISIBLE LWS_EXTERN void
lws_led_gpio_destroy(struct lws_led_state *lcs);
/**
* lws_led_gpio_intensity() - set the static intensity of an led
*
* \param lo: the base class of the led controller
* \param index: which led in the controller set
* \param inten: 16-bit unsigned intensity
*
* For LEDs controlled by a BOOL like GPIO, only inten b15 is significant.
* For PWM type LED control, as many bits as the hardware can support from b15
* down are significant.
*/
LWS_VISIBLE LWS_EXTERN void
lws_led_gpio_intensity(const struct lws_led_ops *lo, const char *name,
lws_led_intensity_t inten);
LWS_VISIBLE LWS_EXTERN int
lws_led_transition(struct lws_led_state *lcs, const char *name,
const lws_led_sequence_def_t *next,
const lws_led_sequence_def_t *trans);
#define lws_led_gpio_ops \
{ \
.create = lws_led_gpio_create, \
.destroy = lws_led_gpio_destroy, \
.intensity = lws_led_gpio_intensity, \
}

View File

@ -0,0 +1,309 @@
/*
* 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 lejp JSON parser
* ##JSON parsing related functions
* \ingroup lwsapi
*
* LEJP is an extremely lightweight JSON stream parser included in lws.
*/
//@{
struct lejp_ctx;
#if !defined(LWS_ARRAY_SIZE)
#define LWS_ARRAY_SIZE(_x) (sizeof(_x) / sizeof(_x[0]))
#endif
#define LEJP_FLAG_WS_KEEP 64
#define LEJP_FLAG_WS_COMMENTLINE 32
enum lejp_states {
LEJP_IDLE = 0,
LEJP_MEMBERS = 1,
LEJP_M_P = 2,
LEJP_MP_STRING = LEJP_FLAG_WS_KEEP | 3,
LEJP_MP_STRING_ESC = LEJP_FLAG_WS_KEEP | 4,
LEJP_MP_STRING_ESC_U1 = LEJP_FLAG_WS_KEEP | 5,
LEJP_MP_STRING_ESC_U2 = LEJP_FLAG_WS_KEEP | 6,
LEJP_MP_STRING_ESC_U3 = LEJP_FLAG_WS_KEEP | 7,
LEJP_MP_STRING_ESC_U4 = LEJP_FLAG_WS_KEEP | 8,
LEJP_MP_DELIM = 9,
LEJP_MP_VALUE = 10,
LEJP_MP_VALUE_NUM_INT = LEJP_FLAG_WS_KEEP | 11,
LEJP_MP_VALUE_NUM_EXP = LEJP_FLAG_WS_KEEP | 12,
LEJP_MP_VALUE_TOK = LEJP_FLAG_WS_KEEP | 13,
LEJP_MP_COMMA_OR_END = 14,
LEJP_MP_ARRAY_END = 15,
};
enum lejp_reasons {
LEJP_CONTINUE = -1,
LEJP_REJECT_IDLE_NO_BRACE = -2,
LEJP_REJECT_MEMBERS_NO_CLOSE = -3,
LEJP_REJECT_MP_NO_OPEN_QUOTE = -4,
LEJP_REJECT_MP_STRING_UNDERRUN = -5,
LEJP_REJECT_MP_ILLEGAL_CTRL = -6,
LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC = -7,
LEJP_REJECT_ILLEGAL_HEX = -8,
LEJP_REJECT_MP_DELIM_MISSING_COLON = -9,
LEJP_REJECT_MP_DELIM_BAD_VALUE_START = -10,
LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC = -11,
LEJP_REJECT_MP_VAL_NUM_FORMAT = -12,
LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP = -13,
LEJP_REJECT_MP_VAL_TOK_UNKNOWN = -14,
LEJP_REJECT_MP_C_OR_E_UNDERF = -15,
LEJP_REJECT_MP_C_OR_E_NOTARRAY = -16,
LEJP_REJECT_MP_ARRAY_END_MISSING = -17,
LEJP_REJECT_STACK_OVERFLOW = -18,
LEJP_REJECT_MP_DELIM_ISTACK = -19,
LEJP_REJECT_NUM_TOO_LONG = -20,
LEJP_REJECT_MP_C_OR_E_NEITHER = -21,
LEJP_REJECT_UNKNOWN = -22,
LEJP_REJECT_CALLBACK = -23
};
#define LEJP_FLAG_CB_IS_VALUE 64
enum lejp_callbacks {
LEJPCB_CONSTRUCTED = 0,
LEJPCB_DESTRUCTED = 1,
LEJPCB_START = 2,
LEJPCB_COMPLETE = 3,
LEJPCB_FAILED = 4,
LEJPCB_PAIR_NAME = 5,
LEJPCB_VAL_TRUE = LEJP_FLAG_CB_IS_VALUE | 6,
LEJPCB_VAL_FALSE = LEJP_FLAG_CB_IS_VALUE | 7,
LEJPCB_VAL_NULL = LEJP_FLAG_CB_IS_VALUE | 8,
LEJPCB_VAL_NUM_INT = LEJP_FLAG_CB_IS_VALUE | 9,
LEJPCB_VAL_NUM_FLOAT = LEJP_FLAG_CB_IS_VALUE | 10,
LEJPCB_VAL_STR_START = 11, /* notice handle separately */
LEJPCB_VAL_STR_CHUNK = LEJP_FLAG_CB_IS_VALUE | 12,
LEJPCB_VAL_STR_END = LEJP_FLAG_CB_IS_VALUE | 13,
LEJPCB_ARRAY_START = 14,
LEJPCB_ARRAY_END = 15,
LEJPCB_OBJECT_START = 16,
LEJPCB_OBJECT_END = 17,
LEJPCB_USER_START = 32,
};
/**
* _lejp_callback() - User parser actions
* \param ctx: LEJP context
* \param reason: Callback reason
*
* Your user callback is associated with the context at construction time,
* and receives calls as the parsing progresses.
*
* All of the callbacks may be ignored and just return 0.
*
* The reasons it might get called, found in @reason, are:
*
* LEJPCB_CONSTRUCTED: The context was just constructed... you might want to
* perform one-time allocation for the life of the context.
*
* LEJPCB_DESTRUCTED: The context is being destructed... if you made any
* allocations at construction-time, you can free them now
*
* LEJPCB_START: Parsing is beginning at the first byte of input
*
* LEJPCB_COMPLETE: Parsing has completed successfully. You'll get a 0 or
* positive return code from lejp_parse indicating the
* amount of unused bytes left in the input buffer
*
* LEJPCB_FAILED: Parsing failed. You'll get a negative error code
* returned from lejp_parse
*
* LEJPCB_PAIR_NAME: When a "name":"value" pair has had the name parsed,
* this callback occurs. You can find the new name at
* the end of ctx->path[]
*
* LEJPCB_VAL_TRUE: The "true" value appeared
*
* LEJPCB_VAL_FALSE: The "false" value appeared
*
* LEJPCB_VAL_NULL: The "null" value appeared
*
* LEJPCB_VAL_NUM_INT: A string representing an integer is in ctx->buf
*
* LEJPCB_VAL_NUM_FLOAT: A string representing a float is in ctx->buf
*
* LEJPCB_VAL_STR_START: We are starting to parse a string, no data yet
*
* LEJPCB_VAL_STR_CHUNK: We filled the string buffer in the ctx, but it's not
* the end of the string. We produce this to spill the
* intermediate buffer to the user code, so we can handle
* huge JSON strings using only the small buffer in the
* ctx. If the whole JSON string fits in the ctx buffer,
* you won't get these callbacks.
*
* LEJPCB_VAL_STR_END: String parsing has completed, the last chunk of the
* string is in ctx->buf.
*
* LEJPCB_ARRAY_START: An array started
*
* LEJPCB_ARRAY_END: An array ended
*
* LEJPCB_OBJECT_START: An object started
*
* LEJPCB_OBJECT_END: An object ended
*/
LWS_EXTERN signed char _lejp_callback(struct lejp_ctx *ctx, char reason);
typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
#ifndef LEJP_MAX_PARSING_STACK_DEPTH
#define LEJP_MAX_PARSING_STACK_DEPTH 8
#endif
#ifndef LEJP_MAX_DEPTH
#define LEJP_MAX_DEPTH 16
#endif
#ifndef LEJP_MAX_INDEX_DEPTH
#define LEJP_MAX_INDEX_DEPTH 12
#endif
#ifndef LEJP_MAX_PATH
#define LEJP_MAX_PATH 192
#endif
#ifndef LEJP_STRING_CHUNK
/* must be >= 30 to assemble floats */
#define LEJP_STRING_CHUNK 254
#endif
enum num_flags {
LEJP_SEEN_MINUS = (1 << 0),
LEJP_SEEN_POINT = (1 << 1),
LEJP_SEEN_POST_POINT = (1 << 2),
LEJP_SEEN_EXP = (1 << 3)
};
struct _lejp_stack {
char s; /* lejp_state stack*/
char p; /* path length */
char i; /* index array length */
char b; /* user bitfield */
};
struct _lejp_parsing_stack {
void *user; /* private to the stack level */
signed char (*callback)(struct lejp_ctx *ctx, char reason);
const char * const *paths;
uint8_t count_paths;
uint8_t ppos;
uint8_t path_match;
};
struct lejp_ctx {
/* sorted by type for most compact alignment
*
* pointers
*/
void *user;
/* arrays */
struct _lejp_parsing_stack pst[LEJP_MAX_PARSING_STACK_DEPTH];
struct _lejp_stack st[LEJP_MAX_DEPTH];
uint16_t i[LEJP_MAX_INDEX_DEPTH]; /* index array */
uint16_t wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
char path[LEJP_MAX_PATH];
char buf[LEJP_STRING_CHUNK + 1];
/* size_t */
size_t path_stride; /* 0 means default ptr size, else stride */
/* int */
uint32_t line;
/* short */
uint16_t uni;
#define LEJP_FLAG_FEAT_OBJECT_INDEXES (1 << 0)
#define LEJP_FLAG_FEAT_LEADING_WC (1 << 1)
#define LEJP_FLAG_LATEST \
(LEJP_FLAG_FEAT_OBJECT_INDEXES | \
LEJP_FLAG_FEAT_LEADING_WC)
uint16_t flags;
/* char */
uint8_t npos;
uint8_t dcount;
uint8_t f;
uint8_t sp; /* stack head */
uint8_t ipos; /* index stack depth */
uint8_t count_paths;
uint8_t path_match;
uint8_t path_match_len;
uint8_t wildcount;
uint8_t pst_sp; /* parsing stack head */
uint8_t outer_array;
};
LWS_VISIBLE LWS_EXTERN void
lejp_construct(struct lejp_ctx *ctx,
signed char (*callback)(struct lejp_ctx *ctx, char reason),
void *user, const char * const *paths, unsigned char paths_count);
LWS_VISIBLE LWS_EXTERN void
lejp_destruct(struct lejp_ctx *ctx);
LWS_VISIBLE LWS_EXTERN int
lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len);
LWS_VISIBLE LWS_EXTERN void
lejp_change_callback(struct lejp_ctx *ctx,
signed char (*callback)(struct lejp_ctx *ctx, char reason));
/*
* push the current paths / paths_count and lejp_cb to a stack in the ctx, and
* start using the new ones
*/
LWS_VISIBLE LWS_EXTERN int
lejp_parser_push(struct lejp_ctx *ctx, void *user, const char * const *paths,
unsigned char paths_count, lejp_callback lejp_cb);
/*
* pop the previously used paths / paths_count and lejp_cb, and continue
* parsing using those as before
*/
LWS_VISIBLE LWS_EXTERN int
lejp_parser_pop(struct lejp_ctx *ctx);
/* exported for use when reevaluating a path for use with a subcontext */
LWS_VISIBLE LWS_EXTERN void
lejp_check_path_match(struct lejp_ctx *ctx);
LWS_VISIBLE LWS_EXTERN int
lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len);
LWS_VISIBLE LWS_EXTERN const char *
lejp_error_to_string(int e);
//@}

View File

@ -0,0 +1,799 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 log Logging
*
* ##Logging
*
* Lws provides flexible and filterable logging facilities, which can be
* used inside lws and in user code.
*
* Log categories may be individually filtered bitwise, and directed to built-in
* sinks for syslog-compatible logging, or a user-defined function.
*
* Traditional logs use a single, processwide logging context. New style log
* apis (lws_xxx_cx()) can pass the logging context to use in.
*/
///@{
#define LLL_ERR (1 << 0)
#define LLL_WARN (1 << 1)
#define LLL_NOTICE (1 << 2)
#define LLL_INFO (1 << 3)
#define LLL_DEBUG (1 << 4)
#define LLL_PARSER (1 << 5)
#define LLL_HEADER (1 << 6)
#define LLL_EXT (1 << 7)
#define LLL_CLIENT (1 << 8)
#define LLL_LATENCY (1 << 9)
#define LLL_USER (1 << 10)
#define LLL_THREAD (1 << 11)
#define LLL_COUNT (12) /* set to count of valid flags */
#define LLLF_SECRECY_PII (1 << 16)
/**< contains Personally Identifiable Information */
#define LLLF_SECRECY_BEARER (1 << 17)
/**< possession of this data allows impersonation */
#define LLLF_LOG_TIMESTAMP (1 << 18)
/**< set to prepend logs with timestamp */
#define LLLF_LOG_CONTEXT_AWARE (1 << 30)
/**< set if the context uses an emit function that takes the logctx, auto-
* applied when setting emit using lws_set_log_level_cx() api */
struct lws_log_cx;
typedef void (*lws_log_emit_t)(int level, const char *line);
typedef void (*lws_log_emit_cx_t)(struct lws_log_cx *cx, int level,
const char *line, size_t len);
typedef void (*lws_log_prepend_cx_t)(struct lws_log_cx *cx, void *obj,
char **p, char *e);
typedef void (*lws_log_use_cx_t)(struct lws_log_cx *cx, int _new);
/*
* This is the logging context
*/
typedef struct lws_log_cx {
union {
lws_log_emit_t emit; /* legacy emit function */
lws_log_emit_cx_t emit_cx; /* LLLF_LOG_CONTEXT_AWARE */
} u;
#if LWS_MAX_SMP > 1
pthread_mutex_t refcount_lock;
#endif
lws_log_use_cx_t refcount_cb;
/**< NULL, or a function called after each change to .refcount below,
* this enables implementing side-effects like opening and closing
* log files when the first and last object binds / unbinds */
lws_log_prepend_cx_t prepend;
/**< NULL, or a cb to optionally prepend a string to logs we are a
* parent of */
struct lws_log_cx *parent;
/**< NULL, or points to log ctx we are a child of */
void *opaque;
/**< ignored by lws, used to pass config to emit_cx, eg, filepath */
void *stg;
/**< ignored by lws, may be used a storage by refcount_cb / emit_cx */
uint32_t lll_flags;
/**< mask of log levels we want to emit in this context */
int32_t refcount;
/**< refcount of objects bound to this log context */
#if LWS_MAX_SMP > 1
char inited;
#endif
} lws_log_cx_t;
/**
* lwsl_timestamp: generate logging timestamp string
*
* \param level: logging level
* \param p: char * buffer to take timestamp
* \param len: length of p
*
* returns length written in p
*/
LWS_VISIBLE LWS_EXTERN int
lwsl_timestamp(int level, char *p, size_t len);
#if defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK)
#define _lws_log(aaa, ...) SMSG(__VA_ARGS__)
#else
LWS_VISIBLE LWS_EXTERN void
_lws_log(int filter, const char *format, ...) LWS_FORMAT(2);
LWS_VISIBLE LWS_EXTERN void
_lws_logv(int filter, const char *format, va_list vl);
#endif
struct lws_vhost;
struct lws;
LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
lwsl_context_get_cx(struct lws_context *cx);
LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
lwsl_vhost_get_cx(struct lws_vhost *vh);
LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
lwsl_wsi_get_cx(struct lws *wsi);
#if defined(LWS_WITH_SECURE_STREAMS)
struct lws_ss_handle;
LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
lwsl_ss_get_cx(struct lws_ss_handle *ss);
#endif
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
struct lws_sspc_handle;
LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
lwsl_sspc_get_cx(struct lws_sspc_handle *ss);
#endif
LWS_VISIBLE LWS_EXTERN void
lws_log_emit_cx_file(struct lws_log_cx *cx, int level, const char *line,
size_t len);
LWS_VISIBLE LWS_EXTERN void
lws_log_use_cx_file(struct lws_log_cx *cx, int _new);
LWS_VISIBLE LWS_EXTERN void
lws_log_prepend_context(struct lws_log_cx *cx, void *obj, char **p, char *e);
LWS_VISIBLE LWS_EXTERN void
lws_log_prepend_vhost(struct lws_log_cx *cx, void *obj, char **p, char *e);
LWS_VISIBLE LWS_EXTERN void
lws_log_prepend_wsi(struct lws_log_cx *cx, void *obj, char **p, char *e);
#if defined(LWS_WITH_SECURE_STREAMS)
LWS_VISIBLE LWS_EXTERN void
lws_log_prepend_ss(struct lws_log_cx *cx, void *obj, char **p, char *e);
#endif
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
LWS_VISIBLE LWS_EXTERN void
lws_log_prepend_sspc(struct lws_log_cx *cx, void *obj, char **p, char *e);
#endif
LWS_VISIBLE LWS_EXTERN void
_lws_log_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
int filter, const char *_fun, const char *format, ...) LWS_FORMAT(6);
#define lwsl_cx(_c, _fil, ...) \
_lws_log_cx(lwsl_context_get_cx(_c), lws_log_prepend_context, \
_c, _fil, __func__, __VA_ARGS__)
#define lwsl_vhost(_v, _fil, ...) \
_lws_log_cx(lwsl_vhost_get_cx(_v), lws_log_prepend_vhost, _v, \
_fil, __func__, __VA_ARGS__)
#define lwsl_wsi(_w, _fil, ...) \
_lws_log_cx(lwsl_wsi_get_cx(_w), lws_log_prepend_wsi, _w, \
_fil, __func__, __VA_ARGS__)
#define lwsl_ss(_h, _fil, ...) \
_lws_log_cx(lwsl_ss_get_cx(_h), lws_log_prepend_ss, _h, \
_fil, __func__, __VA_ARGS__)
#define lwsl_hexdump_context(_c, _fil, _buf, _len) \
lwsl_hexdump_level_cx(lwsl_context_get_cx(_c), \
lws_log_prepend_context, \
_c, _fil, _buf, _len)
#define lwsl_hexdump_vhost(_v, _fil, _buf, _len) \
lwsl_hexdump_level_cx(lwsl_vhost_get_cx(_v), \
lws_log_prepend_vhost, \
_v, _fil, _buf, _len)
#define lwsl_hexdump_wsi(_w, _fil, _buf, _len) \
lwsl_hexdump_level_cx(lwsl_wsi_get_cx(_w), \
lws_log_prepend_wsi, \
_w, _fil, _buf, _len)
#define lwsl_hexdump_ss(_h, _fil, _buf, _len) \
lwsl_hexdump_level_cx(lwsl_ss_get_cx(_h), \
lws_log_prepend_ss, \
_h, _fil, _buf, _len)
/*
* Figure out which logs to build in or not
*/
#if defined(_DEBUG)
/*
* In DEBUG build, select all logs unless NO_LOGS
*/
#if defined(LWS_WITH_NO_LOGS)
#define _LWS_LINIT (LLL_ERR | LLL_USER)
#else
#define _LWS_LINIT ((1 << LLL_COUNT) - 1)
#endif
#else /* not _DEBUG */
#if defined(LWS_WITH_NO_LOGS)
#define _LWS_LINIT (LLL_ERR | LLL_USER)
#else
#define _LWS_LINIT (LLL_ERR | LLL_USER | LLL_WARN | LLL_NOTICE)
#endif
#endif /* _DEBUG */
/*
* Create either empty overrides or the ones forced at build-time.
* These overrides have the final say... any bits set in
* LWS_LOGGING_BITFIELD_SET force the build of those logs, any bits
* set in LWS_LOGGING_BITFIELD_CLEAR disable the build of those logs.
*
* If not defined lws decides based on CMAKE_BUILD_TYPE=DEBUG or not
*/
#if defined(LWS_LOGGING_BITFIELD_SET)
#define _LWS_LBS (LWS_LOGGING_BITFIELD_SET)
#else
#define _LWS_LBS 0
#endif
#if defined(LWS_LOGGING_BITFIELD_CLEAR)
#define _LWS_LBC (LWS_LOGGING_BITFIELD_CLEAR)
#else
#define _LWS_LBC 0
#endif
/*
* Compute the final active logging bitfield for build
*/
#define _LWS_ENABLED_LOGS (((_LWS_LINIT) | (_LWS_LBS)) & ~(_LWS_LBC))
/*
* Individually enable or disable log levels for build
* depending on what was computed
*/
/*
* Process scope logs
*/
#if (_LWS_ENABLED_LOGS & LLL_ERR)
#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__)
#else
#define lwsl_err(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_WARN)
#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
#else
#define lwsl_warn(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
#else
#define lwsl_notice(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_INFO)
#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__)
#else
#define lwsl_info(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__)
#else
#define lwsl_debug(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_PARSER)
#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__)
#else
#define lwsl_parser(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_HEADER)
#define lwsl_header(...) _lws_log(LLL_HEADER, __VA_ARGS__)
#else
#define lwsl_header(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_EXT)
#define lwsl_ext(...) _lws_log(LLL_EXT, __VA_ARGS__)
#else
#define lwsl_ext(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__)
#else
#define lwsl_client(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__)
#else
#define lwsl_latency(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_THREAD)
#define lwsl_thread(...) _lws_log(LLL_THREAD, __VA_ARGS__)
#else
#define lwsl_thread(...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_USER)
#define lwsl_user(...) _lws_log(LLL_USER, __VA_ARGS__)
#else
#define lwsl_user(...) do {} while(0)
#endif
#define lwsl_hexdump_err(...) lwsl_hexdump_level(LLL_ERR, __VA_ARGS__)
#define lwsl_hexdump_warn(...) lwsl_hexdump_level(LLL_WARN, __VA_ARGS__)
#define lwsl_hexdump_notice(...) lwsl_hexdump_level(LLL_NOTICE, __VA_ARGS__)
#define lwsl_hexdump_info(...) lwsl_hexdump_level(LLL_INFO, __VA_ARGS__)
#define lwsl_hexdump_debug(...) lwsl_hexdump_level(LLL_DEBUG, __VA_ARGS__)
/*
* lws_context scope logs
*/
#if (_LWS_ENABLED_LOGS & LLL_ERR)
#define lwsl_cx_err(_c, ...) lwsl_cx(_c, LLL_ERR, __VA_ARGS__)
#else
#define lwsl_cx_err(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_WARN)
#define lwsl_cx_warn(_c, ...) lwsl_cx(_c, LLL_WARN, __VA_ARGS__)
#else
#define lwsl_cx_warn(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
#define lwsl_cx_notice(_c, ...) lwsl_cx(_c, LLL_NOTICE, __VA_ARGS__)
#else
#define lwsl_cx_notice(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_INFO)
#define lwsl_cx_info(_c, ...) lwsl_cx(_c, LLL_INFO, __VA_ARGS__)
#else
#define lwsl_cx_info(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
#define lwsl_cx_debug(_c, ...) lwsl_cx(_c, LLL_DEBUG, __VA_ARGS__)
#else
#define lwsl_cx_debug(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_PARSER)
#define lwsl_cx_parser(_c, ...) lwsl_cx(_c, LLL_PARSER, __VA_ARGS__)
#else
#define lwsl_cx_parser(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_HEADER)
#define lwsl_cx_header(_c, ...) lwsl_cx(_c, LLL_HEADER, __VA_ARGS__)
#else
#define lwsl_cx_header(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_EXT)
#define lwsl_cx_ext(_c, ...) lwsl_cx(_c, LLL_EXT, __VA_ARGS__)
#else
#define lwsl_cx_ext(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
#define lwsl_cx_client(_c, ...) lwsl_cx(_c, LLL_CLIENT, __VA_ARGS__)
#else
#define lwsl_cx_client(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
#define lwsl_cx_latency(_c, ...) lwsl_cx(_c, LLL_LATENCY, __VA_ARGS__)
#else
#define lwsl_cx_latency(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_THREAD)
#define lwsl_cx_thread(_c, ...) lwsl_cx(_c, LLL_THREAD, __VA_ARGS__)
#else
#define lwsl_cx_thread(_c, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_USER)
#define lwsl_cx_user(_c, ...) lwsl_cx(_c, LLL_USER, __VA_ARGS__)
#else
#define lwsl_cx_user(_c, ...) do {} while(0)
#endif
#define lwsl_hexdump_cx_err(_c, ...) lwsl_hexdump_context(_c, LLL_ERR, __VA_ARGS__)
#define lwsl_hexdump_cx_warn(_c, ...) lwsl_hexdump_context(_c, LLL_WARN, __VA_ARGS__)
#define lwsl_hexdump_cx_notice(_c, ...) lwsl_hexdump_context(_c, LLL_NOTICE, __VA_ARGS__)
#define lwsl_hexdump_cx_info(_c, ...) lwsl_hexdump_context(_c, LLL_INFO, __VA_ARGS__)
#define lwsl_hexdump_cx_debug(_c, ...) lwsl_hexdump_context(_c, LLL_DEBUG, __VA_ARGS__)
/*
* lws_vhost
*/
#if (_LWS_ENABLED_LOGS & LLL_ERR)
#define lwsl_vhost_err(_v, ...) lwsl_vhost(_v, LLL_ERR, __VA_ARGS__)
#else
#define lwsl_vhost_err(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_WARN)
#define lwsl_vhost_warn(_v, ...) lwsl_vhost(_v, LLL_WARN, __VA_ARGS__)
#else
#define lwsl_vhost_warn(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
#define lwsl_vhost_notice(_v, ...) lwsl_vhost(_v, LLL_NOTICE, __VA_ARGS__)
#else
#define lwsl_vhost_notice(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_INFO)
#define lwsl_vhost_info(_v, ...) lwsl_vhost(_v, LLL_INFO, __VA_ARGS__)
#else
#define lwsl_vhost_info(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
#define lwsl_vhost_debug(_v, ...) lwsl_vhost(_v, LLL_DEBUG, __VA_ARGS__)
#else
#define lwsl_vhost_debug(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_PARSER)
#define lwsl_vhost_parser(_v, ...) lwsl_vhost(_v, LLL_PARSER, __VA_ARGS__)
#else
#define lwsl_vhost_parser(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_HEADER)
#define lwsl_vhost_header(_v, ...) lwsl_vhost(_v, LLL_HEADER, __VA_ARGS__)
#else
#define lwsl_vhost_header(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_EXT)
#define lwsl_vhost_ext(_v, ...) lwsl_vhost(_v, LLL_EXT, __VA_ARGS__)
#else
#define lwsl_vhost_ext(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
#define lwsl_vhost_client(_v, ...) lwsl_vhost(_v, LLL_CLIENT, __VA_ARGS__)
#else
#define lwsl_vhost_client(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
#define lwsl_vhost_latency(_v, ...) lwsl_vhost(_v, LLL_LATENCY, __VA_ARGS__)
#else
#define lwsl_vhost_latency(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_THREAD)
#define lwsl_vhost_thread(_v, ...) lwsl_vhost(_v, LLL_THREAD, __VA_ARGS__)
#else
#define lwsl_vhost_thread(_v, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_USER)
#define lwsl_vhost_user(_v, ...) lwsl_vhost(_v, LLL_USER, __VA_ARGS__)
#else
#define lwsl_vhost_user(_v, ...) do {} while(0)
#endif
#define lwsl_hexdump_vhost_err(_v, ...) lwsl_hexdump_vhost(_v, LLL_ERR, __VA_ARGS__)
#define lwsl_hexdump_vhost_warn(_v, ...) lwsl_hexdump_vhost(_v, LLL_WARN, __VA_ARGS__)
#define lwsl_hexdump_vhost_notice(_v, ...) lwsl_hexdump_vhost(_v, LLL_NOTICE, __VA_ARGS__)
#define lwsl_hexdump_vhost_info(_v, ...) lwsl_hexdump_vhost(_v, LLL_INFO, __VA_ARGS__)
#define lwsl_hexdump_vhost_debug(_v, ...) lwsl_hexdump_vhost(_v, LLL_DEBUG, __VA_ARGS__)
/*
* lws_wsi
*/
#if (_LWS_ENABLED_LOGS & LLL_ERR)
#define lwsl_wsi_err(_w, ...) lwsl_wsi(_w, LLL_ERR, __VA_ARGS__)
#else
#define lwsl_wsi_err(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_WARN)
#define lwsl_wsi_warn(_w, ...) lwsl_wsi(_w, LLL_WARN, __VA_ARGS__)
#else
#define lwsl_wsi_warn(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
#define lwsl_wsi_notice(_w, ...) lwsl_wsi(_w, LLL_NOTICE, __VA_ARGS__)
#else
#define lwsl_wsi_notice(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_INFO)
#define lwsl_wsi_info(_w, ...) lwsl_wsi(_w, LLL_INFO, __VA_ARGS__)
#else
#define lwsl_wsi_info(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
#define lwsl_wsi_debug(_w, ...) lwsl_wsi(_w, LLL_DEBUG, __VA_ARGS__)
#else
#define lwsl_wsi_debug(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_PARSER)
#define lwsl_wsi_parser(_w, ...) lwsl_wsi(_w, LLL_PARSER, __VA_ARGS__)
#else
#define lwsl_wsi_parser(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_HEADER)
#define lwsl_wsi_header(_w, ...) lwsl_wsi(_w, LLL_HEADER, __VA_ARGS__)
#else
#define lwsl_wsi_header(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_EXT)
#define lwsl_wsi_ext(_w, ...) lwsl_wsi(_w, LLL_EXT, __VA_ARGS__)
#else
#define lwsl_wsi_ext(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
#define lwsl_wsi_client(_w, ...) lwsl_wsi(_w, LLL_CLIENT, __VA_ARGS__)
#else
#define lwsl_wsi_client(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
#define lwsl_wsi_latency(_w, ...) lwsl_wsi(_w, LLL_LATENCY, __VA_ARGS__)
#else
#define lwsl_wsi_latency(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_THREAD)
#define lwsl_wsi_thread(_w, ...) lwsl_wsi(_w, LLL_THREAD, __VA_ARGS__)
#else
#define lwsl_wsi_thread(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_USER)
#define lwsl_wsi_user(_w, ...) lwsl_wsi(_w, LLL_USER, __VA_ARGS__)
#else
#define lwsl_wsi_user(_w, ...) do {} while(0)
#endif
#define lwsl_hexdump_wsi_err(_v, ...) lwsl_hexdump_wsi(_v, LLL_ERR, __VA_ARGS__)
#define lwsl_hexdump_wsi_warn(_v, ...) lwsl_hexdump_wsi(_v, LLL_WARN, __VA_ARGS__)
#define lwsl_hexdump_wsi_notice(_v, ...) lwsl_hexdump_wsi(_v, LLL_NOTICE, __VA_ARGS__)
#define lwsl_hexdump_wsi_info(_v, ...) lwsl_hexdump_wsi(_v, LLL_INFO, __VA_ARGS__)
#define lwsl_hexdump_wsi_debug(_v, ...) lwsl_hexdump_wsi(_v, LLL_DEBUG, __VA_ARGS__)
/*
* lwsl_ss
*/
#if (_LWS_ENABLED_LOGS & LLL_ERR)
#define lwsl_ss_err(_w, ...) lwsl_ss(_w, LLL_ERR, __VA_ARGS__)
#else
#define lwsl_ss_err(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_WARN)
#define lwsl_ss_warn(_w, ...) lwsl_ss(_w, LLL_WARN, __VA_ARGS__)
#else
#define lwsl_ss_warn(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
#define lwsl_ss_notice(_w, ...) lwsl_ss(_w, LLL_NOTICE, __VA_ARGS__)
#else
#define lwsl_ss_notice(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_INFO)
#define lwsl_ss_info(_w, ...) lwsl_ss(_w, LLL_INFO, __VA_ARGS__)
#else
#define lwsl_ss_info(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
#define lwsl_ss_debug(_w, ...) lwsl_ss(_w, LLL_DEBUG, __VA_ARGS__)
#else
#define lwsl_ss_debug(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_PARSER)
#define lwsl_ss_parser(_w, ...) lwsl_ss(_w, LLL_PARSER, __VA_ARGS__)
#else
#define lwsl_ss_parser(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_HEADER)
#define lwsl_ss_header(_w, ...) lwsl_ss(_w, LLL_HEADER, __VA_ARGS__)
#else
#define lwsl_ss_header(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_EXT)
#define lwsl_ss_ext(_w, ...) lwsl_ss(_w, LLL_EXT, __VA_ARGS__)
#else
#define lwsl_ss_ext(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
#define lwsl_ss_client(_w, ...) lwsl_ss(_w, LLL_CLIENT, __VA_ARGS__)
#else
#define lwsl_ss_client(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
#define lwsl_ss_latency(_w, ...) lwsl_ss(_w, LLL_LATENCY, __VA_ARGS__)
#else
#define lwsl_ss_latency(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_THREAD)
#define lwsl_ss_thread(_w, ...) lwsl_ss(_w, LLL_THREAD, __VA_ARGS__)
#else
#define lwsl_ss_thread(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_USER)
#define lwsl_ss_user(_w, ...) lwsl_ss(_w, LLL_USER, __VA_ARGS__)
#else
#define lwsl_ss_user(_w, ...) do {} while(0)
#endif
#define lwsl_hexdump_ss_err(_v, ...) lwsl_hexdump_ss(_v, LLL_ERR, __VA_ARGS__)
#define lwsl_hexdump_ss_warn(_v, ...) lwsl_hexdump_ss(_v, LLL_WARN, __VA_ARGS__)
#define lwsl_hexdump_ss_notice(_v, ...) lwsl_hexdump_ss(_v, LLL_NOTICE, __VA_ARGS__)
#define lwsl_hexdump_ss_info(_v, ...) lwsl_hexdump_ss(_v, LLL_INFO, __VA_ARGS__)
#define lwsl_hexdump_ss_debug(_v, ...) lwsl_hexdump_ss(_v, LLL_DEBUG, __VA_ARGS__)
/**
* lwsl_hexdump_level() - helper to hexdump a buffer at a selected debug level
*
* \param level: one of LLL_ constants
* \param vbuf: buffer start to dump
* \param len: length of buffer to dump
*
* If \p level is visible, does a nice hexdump -C style dump of \p vbuf for
* \p len bytes. This can be extremely convenient while debugging.
*/
LWS_VISIBLE LWS_EXTERN void
lwsl_hexdump_level(int level, const void *vbuf, size_t len);
LWS_VISIBLE LWS_EXTERN void
lwsl_hexdump_level_cx(lws_log_cx_t *cx, lws_log_prepend_cx_t prep, void *obj,
int hexdump_level, const void *vbuf, size_t len);
/**
* lwsl_hexdump() - helper to hexdump a buffer (DEBUG builds only)
*
* \param buf: buffer start to dump
* \param len: length of buffer to dump
*
* Calls through to lwsl_hexdump_level(LLL_DEBUG, ... for compatability.
* It's better to use lwsl_hexdump_level(level, ... directly so you can control
* the visibility.
*/
LWS_VISIBLE LWS_EXTERN void
lwsl_hexdump(const void *buf, size_t len);
/**
* lws_is_be() - returns nonzero if the platform is Big Endian
*/
static LWS_INLINE int lws_is_be(void) {
const int probe = ~0xff;
return *(const char *)&probe;
}
/**
* lws_set_log_level() - Set the logging bitfield
* \param level: OR together the LLL_ debug contexts you want output from
* \param log_emit_function: NULL to leave it as it is, or a user-supplied
* function to perform log string emission instead of
* the default stderr one.
*
* log level defaults to "err", "warn" and "notice" contexts enabled and
* emission on stderr. If stderr is a tty (according to isatty()) then
* the output is coloured according to the log level using ANSI escapes.
*
* You can set the default security level for logging using the
* secrecy_and_log_level() macro to set the \p level parameter, eg
*
* lws_set_log_level(secrecy_and_log_level(LWS_SECRECY_PII, LLL_ERR | LLL_WARN),
* my_emit_function);
*
* Normally you can just leave it at the default.
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_log_level(int level, lws_log_emit_t log_emit_function);
/**
* lwsl_emit_syslog() - helper log emit function writes to system log
*
* \param level: one of LLL_ log level indexes
* \param line: log string
*
* You use this by passing the function pointer to lws_set_log_level(), to set
* it as the log emit function, it is not called directly.
*/
LWS_VISIBLE LWS_EXTERN void
lwsl_emit_syslog(int level, const char *line);
/**
* lwsl_emit_stderr() - helper log emit function writes to stderr
*
* \param level: one of LLL_ log level indexes
* \param line: log string
*
* You use this by passing the function pointer to lws_set_log_level(), to set
* it as the log emit function, it is not called directly.
*
* It prepends a system timestamp like [2018/11/13 07:41:57:3989]
*
* If stderr is a tty, then ansi colour codes are added.
*/
LWS_VISIBLE LWS_EXTERN void
lwsl_emit_stderr(int level, const char *line);
/**
* lwsl_emit_stderr_notimestamp() - helper log emit function writes to stderr
*
* \param level: one of LLL_ log level indexes
* \param line: log string
*
* You use this by passing the function pointer to lws_set_log_level(), to set
* it as the log emit function, it is not called directly.
*
* If stderr is a tty, then ansi colour codes are added.
*/
LWS_VISIBLE LWS_EXTERN void
lwsl_emit_stderr_notimestamp(int level, const char *line);
/**
* lwsl_visible() - returns true if the log level should be printed
*
* \param level: one of LLL_ log level indexes
*
* This is useful if you have to do work to generate the log content, you
* can skip the work if the log level used to print it is not actually
* enabled at runtime.
*/
LWS_VISIBLE LWS_EXTERN int
lwsl_visible(int level);
struct lws;
LWS_VISIBLE LWS_EXTERN const char *
lws_wsi_tag(struct lws *wsi);
LWS_VISIBLE LWS_EXTERN void
lwsl_refcount_cx(lws_log_cx_t *cx, int _new);
///@}

View File

@ -0,0 +1,290 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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 lwsac lwsac
*
* ##Allocated Chunks
*
* If you know you will be allocating a large, unknown number of same or
* differently sized objects, it's certainly possible to do it with libc
* malloc. However the allocation cost in time and memory overhead can
* add up, and deallocation means walking the structure of every object and
* freeing them in turn.
*
* lwsac (LWS Allocated Chunks) allocates chunks intended to be larger
* than your objects (4000 bytes by default) which you linearly allocate from
* using lwsac_use().
*
* If your next request won't fit in the current chunk, a new chunk is added
* to the chain of chunks and the allocaton done from there. If the request
* is larger than the chunk size, an oversize chunk is created to satisfy it.
*
* When you are finished with the allocations, you call lwsac_free() and
* free all the *chunks*. So you may have thousands of objects in the chunks,
* but they are all destroyed with the chunks without having to deallocate them
* one by one pointlessly.
*/
///@{
struct lwsac;
typedef unsigned char * lwsac_cached_file_t;
#define lws_list_ptr_container(P,T,M) ((T *)((char *)(P) - offsetof(T, M)))
/*
* linked-list helper that's commonly useful to manage lists of things
* allocated using lwsac.
*
* These lists point to their corresponding "next" member in the target, NOT
* the original containing struct. To get the containing struct, you must use
* lws_list_ptr_container() to convert.
*
* It's like that because it means we no longer have to have the next pointer
* at the start of the struct, and we can have the same struct on multiple
* linked-lists with everything held in the struct itself.
*/
typedef void * lws_list_ptr;
/*
* optional sorting callback called by lws_list_ptr_insert() to sort the right
* things inside the opqaue struct being sorted / inserted on the list.
*/
typedef int (*lws_list_ptr_sort_func_t)(lws_list_ptr a, lws_list_ptr b);
#define lws_list_ptr_advance(_lp) _lp = *((void **)_lp)
/* sort may be NULL if you don't care about order */
LWS_VISIBLE LWS_EXTERN void
lws_list_ptr_insert(lws_list_ptr *phead, lws_list_ptr *add,
lws_list_ptr_sort_func_t sort);
/**
* lwsac_use - allocate / use some memory from a lwsac
*
* \param head: pointer to the lwsac list object
* \param ensure: the number of bytes we want to use
* \param chunk_size: 0, or the size of the chunk to (over)allocate if
* what we want won't fit in the current tail chunk. If
* 0, the default value of 4000 is used. If ensure is
* larger, it is used instead.
*
* This also serves to init the lwsac if *head is NULL. Basically it does
* whatever is necessary to return you a pointer to ensure bytes of memory
* reserved for the caller.
*
* This always allocates in the current chunk or a new chunk... see the
* lwsac_use_backfill() variant to try first to find space in earlier chunks.
*
* Returns NULL if OOM.
*/
LWS_VISIBLE LWS_EXTERN void *
lwsac_use(struct lwsac **head, size_t ensure, size_t chunk_size);
/**
* lwsac_use_backfill - allocate / use some memory from a lwsac
*
* \param head: pointer to the lwsac list object
* \param ensure: the number of bytes we want to use
* \param chunk_size: 0, or the size of the chunk to (over)allocate if
* what we want won't fit in the current tail chunk. If
* 0, the default value of 4000 is used. If ensure is
* larger, it is used instead.
*
* This also serves to init the lwsac if *head is NULL. Basically it does
* whatever is necessary to return you a pointer to ensure bytes of memory
* reserved for the caller.
*
* Also checks if earlier blocks have enough remaining space to take the
* allocation before making a new allocation.
*
* Returns NULL if OOM.
*/
LWS_VISIBLE LWS_EXTERN void *
lwsac_use_backfill(struct lwsac **head, size_t ensure, size_t chunk_size);
/**
* lwsac_use - allocate / use some memory from a lwsac
*
* \param head: pointer to the lwsac list object
* \param ensure: the number of bytes we want to use, which must be zeroed
* \param chunk_size: 0, or the size of the chunk to (over)allocate if
* what we want won't fit in the current tail chunk. If
* 0, the default value of 4000 is used. If ensure is
* larger, it is used instead.
*
* Same as lwsac_use(), but \p ensure bytes of memory at the return address
* are zero'd before returning.
*
* Returns NULL if OOM.
*/
LWS_VISIBLE LWS_EXTERN void *
lwsac_use_zero(struct lwsac **head, size_t ensure, size_t chunk_size);
#define lwsac_use_zeroed lwsac_use_zero
/**
* lwsac_free - deallocate all chunks in the lwsac and set head NULL
*
* \param head: pointer to the lwsac list object
*
* This deallocates all chunks in the lwsac, then sets *head to NULL. All
* lwsac_use() pointers are invalidated in one hit without individual frees.
*/
LWS_VISIBLE LWS_EXTERN void
lwsac_free(struct lwsac **head);
/*
* Optional helpers useful for where consumers may need to defer destruction
* until all consumers are finished with the lwsac
*/
/**
* lwsac_detach() - destroy an lwsac unless somebody else is referencing it
*
* \param head: pointer to the lwsac list object
*
* The creator of the lwsac can all this instead of lwsac_free() when it itself
* has finished with the lwsac, but other code may be consuming it.
*
* If there are no other references, the lwsac is destroyed, *head is set to
* NULL and that's the end; however if something else has called
* lwsac_reference() on the lwsac, it simply returns. When lws_unreference()
* is called and no references are left, it will be destroyed then.
*/
LWS_VISIBLE LWS_EXTERN void
lwsac_detach(struct lwsac **head);
/**
* lwsac_reference() - increase the lwsac reference count
*
* \param head: pointer to the lwsac list object
*
* Increment the reference count on the lwsac to defer destruction.
*/
LWS_VISIBLE LWS_EXTERN void
lwsac_reference(struct lwsac *head);
/**
* lwsac_unreference() - decrease the lwsac reference count
*
* \param head: pointer to the lwsac list object
*
* Decrement the reference count on the lwsac... if it reached 0 on a detached
* lwsac then the lwsac is immediately destroyed and *head set to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lwsac_unreference(struct lwsac **head);
/**
* lwsac_extend() - try to increase the size of the last block
*
* \param head: pointer to the lwsac list object
* \param amount: amount to try to increase usage for
*
* This will either increase the usage reservation of the last allocated block
* by amount and return 0, or fail and return 1.
*
* This is very cheap to call and is designed to optimize usage after a static
* struct for vari-sized additional content which may flow into an additional
* block in a new chunk if necessary, but wants to make the most of the space
* in front of it first to try to avoid gaps and the new chunk if it can.
*
* The additional area if the call succeeds will have been memset to 0.
*
* To use it, the following must be true:
*
* - only the last lwsac use can be extended
*
* - if another use happens inbetween the use and extend, it will break
*
* - the use cannot have been using backfill
*
* - a user object must be tracking the current allocated size of the last use
* (lwsac doesn't know it) and increment by amount if the extend call succeeds
*
* Despite these restrictions this can be an important optimization for some
* cases
*/
LWS_VISIBLE LWS_EXTERN int
lwsac_extend(struct lwsac *head, size_t amount);
/* helpers to keep a file cached in memory */
LWS_VISIBLE LWS_EXTERN void
lwsac_use_cached_file_start(lwsac_cached_file_t cache);
LWS_VISIBLE LWS_EXTERN void
lwsac_use_cached_file_end(lwsac_cached_file_t *cache);
LWS_VISIBLE LWS_EXTERN void
lwsac_use_cached_file_detach(lwsac_cached_file_t *cache);
LWS_VISIBLE LWS_EXTERN int
lwsac_cached_file(const char *filepath, lwsac_cached_file_t *cache,
size_t *len);
/* more advanced helpers */
/* offset from lac to start of payload, first = 1 = first lac in chain */
LWS_VISIBLE LWS_EXTERN size_t
lwsac_sizeof(int first);
LWS_VISIBLE LWS_EXTERN size_t
lwsac_get_tail_pos(struct lwsac *lac);
LWS_VISIBLE LWS_EXTERN struct lwsac *
lwsac_get_next(struct lwsac *lac);
LWS_VISIBLE LWS_EXTERN size_t
lwsac_align(size_t length);
LWS_VISIBLE LWS_EXTERN void
lwsac_info(struct lwsac *head);
LWS_VISIBLE LWS_EXTERN uint64_t
lwsac_total_alloc(struct lwsac *head);
LWS_VISIBLE LWS_EXTERN uint64_t
lwsac_total_overhead(struct lwsac *head);
/**
* lwsac_scan_extant() - returns existing copy of blob, or NULL
*
* \param head: the lwsac to scan
* \param find: the blob to look for
* \param len: the length of the blob to look for
* \param nul: nonzero if the next byte must be NUL
*
* Helper that looks through a whole lwsac for a given binary blob already
* present. Used in the case that lwsac contents are const once written, and
* strings or blobs may be repeated in the input: this allows the earlier
* copy to be pointed to by subsequent references without repeating the string
* or blob redundantly.
*/
LWS_VISIBLE LWS_EXTERN uint8_t *
lwsac_scan_extant(struct lwsac *head, uint8_t *find, size_t len, int nul);
///@}

View File

@ -0,0 +1,188 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 lws_map generic map apis
* ##Generic map structures and apis
* \ingroup lwsapi
*
* lws_map
*
* Discrete owner object represents the whole map, created with key-specific
* ops for hashing the key to a uint32_t and comparing two keys. Owns a list
* of hash tables whose size / modulo it set at creation time.
*
* Items in the map are contained in a lws_map_item_t that is indexed in a
* hash table.
*
* It's difficult to make a single compact map abstraction that fits all cases,
* this is useful to the extent you have the memory to trade off the number of
* hashtables needed for the amount of items and the lookup latency limit for
* your application, typically for hundreds or low thousands of items.
*/
//@{
typedef struct lws_map lws_map_t;
struct lws_map_item;
typedef void * lws_map_key_t;
typedef void * lws_map_value_t;
typedef uint32_t lws_map_hash_t;
typedef lws_map_hash_t (*lws_map_hash_from_key_t)(const lws_map_key_t key,
size_t kl);
typedef int (*lws_map_compare_key_t)(const lws_map_key_t key1, size_t kl1,
const lws_map_value_t key2, size_t kl2);
typedef void * (*lws_map_alloc_t)(struct lws_map *mo, size_t x);
typedef void (*lws_map_free_t)(void *);
/*
* Creation parameters for the map, copied into the map owner
*/
typedef struct lws_map_info {
lws_map_hash_from_key_t _hash;
lws_map_compare_key_t _compare;
lws_map_alloc_t _alloc; /* NULL = lws_malloc */
lws_map_free_t _free; /* NULL = lws_free */
void *opaque;
/**< &lwsac if using lwsac allocator */
void *aux;
/**< chunk size if using lwsac allocator */
/**< this can be used by the alloc handler, eg for lws_ac */
size_t modulo;
/**< number of hashed owner lists to create */
} lws_map_info_t;
LWS_VISIBLE LWS_EXTERN const void *
lws_map_item_key(struct lws_map_item *_item);
LWS_VISIBLE LWS_EXTERN const void *
lws_map_item_value(struct lws_map_item *_item);
LWS_VISIBLE LWS_EXTERN size_t
lws_map_item_key_len(struct lws_map_item *_item);
LWS_VISIBLE LWS_EXTERN size_t
lws_map_item_value_len(struct lws_map_item *_item);
/*
* Helpers for C string keys case
*/
#define lws_map_item_create_ks(_map, _str, _v, _vl) \
lws_map_item_create(_map, (const lws_map_key_t)_str, \
strlen(_str), (const lws_map_value_t)_v, \
_vl)
#define lws_map_item_lookup_ks(_map, _str) \
lws_map_item_lookup(_map, (const lws_map_key_t)_str, strlen(_str))
/**
* lws_map_create() - create a map object and hashtables on heap
*
* \param info: description of map to create
*
* Creates a map object on heap, using lws_malloc().
*
* \p info may be all zeros inside, if so, modulo defaults to 8, and the
* operation callbacks default to using lws_malloc() / _free() for item alloc,
* a default xor / shift based hash and simple linear memory key compare.
*
* For less typical use-cases, the provided \p info members can be tuned to
* control how the allocation of mapped items is done, lws provides two exports
* lws_map_alloc_lwsac() and lws_map_free_lwsac() that can be used for _alloc
* and _free to have items allocated inside an lwsac.
*
* The map itself is created on the heap directly, the info._alloc() op is only
* used when creating items.
*
* keys have individual memory sizes and do not need to all be the same length.
*/
LWS_VISIBLE LWS_EXTERN lws_map_t *
lws_map_create(const lws_map_info_t *info);
/*
* helpers that can be used for info._alloc and info._free if using lwsac
* allocation for items, set info.opaque to point to the lwsac pointer, and
* aux to (void *)chunksize, or leave zero / NULL for the default
*/
LWS_VISIBLE LWS_EXTERN void *
lws_map_alloc_lwsac(struct lws_map *map, size_t x);
LWS_VISIBLE LWS_EXTERN void
lws_map_free_lwsac(void *v);
/**
* lws_map_destroy() - deallocate all items and free map
*
* \param pmap: pointer to pointer map object to deallocate
*
* Frees all items in the map, using info._free(), and then frees the map
* from heap directly. \p *pmap is set to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_map_destroy(lws_map_t **pmap);
/**
* lws_map_item_create() - allocate and map an item into an existing map
*
* \param map: the map to add items into
* \param key: the key, may be any kind of object
* \param keylen: the length of the key in bytes
* \param value: the value, may be any kind of object
* \param valuelen: the length of value
*
* Allocates space for the item, key and value using the map allocator, and
* if non-NULL, copies the key and value into the item.
*
* If an item with the same key exists, it is removed and destroyed before
* creating and adding the new one.
*/
LWS_VISIBLE LWS_EXTERN struct lws_map_item *
lws_map_item_create(lws_map_t *map,
const lws_map_key_t key, size_t keylen,
const lws_map_value_t value, size_t valuelen);
/**
* lws_map_item_destroy() - remove item from map and free
*
* \param item: the item in the map to remove and free
*/
LWS_VISIBLE LWS_EXTERN void
lws_map_item_destroy(struct lws_map_item *item);
/**
* lws_map_item_lookup() - look for a item with the given key in the map
*
* \param map: the map
* \param key: the key to look for
* \param keylen: the length of the key to look for
*
* Searches for the key in the map, using the map's key hash and key compare
* functions.
*/
LWS_VISIBLE LWS_EXTERN struct lws_map_item *
lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen);
//@}

View File

@ -0,0 +1,329 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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.
*
* Public apis related to metric collection and reporting
*/
/* lws_metrics public part */
typedef uint64_t u_mt_t;
enum {
LWSMTFL_REPORT_OUTLIERS = (1 << 0),
/**< track outliers and report them internally */
LWSMTFL_REPORT_OOB = (1 << 1),
/**< report events as they happen */
LWSMTFL_REPORT_INACTIVITY_AT_PERIODIC = (1 << 2),
/**< explicitly externally report no activity at periodic cb, by
* default no events in the period is just not reported */
LWSMTFL_REPORT_MEAN = (1 << 3),
/**< average/min/max is meaningful, else only sum is meaningful */
LWSMTFL_REPORT_ONLY_GO = (1 << 4),
/**< no-go pieces invalid */
LWSMTFL_REPORT_DUTY_WALLCLOCK_US = (1 << 5),
/**< aggregate compares to wallclock us for duty cycle */
LWSMTFL_REPORT_HIST = (1 << 6),
/**< our type is histogram (otherwise, sum / mean aggregation) */
};
/*
* lws_metrics_tag allows your object to accumulate OpenMetrics-style
* descriptive tags before accounting for it with a metrics object at the end.
*
* Tags should represent low entropy information that is likely to repeat
* identically, so, eg, http method name, not eg, latency in us which is
* unlikely to be seen the same twice.
*
* Tags are just a list of name=value pairs, used for qualifying the final
* metrics entry with decorations in additional dimensions. For example,
* rather than keep individual metrics on methods, scheme, mountpoint, result
* code, you can keep metrics on http transactions only, and qualify the
* transaction metrics entries with tags that can be queried on the metrics
* backend to get the finer-grained information.
*
* http_srv{code="404",mount="/",method="GET",scheme="http"} 3
*
* For OpenMetrics the tags are converted to a { list } and appended to the base
* metrics name before using with actual metrics objects, the same set of tags
* on different transactions resolve to the same qualification string.
*/
typedef struct lws_metrics_tag {
lws_dll2_t list;
const char *name; /* tag, intended to be in .rodata, not copied */
/* overallocated value */
} lws_metrics_tag_t;
LWS_EXTERN LWS_VISIBLE int
lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val);
#if defined(LWS_WITH_SYS_METRICS)
/*
* wsi-specific version that also appends the tag value to the lifecycle tag
* used for logging the wsi identity
*/
LWS_EXTERN LWS_VISIBLE int
lws_metrics_tag_wsi_add(struct lws *wsi, const char *name, const char *val);
#else
#define lws_metrics_tag_wsi_add(_a, _b, _c)
#endif
#if defined(LWS_WITH_SECURE_STREAMS)
/*
* ss-specific version that also appends the tag value to the lifecycle tag
* used for logging the ss identity
*/
#if defined(LWS_WITH_SYS_METRICS)
LWS_EXTERN LWS_VISIBLE int
lws_metrics_tag_ss_add(struct lws_ss_handle *ss, const char *name, const char *val);
#else
#define lws_metrics_tag_ss_add(_a, _b, _c)
#endif
#endif
LWS_EXTERN LWS_VISIBLE void
lws_metrics_tags_destroy(lws_dll2_owner_t *owner);
LWS_EXTERN LWS_VISIBLE size_t
lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len);
LWS_EXTERN LWS_VISIBLE const char *
lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name);
/* histogram bucket */
typedef struct lws_metric_bucket {
struct lws_metric_bucket *next;
uint64_t count;
/* name + NUL is overallocated */
} lws_metric_bucket_t;
/* get overallocated name of bucket from bucket pointer */
#define lws_metric_bucket_name_len(_b) (*((uint8_t *)&(_b)[1]))
#define lws_metric_bucket_name(_b) (((const char *)&(_b)[1]) + 1)
/*
* These represent persistent local event measurements. They may aggregate
* a large number of events inbetween external dumping of summaries of the
* period covered, in two different ways
*
* 1) aggregation by sum or mean, to absorb multiple scalar readings
*
* - go / no-go ratio counting
* - mean averaging for, eg, latencies
* - min / max for averaged values
* - period the stats covers
*
* 2) aggregation by histogram, to absorb a range of outcomes that may occur
* multiple times
*
* - add named buckets to histogram
* - bucket has a 64-bit count
* - bumping a bucket just increments the count if already exists, else adds
* a new one with count set to 1
*
* The same type with a union covers both cases.
*
* The lws_system ops api that hooks lws_metrics up to a metrics backend is
* given a pointer to these according to the related policy, eg, hourly, or
* every event passed straight through.
*/
typedef struct lws_metric_pub {
const char *name;
/**< eg, "n.cn.dns", "vh.myendpoint" */
void *backend_opaque;
/**< ignored by lws, backend handler completely owns it */
lws_usec_t us_first;
/**< us time metric started collecting, reset to us_dumped at dump */
lws_usec_t us_last;
/**< 0, or us time last event, reset to 0 at last dump */
lws_usec_t us_dumped;
/**< 0 if never, else us time of last dump to external api */
/* scope of data in .u is "since last dump" --> */
union {
/* aggregation, by sum or mean */
struct {
u_mt_t sum[2];
/**< go, no-go summed for mean or plan sum */
u_mt_t min;
/**< smallest individual measurement */
u_mt_t max;
/**< largest individual measurement */
uint32_t count[2];
/**< go, no-go count of measurements in sum */
} agg;
/* histogram with dynamic named buckets */
struct {
lws_metric_bucket_t *head;
/**< first bucket in our bucket list */
uint64_t total_count;
/**< total count in all of our buckets */
uint32_t list_size;
/**< number of buckets in our bucket list */
} hist;
} u;
uint8_t flags;
} lws_metric_pub_t;
LWS_EXTERN LWS_VISIBLE void
lws_metrics_hist_bump_priv_tagged(lws_metric_pub_t *mt, lws_dll2_owner_t *tow,
lws_dll2_owner_t *tow2);
/*
* Calipers are a helper struct for implementing "hanging latency" detection,
* where setting the start time and finding the end time may happen in more than
* one place.
*
* There are convenience wrappers to eliminate caliper definitions and code
* cleanly if WITH_SYS_METRICS is disabled for the build.
*/
struct lws_metric;
typedef struct lws_metric_caliper {
struct lws_dll2_owner mtags_owner; /**< collect tags here during
* caliper lifetime */
struct lws_metric *mt; /**< NULL == inactive */
lws_usec_t us_start;
} lws_metric_caliper_t;
#if defined(LWS_WITH_SYS_METRICS)
#define lws_metrics_caliper_compose(_name) \
lws_metric_caliper_t _name;
#define lws_metrics_caliper_bind(_name, _mt) \
{ if (_name.mt) { \
lwsl_err("caliper: overwrite %s\n", \
lws_metrics_priv_to_pub(_name.mt)->name); \
assert(0); } \
_name.mt = _mt; _name.us_start = lws_now_usecs(); }
#define lws_metrics_caliper_declare(_name, _mt) \
lws_metric_caliper_t _name = { .mt = _mt, .us_start = lws_now_usecs() }
#define lws_metrics_caliper_report(_name, _go_nogo) \
{ if (_name.us_start) { lws_metric_event(_name.mt, _go_nogo, \
(u_mt_t)(lws_now_usecs() - \
_name.us_start)); \
} lws_metrics_caliper_done(_name); }
#define lws_metrics_caliper_report_hist(_name, pwsi) if (_name.mt) { \
lws_metrics_hist_bump_priv_tagged(lws_metrics_priv_to_pub(_name.mt), \
&_name.mtags_owner, \
pwsi ? &((pwsi)->cal_conn.mtags_owner) : NULL); \
lws_metrics_caliper_done(_name); }
#define lws_metrics_caliper_cancel(_name) { lws_metrics_caliper_done(_name); }
#define lws_metrics_hist_bump(_mt, _name) \
lws_metrics_hist_bump_(_mt, _name)
#define lws_metrics_hist_bump_priv(_mt, _name) \
lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_mt), _name)
#define lws_metrics_caliper_done(_name) { \
_name.us_start = 0; _name.mt = NULL; \
lws_metrics_tags_destroy(&_name.mtags_owner); }
#else
#define lws_metrics_caliper_compose(_name)
#define lws_metrics_caliper_bind(_name, _mt)
#define lws_metrics_caliper_declare(_name, _mp)
#define lws_metrics_caliper_report(_name, _go_nogo)
#define lws_metrics_caliper_report_hist(_name, pwsiconn)
#define lws_metrics_caliper_cancel(_name)
#define lws_metrics_hist_bump(_mt, _name)
#define lws_metrics_hist_bump_priv(_mt, _name)
#define lws_metrics_caliper_done(_name)
#endif
/**
* lws_metrics_format() - helper to format a metrics object for logging
*
* \param pub: public part of metrics object
* \param buf: output buffer to place string in
* \param len: available length of \p buf
*
* Helper for describing the state of a metrics object as a human-readable
* string, accounting for how its flags indicate what it contains. This is not
* how you would report metrics, but during development it can be useful to
* log them inbetween possibily long report intervals.
*
* It uses the metric's flags to adapt the format shown appropriately, eg,
* as a histogram if LWSMTFL_REPORT_HIST etc
*/
LWS_EXTERN LWS_VISIBLE int
lws_metrics_format(lws_metric_pub_t *pub, lws_metric_bucket_t **sub,
char *buf, size_t len);
/**
* lws_metrics_hist_bump() - add or increment histogram bucket
*
* \param pub: public part of metrics object
* \param name: bucket name to increment
*
* Either increment the count of an existing bucket of the right name in the
* metrics object, or add a new bucket of the given name and set its count to 1.
*
* The metrics object must have been created with flag LWSMTFL_REPORT_HIST
*
* Normally, you will actually use the preprocessor wrapper
* lws_metrics_hist_bump() defined above, since this automatically takes care of
* removing itself from the build if WITH_SYS_METRICS is not defined, without
* needing any preprocessor conditionals.
*/
LWS_EXTERN LWS_VISIBLE int
lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name);
LWS_VISIBLE LWS_EXTERN int
lws_metrics_foreach(struct lws_context *ctx, void *user,
int (*cb)(lws_metric_pub_t *pub, void *user));
LWS_VISIBLE LWS_EXTERN int
lws_metrics_hist_bump_describe_wsi(struct lws *wsi, lws_metric_pub_t *pub,
const char *name);
enum {
LMT_NORMAL = 0, /* related to successful events */
LMT_OUTLIER, /* related to successful events outside of bounds */
LMT_FAIL, /* related to failed events */
LMT_COUNT,
};
typedef enum lws_metric_rpt {
LMR_PERIODIC = 0, /* we are reporting on a schedule */
LMR_OUTLIER, /* we are reporting the last outlier */
} lws_metric_rpt_kind_t;
#define METRES_GO 0
#define METRES_NOGO 1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,381 @@
/*
* libwebsockets - protocol - mqtt
*
* Copyright (C) 2010 - 2021 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.
*
* included from libwebsockets.h
*/
#ifndef _LWS_MQTT_H
#define _LWS_MQTT_H 1
struct _lws_mqtt_related;
typedef struct _lws_mqtt_related lws_mqtt_related_t;
struct lws_mqtt_str_st;
typedef struct lws_mqtt_str_st lws_mqtt_str_t;
#define MQTT_VER_3_1_1 4
#define LWS_MQTT_FINAL_PART 1
#define LWS_MQTT_MAX_AWSIOT_TOPICLEN 256
#define LWS_MQTT_MAX_TOPICLEN 65535
#define LWS_MQTT_MAX_CIDLEN 128
#define LWS_MQTT_RANDOM_CIDLEN 23 /* 3.1.3.1-5: Server MUST... between
1 and 23 chars... */
#define LWS_MQTT_SHADOW_MAX_THING_LEN 128
#define LWS_MQTT_SHADOW_MAX_SHADOW_LEN 64
#define LWS_MQTT_SHADOW_UPDATE_STR "/update"
#define LWS_MQTT_SHADOW_DELETE_STR "/delete"
#define LWS_MQTT_SHADOW_GET_STR "/get"
#define LWS_MQTT_SHADOW_RESP_ACCEPTED_STR "/accepted"
#define LWS_MQTT_SHADOW_RESP_REJECTED_STR "/rejected"
#define LWS_MQTT_SHADOW_RESP_DELTA_STR "/delta"
#define LWS_MQTT_SHADOW_RESP_DOCUMENT_STR "/documents"
#define LWS_MQTT_SHADOW_UPDATE_ACCEPTED_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_ACCEPTED_STR
#define LWS_MQTT_SHADOW_UPDATE_REJECTED_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_REJECTED_STR
#define LWS_MQTT_SHADOW_UPDATE_DELTA_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_DELTA_STR
#define LWS_MQTT_SHADOW_UPDATE_DOCUMENT_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_DOCUMENT_STR
#define LWS_MQTT_SHADOW_DELETE_ACCEPTED_STR LWS_MQTT_SHADOW_DELETE_STR LWS_MQTT_SHADOW_RESP_ACCEPTED_STR
#define LWS_MQTT_SHADOW_DELETE_REJECTED_STR LWS_MQTT_SHADOW_DELETE_STR LWS_MQTT_SHADOW_RESP_REJECTED_STR
#define LWS_MQTT_SHADOW_GET_ACCEPTED_STR LWS_MQTT_SHADOW_GET_STR LWS_MQTT_SHADOW_RESP_ACCEPTED_STR
#define LWS_MQTT_SHADOW_GET_REJECTED_STR LWS_MQTT_SHADOW_GET_STR LWS_MQTT_SHADOW_RESP_REJECTED_STR
#define LWS_MQTT_SHADOW_PREFIX_FORMAT "$aws/things/%s"
#define LWS_MQTT_SHADOW_NAMED_SHADOW_TOPIC_FORMAT LWS_MQTT_SHADOW_PREFIX_FORMAT "/shadow/name/%s%s"
#define LWS_MQTT_SHADOW_UNNAMED_SHADOW_TOPIC_FORMAT LWS_MQTT_SHADOW_PREFIX_FORMAT "/shadow%s"
#define LWS_MQTT_SHADOW_UNNAMED_TOPIC_MATCH "$aws/things/+/shadow/+"
#define LWS_MQTT_SHADOW_NAMED_TOPIC_MATCH "$aws/things/+/shadow/name/+/+"
typedef enum {
QOS0,
QOS1,
QOS2, /* not supported */
RESERVED_QOS_LEVEL,
FAILURE_QOS_LEVEL = 0x80
} lws_mqtt_qos_levels_t;
typedef union {
struct {
uint8_t retain:1;
uint8_t qos:2;
uint8_t dup:1;
uint8_t ctrl_pkt_type:4;
} flags;
uint8_t bits;
} lws_mqtt_fixed_hdr_t;
/*
* MQTT connection parameters, passed into struct
* lws_client_connect_info to establish a connection using
* lws_client_connect_via_info().
*/
typedef struct lws_mqtt_client_connect_param_s {
const char *client_id; /* Client ID */
uint16_t keep_alive; /* MQTT keep alive
interval in
seconds */
uint8_t clean_start:1; /* MQTT clean
session */
uint8_t client_id_nofree:1;
/**< do not free the client id */
uint8_t username_nofree:1;
/**< do not free the username */
uint8_t password_nofree:1;
/**< do not free the password */
struct {
const char *topic;
const char *message;
lws_mqtt_qos_levels_t qos;
uint8_t retain;
} will_param; /* MQTT LWT
parameters */
struct {
const char *topic;
const char *message;
lws_mqtt_qos_levels_t qos;
uint8_t retain;
} birth_param; /* MQTT Birth
parameters */
const char *username;
const char *password;
uint8_t aws_iot;
} lws_mqtt_client_connect_param_t;
/*
* MQTT publish parameters
*/
typedef struct lws_mqtt_publish_param_s {
char *topic; /* Topic Name */
uint16_t topic_len;
const void *payload; /* Publish Payload */
uint32_t payload_len; /* Size of the
complete payload */
uint32_t payload_pos; /* where we are in payload */
lws_mqtt_qos_levels_t qos;
/*--v-Following will be used by LWS-v--*/
uint16_t packet_id; /* Packet ID for QoS >
0 */
uint8_t dup:1; /* Retried PUBLISH,
for QoS > 0 */
uint8_t retain:1; /* Retained message */
} lws_mqtt_publish_param_t;
typedef struct topic_elem {
const char *name; /* Topic Name */
lws_mqtt_qos_levels_t qos; /* Requested QoS */
/*--v-Following will be used by LWS-v--*/
uint8_t acked;
} lws_mqtt_topic_elem_t;
/*
* MQTT publish parameters
*/
typedef struct lws_mqtt_subscribe_param_s {
uint32_t num_topics; /* Number of topics */
lws_mqtt_topic_elem_t *topic; /* Array of topic elements */
/*--v-Following will be used by LWS-v--*/
uint16_t packet_id;
} lws_mqtt_subscribe_param_t;
typedef enum {
LMQCP_RESERVED,
LMQCP_CTOS_CONNECT, /* Connection request */
LMQCP_STOC_CONNACK, /* Connection acknowledgment */
LMQCP_PUBLISH, /* Publish Message */
LMQCP_PUBACK, /* QoS 1: Publish acknowledgment */
LMQCP_PUBREC, /* QoS 2.1: Publish received */
LMQCP_PUBREL, /* QoS 2.2: Publish release */
LMQCP_PUBCOMP, /* QoS 2.3: Publish complete */
LMQCP_CTOS_SUBSCRIBE, /* Subscribe request */
LMQCP_STOC_SUBACK, /* Subscribe acknowledgment */
LMQCP_CTOS_UNSUBSCRIBE, /* Unsubscribe request */
LMQCP_STOC_UNSUBACK, /* Unsubscribe acknowledgment */
LMQCP_CTOS_PINGREQ, /* PING request */
LMQCP_STOC_PINGRESP, /* PONG response */
LMQCP_DISCONNECT, /* Disconnect notification */
LMQCP_AUTH /* Authentication exchange */
} lws_mqtt_control_packet_t;
/* flags from byte 8 of C_TO_S CONNECT */
typedef enum {
LMQCFT_USERNAME_NOFREE = (1 << 10),
LMQCFT_PASSWORD_NOFREE = (1 << 9),
LMQCFT_CLIENT_ID_NOFREE = (1 << 8),
/* only the low 8 are standardized and go out in the protocol */
LMQCFT_USERNAME = (1 << 7),
LMQCFT_PASSWORD = (1 << 6),
LMQCFT_WILL_RETAIN = (1 << 5),
LMQCFT_WILL_QOS = (1 << 3),
LMQCFT_WILL_FLAG = (1 << 2),
LMQCFT_CLEAN_START = (1 << 1),
LMQCFT_RESERVED = (1 << 0),
LMQCFT_WILL_QOS_MASK = (3 << 3),
} lws_mqtt_connect_flags_t;
/* flags for S_TO_C CONNACK */
typedef enum {
LMQCFT_SESSION_PRESENT = (1 << 0),
} lws_mqtt_connack_flags_t;
typedef enum {
LMQCP_REASON_SUCCESS = 0x00,
LMQCP_REASON_NORMAL_DISCONNECTION = 0x00,
LMQCP_REASON_GRANTED_QOS0 = 0x00,
LMQCP_REASON_GRANTED_QOS1 = 0x01,
LMQCP_REASON_GRANTED_QOS2 = 0x02,
LMQCP_REASON_DISCONNECT_WILL = 0x04,
LMQCP_REASON_NO_MATCHING_SUBSCRIBER = 0x10,
LMQCP_REASON_NO_SUBSCRIPTION_EXISTED = 0x11,
LMQCP_REASON_CONTINUE_AUTHENTICATION = 0x18,
LMQCP_REASON_RE_AUTHENTICATE = 0x19,
LMQCP_REASON_UNSPECIFIED_ERROR = 0x80,
LMQCP_REASON_MALFORMED_PACKET = 0x81,
LMQCP_REASON_PROTOCOL_ERROR = 0x82,
LMQCP_REASON_IMPLEMENTATION_SPECIFIC_ERROR = 0x83,
/* Begin - Error codes for CONNACK */
LMQCP_REASON_UNSUPPORTED_PROTOCOL = 0x84,
LMQCP_REASON_CLIENT_ID_INVALID = 0x85,
LMQCP_REASON_BAD_CREDENTIALS = 0x86,
LMQCP_REASON_NOT_AUTHORIZED = 0x87,
/* End - Error codes for CONNACK */
LMQCP_REASON_SERVER_UNAVAILABLE = 0x88,
LMQCP_REASON_SERVER_BUSY = 0x89,
LMQCP_REASON_BANNED = 0x8a,
LMQCP_REASON_SERVER_SHUTTING_DOWN = 0x8b,
LMQCP_REASON_BAD_AUTHENTICATION_METHOD = 0x8c,
LMQCP_REASON_KEEPALIVE_TIMEOUT = 0x8d,
LMQCP_REASON_SESSION_TAKEN_OVER = 0x8e,
LMQCP_REASON_TOPIC_FILTER_INVALID = 0x8f,
LMQCP_REASON_TOPIC_NAME_INVALID = 0x90,
LMQCP_REASON_PACKET_ID_IN_USE = 0x91,
LMQCP_REASON_PACKET_ID_NOT_FOUND = 0x92,
LMQCP_REASON_MAX_RX_EXCEEDED = 0x93,
LMQCP_REASON_TOPIC_ALIAS_INVALID = 0x94,
LMQCP_REASON_PACKET_TOO_LARGE = 0x95,
LMQCP_REASON_RATELIMIT = 0x96,
LMQCP_REASON_QUOTA_EXCEEDED = 0x97,
LMQCP_REASON_ADMINISTRATIVE_ACTION = 0x98,
LMQCP_REASON_PAYLOAD_FORMAT_INVALID = 0x99,
LMQCP_REASON_RETAIN_NOT_SUPPORTED = 0x9a,
LMQCP_REASON_QOS_NOT_SUPPORTED = 0x9b,
LMQCP_REASON_USE_ANOTHER_SERVER = 0x9c,
LMQCP_REASON_SERVER_MOVED = 0x9d,
LMQCP_REASON_SHARED_SUBSCRIPTIONS_NOT_SUPPORTED = 0x9e,
LMQCP_REASON_CONNECTION_RATE_EXCEEDED = 0x9f,
LMQCP_REASON_MAXIMUM_CONNECT_TIME = 0xa0,
LMQCP_REASON_SUBSCRIPTION_IDS_NOT_SUPPORTED = 0xa1,
LMQCP_REASON_WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 0xa2,
} lws_mqtt_reason_t;
typedef enum {
LMQPROP_INVALID,
LMQPROP_PAYLOAD_FORMAT_INDICATOR = 0x01,
LMQPROP_MESSAGE_EXPIRY_INTERVAL = 0x02,
LMQPROP_CONTENT_TYPE = 0x03,
LMQPROP_RESPONSE_TOPIC = 0x08,
LMQPROP_CORRELATION_DATA = 0x09,
LMQPROP_SUBSCRIPTION_IDENTIFIER = 0x0b,
LMQPROP_SESSION_EXPIRY_INTERVAL = 0x11,
LMQPROP_ASSIGNED_CLIENT_IDENTIFIER = 0x12,
LMQPROP_SERVER_KEEP_ALIVE = 0x13,
LMQPROP_AUTHENTICATION_METHOD = 0x15,
LMQPROP_AUTHENTICATION_DATA = 0x16,
LMQPROP_REQUEST_PROBLEM_INFORMATION = 0x17,
LMQPROP_WILL_DELAY_INTERVAL = 0x18,
LMQPROP_REQUEST_RESPONSE_INFORMATION = 0x19,
LMQPROP_RESPONSE_INFORMATION = 0x1a,
LMQPROP_SERVER_REFERENCE = 0x1c,
LMQPROP_REASON_STRING = 0x1f,
LMQPROP_RECEIVE_MAXIMUM = 0x21,
LMQPROP_TOPIC_ALIAS_MAXIMUM = 0x22,
LMQPROP_TOPIC_ALIAS = 0x23,
LMQPROP_MAXIMUM_QOS = 0x24,
LMQPROP_RETAIN_AVAILABLE = 0x25,
LMQPROP_USER_PROPERTY = 0x26,
LMQPROP_MAXIMUM_PACKET_SIZE = 0x27,
LMQPROP_WILDCARD_SUBSCRIPTION_AVAIL = 0x28,
LMQPROP_SUBSCRIPTION_IDENTIFIER_AVAIL = 0x29,
LMQPROP_SHARED_SUBSCRIPTION_AVAIL = 0x2a
} lws_mqtt_property;
int
lws_read_mqtt(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
/* returns 0 if bd1 and bd2 are "the same", that includes empty, else nonzero */
LWS_VISIBLE LWS_EXTERN int
lws_mqtt_bindata_cmp(const lws_mqtt_str_t *bd1, const lws_mqtt_str_t *bd2);
LWS_VISIBLE LWS_EXTERN void
lws_mqtt_str_init(lws_mqtt_str_t *s, uint8_t *buf, uint16_t lim, char nf);
LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t *
lws_mqtt_str_create(uint16_t lim);
LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t *
lws_mqtt_str_create_init(uint8_t *buf, uint16_t len, uint16_t lim);
LWS_VISIBLE LWS_EXTERN lws_mqtt_str_t *
lws_mqtt_str_create_cstr_dup(const char *buf, uint16_t lim);
LWS_VISIBLE LWS_EXTERN uint8_t *
lws_mqtt_str_next(lws_mqtt_str_t *s, uint16_t *budget);
LWS_VISIBLE LWS_EXTERN int
lws_mqtt_str_advance(lws_mqtt_str_t *s, int n);
LWS_VISIBLE LWS_EXTERN void
lws_mqtt_str_free(lws_mqtt_str_t **s);
/**
* lws_mqtt_client_send_publish() - lws_write a publish packet
*
* \param wsi: the mqtt child wsi
* \param pub: additional information on what we're publishing
* \param buf: payload to send
* \param len: length of data in buf
* \param final: flag indicating this is the last part
*
* Issues part of, or the whole of, a PUBLISH frame. The first part of the
* frame contains the header, and uses the .qos and .payload_len parts of \p pub
* since MQTT requires the frame to specify the PUBLISH message length at the
* start. The \p len paramter may be less than \p pub.payload_len, in which
* case subsequent calls with more payload are needed to complete the frame.
*
* Although the connection is stuck waiting for the remainder, in that it can't
* issue any other frames until the current one is completed, lws returns to the
* event loop normally and can continue the calls with additional payload even
* for huge frames as the data becomes available, consistent with timeout needs
* and latency to start any new frame (even, eg, related to ping / pong).
*
* If you're sending large frames, the OS will typically not allow the data to
* be sent all at once to kernel side. So you should ideally cut the payload
* up into 1 or 2- mtu sized chunks and send that.
*
* Final should be set when you're calling with the last part of the payload.
*/
LWS_VISIBLE LWS_EXTERN int
lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub,
const void *buf, uint32_t len, int final);
/**
* lws_mqtt_client_send_subcribe() - lws_write a subscribe packet
*
* \param wsi: the mqtt child wsi
* \param sub: which topic(s) we want to subscribe to
*
* For topics other child streams have not already subscribed to, send a packet
* to the server asking to subscribe to them. If all topics listed are already
* subscribed to be the shared network connection, just trigger the
* LWS_CALLBACK_MQTT_SUBSCRIBED callback as if a SUBACK had come.
*
* \p sub doesn't need to exist after the return from this function.
*/
LWS_VISIBLE LWS_EXTERN int
lws_mqtt_client_send_subcribe(struct lws *wsi, lws_mqtt_subscribe_param_t *sub);
/**
* lws_mqtt_client_send_unsubcribe() - lws_write a unsubscribe packet
*
* \param wsi: the mqtt child wsi
* \param sub: which topic(s) we want to unsubscribe from
*
* For topics other child streams are not subscribed to, send a packet
* to the server asking to unsubscribe from them. If all topics
* listed are already subscribed by other child streams on the shared
* network connection, just trigger the LWS_CALLBACK_MQTT_UNSUBSCRIBED
* callback as if a UNSUBACK had come.
*
* \p unsub doesn't need to exist after the return from this function.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_mqtt_client_send_unsubcribe(struct lws *wsi,
const lws_mqtt_subscribe_param_t *unsub);
#endif /* _LWS_MQTT_H */

View File

@ -0,0 +1,283 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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.
*/
#define LWS_WIFI_MAX_SCAN_TRACK 16
#define LWS_ETH_ALEN 6
typedef uint8_t lws_wifi_ch_t;
typedef int8_t lws_wifi_rssi_t;
struct lws_netdev_instance;
typedef enum {
LWSNDTYP_UNKNOWN,
LWSNDTYP_WIFI,
LWSNDTYP_ETH,
} lws_netdev_type_t;
/*
* Base class for netdev configuration
*/
typedef struct lws_netdev_config {
void *plat_config;
} lws_netdev_config_t;
/*
* Const Logical generic network interface ops
*/
typedef struct lws_netdev_ops {
struct lws_netdev_instance * (*create)(struct lws_context *ctx,
const struct lws_netdev_ops *ops,
const char *name, void *platinfo);
int (*configure)(struct lws_netdev_instance *nd,
lws_netdev_config_t *config);
int (*up)(struct lws_netdev_instance *nd);
int (*down)(struct lws_netdev_instance *nd);
int (*event)(struct lws_netdev_instance *nd, lws_usec_t timestamp,
void *buf, size_t len);
/**< these are SMD events coming from lws event loop thread context */
void (*destroy)(struct lws_netdev_instance **pnd);
int (*connect)(struct lws_netdev_instance *wnd, const char *ssid,
const char *passphrase, uint8_t *bssid);
void (*scan)(struct lws_netdev_instance *nd);
} lws_netdev_ops_t;
/*
* Network devices on this platform
*
* We also hold a list of all known network credentials (when they are needed
* because there is a network interface without anything to connect to) and
* the lws_settings instance they are stored in
*/
typedef struct lws_netdevs {
lws_dll2_owner_t owner;
/**< list of netdevs / lws_netdev_instance_t -based objects */
lws_dll2_owner_t owner_creds;
/**< list of known credentials */
struct lwsac *ac_creds;
/**< lwsac holding retreived credentials settings, or NULL */
lws_settings_instance_t *si;
lws_sockaddr46 sa46_dns_resolver;
uint8_t refcount_creds;
/**< when there are multiple netdevs, must refcount creds in mem */
} lws_netdevs_t;
/*
* Base class for an allocated instantiated derived object using lws_netdev_ops,
* ie, a specific ethernet device
*/
typedef struct lws_netdev_instance {
const char *name;
const lws_netdev_ops_t *ops;
void *platinfo;
lws_dll2_t list;
uint8_t mac[LWS_ETH_ALEN];
uint8_t type; /* lws_netdev_type_t */
} lws_netdev_instance_t;
enum {
LNDIW_ALG_OPEN,
LNDIW_ALG_WPA2,
LNDIW_MODE_STA = (1 << 0),
LNDIW_MODE_AP = (1 << 1),
LNDIW_UP = (1 << 7),
LNDIW_ACQ_IPv4 = (1 << 0),
LNDIW_ACQ_IPv6 = (1 << 1),
};
/*
* Group AP / Station State
*/
typedef enum {
LWSNDVWIFI_STATE_INITIAL,
/*
* We should gratuitously try whatever last worked for us, then
* if that fails, worry about the rest of the logic
*/
LWSNDVWIFI_STATE_SCAN,
/*
* Unconnected, scanning: AP known in one of the config slots ->
* configure it, start timeout + LWSNDVWIFI_STATE_STAT, if no AP
* already up in same group with lower MAC, after a random
* period start up our AP (LWSNDVWIFI_STATE_AP)
*/
LWSNDVWIFI_STATE_AP,
/* Trying to be the group AP... periodically do a scan
* LWSNDVWIFI_STATE_AP_SCAN, faster and then slower
*/
LWSNDVWIFI_STATE_AP_SCAN,
/*
* doing a scan while trying to be the group AP... if we see a
* lower MAC being the AP for the same group AP, abandon being
* an AP and join that AP as a station
*/
LWSNDVWIFI_STATE_STAT_GRP_AP,
/*
* We have decided to join another group member who is being the
* AP, as its MAC is lower than ours. This is a stable state,
* but we still do periodic scans
* LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN and will always prefer an
* AP configured in a slot.
*/
LWSNDVWIFI_STATE_STAT_GRP_AP_SCAN,
/*
* We have joined a group member who is doing the AP job... we
* want to check every now and then if a configured AP has
* appeared that we should better use instead. Otherwise stay
* in LWSNDVWIFI_STATE_STAT_GRP_AP
*/
LWSNDVWIFI_STATE_STAT,
/*
* trying to connect to another non-group AP. If we don't get an
* IP within a timeout and retries, mark it as unusable it and go back
*/
LWSNDVWIFI_STATE_STAT_HAPPY,
} lws_netdev_wifi_state_t;
/*
* Generic WIFI credentials
*/
typedef struct lws_wifi_creds {
lws_dll2_t list;
uint8_t bssid[LWS_ETH_ALEN];
char passphrase[64];
char ssid[33];
uint8_t alg;
} lws_wifi_creds_t;
/*
* Generic WIFI Network Device Instance
*/
typedef struct lws_netdev_instance_wifi {
lws_netdev_instance_t inst;
lws_dll2_owner_t scan; /* sorted scan results */
lws_sorted_usec_list_t sul_scan;
lws_wifi_creds_t *ap_cred;
const char *ap_ip;
const char *sta_ads;
char current_attempt_ssid[33];
uint8_t current_attempt_bssid[LWS_ETH_ALEN];
uint8_t flags;
uint8_t state; /* lws_netdev_wifi_state_t */
} lws_netdev_instance_wifi_t;
/*
* Logical scan results sorted list item
*/
typedef struct lws_wifi_sta {
lws_dll2_t list;
uint32_t last_seen; /* unix time */
uint32_t last_tried; /* unix time */
uint8_t bssid[LWS_ETH_ALEN];
char *ssid; /* points to overallocation */
uint8_t ssid_len;
lws_wifi_ch_t ch;
lws_wifi_rssi_t rssi[8];
int16_t rssi_avg;
uint8_t authmode;
uint8_t rssi_count;
uint8_t rssi_next;
/* ssid overallocated afterwards */
} lws_wifi_sta_t;
#define rssi_averaged(_x) (_x->rssi_count ? \
((int)_x->rssi_avg / (int)_x->rssi_count) : \
-200)
LWS_VISIBLE LWS_EXTERN lws_netdevs_t *
lws_netdevs_from_ctx(struct lws_context *ctx);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_credentials_settings_set(lws_netdevs_t *nds);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_credentials_settings_get(lws_netdevs_t *nds);
LWS_VISIBLE LWS_EXTERN struct lws_netdev_instance *
lws_netdev_wifi_create_plat(struct lws_context *ctx,
const lws_netdev_ops_t *ops, const char *name,
void *platinfo);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_wifi_configure_plat(struct lws_netdev_instance *nd,
lws_netdev_config_t *config);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_wifi_event_plat(struct lws_netdev_instance *nd, lws_usec_t timestamp,
void *buf, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_wifi_up_plat(struct lws_netdev_instance *nd);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_wifi_down_plat(struct lws_netdev_instance *nd);
LWS_VISIBLE LWS_EXTERN void
lws_netdev_wifi_destroy_plat(struct lws_netdev_instance **pnd);
LWS_VISIBLE LWS_EXTERN void
lws_netdev_wifi_scan_plat(lws_netdev_instance_t *nd);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_wifi_connect_plat(lws_netdev_instance_t *wnd, const char *ssid,
const char *passphrase, uint8_t *bssid);
LWS_VISIBLE LWS_EXTERN lws_netdev_instance_t *
lws_netdev_find(lws_netdevs_t *netdevs, const char *ifname);
#define lws_netdev_wifi_plat_ops \
.create = lws_netdev_wifi_create_plat, \
.configure = lws_netdev_wifi_configure_plat, \
.event = lws_netdev_wifi_event_plat, \
.up = lws_netdev_wifi_up_plat, \
.down = lws_netdev_wifi_down_plat, \
.connect = lws_netdev_wifi_connect_plat, \
.scan = lws_netdev_wifi_scan_plat, \
.destroy = lws_netdev_wifi_destroy_plat
/*
* This is for plat / OS level init that is necessary to be able to use
* networking or wifi at all, without mentioning any specific device
*/
LWS_VISIBLE LWS_EXTERN int
lws_netdev_plat_init(void);
LWS_VISIBLE LWS_EXTERN int
lws_netdev_plat_wifi_init(void);

View File

@ -0,0 +1,261 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2023 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 net Network related helper APIs
* ##Network related helper APIs
*
* These wrap miscellaneous useful network-related functions
*/
///@{
#if defined(LWS_ESP_PLATFORM)
#include <lwip/sockets.h>
#endif
/* cope with large amounts of route information */
typedef uint16_t lws_route_uidx_t;
typedef struct lws_dns_score {
uint8_t precedence;
uint8_t label;
} lws_dns_score_t;
/*
* This represents an entry in the system routing table
*/
typedef struct lws_route {
lws_dll2_t list;
lws_sockaddr46 src;
lws_sockaddr46 dest;
lws_sockaddr46 gateway;
struct lws_route *source; /* when used as lws_dns_sort_t */
lws_dns_score_t score; /* when used as lws_dns_sort_t */
int if_idx;
int priority;
int ifa_flags; /* if source_ads */
lws_route_uidx_t uidx; /* unique index for this route */
uint8_t proto;
uint8_t dest_len;
uint8_t src_len;
uint8_t scope; /* if source_ads */
uint8_t af; /* if source_ads */
uint8_t source_ads:1;
} lws_route_t;
/*
* We reuse the route object as the dns sort granule, so there's only one
* struct needs to know all the gnarly ipv6 details
*/
typedef lws_route_t lws_dns_sort_t;
/**
* lws_canonical_hostname() - returns this host's hostname
*
* This is typically used by client code to fill in the host parameter
* when making a client connection. You can only call it after the context
* has been created.
*
* \param context: Websocket context
*/
LWS_VISIBLE LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT
lws_canonical_hostname(struct lws_context *context);
/**
* lws_get_peer_addresses() - Get client address information
* \param wsi: Local struct lws associated with
* \param fd: Connection socket descriptor
* \param name: Buffer to take client address name
* \param name_len: Length of client address name buffer
* \param rip: Buffer to take client address IP dotted quad
* \param rip_len: Length of client address IP buffer
*
* This function fills in name and rip with the name and IP of
* the client connected with socket descriptor fd. Names may be
* truncated if there is not enough room. If either cannot be
* determined, they will be returned as valid zero-length strings.
*/
LWS_VISIBLE LWS_EXTERN void
lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
int name_len, char *rip, int rip_len);
/**
* lws_get_peer_simple() - Get client address information without RDNS
*
* \param wsi: Local struct lws associated with
* \param name: Buffer to take client address name
* \param namelen: Length of client address name buffer
*
* This provides a 123.123.123.123 type IP address in name from the
* peer that has connected to wsi
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_get_peer_simple(struct lws *wsi, char *name, size_t namelen);
LWS_VISIBLE LWS_EXTERN const char *
lws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen);
#define LWS_ITOSA_USABLE 0
#define LWS_ITOSA_NOT_EXIST -1
#define LWS_ITOSA_NOT_USABLE -2
#define LWS_ITOSA_BUSY -3 /* only returned by lws_socket_bind() on
EADDRINUSE */
#if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
/**
* lws_interface_to_sa() - Convert interface name or IP to sockaddr struct
*
* \param ipv6: Allow IPV6 addresses
* \param ifname: Interface name or IP
* \param addr: struct sockaddr_in * to be written
* \param addrlen: Length of addr
*
* This converts a textual network interface name to a sockaddr usable by
* other network functions.
*
* If the network interface doesn't exist, it will return LWS_ITOSA_NOT_EXIST.
*
* If the network interface is not usable, eg ethernet cable is removed, it
* may logically exist but not have any IP address. As such it will return
* LWS_ITOSA_NOT_USABLE.
*
* If the network interface exists and is usable, it will return
* LWS_ITOSA_USABLE.
*/
LWS_VISIBLE LWS_EXTERN int
lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
size_t addrlen);
#endif
/**
* lws_sa46_compare_ads() - checks if two sa46 have the same address
*
* \param sa46a: first
* \param sa46b: second
*
* Returns 0 if the address family is INET or INET6 and the address is the same,
* or if the AF is the same but not INET or INET6, otherwise nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b);
/**
* lws_sa46_on_net() - checks if an sa46 is on the subnet represented by another
*
* \param sa46a: first
* \param sa46_net: network
* \param net_len: length of network non-mask
*
* Returns 0 if sa46a belongs on network sa46_net/net_len
*
* If there is an ipv4 / v6 mismatch between the ip and the net, the ipv4
* address is promoted to ::ffff:x.x.x.x before the comparison.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
int net_len);
/*
* lws_parse_numeric_address() - converts numeric ipv4 or ipv6 to byte address
*
* \param ads: the numeric ipv4 or ipv6 address string
* \param result: result array
* \param max_len: max length of result array
*
* Converts a 1.2.3.4 or 2001:abcd:123:: or ::ffff:1.2.3.4 formatted numeric
* address into an array of network ordered byte address elements.
*
* Returns < 0 on error, else length of result set, either 4 or 16 for ipv4 /
* ipv6.
*/
LWS_VISIBLE LWS_EXTERN int
lws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len);
/*
* lws_sa46_parse_numeric_address() - converts numeric ipv4 or ipv6 to sa46
*
* \param ads: the numeric ipv4 or ipv6 address string
* \param sa46: pointer to sa46 to set
*
* Converts a 1.2.3.4 or 2001:abcd:123:: or ::ffff:1.2.3.4 formatted numeric
* address into an sa46, a union of sockaddr_in or sockaddr_in6 depending on
* what kind of address was found. sa46->sa4.sin_fmaily will be AF_INET if
* ipv4, or AF_INET6 if ipv6.
*
* Returns 0 if the sa46 was set, else < 0 on error.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46);
/**
* lws_write_numeric_address() - convert network byte order ads to text
*
* \param ads: network byte order address array
* \param size: number of bytes valid in ads
* \param buf: result buffer to take text format
* \param len: max size of text buffer
*
* Converts an array of network-ordered byte address elements to a textual
* representation of the numeric address, like "1.2.3.4" or "::1". Returns the
* number of chars written into buf, else < 0. ipv6 only supported with
* LWS_IPV6=1 at cmake.
*/
LWS_VISIBLE LWS_EXTERN int
lws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len);
/**
* lws_sa46_write_numeric_address() - convert sa46 ads to textual numeric ads
*
* \param sa46: the sa46 whose address to show
* \param buf: result buffer to take text format
* \param len: max size of text buffer
*
* Converts the ipv4 or ipv6 address in an lws_sockaddr46 to a textual
* representation of the numeric address, like "1.2.3.4" or "::1". Returns the
* number of chars written into buf, else < 0. ipv6 only supported with
* LWS_IPV6=1 at cmake.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len);
/**
* lws_parse_mac() - convert XX:XX:XX:XX:XX:XX to 6-byte MAC address
*
* \param ads: mac address as XX:XX:XX:XX:XX:XX string
* \param result_6_bytes: result buffer to take 6 bytes
*
* Converts a string representation of a 6-byte hex mac address to a 6-byte
* array.
*/
LWS_VISIBLE LWS_EXTERN int
lws_parse_mac(const char *ads, uint8_t *result_6_bytes);
///@}

View File

@ -0,0 +1,77 @@
/*
* 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.
*/
#ifndef __LWS_OPTEE_H
#define __LWS_OPTEE_H
/* 128-bit IP6 address */
struct in6_addr {
union {
uint8_t u6_addr8[16];
uint16_t u6_addr16[8];
uint32_t u6_addr32[4];
};
};
#define _SS_MAXSIZE 128U
#define _SS_ALIGNSIZE (sizeof(int64_t))
#define _SS_PAD1SIZE (_SS_ALIGNSIZE - \
sizeof(sa_family_t))
#define _SS_PAD2SIZE (_SS_MAXSIZE - \
sizeof(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE)
struct sockaddr_storage {
sa_family_t ss_family; /* address family */
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align; /* force desired struct alignment */
char __ss_pad2[_SS_PAD2SIZE];
};
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr {
sa_family_t sa_family; /* address family */
uint8_t sa_data[__SOCK_SIZE__ /* address value */
- sizeof(sa_family_t)];
};
/* 16 bytes */
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
uint8_t sin_zero[__SOCK_SIZE__ /* padding until 16 bytes */
- sizeof(sa_family_t)
- sizeof(in_port_t)
- sizeof(struct in_addr)];
};
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IP6 flow information */
struct in6_addr sin6_addr; /* IP6 address */
uint32_t sin6_scope_id; /* scope zone index */
};
#endif /* __LWS_OPTEE_H */

View File

@ -0,0 +1,122 @@
/*
* lws OTA updates
*
* Copyright (C) 2019 - 2022 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.
*
* This is the platform interface that lws_ota uses to flash new firmware.
* The platform implementation for these ops is set via lws_system and consists
* of user code.
*
* All the update-related calls have async interfaces with a callback and opaque
* callback context that is called on completion. This allows us to, eg,
* download the next buffer while flashing the previous one.
*
* If the platform implementation is actually synchronous, then just call the
* callback before returning.
*
* If it is async, because eg, erase is slow, in the platform ota op
* implementation spawn a thread to do the platform operation, return
* immediately with LWSOTARET_ONGOING, and call the callback from the spawned
* thread context with the real return before terminating the thread.
*/
typedef void * lws_ota_process_t;
typedef enum {
LWSOTARET_OK,
LWSOTARET_ONGOING, /* result not ready to read yet */
LWSOTARET_REJECTED,
LWSOTARET_NOSLOT,
LWSOTARET_UPDATE_AVAILABLE,
LWSOTARET_PROGRESS,
LWSOTARET_FAILED,
LWSOTARET_COMPLETED
} lws_ota_ret_t;
typedef enum {
LWS_OTA_ASYNC_START = 1,
LWS_OTA_ASYNC_WRITE,
LWS_OTA_ASYNC_ABORT,
LWS_OTA_ASYNC_FINALIZE
} lws_ota_async_t;
struct lws_ota;
typedef void (*lws_ota_cb_t)(void *ctx, lws_ota_ret_t r);
typedef struct {
/* asynchronous (completions via lws_cancel_service) */
int (*ota_start)(struct lws_ota *g);
/**< Creates the ota task and queues LWS_OTA_ASYNC_START on it. */
void (*ota_queue)(struct lws_ota *g, lws_ota_async_t a);
/**< Queue next command to OTA task (args are in g) */
/* synchronous */
int (*ota_report_current)(struct lws_ota *g, int bad);
/**< Report information to the platform code about how we feel about the
* current boot... if we can check the OTA then we report it seems in
* good shape (bad = 0), if we can identify it's brain-damaged then
* (bad = 1). What action the platform takes about these reports is up
* to the platform code */
int (*ota_progress)(lws_ota_ret_t state, int percent);
/**< Gets called so the platform can represent OTA progress, give
* platform a chance to choose what to do about an available update */
int (*ota_get_last_fw_unixtime)(uint64_t *fw_unixtime);
/**< tries to recover the newest firmware unixtime that had been
* OTA'd into fw_unixtime, updates from same or earlier unixtime are
* ignored for update purposes. */
int ota_periodic_check_secs;
/**< Check after this many seconds for a new update */
} lws_ota_ops_t;
/**
* lws_ota_variant_name() - returns the build variant name
*
* Returns a string that uniquely identifies the kind of firmware build this
* device is running.
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_ota_variant_name(void);
LWS_VISIBLE LWS_EXTERN int
lws_plat_ota_start(struct lws_ota *g);
#define LWSOTAFIN_OK 0
#define LWSOTAFIN_BAD 1
LWS_VISIBLE LWS_EXTERN void
lws_plat_ota_queue(struct lws_ota *g, lws_ota_async_t a);
LWS_VISIBLE LWS_EXTERN int
lws_plat_ota_report_current(struct lws_ota *g, int bad);
LWS_VISIBLE LWS_EXTERN int
lws_plat_ota_get_last_fw_unixtime(uint64_t *fw_unixtime);

View File

@ -0,0 +1,383 @@
/*
* 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 Protocols-and-Plugins Protocols and Plugins
* \ingroup lwsapi
*
* ##Protocol and protocol plugin -related apis
*
* Protocols bind ws protocol names to a custom callback specific to that
* protocol implementaion.
*
* A list of protocols can be passed in at context creation time, but it is
* also legal to leave that NULL and add the protocols and their callback code
* using plugins.
*
* Plugins are much preferable compared to cut and pasting code into an
* application each time, since they can be used standalone.
*/
///@{
/** struct lws_protocols - List of protocols and handlers client or server
* supports. */
struct lws_protocols {
const char *name;
/**< Protocol name that must match the one given in the client
* Javascript new WebSocket(url, 'protocol') name. */
lws_callback_function *callback;
/**< The service callback used for this protocol. It allows the
* service action for an entire protocol to be encapsulated in
* the protocol-specific callback */
size_t per_session_data_size;
/**< Each new connection using this protocol gets
* this much memory allocated on connection establishment and
* freed on connection takedown. A pointer to this per-connection
* allocation is passed into the callback in the 'user' parameter */
size_t rx_buffer_size;
/**< lws allocates this much space for rx data and informs callback
* when something came. Due to rx flow control, the callback may not
* be able to consume it all without having to return to the event
* loop. That is supported in lws.
*
* If .tx_packet_size is 0, this also controls how much may be sent at
* once for backwards compatibility.
*/
unsigned int id;
/**< ignored by lws, but useful to contain user information bound
* to the selected protocol. For example if this protocol was
* called "myprotocol-v2", you might set id to 2, and the user
* code that acts differently according to the version can do so by
* switch (wsi->a.protocol->id), user code might use some bits as
* capability flags based on selected protocol version, etc. */
void *user; /**< ignored by lws, but user code can pass a pointer
here it can later access from the protocol callback */
size_t tx_packet_size;
/**< 0 indicates restrict send() size to .rx_buffer_size for backwards-
* compatibility.
* If greater than zero, a single send() is restricted to this amount
* and any remainder is buffered by lws and sent afterwards also in
* these size chunks. Since that is expensive, it's preferable
* to restrict one fragment you are trying to send to match this
* size.
*/
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility */
};
#define LWS_PROTOCOL_LIST_TERM { NULL, NULL, 0, 0, 0, NULL, 0 }
/**
* lws_vhost_name_to_protocol() - get vhost's protocol object from its name
*
* \param vh: vhost to search
* \param name: protocol name
*
* Returns NULL or a pointer to the vhost's protocol of the requested name
*/
LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name);
/**
* lws_get_protocol() - Returns a protocol pointer from a websocket
* connection.
* \param wsi: pointer to struct websocket you want to know the protocol of
*
*
* Some apis can act on all live connections of a given protocol,
* this is how you can get a pointer to the active protocol if needed.
*/
LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
lws_get_protocol(struct lws *wsi);
/** lws_protocol_get() - deprecated: use lws_get_protocol */
LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
lws_protocol_get(struct lws *wsi) LWS_WARN_DEPRECATED;
/**
* lws_protocol_vh_priv_zalloc() - Allocate and zero down a protocol's per-vhost
* storage
* \param vhost: vhost the instance is related to
* \param prot: protocol the instance is related to
* \param size: bytes to allocate
*
* Protocols often find it useful to allocate a per-vhost struct, this is a
* helper to be called in the per-vhost init LWS_CALLBACK_PROTOCOL_INIT
*/
LWS_VISIBLE LWS_EXTERN void *
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
const struct lws_protocols *prot, int size);
/**
* lws_protocol_vh_priv_get() - retreive a protocol's per-vhost storage
*
* \param vhost: vhost the instance is related to
* \param prot: protocol the instance is related to
*
* Recover a pointer to the allocated per-vhost storage for the protocol created
* by lws_protocol_vh_priv_zalloc() earlier
*/
LWS_VISIBLE LWS_EXTERN void *
lws_protocol_vh_priv_get(struct lws_vhost *vhost,
const struct lws_protocols *prot);
/**
* lws_vhd_find_by_pvo() - find a partner vhd
*
* \param cx: the lws_context
* \param protname: the name of the lws_protocol the vhd belongs to
* \param pvo_name: the name of a pvo that must exist bound to the vhd
* \param pvo_value: the required value of the named pvo
*
* This allows architectures with multiple protocols bound together to
* cleanly discover partner protocol instances even on completely
* different vhosts. For example, a proxy may consist of two protocols
* listening on different vhosts, and there may be multiple instances
* of the proxy in the same process. It's desirable that each side of
* the proxy is an independent protocol that can be freely bound to any
* vhost, eg, allowing Unix Domain to tls / h2 proxying, or each side
* bound to different network interfaces for localhost-only visibility
* on one side, using existing vhost management.
*
* That leaves the problem that the two sides have to find each other
* and bind at runtime. This api allows each side to specify the
* protocol name, and a common pvo name and pvo value that indicates
* the two sides belong together, and search through all the instantiated
* vhost-protocols looking for a match. If found, the private allocation
* (aka "vhd" of the match is returned). NULL is returned on no match.
*
* Since this can only succeed when called by the last of the two
* protocols to be instantiated, both sides should call it and handle
* NULL gracefully, since it may mean that they were first and their
* partner vhsot-protocol has not been instantiated yet.
*/
LWS_VISIBLE LWS_EXTERN void *
lws_vhd_find_by_pvo(struct lws_context *cx, const char *protname,
const char *pvo_name, const char *pvo_value);
/**
* lws_adjust_protocol_psds - change a vhost protocol's per session data size
*
* \param wsi: a connection with the protocol to change
* \param new_size: the new size of the per session data size for the protocol
*
* Returns user_space for the wsi, after allocating
*
* This should not be used except to initalize a vhost protocol's per session
* data size one time, before any connections are accepted.
*
* Sometimes the protocol wraps another protocol and needs to discover and set
* its per session data size at runtime.
*/
LWS_VISIBLE LWS_EXTERN void *
lws_adjust_protocol_psds(struct lws *wsi, size_t new_size);
/**
* lws_finalize_startup() - drop initial process privileges
*
* \param context: lws context
*
* This is called after the end of the vhost protocol initializations, but
* you may choose to call it earlier
*/
LWS_VISIBLE LWS_EXTERN int
lws_finalize_startup(struct lws_context *context);
/**
* lws_pvo_search() - helper to find a named pvo in a linked-list
*
* \param pvo: the first pvo in the linked-list
* \param name: the name of the pvo to return if found
*
* Returns NULL, or a pointer to the name pvo in the linked-list
*/
LWS_VISIBLE LWS_EXTERN const struct lws_protocol_vhost_options *
lws_pvo_search(const struct lws_protocol_vhost_options *pvo, const char *name);
/**
* lws_pvo_get_str() - retreive a string pvo value
*
* \param in: the first pvo in the linked-list
* \param name: the name of the pvo to return if found
* \param result: pointer to a const char * to get the result if any
*
* Returns 0 if found and *result set, or nonzero if not found
*/
LWS_VISIBLE LWS_EXTERN int
lws_pvo_get_str(void *in, const char *name, const char **result);
LWS_VISIBLE LWS_EXTERN int
lws_protocol_init(struct lws_context *context);
#define LWS_PLUGIN_API_MAGIC 191
/*
* Abstract plugin header for any kind of plugin class, always at top of
* actual class plugin export type.
*
* The export type object must be exported with the same name as the plugin
* file, eg, libmyplugin.so must export a const one of these as the symbol
* "myplugin".
*
* That is the only expected export from the plugin.
*/
typedef struct lws_plugin_header {
const char *name;
const char *_class;
const char *lws_build_hash; /* set to LWS_BUILD_HASH */
unsigned int api_magic;
/* set to LWS_PLUGIN_API_MAGIC at plugin build time */
/* plugin-class specific superclass data follows */
} lws_plugin_header_t;
/*
* "lws_protocol_plugin" class export, for lws_protocol implementations done
* as plugins
*/
typedef struct lws_plugin_protocol {
lws_plugin_header_t hdr;
const struct lws_protocols *protocols; /**< array of supported protocols provided by plugin */
const struct lws_extension *extensions; /**< array of extensions provided by plugin */
int count_protocols; /**< how many protocols */
int count_extensions; /**< how many extensions */
} lws_plugin_protocol_t;
/*
* This is the dynamic, runtime created part of the plugin instantiation.
* These are kept in a linked-list and destroyed with the context.
*/
struct lws_plugin {
struct lws_plugin *list; /**< linked list */
const lws_plugin_header_t *hdr;
union {
#if defined(LWS_WITH_LIBUV) && defined(UV_ERRNO_MAP)
#if (UV_VERSION_MAJOR > 0)
uv_lib_t lib; /**< shared library pointer */
#endif
#endif
void *l; /**< */
} u;
};
/*
* Event lib library plugin type (when LWS_WITH_EVLIB_PLUGINS)
* Public so new event libs can equally be supported outside lws itself
*/
typedef struct lws_plugin_evlib {
lws_plugin_header_t hdr;
const struct lws_event_loop_ops *ops;
} lws_plugin_evlib_t;
typedef int (*each_plugin_cb_t)(struct lws_plugin *p, void *user);
/**
* lws_plugins_init() - dynamically load plugins of matching class from dirs
*
* \param pplugin: pointer to linked-list for this kind of plugin
* \param d: array of directory paths to look in
* \param _class: class string that plugin must declare
* \param filter: NULL, or a string that must appear after the third char of the plugin filename
* \param each: NULL, or each_plugin_cb_t callback for each instantiated plugin
* \param each_user: pointer passed to each callback
*
* Allows you to instantiate a class of plugins to a specified linked-list.
* The each callback allows you to init each inistantiated callback and pass a
* pointer each_user to it.
*
* To take down the plugins, pass a pointer to the linked-list head to
* lws_plugins_destroy.
*
* This is used for lws protocol plugins but you can define your own plugin
* class name like "mypluginclass", declare it in your plugin headers, and load
* your own plugins to your own list using this api the same way.
*/
LWS_VISIBLE LWS_EXTERN int
lws_plugins_init(struct lws_plugin **pplugin, const char * const *d,
const char *_class, const char *filter,
each_plugin_cb_t each, void *each_user);
/**
* lws_plugins_destroy() - dynamically unload list of plugins
*
* \param pplugin: pointer to linked-list for this kind of plugin
* \param each: NULL, or each_plugin_cb_t callback for each instantiated plugin
* \param each_user: pointer passed to each callback
*
* Allows you to destroy a class of plugins from a specified linked-list
* created by a call to lws_plugins_init().
*
* The each callback allows you to deinit each inistantiated callback and pass a
* pointer each_user to it, just before its footprint is destroyed.
*/
LWS_VISIBLE LWS_EXTERN int
lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each,
void *each_user);
#if defined(LWS_WITH_PLUGINS_BUILTIN)
/* provide exports for builtin plugin protocols */
extern const struct lws_protocols post_demo_protocols[1];
extern const struct lws_protocols lws_raw_proxy_protocols[1];
extern const struct lws_protocols lws_status_protocols[1];
extern const struct lws_protocols lws_mirror_protocols[1];
extern const struct lws_protocols lws_ssh_base_protocols[2];
extern const struct lws_protocols post_demo_protocols[1];
extern const struct lws_protocols dumb_increment_protocols[1];
extern const struct lws_protocols deaddrop_protocols[1];
extern const struct lws_protocols lws_raw_test_protocols[1];
extern const struct lws_protocols lws_sshd_demo_protocols[1];
extern const struct lws_protocols lws_acme_client_protocols[1];
extern const struct lws_protocols client_loopback_test_protocols[1];
extern const struct lws_protocols fulltext_demo_protocols[1];
extern const struct lws_protocols lws_openmetrics_export_protocols[
#if defined(LWS_WITH_SERVER) && defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS)
4
#else
#if defined(LWS_WITH_SERVER)
3
#else
1
#endif
#endif
];
#define LWSOMPROIDX_DIRECT_HTTP_SERVER 0
#define LWSOMPROIDX_PROX_HTTP_SERVER 1
#define LWSOMPROIDX_PROX_WS_SERVER 2
#define LWSOMPROIDX_PROX_WS_CLIENT 3
#endif
///@}

View File

@ -0,0 +1,105 @@
/*
* 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 pur Sanitize / purify SQL and JSON helpers
*
* ##Sanitize / purify SQL and JSON helpers
*
* APIs for escaping untrusted JSON and SQL safely before use
*/
//@{
/**
* lws_sql_purify() - like strncpy but with escaping for sql quotes
*
* \param escaped: output buffer
* \param string: input buffer ('/0' terminated)
* \param len: output buffer max length
*
* Because escaping expands the output string, it's not
* possible to do it in-place, ie, with escaped == string
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_sql_purify(char *escaped, const char *string, size_t len);
/**
* lws_sql_purify_len() - return length of purified version of input string
*
* \param string: input buffer ('/0' terminated)
*
* Calculates any character escaping without writing it anywhere and returns the
* calculated length of the purified string.
*/
int
lws_sql_purify_len(const char *p);
/**
* lws_json_purify() - like strncpy but with escaping for json chars
*
* \param escaped: output buffer
* \param string: input buffer ('/0' terminated)
* \param len: output buffer max length
* \param in_used: number of bytes of string we could escape in len
*
* Because escaping expands the output string, it's not
* possible to do it in-place, ie, with escaped == string
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_json_purify(char *escaped, const char *string, int len, int *in_used);
/**
* lws_json_purify_len() - find out the escaped length of a string
*
* \param string: input buffer ('/0' terminated)
*
* JSON may have to expand escapes by up to 6x the original depending on what
* it is. This doesn't actually do the escaping but goes through the motions
* and computes the length of the escaped string.
*/
LWS_VISIBLE LWS_EXTERN int
lws_json_purify_len(const char *string);
/**
* lws_filename_purify_inplace() - replace scary filename chars with underscore
*
* \param filename: filename to be purified
*
* Replace scary characters in the filename (it should not be a path)
* with underscore, so it's safe to use.
*/
LWS_VISIBLE LWS_EXTERN void
lws_filename_purify_inplace(char *filename);
LWS_VISIBLE LWS_EXTERN int
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_plat_write_file(const char *filename, void *buf, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_plat_read_file(const char *filename, void *buf, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_plat_recommended_rsa_bits(void);
///@}

View File

@ -0,0 +1,67 @@
/*
* Generic PWM controller ops
*
* Copyright (C) 2019 - 2020 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.
*/
typedef struct lws_pwm_map {
_lws_plat_gpio_t gpio;
uint8_t index;
uint8_t active_level;
} lws_pwm_map_t;
typedef struct lws_pwm_ops {
int (*init)(const struct lws_pwm_ops *lo);
void (*intensity)(const struct lws_pwm_ops *lo, _lws_plat_gpio_t gpio,
lws_led_intensity_t inten);
const lws_pwm_map_t *pwm_map;
uint8_t count_pwm_map;
} lws_pwm_ops_t;
LWS_VISIBLE LWS_EXTERN int
lws_pwm_plat_init(const struct lws_pwm_ops *lo);
LWS_VISIBLE LWS_EXTERN void
lws_pwm_plat_intensity(const struct lws_pwm_ops *lo, _lws_plat_gpio_t gpio,
lws_led_intensity_t inten);
#define lws_pwm_plat_ops \
.init = lws_pwm_plat_init, \
.intensity = lws_pwm_plat_intensity
/*
* May be useful for making your own transitions or sequences
*/
LWS_VISIBLE LWS_EXTERN lws_led_intensity_t
lws_led_func_linear(lws_led_seq_phase_t n);
LWS_VISIBLE LWS_EXTERN lws_led_intensity_t
lws_led_func_sine(lws_led_seq_phase_t n);
/* canned sequences that can work out of the box */
extern const lws_led_sequence_def_t lws_pwmseq_sine_endless_slow,
lws_pwmseq_sine_endless_fast,
lws_pwmseq_linear_wipe,
lws_pwmseq_sine_up, lws_pwmseq_sine_down,
lws_pwmseq_static_on,
lws_pwmseq_static_half,
lws_pwmseq_static_off;

View File

@ -0,0 +1,95 @@
/*
* 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.
*/
typedef struct lws_retry_bo {
const uint32_t *retry_ms_table; /* base delay in ms */
uint16_t retry_ms_table_count; /* entries in table */
uint16_t conceal_count; /* max retries to conceal */
uint16_t secs_since_valid_ping; /* idle before PING issued */
uint16_t secs_since_valid_hangup; /* idle before hangup conn */
uint8_t jitter_percent; /* % additional random jitter */
} lws_retry_bo_t;
#define LWS_RETRY_CONCEAL_ALWAYS (0xffff)
/**
* lws_retry_get_delay_ms() - get next delay from backoff table
*
* \param lws_context: the lws context (used for getting random)
* \param retry: the retry backoff table we are using, or NULL for default
* \param ctry: pointer to the try counter
* \param conceal: pointer to flag set to nonzero if the try should be concealed
* in terms of creating an error
*
* Increments *\p try and retruns the number of ms that should elapse before the
* next connection retry, according to the backoff table \p retry. *\p conceal is
* set if the number of tries is less than the backoff table conceal_count, or
* is zero if it exceeded it. This lets you conceal a certain number of retries
* before alerting the caller there is a problem.
*
* If \p retry is NULL, a default of 3s + (0..300ms jitter) is used. If it's
* non-NULL but jitter_percent is 0, the default of 30% jitter is retained.
*/
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 just 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);
/**
* lws_retry_sul_schedule_retry_wsi() - retry sul schedule helper using wsi
*
* \param wsi: the wsi to set the hrtimer sul on to the next retry interval
* \param sul: pointer to the sul to schedule
* \param cb: the callback for when the sul schedule time arrives
* \param ctry: pointer to the try counter
*
* Helper that uses context, tid and retry policy from a wsi to call
* lws_retry_sul_schedule.
*
* Since a udp connection can have many writes in flight, the retry count and
* the sul used to track each thing that wants to be written have to be handled
* individually, not the wsi. But the retry policy and the other things can
* be filled in from the wsi conveniently.
*/
LWS_VISIBLE LWS_EXTERN int
lws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
sul_cb_t cb, uint16_t *ctry);

View File

@ -0,0 +1,306 @@
/*
* 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 lws_ring LWS Ringbuffer APIs
* ##lws_ring: generic ringbuffer struct
*
* Provides an abstract ringbuffer api supporting one head and one or an
* unlimited number of tails.
*
* All of the members are opaque and manipulated by lws_ring_...() apis.
*
* The lws_ring and its buffer is allocated at runtime on the heap, using
*
* - lws_ring_create()
* - lws_ring_destroy()
*
* It may contain any type, the size of the "element" stored in the ring
* buffer and the number of elements is given at creation time.
*
* When you create the ringbuffer, you can optionally provide an element
* destroy callback that frees any allocations inside the element. This is then
* automatically called for elements with no tail behind them, ie, elements
* which don't have any pending consumer are auto-freed.
*
* Whole elements may be inserted into the ringbuffer and removed from it, using
*
* - lws_ring_insert()
* - lws_ring_consume()
*
* You can find out how many whole elements are free or waiting using
*
* - lws_ring_get_count_free_elements()
* - lws_ring_get_count_waiting_elements()
*
* In addition there are special purpose optional byte-centric apis
*
* - lws_ring_next_linear_insert_range()
* - lws_ring_bump_head()
*
* which let you, eg, read() directly into the ringbuffer without needing
* an intermediate bounce buffer.
*
* The accessors understand that the ring wraps, and optimizes insertion and
* consumption into one or two memcpy()s depending on if the head or tail
* wraps.
*
* lws_ring only supports a single head, but optionally multiple tails with
* an API to inform it when the "oldest" tail has moved on. You can give
* NULL where-ever an api asks for a tail pointer, and it will use an internal
* single tail pointer for convenience.
*
* The "oldest tail", which is the only tail if you give it NULL instead of
* some other tail, is used to track which elements in the ringbuffer are
* still unread by anyone.
*
* - lws_ring_update_oldest_tail()
*/
///@{
struct lws_ring;
/**
* lws_ring_create(): create a new ringbuffer
*
* \param element_len: the size in bytes of one element in the ringbuffer
* \param count: the number of elements the ringbuffer can contain
* \param destroy_element: NULL, or callback to be called for each element
* that is removed from the ringbuffer due to the
* oldest tail moving beyond it
*
* Creates the ringbuffer and allocates the storage. Returns the new
* lws_ring *, or NULL if the allocation failed.
*
* If non-NULL, destroy_element will get called back for every element that is
* retired from the ringbuffer after the oldest tail has gone past it, and for
* any element still left in the ringbuffer when it is destroyed. It replaces
* all other element destruction code in your user code.
*/
LWS_VISIBLE LWS_EXTERN struct lws_ring *
lws_ring_create(size_t element_len, size_t count,
void (*destroy_element)(void *element));
/**
* lws_ring_destroy(): destroy a previously created ringbuffer
*
* \param ring: the struct lws_ring to destroy
*
* Destroys the ringbuffer allocation and the struct lws_ring itself.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ring_destroy(struct lws_ring *ring);
/**
* lws_ring_get_count_free_elements(): return how many elements can fit
* in the free space
*
* \param ring: the struct lws_ring to report on
*
* Returns how much room is left in the ringbuffer for whole element insertion.
*/
LWS_VISIBLE LWS_EXTERN size_t
lws_ring_get_count_free_elements(struct lws_ring *ring);
/**
* lws_ring_get_count_waiting_elements(): return how many elements can be consumed
*
* \param ring: the struct lws_ring to report on
* \param tail: a pointer to the tail struct to use, or NULL for single tail
*
* Returns how many elements are waiting to be consumed from the perspective
* of the tail pointer given.
*/
LWS_VISIBLE LWS_EXTERN size_t
lws_ring_get_count_waiting_elements(struct lws_ring *ring, uint32_t *tail);
/**
* lws_ring_insert(): attempt to insert up to max_count elements from src
*
* \param ring: the struct lws_ring to report on
* \param src: the array of elements to be inserted
* \param max_count: the number of available elements at src
*
* Attempts to insert as many of the elements at src as possible, up to the
* maximum max_count. Returns the number of elements actually inserted.
*/
LWS_VISIBLE LWS_EXTERN size_t
lws_ring_insert(struct lws_ring *ring, const void *src, size_t max_count);
/**
* lws_ring_consume(): attempt to copy out and remove up to max_count elements
* to src
*
* \param ring: the struct lws_ring to report on
* \param tail: a pointer to the tail struct to use, or NULL for single tail
* \param dest: the array of elements to be inserted. or NULL for no copy
* \param max_count: the number of available elements at src
*
* Attempts to copy out as many waiting elements as possible into dest, from
* the perspective of the given tail, up to max_count. If dest is NULL, the
* copying out is not done but the elements are logically consumed as usual.
* NULL dest is useful in combination with lws_ring_get_element(), where you
* can use the element direct from the ringbuffer and then call this with NULL
* dest to logically consume it.
*
* Increments the tail position according to how many elements could be
* consumed.
*
* Returns the number of elements consumed.
*/
LWS_VISIBLE LWS_EXTERN size_t
lws_ring_consume(struct lws_ring *ring, uint32_t *tail, void *dest,
size_t max_count);
/**
* lws_ring_get_element(): get a pointer to the next waiting element for tail
*
* \param ring: the struct lws_ring to report on
* \param tail: a pointer to the tail struct to use, or NULL for single tail
*
* Points to the next element that tail would consume, directly in the
* ringbuffer. This lets you write() or otherwise use the element without
* having to copy it out somewhere first.
*
* After calling this, you must call lws_ring_consume(ring, &tail, NULL, 1)
* which will logically consume the element you used up and increment your
* tail (tail may also be NULL there if you use a single tail).
*
* Returns NULL if no waiting element, or a const void * pointing to it.
*/
LWS_VISIBLE LWS_EXTERN const void *
lws_ring_get_element(struct lws_ring *ring, uint32_t *tail);
/**
* lws_ring_update_oldest_tail(): free up elements older than tail for reuse
*
* \param ring: the struct lws_ring to report on
* \param tail: a pointer to the tail struct to use, or NULL for single tail
*
* If you are using multiple tails, you must use this API to inform the
* lws_ring when none of the tails still need elements in the fifo any more,
* by updating it when the "oldest" tail has moved on.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ring_update_oldest_tail(struct lws_ring *ring, uint32_t tail);
/**
* lws_ring_get_oldest_tail(): get current oldest available data index
*
* \param ring: the struct lws_ring to report on
*
* If you are initializing a new ringbuffer consumer, you can set its tail to
* this to start it from the oldest ringbuffer entry still available.
*/
LWS_VISIBLE LWS_EXTERN uint32_t
lws_ring_get_oldest_tail(struct lws_ring *ring);
/**
* lws_ring_next_linear_insert_range(): used to write directly into the ring
*
* \param ring: the struct lws_ring to report on
* \param start: pointer to a void * set to the start of the next ringbuffer area
* \param bytes: pointer to a size_t set to the max length you may use from *start
*
* This provides a low-level, bytewise access directly into the ringbuffer
* allowing direct insertion of data without having to use a bounce buffer.
*
* The api reports the position and length of the next linear range that can
* be written in the ringbuffer, ie, up to the point it would wrap, and sets
* *start and *bytes accordingly. You can then, eg, directly read() into
* *start for up to *bytes, and use lws_ring_bump_head() to update the lws_ring
* with what you have done.
*
* Returns nonzero if no insertion is currently possible.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ring_next_linear_insert_range(struct lws_ring *ring, void **start,
size_t *bytes);
/**
* lws_ring_bump_head(): used to write directly into the ring
*
* \param ring: the struct lws_ring to operate on
* \param bytes: the number of bytes you inserted at the current head
*/
LWS_VISIBLE LWS_EXTERN void
lws_ring_bump_head(struct lws_ring *ring, size_t bytes);
LWS_VISIBLE LWS_EXTERN void
lws_ring_dump(struct lws_ring *ring, uint32_t *tail);
/*
* This is a helper that combines the common pattern of needing to consume
* some ringbuffer elements, move the consumer tail on, and check if that
* has moved any ringbuffer elements out of scope, because it was the last
* consumer that had not already consumed them.
*
* Elements that go out of scope because the oldest tail is now after them
* get garbage-collected by calling the destroy_element callback on them
* defined when the ringbuffer was created.
*/
#define lws_ring_consume_and_update_oldest_tail(\
___ring, /* the lws_ring object */ \
___type, /* type of objects with tails */ \
___ptail, /* ptr to tail of obj with tail doing consuming */ \
___count, /* count of payload objects being consumed */ \
___list_head, /* head of list of objects with tails */ \
___mtail, /* member name of tail in ___type */ \
___mlist /* member name of next list member ptr in ___type */ \
) { \
int ___n, ___m; \
\
___n = lws_ring_get_oldest_tail(___ring) == *(___ptail); \
lws_ring_consume(___ring, ___ptail, NULL, ___count); \
if (___n) { \
uint32_t ___oldest; \
___n = 0; \
___oldest = *(___ptail); \
lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
___m = (int)lws_ring_get_count_waiting_elements( \
___ring, &(*___ppss)->___mtail); \
if (___m >= ___n) { \
___n = ___m; \
___oldest = (*___ppss)->___mtail; \
} \
} lws_end_foreach_llp(___ppss, ___mlist); \
\
lws_ring_update_oldest_tail(___ring, ___oldest); \
} \
}
/*
* This does the same as the lws_ring_consume_and_update_oldest_tail()
* helper, but for the simpler case there is only one consumer, so one
* tail, and that tail is always the oldest tail.
*/
#define lws_ring_consume_single_tail(\
___ring, /* the lws_ring object */ \
___ptail, /* ptr to tail of obj with tail doing consuming */ \
___count /* count of payload objects being consumed */ \
) { \
lws_ring_consume(___ring, ___ptail, NULL, ___count); \
lws_ring_update_oldest_tail(___ring, *(___ptail)); \
}
///@}

View File

@ -0,0 +1,362 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2019 - 2020 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.
*
* This is the headers for secure stream api variants that deal with clients in
* different threads or even different processes.
*
* lws_ss_ when client is directly using the event loop
* lws_sstc_ when client is in a different thread to the event loop
* lws_sspc_ when client is in a different process to the event loop
*
* The client api is almost the same except the slightly diffent names.
*
* This header is included as part of libwebsockets.h, for link against the
* libwebsockets library.
*/
/*
* lws_sspc_ apis... different process
*/
/*
* Helper translation so user code written to lws_ss_ can be built for
* lws_sspc_ in one step by #define LWS_SS_USE_SSPC before including
*/
struct lws_sspc_handle;
#if defined(LWS_SS_USE_SSPC)
#define lws_ss_handle lws_sspc_handle
#define lws_ss_create lws_sspc_create
#define lws_ss_destroy lws_sspc_destroy
#define lws_ss_request_tx lws_sspc_request_tx
#define lws_ss_request_tx_len lws_sspc_request_tx_len
#define lws_ss_client_connect lws_sspc_client_connect
#define lws_ss_get_sequencer lws_sspc_get_sequencer
#define lws_ss_proxy_create lws_sspc_proxy_create
#define lws_ss_get_context lws_sspc_get_context
#define lws_ss_rideshare lws_sspc_rideshare
#define lws_ss_set_metadata lws_sspc_set_metadata
#define lws_ss_get_metadata lws_sspc_get_metadata
#define lws_ss_add_peer_tx_credit lws_sspc_add_peer_tx_credit
#define lws_ss_get_est_peer_tx_credit lws_sspc_get_est_peer_tx_credit
#define lws_ss_start_timeout lws_sspc_start_timeout
#define lws_ss_cancel_timeout lws_sspc_cancel_timeout
#define lws_ss_to_user_object lws_sspc_to_user_object
#define lws_ss_change_handlers lws_sspc_change_handlers
#define lws_smd_ss_rx_forward lws_smd_sspc_rx_forward
#define lws_ss_server_ack lws_sspc_server_ack
#define lws_ss_tag lws_sspc_tag
#define _lws_fi_user_ss_fi _lws_fi_user_sspc_fi
#define lwsl_ss_get_cx lwsl_sspc_get_cx
#undef lwsl_ss
#define lwsl_ss lwsl_sspc
#undef lwsl_hexdump_ss
#define lwsl_hexdump_ss lwsl_hexdump_sspc
#endif
LWS_VISIBLE LWS_EXTERN void
lws_log_prepend_sspc(struct lws_log_cx *cx, void *obj, char **p, char *e);
LWS_VISIBLE LWS_EXTERN struct lws_log_cx *
lwsl_sspc_get_cx(struct lws_sspc_handle *ss);
#define lwsl_sspc(_h, _fil, ...) \
_lws_log_cx(lwsl_sspc_get_cx(_h), lws_log_prepend_sspc, _h, \
_fil, __func__, __VA_ARGS__)
#define lwsl_hexdump_sspc(_h, _fil, _buf, _len) \
lwsl_hexdump_level_cx(lwsl_sspc_get_cx(_h), \
lws_log_prepend_sspc, \
_h, _fil, _buf, _len)
/*
* lwsl_sspc
*/
#if (_LWS_ENABLED_LOGS & LLL_ERR)
#define lwsl_sspc_err(_w, ...) lwsl_sspc(_w, LLL_ERR, __VA_ARGS__)
#else
#define lwsl_sspc_err(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_WARN)
#define lwsl_sspc_warn(_w, ...) lwsl_sspc(_w, LLL_WARN, __VA_ARGS__)
#else
#define lwsl_sspc_warn(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_NOTICE)
#define lwsl_sspc_notice(_w, ...) lwsl_sspc(_w, LLL_NOTICE, __VA_ARGS__)
#else
#define lwsl_sspc_notice(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_INFO)
#define lwsl_sspc_info(_w, ...) lwsl_sspc(_w, LLL_INFO, __VA_ARGS__)
#else
#define lwsl_sspc_info(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_DEBUG)
#define lwsl_sspc_debug(_w, ...) lwsl_sspc(_w, LLL_DEBUG, __VA_ARGS__)
#else
#define lwsl_sspc_debug(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_PARSER)
#define lwsl_sspc_parser(_w, ...) lwsl_sspc(_w, LLL_PARSER, __VA_ARGS__)
#else
#define lwsl_sspc_parser(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_HEADER)
#define lwsl_sspc_header(_w, ...) lwsl_sspc(_w, LLL_HEADER, __VA_ARGS__)
#else
#define lwsl_sspc_header(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_EXT)
#define lwsl_sspc_ext(_w, ...) lwsl_sspc(_w, LLL_EXT, __VA_ARGS__)
#else
#define lwsl_sspc_ext(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_CLIENT)
#define lwsl_sspc_client(_w, ...) lwsl_sspc(_w, LLL_CLIENT, __VA_ARGS__)
#else
#define lwsl_sspc_client(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_LATENCY)
#define lwsl_sspc_latency(_w, ...) lwsl_sspc(_w, LLL_LATENCY, __VA_ARGS__)
#else
#define lwsl_sspc_latency(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_THREAD)
#define lwsl_sspc_thread(_w, ...) lwsl_sspc(_w, LLL_THREAD, __VA_ARGS__)
#else
#define lwsl_sspc_thread(_w, ...) do {} while(0)
#endif
#if (_LWS_ENABLED_LOGS & LLL_USER)
#define lwsl_sspc_user(_w, ...) lwsl_sspc(_w, LLL_USER, __VA_ARGS__)
#else
#define lwsl_sspc_user(_w, ...) do {} while(0)
#endif
#define lwsl_hexdump_sspc_err(_v, ...) lwsl_hexdump_sspc(_v, LLL_ERR, __VA_ARGS__)
#define lwsl_hexdump_sspc_warn(_v, ...) lwsl_hexdump_sspc(_v, LLL_WARN, __VA_ARGS__)
#define lwsl_hexdump_sspc_notice(_v, ...) lwsl_hexdump_sspc(_v, LLL_NOTICE, __VA_ARGS__)
#define lwsl_hexdump_sspc_info(_v, ...) lwsl_hexdump_sspc(_v, LLL_INFO, __VA_ARGS__)
#define lwsl_hexdump_sspc_debug(_v, ...) lwsl_hexdump_sspc(_v, LLL_DEBUG, __VA_ARGS__)
/*
* How lws refers to your per-proxy-link private data... not allocated or freed
* by lws, nor used except to pass a pointer to it through to ops callbacks
* below. Should be set to your transport private instance object, it's set to
* the wsi for the wsi transport. Notice it is provided as a ** (ptr-to-ptr) in
* most apis.
*/
/*
* Stub context when using LWS_ONLY_SSPC
*/
struct lws_context_standalone {
lws_txp_path_client_t txp_cpath;
lws_dll2_owner_t ss_client_owner;
uint32_t ssidx;
};
#if defined(STANDALONE)
#define lws_context lws_context_standalone
struct lws_context_standalone;
#endif
LWS_VISIBLE LWS_EXTERN int
lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
void *opaque_user_data, struct lws_sspc_handle **ppss,
void *reserved, const char **ppayload_fmt);
/**
* lws_sspc_destroy() - Destroy secure stream
*
* \param ppss: pointer to lws_ss_t pointer to be destroyed
*
* Destroys the lws_ss_t pointed to by *ppss, and sets *ppss to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_sspc_destroy(struct lws_sspc_handle **ppss);
/**
* lws_sspc_request_tx() - Schedule stream for tx
*
* \param pss: pointer to lws_ss_t representing stream that wants to transmit
*
* Schedules a write on the stream represented by \p pss. When it's possible to
* write on this stream, the *tx callback will occur with an empty buffer for
* the stream owner to fill in.
*/
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
lws_sspc_request_tx(struct lws_sspc_handle *pss);
/**
* lws_sspc_request_tx_len() - Schedule stream for tx with length hint
*
* \param h: pointer to handle representing stream that wants to transmit
* \param len: the length of the write in bytes
*
* Schedules a write on the stream represented by \p pss. When it's possible to
* write on this stream, the *tx callback will occur with an empty buffer for
* the stream owner to fill in.
*
* This api variant should be used when it's possible the payload will go out
* over h1 with x-web-form-urlencoded or similar Content-Type.
*
* The serialized, sspc type api actually serializes and forwards the length
* hint to its upstream proxy, where it's available for use to produce the
* internet-capable protocol framing.
*/
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
lws_sspc_request_tx_len(struct lws_sspc_handle *h, unsigned long len);
/**
* lws_sspc_client_connect() - Attempt the client connect
*
* \param h: secure streams handle
*
* Starts the connection process for the secure stream. Returns 0.
*/
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t
lws_sspc_client_connect(struct lws_sspc_handle *h);
/**
* lws_sspc_proxy_create() - Start a unix domain socket proxy for Secure Streams
*
* \param context: lws_context
*
* Creates a vhost that listens on an abstract namespace unix domain socket at
* address "proxy.ss.lws". Client connections to this proxy to Secure Streams
*/
LWS_VISIBLE LWS_EXTERN int
lws_sspc_proxy_create(struct lws_context *context);
/**
* lws_ss_get_context() - convenience helper to recover the lws context
*
* \h: secure streams handle
*
* Returns the lws context. Dispenses with the need to pass a copy of it into
* your secure streams handler.
*/
LWS_VISIBLE LWS_EXTERN struct lws_context *
lws_sspc_get_context(struct lws_sspc_handle *h);
#if defined(LWS_WITH_NETWORK)
extern const struct lws_protocols lws_sspc_protocols[2];
#endif
LWS_VISIBLE LWS_EXTERN const char *
lws_sspc_rideshare(struct lws_sspc_handle *h);
/**
* lws_sspc_set_metadata() - allow user to bind external data to defined ss metadata
*
* \h: secure streams handle
* \name: metadata name from the policy
* \value: pointer to user-managed data to bind to name
* \len: length of the user-managed data in value
*
* Binds user-managed data to the named metadata item from the ss policy.
* If present, the metadata item is handled in a protocol-specific way using
* the associated policy information. For example, in the policy
*
* "\"metadata\":" "["
* "{\"uptag\":" "\"X-Upload-Tag:\"},"
* "{\"ctype\":" "\"Content-Type:\"},"
* "{\"xctype\":" "\"X-Content-Type:\"}"
* "],"
*
* when the policy is using h1 is interpreted to add h1 headers of the given
* name with the value of the metadata on the left.
*
* Return 0 if OK, or nonzero if failed.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sspc_set_metadata(struct lws_sspc_handle *h, const char *name,
const void *value, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_sspc_get_metadata(struct lws_sspc_handle *h, const char *name,
const void **value, size_t *len);
LWS_VISIBLE LWS_EXTERN int
lws_sspc_add_peer_tx_credit(struct lws_sspc_handle *h, int32_t add);
LWS_VISIBLE LWS_EXTERN int
lws_sspc_get_est_peer_tx_credit(struct lws_sspc_handle *h);
LWS_VISIBLE LWS_EXTERN void
lws_sspc_start_timeout(struct lws_sspc_handle *h, unsigned int timeout_ms);
LWS_VISIBLE LWS_EXTERN void
lws_sspc_cancel_timeout(struct lws_sspc_handle *h);
LWS_VISIBLE LWS_EXTERN void *
lws_sspc_to_user_object(struct lws_sspc_handle *h);
LWS_VISIBLE LWS_EXTERN void
lws_sspc_change_handlers(struct lws_sspc_handle *h,
lws_sscb_rx rx,lws_sscb_tx tx, lws_sscb_state state);
LWS_VISIBLE LWS_EXTERN void
lws_sspc_server_ack(struct lws_sspc_handle *h, int nack);
/*
* Helpers offered by lws to handle transport SSPC-side proxy link events
*/
/**
* lws_sspc_tag() - get the sspc log tag
*
* \param h: the sspc handle
*
* Returns the sspc log tag, to assist in logging traceability
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_sspc_tag(struct lws_sspc_handle *h);
#if defined(STANDALONE)
#undef lws_context
#endif

View File

@ -0,0 +1,392 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2019 - 2021 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.
*
* included from libwebsockets.h
*/
typedef int (*plugin_auth_status_cb)(struct lws_ss_handle *ss, int status);
/**
* lws_ss_plugin_auth_t - api for an auth plugin
*
* Auth plugins create and sequence authenticated connections that can carry one
* or more streams to an endpoint. That may involve other connections to other
* places to eg, gather authenticated tokens and then make the real connection
* using the tokens.
*
* The secure stream object contains members to record which auth plugin the
* stream is bound to and an over-allocation of the secure stream object to
* contain the plugin auth private data.
*
* The auth plugin controls the state of the stream connection via the status
* callback, and handles retries.
*
* Network connections may require one kind of auth sequencing, and streams
* inside those connections another kind of auth sequencing depending on their
* role. So the secure stream object allows defining plugins for both kinds.
*
* Streams may disappear at any time and require reauth to bring a new one up.
* The auth plugin sequencer will connect / reconnect either on demand, or from
* the start and after any connectivity loss if any stream using the connection
* has the LWSSSPOLF_NAILED_UP flag.
*/
/* the public, const metrics policy definition */
typedef struct lws_metric_policy {
/* order of first two mandated by JSON policy parsing scope union */
const struct lws_metric_policy *next;
const char *name;
const char *report;
/**< the metrics policy name in the policy, used to bind to it */
uint64_t us_schedule;
/**< us interval between lws_system metrics api reports */
uint32_t us_decay_unit;
/**< how many us to decay avg by half, 0 = no decay */
uint8_t min_contributors;
/**< before we can judge something is an outlier */
} lws_metric_policy_t;
typedef struct lws_ss_x509 {
struct lws_ss_x509 *next;
const char *vhost_name; /**< vhost name using cert ctx */
const uint8_t *ca_der; /**< DER x.509 cert */
size_t ca_der_len; /**< length of DER cert */
uint8_t keep:1; /**< ie, if used in server tls */
} lws_ss_x509_t;
enum {
LWSSSPOLF_OPPORTUNISTIC = (1 << 0),
/**< the connection doesn't exist unless client asks to write */
LWSSSPOLF_NAILED_UP = (1 << 1),
/**< the connection tries to be connected the whole life of the ss */
LWSSSPOLF_URGENT_TX = (1 << 2),
/**< this connection carries critical tx data */
LWSSSPOLF_URGENT_RX = (1 << 3),
/**< this connection carries critical rx data */
LWSSSPOLF_TLS = (1 << 4),
/**< stream must be connected via a tls tunnel */
LWSSSPOLF_LONG_POLL = (1 << 5),
/**< stream used to receive async rx at arbitrary intervals */
LWSSSPOLF_AUTH_BEARER = (1 << 6),
/**< for http, use lws_system auth token 0 in authentication: bearer */
LWSSSPOLF_HTTP_NO_CONTENT_LENGTH = (1 << 7),
/**< don't add any content length even if we have it */
LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM = (1 << 8),
/**< set the client flag LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM */
LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR = (1 << 9),
/**< set the client flag LCCSCF_H2_QUIRK_OVERFLOWS_TXCR */
LWSSSPOLF_H2_QUIRK_UNCLEAN_HPACK_STATE = (1 << 10),
/**< HPACK decoder state does not end cleanly */
LWSSSPOLF_HTTP_MULTIPART = (1 << 11),
/**< indicates stream goes out as specifically a multipart mime POST
* section... if the tx has LWSSS_FLAG_COALESCE_CONTINUES flag then more
* multipart sections are expected. Without it, the multipart wrapper
* is closed and the http transaction issue completed when this message
* finishes. */
LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED = (1 << 12),
/**< set up lws_system client cert */
LWSSSPOLF_LOCAL_SINK = (1 << 13),
/**< expected to bind to a local sink only */
LWSSSPOLF_WAKE_SUSPEND__VALIDITY = (1 << 14),
/**< this stream's idle validity checks are critical enough we
* should arrange to wake from suspend to perform them
*/
LWSSSPOLF_SERVER = (1 << 15),
/**< we listen on a socket as a server */
LWSSSPOLF_ALLOW_REDIRECTS = (1 << 16),
/**< follow redirects */
LWSSSPOLF_HTTP_MULTIPART_IN = (1 << 17),
/**< handle inbound multipart mime at SS level */
LWSSSPOLF_ATTR_LOW_LATENCY = (1 << 18),
/**< stream requires low latency */
LWSSSPOLF_ATTR_HIGH_THROUGHPUT = (1 << 19),
/**< stream requires high throughput */
LWSSSPOLF_ATTR_HIGH_RELIABILITY = (1 << 20),
/**< stream requires high reliability */
LWSSSPOLF_ATTR_LOW_COST = (1 << 21),
/**< stream is not critical and should be handled as cheap as poss */
LWSSSPOLF_PERF = (1 << 22),
/**< capture and report performace information */
LWSSSPOLF_DIRECT_PROTO_STR = (1 << 23),
/**< metadata as direct protocol string, e.g. http header */
LWSSSPOLF_HTTP_CACHE_COOKIES = (1 << 24),
/**< Record http cookies and pass them back on future requests */
LWSSSPOLF_PRIORITIZE_READS = (1 << 25),
/**< prioritize clearing reads at expense of writes */
};
typedef struct lws_ss_trust_store {
struct lws_ss_trust_store *next;
const char *name;
const lws_ss_x509_t *ssx509[6];
int count;
} lws_ss_trust_store_t;
enum {
LWSSSP_H1,
LWSSSP_H2,
LWSSSP_WS,
LWSSSP_MQTT,
LWSSSP_RAW,
LWSSS_HBI_AUTH = 0,
LWSSS_HBI_DSN,
LWSSS_HBI_FWV,
LWSSS_HBI_TYPE,
_LWSSS_HBI_COUNT /* always last */
};
/*
* This does for both the static policy metadata entry, and the runtime metadata
* handling object.
*/
typedef struct lws_ss_metadata {
struct lws_ss_metadata *next;
const char *name;
void *value__may_own_heap;
size_t length;
uint8_t value_length; /* only valid if set by policy */
uint8_t value_is_http_token; /* valid if set by policy */
#if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR)
uint8_t name_on_lws_heap:1; /* proxy metatadata does this */
#endif
uint8_t value_on_lws_heap:1; /* proxy + rx metadata does this */
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
uint8_t pending_onward:1;
#endif
} lws_ss_metadata_t;
typedef struct lws_ss_http_respmap {
uint16_t resp; /* the http response code */
uint16_t state; /* low 16-bits of associated state */
} lws_ss_http_respmap_t;
/*
* This is a mapping between an auth streamtype and a name and other information
* that can be independently instantiated. Other streamtypes can indicate they
* require this authentication on their connection.
*/
typedef struct lws_ss_auth {
struct lws_ss_auth *next;
const char *name;
const char *type;
const char *streamtype;
uint8_t blob_index;
} lws_ss_auth_t;
/**
* lws_ss_policy_t: policy database entry for a stream type
*
* Decides the system policy for how to implement connections of name
* .streamtype.
*
* Streams may need one kind of auth sequencing for the network connection and
* another kind of auth sequencing for the streams that are carried inside it,
* this is the purpose of .nauth and .sauth. Both are optional and may be NULL.
*
* An array of these is set at context creation time, ending with one with a
* NULL streamtype.
*/
typedef struct lws_ss_policy {
struct lws_ss_policy *next;
const char *streamtype; /**< stream type lhs to match on */
const char *endpoint; /**< DNS address to connect to */
const char *rideshare_streamtype; /**< optional transport
* on another, preexisting stream of this
* streamtype name */
const char *payload_fmt;
const char *socks5_proxy;
lws_ss_metadata_t *metadata; /* linked-list of metadata */
const lws_metric_policy_t *metrics; /* linked-list of metric policies */
const lws_ss_auth_t *auth; /* NULL or auth object we bind to */
#if defined(LWS_WITH_SERVER)
const struct lws_protocol_vhost_options *pvo;
#endif
/* protocol-specific connection policy details */
union {
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) || defined(LWS_ROLE_WS)
/* details for http-related protocols... */
struct {
/* common to all http-related protocols */
const char *method;
const char *url;
const char *multipart_name;
const char *multipart_filename;
const char *multipart_content_type;
const char *blob_header[_LWSSS_HBI_COUNT];
const char *auth_preamble;
const lws_ss_http_respmap_t *respmap;
union {
// struct { /* LWSSSP_H1 */
// } h1;
// struct { /* LWSSSP_H2 */
// } h2;
struct { /* LWSSSP_WS */
const char *subprotocol;
uint8_t binary;
/* false = TEXT, true = BINARY */
} ws;
} u;
uint16_t resp_expect;
uint8_t count_respmap;
uint8_t fail_redirect:1;
} http;
#endif
#if defined(LWS_ROLE_MQTT)
struct {
const char *topic; /* stream sends on this topic */
const char *subscribe; /* stream subscribes to this topic */
const char *will_topic;
const char *will_message;
const char *birth_topic;
const char *birth_message;
uint16_t keep_alive;
uint8_t qos;
uint8_t clean_start;
uint8_t will_qos;
uint8_t will_retain;
uint8_t birth_qos;
uint8_t birth_retain;
uint8_t aws_iot;
uint8_t retain;
} mqtt;
#endif
/* details for non-http related protocols... */
} u;
#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
/* directly point to the metadata name, no need to expand */
const char *aws_region;
const char *aws_service;
#endif
/*
* We're either a client connection policy that wants a trust store,
* or we're a server policy that wants a mem cert and key... Hold
* these mutually-exclusive things in a union.
*/
union {
const lws_ss_trust_store_t *store;
/**< CA certs needed for conn validation, only set between
* policy parsing and vhost creation */
struct {
const lws_ss_x509_t *cert;
/**< the server's signed cert with the pubkey */
const lws_ss_x509_t *key;
/**< the server's matching private key */
} server;
} trust;
const lws_retry_bo_t *retry_bo; /**< retry policy to use */
int32_t txc;
int32_t txc_peer;
uint32_t proxy_buflen; /**< max dsh alloc for proxy */
uint32_t proxy_buflen_rxflow_on_above;
uint32_t proxy_buflen_rxflow_off_below;
uint32_t client_buflen; /**< max dsh alloc for client */
uint32_t client_buflen_rxflow_on_above;
uint32_t client_buflen_rxflow_off_below;
uint32_t timeout_ms; /**< default message response
* timeout in ms */
uint32_t flags; /**< stream attribute flags */
uint16_t port; /**< endpoint port */
uint8_t metadata_count; /**< metadata count */
uint8_t protocol; /**< protocol index */
uint8_t client_cert; /**< which client cert to apply
0 = none, 1+ = cc 0+ */
uint8_t priority; /* 0 = normal, 6 = max normal,
* 7 = network management */
} lws_ss_policy_t;
#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY)
/*
* These only exist / have meaning if there's a dynamic JSON policy enabled
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_policy_parse_begin(struct lws_context *context, int overlay);
LWS_VISIBLE LWS_EXTERN int
lws_ss_policy_parse_abandon(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN int
lws_ss_policy_parse(struct lws_context *context, const uint8_t *buf, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_ss_policy_overlay(struct lws_context *context, const char *overlay);
/*
* You almost certainly don't want these, they return the first policy or auth
* object in a linked-list of objects created by lws_ss_policy_parse above,
* they are exported to generate static policy with
*/
LWS_VISIBLE LWS_EXTERN const lws_ss_policy_t *
lws_ss_policy_get(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN const lws_ss_auth_t *
lws_ss_auth_get(struct lws_context *context);
#endif

View File

@ -0,0 +1,599 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2019 - 2021 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.
*
* included from libwebsockets.h
*
* This defines the Serialized Secure Streams framing, and the optional
* lws_transport_mux framing.
*
* APIs are declared for lws_transport and binding those to the SSPC and proxy
* sides in lws.
*/
#if defined(STANDALONE)
struct lws_context_standalone;
#define lws_context lws_context_standalone
#endif
#define LWSSSS_VERSION 1
typedef enum {
/*
* This is the Serialized Serure Streams framing. It's sufficient to
* carry all SS API actions over a point-to-point bytestream between
* an SSPC client and an SS oroxy, in both directions.
*
* These serialized streams may be multiplexed by the transport (eg,
* for unix domain sockets transport, each SS opens its own UDS socket
* to the proxy) or via lws_transport_mux framing encapsulation.
*
*
* Framing for Proxy -> Client direction
*/
LWSSS_SER_RXPRE_RX_PAYLOAD = 0x55,
/*
* Proxied rx
*
* - 0: LWSSS_SER_RXPRE_RX_PAYLOAD
* - 1: 2 byte MSB-first rest-of-frame length
* - 3: 4-byte MSB-first flags
* - 7: 4-byte MSB-first us between inbound read and wrote to client
* - 11: 8-byte MSB-first us resolution unix time proxy wrote to client
* - 17: (rideshare name len + rideshare name if flags &
* LWSSS_FLAG_RIDESHARE) payload
*/
LWSSS_SER_RXPRE_CREATE_RESULT,
/*
* Proxied connection setup result
*
* - 0: LWSSS_SER_RXPRE_CREATE_RESULT
* - 1: 2 byte MSB-first rest-of-frame length (usually 00, 03)
* - 3: 1 byte result, 0 = success. On failure, proxy will close
* connection.
* - 4: 4 byte client dsh allocation recommended for stream type,
* from policy (introduced in SSSv1)
* - 8: 2 byte MSB-first initial tx credit
* - 10: if present, comma-sep list of rideshare types from policy
*/
LWSSS_SER_RXPRE_CONNSTATE,
/*
* Proxied state (8 or 11 byte packet)
*
* - 0: LWSSS_SER_RXPRE_CONNSTATE
* - 1: 00, 05 if state < 256, else 00, 08
* - 3: 1 byte state index if state < 256, else 4-byte MSB-first
* state index
* - 4 or 7: 4-byte MSB-first ordinal
*/
LWSSS_SER_RXPRE_TXCR_UPDATE,
/*
* Proxied tx credit
*
* - 0: LWSSS_SER_RXPRE_TXCR_UPDATE
* - 1: 00, 04
* - 3: 4-byte MSB-first addition tx credit bytes
*/
LWSSS_SER_RXPRE_METADATA,
/*
* Proxied rx metadata
*
* - 0: LWSSS_SER_RXPRE_METADATA
* - 1: 2-byte MSB-first rest-of-frame length
* - 3: 1-byte metadata name length
* - 4: metadata name
* - ...: metadata value (for rest of packet)
*/
LWSSS_SER_RXPRE_TLSNEG_ENCLAVE_SIGN,
/* reserved */
LWSSS_SER_RXPRE_PERF,
/*
* Proxied performance information
*
* - 0: LWSSS_SER_RXPRE_PERF
* - 1: 2-byte MSB-first rest-of-frame length
* - 3: ... performance JSON (for rest of packet)
*/
/*
* Framing for Client -> Proxy direction
*/
LWSSS_SER_TXPRE_STREAMTYPE = 0xaa,
/*
* Proxied connection setup
*
* - 0: LWSSS_SER_TXPRE_STREAMTYPE
* - 1: 2-byte MSB-first rest-of-frame length
* - 3: 1-byte Client SSS protocol version (introduced in SSSv1)
* - 4: 4-byte Client PID (introduced in SSSv1)
* - 8: 4-byte MSB-first initial tx credit
* - 12: the streamtype name with no NUL
*/
LWSSS_SER_TXPRE_ONWARD_CONNECT,
/*
* Proxied request for onward connection
*
* - 0: LWSSS_SER_TXPRE_ONWARD_CONNECT
* - 1: 00, 00
*/
LWSSS_SER_TXPRE_DESTROYING,
/*
* Proxied secure stream destroy
*
* - 0: LWSSS_SER_TXPRE_DESTROYING
* - 1: 00, 00
*/
LWSSS_SER_TXPRE_TX_PAYLOAD,
/*
* Proxied tx
*
* - 0: LWSSS_SER_TXPRE_TX_PAYLOAD
* - 1: 2 byte MSB-first rest-of-frame length
* - 3: 4-byte MSB-first flags
* - 7: 4-byte MSB-first us between client requested write and wrote
* to proxy
* - 11: 8-byte MSB-first us resolution unix time client wrote to proxy
* - 19: ...payload (for rest of packet)
*/
LWSSS_SER_TXPRE_METADATA,
/*
* Proxied metadata - sent when one metadata item set clientside
*
* - 0: LWSSS_SER_TXPRE_METADATA
* - 1: 2-byte MSB-first rest-of-frame length
* - 3: 1-byte metadata name length
* - 4: metadata name
* - ...: metadata value (for rest of packet)
*/
LWSSS_SER_TXPRE_TXCR_UPDATE,
/*
* TX credit management - sent when using tx credit apis, cf METADATA
*
* - 0: LWSSS_SER_TXPRE_TXCR_UPDATE
* - 1: 2-byte MSB-first rest-of-frame length 00, 04
* - 3: 4-byte additional tx credit adjust value
*/
LWSSS_SER_TXPRE_TIMEOUT_UPDATE,
/*
* Stream timeout management - forwarded when user applying or
* cancelling t.o.
*
* - 0: LWSSS_SER_TXPRE_TIMEOUT_UPDATE
* - 1: 2-byte MSB-first rest-of-frame length 00, 04
* - 3: 4-byte MSB-first unsigned 32-bit timeout,
* 0 = use policy, -1 = cancel
*/
LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT,
/*
* Passing up payload length hint
*
* - 0: LWSSS_SER_TXPRE_PAYLOAD_LENGTH_HINT
* - 1: 2-byte MSB-first rest-of-frame length 00, 04
* - 3: 4-byte MSB-first unsigned 32-bit payload length hint
*/
LWSSS_SER_TXPRE_TLSNEG_ENCLAVE_SIGNED,
/* reserved */
LWSSS_SER_TXPRE_LINK_VALIDITY_PROBE,
} lws_sss_cmds_t;
/* SSPC serialization states */
typedef enum {
LPCSPROX_WAIT_INITIAL_TX = 1, /* after connect, must send streamtype */
LPCSPROX_REPORTING_FAIL, /* stream creation failed, wait to to tell */
LPCSPROX_REPORTING_OK, /* stream creation succeeded, wait to to tell */
LPCSPROX_OPERATIONAL, /* ready for payloads */
LPCSPROX_DESTROYED,
LPCSCLI_SENDING_INITIAL_TX, /* after connect, must send streamtype */
LPCSCLI_WAITING_CREATE_RESULT, /* wait to hear if proxy ss create OK */
LPCSCLI_LOCAL_CONNECTED, /* we are in touch with the proxy */
LPCSCLI_ONWARD_CONNECT, /* request onward ss connection */
LPCSCLI_OPERATIONAL, /* ready for payloads */
} lws_ss_conn_states_t;
/*
* Optional multiplexing layer
*
* Either side can:
*
* - open and close channels asynchronously
* - send and receive transport-level (not mux channel) timed PINGs / PONGs
* - send and receive data bound to an open mux channel
*
* PONGs are produced and sent automatically on recipt of a PING from the peer
* The peer sends a PONGACK so the single transaction can validate connection
* viability in both directions.
*/
enum {
LWSSSS_LLM_CHANNEL_REQ = 0xf0,
/**<
* Either side proposes to open a new mux channel
*
* - 0: LWSSSS_LLM_CHANNEL_REQ
* - 1: 1-byte mux channel index, client initiated: first free from
* zero up, server initiated: first free from 0xff down
*/
LWSSSS_LLM_CHANNEL_ACK,
/**<
* Positive response to earlier LWSSSS_LLM_CHANNEL_REQ
*
* - 0: LWSSSS_LLM_CHANNEL_ACK
* - 1: 1-byte mux channel index, from the reqyuest
*/
LWSSSS_LLM_CHANNEL_NACK,
/**<
* Negative response to earlier LWSSSS_LLM_CHANNEL_REQ. This also acts
* as a FIN if one arrives on a channel unsolicited.
*
* - 0: LWSSSS_LLM_CHANNEL_NACK
* - 1: 1-byte mux channel index, from the reqyuest
*/
LWSSSS_LLM_CHANNEL_CLOSE,
/**<
* Either side informs peer it is closing a mux channel
*
* - 0: LWSSSS_LLM_CHANNEL_CLOSE
* - 1: 1-byte mux channel index
*/
LWSSSS_LLM_CHANNEL_CLOSE_ACK,
/**<
* Peer acknowledges closing a mux channel, so it can be reused
*
* - 0: LWSSSS_LLM_CHANNEL_CLOSE_ACK
* - 1: 1-byte mux channel index
*/
LWSSSS_LLM_MUX,
/**<
* Encapsulate data on an open mux channel
*
* - 0: LWSSSS_LLM_MUX
* - 1: 1-byte mux channel index
* - 2: 2-byte MSB-first rest-of-frame length
* - 4... mux payload
*/
LWSSSS_LLM_PING,
/**<
* Either side wants to validate communication on mux transport
*
* - 0: LWSSSS_LLM_PING
* - 1: 8-byte MSB-first us resolution unix time this was issued
*/
LWSSSS_LLM_PONG,
/**<
* Either side responds to peer's PING.
*
* - 0: LWSSSS_LLM_PONG
* - 1: 8-byte MSB-first us resolution unix time from PING
* - 9: 8-byte MSB-first us resolution unix time this PONG sent
*/
LWSSSS_LLM_PONGACK,
/**<
* When the original PING sender receives a PONG, it immediately sends
* a PINGACK, which is not replied to. This allows the other side to
* also know the connection is valid in both directions, with only one
* side needing to issue PINGs.
*
* It also synchronizes both sides' understanding of the transport
* validity in one transaction.
*
* - 0: LWSSSS_LLM_PONGACK
* - 1: 8-byte MSB-first us resolution unix time from PING
*/
LWSSSS_LLM_RESET_TRANSPORT,
/**<
* Either side can issue this to indicate they no longer trust the
* transport link. They should close all their channels and enter a
* state trying to resync using 3-way PINGs
*/
};
typedef void * lws_transport_priv_t; /* care - this is a pointer type already */
struct lws_transport_mux;
struct lws_sss_proxy_conn;
struct lws_transport_client_ops;
struct lws_transport_proxy_ops;
struct lws_sspc_handle;
/*
* These describe the path through different transport layers. Each has an
* 'in' and 'onw' (onward) side that can be bound to different parts in lws.
* SSPC and the SS Proxy code in lws each exposes one of these as terminals
* for the "path" to handle the SS Serialization on each side.
*
* sspc-transport-wsi and proxy-transport-wsi expose possible endpoints for the
* paths, so you can simply "wire SSPC and proxy up to a wsi transport".
*
* You can also create a lws_transport_mux_t and interpose it in the transport
* path on each side, and produce your own custom lws_transport ops implementing
* arbitrary transport support.
*/
typedef struct lws_txp_path_client {
const struct lws_transport_client_ops *ops_in;
lws_transport_priv_t priv_in;
const struct lws_transport_client_ops *ops_onw;
lws_transport_priv_t priv_onw;
struct lws_transport_mux *mux;
} lws_txp_path_client_t;
typedef struct lws_txp_path_proxy {
const struct lws_transport_proxy_ops *ops_in;
lws_transport_priv_t priv_in;
const struct lws_transport_proxy_ops *ops_onw;
lws_transport_priv_t priv_onw;
struct lws_transport_mux *mux;
} lws_txp_path_proxy_t;
/*
* Operations for client-side transport
*/
typedef struct lws_transport_client_ops {
const char *name;
int (*event_retry_connect)(lws_txp_path_client_t *path,
struct lws_sspc_handle *h);
/**< Attempt to create a new connection / channel to the proxy */
lws_ss_state_return_t (*event_connect_disposition)(
struct lws_sspc_handle *h, int disposition);
/**< Connection attempt result, disposition 9 = success, else failed */
void (*req_write)(lws_transport_priv_t priv);
/**< Request a write to the proxy on this channel */
int (*_write)(lws_transport_priv_t priv, uint8_t *buf, size_t len);
/**< Write the requested data on the channel to the proxy *** MUST have
* LWS_PRE usable behind buf */
lws_ss_state_return_t (*event_read)(lws_transport_priv_t priv,
const uint8_t *buf, size_t len);
/**< len bytes at buf have been received */
void (*lost_coherence)(lws_transport_priv_t priv);
/**< report that the framing inside the mux channel is broken */
void (*_close)(lws_transport_priv_t priv);
/**< Close the channel to the proxy */
void (*event_stream_up)(lws_transport_priv_t priv);
/**< Called when a new channel to the proxy is acknowledged as up */
void (*event_client_up)(lws_transport_priv_t priv);
/**< Called when a client channel is acknowledged as up */
lws_ss_state_return_t (*event_can_write)(struct lws_sspc_handle *h,
size_t metadata_limit);
/**< Called when possible to write on the transport, after req_write */
lws_ss_state_return_t (*event_closed)(lws_transport_priv_t priv /*struct lws_sspc_handle *h */);
/**< we notice an onward proxy connection had closed */
uint32_t flags;
/**< Used for DSH creation flags */
uint32_t dsh_splitat;
} lws_transport_client_ops_t;
/*
* Operations for proxy-side transport
*/
typedef struct lws_transport_proxy_ops {
const char *name;
int (*init_proxy_server)(struct lws_context *context,
const struct lws_transport_proxy_ops *txp_ops_inward,
lws_transport_priv_t txp_priv_inward,
lws_txp_path_proxy_t *txp_ppath, const void *aux,
const char *bind, int port);
/**< Instantiate a proxy transport... bind/port are as shown for wsi
* transport, but may be overloaded to provide transport-specific init */
int (*destroy_proxy_server)(struct lws_context *context);
lws_ss_state_return_t (*event_new_conn)(struct lws_context *cx,
const struct lws_transport_proxy_ops *txp_ops_inward,
lws_transport_priv_t txp_priv_inward,
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
const lws_fi_ctx_t *fic,
#endif
struct lws_sss_proxy_conn **conn,
lws_transport_priv_t txp_priv);
/**< proxy has received a new connection from client */
void (*event_onward_bind)(lws_transport_priv_t priv,
struct lws_ss_handle *h);
/**< Called when the proxy creates an onward SS for a client channel */
void (*proxy_req_write)(lws_transport_priv_t priv);
/**< Request a write to the proxy on this channel */
lws_ss_state_return_t (*event_proxy_can_write)(
lws_transport_priv_t priv
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
, const lws_fi_ctx_t *fic
#endif
);
/**< Transport can now be written on, after earlier proxy_req_write */
int (*proxy_write)(lws_transport_priv_t priv, uint8_t *buf, size_t *len);
/**< Write the requested data on the channel to the proxy *** MUST have
* LWS_PRE usable behind buf. May do partial writes, len is set on return
* to actual length written*/
lws_ss_state_return_t (*event_close_conn)(
struct lws_sss_proxy_conn *conn);
/**< proxy sees an existing conn closes */
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
const lws_fi_ctx_t * (*fault_context)(lws_transport_priv_t priv);
/**< Get the fault context relating to the proxy connection, if any */
#endif
lws_ss_state_return_t (*close_conn)(struct lws_sss_proxy_conn *conn);
/**< called to handle closure of underlying transport */
lws_ss_state_return_t (*proxy_read)(lws_transport_priv_t priv,
const uint8_t *buf, size_t len);
void (*event_client_up)(lws_transport_priv_t priv);
/**< Called when the proxy has accepted a new client conn */
int (*proxy_check_write_more)(lws_transport_priv_t priv);
/**< optional, allows checking if we can write again */
uint32_t flags; /* dsh flags */
} lws_transport_proxy_ops_t;
/* lws_transport_mux parser states */
enum lwstmc_parser {
LWSTMCPAR_CMD,
LWSTMCPAR_CHIDX_DONE,
LWSTMCPAR_CHIDX,
LWSTMCPAR_PLENH,
LWSTMCPAR_PLENL,
LWSTMCPAR_PAY,
LWSTMCPAR_T64_1,
LWSTMCPAR_T64_2
};
/* lws_transport_mux channel definitions */
typedef uint8_t lws_mux_ch_idx_t;
#define LWS_MUCH_RANGE 256
/* lws_transport mux states */
enum {
/* lws_transport_mux_ch_t created */
LWSTMC_PENDING_CREATE_CHANNEL, /* waiting to send create channel */
LWSTMC_AWAITING_CREATE_CHANNEL_ACK, /* sent create ch, awaiting ack */
LWSTMC_PENDING_CREATE_CHANNEL_NACK, /* waiting to send create ch ack */
LWSTMC_PENDING_CREATE_CHANNEL_ACK, /* waiting to send create ch ack */
LWSTMC_OPERATIONAL, /* had ack, we are operational */
LWSTMC_PENDING_CLOSE_CHANNEL, /* waiting to send close channel */
LWSTMC_AWAITING_CLOSE_CHANNEL_ACK, /* sent close ch, awaiting ack */
LWSTMC_PENDING_CLOSE_CHANNEL_ACK, /* waiting to send close ch ack */
/* lws_transport_mux_ch_t destroyed */
};
#define LWS_TRANSPORT_MUXCH_MAGIC LWS_FOURCC('T', 'm', 'C', 'h')
#define assert_is_tmch(_tm) lws_assert_fourcc(_tm->magic, LWS_TRANSPORT_MUXCH_MAGIC)
typedef struct lws_transport_mux_ch {
#if defined(_DEBUG)
uint32_t magic;
#endif
lws_dll2_t list;
lws_dll2_t list_pending_tx;
lws_transport_priv_t priv;
lws_sorted_usec_list_t sul;
void *opaque;
lws_mux_ch_idx_t ch_idx;
uint8_t state;
uint8_t server:1;
} lws_transport_mux_ch_t;
enum { /* states of the transport */
LWSTM_TRANSPORT_DOWN,
LWSTM_OPERATIONAL,
};
#define LWSTMINFO_SERVER (1 << 0)
typedef struct lws_transport_info {
uint32_t ping_interval_us;
/**< us inbetween transport mux sending pings on transport */
uint32_t pong_grace_us;
/**< us we should wait for pong before assuming transport down */
lws_txp_path_client_t txp_cpath;
lws_txp_path_proxy_t txp_ppath;
struct lws_transport_info *onward_txp_info;
uint32_t flags; /* LWSTMINFO_.... */
} lws_transport_info_t;
#define LWS_TRANSPORT_MUX_MAGIC LWS_FOURCC('I', 's', 'T', 'M')
#define assert_is_tm(_tm) lws_assert_fourcc(_tm->magic, LWS_TRANSPORT_MUX_MAGIC)
typedef struct lws_transport_mux {
#if defined(_DEBUG)
uint32_t magic;
#endif
struct lws_context *cx;
lws_transport_info_t info;
lws_sorted_usec_list_t sul_ping;
void *txp_handle;
void *txp_aux;
uint64_t us_ping_in;
uint64_t us_ping_out;
uint64_t us_unixtime_peer;
uint64_t us_unixtime_peer_loc;
uint64_t mp_time;
uint64_t mp_time1;
enum lwstmc_parser mp_state;
uint32_t mp_pay; /* remaining payload */
uint8_t mp_cmd;
lws_mux_ch_idx_t mp_idx;
uint8_t mp_ctr;
uint32_t _open[LWS_MUCH_RANGE / 32];
uint32_t fin[LWS_MUCH_RANGE / 32];
lws_dll2_owner_t pending_tx;
lws_dll2_owner_t owner; /* lws_mux_ch_t */
uint8_t link_state;
uint8_t issue_ping:1;
uint8_t issue_pong:1;
uint8_t issue_pongack:1;
uint8_t awaiting_pong:1;
} lws_transport_mux_t;
lws_transport_mux_t *
lws_transport_mux_create(struct lws_context *cx, lws_transport_info_t *info,
void *txp_handle);
void
lws_transport_mux_destroy(lws_transport_mux_t **tm);
void
lws_transport_mux_request_tx(lws_transport_mux_t *tm);
#if defined(_DEBUG)
void
lws_transport_path_client_dump(lws_txp_path_client_t *path, const char *ctx);
void
lws_transport_path_proxy_dump(lws_txp_path_proxy_t *path, const char *ctx);
#else
#define lws_transport_path_client_dump(_a, _b)
#define lws_transport_path_proxy_dump(_a, _b)
#endif
/*
* Callback set used to customize parser and _pending apis
*/
typedef struct lws_txp_mux_parse_cbs {
int (*payload)(lws_transport_mux_ch_t *tmc, const uint8_t *buf,
size_t len);
int (*ch_opens)(lws_transport_mux_ch_t *tmc, int determination);
int (*ch_closes)(lws_transport_mux_ch_t *tmc);
void (*txp_req_write)(lws_transport_mux_t *tm);
int (*txp_can_write)(lws_transport_mux_ch_t *tmc);
} lws_txp_mux_parse_cbs_t;
int
lws_transport_mux_rx_parse(lws_transport_mux_t *tm, const uint8_t *buf,
size_t len, const lws_txp_mux_parse_cbs_t *cbs);
int /* nonzero if the transport mux has filled buf and wants to write it */
lws_transport_mux_pending(lws_transport_mux_t *tm, uint8_t *buf, size_t *len,
const lws_txp_mux_parse_cbs_t *cbs);
extern const lws_transport_client_ops_t lws_transport_mux_client_ops;
extern const lws_transport_proxy_ops_t lws_transport_mux_proxy_ops;
extern const lws_transport_client_ops_t lws_txp_inside_sspc;
extern const lws_transport_proxy_ops_t lws_txp_inside_proxy;
#if defined(STANDALONE)
#undef lws_context
#endif

View File

@ -0,0 +1,47 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2019 - 2021 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.
*
*
* These headers are related to providing user Secure Streams Serialization
* transport implementations in user code.
*
* The default implementation uses wsi for proxy serving and connecting clients,
* but it's also possible to provide user implementations of the operations
* needed to serve on a different transport for proxy, and to connect out on
* the different transport for client.
*
* You can provide your own lws_sss_ops_client_t and lws_sss_ops_proxy_t to
* control how serialized data is transmitted and received, to use SS
* serialization over, eg, UART instead.
*
* This allows situations where full SS proxy services can be offered to much
* weker devices, without any networking stack or tls library being needed.
*/
/*
* SSS Proxy Transport-related implementation apis
*/
struct lws_sss_proxy_conn;

View File

@ -0,0 +1,713 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2019 - 2021 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.
*
* included from libwebsockets.h
*
*
* Secure Streams is a *payload-only* client communication channel where all the
* details about the connection are held in a systemwide policy database and
* are keyed by the streamtype field... the user of the communication channel
* does not know or manage the choice of endpoint, tls CA, or even wire
* protocol. The advantage is he then does not have any dependency on any of
* those and they can be changed just by changing the policy database without
* touching the code using the stream.
*
* There are two ways secure streams interfaces to user code:
*
* 1) [Linux / RTOS] the natural, smallest interface is to call back to user
* code that only operates directly from the lws event loop thread context
* (direct callbacks from lws_ss_t)
*
* lws_thread( [user code] ---- lws )
*
* 2) [Linux] where the user code is in a different process and communicates
* asynchronously via a proxy socket
*
* user_process{ [user code] | shim | socket-}------ lws_process{ lws }
*
* In the second, IPC, case, all packets are prepended by one or more bytes
* indicating the packet type and serializing any associated data, known as
* Serialized Secure Streams or SSS.
*/
/** \defgroup secstr Secure Streams
* ##Secure Streams
*
* Secure Streams related apis
*/
///@{
#define LWS_SS_MTU 1540
struct lws_ss_handle;
typedef uint32_t lws_ss_tx_ordinal_t;
#if defined(STANDALONE)
#define lws_context lws_context_standalone
struct lws_context_standalone;
#endif
/*
* connection state events
*
* If you add states, take care about the state names and state transition
* validity enforcement tables too
*/
typedef enum {
/* zero means unset */
LWSSSCS_CREATING = 1,
LWSSSCS_DISCONNECTED,
LWSSSCS_UNREACHABLE, /* oridinal arg = 1 = caused by dns
* server reachability failure */
LWSSSCS_AUTH_FAILED,
LWSSSCS_CONNECTED,
LWSSSCS_CONNECTING,
LWSSSCS_DESTROYING,
LWSSSCS_POLL,
LWSSSCS_ALL_RETRIES_FAILED, /* all retries in bo policy failed */
LWSSSCS_QOS_ACK_REMOTE, /* remote peer received and acked tx */
LWSSSCS_QOS_NACK_REMOTE,
LWSSSCS_QOS_ACK_LOCAL, /* local proxy accepted our tx */
LWSSSCS_QOS_NACK_LOCAL, /* local proxy refused our tx */
LWSSSCS_TIMEOUT, /* optional timeout timer fired */
LWSSSCS_SERVER_TXN,
LWSSSCS_SERVER_UPGRADE, /* the server protocol upgraded */
LWSSSCS_EVENT_WAIT_CANCELLED, /* somebody called lws_cancel_service */
LWSSSCS_UPSTREAM_LINK_RETRY, /* if we are being proxied over some
* intermediate link, this transient
* state may be sent to indicate we are
* waiting to establish that link before
* creation can proceed.. ack is the
* number of ms we have been trying */
LWSSSCS_SINK_JOIN, /* sinks get this when a new source
* stream joins the sink */
LWSSSCS_SINK_PART, /* sinks get this when a new source
* stream leaves the sink */
LWSSSCS_USER_BASE = 1000
} lws_ss_constate_t;
enum {
LWSSS_FLAG_SOM = (1 << 0),
/* payload contains the start of new message */
LWSSS_FLAG_EOM = (1 << 1),
/* payload contains the end of message */
LWSSS_FLAG_POLL = (1 << 2),
/* Not a real transmit... poll for rx if protocol needs it */
LWSSS_FLAG_RELATED_START = (1 << 3),
/* Appears in a zero-length message indicating a message group of zero
* or more messages is now starting. */
LWSSS_FLAG_RELATED_END = (1 << 4),
/* Appears in a zero-length message indicating a message group of zero
* or more messages has now finished. */
LWSSS_FLAG_RIDESHARE = (1 << 5),
/* Serialized payload starts with non-default rideshare name length and
* name string without NUL, then payload */
LWSSS_FLAG_PERF_JSON = (1 << 6),
/* This RX is JSON performance data, only on streams with "perf" flag
* set */
};
/*
* Returns from state() callback can tell the caller what the user code
* wants to do
*/
typedef enum lws_ss_state_return {
LWSSSSRET_TX_DONT_SEND = 1, /* (*tx) only, or failure */
LWSSSSRET_OK = 0, /* no error */
LWSSSSRET_DISCONNECT_ME = -1, /* caller should disconnect us */
LWSSSSRET_DESTROY_ME = -2, /* caller should destroy us */
} lws_ss_state_return_t;
/**
* lws_ss_info_t: information about stream to be created
*
* Prepare this struct with information about what the stream type is and how
* the stream should interface with your code, and pass it to lws_ss_create()
* to create the requested stream.
*/
enum {
LWSSSINFLAGS_REGISTER_SINK = (1 << 0),
/**< If set, we're not creating a specific stream, but registering
* ourselves as the "sink" for .streamtype. It's analogous to saying
* we want to be the many-to-one "server" for .streamtype; when other
* streams are created with that streamtype, they should be forwarded
* to this stream owner, where they join and part from the sink via
* (*state) LWSSSCS_SINK_JOIN / _PART events, the new client handle
* being provided in the h_src parameter.
*/
LWSSSINFLAGS_PROXIED = (1 << 1),
/**< Set if the stream is being created as a stand-in at the proxy */
LWSSSINFLAGS_SERVER = (1 << 2),
/**< Set on the server object copy of the ssi / info to indicate that
* stream creation using this ssi is for Accepted connections belonging
* to a server */
LWSSSINFLAGS_ACCEPTED = (1 << 3),
/**< Set on the accepted object copy of the ssi / info to indicate that
* we are an accepted connection from a server's listening socket */
LWSSSINFLAGS_ACCEPTED_SINK = (1 << 4),
/**< Set on the accepted object copy of the ssi / info to indicate that
* we are an accepted connection from a local sink */
};
typedef lws_ss_state_return_t (*lws_sscb_rx)(void *userobj, const uint8_t *buf,
size_t len, int flags);
typedef lws_ss_state_return_t (*lws_sscb_tx)(void *userobj,
lws_ss_tx_ordinal_t ord,
uint8_t *buf, size_t *len,
int *flags);
typedef lws_ss_state_return_t (*lws_sscb_state)(void *userobj, void *h_src,
lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack);
#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
typedef void (*lws_ss_buffer_dump_cb)(void *userobj, const uint8_t *buf,
size_t len, int done);
#endif
struct lws_ss_policy;
typedef struct lws_ss_info {
const char *streamtype; /**< type of stream we want to create */
size_t user_alloc; /**< size of user allocation */
size_t handle_offset; /**< offset of handle stg in user_alloc type,
set to offsetof(mytype, my_handle_member) */
size_t opaque_user_data_offset;
/**< offset of opaque user data ptr in user_alloc type, set to
offsetof(mytype, opaque_ud_member) */
#if defined(LWS_WITH_SECURE_STREAMS_CPP)
const struct lws_ss_policy *policy;
/**< Normally NULL, or a locally-generated policy to apply to this
* connection instead of a named streamtype */
#endif
#if defined(LWS_WITH_SYS_FAULT_INJECTION)
lws_fi_ctx_t fic;
/**< Attach external Fault Injection context to the stream, hierarchy
* is ss->context */
#endif
lws_sscb_rx rx;
/**< callback with rx payload for this stream */
lws_sscb_tx tx;
/**< callback to send payload on this stream... 0 = send as set in
* len and flags, 1 = do not send anything (ie, not even 0 len frame) */
lws_sscb_state state;
/**< advisory cb about state of stream and QoS status if applicable...
* h_src is only used with sinks and LWSSSCS_SINK_JOIN/_PART events.
* Return nonzero to indicate you want to destroy the stream. */
#if defined(LWS_WITH_SECURE_STREAMS_BUFFER_DUMP)
lws_ss_buffer_dump_cb dump;
/**< cb to record needed protocol buffer data*/
#endif
int manual_initial_tx_credit;
/**< 0 = manage any tx credit automatically, nonzero explicitly sets the
* peer stream to have the given amount of tx credit, if the protocol
* can support it.
*
* In the special case of _lws_smd streamtype, this is used to indicate
* the connection's rx class mask.
* */
uint32_t client_pid;
/**< used in proxy / serialization case to hold the client pid this
* proxied connection is to be tagged with
*/
uint8_t flags;
uint8_t sss_protocol_version;
/**< used in proxy / serialization case to hold the SS serialization
* protocol level to use with this peer... clients automatically request
* the most recent version they were built with
* (LWS_SSS_CLIENT_PROTOCOL_VERSION) and the proxy stores the requested
* version in here
*/
} lws_ss_info_t;
#define LWS_SS_USER_TYPEDEF \
typedef struct { \
struct lws_ss_handle *ss; \
void *opaque_data;
#define LWS_SS_INFO(_streamtype, _type) \
const lws_ss_info_t ssi_##_type = { \
.handle_offset = offsetof(_type, ss), \
.opaque_user_data_offset = offsetof(_type, opaque_data), \
.user_alloc = sizeof(_type), \
.streamtype = _streamtype,
#define lws_ss_from_user(_u) (_u)->ss
#define lws_ss_opaque_from_user(_u) (_u)->opaque_data
#define lws_ss_cx_from_user(_u) lws_ss_get_context((_u)->ss)
#if defined(LWS_SS_USE_SSPC)
#define lws_context_info_defaults(_x, _y) _lws_context_info_defaults(_x, NULL)
#else
#define lws_context_info_defaults(_x, _y) _lws_context_info_defaults(_x, _y)
#endif
/**
* lws_ss_create() - Create secure stream
*
* \param context: the lws context to create this inside
* \param tsi: service thread index to create on (normally 0)
* \param ssi: pointer to lws_ss_info_t filled in with info about desired stream
* \param opaque_user_data: opaque data to set in the stream's user object
* \param ppss: pointer to secure stream handle pointer set on exit
* \param ppayload_fmt: NULL or pointer to a string ptr to take payload format
* name from the policy
*
* Requests a new secure stream described by \p ssi be created. If successful,
* the stream is created, its state callback called with LWSSSCS_CREATING, \p *ppss
* is set to point to the handle, and it returns 0. If it failed, it returns
* nonzero.
*
* Along with the opaque stream object, streams overallocate
*
* 1) a user data struct whose size is set in ssi
* 2) nauth plugin instantiation data (size set in the plugin struct)
* 3) sauth plugin instantiation data (size set in the plugin struct)
* 4) space for a copy of the stream type name
*
* The user data struct is initialized to all zeros, then the .handle_offset and
* .opaque_user_data_offset fields of the ssi are used to prepare the user data
* struct with the ss handle that was created, and a copy of the
* opaque_user_data pointer given as an argument.
*
* If you want to set up the stream with specific information, point to it in
* opaque_user_data and use the copy of that pointer in your user data member
* for it starting from the LWSSSCS_CREATING state call.
*
* Since different endpoints chosen by the policy may require different payload
* formats, \p ppayload_fmt is set to point to the name of the needed payload
* format from the policy database if non-NULL.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi,
void *opaque_user_data, struct lws_ss_handle **ppss,
void *reserved, const char **ppayload_fmt);
/**
* lws_ss_destroy() - Destroy secure stream
*
* \param ppss: pointer to lws_ss_t pointer to be destroyed
*
* Destroys the lws_ss_t pointed to by \p *ppss, and sets \p *ppss to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ss_destroy(struct lws_ss_handle **ppss);
/**
* lws_ss_request_tx() - Schedule stream for tx
*
* \param pss: pointer to lws_ss_t representing stream that wants to transmit
*
* Schedules a write on the stream represented by \p pss. When it's possible to
* write on this stream, the \p *tx callback will occur with an empty buffer for
* the stream owner to fill in.
*
* Returns 0 or LWSSSSRET_DESTROY_ME
*/
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
lws_ss_request_tx(struct lws_ss_handle *pss);
/**
* lws_ss_request_tx() - Schedule stream for tx
*
* \param pss: pointer to lws_ss_t representing stream that wants to transmit
* \param len: the length of the write in bytes
*
* Schedules a write on the stream represented by \p pss. When it's possible to
* write on this stream, the \p *tx callback will occur with an empty buffer for
* the stream owner to fill in.
*
* This api variant should be used when it's possible the payload will go out
* over h1 with x-web-form-urlencoded or similar Content-Type.
*/
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
lws_ss_request_tx_len(struct lws_ss_handle *pss, unsigned long len);
/**
* lws_ss_client_connect() - Attempt the client connect
*
* \param h: secure streams handle
*
* Starts the connection process for the secure stream.
*
* Can return any of the lws_ss_state_return_t values depending on user
* state callback returns.
*
* LWSSSSRET_OK means the connection is ongoing.
*
*/
LWS_VISIBLE LWS_EXTERN lws_ss_state_return_t LWS_WARN_UNUSED_RESULT
lws_ss_client_connect(struct lws_ss_handle *h);
/**
* lws_ss_proxy_create() - Start a unix domain socket proxy for Secure Streams
*
* \param context: lws_context
* \param bind: if port is 0, unix domain path with leading @ for abstract.
* if port nonzero, NULL, or network interface to bind listen to
* \param port: tcp port to listen on
*
* Creates a vhost that listens either on an abstract namespace unix domain
* socket (port = 0) or a tcp listen socket (port nonzero). If bind is NULL
* and port is 0, the abstract unix domain socket defaults to "proxy.ss.lws".
*
* Client connections to this proxy to Secure Streams are fulfilled using the
* policy local to the proxy and the data passed between the client and the
* proxy using serialized Secure Streams protocol.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_proxy_create(struct lws_context *context, const char *bind, int port);
/**
* lws_ss_state_name() - convenience helper to get a printable conn state name
*
* \param state: the connection state index
*
* Returns a printable name for the connection state index passed in.
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_ss_state_name(int state);
/**
* lws_ss_get_context() - convenience helper to recover the lws context
*
* \param h: secure streams handle
*
* Returns the lws context. Dispenses with the need to pass a copy of it into
* your secure streams handler.
*/
LWS_VISIBLE LWS_EXTERN struct lws_context *
lws_ss_get_context(struct lws_ss_handle *h);
/**
* lws_ss_get_vhost() - convenience helper to get the vhost the ss is bound to
*
* \param h: secure streams handle
*
* Returns NULL if disconnected, or the the lws_vhost of the ss' wsi connection.
*/
LWS_VISIBLE LWS_EXTERN struct lws_vhost *
lws_ss_get_vhost(struct lws_ss_handle *h);
#define LWSSS_TIMEOUT_FROM_POLICY 0
/**
* lws_ss_start_timeout() - start or restart the timeout on the stream
*
* \param h: secure streams handle
* \param timeout_ms: LWSSS_TIMEOUT_FROM_POLICY for policy value, else use timeout_ms
*
* Starts or restarts the stream's own timeout timer. If the specified time
* passes without lws_ss_cancel_timeout() being called on the stream, then the
* stream state callback receives LWSSSCS_TIMEOUT
*
* The process being protected by the timeout is up to the user code, it may be
* arbitrarily long and cross multiple protocol transactions or involve other
* streams. It's up to the user to decide when to start and when / if to cancel
* the stream timeout.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ss_start_timeout(struct lws_ss_handle *h, unsigned int timeout_ms);
/**
* lws_ss_cancel_timeout() - remove any timeout on the stream
*
* \param h: secure streams handle
*
* Disable any timeout that was applied to the stream by lws_ss_start_timeout().
*/
LWS_VISIBLE LWS_EXTERN void
lws_ss_cancel_timeout(struct lws_ss_handle *h);
/**
* lws_ss_to_user_object() - convenience helper to get user object from handle
*
* \param h: secure streams handle
*
* Returns the user allocation related to the handle. Normally you won't need
* this since it's available in the rx, tx and state callbacks as "userdata"
* already.
*/
LWS_VISIBLE LWS_EXTERN void *
lws_ss_to_user_object(struct lws_ss_handle *h);
/**
* lws_ss_rideshare() - find the current streamtype when types rideshare
*
* \param h: the stream handle
*
* Under some conditions, the payloads may be structured using protocol-
* specific formatting, eg, http multipart mime. It's possible to map the
* logical partitions in the payload to different stream types using
* the policy "rideshare" feature.
*
* This api lets the callback code find out which rideshare stream type the
* current payload chunk belongs to.
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_ss_rideshare(struct lws_ss_handle *h);
/**
* lws_ss_set_metadata() - allow user to bind external data to defined ss metadata
*
* \param h: secure streams handle
* \param name: metadata name from the policy
* \param value: pointer to user-managed data to bind to name
* \param len: length of the user-managed data in value
*
* Binds user-managed data to the named metadata item from the ss policy.
* If present, the metadata item is handled in a protocol-specific way using
* the associated policy information. For example, in the policy
*
* "\"metadata\":" "["
* "{\"uptag\":" "\"X-Upload-Tag:\"},"
* "{\"ctype\":" "\"Content-Type:\"},"
* "{\"xctype\":" "\"\"}"
* "],"
*
* when the policy is using h1 is interpreted to add h1 headers of the given
* name with the value of the metadata on the left.
*
* Return 0 if OK or nonzero if, eg, metadata name does not exist on the
* streamtype. You must check the result of this, eg, transient OOM can cause
* these to fail and you should retry later.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_ss_set_metadata(struct lws_ss_handle *h, const char *name,
const void *value, size_t len);
/**
* lws_ss_alloc_set_metadata() - copy data and bind to ss metadata
*
* \param h: secure streams handle
* \param name: metadata name from the policy
* \param value: pointer to user-managed data to bind to name
* \param len: length of the user-managed data in value
*
* Same as lws_ss_set_metadata(), but allocates a heap buffer for the data
* first and takes a copy of it, so the original can go out of scope
* immediately after.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_ss_alloc_set_metadata(struct lws_ss_handle *h, const char *name,
const void *value, size_t len);
/**
* lws_ss_get_metadata() - get current value of stream metadata item
*
* \param h: secure streams handle
* \param name: metadata name from the policy
* \param value: pointer to pointer to be set to point at the value
* \param len: pointer to size_t to set to the length of the value
*
* Binds user-managed data to the named metadata item from the ss policy.
* If present, the metadata item is handled in a protocol-specific way using
* the associated policy information. For example, in the policy
*
* "\"metadata\":" "["
* "{\"uptag\":" "\"X-Upload-Tag:\"},"
* "{\"ctype\":" "\"Content-Type:\"},"
* "{\"xctype\":" "\"\"}"
* "],"
*
* when the policy is using h1 is interpreted to add h1 headers of the given
* name with the value of the metadata on the left.
*
* Return 0 if \p *value and \p *len set OK, or nonzero if, eg, metadata \p name does
* not exist on the streamtype.
*
* The pointed-to values may only exist until the next time around the event
* loop.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_get_metadata(struct lws_ss_handle *h, const char *name,
const void **value, size_t *len);
/**
* lws_ss_server_ack() - indicate how we feel about what the server has sent
*
* \param h: ss handle of accepted connection
* \param nack: 0 means we are OK with it, else some problem
*
* For SERVER secure streams
*
* Depending on the protocol, the server sending us something may be
* transactional, ie, built into it sending something is the idea we will
* respond somehow out-of-band; HTTP is like this with, eg, 200 response code.
*
* Calling this with nack=0 indicates that when we later respond, we want to
* acknowledge the transaction (eg, it means a 200 if http underneath), if
* nonzero that the transaction should act like it failed.
*
* If the underlying protocol doesn't understand transactions (eg, ws) then this
* has no effect either way.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ss_server_ack(struct lws_ss_handle *h, int nack);
typedef void (*lws_sssfec_cb)(struct lws_ss_handle *h, void *arg);
/**
* lws_ss_server_foreach_client() - callback for each live client connected to server
*
* \param h: server ss handle
* \param cb: the callback
* \param arg: arg passed to callback
*
* For SERVER secure streams
*
* Call the callback \p cb once for each client ss connected to the server,
* passing \p arg as an additional callback argument each time.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ss_server_foreach_client(struct lws_ss_handle *h, lws_sssfec_cb cb,
void *arg);
/**
* lws_ss_change_handlers() - helper for dynamically changing stream handlers
*
* \param h: ss handle
* \param rx: the new RX handler
* \param tx: the new TX handler
* \param state: the new state handler
*
* Handlers set to NULL are left unchanged.
*
* This works on any handle, client or server and takes effect immediately.
*
* Depending on circumstances this may be helpful when
*
* a) a server stream undergoes an LWSSSCS_SERVER_UPGRADE (as in http -> ws) and
* the payloads in the new protocol have a different purpose that is best
* handled in their own rx and tx callbacks, and
*
* b) you may want to serve several different, possibly large things based on
* what was requested. Setting a customized handler allows clean encapsulation
* of the different serving strategies.
*
* If the stream is long-lived, like ws, you should set the changed handler back
* to the default when the transaction wanting it is completed.
*/
LWS_VISIBLE LWS_EXTERN void
lws_ss_change_handlers(struct lws_ss_handle *h, lws_sscb_rx rx, lws_sscb_tx tx,
lws_sscb_state state);
/**
* lws_ss_add_peer_tx_credit() - allow peer to transmit more to us
*
* \param h: secure streams handle
* \param add: additional tx credit (signed)
*
* Indicate to remote peer that we can accept \p add bytes more payload being
* sent to us.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_add_peer_tx_credit(struct lws_ss_handle *h, int32_t add);
/**
* lws_ss_get_est_peer_tx_credit() - get our current estimate of peer's tx credit
*
* \param h: secure streams handle
*
* Based on what credit we gave it, and what we have received, report our
* estimate of peer's tx credit usable to transmit to us. This may be outdated
* in that some or all of its credit may already have been expended by sending
* stuff to us that is in flight already.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_get_est_peer_tx_credit(struct lws_ss_handle *h);
LWS_VISIBLE LWS_EXTERN const char *
lws_ss_tag(struct lws_ss_handle *h);
/**
* lws_ss_adopt_raw() - bind ss to existing fd
*
* \param ss: pointer to lws_ss_t to adopt the fd
* \param fd: the existing fd
*
* "connects" the existing ss to a wsi adoption of fd, it's useful for cases
* like local representation of eg a pipe() fd using ss.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_adopt_raw(struct lws_ss_handle *ss, lws_sock_file_fd_type fd);
#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
/**
* lws_ss_sigv4_set_aws_key() - set aws credential into system blob
*
* \param context: lws_context
* \param idx: the system blob index specified in the policy, currently
* up to 4 blobs.
* \param keyid: aws access keyid
* \param key: aws access key
*
* Return 0 if OK or nonzero if e.g. idx is invalid; system blob heap appending
* fails.
*/
LWS_VISIBLE LWS_EXTERN int
lws_ss_sigv4_set_aws_key(struct lws_context* context, uint8_t idx,
const char * keyid, const char * key);
/**
* lws_aws_filesystem_credentials_helper() - read aws credentials from file
*
* \param path: path to read, ~ at start is converted to $HOME contents if any
* \param kid: eg, "aws_access_key_id"
* \param ak: eg, "aws_secret_access_key"
* \param aws_keyid: pointer to pointer for allocated keyid from credentials file
* \param aws_key: pointer to pointer for allocated key from credentials file
*
* Return 0 if both *aws_keyid and *aws_key allocated from the config file, else
* nonzero, and neither *aws_keyid or *aws_key are allocated.
*
* If *aws_keyid and *aws_key are set, it's the user's responsibility to
* free() them when they are no longer needed.
*/
LWS_VISIBLE LWS_EXTERN int
lws_aws_filesystem_credentials_helper(const char *path, const char *kid,
const char *ak, char **aws_keyid,
char **aws_key);
#endif
#if defined(STANDALONE)
#undef lws_context
#endif
///@}

View File

@ -0,0 +1,202 @@
/*
* 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 service Built-in service loop entry
*
* ##Built-in service loop entry
*
* If you're not using libev / libuv, these apis are needed to enter the poll()
* wait in lws and service any connections with pending events.
*/
///@{
/**
* lws_service() - Service any pending websocket activity
* \param context: Websocket context
* \param timeout_ms: Set to 0; ignored; for backward compatibility
*
* This function deals with any pending websocket traffic, for three
* kinds of event. It handles these events on both server and client
* types of connection the same.
*
* 1) Accept new connections to our context's server
*
* 2) Call the receive callback for incoming frame data received by
* server or client connections.
*
* Since v3.2 internally the timeout wait is ignored, the lws scheduler is
* smart enough to stay asleep until an event is queued.
*/
LWS_VISIBLE LWS_EXTERN int
lws_service(struct lws_context *context, int timeout_ms);
/**
* lws_service_tsi() - Service any pending websocket activity
*
* \param context: Websocket context
* \param timeout_ms: Set to 0; ignored; for backwards compatibility
* \param tsi: Thread service index, starting at 0
*
* Same as lws_service(), but for a specific thread service index. Only needed
* if you are spawning multiple service threads that operate on the same lws_context.
*/
LWS_VISIBLE LWS_EXTERN int
lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi);
/**
* lws_cancel_service_pt() - Cancel servicing of pending socket activity
* on one thread
* \param wsi: Cancel service on the thread this wsi is serviced by
*
* Same as lws_cancel_service(), but targets a single service thread, the one
* the wsi belongs to. You probably want to use lws_cancel_service() instead.
*/
LWS_VISIBLE LWS_EXTERN void
lws_cancel_service_pt(struct lws *wsi);
/**
* lws_cancel_service() - Cancel wait for new pending socket activity
* \param context: Websocket context
*
* This function creates an immediate "synchronous interrupt" to the lws poll()
* wait or event loop. As soon as possible in the serialzed service sequencing,
* a LWS_CALLBACK_EVENT_WAIT_CANCELLED callback is sent to every protocol on
* every vhost.
*
* lws_cancel_service() may be called from another thread while the context
* exists, and its effect will be immediately serialized.
*/
LWS_VISIBLE LWS_EXTERN void
lws_cancel_service(struct lws_context *context);
/**
* lws_service_fd() - Service polled socket with something waiting
* \param context: Websocket context
* \param pollfd: The pollfd entry describing the socket fd and which events
* happened
*
* This function takes a pollfd that has POLLIN or POLLOUT activity and
* services it according to the state of the associated
* struct lws.
*
* The one call deals with all "service" that might happen on a socket
* including listen accepts, http files as well as websocket protocol.
*
* If a pollfd says it has something, you can just pass it to
* lws_service_fd() whether it is a socket handled by lws or not.
* If it sees it is a lws socket, the traffic will be handled and
* pollfd->revents will be zeroed now.
*
* If the socket is foreign to lws, it leaves revents alone. So you can
* see if you should service yourself by checking the pollfd revents
* after letting lws try to service it.
*
* lws before v3.2 allowed pollfd to be NULL, to indicate that background
* periodic processing should be done. Since v3.2, lws schedules any items
* that need handling in the future using lws_sul and NULL is no longer valid.
*/
LWS_VISIBLE LWS_EXTERN int
lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd);
/**
* lws_service_fd_tsi() - Service polled socket in specific service thread
* \param context: Websocket context
* \param pollfd: The pollfd entry describing the socket fd and which events
* happened.
* \param tsi: thread service index
*
* Same as lws_service_fd() but used with multiple service threads
*/
LWS_VISIBLE LWS_EXTERN int
lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
int tsi);
/**
* lws_service_adjust_timeout() - Check for any connection needing forced service
* \param context: Websocket context
* \param timeout_ms: The original poll timeout value. You can just set this
* to 1 if you don't really have a poll timeout.
* \param tsi: thread service index
*
* Under some conditions connections may need service even though there is no
* pending network action on them, this is "forced service". For default
* poll() and libuv / libev, the library takes care of calling this and
* dealing with it for you. But for external poll() integration, you need
* access to the apis.
*
* If anybody needs "forced service", returned timeout is zero. In that case,
* you can call lws_service_tsi() with a timeout of -1 to only service
* guys who need forced service.
*/
LWS_VISIBLE LWS_EXTERN int
lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi);
/* Backwards compatibility */
#define lws_plat_service_tsi lws_service_tsi
LWS_VISIBLE LWS_EXTERN int
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
///@}
/*! \defgroup uv libuv helpers
*
* ##libuv helpers
*
* APIs specific to libuv event loop itegration
*/
///@{
#if defined(LWS_WITH_LIBUV) && defined(UV_ERRNO_MAP)
/*
* Any direct libuv allocations in lws protocol handlers must participate in the
* lws reference counting scheme. Two apis are provided:
*
* - lws_libuv_static_refcount_add(handle, context, tsi) to mark the handle with
* a pointer to the context and increment the global uv object counter
*
* - lws_libuv_static_refcount_del() which should be used as the close callback
* for your own libuv objects declared in the protocol scope.
*
* Using the apis allows lws to detach itself from a libuv loop completely
* cleanly and at the moment all of its libuv objects have completed close.
*/
LWS_VISIBLE LWS_EXTERN uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_static_refcount_add(uv_handle_t *, struct lws_context *context,
int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_static_refcount_del(uv_handle_t *);
#endif /* LWS_WITH_LIBUV */
#if defined(LWS_PLAT_FREERTOS)
#define lws_libuv_static_refcount_add(_a, _b, _c)
#define lws_libuv_static_refcount_del NULL
#endif
///@}

View File

@ -0,0 +1,112 @@
/*
* Generic Settings storage
*
* Copyright (C) 2020 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.
*
*
* This is like an abstract class for non-volatile storage, whether in a file-
* system or flash-backed blocks, etc. Named blobs of variable size are stored
* in nonvolatile media of some sort. Typically, these are JSON objects under
* a naming scheme like, eg, "network".
*
* There's a platform-specific storage identifier opaque_plat provided when the
* storage object is instantiated, this describes eg the storage device or
* partition in instantiation-specific terms.
*
* Blobs have a further "filename" associated with them.
*/
#define LSOOPEN_FLAG_WRITEABLE (1 << 0)
struct lws_settings_ops;
typedef struct {
void *handle_plat;
const struct lws_settings_ops *so;
uint8_t refcount;
void *opaque_plat;
} lws_settings_instance_t;
typedef struct lws_settings_ops {
int (*get)(lws_settings_instance_t *si, const char *name,
uint8_t *dest, size_t *max_actual);
/**< if dest is NULL, max_actual is set to the actual length without
* copying anything out */
int (*set)(lws_settings_instance_t *si, const char *name,
const uint8_t *src, size_t len);
} lws_settings_ops_t;
/**
* lws_settings_plat_get() - read a named blob from a settings instance
*
* \param si: the settings instance
* \param name: the name of the setting blob in the instance
* \param dest: NULL, or the buffer to copy the setting blob info
* \param max_actual: point to size of dest, or zero; actual blob size on exit
*
* If the named blob doesn't exist in the si, or can't read, returns nonzero.
* Otherwise, returns 0 and sets *max_actual to the true blob size. If dest is
* non-NULL, as much of the blob as will fit in the amount specified by
* *max_actual on entry is copied to dest.
*/
LWS_VISIBLE LWS_EXTERN int
lws_settings_plat_get(lws_settings_instance_t *si, const char *name,
uint8_t *dest, size_t *max_actual);
/**
* lws_settings_plat_get() - read a named blob from a settings instance
*
* \param si: the settings instance
* \param name: the name of the setting blob in the instance
* \param src: blob to copy to settings instance
* \param len: length of blob to copy
*
* Creates or replaces a settings blob of the given name made up of the \p len
* bytes of data from \p src.
*/
LWS_VISIBLE LWS_EXTERN int
lws_settings_plat_set(lws_settings_instance_t *si, const char *name,
const uint8_t *src, size_t len);
/**
* lws_settings_plat_printf() - read a named blob from a settings instance
*
* \param si: the settings instance
* \param name: the name of the setting blob in the instance
* \param format: printf-style format string
*
* Creates or replaces a settings blob of the given name from the printf-style
* format string and arguments provided. There's no specific limit to the size,
* the size is computed and then a temp heap buffer used.
*/
LWS_VISIBLE LWS_EXTERN int
lws_settings_plat_printf(lws_settings_instance_t *si, const char *name,
const char *format, ...) LWS_FORMAT(3);
#define lws_settings_ops_plat \
.get = lws_settings_plat_get, \
.set = lws_settings_plat_set,
LWS_VISIBLE LWS_EXTERN lws_settings_instance_t *
lws_settings_init(const lws_settings_ops_t *so, void *opaque_plat);
LWS_VISIBLE LWS_EXTERN void
lws_settings_deinit(lws_settings_instance_t **si);

View File

@ -0,0 +1,113 @@
/*
* 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 sha SHA and B64 helpers
* ##SHA and B64 helpers
*
* These provide SHA-1 and B64 helper apis
*/
///@{
#ifdef LWS_SHA1_USE_OPENSSL_NAME
#define lws_SHA1 SHA1
#else
/**
* lws_SHA1(): make a SHA-1 digest of a buffer
*
* \param d: incoming buffer
* \param n: length of incoming buffer
* \param md: buffer for message digest (must be >= 20 bytes)
*
* Reduces any size buffer into a 20-byte SHA-1 hash.
*/
LWS_VISIBLE LWS_EXTERN unsigned char *
lws_SHA1(const unsigned char *d, size_t n, unsigned char *md);
#endif
/**
* lws_b64_encode_string(): encode a string into base 64
*
* \param in: incoming buffer
* \param in_len: length of incoming buffer
* \param out: result buffer
* \param out_size: length of result buffer
*
* Encodes a string using b64
*/
LWS_VISIBLE LWS_EXTERN int
lws_b64_encode_string(const char *in, int in_len, char *out, int out_size);
/**
* lws_b64_encode_string_url(): encode a string into base 64
*
* \param in: incoming buffer
* \param in_len: length of incoming buffer
* \param out: result buffer
* \param out_size: length of result buffer
*
* Encodes a string using b64 with the "URL" variant (+ -> -, and / -> _)
*/
LWS_VISIBLE LWS_EXTERN int
lws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size);
/**
* lws_b64_decode_string(): decode a string from base 64
*
* \param in: incoming buffer
* \param out: result buffer
* \param out_size: length of result buffer
*
* Decodes a NUL-terminated string using b64
*
* Returns used length of output buffer
*/
LWS_VISIBLE LWS_EXTERN int
lws_b64_decode_string(const char *in, char *out, int out_size);
/**
* lws_b64_decode_string_len(): decode a string from base 64
*
* \param in: incoming buffer
* \param in_len: length of incoming buffer
* \param out: result buffer
* \param out_size: length of result buffer
*
* Decodes a range of chars using b64
*
* Returns used length of output buffer
*/
LWS_VISIBLE LWS_EXTERN int
lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size);
struct lws_b64state {
unsigned char quad[4];
size_t done;
size_t len;
int i;
int c;
};
LWS_VISIBLE LWS_EXTERN void
lws_b64_decode_state_init(struct lws_b64state *state);
LWS_VISIBLE LWS_EXTERN int
lws_b64_decode_stateful(struct lws_b64state *s, const char *in, size_t *in_len,
uint8_t *out, size_t *out_size, int final);
///@}

View File

@ -0,0 +1,227 @@
/*
* lws System Message Distribution
*
* Copyright (C) 2010 - 2020 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.
*/
#define LWS_SMD_MAX_PAYLOAD 384
#define LWS_SMD_CLASS_BITFIELD_BYTES 4
#define LWS_SMD_STREAMTYPENAME "_lws_smd"
#define LWS_SMD_SS_RX_HEADER_LEN 16
typedef uint32_t lws_smd_class_t;
struct lws_smd_msg; /* opaque */
struct lws_smd_peer; /* opaque */
/*
* Well-known device classes
*/
enum {
LWSSMDCL_INTERACTION = (1 << 0),
/**<
* Any kind of event indicating a user was interacting with the device,
* eg, press a button, touched the screen, lifted the device etc
*/
LWSSMDCL_SYSTEM_STATE = (1 << 1),
/**<
* The lws_system state changed, eg, to OPERATIONAL
*/
LWSSMDCL_NETWORK = (1 << 2),
/**<
* Something happened on the network, eg, link-up or DHCP, or captive
* portal state update
*/
LWSSMDCL_METRICS = (1 << 3),
/**<
* An SS client process is reporting a metric to the proxy (this class
* is special in that it is not rebroadcast by the proxy)
*/
LWSSMDCL_USER_BASE_BITNUM = 24
};
/**
* lws_smd_msg_alloc() - allocate a message of length len
*
* \param ctx: the lws_context
* \param _class: the smd message class, recipients filter on this
* \param len: the required payload length
*
* This helper returns an opaque lws_smd_msg pointer and sets *buf to a buffer
* associated with it of length \p len.
*
* In this way the lws_msg_smd type remains completely opaque and the allocated
* area can be prepared by the caller directly, without copying.
*
* On failure, it returns NULL... it may fail for OOM but it may also fail if
* you request to allocate for a message class that the system has no
* participant who is listening for that class of event currently... the event
* generation action at the caller should be bypassed without error then.
*
* This is useful if you have a message you know the length of. For text-based
* messages like JSON, lws_smd_msg_printf() is more convenient.
*/
LWS_VISIBLE LWS_EXTERN void * /* payload */
lws_smd_msg_alloc(struct lws_context *ctx, lws_smd_class_t _class, size_t len);
/**
* lws_smd_msg_free() - abandon a previously allocated message before sending
*
* \param payload: pointer the previously-allocated message payload
*
* Destroys a previously-allocated opaque message object and the requested
* buffer space, in the case that between allocating it and sending it, some
* condition was met that means it can no longer be sent, eg, an error
* generating the content. Otherwise there is no need to destroy allocated
* message objects with this, lws will take care of it.
*/
LWS_VISIBLE LWS_EXTERN void
lws_smd_msg_free(void **payload);
/**
* lws_smd_msg_send() - queue a previously allocated message
*
* \param ctx: the lws_context
* \param msg: the prepared message
*
* Queues an allocated, prepared message for delivery to smd clients
*
* This is threadsafe to call from a non-service thread.
*/
LWS_VISIBLE LWS_EXTERN int
lws_smd_msg_send(struct lws_context *ctx, void *payload);
/**
* lws_smd_msg_printf() - queue a previously allocated message
*
* \param ctx: the lws_context
* \param _class: the message class
* \param format: the format string to prepare the payload with
* \param ...: arguments for the format string, if any
*
* For string-based messages, eg, JSON, allows formatted creating of the payload
* size discovery, allocation and message send all in one step.
*
* Unlike lws_smd_msg_alloc() you do not need to know the length beforehand as
* this computes it and calls lws_smd_msg_alloc() with the correct length.
*
* To be clear this also calls through to lws_smd_msg_send(), it really does
* everything in one step. If there are no registered participants that want
* messages of \p _class, this function returns immediately without doing any
* allocation or anything else.
*
* This is threadsafe to call from a non-service thread.
*/
LWS_VISIBLE LWS_EXTERN int
lws_smd_msg_printf(struct lws_context *ctx, lws_smd_class_t _class,
const char *format, ...) LWS_FORMAT(3);
/**
* lws_smd_ss_msg_printf() - helper to prepare smd ss message tx
*
* \param h: the ss handle
* \param buf: the ss tx buffer
* \param len: on entry, points to the ss tx buffer length, on exit, set to used
* \param _class: the message class
* \param format: the format string to prepare the payload with
* \param ...: arguments for the format string, if any
*
* This helper lets you produce SMD messages on an SS link of the builtin
* streamtype LWS_SMD_STREAMTYPENAME, using the same api format as
* lws_smd_msg_prinf(), but writing the message into the ss tx buffer from
* its tx() callback.
*/
struct lws_ss_handle;
LWS_VISIBLE LWS_EXTERN int
lws_smd_ss_msg_printf(const char *tag, uint8_t *buf, size_t *len,
lws_smd_class_t _class, const char *format, ...)
LWS_FORMAT(5);
/**
* lws_smd_ss_rx_forward() - helper to forward smd messages that came in by SS
*
* \param ss_user: ss user pointer, as delivered to rx callback
* \param buf: the ss rx buffer
* \param len: the length of the ss rx buffer
*
* Proxied Secure Streams with the streamtype LWS_SMD_STREAMTYPENAME receive
* serialized SMD messages from the proxy, this helper allows them to be
* translated into deserialized SMD messages and forwarded to registered SMD
* participants in the local context in one step.
*
* Just pass through what arrived in the LWS_SMD_STREAMTYPENAME rx() callback
* to this api.
*
* Returns 0 if OK else nonzero if unable to queue the SMD message.
*/
LWS_VISIBLE LWS_EXTERN int
lws_smd_ss_rx_forward(void *ss_user, const uint8_t *buf, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_smd_sspc_rx_forward(void *ss_user, const uint8_t *buf, size_t len);
typedef int (*lws_smd_notification_cb_t)(void *opaque, lws_smd_class_t _class,
lws_usec_t timestamp, void *buf,
size_t len);
#define LWSSMDREG_FLAG_PROXIED_SS (1 << 0)
/**< It's actually a proxied SS connection registering, opaque is the ss h */
/*
* lws_smd_register() - register to receive smd messages
*
* \param ctx: the lws_context
* \param opaque: an opaque pointer handed to the callback
* \param flags: typically 0
* \param _class_filter: bitmap of message classes we care about
* \param cb: the callback to receive messages
*
* Queues an allocated, prepared message for delivery to smd clients.
*
* Returns NULL on failure, or an opaque handle which may be given to
* lws_smd_unregister() to stop participating in the shared message queue.
*
* This is threadsafe to call from a non-service thread.
*/
LWS_VISIBLE LWS_EXTERN struct lws_smd_peer *
lws_smd_register(struct lws_context *ctx, void *opaque, int flags,
lws_smd_class_t _class_filter, lws_smd_notification_cb_t cb);
/*
* lws_smd_unregister() - unregister receiving smd messages
*
* \param pr: the handle returned from the registration
*
* Destroys the registration of the callback for messages and ability to send
* messages.
*
* It's not necessary to call this if the registration wants to survive for as
* long as the lws_context... lws_context_destroy will also clean up any
* registrations still active by then.
*/
LWS_VISIBLE LWS_EXTERN void
lws_smd_unregister(struct lws_smd_peer *pr);

View File

@ -0,0 +1,177 @@
/*
* 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 form-parsing Form Parsing
* \ingroup http
* ##POSTed form parsing functions
*
* These lws_spa (stateful post arguments) apis let you parse and urldecode
* POSTed form arguments, both using simple urlencoded and multipart transfer
* encoding.
*
* It's capable of handling file uploads as well a named input parsing,
* and the apis are the same for both form upload styles.
*
* You feed it a list of parameter names and it creates pointers to the
* urldecoded arguments: file upload parameters pass the file data in chunks to
* a user-supplied callback as they come.
*
* Since it's stateful, it handles the incoming data needing more than one
* POST_BODY callback and has no limit on uploaded file size.
*/
///@{
/** enum lws_spa_fileupload_states */
enum lws_spa_fileupload_states {
LWS_UFS_CONTENT,
/**< a chunk of file content has arrived */
LWS_UFS_FINAL_CONTENT,
/**< the last chunk (possibly zero length) of file content has arrived */
LWS_UFS_OPEN,
/**< a new file is starting to arrive */
LWS_UFS_CLOSE
/**< the file decode stuff is being destroyed */
};
/**
* lws_spa_fileupload_cb() - callback to receive file upload data
*
* \param data: opt_data pointer set in lws_spa_create
* \param name: name of the form field being uploaded
* \param filename: original filename from client
* \param buf: start of data to receive
* \param len: length of data to receive
* \param state: information about how this call relates to file
*
* Notice name and filename shouldn't be trusted, as they are passed from
* HTTP provided by the client.
*/
typedef int (*lws_spa_fileupload_cb)(void *data, const char *name,
const char *filename, char *buf, int len,
enum lws_spa_fileupload_states state);
/** struct lws_spa - opaque urldecode parser capable of handling multipart
* and file uploads */
struct lws_spa;
/**
* lws_spa_create() - create urldecode parser
*
* \param wsi: lws connection (used to find Content Type)
* \param param_names: array of form parameter names, like "username"
* \param count_params: count of param_names
* \param max_storage: total amount of form parameter values we can store
* \param opt_cb: NULL, or callback to receive file upload data.
* \param opt_data: NULL, or user pointer provided to opt_cb.
*
* Creates a urldecode parser and initializes it.
*
* It's recommended to use the newer api, lws_spa_create_via_info()
* instead.
*
* opt_cb can be NULL if you just want normal name=value parsing, however
* if one or more entries in your form are bulk data (file transfer), you
* can provide this callback and filter on the name callback parameter to
* treat that urldecoded data separately. The callback should return -1
* in case of fatal error, and 0 if OK.
*/
LWS_VISIBLE LWS_EXTERN struct lws_spa *
lws_spa_create(struct lws *wsi, const char * const *param_names,
int count_params, int max_storage, lws_spa_fileupload_cb opt_cb,
void *opt_data);
typedef struct lws_spa_create_info {
const char * const *param_names; /**< array of form parameter names, like "username"
These may be NULL, to make space for arbitrary POST items */
int count_params; /* count of param_names */
int max_storage; /* total amount of form parameter values we can store */
lws_spa_fileupload_cb opt_cb; /* NULL, or callback to receive file upload data. */
void *opt_data; /* NULL, or user pointer provided to opt_cb. */
size_t param_names_stride; /* 0 if param_names is an array of char *.
Else stride to next char * */
struct lwsac **ac; /* NULL, or pointer to lwsac * to contain all
related heap allocations */
size_t ac_chunk_size; /* 0 for default, or ac chunk size */
} lws_spa_create_info_t;
/**
* lws_spa_create_via_info() - create urldecode parser
*
* \param wsi: lws connection (used to find Content Type)
* \param info: pointer to struct defining the arguments
*
* Creates a urldecode parser and initializes it.
*
* opt_cb can be NULL if you just want normal name=value parsing, however
* if one or more entries in your form are bulk data (file transfer), you
* can provide this callback and filter on the name callback parameter to
* treat that urldecoded data separately. The callback should return -1
* in case of fatal error, and 0 if OK.
*/
LWS_VISIBLE LWS_EXTERN struct lws_spa *
lws_spa_create_via_info(struct lws *wsi, const lws_spa_create_info_t *info);
/**
* lws_spa_process() - parses a chunk of input data
*
* \param spa: the parser object previously created
* \param in: incoming urlencoded data
* \param len: count of bytes valid at \p in
*/
LWS_VISIBLE LWS_EXTERN int
lws_spa_process(struct lws_spa *spa, const char *in, int len);
/**
* lws_spa_finalize() - indicate incoming data completed
*
* \param spa: the parser object previously created
*/
LWS_VISIBLE LWS_EXTERN int
lws_spa_finalize(struct lws_spa *spa);
/**
* lws_spa_get_length() - return length of parameter value
*
* \param spa: the parser object previously created
* \param n: parameter ordinal to return length of value for
*/
LWS_VISIBLE LWS_EXTERN int
lws_spa_get_length(struct lws_spa *spa, int n);
/**
* lws_spa_get_string() - return pointer to parameter value
* \param spa: the parser object previously created
* \param n: parameter ordinal to return pointer to value for
*/
LWS_VISIBLE LWS_EXTERN const char *
lws_spa_get_string(struct lws_spa *spa, int n);
/**
* lws_spa_destroy() - destroy parser object
*
* \param spa: the parser object previously created
*/
LWS_VISIBLE LWS_EXTERN int
lws_spa_destroy(struct lws_spa *spa);
///@}

View File

@ -0,0 +1,55 @@
/*
* lws abstract display implementation for epd-acep on spi
*
* Copyright (C) 2019 - 2022 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.
*/
#if !defined(__LWS_DISPLAY_SPD1656_SPI_H__)
#define __LWS_DISPLAY_SPD1656_SPI_H__
typedef struct lws_display_spd1656_spi {
lws_display_t disp; /* use lws_display_spd1656_ops to set */
const lws_spi_ops_t *spi; /* spi ops */
lws_display_completion_t cb;
const lws_gpio_ops_t *gpio; /* NULL or gpio ops */
_lws_plat_gpio_t reset_gpio; /* if gpio ops, nReset gpio # */
_lws_plat_gpio_t busy_gpio; /* if gpio ops, busy gpio # */
uint8_t spi_index; /* cs index starting from 0 */
} lws_display_spd1656_spi_t;
int
lws_display_spd1656_spi_init(lws_display_state_t *lds);
int
lws_display_spd1656_spi_blit(lws_display_state_t *lds, const uint8_t *src,
lws_box_t *box, lws_dll2_owner_t *ids);
int
lws_display_spd1656_spi_power(lws_display_state_t *lds, int state);
#define lws_display_spd1656_ops \
.init = lws_display_spd1656_spi_init, \
.blit = lws_display_spd1656_spi_blit, \
.power = lws_display_spd1656_spi_power
#endif

View File

@ -0,0 +1,93 @@
/*
* Generic I2C ops
*
* Copyright (C) 2019 - 2020 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.
*
* This is like an abstract class for spi, a real implementation provides
* functions for the ops that use the underlying OS arrangements.
*
* It uses descriptor / queuing semantics but eg the GPIO BB implementantion is
* synchronous.
*/
#if !defined(__LWS_SPI_H__)
#define __LWS_SPI_H__
#include <stdint.h>
#include <stddef.h>
typedef int (*lws_spi_cb_t)(void *opaque);
enum {
LWSSPIMODE_CPOL = (1 << 0),
LWSSPIMODE_CPHA = (1 << 1),
LWS_SPI_BUSMODE_CLK_IDLE_LOW_SAMP_RISING = 0,
LWS_SPI_BUSMODE_CLK_IDLE_HIGH_SAMP_RISING = LWSSPIMODE_CPOL,
LWS_SPI_BUSMODE_CLK_IDLE_LOW_SAMP_FALLING = LWSSPIMODE_CPHA,
LWS_SPI_BUSMODE_CLK_IDLE_HIGH_SAMP_FALLING = LWSSPIMODE_CPHA |
LWSSPIMODE_CPOL,
LWS_SPI_TXN_HALF_DUPLEX_DISCRETE = 0,
/**< separate MISO and MOSI, but only either MISO or MOSI has data at
* one time... i2c style in SPI */
LWS_SPI_FLAG_DATA_CONTINUE = (1 << 0),
/**< leave without finalizing the SPI transaction */
LWS_SPI_FLAG_DC_CMD_IS_HIGH = (1 << 1),
/**< It's normally 0 for cmd phase, invert with this flag */
LWS_SPI_FLAG_DMA_BOUNCE_NOT_NEEDED = (1 << 2),
/**< It's normally 0 for cmd phase, invert with this flag */
};
typedef struct lws_spi_desc {
const uint8_t *src;
const uint8_t *data;
uint8_t *dest;
void *opaque;
lws_spi_cb_t completion_cb;
uint16_t count_cmd;
uint16_t count_write;
uint16_t count_read;
uint8_t txn_type;
uint8_t channel;
uint8_t flags;
} lws_spi_desc_t;
typedef struct lws_spi_ops {
int (*init)(const struct lws_spi_ops *ctx);
int (*queue)(const struct lws_spi_ops *ctx, const lws_spi_desc_t *desc);
void * (*alloc_dma)(const struct lws_spi_ops *ctx, size_t size);
void (*free_dma)(const struct lws_spi_ops *ctx, void **p);
int (*in_flight)(const struct lws_spi_ops *ctx);
uint32_t spi_clk_hz;
uint8_t bus_mode;
} lws_spi_ops_t;
LWS_VISIBLE LWS_EXTERN int
lws_spi_table_issue(const lws_spi_ops_t *spi_ops, uint32_t flags, const uint8_t *p, size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_spi_readback(const lws_spi_ops_t *spi_ops, uint32_t flags,
const uint8_t *p, size_t len, uint8_t *rb, size_t rb_len);
#endif

View File

@ -0,0 +1,64 @@
/*
* lws abstract display implementation for ssd1306 on i2c
*
* Copyright (C) 2019 - 2022 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.
*/
#if !defined(__LWS_DISPLAY_SSD1306_I2C_H__)
#define __LWS_DISPLAY_SSD1306_I2C_H__
/*
* D/C# pin on SSD1306 sets the I2C device ads
* from these two options (7-bit address)
*/
#define SSD1306_I2C7_ADS1 0x3c
#define SSD1306_I2C7_ADS2 0x3d
typedef struct lws_display_ssd1306 {
lws_display_t disp; /* use lws_display_ssd1306_ops to set ops */
const lws_i2c_ops_t *i2c; /* i2c ops */
lws_display_completion_t cb;
const lws_gpio_ops_t *gpio; /* NULL or gpio ops */
_lws_plat_gpio_t reset_gpio; /* if gpio ops, nReset gpio # */
uint8_t i2c7_address; /* one of SSD1306_I2C7_ADS... */
} lws_display_ssd1306_t;
int
lws_display_ssd1306_i2c_init(lws_display_state_t *lds);
int
lws_display_ssd1306_i2c_contrast(lws_display_state_t *lds, uint8_t b);
int
lws_display_ssd1306_i2c_blit(lws_display_state_t *lds, const uint8_t *src,
lws_box_t *box, lws_dll2_owner_t *ids);
int
lws_display_ssd1306_i2c_power(lws_display_state_t *lds, int state);
#define lws_display_ssd1306_ops \
.init = lws_display_ssd1306_i2c_init, \
.contrast = lws_display_ssd1306_i2c_contrast, \
.blit = lws_display_ssd1306_i2c_blit, \
.power = lws_display_ssd1306_i2c_power
#endif

View File

@ -0,0 +1,55 @@
/*
* lws abstract display implementation for SSD1675B on spi
*
* Copyright (C) 2019 - 2022 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.
*/
#if !defined(__LWS_DISPLAY_SSD1675B_SPI_H__)
#define __LWS_DISPLAY_SSD1675B_SPI_H__
typedef struct lws_display_ssd1675b_spi {
lws_display_t disp; /* use lws_display_ssd1675b_ops to set */
const lws_spi_ops_t *spi; /* spi ops */
lws_display_completion_t cb;
const lws_gpio_ops_t *gpio; /* NULL or gpio ops */
_lws_plat_gpio_t reset_gpio; /* if gpio ops, nReset gpio # */
_lws_plat_gpio_t busy_gpio; /* if gpio ops, busy gpio # */
uint8_t spi_index; /* cs index starting from 0 */
} lws_display_ssd1675b_spi_t;
int
lws_display_ssd1675b_spi_init(lws_display_state_t *lds);
int
lws_display_ssd1675b_spi_blit(lws_display_state_t *lds, const uint8_t *src,
lws_box_t *box);
int
lws_display_ssd1675b_spi_power(lws_display_state_t *lds, int state);
#define lws_display_ssd1675b_ops \
.init = lws_display_ssd1675b_spi_init, \
.blit = lws_display_ssd1675b_spi_blit, \
.power = lws_display_ssd1675b_spi_power
#endif

View File

@ -0,0 +1,119 @@
/*
* 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;
#if defined(LWS_WITH_SYS_STATE)
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;
struct lws_context *context;
void *parent;
#if defined(LWS_WITH_SYS_SMD)
lws_smd_class_t smd_class;
#endif
/**< optional opaque pointer to owning object... useful to make such
* a pointer available to a notification callback. Ignored by lws */
const char **state_names;
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_deregister() - deregister a notifier
*
* \param nl: notification hardler to deregister
*
* Remove a notification handler from its state manager
*/
LWS_EXTERN LWS_VISIBLE void
lws_state_reg_deregister(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 * const *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);
#else
#endif

View File

@ -0,0 +1,284 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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.
*/
#if defined(LWS_WITH_STRUCT_SQLITE3)
#include <sqlite3.h>
#endif
typedef enum {
LSMT_SIGNED,
LSMT_UNSIGNED,
LSMT_BOOLEAN,
LSMT_STRING_CHAR_ARRAY,
LSMT_STRING_PTR,
LSMT_LIST,
LSMT_CHILD_PTR,
LSMT_SCHEMA,
LSMT_BLOB_PTR,
} lws_struct_map_type_eum;
typedef struct lejp_collation {
struct lws_dll2 chunks;
int len;
char buf[LEJP_STRING_CHUNK + 1];
} lejp_collation_t;
typedef struct lws_struct_map {
const char *colname;
const struct lws_struct_map *child_map;
lejp_callback lejp_cb;
size_t ofs; /* child dll2; points to dll2_owner */
size_t aux;
size_t ofs_clist;
size_t child_map_size;
lws_struct_map_type_eum type;
} lws_struct_map_t;
typedef int (*lws_struct_args_cb)(void *obj, void *cb_arg);
typedef struct lws_struct_args {
const lws_struct_map_t *map_st[LEJP_MAX_PARSING_STACK_DEPTH];
lws_struct_args_cb cb;
struct lwsac *ac;
void *cb_arg;
void *dest;
size_t dest_len;
size_t toplevel_dll2_ofs;
size_t map_entries_st[LEJP_MAX_PARSING_STACK_DEPTH];
size_t ac_block_size;
int subtype;
int top_schema_index;
/*
* temp ac used to collate unknown possibly huge strings before final
* allocation and copy
*/
struct lwsac *ac_chunks;
struct lws_dll2_owner chunks_owner;
size_t chunks_length;
} lws_struct_args_t;
#define LSM_SIGNED(type, name, qname) \
{ \
qname, \
NULL, \
NULL, \
offsetof(type, name), \
sizeof ((type *)0)->name, \
0, \
0, \
LSMT_SIGNED \
}
#define LSM_UNSIGNED(type, name, qname) \
{ \
qname, \
NULL, \
NULL, \
offsetof(type, name), \
sizeof ((type *)0)->name, \
0, \
0, \
LSMT_UNSIGNED \
}
#define LSM_BOOLEAN(type, name, qname) \
{ \
qname, \
NULL, \
NULL, \
offsetof(type, name), \
sizeof ((type *)0)->name, \
0, \
0, \
LSMT_BOOLEAN \
}
#define LSM_CARRAY(type, name, qname) \
{ \
qname, \
NULL, \
NULL, \
offsetof(type, name), \
sizeof (((type *)0)->name), \
0, \
0, \
LSMT_STRING_CHAR_ARRAY \
}
#define LSM_STRING_PTR(type, name, qname) \
{ \
qname, \
NULL, \
NULL, \
offsetof(type, name), \
sizeof (((type *)0)->name), \
0, \
0, \
LSMT_STRING_PTR \
}
#define LSM_LIST(ptype, pname, ctype, cname, lejp_cb, cmap, qname) \
{ \
qname, \
cmap, \
lejp_cb, \
offsetof(ptype, pname), \
sizeof (ctype), \
offsetof(ctype, cname), \
LWS_ARRAY_SIZE(cmap), \
LSMT_LIST \
}
#define LSM_CHILD_PTR(ptype, pname, ctype, lejp_cb, cmap, qname) \
{ \
qname, \
cmap, \
lejp_cb, \
offsetof(ptype, pname), \
sizeof (ctype), \
0, \
LWS_ARRAY_SIZE(cmap), \
LSMT_CHILD_PTR \
}
#define LSM_SCHEMA(ctype, lejp_cb, map, schema_name) \
{ \
schema_name, \
map, \
lejp_cb, \
0, \
sizeof (ctype), \
0, \
LWS_ARRAY_SIZE(map), \
LSMT_SCHEMA \
}
#define LSM_SCHEMA_DLL2(ctype, cdll2mem, lejp_cb, map, schema_name) \
{ \
schema_name, \
map, \
lejp_cb, \
offsetof(ctype, cdll2mem), \
sizeof (ctype), \
0, \
LWS_ARRAY_SIZE(map), \
LSMT_SCHEMA \
}
/*
* This is just used to create the table schema, it is not part of serialization
* and deserialization. Blobs should be accessed separately.
*/
#define LSM_BLOB_PTR(type, blobptr_name, qname) \
{ \
qname, /* JSON item, or sqlite3 column name */ \
NULL, \
NULL, \
offsetof(type, blobptr_name), /* member that points to blob */ \
sizeof (((type *)0)->blobptr_name), /* size of blob pointer */ \
0, /* member holding blob len */ \
0, /* size of blob length member */ \
LSMT_BLOB_PTR \
}
typedef struct lws_struct_serialize_st {
const struct lws_dll2 *dllpos;
const lws_struct_map_t *map;
const char *obj;
size_t map_entries;
size_t map_entry;
size_t size;
char subsequent;
char idt;
} lws_struct_serialize_st_t;
enum {
LSSERJ_FLAG_PRETTY = (1 << 0),
LSSERJ_FLAG_OMIT_SCHEMA = (1 << 1)
};
typedef struct lws_struct_serialize {
lws_struct_serialize_st_t st[LEJP_MAX_PARSING_STACK_DEPTH];
size_t offset;
size_t remaining;
int sp;
int flags;
} lws_struct_serialize_t;
typedef enum {
LSJS_RESULT_CONTINUE,
LSJS_RESULT_FINISH,
LSJS_RESULT_ERROR
} lws_struct_json_serialize_result_t;
LWS_VISIBLE LWS_EXTERN int
lws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb,
void *user);
LWS_VISIBLE LWS_EXTERN signed char
lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason);
LWS_VISIBLE LWS_EXTERN signed char
lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason);
LWS_VISIBLE LWS_EXTERN lws_struct_serialize_t *
lws_struct_json_serialize_create(const lws_struct_map_t *map,
size_t map_entries, int flags,
const void *ptoplevel);
LWS_VISIBLE LWS_EXTERN void
lws_struct_json_serialize_destroy(lws_struct_serialize_t **pjs);
LWS_VISIBLE LWS_EXTERN lws_struct_json_serialize_result_t
lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
size_t len, size_t *written);
typedef struct sqlite3 sqlite3;
LWS_VISIBLE LWS_EXTERN int
lws_struct_sq3_serialize(sqlite3 *pdb, const lws_struct_map_t *schema,
lws_dll2_owner_t *owner, uint32_t manual_idx);
LWS_VISIBLE LWS_EXTERN int
lws_struct_sq3_deserialize(sqlite3 *pdb, const char *filter, const char *order,
const lws_struct_map_t *schema, lws_dll2_owner_t *o,
struct lwsac **ac, int start, int limit);
LWS_VISIBLE LWS_EXTERN int
lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema);
LWS_VISIBLE LWS_EXTERN int
lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
char create_if_missing, sqlite3 **pdb);
LWS_VISIBLE LWS_EXTERN int
lws_struct_sq3_close(sqlite3 **pdb);

View File

@ -0,0 +1,417 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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.
*
* 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.
*/
/*
* Types of system blob that can be set and retreived
*/
typedef enum {
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_SYSBLOB_TYPE_MQTT_CLIENT_ID,
LWS_SYSBLOB_TYPE_MQTT_USERNAME,
LWS_SYSBLOB_TYPE_MQTT_PASSWORD,
#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
/* extend 4 more auth blobs, each has 2 slots */
LWS_SYSBLOB_TYPE_EXT_AUTH1,
LWS_SYSBLOB_TYPE_EXT_AUTH2 = LWS_SYSBLOB_TYPE_EXT_AUTH1 + 2,
LWS_SYSBLOB_TYPE_EXT_AUTH3 = LWS_SYSBLOB_TYPE_EXT_AUTH2 + 2,
LWS_SYSBLOB_TYPE_EXT_AUTH4 = LWS_SYSBLOB_TYPE_EXT_AUTH3 + 2,
LWS_SYSBLOB_TYPE_EXT_AUTH4_1,
#endif
LWS_SYSBLOB_TYPE_COUNT /* ... always last */
} lws_system_blob_item_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
* 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_CPD_PRE_TIME, /* Captive portal detect without valid
* time, good for non-https tests... if
* you care about it, implement and
* call lws_system_ops_t
* .captive_portal_detect_request()
* and move the state forward according
* to the result. */
LWS_SYSTATE_TIME_VALID, /* ntpclient ran, or hw time valid...
* tls cannot work until we reach here
*/
LWS_SYSTATE_CPD_POST_TIME, /* Captive portal detect after time was
* time, good for https tests... if
* you care about it, implement and
* call lws_system_ops_t
* .captive_portal_detect_request()
* and move the state forward according
* to the result. */
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_ONE_TIME_UPDATES, /* pre-OPERATIONAL one-time updates,
* when a firmware needs to perform
* one-time upgrades to state before
* OPERATIONAL */
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_SYSTATE_CONTEXT_DESTROYING, /* Context is being destroyed */
LWS_SYSTATE_AWAITING_MODAL_UPDATING, /* We're negotiating with the
* user code for update mode */
LWS_SYSTATE_MODAL_UPDATING, /* We're updating the firmware */
} lws_system_states_t;
/* Captive Portal Detect -related */
typedef enum {
LWS_CPD_UNKNOWN = 0, /* test didn't happen ince last DHCP acq yet */
LWS_CPD_INTERNET_OK, /* no captive portal: our CPD test passed OK,
* we can go out on the internet */
LWS_CPD_CAPTIVE_PORTAL, /* we inferred we're behind a captive portal */
LWS_CPD_NO_INTERNET, /* we couldn't touch anything */
} lws_cpd_result_t;
typedef void (*lws_attach_cb_t)(struct lws_context *context, int tsi, void *opaque);
struct lws_attach_item;
LWS_EXTERN LWS_VISIBLE int
lws_tls_jit_trust_got_cert_cb(struct lws_context *cx, void *got_opaque,
const uint8_t *skid, size_t skid_len,
const uint8_t *der, size_t der_len);
typedef struct lws_system_ops {
int (*reboot)(void);
int (*set_clock)(lws_usec_t us);
int (*attach)(struct lws_context *context, int tsi, lws_attach_cb_t cb,
lws_system_states_t state, void *opaque,
struct lws_attach_item **get);
/**< if \p get is NULL, add an attach callback request to the pt for
* \p cb with arg \p opaque, that should be called when we're at or past
* system state \p state.
*
* If \p get is non-NULL, look for the first listed item on the pt whose
* state situation is ready, and set *get to point to it. If no items,
* or none where the system state is right, set *get to NULL.
*
* It's done like this so (*attach) can perform system-specific
* locking outside of lws core, for both getting and adding items the
* same so it is thread-safe. A non-threadsafe helper
* __lws_system_attach() is provided to do the actual work inside the
* system-specific locking.
*/
int (*captive_portal_detect_request)(struct lws_context *context);
/**< Check if we can go out on the internet cleanly, or if we are being
* redirected or intercepted by a captive portal.
* Start the check that proceeds asynchronously, and report the results
* by calling lws_captive_portal_detect_result() api
*/
#if defined(LWS_WITH_NETWORK)
int (*metric_report)(lws_metric_pub_t *mdata);
/**< metric \p item is reporting an event of kind \p rpt,
* held in \p mdata... return 0 to leave the metric object as it is,
* or nonzero to reset it. */
#endif
int (*jit_trust_query)(struct lws_context *cx, const uint8_t *skid,
size_t skid_len, void *got_opaque);
/**< user defined trust store search, if we do trust a cert with SKID
* matching skid / skid_len, then it should get hold of the DER for the
* matching root CA and call
* lws_tls_jit_trust_got_cert_cb(..., got_opaque) before cleaning up and
* returning. The DER should be destroyed if in heap before returning.
*/
#if defined(LWS_WITH_OTA)
lws_ota_ops_t ota_ops;
/**< Platform OTA interface to lws_ota, see lws-ota.h */
#endif
uint32_t wake_latency_us;
/**< time taken for this device to wake from suspend, in us
*/
} lws_system_ops_t;
#if defined(LWS_WITH_SYS_STATE)
/**
* 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);
#endif
/* wrappers handle NULL members or no ops struct set at all cleanly */
#define LWSSYSGAUTH_HEX (1 << 0)
/**
* lws_system_get_ops() - get ahold of the system ops struct from the context
*
* \param context: the lws_context
*
* Returns the system ops struct. It may return NULL and if not, anything in
* there may be NULL.
*/
LWS_EXTERN LWS_VISIBLE const lws_system_ops_t *
lws_system_get_ops(struct lws_context *context);
#if defined(LWS_WITH_SYS_STATE)
/**
* lws_system_context_from_system_mgr() - return context from system state mgr
*
* \param mgr: pointer to specifically the system state mgr
*
* Returns the context from the system state mgr. Helper since the lws_context
* is opaque.
*/
LWS_EXTERN LWS_VISIBLE struct lws_context *
lws_system_context_from_system_mgr(lws_state_manager_t *mgr);
#endif
/**
* __lws_system_attach() - get and set items on context attach list
*
* \param context: context to get or set attach items to
* \param tsi: thread service index (normally 0)
* \param cb: callback to call from context event loop thread
* \param state: the lws_system state we have to be in or have passed through
* \param opaque: optional pointer to user specific info given to callback
* \param get: NULL, or pointer to pointer to take detached tail item on exit
*
* This allows other threads to enqueue callback requests to happen from a pt's
* event loop thread safely. The callback gets the context pointer and a user
* opaque pointer that can be optionally given when the item is added to the
* attach list.
*
* This api is the no-locking core function for getting and setting items on the
* pt's attach list. The lws_system operation (*attach) is the actual
* api that user and internal code calls for this feature, it should perform
* system-specific locking, call this helper, release the locking and then
* return the result. This api is public only so it can be used in the locked
* implementation of (*attach).
*
* If get is NULL, then the call adds to the head of the pt attach list using
* cb, state, and opaque; if get is non-NULL, then *get is set to the first
* waiting attached item that meets the state criteria and that item is removed
* from the list.
*
* This is a non-threadsafe helper only designed to be called from
* implementations of struct lws_system's (*attach) operation where system-
* specific locking has been applied around it, making it threadsafe.
*/
LWS_EXTERN LWS_VISIBLE int
__lws_system_attach(struct lws_context *context, int tsi, lws_attach_cb_t cb,
lws_system_states_t state, void *opaque,
struct lws_attach_item **get);
enum {
LWSDH_IPV4_SUBNET_MASK = 0,
LWSDH_IPV4_BROADCAST,
LWSDH_LEASE_SECS,
LWSDH_REBINDING_SECS,
LWSDH_RENEWAL_SECS,
_LWSDH_NUMS_COUNT,
LWSDH_SA46_IP = 0,
LWSDH_SA46_DNS_SRV_1,
LWSDH_SA46_DNS_SRV_2,
LWSDH_SA46_DNS_SRV_3,
LWSDH_SA46_DNS_SRV_4,
LWSDH_SA46_IPV4_ROUTER,
LWSDH_SA46_NTP_SERVER,
LWSDH_SA46_DHCP_SERVER,
_LWSDH_SA46_COUNT,
};
#if defined(LWS_WITH_NETWORK)
typedef struct lws_dhcpc_ifstate {
char ifname[16];
char domain[64];
uint8_t mac[6];
uint32_t nums[_LWSDH_NUMS_COUNT];
lws_sockaddr46 sa46[_LWSDH_SA46_COUNT];
} lws_dhcpc_ifstate_t;
typedef int (*dhcpc_cb_t)(void *opaque, lws_dhcpc_ifstate_t *is);
/**
* lws_dhcpc_request() - add a network interface to dhcpc management
*
* \param c: the lws_context
* \param i: the interface name, like "eth0"
* \param af: address family
* \param cb: the change callback
* \param opaque: opaque pointer given to the callback
*
* Register a network interface as being managed by DHCP. lws will proceed to
* try to acquire an IP. Requires LWS_WITH_SYS_DHCP_CLIENT at cmake.
*/
LWS_EXTERN LWS_VISIBLE int
lws_dhcpc_request(struct lws_context *c, const char *i, int af, dhcpc_cb_t cb,
void *opaque);
/**
* lws_dhcpc_remove() - remove a network interface to dhcpc management
*
* \param context: the lws_context
* \param iface: the interface name, like "eth0"
*
* Remove handling of the network interface from dhcp.
*/
LWS_EXTERN LWS_VISIBLE int
lws_dhcpc_remove(struct lws_context *context, const char *iface);
/**
* lws_dhcpc_status() - has any interface reached BOUND state
*
* \param context: the lws_context
* \param sa46: set to a DNS server from a bound interface, or NULL
*
* Returns 1 if any network interface managed by dhcpc has reached the BOUND
* state (has acquired an IP, gateway and DNS server), otherwise 0.
*/
LWS_EXTERN LWS_VISIBLE int
lws_dhcpc_status(struct lws_context *context, lws_sockaddr46 *sa46);
/**
* lws_system_cpd_start() - helper to initiate captive portal detection
*
* \param context: the lws_context
*
* Resets the context's captive portal state to LWS_CPD_UNKNOWN and calls the
* lws_system_ops_t captive_portal_detect_request() implementation to begin
* testing the captive portal state.
*/
LWS_EXTERN LWS_VISIBLE int
lws_system_cpd_start(struct lws_context *context);
LWS_EXTERN LWS_VISIBLE void
lws_system_cpd_start_defer(struct lws_context *cx, lws_usec_t defer_us);
/**
* lws_system_cpd_set() - report the result of the captive portal detection
*
* \param context: the lws_context
* \param result: one of the LWS_CPD_ constants representing captive portal state
*
* Sets the context's captive portal detection state to result. User captive
* portal detection code would call this once it had a result from its test.
*/
LWS_EXTERN LWS_VISIBLE void
lws_system_cpd_set(struct lws_context *context, lws_cpd_result_t result);
/**
* lws_system_cpd_state_get() - returns the last tested captive portal state
*
* \param context: the lws_context
*
* Returns one of the LWS_CPD_ constants indicating the system's understanding
* of the current captive portal situation.
*/
LWS_EXTERN LWS_VISIBLE lws_cpd_result_t
lws_system_cpd_state_get(struct lws_context *context);
#endif

View File

@ -0,0 +1,61 @@
/*
* 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.
*
* lws_test_sequencer manages running an array of unit tests.
*/
typedef void (*lws_test_sequence_cb)(const void *cb_user);
typedef struct lws_test_sequencer_args {
lws_abs_t *abs; /* abstract protocol + unit test txport */
lws_unit_test_t *tests; /* array of lws_unit_test_t */
int *results; /* takes result dispositions */
int results_max; /* max space usable in results */
int *count_tests; /* count of done tests */
int *count_passes; /* count of passed tests */
lws_test_sequence_cb cb; /* completion callback */
void *cb_user; /* opaque user ptr given to cb */
} lws_test_sequencer_args_t;
/**
* lws_abs_unit_test_sequencer() - helper to sequence multiple unit tests
*
* \param args: lws_test_sequencer_args_t prepared with arguments for the tests
*
* This helper sequences one or more unit tests to run and collects the results.
*
* The incoming abs should be set up for the abstract protocol you want to test
* and the lws unit-test transport.
*
* Results are one of
*
* LPE_SUCCEEDED
* LPE_FAILED
* LPE_FAILED_UNEXPECTED_TIMEOUT
* LPE_FAILED_UNEXPECTED_PASS
* LPE_FAILED_UNEXPECTED_CLOSE
*
* The callback args->cb is called when the tests have been done.
*/
LWS_VISIBLE LWS_EXTERN int
lws_abs_unit_test_sequencer(const lws_test_sequencer_args_t *args);

View File

@ -0,0 +1,280 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2020 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 threadpool Threadpool related functions
* ##Threadpool
* \ingroup lwsapi
*
* This allows you to create one or more pool of threads which can run tasks
* associated with a wsi. If the pool is busy, tasks wait on a queue.
*
* Tasks don't have to be atomic, if they will take more than a few tens of ms
* they should return back to the threadpool worker with a return of 0. This
* will allow them to abort cleanly.
*/
//@{
struct lws_threadpool;
struct lws_threadpool_task;
enum lws_threadpool_task_status {
LWS_TP_STATUS_QUEUED,
LWS_TP_STATUS_RUNNING,
LWS_TP_STATUS_SYNCING,
LWS_TP_STATUS_STOPPING,
LWS_TP_STATUS_FINISHED, /* lws_threadpool_task_status() frees task */
LWS_TP_STATUS_STOPPED, /* lws_threadpool_task_status() frees task */
};
enum lws_threadpool_task_return {
/** Still work to do, just confirming not being stopped */
LWS_TP_RETURN_CHECKING_IN,
/** Still work to do, enter cond_wait until service thread syncs. This
* is used if you have filled your buffer(s) of data to the service
* thread and are blocked until the service thread completes sending at
* least one.
*/
LWS_TP_RETURN_SYNC,
/** No more work to do... */
LWS_TP_RETURN_FINISHED,
/** Responding to request to stop */
LWS_TP_RETURN_STOPPED,
/* OR on to indicate this task wishes to outlive its wsi */
LWS_TP_RETURN_FLAG_OUTLIVE = 64
};
struct lws_threadpool_create_args {
int threads;
int max_queue_depth;
};
struct lws_threadpool_task_args {
#if defined(LWS_WITH_SECURE_STREAMS)
struct lws_ss_handle *ss; /**< either wsi or ss must be set */
#endif
struct lws *wsi; /**< either wsi or ss must be set */
void *user; /**< user may set (user-private pointer) */
const char *name; /**< user may set to describe task */
char async_task; /**< set to allow the task to shrug off the loss
of the associated wsi and continue to
completion */
enum lws_threadpool_task_return (*task)(void *user,
enum lws_threadpool_task_status s);
/**< user must set to actual task function */
void (*cleanup)(struct lws *wsi, void *user);
/**< socket lifecycle may end while task is not stoppable, so the task
* must be able to detach from any wsi and clean itself up when it does
* stop. If NULL, no cleanup necessary, otherwise point to a user-
* supplied function that destroys the stuff in \p user.
*
* wsi may be NULL on entry, indicating the task got detached due to the
* wsi closing before.
*/
};
/**
* lws_threadpool_create() - create a pool of worker threads
*
* \param context: the lws_context the threadpool will exist inside
* \param args: argument struct prepared by caller
* \param format: printf-type format for the task name
* \param ...: printf type args for the task name format
*
* Creates a pool of worker threads with \p threads and a queue of up to
* \p max_queue_depth waiting tasks if all the threads are busy.
*
* Returns NULL if OOM, or a struct lws_threadpool pointer that must be
* destroyed by lws_threadpool_destroy().
*/
LWS_VISIBLE LWS_EXTERN struct lws_threadpool *
lws_threadpool_create(struct lws_context *context,
const struct lws_threadpool_create_args *args,
const char *format, ...) LWS_FORMAT(3);
/**
* lws_threadpool_finish() - Stop all pending and running tasks
*
* \param tp: the threadpool object
*
* Marks the threadpool as under destruction. Removes everything from the
* pending queue and completes those tasks as LWS_TP_STATUS_STOPPED.
*
* Running tasks will also get LWS_TP_STATUS_STOPPED as soon as they
* "resurface".
*
* This doesn't reap tasks or free the threadpool, the reaping is done by the
* lws_threadpool_task_status() on the done task.
*/
LWS_VISIBLE LWS_EXTERN void
lws_threadpool_finish(struct lws_threadpool *tp);
/**
* lws_threadpool_destroy() - Destroy a threadpool
*
* \param tp: the threadpool object
*
* Waits for all worker threads to stop, ends the threads and frees the tp.
*/
LWS_VISIBLE LWS_EXTERN void
lws_threadpool_destroy(struct lws_threadpool *tp);
/**
* lws_threadpool_enqueue() - Queue the task and run it on a worker thread when possible
*
* \param tp: the threadpool to queue / run on
* \param args: information about what to run
* \param format: printf-type format for the task name
* \param ...: printf type args for the task name format
*
* This asks for a task to run ASAP on a worker thread in threadpool \p tp.
*
* The args defines the wsi, a user-private pointer, a timeout in secs and
* a pointer to the task function.
*
* Returns NULL or an opaque pointer to the queued (or running, or completed)
* task.
*
* Once a task is created and enqueued, it can only be destroyed by calling
* lws_threadpool_task_status() on it after it has reached the state
* LWS_TP_STATUS_FINISHED or LWS_TP_STATUS_STOPPED.
*/
LWS_VISIBLE LWS_EXTERN struct lws_threadpool_task *
lws_threadpool_enqueue(struct lws_threadpool *tp,
const struct lws_threadpool_task_args *args,
const char *format, ...) LWS_FORMAT(3);
/**
* lws_threadpool_dequeue() - Dequeue or try to stop a running task
*
* \param wsi: the wsi whose current task we want to eliminate
*
* Returns 0 is the task was dequeued or already compeleted, or 1 if the task
* has been asked to stop asynchronously.
*
* This doesn't free the task. It only shortcuts it to state
* LWS_TP_STATUS_STOPPED. lws_threadpool_task_status() must be performed on
* the task separately once it is in LWS_TP_STATUS_STOPPED to free the task.
*
* DEPRECATED: You should use lws_threadpool_dequeue_task() with
* lws_threadpool_get_task_wsi() / _ss() if you know there can only be one task
* per connection, or call it via lws_threadpool_foreach_task_wsi() / _ss() to
* get the tasks bound to the connection.
*/
LWS_VISIBLE LWS_EXTERN int
lws_threadpool_dequeue(struct lws *wsi) LWS_WARN_DEPRECATED;
LWS_VISIBLE LWS_EXTERN int
lws_threadpool_dequeue_task(struct lws_threadpool_task *task);
/**
* lws_threadpool_task_status() - reap completed tasks
*
* \param wsi: the wsi to query the current task of
* \param task: receives a pointer to the opaque task
* \param user: receives a void * pointer to the task user data
*
* This is the equivalent of posix waitpid()... it returns the status of the
* task, and if the task is in state LWS_TP_STATUS_FINISHED or
* LWS_TP_STATUS_STOPPED, frees \p task. If in another state, the task
* continues to exist.
*
* This is designed to be called from the service thread.
*
* Its use is to make sure the service thread has seen the state of the task
* before deleting it.
*
* DEPRECATED... use lws_threadpool_task_status() instead and get the task
* pointer from lws_threadpool_get_task_wsi() / _ss() if you know there can only
* be one, else call it via lws_threadpool_foreach_task_wsi() / _ss()
*/
LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status
lws_threadpool_task_status_wsi(struct lws *wsi,
struct lws_threadpool_task **task, void **user)
LWS_WARN_DEPRECATED;
LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status
lws_threadpool_task_status(struct lws_threadpool_task *task, void **user);
LWS_VISIBLE LWS_EXTERN enum lws_threadpool_task_status
lws_threadpool_task_status_noreap(struct lws_threadpool_task *task);
/**
* lws_threadpool_task_sync() - Indicate to a stalled task it may continue
*
* \param task: the task to unblock
* \param stop: 0 = run after unblock, 1 = when he unblocks, stop him
*
* Inform the task that the service thread has finished with the shared data
* and that the task, if blocked in LWS_TP_RETURN_SYNC, may continue.
*
* If the lws service context determined that the task must be aborted, it
* should still call this but with stop = 1, causing the task to finish.
*/
LWS_VISIBLE LWS_EXTERN void
lws_threadpool_task_sync(struct lws_threadpool_task *task, int stop);
/**
* lws_threadpool_dump() - dump the state of a threadpool to the log
*
* \param tp: The threadpool to dump
*
* This locks the threadpool and then dumps the pending queue, the worker
* threads and the done queue, together with time information for how long
* the tasks have been in their current state, how long they have occupied a
* thread, etc.
*
* This only does anything on lws builds with CMAKE_BUILD_TYPE=DEBUG, otherwise
* while it still exists, it's a NOP.
*/
LWS_VISIBLE LWS_EXTERN void
lws_threadpool_dump(struct lws_threadpool *tp);
LWS_VISIBLE LWS_EXTERN struct lws_threadpool_task *
lws_threadpool_get_task_wsi(struct lws *wsi);
#if defined(LWS_WITH_SECURE_STREAMS)
LWS_VISIBLE LWS_EXTERN struct lws_threadpool_task *
lws_threadpool_get_task_ss(struct lws_ss_handle *ss);
#endif
LWS_VISIBLE LWS_EXTERN int
lws_threadpool_foreach_task_wsi(struct lws *wsi, void *user,
int (*cb)(struct lws_threadpool_task *task,
void *user));
#if defined(LWS_WITH_SECURE_STREAMS)
LWS_VISIBLE LWS_EXTERN int
lws_threadpool_foreach_task_ss(struct lws_ss_handle *ss, void *user,
int (*cb)(struct lws_threadpool_task *task, void *user));
#endif
//@}

View File

@ -0,0 +1,313 @@
/*
* 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 timeout Connection timeouts
APIs related to setting connection timeouts
*/
//@{
#if defined(STANDALONE)
struct lws_context_standalone;
#define lws_context lws_context_standalone
#endif
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
*/
enum pending_timeout {
NO_PENDING_TIMEOUT = 0,
PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE = 1,
PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE = 2,
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER = 3,
PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE = 4,
PENDING_TIMEOUT_AWAITING_PING = 5,
PENDING_TIMEOUT_CLOSE_ACK = 6,
PENDING_TIMEOUT_UNUSED1 = 7,
PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE = 8,
PENDING_TIMEOUT_SSL_ACCEPT = 9,
PENDING_TIMEOUT_HTTP_CONTENT = 10,
PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND = 11,
PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE = 12,
PENDING_TIMEOUT_SHUTDOWN_FLUSH = 13,
PENDING_TIMEOUT_CGI = 14,
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE = 15,
PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING = 16,
PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG = 17,
PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD = 18,
PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY = 19,
PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY = 20,
PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY = 21,
PENDING_TIMEOUT_KILLED_BY_SSL_INFO = 22,
PENDING_TIMEOUT_KILLED_BY_PARENT = 23,
PENDING_TIMEOUT_CLOSE_SEND = 24,
PENDING_TIMEOUT_HOLDING_AH = 25,
PENDING_TIMEOUT_UDP_IDLE = 26,
PENDING_TIMEOUT_CLIENT_CONN_IDLE = 27,
PENDING_TIMEOUT_LAGGING = 28,
PENDING_TIMEOUT_THREADPOOL = 29,
PENDING_TIMEOUT_THREADPOOL_TASK = 30,
PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE = 31,
PENDING_TIMEOUT_USER_OK = 32,
/****** add new things just above ---^ ******/
PENDING_TIMEOUT_USER_REASON_BASE = 1000
};
#define lws_time_in_microseconds lws_now_usecs
#define LWS_TO_KILL_ASYNC -1
/**< If LWS_TO_KILL_ASYNC is given as the timeout sec in a lws_set_timeout()
* call, then the connection is marked to be killed at the next timeout
* check. This is how you should force-close the wsi being serviced if
* you are doing it outside the callback (where you should close by nonzero
* return).
*/
#define LWS_TO_KILL_SYNC -2
/**< If LWS_TO_KILL_SYNC is given as the timeout sec in a lws_set_timeout()
* call, then the connection is closed before returning (which may delete
* the wsi). This should only be used where the wsi being closed is not the
* wsi currently being serviced.
*/
/**
* lws_set_timeout() - marks the wsi as subject to a timeout some seconds hence
*
* \param wsi: Websocket connection instance
* \param reason: timeout reason
* \param secs: how many seconds. You may set to LWS_TO_KILL_ASYNC to
* force the connection to timeout at the next opportunity, or
* LWS_TO_KILL_SYNC to close it synchronously if you know the
* wsi is not the one currently being serviced.
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
/**
* lws_set_timeout_us() - marks the wsi as subject to a timeout some us hence
*
* \param wsi: Websocket connection instance
* \param reason: timeout reason
* \param us: 0 removes the timeout, otherwise number of us to wait
*
* Higher-resolution version of lws_set_timeout(). Actual resolution depends
* on platform and load, usually ms.
*/
void
lws_set_timeout_us(struct lws *wsi, enum pending_timeout reason, lws_usec_t us);
/* helper for clearer LWS_TO_KILL_ASYNC / LWS_TO_KILL_SYNC usage */
#define lws_wsi_close(w, to_kill) lws_set_timeout(w, 1, to_kill)
#define LWS_SET_TIMER_USEC_CANCEL ((lws_usec_t)-1ll)
#define LWS_USEC_PER_SEC ((lws_usec_t)1000000)
/**
* lws_set_timer_usecs() - schedules a callback on the wsi in the future
*
* \param wsi: Websocket connection instance
* \param usecs: LWS_SET_TIMER_USEC_CANCEL removes any existing scheduled
* callback, otherwise number of microseconds in the future
* the callback will occur at.
*
* NOTE: event loop support for this:
*
* default poll() loop: yes
* libuv event loop: yes
* libev: not implemented (patch welcome)
* libevent: not implemented (patch welcome)
*
* After the deadline expires, the wsi will get a callback of type
* LWS_CALLBACK_TIMER and the timer is exhausted. The deadline may be
* continuously deferred by further calls to lws_set_timer_usecs() with a later
* deadline, or cancelled by lws_set_timer_usecs(wsi, -1).
*
* If the timer should repeat, lws_set_timer_usecs() must be called again from
* LWS_CALLBACK_TIMER.
*
* Accuracy depends on the platform and the load on the event loop or system...
* all that's guaranteed is the callback will come after the requested wait
* period.
*/
LWS_VISIBLE LWS_EXTERN void
lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs);
struct lws_sorted_usec_list;
typedef void (*sul_cb_t)(struct lws_sorted_usec_list *sul);
typedef struct lws_sorted_usec_list {
struct lws_dll2 list; /* simplify the code by keeping this at start */
lws_usec_t us;
sul_cb_t cb;
uint32_t latency_us; /* us it may safely be delayed */
} lws_sorted_usec_list_t;
/*
* There are multiple sul owners to allow accounting for, a) events that must
* wake from suspend, and b) events that can be missued due to suspend
*/
#define LWS_COUNT_PT_SUL_OWNERS 2
#define LWSSULLI_MISS_IF_SUSPENDED 0
#define LWSSULLI_WAKE_IF_SUSPENDED 1
/*
* lws_sul2_schedule() - schedule a callback
*
* \param context: the lws_context
* \param tsi: the thread service index (usually 0)
* \param flags: LWSSULLI_...
* \param sul: pointer to the sul element
*
* Generic callback-at-a-later time function. The callback happens on the
* event loop thread context.
*
* Although the api has us resultion, the actual resolution depends on the
* platform and may be, eg, 1ms.
*
* This doesn't allocate and doesn't fail.
*
* If flags contains LWSSULLI_WAKE_IF_SUSPENDED, the scheduled event is placed
* on a sul owner list that, if the system has entered low power suspend mode,
* tries to arrange that the system should wake from platform suspend just
* before the event is due. Scheduled events without this flag will be missed
* in the case the system is in suspend and nothing else happens to have woken
* it.
*
* You can call it again with another us value to change the delay or move the
* event to a different owner (ie, wake or miss on suspend).
*/
LWS_VISIBLE LWS_EXTERN void
lws_sul2_schedule(struct lws_context *context, int tsi, int flags,
lws_sorted_usec_list_t *sul);
/*
* lws_sul_cancel() - cancel scheduled callback
*
* \param sul: pointer to the sul element
*
* If it's scheduled, remove the sul from its owning sorted list.
* If not scheduled, it's a NOP.
*/
LWS_VISIBLE LWS_EXTERN void
lws_sul_cancel(lws_sorted_usec_list_t *sul);
/*
* lws_sul_earliest_wakeable_event() - get earliest wake-from-suspend event
*
* \param ctx: the lws context
* \param pearliest: pointer to lws_usec_t to take the result
*
* Either returns 1 if no pending event, or 0 and sets *pearliest to the
* MONOTONIC time of the current earliest next expected event.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sul_earliest_wakeable_event(struct lws_context *ctx, lws_usec_t *pearliest);
/*
* For backwards compatibility
*
* If us is LWS_SET_TIMER_USEC_CANCEL, the sul is removed from the scheduler.
* New code can use lws_sul_cancel()
*/
LWS_VISIBLE LWS_EXTERN void
lws_sul_schedule(struct lws_context *ctx, int tsi, lws_sorted_usec_list_t *sul,
sul_cb_t _cb, lws_usec_t _us);
LWS_VISIBLE LWS_EXTERN void
lws_sul_schedule_wakesuspend(struct lws_context *ctx, int tsi,
lws_sorted_usec_list_t *sul, sul_cb_t _cb,
lws_usec_t _us);
#if defined(LWS_WITH_SUL_DEBUGGING)
/**
* lws_sul_debug_zombies() - assert there are no scheduled sul in a given object
*
* \param ctx: lws_context
* \param po: pointer to the object that is about to be destroyed
* \param len: length of the object that is about to be destroyed
* \param destroy_description: string clue what any failure is related to
*
* This is an optional debugging helper that walks the sul scheduler lists
* confirming that there are no suls scheduled that live inside the object
* footprint described by po and len. When internal objects are about to be
* destroyed, like wsi / user_data or secure stream handles, if
* LWS_WITH_SUL_DEBUGGING is enabled the scheduler is checked for anything
* in the object being destroyed. If something found, an error is printed and
* an assert fired.
*
* Internal sul like timeouts should always be cleaned up correctly, but user
* suls in, eg, wsi user_data area, or in secure stream user allocation, may be
* the cause of difficult to find bugs if valgrind not available and the user
* code left a sul in the scheduler after destroying the object the sul was
* living in.
*/
LWS_VISIBLE LWS_EXTERN void
lws_sul_debug_zombies(struct lws_context *ctx, void *po, size_t len,
const char *destroy_description);
#else
#define lws_sul_debug_zombies(_a, _b, _c, _d)
#endif
/*
* lws_validity_confirmed() - reset the validity timer for a network connection
*
* \param wsi: the connection that saw traffic proving the connection valid
*
* Network connections are subject to intervals defined by the context, the
* vhost if server connections, or the client connect info if a client
* connection. If the connection goes longer than the specified time since
* last observing traffic that can only happen if traffic is passing in both
* directions, then lws will try to create a PING transaction on the network
* connection.
*
* If the connection reaches the specified `.secs_since_valid_hangup` time
* still without any proof of validity, the connection will be closed.
*
* If the PONG comes, or user code observes traffic that satisfies the proof
* that both directions are passing traffic to the peer and calls this api,
* the connection validity timer is reset and the scheme repeats.
*/
LWS_VISIBLE LWS_EXTERN void
lws_validity_confirmed(struct lws *wsi);
/*
* These are not normally needed, they're exported for the case there's code
* using lws_sul for which lws is an optional link dependency.
*/
LWS_VISIBLE LWS_EXTERN int
__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul);
LWS_VISIBLE LWS_EXTERN lws_usec_t
__lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow);
#if defined(STANDALONE)
#undef lws_context
#endif
///@}

View File

@ -0,0 +1,81 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2021 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 tls_sessions TLS Session Management
APIs related to managing TLS Sessions
*/
//@{
#define LWS_SESSION_TAG_LEN 96
struct lws_tls_session_dump
{
char tag[LWS_SESSION_TAG_LEN];
void *blob;
void *opaque;
size_t blob_len;
};
typedef int (*lws_tls_sess_cb_t)(struct lws_context *cx,
struct lws_tls_session_dump *info);
/**
* lws_tls_session_dump_save() - serialize a tls session via a callback
*
* \param vh: the vhost to load into the session cache
* \param host: the name of the host the session relates to
* \param port: the port the session connects to on the host
* \param cb_save: the callback to perform the saving of the session blob
* \param opq: an opaque pointer passed into the callback
*
* If a session matching the vhost/host/port exists in the vhost's session
* cache, serialize it via the provided callback.
*
* \p opq is passed to the callback without being used by lws at all.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_session_dump_save(struct lws_vhost *vh, const char *host, uint16_t port,
lws_tls_sess_cb_t cb_save, void *opq);
/**
* lws_tls_session_dump_load() - deserialize a tls session via a callback
*
* \param vh: the vhost to load into the session cache
* \param host: the name of the host the session relates to
* \param port: the port the session connects to on the host
* \param cb_load: the callback to retreive the session blob from
* \param opq: an opaque pointer passed into the callback
*
* Try to preload a session described by the first three parameters into the
* client session cache, from the given callback.
*
* \p opq is passed to the callback without being used by lws at all.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_session_dump_load(struct lws_vhost *vh, const char *host, uint16_t port,
lws_tls_sess_cb_t cb_load, void *opq);
///@}

View File

@ -0,0 +1,295 @@
/*
* 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.
*/
/* Do not treat - as a terminal character, so "my-token" is one token */
#define LWS_TOKENIZE_F_MINUS_NONTERM (1 << 0)
/* Separately report aggregate colon-delimited tokens */
#define LWS_TOKENIZE_F_AGG_COLON (1 << 1)
/* Enforce sequencing for a simple token , token , token ... list */
#define LWS_TOKENIZE_F_COMMA_SEP_LIST (1 << 2)
/* Allow more characters in the tokens and less delimiters... default is
* only alphanumeric + underscore in tokens */
#define LWS_TOKENIZE_F_RFC7230_DELIMS (1 << 3)
/* Do not treat . as a terminal character, so "warmcat.com" is one token */
#define LWS_TOKENIZE_F_DOT_NONTERM (1 << 4)
/* If something starts looking like a float, like 1.2, force to be string token.
* This lets you receive dotted-quads like 192.168.0.1 as string tokens, and
* avoids illegal float format detection like 1.myserver.com */
#define LWS_TOKENIZE_F_NO_FLOATS (1 << 5)
/* Instead of LWS_TOKZE_INTEGER, report integers as any other string token */
#define LWS_TOKENIZE_F_NO_INTEGERS (1 << 6)
/* # makes the rest of the line a comment */
#define LWS_TOKENIZE_F_HASH_COMMENT (1 << 7)
/* Do not treat / as a terminal character, so "multipart/related" is one token */
#define LWS_TOKENIZE_F_SLASH_NONTERM (1 << 8)
/* Do not treat * as a terminal character, so "myfile*" is one token */
#define LWS_TOKENIZE_F_ASTERISK_NONTERM (1 << 9)
/* Do not treat = as a terminal character, so "x=y" is one token */
#define LWS_TOKENIZE_F_EQUALS_NONTERM (1 << 10)
/* Do not treat : as a terminal character, so ::1 is one token */
#define LWS_TOKENIZE_F_COLON_NONTERM (1 << 11)
/* We're just tokenizing a chunk, don't treat running out of input as final */
#define LWS_TOKENIZE_F_EXPECT_MORE (1 << 12)
typedef enum {
LWS_TOKZE_ERRS = 7, /* the number of errors defined */
LWS_TOKZE_TOO_LONG = -7, /* token too long */
LWS_TOKZE_WANT_READ = -6, /* need more input */
LWS_TOKZE_ERR_BROKEN_UTF8 = -5, /* malformed or partial utf8 */
LWS_TOKZE_ERR_UNTERM_STRING = -4, /* ended while we were in "" */
LWS_TOKZE_ERR_MALFORMED_FLOAT = -3, /* like 0..1 or 0.1.1 */
LWS_TOKZE_ERR_NUM_ON_LHS = -2, /* like 123= or 0.1= */
LWS_TOKZE_ERR_COMMA_LIST = -1, /* like ",tok", or, "tok,," */
LWS_TOKZE_ENDED = 0, /* no more content */
/* Note: results have ordinal 1+, EOT is 0 and errors are < 0 */
LWS_TOKZE_DELIMITER, /* a delimiter appeared */
LWS_TOKZE_TOKEN, /* a token appeared */
LWS_TOKZE_INTEGER, /* an integer appeared */
LWS_TOKZE_FLOAT, /* a float appeared */
LWS_TOKZE_TOKEN_NAME_EQUALS, /* token [whitespace] = */
LWS_TOKZE_TOKEN_NAME_COLON, /* token [whitespace] : (only with
LWS_TOKENIZE_F_AGG_COLON flag) */
LWS_TOKZE_QUOTED_STRING, /* "*", where * may have any char */
} lws_tokenize_elem;
/*
* helper enums to allow caller to enforce legal delimiter sequencing, eg
* disallow "token,,token", "token,", and ",token"
*/
enum lws_tokenize_delimiter_tracking {
LWSTZ_DT_NEED_FIRST_CONTENT,
LWSTZ_DT_NEED_DELIM,
LWSTZ_DT_NEED_NEXT_CONTENT,
};
typedef enum {
LWS_TOKZS_LEADING_WHITESPACE,
LWS_TOKZS_QUOTED_STRING,
LWS_TOKZS_TOKEN,
LWS_TOKZS_TOKEN_POST_TERMINAL
} lws_tokenize_state;
typedef struct lws_tokenize {
char collect[256]; /* token length limit */
const char *start; /**< set to the start of the string to tokenize */
const char *token; /**< the start of an identified token or delimiter */
size_t len; /**< set to the length of the string to tokenize */
size_t token_len; /**< the length of the identied token or delimiter */
lws_tokenize_state state;
int line;
int effline;
uint16_t flags; /**< optional LWS_TOKENIZE_F_ flags, or 0 */
uint8_t delim;
int8_t e; /**< convenient for storing lws_tokenize return */
uint8_t reset_token:1;
uint8_t crlf:1;
uint8_t dry:1;
} lws_tokenize_t;
/**
* lws_tokenize() - breaks down a string into tokens and delimiters in-place
*
* \param ts: the lws_tokenize struct to init
* \param start: the string to tokenize
* \param flags: LWS_TOKENIZE_F_ option flags
*
* This initializes the tokenize struct to point to the given string, and
* sets the length to 2GiB - 1 (so there must be a terminating NUL)... you can
* override this requirement by setting ts.len yourself before using it.
*
* .delim is also initialized to LWSTZ_DT_NEED_FIRST_CONTENT.
*/
LWS_VISIBLE LWS_EXTERN void
lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags);
/**
* lws_tokenize() - breaks down a string into tokens and delimiters in-place
*
* \param ts: the lws_tokenize struct with information and state on what to do
*
* The \p ts struct should have its start, len and flags members initialized to
* reflect the string to be tokenized and any options.
*
* Then `lws_tokenize()` may be called repeatedly on the struct, returning one
* of `lws_tokenize_elem` each time, and with the struct's `token` and
* `token_len` members set to describe the content of the delimiter or token
* payload each time.
*
* There are no allocations during the process.
*
* returns lws_tokenize_elem that was identified (LWS_TOKZE_ENDED means reached
* the end of the string).
*/
LWS_VISIBLE LWS_EXTERN lws_tokenize_elem
lws_tokenize(struct lws_tokenize *ts);
/**
* lws_tokenize_cstr() - copy token string to NUL-terminated buffer
*
* \param ts: pointer to lws_tokenize struct to operate on
* \param str: destination buffer
* \pparam max: bytes in destination buffer
*
* returns 0 if OK or nonzero if the string + NUL won't fit.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tokenize_cstr(struct lws_tokenize *ts, char *str, size_t max);
/*
* lws_strexp: flexible string expansion helper api
*
* This stateful helper can handle multiple separate input chunks and multiple
* output buffer loads with arbitrary boundaries between literals and expanded
* symbols. This allows it to handle fragmented input as well as arbitrarily
* long symbol expansions that are bigger than the output buffer itself.
*
* A user callback is used to convert symbol names to the symbol value.
*
* A single byte buffer for input and another for output can process any
* length substitution then. The state object is around 64 bytes on a 64-bit
* system and it only uses 8 bytes stack.
*/
typedef int (*lws_strexp_expand_cb)(void *priv, const char *name, char *out,
size_t *pos, size_t olen, size_t *exp_ofs);
typedef struct lws_strexp {
char name[32];
lws_strexp_expand_cb cb;
void *priv;
char *out;
size_t olen;
size_t pos;
size_t exp_ofs;
uint8_t name_pos;
char state;
} lws_strexp_t;
enum {
LSTRX_DONE, /* it completed OK */
LSTRX_FILLED_OUT, /* out buf filled and needs resetting */
LSTRX_FATAL_NAME_TOO_LONG = -1, /* fatal */
LSTRX_FATAL_NAME_UNKNOWN = -2,
};
/**
* lws_strexp_init() - initialize an lws_strexp_t for use
*
* \p exp: the exp object to init
* \p priv: the user's object pointer to pass to callback
* \p cb: the callback to expand named objects
* \p out: the start of the output buffer, or NULL just to get the length
* \p olen: the length of the output buffer in bytes
*
* Prepares an lws_strexp_t for use and sets the initial output buffer
*
* If \p out is NULL, substitution proceeds normally, but no output is produced,
* only the length is returned. olen should be set to the largest feasible
* overall length. To use this mode, the substitution callback must also check
* for NULL \p out and avoid producing the output.
*/
LWS_VISIBLE LWS_EXTERN void
lws_strexp_init(lws_strexp_t *exp, void *priv, lws_strexp_expand_cb cb,
char *out, size_t olen);
/**
* lws_strexp_reset_out() - reset the output buffer on an existing strexp
*
* \p exp: the exp object to init
* \p out: the start of the output buffer, or NULL to just get length
* \p olen: the length of the output buffer in bytes
*
* Provides a new output buffer for lws_strexp_expand() to continue to write
* into. It can be the same as the old one if it has been copied out or used.
* The position of the next write will be reset to the start of the given buf.
*
* If \p out is NULL, substitution proceeds normally, but no output is produced,
* only the length is returned. \p olen should be set to the largest feasible
* overall length. To use this mode, the substitution callback must also check
* for NULL \p out and avoid producing the output.
*/
LWS_VISIBLE LWS_EXTERN void
lws_strexp_reset_out(lws_strexp_t *exp, char *out, size_t olen);
/**
* lws_strexp_expand() - copy / expand a string into the output buffer
*
* \p exp: the exp object for the copy / expansion
* \p in: the start of the next input data
* \p len: the length of the input data
* \p pused_in: pointer to write the amount of input used
* \p pused_out: pointer to write the amount of output used
*
* Copies in to the output buffer set in exp, expanding any ${name} tokens using
* the callback. \p *pused_in is set to the number of input chars used and
* \p *pused_out the number of output characters used
*
* May return LSTRX_FILLED_OUT early with *pused < len if the output buffer is
* filled. Handle the output buffer and reset it with lws_strexp_reset_out()
* before calling again with adjusted in / len to continue.
*
* In the case of large expansions, the expansion itself may fill the output
* buffer, in which case the expansion callback returns the LSTRX_FILLED_OUT
* and will be called again to continue with its *exp_ofs parameter set
* appropriately.
*/
LWS_VISIBLE LWS_EXTERN int
lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len,
size_t *pused_in, size_t *pused_out);
/**
* lws_strcmp_wildcard() - strcmp but the first arg can have wildcards
*
* \p wildcard: a string that may contain zero to three *, and may lack a NUL
* \p wlen: length of the wildcard string
* \p check: string to test to see if it matches wildcard
* \p clen: length of check string
*
* Like strcmp, but supports patterns like "a*", "a*b", "a*b*" etc
* where a and b are arbitrary substrings. Both the wc and check strings need
* not be NUL terminated, but are specified by lengths.
*/
LWS_VISIBLE LWS_EXTERN int
lws_strcmp_wildcard(const char *wildcard, size_t wlen, const char *check,
size_t clen);

View File

@ -0,0 +1,55 @@
/*
* lws abstract display implementation for epd-acep on spi
*
* Copyright (C) 2019 - 2022 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.
*/
#if !defined(__LWS_DISPLAY_UC8176_SPI_H__)
#define __LWS_DISPLAY_UC8176_SPI_H__
typedef struct lws_display_uc8176_spi {
lws_display_t disp; /* use lws_display_uc8176_ops to set */
const lws_spi_ops_t *spi; /* spi ops */
lws_display_completion_t cb;
const lws_gpio_ops_t *gpio; /* NULL or gpio ops */
_lws_plat_gpio_t reset_gpio; /* if gpio ops, nReset gpio # */
_lws_plat_gpio_t busy_gpio; /* if gpio ops, busy gpio # */
uint8_t spi_index; /* cs index starting from 0 */
} lws_display_uc8176_spi_t;
int
lws_display_uc8176_spi_init(lws_display_state_t *lds);
int
lws_display_uc8176_spi_blit(lws_display_state_t *lds, const uint8_t *src,
lws_box_t *box, lws_dll2_owner_t *ids);
int
lws_display_uc8176_spi_power(lws_display_state_t *lds, int state);
#define lws_display_uc8176_ops \
.init = lws_display_uc8176_spi_init, \
.blit = lws_display_uc8176_spi_blit, \
.power = lws_display_uc8176_spi_power
#endif

View File

@ -0,0 +1,160 @@
/*
* uPNG -- derived from LodePNG version 20100808
*
* Copyright (c) 2005-2010 Lode Vandevenne
* Copyright (c) 2010 Sean Middleditch
* Copyright (c) 2021-2022 Andy Green <andy@warmcat.com>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* The above notice is the ZLIB license, libpng also uses it.
*
* This version is based on upng project's fork of lodepng and rewritten for
* lws, changing the whole approach to decode on demand to issue a line of
* output at a time, statefully.
*/
typedef enum lws_upng_format_t {
LWS_UPNG_BADFORMAT,
LWS_UPNG_RGB8,
LWS_UPNG_RGB16,
LWS_UPNG_RGBA8,
LWS_UPNG_RGBA16,
LWS_UPNG_LUMINANCE1,
LWS_UPNG_LUMINANCE2,
LWS_UPNG_LUMINANCE4,
LWS_UPNG_LUMINANCE8,
LWS_UPNG_LUMINANCE_ALPHA1,
LWS_UPNG_LUMINANCE_ALPHA2,
LWS_UPNG_LUMINANCE_ALPHA4,
LWS_UPNG_LUMINANCE_ALPHA8
} lws_upng_format_t;
struct inflator_ctx;
typedef struct lws_upng_t lws_upng_t;
/**
* lws_upng_new() - Create new UPNG decode object
*
* Returns a new PNG decoding object, which should be destroyed with
* lws_upng_free() when done with, or NULL if OOM.
*/
LWS_VISIBLE LWS_EXTERN lws_upng_t *
lws_upng_new(void);
/**
* lws_upng_free() - Destroy a PNG decode object
*
* \param upng: Pointer to the decode object to destroy and set to NULL
*
* This also frees any sub-allocations in the object.
*/
LWS_VISIBLE LWS_EXTERN void
lws_upng_free(lws_upng_t **upng);
/**
* lws_upng_emit_next_line() - deocde the next line
*
* \param upng: the decode object
* \param ppix: pointer to a pointer set to the line's decoded pixel data
* \param buf: pointer to a const uint8_t array of PNG input
* \param size: pointer to the count of bytes available at *buf
* \param hold_at_metadata: true if we should not advance to decode
*
* Make PNG input available to the decoder so it can issue the next line's
* worth of pixels. If the call consumed any input, *buf and *size are
* adjusted accordingly.
*
* The decoder is stateful so it is not sensitive to the chunk size for the
* input.
*
* If \p hold_at_metadata is set, then the decoder will only go as far as
* picking out the metadata like image dimensions, but not start the decode,
* which requires the >30KB heap allocation. This lets you put off for as long
* as possible committing to the decode allocation... this only helps overall
* if you have flow controlled the incoming PNG data.
*
* Return will be one of LWS_SRET_WANT_INPUT is the decoder is stalled waiting
* for more input to be provided, LWS_SRET_WANT_OUTPUT is the decoder stopped
* because it had produced a whole line of output pixels (which can be found
* starting at *ppix), LWS_SRET_OK is it completed and LWS_SRET_FATAL or larger
* if the decode failed.
*/
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_upng_emit_next_line(lws_upng_t *upng, const uint8_t **ppix,
const uint8_t **buf, size_t *size,
char hold_at_metadata);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_upng_get_width(const lws_upng_t *upng);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_upng_get_height(const lws_upng_t *upng);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_upng_get_bpp(const lws_upng_t *upng);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_upng_get_bitdepth(const lws_upng_t *upng);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_upng_get_components(const lws_upng_t *upng);
LWS_VISIBLE LWS_EXTERN unsigned int
lws_upng_get_pixelsize(const lws_upng_t *upng);
LWS_VISIBLE LWS_EXTERN lws_upng_format_t
lws_upng_get_format(const lws_upng_t *upng);
/**
* lws_upng_inflator_create() - create a gzip inflator context
*
* \param outring: pointer set to the output ringbuffer on exit
* \param outringlen: size of the output ringbuffer set on exit
* \param opl: pointer to set to point to ctx outpos_linear
* \param cl: pointer to set to point to ctx consumed_linear
*
* Creates an opaque gzip inflator object.
*/
LWS_VISIBLE LWS_EXTERN struct inflator_ctx *
lws_upng_inflator_create(const uint8_t **outring, size_t *outringlen,
size_t **opl, size_t **cl);
/**
* lws_upng_inflate_data() - inflate compressed data statefully
*
* \param inf: inflator context created with lws_upng_inflator_create()
* \param buf: NULL to continue consumption of existing input, or new input
* \param len: ignored if \p buf is NULL, else amount of new input at \p buf
*
* Tries to progress the inflation. If output is available, \p *opl will be
* further along than before it was called. \p *cl should be set to \p opl
* to consume the available output data.
*
* Output is into a ringfuffer, typically sized at 32KB. \p opl and \p cl
* are "linear", that is extend beyond the ringbuffer. They should be modulo
* outringlen (given when the inflator was created) when accessing outring.
*/
LWS_VISIBLE LWS_EXTERN lws_stateful_ret_t
lws_upng_inflate_data(struct inflator_ctx *inf, const void *buf, size_t len);
/**
* lws_upng_inflator_destroy() - destroys the inflation context and ringbuffer
*
* \p inf: pointer to pointer to inflation context
*
* Frees the inflation context and its allocations, and sets \p *inf to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_upng_inflator_destroy(struct inflator_ctx **inf);

View File

@ -0,0 +1,284 @@
/*
* 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 fops file operation wrapping
*
* ##File operation wrapping
*
* Use these helper functions if you want to access a file from the perspective
* of a specific wsi, which is usually the case. If you just want contextless
* file access, use the fops callbacks directly with NULL wsi instead of these
* helpers.
*
* If so, then it calls the platform handler or user overrides where present
* (as defined in info->fops)
*
* The advantage from all this is user code can be portable for file operations
* without having to deal with differences between platforms.
*/
//@{
/** struct lws_plat_file_ops - Platform-specific file operations
*
* These provide platform-agnostic ways to deal with filesystem access in the
* library and in the user code.
*/
#if defined(LWS_PLAT_FREERTOS)
/* sdk preprocessor defs? compiler issue? gets confused with member names */
#define LWS_FOP_OPEN _open
#define LWS_FOP_CLOSE _close
#define LWS_FOP_SEEK_CUR _seek_cur
#define LWS_FOP_READ _read
#define LWS_FOP_WRITE _write
#else
#define LWS_FOP_OPEN open
#define LWS_FOP_CLOSE close
#define LWS_FOP_SEEK_CUR seek_cur
#define LWS_FOP_READ read
#define LWS_FOP_WRITE write
#endif
#define LWS_FOP_FLAGS_MASK ((1 << 23) - 1)
#define LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP (1 << 24)
#define LWS_FOP_FLAG_COMPR_IS_GZIP (1 << 25)
#define LWS_FOP_FLAG_MOD_TIME_VALID (1 << 26)
#define LWS_FOP_FLAG_VIRTUAL (1 << 27)
struct lws_plat_file_ops;
struct lws_fop_fd {
lws_filefd_type fd;
/**< real file descriptor related to the file... */
const struct lws_plat_file_ops *fops;
/**< fops that apply to this fop_fd */
void *filesystem_priv;
/**< ignored by lws; owned by the fops handlers */
lws_filepos_t pos;
/**< generic "position in file" */
lws_filepos_t len;
/**< generic "length of file" */
lws_fop_flags_t flags;
/**< copy of the returned flags */
uint32_t mod_time;
/**< optional "modification time of file", only valid if .open()
* set the LWS_FOP_FLAG_MOD_TIME_VALID flag */
};
typedef struct lws_fop_fd *lws_fop_fd_t;
struct lws_fops_index {
const char *sig; /* NULL or vfs signature, eg, ".zip/" */
uint8_t len; /* length of above string */
};
struct lws_plat_file_ops {
lws_fop_fd_t (*LWS_FOP_OPEN)(const struct lws_plat_file_ops *fops_own,
const struct lws_plat_file_ops *fops,
const char *filename, const char *vpath,
lws_fop_flags_t *flags);
/**< Open file (always binary access if plat supports it)
* fops_own is the fops this was called through. fops is the base
* fops the open can use to find files to process as present as its own,
* like the zip fops does.
*
* vpath may be NULL, or if the fops understands it, the point at which
* the filename's virtual part starts.
* *flags & LWS_FOP_FLAGS_MASK should be set to O_RDONLY or O_RDWR.
* If the file may be gzip-compressed,
* LWS_FOP_FLAG_COMPR_ACCEPTABLE_GZIP is set. If it actually is
* gzip-compressed, then the open handler should OR
* LWS_FOP_FLAG_COMPR_IS_GZIP on to *flags before returning.
*/
int (*LWS_FOP_CLOSE)(lws_fop_fd_t *fop_fd);
/**< close file AND set the pointer to NULL */
lws_fileofs_t (*LWS_FOP_SEEK_CUR)(lws_fop_fd_t fop_fd,
lws_fileofs_t offset_from_cur_pos);
/**< seek from current position */
int (*LWS_FOP_READ)(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len);
/**< Read from file, on exit *amount is set to amount actually read */
int (*LWS_FOP_WRITE)(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len);
/**< Write to file, on exit *amount is set to amount actually written */
struct lws_fops_index fi[3];
/**< vfs path signatures implying use of this fops */
const struct lws_plat_file_ops *next;
/**< NULL or next fops in list... eg copy static fops def to heap
* and modify copy at runtime */
struct lws_context *cx;
/**< the lws_context... eg copy static fops def to heap
* and modify copy at runtime */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility */
};
/**
* lws_get_fops() - get current file ops
*
* \param context: context
*/
LWS_VISIBLE LWS_EXTERN struct lws_plat_file_ops * LWS_WARN_UNUSED_RESULT
lws_get_fops(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_set_fops(struct lws_context *context, const struct lws_plat_file_ops *fops);
/**
* lws_vfs_tell() - get current file position
*
* \param fop_fd: fop_fd we are asking about
*/
LWS_VISIBLE LWS_EXTERN lws_filepos_t LWS_WARN_UNUSED_RESULT
lws_vfs_tell(lws_fop_fd_t fop_fd);
/**
* lws_vfs_get_length() - get current file total length in bytes
*
* \param fop_fd: fop_fd we are asking about
*/
LWS_VISIBLE LWS_EXTERN lws_filepos_t LWS_WARN_UNUSED_RESULT
lws_vfs_get_length(lws_fop_fd_t fop_fd);
/**
* lws_vfs_get_mod_time() - get time file last modified
*
* \param fop_fd: fop_fd we are asking about
*/
LWS_VISIBLE LWS_EXTERN uint32_t LWS_WARN_UNUSED_RESULT
lws_vfs_get_mod_time(lws_fop_fd_t fop_fd);
/**
* lws_vfs_file_seek_set() - seek relative to start of file
*
* \param fop_fd: fop_fd we are seeking in
* \param offset: offset from start of file
*/
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
/**
* lws_vfs_file_seek_end() - seek relative to end of file
*
* \param fop_fd: fop_fd we are seeking in
* \param offset: offset from start of file
*/
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
extern struct lws_plat_file_ops fops_zip;
/**
* lws_plat_file_open() - open vfs filepath
*
* \param fops: file ops struct that applies to this descriptor
* \param vfs_path: filename to open
* \param flags: pointer to open flags
*
* The vfs_path is scanned for known fops signatures, and the open directed
* to any matching fops open.
*
* User code should use this api to perform vfs opens.
*
* returns semi-opaque handle
*/
LWS_VISIBLE LWS_EXTERN lws_fop_fd_t LWS_WARN_UNUSED_RESULT
lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
lws_fop_flags_t *flags);
/**
* lws_plat_file_close() - close file
*
* \param fop_fd: file handle to close
*/
static LWS_INLINE int
lws_vfs_file_close(lws_fop_fd_t *fop_fd)
{
if (*fop_fd && (*fop_fd)->fops)
return (*fop_fd)->fops->LWS_FOP_CLOSE(fop_fd);
return 0;
}
/**
* lws_plat_file_seek_cur() - close file
*
*
* \param fop_fd: file handle
* \param offset: position to seek to
*/
static LWS_INLINE lws_fileofs_t
lws_vfs_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
{
return fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, offset);
}
/**
* lws_plat_file_read() - read from file
*
* \param fop_fd: file handle
* \param amount: how much to read (rewritten by call)
* \param buf: buffer to write to
* \param len: max length
*/
static LWS_INLINE int LWS_WARN_UNUSED_RESULT
lws_vfs_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len)
{
return fop_fd->fops->LWS_FOP_READ(fop_fd, amount, buf, len);
}
/**
* lws_plat_file_write() - write from file
*
* \param fop_fd: file handle
* \param amount: how much to write (rewritten by call)
* \param buf: buffer to read from
* \param len: max length
*/
static LWS_INLINE int LWS_WARN_UNUSED_RESULT
lws_vfs_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len)
{
return fop_fd->fops->LWS_FOP_WRITE(fop_fd, amount, buf, len);
}
/* these are the platform file operations implementations... they can
* be called directly and used in fops arrays
*/
LWS_VISIBLE LWS_EXTERN lws_fop_fd_t
_lws_plat_file_open(const struct lws_plat_file_ops *fops_own,
const struct lws_plat_file_ops *fops, const char *filename,
const char *vpath, lws_fop_flags_t *flags);
LWS_VISIBLE LWS_EXTERN int
_lws_plat_file_close(lws_fop_fd_t *fop_fd);
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
_lws_plat_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset);
LWS_VISIBLE LWS_EXTERN int
_lws_plat_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len);
LWS_VISIBLE LWS_EXTERN int
_lws_plat_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
uint8_t *buf, lws_filepos_t len);
LWS_VISIBLE LWS_EXTERN int
lws_alloc_vfs_file(struct lws_context *context, const char *filename,
uint8_t **buf, lws_filepos_t *amount);
//@}

View File

@ -0,0 +1,259 @@
/*
* 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 sending-data Sending data
APIs related to writing data on a connection
*/
//@{
#define LWS_WRITE_RAW LWS_WRITE_HTTP
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
*/
enum lws_write_protocol {
LWS_WRITE_TEXT = 0,
/**< Send a ws TEXT message,the pointer must have LWS_PRE valid
* memory behind it.
*
* The receiver expects only valid utf-8 in the payload */
LWS_WRITE_BINARY = 1,
/**< Send a ws BINARY message, the pointer must have LWS_PRE valid
* memory behind it.
*
* Any sequence of bytes is valid */
LWS_WRITE_CONTINUATION = 2,
/**< Continue a previous ws message, the pointer must have LWS_PRE valid
* memory behind it */
LWS_WRITE_HTTP = 3,
/**< Send HTTP content */
/* LWS_WRITE_CLOSE is handled by lws_close_reason() */
LWS_WRITE_PING = 5,
LWS_WRITE_PONG = 6,
/* Same as write_http but we know this write ends the transaction */
LWS_WRITE_HTTP_FINAL = 7,
/* HTTP2 */
LWS_WRITE_HTTP_HEADERS = 8,
/**< Send http headers (http2 encodes this payload and LWS_WRITE_HTTP
* payload differently, http 1.x links also handle this correctly. so
* to be compatible with both in the future,header response part should
* be sent using this regardless of http version expected)
*/
LWS_WRITE_HTTP_HEADERS_CONTINUATION = 9,
/**< Continuation of http/2 headers
*/
/****** add new things just above ---^ ******/
/* flags */
LWS_WRITE_BUFLIST = 0x20,
/**< Don't actually write it... stick it on the output buflist and
* write it as soon as possible. Useful if you learn you have to
* write something, have the data to write to hand but the timing is
* unrelated as to whether the connection is writable or not, and were
* otherwise going to have to allocate a temp buffer and write it
* later anyway */
LWS_WRITE_NO_FIN = 0x40,
/**< This part of the message is not the end of the message */
LWS_WRITE_H2_STREAM_END = 0x80,
/**< Flag indicates this packet should go out with STREAM_END if h2
* STREAM_END is allowed on DATA or HEADERS.
*/
LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80
/**< client packet payload goes out on wire unmunged
* only useful for security tests since normal servers cannot
* decode the content if used */
};
/* used with LWS_CALLBACK_CHILD_WRITE_VIA_PARENT */
struct lws_write_passthru {
struct lws *wsi;
unsigned char *buf;
size_t len;
enum lws_write_protocol wp;
};
/**
* lws_write() - Apply protocol then write data to client
*
* \param wsi: Websocket instance (available from user callback)
* \param buf: The data to send. For data being sent on a websocket
* connection (ie, not default http), this buffer MUST have
* LWS_PRE bytes valid BEFORE the pointer.
* This is so the protocol header data can be added in-situ.
* \param len: Count of the data bytes in the payload starting from buf
* \param protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
* of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
* data on a websockets connection. Remember to allow the extra
* bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
* are used.
*
* This function provides the way to issue data back to the client, for any
* role (h1, h2, ws, raw, etc). It can only be called from the WRITEABLE
* callback.
*
* IMPORTANT NOTICE!
*
* When sending with ws protocol
*
* LWS_WRITE_TEXT,
* LWS_WRITE_BINARY,
* LWS_WRITE_CONTINUATION,
* LWS_WRITE_PING,
* LWS_WRITE_PONG,
*
* or sending on http/2... the send buffer has to have LWS_PRE bytes valid
* BEFORE the buffer pointer you pass to lws_write(). Since you'll probably
* want to use http/2 before too long, it's wise to just always do this with
* lws_write buffers... LWS_PRE is typically 16 bytes it's not going to hurt
* usually.
*
* start of alloc ptr passed to lws_write end of allocation
* | | |
* v <-- LWS_PRE bytes --> v v
* [---------------- allocated memory ---------------]
* (for lws use) [====== user buffer ======]
*
* This allows us to add protocol info before the data, and send as one packet
* on the network without payload copying, for maximum efficiency.
*
* So for example you need this kind of code to use lws_write with a
* 128-byte payload
*
* char buf[LWS_PRE + 128];
*
* // fill your part of the buffer... for example here it's all zeros
* memset(&buf[LWS_PRE], 0, 128);
*
* if (lws_write(wsi, &buf[LWS_PRE], 128, LWS_WRITE_TEXT) < 128) {
* ... the connection is dead ...
* return -1;
* }
*
* LWS_PRE is currently 16, which covers ws and h2 frame headers, and is
* compatible with 32 and 64-bit alignment requirements.
*
* (LWS_SEND_BUFFER_POST_PADDING is deprecated, it's now 0 and can be left off.)
*
* Return may be -1 is the write failed in a way indicating that the connection
* has ended already, in which case you can close your side, or a positive
* number that is at least the number of bytes requested to send (under some
* encapsulation scenarios, it can indicate more than you asked was sent).
*
* The recommended test of the return is less than what you asked indicates
* the connection has failed.
*
* Truncated Writes
* ================
*
* The OS may not accept everything you asked to write on the connection.
*
* Posix defines POLLOUT indication from poll() to show that the connection
* will accept more write data, but it doesn't specifiy how much. It may just
* accept one byte of whatever you wanted to send.
*
* LWS will buffer the remainder automatically, and send it out autonomously.
*
* During that time, WRITABLE callbacks to user code will be suppressed and
* instead used internally. After it completes, it will send an extra WRITEABLE
* callback to the user code, in case any request was missed. So it is possible
* to receive unasked-for WRITEABLE callbacks, the user code should have enough
* state to know if it wants to write anything and just return if not.
*
* This is to handle corner cases where unexpectedly the OS refuses what we
* usually expect it to accept. It's not recommended as the way to randomly
* send huge payloads, since it is being copied on to heap and is inefficient.
*
* Huge payloads should instead be sent in fragments that are around 2 x mtu,
* which is almost always directly accepted by the OS. To simplify this for
* ws fragments, there is a helper lws_write_ws_flags() below that simplifies
* selecting the correct flags to give lws_write() for each fragment.
*
* In the case of RFC8441 ws-over-h2, you cannot send ws fragments larger than
* the max h2 frame size, typically 16KB, but should further restrict it to
* the same ~2 x mtu limit mentioned above.
*/
LWS_VISIBLE LWS_EXTERN int
lws_write(struct lws *wsi, unsigned char *buf, size_t len,
enum lws_write_protocol protocol);
/* helper for case where buffer may be const */
#define lws_write_http(wsi, buf, len) \
lws_write(wsi, (unsigned char *)(buf), len, LWS_WRITE_HTTP)
/**
* lws_write_ws_flags() - Helper for multi-frame ws message flags
*
* \param initial: the lws_write flag to use for the start fragment, eg,
* LWS_WRITE_TEXT
* \param is_start: nonzero if this is the first fragment of the message
* \param is_end: nonzero if this is the last fragment of the message
*
* Returns the correct LWS_WRITE_ flag to use for each fragment of a message
* in turn.
*/
static LWS_INLINE int
lws_write_ws_flags(int initial, int is_start, int is_end)
{
int r;
if (is_start)
r = initial;
else
r = LWS_WRITE_CONTINUATION;
if (!is_end)
r |= LWS_WRITE_NO_FIN;
return r;
}
/**
* lws_raw_transaction_completed() - Helper for flushing before close
*
* \param wsi: the struct lws to operate on
*
* Returns -1 if the wsi can close now. However if there is buffered, unsent
* data, the wsi is marked as to be closed when the output buffer data is
* drained, and it returns 0.
*
* For raw cases where the transaction completed without failure,
* `return lws_raw_transaction_completed(wsi)` should better be used than
* return -1.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_raw_transaction_completed(struct lws *wsi);
///@}

View File

@ -0,0 +1,246 @@
/*
* 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 callback-when-writeable Callback when writeable
*
* ##Callback When Writeable
*
* lws can only write data on a connection when it is able to accept more
* data without blocking.
*
* So a basic requirement is we should only use the lws_write() apis when the
* connection we want to write on says that he can accept more data.
*
* When lws cannot complete your send at the time, it will buffer the data
* and send it in the background, suppressing any further WRITEABLE callbacks
* on that connection until it completes. So it is important to write new
* things in a new writeable callback.
*
* These apis reflect the various ways we can indicate we would like to be
* called back when one or more connections is writeable.
*/
///@{
/**
* lws_callback_on_writable() - Request a callback when this socket
* becomes able to be written to without
* blocking
*
* \param wsi: Websocket connection instance to get callback for
*
* - Which: only this wsi
* - When: when the individual connection becomes writeable
* - What: LWS_CALLBACK_*_WRITEABLE
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_on_writable(struct lws *wsi);
/**
* lws_callback_on_writable_all_protocol() - Request a callback for all
* connections using the given protocol when it
* becomes possible to write to each socket without
* blocking in turn.
*
* \param context: lws_context
* \param protocol: Protocol whose connections will get callbacks
*
* - Which: connections using this protocol on ANY VHOST
* - When: when the individual connection becomes writeable
* - What: LWS_CALLBACK_*_WRITEABLE
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_on_writable_all_protocol(const struct lws_context *context,
const struct lws_protocols *protocol);
/**
* lws_callback_on_writable_all_protocol_vhost() - Request a callback for
* all connections on same vhost using the given protocol
* when it becomes possible to write to each socket without
* blocking in turn.
*
* \param vhost: Only consider connections on this lws_vhost
* \param protocol: Protocol whose connections will get callbacks
*
* - Which: connections using this protocol on GIVEN VHOST ONLY
* - When: when the individual connection becomes writeable
* - What: LWS_CALLBACK_*_WRITEABLE
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
const struct lws_protocols *protocol);
/**
* lws_callback_all_protocol() - Callback all connections using
* the given protocol with the given reason
*
* \param context: lws_context
* \param protocol: Protocol whose connections will get callbacks
* \param reason: Callback reason index
*
* - Which: connections using this protocol on ALL VHOSTS
* - When: before returning
* - What: reason
*
* This isn't normally what you want... normally any update of connection-
* specific information can wait until a network-related callback like rx,
* writable, or close.
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_all_protocol(struct lws_context *context,
const struct lws_protocols *protocol, int reason);
/**
* lws_callback_all_protocol_vhost() - Callback all connections using
* the given protocol with the given reason. This is
* deprecated since v2.4: use lws_callback_all_protocol_vhost_args
*
* \param vh: Vhost whose connections will get callbacks
* \param protocol: Which protocol to match. NULL means all.
* \param reason: Callback reason index
*
* - Which: connections using this protocol on GIVEN VHOST ONLY
* - When: now
* - What: reason
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
const struct lws_protocols *protocol,
int reason)
LWS_WARN_DEPRECATED;
/**
* lws_callback_all_protocol_vhost_args() - Callback all connections using
* the given protocol with the given reason and args
*
* \param vh: Vhost whose connections will get callbacks
* \param protocol: Which protocol to match. NULL means all.
* \param reason: Callback reason index
* \param argp: Callback "in" parameter
* \param len: Callback "len" parameter
*
* - Which: connections using this protocol on GIVEN VHOST ONLY
* - When: now
* - What: reason
*/
LWS_VISIBLE int
lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
const struct lws_protocols *protocol,
int reason, void *argp, size_t len);
/**
* lws_callback_vhost_protocols() - Callback all protocols enabled on a vhost
* with the given reason
*
* \param wsi: wsi whose vhost will get callbacks
* \param reason: Callback reason index
* \param in: in argument to callback
* \param len: len argument to callback
*
* - Which: connections using this protocol on same VHOST as wsi ONLY
* - When: now
* - What: reason
*
* This is deprecated since v2.5, use lws_callback_vhost_protocols_vhost()
* which takes the pointer to the vhost directly without using or needing the
* wsi.
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, size_t len)
LWS_WARN_DEPRECATED;
/**
* lws_callback_vhost_protocols_vhost() - Callback all protocols enabled on a vhost
* with the given reason
*
* \param vh: vhost that will get callbacks
* \param reason: Callback reason index
* \param in: in argument to callback
* \param len: len argument to callback
*
* - Which: connections using this protocol on same VHOST as wsi ONLY
* - When: now
* - What: reason
*/
LWS_VISIBLE LWS_EXTERN int
lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
size_t len);
LWS_VISIBLE LWS_EXTERN int
lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len);
/**
* lws_get_socket_fd() - returns the socket file descriptor
*
* This is needed to use sendto() on UDP raw sockets
*
* \param wsi: Websocket connection instance
*/
LWS_VISIBLE LWS_EXTERN lws_sockfd_type
lws_get_socket_fd(struct lws *wsi);
/**
* lws_get_peer_write_allowance() - get the amount of data writeable to peer
* if known
*
* \param wsi: Websocket connection instance
*
* if the protocol does not have any guidance, returns -1. Currently only
* http2 connections get send window information from this API. But your code
* should use it so it can work properly with any protocol.
*
* If nonzero return is the amount of payload data the peer or intermediary has
* reported it has buffer space for. That has NO relationship with the amount
* of buffer space your OS can accept on this connection for a write action.
*
* This number represents the maximum you could send to the peer or intermediary
* on this connection right now without the protocol complaining.
*
* lws manages accounting for send window updates and payload writes
* automatically, so this number reflects the situation at the peer or
* intermediary dynamically.
*/
LWS_VISIBLE LWS_EXTERN lws_fileofs_t
lws_get_peer_write_allowance(struct lws *wsi);
/**
* lws_wsi_tx_credit() - get / set generic tx credit if role supports it
*
* \param wsi: connection to set / get tx credit on
* \param peer_to_us: 0 = set / get us-to-peer direction, else peer-to-us
* \param add: amount of credit to add
*
* If the wsi does not support tx credit, returns 0.
*
* If add is zero, returns one of the wsi tx credit values for the wsi.
* If add is nonzero, \p add is added to the selected tx credit value
* for the wsi.
*/
#define LWSTXCR_US_TO_PEER 0
#define LWSTXCR_PEER_TO_US 1
LWS_VISIBLE LWS_EXTERN int
lws_wsi_tx_credit(struct lws *wsi, char peer_to_us, int add);
///@}

View File

@ -0,0 +1,125 @@
/*
* 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 wsclose Websocket Close
*
* ##Websocket close frame control
*
* When we close a ws connection, we can send a reason code and a short
* UTF-8 description back with the close packet.
*/
///@{
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
*/
/** enum lws_close_status - RFC6455 close status codes */
enum lws_close_status {
LWS_CLOSE_STATUS_NOSTATUS = 0,
LWS_CLOSE_STATUS_NORMAL = 1000,
/**< 1000 indicates a normal closure, meaning that the purpose for
which the connection was established has been fulfilled. */
LWS_CLOSE_STATUS_GOINGAWAY = 1001,
/**< 1001 indicates that an endpoint is "going away", such as a server
going down or a browser having navigated away from a page. */
LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002,
/**< 1002 indicates that an endpoint is terminating the connection due
to a protocol error. */
LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003,
/**< 1003 indicates that an endpoint is terminating the connection
because it has received a type of data it cannot accept (e.g., an
endpoint that understands only text data MAY send this if it
receives a binary message). */
LWS_CLOSE_STATUS_RESERVED = 1004,
/**< Reserved. The specific meaning might be defined in the future. */
LWS_CLOSE_STATUS_NO_STATUS = 1005,
/**< 1005 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that no status
code was actually present. */
LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006,
/**< 1006 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that the
connection was closed abnormally, e.g., without sending or
receiving a Close control frame. */
LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007,
/**< 1007 indicates that an endpoint is terminating the connection
because it has received data within a message that was not
consistent with the type of the message (e.g., non-UTF-8 [RFC3629]
data within a text message). */
LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008,
/**< 1008 indicates that an endpoint is terminating the connection
because it has received a message that violates its policy. This
is a generic status code that can be returned when there is no
other more suitable status code (e.g., 1003 or 1009) or if there
is a need to hide specific details about the policy. */
LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009,
/**< 1009 indicates that an endpoint is terminating the connection
because it has received a message that is too big for it to
process. */
LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010,
/**< 1010 indicates that an endpoint (client) is terminating the
connection because it has expected the server to negotiate one or
more extension, but the server didn't return them in the response
message of the WebSocket handshake. The list of extensions that
are needed SHOULD appear in the /reason/ part of the Close frame.
Note that this status code is not used by the server, because it
can fail the WebSocket handshake instead */
LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011,
/**< 1011 indicates that a server is terminating the connection because
it encountered an unexpected condition that prevented it from
fulfilling the request. */
LWS_CLOSE_STATUS_TLS_FAILURE = 1015,
/**< 1015 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that the
connection was closed due to a failure to perform a TLS handshake
(e.g., the server certificate can't be verified). */
LWS_CLOSE_STATUS_CLIENT_TRANSACTION_DONE = 2000,
/****** add new things just above ---^ ******/
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY = 9999,
};
/**
* lws_close_reason - Set reason and aux data to send with Close packet
* If you are going to return nonzero from the callback
* requesting the connection to close, you can optionally
* call this to set the reason the peer will be told if
* possible.
*
* \param wsi: The websocket connection to set the close reason on
* \param status: A valid close status from websocket standard
* \param buf: NULL or buffer containing up to 124 bytes of auxiliary data
* \param len: Length of data in \p buf to send
*/
LWS_VISIBLE LWS_EXTERN void
lws_close_reason(struct lws *wsi, enum lws_close_status status,
unsigned char *buf, size_t len);
///@}

View File

@ -0,0 +1,198 @@
/*
* 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 extensions Extension related functions
* ##Extension releated functions
*
* Ws defines optional extensions, lws provides the ability to implement these
* in user code if so desired.
*
* We provide one extensions permessage-deflate.
*/
///@{
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* add it at where specified so existing users are unaffected.
*/
enum lws_extension_callback_reasons {
LWS_EXT_CB_CONSTRUCT = 4,
LWS_EXT_CB_CLIENT_CONSTRUCT = 5,
LWS_EXT_CB_DESTROY = 8,
LWS_EXT_CB_PACKET_TX_PRESEND = 12,
LWS_EXT_CB_PAYLOAD_TX = 21,
LWS_EXT_CB_PAYLOAD_RX = 22,
LWS_EXT_CB_OPTION_DEFAULT = 23,
LWS_EXT_CB_OPTION_SET = 24,
LWS_EXT_CB_OPTION_CONFIRM = 25,
LWS_EXT_CB_NAMED_OPTION_SET = 26,
/****** add new things just above ---^ ******/
};
/** enum lws_ext_options_types */
enum lws_ext_options_types {
EXTARG_NONE, /**< does not take an argument */
EXTARG_DEC, /**< requires a decimal argument */
EXTARG_OPT_DEC /**< may have an optional decimal argument */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility */
};
/** struct lws_ext_options - Option arguments to the extension. These are
* used in the negotiation at ws upgrade time.
* The helper function lws_ext_parse_options()
* uses these to generate callbacks */
struct lws_ext_options {
const char *name; /**< Option name, eg, "server_no_context_takeover" */
enum lws_ext_options_types type; /**< What kind of args the option can take */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility */
};
/** struct lws_ext_option_arg */
struct lws_ext_option_arg {
const char *option_name; /**< may be NULL, option_index used then */
int option_index; /**< argument ordinal to use if option_name missing */
const char *start; /**< value */
int len; /**< length of value */
};
/**
* typedef lws_extension_callback_function() - Hooks to allow extensions to operate
* \param context: Websockets context
* \param ext: This extension
* \param wsi: Opaque websocket instance pointer
* \param reason: The reason for the call
* \param user: Pointer to ptr to per-session user data allocated by library
* \param in: Pointer used for some callback reasons
* \param len: Length set for some callback reasons
*
* Each extension that is active on a particular connection receives
* callbacks during the connection lifetime to allow the extension to
* operate on websocket data and manage itself.
*
* Libwebsockets takes care of allocating and freeing "user" memory for
* each active extension on each connection. That is what is pointed to
* by the user parameter.
*
* LWS_EXT_CB_CONSTRUCT: called when the server has decided to
* select this extension from the list provided by the client,
* just before the server will send back the handshake accepting
* the connection with this extension active. This gives the
* extension a chance to initialize its connection context found
* in user.
*
* LWS_EXT_CB_CLIENT_CONSTRUCT: same as LWS_EXT_CB_CONSTRUCT
* but called when client is instantiating this extension. Some
* extensions will work the same on client and server side and then
* you can just merge handlers for both CONSTRUCTS.
*
* LWS_EXT_CB_DESTROY: called when the connection the extension was
* being used on is about to be closed and deallocated. It's the
* last chance for the extension to deallocate anything it has
* allocated in the user data (pointed to by user) before the
* user data is deleted. This same callback is used whether you
* are in client or server instantiation context.
*
* LWS_EXT_CB_PACKET_TX_PRESEND: this works the same way as
* LWS_EXT_CB_PACKET_RX_PREPARSE above, except it gives the
* extension a chance to change websocket data just before it will
* be sent out. Using the same lws_token pointer scheme in in,
* the extension can change the buffer and the length to be
* transmitted how it likes. Again if it wants to grow the
* buffer safely, it should copy the data into its own buffer and
* set the lws_tokens token pointer to it.
*
* LWS_EXT_CB_ARGS_VALIDATE:
*/
typedef int
lws_extension_callback_function(struct lws_context *context,
const struct lws_extension *ext, struct lws *wsi,
enum lws_extension_callback_reasons reason,
void *user, void *in, size_t len);
/** struct lws_extension - An extension we support */
struct lws_extension {
const char *name; /**< Formal extension name, eg, "permessage-deflate" */
lws_extension_callback_function *callback; /**< Service callback */
const char *client_offer; /**< String containing exts and options client offers */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility */
};
/**
* lws_set_extension_option(): set extension option if possible
*
* \param wsi: websocket connection
* \param ext_name: name of ext, like "permessage-deflate"
* \param opt_name: name of option, like "rx_buf_size"
* \param opt_val: value to set option to
*/
LWS_VISIBLE LWS_EXTERN int
lws_set_extension_option(struct lws *wsi, const char *ext_name,
const char *opt_name, const char *opt_val);
/**
* lws_ext_parse_options() - deal with parsing negotiated extension options
*
* \param ext: related extension struct
* \param wsi: websocket connection
* \param ext_user: per-connection extension private data
* \param opts: list of supported options
* \param o: option string to parse
* \param len: length
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_ext_parse_options(const struct lws_extension *ext, struct lws *wsi,
void *ext_user, const struct lws_ext_options *opts,
const char *o, int len);
/** lws_extension_callback_pm_deflate() - extension for RFC7692
*
* \param context: lws context
* \param ext: related lws_extension struct
* \param wsi: websocket connection
* \param reason: incoming callback reason
* \param user: per-connection extension private data
* \param in: pointer parameter
* \param len: length parameter
*
* Built-in callback implementing RFC7692 permessage-deflate
*/
LWS_VISIBLE LWS_EXTERN int
lws_extension_callback_pm_deflate(struct lws_context *context,
const struct lws_extension *ext,
struct lws *wsi,
enum lws_extension_callback_reasons reason,
void *user, void *in, size_t len);
/*
* The internal exts are part of the public abi
* If we add more extensions, publish the callback here ------v
*/
///@}

View File

@ -0,0 +1,100 @@
/*
* 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 wsstatus Websocket status APIs
* ##Websocket connection status APIs
*
* These provide information about ws connection or message status
*/
///@{
/**
* lws_send_pipe_choked() - tests if socket is writable or not
* \param wsi: lws connection
*
* Allows you to check if you can write more on the socket
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_send_pipe_choked(struct lws *wsi);
/**
* lws_is_final_fragment() - tests if last part of ws message
*
* \param wsi: lws connection
*/
LWS_VISIBLE LWS_EXTERN int
lws_is_final_fragment(struct lws *wsi);
/**
* lws_is_first_fragment() - tests if first part of ws message
*
* \param wsi: lws connection
*/
LWS_VISIBLE LWS_EXTERN int
lws_is_first_fragment(struct lws *wsi);
/**
* lws_get_reserved_bits() - access reserved bits of ws frame
* \param wsi: lws connection
*/
LWS_VISIBLE LWS_EXTERN unsigned char
lws_get_reserved_bits(struct lws *wsi);
/**
* lws_get_opcode() - access opcode of ws frame
* \param wsi: lws connection
*/
LWS_VISIBLE LWS_EXTERN uint8_t
lws_get_opcode(struct lws *wsi);
/**
* lws_partial_buffered() - find out if lws buffered the last write
* \param wsi: websocket connection to check
*
* Returns 1 if you cannot use lws_write because the last
* write on this connection is still buffered, and can't be cleared without
* returning to the service loop and waiting for the connection to be
* writeable again.
*
* If you will try to do >1 lws_write call inside a single
* WRITEABLE callback, you must check this after every write and bail if
* set, ask for a new writeable callback and continue writing from there.
*
* This is never set at the start of a writeable callback, but any write
* may set it.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_partial_buffered(struct lws *wsi);
/**
* lws_frame_is_binary(): true if the current frame was sent in binary mode
*
* \param wsi: the connection we are inquiring about
*
* This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
* it's interested to see if the frame it's dealing with was sent in binary
* mode.
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_frame_is_binary(struct lws *wsi);
///@}

View File

@ -0,0 +1,293 @@
/*
* 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.
*/
enum lws_tls_cert_info {
LWS_TLS_CERT_INFO_VALIDITY_FROM,
/**< fills .time with the time_t the cert validity started from */
LWS_TLS_CERT_INFO_VALIDITY_TO,
/**< fills .time with the time_t the cert validity ends at */
LWS_TLS_CERT_INFO_COMMON_NAME,
/**< fills up to len bytes of .ns.name with the cert common name */
LWS_TLS_CERT_INFO_ISSUER_NAME,
/**< fills up to len bytes of .ns.name with the cert issuer name */
LWS_TLS_CERT_INFO_USAGE,
/**< fills verified with a bitfield asserting the valid uses */
LWS_TLS_CERT_INFO_VERIFIED,
/**< fills .verified with a bool representing peer cert validity,
* call returns -1 if no cert */
LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY,
/**< the certificate's public key, as an opaque bytestream. These
* opaque bytestreams can only be compared with each other using the
* same tls backend, ie, OpenSSL or mbedTLS. The different backends
* produce different, incompatible representations for the same cert.
*/
LWS_TLS_CERT_INFO_DER_RAW,
/**< the certificate's raw DER representation. If it's too big,
* -1 is returned and the size will be returned in buf->ns.len.
* If the certificate cannot be found -1 is returned and 0 in
* buf->ns.len. */
LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID,
/**< If the cert has one, the key ID responsible for the signature */
LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER,
/**< If the cert has one, the issuer responsible for the signature */
LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_SERIAL,
/**< If the cert has one, serial number responsible for the signature */
LWS_TLS_CERT_INFO_SUBJECT_KEY_ID,
/**< If the cert has one, the cert's subject key ID */
};
union lws_tls_cert_info_results {
unsigned int verified;
time_t time;
unsigned int usage;
struct {
int len;
/* KEEP LAST... notice the [64] is only there because
* name[] is not allowed in a union. The actual length of
* name[] is arbitrary and is passed into the api using the
* len parameter. Eg
*
* char big[1024];
* union lws_tls_cert_info_results *buf =
* (union lws_tls_cert_info_results *)big;
*
* lws_tls_peer_cert_info(wsi, type, buf, sizeof(big) -
* sizeof(*buf) + sizeof(buf->ns.name));
*/
char name[64];
} ns;
};
struct lws_x509_cert;
struct lws_jwk;
/**
* lws_x509_create() - Allocate an lws_x509_cert object
*
* \param x509: pointer to lws_x509_cert pointer to be set to allocated object
*
* Allocates an lws_x509_cert object and set *x509 to point to it.
*/
LWS_VISIBLE LWS_EXTERN int
lws_x509_create(struct lws_x509_cert **x509);
/**
* lws_x509_parse_from_pem() - Read one or more x509 certs in PEM format from memory
*
* \param x509: pointer to lws_x509_cert object
* \param pem: pointer to PEM format content
* \param len: length of PEM format content
*
* Parses PEM certificates in memory into a native x509 representation for the
* TLS library. If there are multiple PEM certs concatenated, they are all
* read into the same object and exist as a "chain".
*
* IMPORTANT for compatibility with mbedtls, the last used byte of \p pem
* must be '\0' and the \p len must include it.
*
* Returns 0 if all went OK, or nonzero for failure.
*/
LWS_VISIBLE LWS_EXTERN int
lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len);
/**
* lws_x509_verify() - Validate signing relationship between one or more certs
* and a trusted CA cert
*
* \param x509: pointer to lws_x509_cert object, may contain multiple
* \param trusted: a single, trusted cert object that we are checking for
* \param common_name: NULL, or required CN (Common Name) of \p x509
*
* Returns 0 if the cert or certs in \p x509 represent a complete chain that is
* ultimately signed by the cert in \p trusted. Returns nonzero if that's not
* the case.
*/
LWS_VISIBLE LWS_EXTERN int
lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted,
const char *common_name);
/**
* lws_x509_public_to_jwk() - Copy the public key out of a cert and into a JWK
*
* \param jwk: pointer to the jwk to initialize and set to the public key
* \param x509: pointer to lws_x509_cert object that has the public key
* \param curves: NULL to disallow EC, else a comma-separated list of valid
* curves using the JWA naming, eg, "P-256,P-384,P-521".
* \param rsabits: minimum number of RSA bits required in the cert if RSA
*
* Returns 0 if JWK was set to the certificate public key correctly and the
* curve / the RSA key size was acceptable. Automatically produces an RSA or
* EC JWK depending on what the cert had.
*/
LWS_VISIBLE LWS_EXTERN int
lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
const char *curves, int rsabits);
/**
* lws_x509_jwk_privkey_pem() - Copy a private key PEM into a jwk that has the
* public part already
*
* \param cx: lws_context (for random)
* \param jwk: pointer to the jwk to initialize and set to the public key
* \param pem: pointer to PEM private key in memory
* \param len: length of PEM private key in memory
* \param passphrase: NULL or passphrase needed to decrypt private key
*
* IMPORTANT for compatibility with mbedtls, the last used byte of \p pem
* must be '\0' and the \p len must include it.
*
* Returns 0 if the private key was successfully added to the JWK, else
* nonzero if failed.
*
* The PEM image in memory is zeroed down on both successful and failed exits.
* The caller should take care to zero down passphrase if used.
*/
LWS_VISIBLE LWS_EXTERN int
lws_x509_jwk_privkey_pem(struct lws_context *cx, struct lws_jwk *jwk,
void *pem, size_t len, const char *passphrase);
/**
* lws_x509_destroy() - Destroy a previously allocated lws_x509_cert object
*
* \param x509: pointer to lws_x509_cert pointer
*
* Deallocates an lws_x509_cert object and sets its pointer to NULL.
*/
LWS_VISIBLE LWS_EXTERN void
lws_x509_destroy(struct lws_x509_cert **x509);
LWS_VISIBLE LWS_EXTERN int
lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
union lws_tls_cert_info_results *buf, size_t len);
/**
* lws_tls_peer_cert_info() - get information from the peer's TLS cert
*
* \param wsi: the connection to query
* \param type: one of LWS_TLS_CERT_INFO_
* \param buf: pointer to union to take result
* \param len: when result is a string, the true length of buf->ns.name[]
*
* lws_tls_peer_cert_info() lets you get hold of information from the peer
* certificate.
*
* Return 0 if there is a result in \p buf, or nonzero indicating there was no
* cert, or another problem.
*
* This function works the same no matter if the TLS backend is OpenSSL or
* mbedTLS.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
union lws_tls_cert_info_results *buf, size_t len);
/**
* lws_tls_vhost_cert_info() - get information from the vhost's own TLS cert
*
* \param vhost: the vhost to query
* \param type: one of LWS_TLS_CERT_INFO_
* \param buf: pointer to union to take result
* \param len: when result is a string, the true length of buf->ns.name[]
*
* lws_tls_vhost_cert_info() lets you get hold of information from the vhost
* certificate.
*
* Return 0 if there is a result in \p buf, or nonzero indicating there was no
* cert, or another problem.
*
* This function works the same no matter if the TLS backend is OpenSSL or
* mbedTLS.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
union lws_tls_cert_info_results *buf, size_t len);
/**
* lws_tls_acme_sni_cert_create() - creates a temp selfsigned cert
* and attaches to a vhost
*
* \param vhost: the vhost to acquire the selfsigned cert
* \param san_a: SAN written into the certificate
* \param san_b: second SAN written into the certificate
*
*
* Returns 0 if created and attached to the vhost. Returns nonzero if problems,
* and frees all allocations before returning.
*
* On success, any allocations are destroyed at vhost destruction automatically.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
const char *san_b);
/**
* lws_tls_acme_sni_csr_create() - creates a CSR and related private key PEM
*
* \param context: lws_context used for random
* \param elements: array of LWS_TLS_REQ_ELEMENT_COUNT const char *
* \param csr: buffer that will get the b64URL(ASN-1 CSR)
* \param csr_len: max length of the csr buffer
* \param privkey_pem: pointer to pointer allocated to hold the privkey_pem
* \param privkey_len: pointer to size_t set to the length of the privkey_pem
*
* Creates a CSR according to the information in \p elements, and a private
* RSA key used to sign the CSR.
*
* The outputs are the b64URL(ASN-1 CSR) into csr, and the PEM private key into
* privkey_pem.
*
* Notice that \p elements points to an array of const char *s pointing to the
* information listed in the enum above. If an entry is NULL or an empty
* string, the element is set to "none" in the CSR.
*
* Returns 0 on success or nonzero for failure.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
uint8_t *csr, size_t csr_len, char **privkey_pem,
size_t *privkey_len);
/**
* lws_tls_cert_updated() - update every vhost using the given cert path
*
* \param context: our lws_context
* \param certpath: the filepath to the certificate
* \param keypath: the filepath to the private key of the certificate
* \param mem_cert: copy of the cert in memory
* \param len_mem_cert: length of the copy of the cert in memory
* \param mem_privkey: copy of the private key in memory
* \param len_mem_privkey: length of the copy of the private key in memory
*
* Checks every vhost to see if it is the using certificate described by the
* the given filepaths. If so, it attempts to update the vhost ssl_ctx to use
* the new certificate.
*
* Returns 0 on success or nonzero for failure.
*/
LWS_VISIBLE LWS_EXTERN int
lws_tls_cert_updated(struct lws_context *context, const char *certpath,
const char *keypath,
const char *mem_cert, size_t len_mem_cert,
const char *mem_privkey, size_t len_mem_privkey);