Subject: Support to bind accepted socket to device on Linux
[platform/upstream/libwebsockets.git] / lib / libwebsockets.h
index 3598bc1..427fdae 100644 (file)
 #ifdef __cplusplus
 #include <cstddef>
 #include <cstdarg>
-#ifdef MBED_OPERATORS
-#include "mbed-drivers/mbed.h"
-#include "sal-iface-eth/EthernetInterface.h"
-#include "sockets/TCPListener.h"
-#include "sal-stack-lwip/lwipv4_init.h"
-
-namespace {
-}
-using namespace mbed::Sockets::v0;
-
-
-struct sockaddr_in;
-struct lws;
-
-class lws_conn {
-       public:
-       lws_conn():
-               ts(NULL),
-               wsi(NULL),
-               writeable(1),
-               awaiting_on_writeable(0)
-       {
-       }
-
-public:
-       void set_wsi(struct lws *_wsi) { wsi = _wsi; }
-       int actual_onRX(Socket *s);
-       void onRX(Socket *s);
-       void onError(Socket *s, socket_error_t err);
-       void onDisconnect(TCPStream *s);
-       void onSent(Socket *s, uint16_t len);
-       void serialized_writeable(struct lws *wsi);
-
-public:
-       TCPStream *ts;
-
-public:
-       struct lws *wsi;
-       char writeable;
-       char awaiting_on_writeable;
-};
-
-class lws_conn_listener : lws_conn {
-public:
-       lws_conn_listener():
-               srv(SOCKET_STACK_LWIP_IPV4)
-       {
-               srv.setOnError(TCPStream::ErrorHandler_t(this,
-                               &lws_conn_listener::onError));
-       }
-
-       void start(const uint16_t port); /**< start listening */
-
-protected:
-       void onRX(Socket *s); /**< incoming data ready */
-       void onError(Socket *s, socket_error_t err); /**< if error occurs */
-       void onIncoming(TCPListener *s, void *impl); /**< new connection */
-       void onDisconnect(TCPStream *s); /**< disconnection */
-
-public:
-       TCPListener srv;
-};
-
-#endif
-
+#
 extern "C" {
 #else
 #include <stdarg.h>
 #endif
 
-#if defined(MBED_OPERATORS) || defined(LWS_WITH_ESP8266)
+#if defined(LWS_WITH_ESP8266)
 struct sockaddr_in;
 #define LWS_POSIX 0
 #else
@@ -134,6 +70,7 @@ struct sockaddr_in;
 #define LWS_VISIBLE
 #define LWS_WARN_UNUSED_RESULT
 #define LWS_WARN_DEPRECATED
+#define LWS_FORMAT(string_index)
 
 #ifdef LWS_DLL
 #ifdef LWS_INTERNAL
@@ -147,6 +84,9 @@ struct sockaddr_in;
 
 #define LWS_INVALID_FILE INVALID_HANDLE_VALUE
 #define LWS_O_RDONLY _O_RDONLY
+#define LWS_O_WRONLY _O_WRONLY
+#define LWS_O_CREAT _O_CREAT
+#define LWS_O_TRUNC _O_TRUNC
 
 #if !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER < 1900) /* Visual Studio 2015 already defines this in <stdio.h> */
 #define lws_snprintf _snprintf
@@ -156,8 +96,15 @@ struct sockaddr_in;
 #define __func__ __FUNCTION__
 #endif
 
+#if !defined(__MINGW32__) &&(!defined(_MSC_VER) || _MSC_VER < 1900) && !defined(snprintf)
+#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
+#endif
+
 #else /* NOT WIN32 */
 #include <unistd.h>
+#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
+#include <sys/capability.h>
+#endif
 
 #if defined(__NetBSD__) || defined(__FreeBSD__)
 #include <netinet/in.h>
@@ -165,15 +112,22 @@ struct sockaddr_in;
 
 #define LWS_INLINE inline
 #define LWS_O_RDONLY O_RDONLY
+#define LWS_O_WRONLY O_WRONLY
+#define LWS_O_CREAT O_CREAT
+#define LWS_O_TRUNC O_TRUNC
 
-#if !defined(MBED_OPERATORS) && !defined(LWS_WITH_ESP8266) && !defined(OPTEE_TA)
+#if !defined(LWS_WITH_ESP8266) && !defined(OPTEE_TA) && !defined(LWS_WITH_ESP32)
 #include <poll.h>
 #include <netdb.h>
 #define LWS_INVALID_FILE -1
 #else
-#define getdtablesize() (20)
+#define getdtablesize() (30)
+#if defined(LWS_WITH_ESP32)
+#define LWS_INVALID_FILE NULL
+#else
 #define LWS_INVALID_FILE NULL
 #endif
+#endif
 
 #if defined(__GNUC__)
 
@@ -186,10 +140,12 @@ struct sockaddr_in;
 
 #define LWS_VISIBLE __attribute__((visibility("default")))
 #define LWS_WARN_DEPRECATED __attribute__ ((deprecated))
+#define LWS_FORMAT(string_index) __attribute__ ((format(printf, string_index, string_index+1)))
 #else
 #define LWS_VISIBLE
 #define LWS_WARN_UNUSED_RESULT
 #define LWS_WARN_DEPRECATED
+#define LWS_FORMAT(string_index)
 #endif
 
 #if defined(__ANDROID__)
@@ -208,6 +164,9 @@ struct sockaddr_in;
 #include <uv-version.h>
 #endif
 #endif /* LWS_USE_LIBUV */
+#ifdef LWS_USE_LIBEVENT
+#include <event2/event.h>
+#endif /* LWS_USE_LIBEVENT */
 
 #ifndef LWS_EXTERN
 #define LWS_EXTERN extern
@@ -233,23 +192,10 @@ struct sockaddr_in;
 #include <wolfssl/error-ssl.h>
 #endif /* not USE_OLD_CYASSL */
 #else
-#if defined(LWS_USE_POLARSSL)
-#include <polarssl/ssl.h>
-struct lws_polarssl_context {
-       x509_crt ca; /**< ca */
-       x509_crt certificate; /**< cert */
-       rsa_context key; /**< key */
-};
-typedef struct lws_polarssl_context SSL_CTX;
-typedef ssl_context SSL;
-#else
-#if defined(LWS_USE_MBEDTLS)
-#include <mbedtls/ssl.h>
-#else
 #include <openssl/ssl.h>
+#if !defined(LWS_WITH_ESP32)
 #include <openssl/err.h>
-#endif /* not USE_MBEDTLS */
-#endif /* not USE_POLARSSL */
+#endif
 #endif /* not USE_WOLFSSL */
 #endif
 
@@ -280,11 +226,12 @@ enum lws_log_levels {
        LLL_EXT = 1 << 7,
        LLL_CLIENT = 1 << 8,
        LLL_LATENCY = 1 << 9,
+       LLL_USER = 1 << 10,
 
-       LLL_COUNT = 10 /* set to count of valid flags */
+       LLL_COUNT = 11 /* set to count of valid flags */
 };
 
-LWS_VISIBLE LWS_EXTERN void _lws_log(int filter, const char *format, ...);
+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);
 /**
  * lwsl_timestamp: generate logging timestamp string
@@ -298,15 +245,18 @@ LWS_VISIBLE LWS_EXTERN void _lws_logv(int filter, const char *format, va_list vl
 LWS_VISIBLE LWS_EXTERN int
 lwsl_timestamp(int level, char *p, int len);
 
+/* these guys are unconditionally included */
+
 #define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__)
+#define lwsl_user(...) _lws_log(LLL_USER, __VA_ARGS__)
 
 #if !defined(LWS_WITH_NO_LOGS)
-/* notice, warn and log are always compiled in */
+/* notice and warn are usually included by being compiled in */
 #define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
 #define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
 #endif
 /*
- *  weaker logging can be deselected at configure time using --disable-debug
+ *  weaker logging can be deselected by telling CMake to build in RELEASE mode
  *  that gets rid of the overhead of checking while keeping _warn and _err
  *  active
  */
@@ -318,7 +268,6 @@ lwsl_timestamp(int level, char *p, int len);
 #ifdef _DEBUG
 #if defined(LWS_WITH_NO_LOGS)
 /* notice, warn and log are always compiled in */
-//#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__)
 #define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
 #define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
 #endif
@@ -339,7 +288,6 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
 
 #else /* no debug */
 #if defined(LWS_WITH_NO_LOGS)
-//#define lwsl_err(...) do {} while(0)
 #define lwsl_warn(...) do {} while(0)
 #define lwsl_notice(...) do {} while(0)
 #endif
@@ -354,6 +302,12 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
 
 #endif
 
+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
@@ -380,6 +334,18 @@ lws_set_log_level(int level,
 LWS_VISIBLE LWS_EXTERN void
 lwsl_emit_syslog(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);
+
 ///@}
 
 
@@ -426,30 +392,7 @@ struct lws_pollfd {
 #define LWS_POLLOUT (FD_WRITE)
 #else
 
-#if defined(MBED_OPERATORS)
-/* it's a class lws_conn * */
-typedef void * lws_sockfd_type;
-typedef void * lws_filefd_type;
-#define lws_sockfd_valid(sfd) (!!sfd)
-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
 
-struct lws;
-
-void * mbed3_create_tcp_stream_socket(void);
-void mbed3_delete_tcp_stream_socket(void *sockfd);
-void mbed3_tcp_stream_bind(void *sock, int port, struct lws *);
-void mbed3_tcp_stream_accept(void *sock, struct lws *);
-#else
 #if defined(LWS_WITH_ESP8266)
 
 #include <user_interface.h>
@@ -479,7 +422,7 @@ void esp8266_tcp_stream_accept(lws_sockfd_type fd, struct lws *wsi);
 #include <osapi.h>
 #include "ets_sys.h"
 
-int ets_snprintf(char *str, size_t size, const char *format, ...);
+int ets_snprintf(char *str, size_t size, const char *format, ...) LWS_FORMAT(3);
 #define snprintf  ets_snprintf
 
 typedef os_timer_t uv_timer_t;
@@ -516,6 +459,205 @@ static inline void uv_timer_stop(uv_timer_t *t)
 }
 
 #else
+#if defined(LWS_WITH_ESP32)
+
+typedef int lws_sockfd_type;
+typedef int lws_filefd_type;
+#define lws_sockfd_valid(sfd) (sfd >= 0)
+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
+
+#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 "esp_spi_flash.h"
+#include "freertos/timers.h"
+
+#if !defined(CONFIG_FREERTOS_HZ)
+#define CONFIG_FREERTOS_HZ 100
+#endif
+
+typedef TimerHandle_t uv_timer_t;
+typedef void uv_cb_t(uv_timer_t *);
+typedef void * uv_handle_t;
+
+struct timer_mapping {
+       uv_cb_t *cb;
+       uv_timer_t *t;
+};
+
+#define UV_VERSION_MAJOR 1
+
+#define lws_uv_getloop(a, b) (NULL)
+
+static inline void uv_timer_init(void *l, uv_timer_t *t)
+{
+       (void)l;
+       *t = NULL;
+}
+
+extern void esp32_uvtimer_cb(TimerHandle_t t);
+
+static inline void uv_timer_start(uv_timer_t *t, uv_cb_t *cb, int first, int rep)
+{
+       struct timer_mapping *tm = (struct timer_mapping *)malloc(sizeof(*tm));
+
+       if (!tm)
+               return;
+
+       tm->t = t;
+       tm->cb = cb;
+
+       *t = xTimerCreate("x", pdMS_TO_TICKS(first), !!rep, tm,
+                         (TimerCallbackFunction_t)esp32_uvtimer_cb);
+       xTimerStart(*t, 0);
+}
+
+static inline void uv_timer_stop(uv_timer_t *t)
+{
+       xTimerStop(*t, 0);
+}
+
+static inline void uv_close(uv_handle_t *h, void *v)
+{
+       free(pvTimerGetTimerID((uv_timer_t)h));
+       xTimerDelete(*(uv_timer_t *)h, 0);
+}
+
+/* ESP32 helper declarations */
+
+#include <mdns.h>
+#include <esp_partition.h>
+
+#define LWS_PLUGIN_STATIC
+#define LWS_MAGIC_REBOOT_TYPE_ADS 0x50001ffc
+#define LWS_MAGIC_REBOOT_TYPE_REQ_FACTORY 0xb00bcafe
+#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY 0xfaceb00b
+#define LWS_MAGIC_REBOOT_TYPE_FORCED_FACTORY_BUTTON 0xf0cedfac
+
+
+/* user code provides these */
+
+extern void
+lws_esp32_identify_physical_device(void);
+
+/* lws-plat-esp32 provides these */
+
+typedef void (*lws_cb_scan_done)(uint16_t count, wifi_ap_record_t *recs, void *arg);
+
+enum genled_state {
+       LWSESP32_GENLED__INIT,
+       LWSESP32_GENLED__LOST_NETWORK,
+       LWSESP32_GENLED__NO_NETWORK,
+       LWSESP32_GENLED__CONN_AP,
+       LWSESP32_GENLED__GOT_IP,
+       LWSESP32_GENLED__OK,
+};
+
+struct lws_group_member {
+       struct lws_group_member *next;
+       uint64_t last_seen;
+       char model[16];
+       char role[16];
+       char host[32];
+       char mac[20];
+       int width, height;
+       struct ip4_addr addr;
+       struct ip6_addr addrv6;
+       uint8_t flags;
+};
+
+#define LWS_SYSTEM_GROUP_MEMBER_ADD            1
+#define LWS_SYSTEM_GROUP_MEMBER_CHANGE         2
+#define LWS_SYSTEM_GROUP_MEMBER_REMOVE         3
+
+#define LWS_GROUP_FLAG_SELF 1
+
+struct lws_esp32 {
+       char sta_ip[16];
+       char sta_mask[16];
+       char sta_gw[16];
+       char serial[16];
+       char opts[16];
+       char model[16];
+       char group[16];
+       char role[16];
+       char ssid[4][16];
+       char password[4][32];
+       char active_ssid[32];
+       char access_pw[16];
+       char hostname[32];
+       char mac[20];
+       mdns_server_t *mdns;
+               char region;
+               char inet;
+       char conn_ap;
+
+       enum genled_state genled;
+       uint64_t genled_t;
+
+       lws_cb_scan_done scan_consumer;
+       void *scan_consumer_arg;
+       struct lws_group_member *first;
+       int extant_group_members;
+};
+
+struct lws_esp32_image {
+       uint32_t romfs;
+       uint32_t romfs_len;
+       uint32_t json;
+       uint32_t json_len;
+};
+
+extern struct lws_esp32 lws_esp32;
+
+extern esp_err_t
+lws_esp32_event_passthru(void *ctx, system_event_t *event);
+extern void
+lws_esp32_wlan_config(void);
+extern void
+lws_esp32_wlan_start_ap(void);
+extern void
+lws_esp32_wlan_start_station(void);
+struct lws_context_creation_info;
+extern void
+lws_esp32_set_creation_defaults(struct lws_context_creation_info *info);
+extern struct lws_context *
+lws_esp32_init(struct lws_context_creation_info *);
+extern int
+lws_esp32_wlan_nvs_get(int retry);
+extern esp_err_t
+lws_nvs_set_str(nvs_handle handle, const char* key, const char* value);
+extern void
+lws_esp32_restart_guided(uint32_t type);
+extern const esp_partition_t *
+lws_esp_ota_get_boot_partition(void);
+extern int
+lws_esp32_get_image_info(const esp_partition_t *part, struct lws_esp32_image *i, char *json, int json_len);
+extern int
+lws_esp32_leds_network_indication(void);
+
+extern uint32_t lws_esp32_get_reboot_type(void);
+extern uint16_t lws_esp32_sine_interp(int n);
+
+/* required in external code by esp32 plat (may just return if no leds) */
+extern void lws_esp32_leds_timer_cb(TimerHandle_t th);
+#else
 typedef int lws_sockfd_type;
 typedef int lws_filefd_type;
 #define lws_sockfd_valid(sfd) (sfd >= 0)
@@ -877,8 +1019,7 @@ enum lws_callback_reasons {
         * 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.
-        * Notice this callback comes to protocols[0]. */
+        * content during this callback might not be useful for anything. */
        LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED         = 26,
        /**< When a client
         * connection is being prepared to start a handshake to a server,
@@ -1048,11 +1189,27 @@ enum lws_callback_reasons {
         * LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK still work without this
         * callback being implemented.
         */
+       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_ADOPT_FILE                             = 63,
+       /**< RAW mode file was adopted (equivalent to 'wsi created') */
+       LWS_CALLBACK_RAW_RX_FILE                                = 64,
+       /**< RAW mode file has something to read */
+       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 */
 
        /****** add new things just above ---^ ******/
 
        LWS_CALLBACK_USER = 1000,
-       /**<  user code can use any including above without fear of clashes */
+       /**<  user code can use any including above without fear of clashes */
 };
 
 
@@ -1330,8 +1487,8 @@ struct lws_protocols {
         * be able to consume it all without having to return to the event
         * loop.  That is supported in lws.
         *
-        * This also controls how much may be sent at once at the moment,
-        * although this is likely to change.
+        * 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
@@ -1342,6 +1499,15 @@ struct lws_protocols {
         * 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 */
@@ -1413,6 +1579,9 @@ lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *pr
 LWS_VISIBLE LWS_EXTERN int
 lws_finalize_startup(struct lws_context *context);
 
+LWS_VISIBLE LWS_EXTERN int
+lws_protocol_init(struct lws_context *context);
+
 #ifdef LWS_WITH_PLUGINS
 
 /* PLUGINS implies LIBUV */
@@ -1583,12 +1752,22 @@ enum lws_context_options {
         * the context, only the string you give in the client connect
         * info for .origin (if any) will be used directly.
         */
+       LWS_SERVER_OPTION_FALLBACK_TO_RAW                       = (1 << 20),
+       /**< (VH) if invalid http is coming in the first line,  */
+       LWS_SERVER_OPTION_LIBEVENT                              = (1 << 21),
+       /**< (CTX) Use libevent event loop */
+       LWS_SERVER_OPTION_ONLY_RAW                              = (1 << 22),
+       /**< (VH) All connections to this vhost / port are RAW as soon as
+        * the connection is accepted, no HTTP is going to be coming.
+        */
 
        /****** add new things just above ---^ ******/
 };
 
 #define lws_check_opt(c, f) (((c) & (f)) == (f))
 
+struct lws_plat_file_ops;
+
 /** struct lws_context_creation_info - parameters to create context and /or vhost with
  *
  * This is also used to create vhosts.... if LWS_SERVER_OPTION_EXPLICIT_VHOSTS
@@ -1652,7 +1831,7 @@ struct lws_context_creation_info {
        /**< VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields */
        void *user;
        /**< CONTEXT: optional user pointer that can be recovered via the context
*             pointer using lws_context_user */
       *              pointer using lws_context_user */
        int ka_time;
        /**< CONTEXT: 0 for no TCP keepalive, otherwise apply this keepalive
         * timeout to all libwebsocket sockets, client or server */
@@ -1763,6 +1942,67 @@ struct lws_context_creation_info {
         * succeeded to create.
         */
 
+#ifdef LWS_OPENSSL_SUPPORT
+        /**< CONTEXT: NULL or struct lws_token_limits pointer which is initialized
+        * with a token length limit for each possible WSI_TOKEN_ */
+       const char *client_ssl_private_key_password;
+       /**< VHOST: NULL or the passphrase needed for the private key */
+       const char *client_ssl_cert_filepath;
+       /**< VHOST: If libwebsockets was compiled to use ssl, and you want
+       * to listen using SSL, set to the filepath to fetch the
+       * server cert from, otherwise NULL for unencrypted */
+       const char *client_ssl_private_key_filepath;
+       /**<  VHOST: filepath to private key if wanting SSL mode;
+       * if this is set to NULL but sll_cert_filepath is set, the
+       * OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY callback is called
+       * to allow setting of the private key directly via openSSL
+       * library calls */
+       const char *client_ssl_ca_filepath;
+       /**< VHOST: CA certificate filepath or NULL */
+       const char *client_ssl_cipher_list;
+       /**< VHOST: List of valid ciphers to use (eg,
+       * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
+       * or you can leave it as NULL to get "DEFAULT" */
+#endif
+
+       const struct lws_plat_file_ops *fops;
+       /**< CONTEXT: NULL, or pointer to an array of fops structs, terminated
+        * by a sentinel with NULL .open.
+        *
+        * If NULL, lws provides just the platform file operations struct for
+        * backwards compatibility.
+        */
+       int simultaneous_ssl_restriction;
+       /**< CONTEXT: 0 (no limit) or limit of simultaneous SSL sessions possible.*/
+       const char *socks_proxy_address;
+       /**< VHOST: If non-NULL, attempts to proxy via the given address.
+        * If proxy auth is required, use format "username:password\@server:port" */
+       unsigned int socks_proxy_port;
+       /**< VHOST: If socks_proxy_address was non-NULL, uses this port */
+#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
+       cap_value_t caps[4];
+       /**< CONTEXT: array holding Linux capabilities you want to
+        * continue to be available to the server after it transitions
+        * to a noprivileged user.  Usually none are needed but for, eg,
+        * .bind_iface, CAP_NET_RAW is required.  This gives you a way
+        * to still have the capability but drop root.
+        */
+       char count_caps;
+       /**< CONTEXT: count of Linux capabilities in .caps[].  0 means
+        * no capabilities will be inherited from root (the default) */
+#endif
+       int bind_iface;
+       /**< VHOST: nonzero to strictly bind sockets to the interface name in
+        * .iface (eg, "eth2"), using SO_BIND_TO_DEVICE.
+        *
+        * Requires SO_BINDTODEVICE support from your OS and CAP_NET_RAW
+        * capability.
+        *
+        * Notice that common things like access network interface IP from
+        * your local machine use your lo / loopback interface and will be
+        * disallowed by this.
+        */
+
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility
         *
@@ -1877,6 +2117,25 @@ lws_context_is_deprecated(struct lws_context *context);
 LWS_VISIBLE LWS_EXTERN int
 lws_set_proxy(struct lws_vhost *vhost, const char *proxy);
 
+/**
+ * lws_set_socks() - Setup socks to lws_context.
+ * \param vhost:       pointer to struct lws_vhost you want set socks for
+ * \param socks: pointer to c string containing socks in format address:port
+ *
+ * Returns 0 if socks string was parsed and socks was setup.
+ * Returns -1 if socks is NULL or has incorrect format.
+ *
+ * This is only required if your OS does not provide the socks_proxy
+ * environment variable (eg, OSX)
+ *
+ *   IMPORTANT! You should call this function right after creation of the
+ *   lws_context and before call to connect. If you call this
+ *   function after connect behavior is undefined.
+ *   This function will override proxy settings made on lws_context
+ *   creation with genenv() call.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_set_socks(struct lws_vhost *vhost, const char *socks);
 
 struct lws_vhost;
 
@@ -2107,8 +2366,8 @@ struct lws_client_connect_info {
        /**< deprecated: currently leave at 0 or -1 */
        void *userdata;
        /**< if non-NULL, use this as wsi user_data instead of malloc it */
-       const struct lws_extension *client_exts;
-       /**< array of extensions that may be used on connection */
+       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 */
@@ -2238,7 +2497,26 @@ lws_client_connect_extended(struct lws_context *clients, const char *address,
 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);
 
@@ -2481,6 +2759,7 @@ lws_get_mimetype(const char *file, const struct lws_http_mount *m);
 LWS_VISIBLE LWS_EXTERN int
 lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type,
                    const char *other_headers, int other_headers_len);
+
 LWS_VISIBLE LWS_EXTERN int
 lws_serve_http_file_fragment(struct lws *wsi);
 //@}
@@ -2504,6 +2783,7 @@ enum http_status {
        HTTP_STATUS_MOVED_PERMANENTLY                           = 301,
        HTTP_STATUS_FOUND                                       = 302,
        HTTP_STATUS_SEE_OTHER                                   = 303,
+       HTTP_STATUS_NOT_MODIFIED                                = 304,
 
        HTTP_STATUS_BAD_REQUEST                                 = 400,
        HTTP_STATUS_UNAUTHORIZED,
@@ -2698,7 +2978,7 @@ enum lws_token_indexes {
        WSI_TOKEN_HTTP_X_REAL_IP                                = 78,
        WSI_TOKEN_HTTP1_0                                       = 79,
        WSI_TOKEN_X_FORWARDED_FOR                               = 80,
-
+       WSI_TOKEN_CONNECT                                       = 81,
        /****** add new things just above ---^ ******/
 
        /* use token storage to stash these internally, not for
@@ -2824,6 +3104,10 @@ lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len);
  * and fail with nonzero return.
  */
 ///@{
+
+#define LWSAHH_CODE_MASK                       ((1 << 16) - 1)
+#define LWSAHH_FLAG_NO_SERVER_NAME             (1 << 30)
+
 /**
  * lws_add_http_header_status() - add the HTTP response status code
  *
@@ -2832,7 +3116,11 @@ lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len);
  * \param p: pointer to current position in buffer pointer
  * \param end: pointer to end of buffer
  *
- * Adds the initial response code, so should be called first
+ * Adds the initial response code, so should be called first.
+ *
+ * Code may additionally take OR'd flags:
+ *
+ *    LWSAHH_FLAG_NO_SERVER_NAME:  don't apply server name header this time
  */
 LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
 lws_add_http_header_status(struct lws *wsi,
@@ -2872,7 +3160,7 @@ lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
                             const unsigned char *value, int length,
                             unsigned char **p, unsigned char *end);
 /**
- * lws_add_http_header_by_name() - append content-length helper
+ * lws_add_http_header_content_length() - append content-length helper
  *
  * \param wsi: the connection to check
  * \param content_length: the content length to use
@@ -3192,6 +3480,33 @@ lws_uv_sigint_cb(uv_signal_t *watcher, int signum);
 #endif /* LWS_USE_LIBUV */
 ///@}
 
+/*! \defgroup event libevent helpers
+ *
+ * ##libevent helpers
+ *
+ * APIs specific to libevent event loop itegration
+ */
+///@{
+
+#ifdef LWS_USE_LIBEVENT
+typedef void (lws_event_signal_cb_t) (evutil_socket_t sock_fd, short revents,
+                 void *ctx);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
+                 lws_event_signal_cb_t cb);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_event_initloop(struct lws_context *context, struct event_base *loop,
+                 int tsi);
+
+LWS_VISIBLE LWS_EXTERN void
+lws_event_sigint_cb(evutil_socket_t sock_fd, short revents,
+                 void *ctx);
+#endif /* LWS_USE_LIBEVENT */
+
+///@}
+
 /*! \defgroup timeout Connection timeouts
 
     APIs related to setting connection timeouts
@@ -3222,6 +3537,9 @@ enum pending_timeout {
        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,
 
        /****** add new things just above ---^ ******/
 };
@@ -3483,8 +3801,12 @@ lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
  * \param reason:      Callback reason index
  *
  * - Which:  connections using this protocol on ALL VHOSTS
- * - When:   when the individual connection becomes writeable
+ * - 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,
@@ -3645,6 +3967,43 @@ lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd);
  */
 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 descr */
+       LWS_ADOPT_ALLOW_SSL = 4         /* flag: if set requires LWS_ADOPT_SOCKET */
+} lws_adoption_type;
+
+typedef union {
+       lws_sockfd_type sockfd;
+       lws_filefd_type filefd;
+} lws_sock_file_fd_type;
+
+/*
+* lws_adopt_descriptor_vhost() - adopt foreign socket or file descriptor
+* if socket descriptor, should already have been accepted from listen socket
+*
+* \param vhost: 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 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);
+
 /**
  * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it
  * for the default vhost of context.
@@ -3748,7 +4107,7 @@ lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
  */
 LWS_VISIBLE LWS_EXTERN const char *
 lws_get_peer_simple(struct lws *wsi, char *name, int namelen);
-#ifndef LWS_WITH_ESP8266
+#if !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32)
 /**
  * lws_interface_to_sa() - Convert interface name or IP to sockaddr struct
  *
@@ -3785,7 +4144,7 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
  * reach the limit the reported length doesn't exceed the limit.
  */
 LWS_VISIBLE LWS_EXTERN int
-lws_snprintf(char *str, size_t size, const char *format, ...);
+lws_snprintf(char *str, size_t size, const char *format, ...) LWS_FORMAT(3);
 
 /**
  * lws_get_random(): fill a buffer with platform random data
@@ -3801,7 +4160,7 @@ lws_snprintf(char *str, size_t size, const char *format, ...);
 LWS_VISIBLE LWS_EXTERN int
 lws_get_random(struct lws_context *context, void *buf, int len);
 /**
- * lws_daemonize(): fill a buffer with platform random data
+ * lws_daemonize(): make current process run in the background
  *
  * \param _lock_path: the filepath to write the lock file
  *
@@ -3827,6 +4186,19 @@ LWS_VISIBLE LWS_EXTERN void *
 lws_wsi_user(struct lws *wsi);
 
 /**
+ * lws_wsi_set_user() - set the user data associated with the client connection
+ * \param wsi: lws connection
+ * \param user: user data
+ *
+ * By default lws allocates this and it's not legal to externally set it
+ * yourself.  However client connections may have it set externally when the
+ * connection is created... if so, this api can be used to modify it at
+ * runtime additionally.
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_set_wsi_user(struct lws *wsi, void *user);
+
+/**
  * lws_parse_uri:      cut up prot:/ads:port/path into pieces
  *                     Notice it does so by dropping '\0' into input string
  *                     and the leading / on the path is consequently lost
@@ -4069,6 +4441,8 @@ enum lws_cgi_hdr_state {
        LCHS_LF1,
        LCHS_CR2,
        LCHS_LF2,
+       LHCS_RESPONSE,
+       LHCS_DUMP_HEADERS,
        LHCS_PAYLOAD,
        LCHS_SINGLE_0A,
 };
@@ -4137,24 +4511,111 @@ lws_cgi_kill(struct lws *wsi);
  * These provide platform-agnostic ways to deal with filesystem access in the
  * library and in the user code.
  */
+
+#if defined(LWS_WITH_ESP32)
+/* 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;
+
+#if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__)
+/* ... */
+#if !defined(ssize_t)
+typedef SSIZE_T ssize_t;
+#endif
+#endif
+
+#if defined(LWS_HAVE_STDINT_H)
+#include <stdint.h>
+#else
+#if defined(WIN32) || defined(_WIN32)
+/* !!! >:-[  */
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+#else
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
+#endif
+
+typedef size_t lws_filepos_t;
+typedef ssize_t lws_fileofs_t;
+typedef uint32_t lws_fop_flags_t;
+
+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_filefd_type (*open)(struct lws *wsi, const char *filename,
-                               unsigned long *filelen, int flags);
+       lws_fop_fd_t (*LWS_FOP_OPEN)(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)
-        * filelen is filled on exit to be the length of the file
-        * flags should be set to O_RDONLY or O_RDWR */
-       int (*close)(struct lws *wsi, lws_filefd_type fd);
-       /**< close file */
-       unsigned long (*seek_cur)(struct lws *wsi, lws_filefd_type fd,
-                                 long offset_from_cur_pos);
+        * 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 (*read)(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
-                   unsigned char *buf, unsigned long len);
+       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 (*write)(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
-                    unsigned char *buf, unsigned long len);
+       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 */
+
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility */
 };
@@ -4166,79 +4627,139 @@ struct lws_plat_file_ops {
  */
 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() - file open operations
+ * 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
  *
- * \param wsi: connection doing the opening
- * \param filename: filename to open
- * \param filelen: length of file (filled in by call)
- * \param flags: 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
  */
-static LWS_INLINE lws_filefd_type LWS_WARN_UNUSED_RESULT
-lws_plat_file_open(struct lws *wsi, const char *filename,
-                  unsigned long *filelen, int flags)
-{
-       return lws_get_fops(lws_get_context(wsi))->open(wsi, filename,
-                                                   filelen, flags);
-}
+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 wsi: connection opened by
- * \param fd: file descriptor
+ * \param fop_fd: file handle to close
  */
 static LWS_INLINE int
-lws_plat_file_close(struct lws *wsi, lws_filefd_type fd)
+lws_vfs_file_close(lws_fop_fd_t *fop_fd)
 {
-       return lws_get_fops(lws_get_context(wsi))->close(wsi, fd);
+       return (*fop_fd)->fops->LWS_FOP_CLOSE(fop_fd);
 }
 
 /**
  * lws_plat_file_seek_cur() - close file
  *
- * \param wsi: connection opened by
- * \param fd: file descriptor
+ *
+ * \param fop_fd: file handle
  * \param offset: position to seek to
  */
-static LWS_INLINE unsigned long
-lws_plat_file_seek_cur(struct lws *wsi, lws_filefd_type fd, long offset)
+static LWS_INLINE lws_fileofs_t
+lws_vfs_file_seek_cur(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
 {
-       return lws_get_fops(lws_get_context(wsi))->seek_cur(wsi, fd, offset);
+       return fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, offset);
 }
 /**
  * lws_plat_file_read() - read from file
  *
- * \param wsi: connection opened by
- * \param fd: file descriptor
+ * \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_plat_file_read(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
-                  unsigned char *buf, unsigned long len)
+lws_vfs_file_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
+                  uint8_t *buf, lws_filepos_t len)
 {
-       return lws_get_fops(lws_get_context(wsi))->read(wsi, fd, amount, buf,
-                                                       len);
+       return fop_fd->fops->LWS_FOP_READ(fop_fd, amount, buf, len);
 }
 /**
  * lws_plat_file_write() - write from file
  *
- * \param wsi: connection opened by
- * \param fd: file descriptor
+ * \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_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
-                   unsigned char *buf, unsigned long len)
+lws_vfs_file_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
+                   uint8_t *buf, lws_filepos_t len)
 {
-       return lws_get_fops(lws_get_context(wsi))->write(wsi, fd, amount, buf,
-                                                        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, 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);
 //@}
 
 /** \defgroup smtp
@@ -4365,6 +4886,56 @@ lws_email_destroy(struct lws_email *email);
 #endif
 //@}
 
+/*
+ * Stats are all uint64_t numbers that start at 0.
+ * Index names here have the convention
+ *
+ *  _C_ counter
+ *  _B_ byte count
+ *  _MS_ millisecond count
+ */
+
+enum {
+       LWSSTATS_C_CONNECTIONS, /**< count incoming connections */
+       LWSSTATS_C_API_CLOSE, /**< count calls to close api */
+       LWSSTATS_C_API_READ, /**< count calls to read from socket api */
+       LWSSTATS_C_API_LWS_WRITE, /**< count calls to lws_write API */
+       LWSSTATS_C_API_WRITE, /**< count calls to write API */
+       LWSSTATS_C_WRITE_PARTIALS, /**< count of partial writes */
+       LWSSTATS_C_WRITEABLE_CB_REQ, /**< count of writable callback requests */
+       LWSSTATS_C_WRITEABLE_CB_EFF_REQ, /**< count of effective writable callback requests */
+       LWSSTATS_C_WRITEABLE_CB, /**< count of writable callbacks */
+       LWSSTATS_C_SSL_CONNECTIONS_FAILED, /**< count of failed SSL connections */
+       LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED, /**< count of accepted SSL connections */
+       LWSSTATS_C_SSL_CONNS_HAD_RX, /**< count of accepted SSL conns that have had some RX */
+       LWSSTATS_C_TIMEOUTS, /**< count of timed-out connections */
+       LWSSTATS_C_SERVICE_ENTRY, /**< count of entries to lws service loop */
+       LWSSTATS_B_READ, /**< aggregate bytes read */
+       LWSSTATS_B_WRITE, /**< aggregate bytes written */
+       LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, /**< aggreate of size of accepted write data from new partials */
+       LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY, /**< aggregate delay in accepting connection */
+       LWSSTATS_MS_WRITABLE_DELAY, /**< aggregate delay between asking for writable and getting cb */
+       LWSSTATS_MS_WORST_WRITABLE_DELAY, /**< single worst delay between asking for writable and getting cb */
+       LWSSTATS_MS_SSL_RX_DELAY, /**< aggregate delay between ssl accept complete and first RX */
+
+       /* Add new things just above here ---^
+        * This is part of the ABI, don't needlessly break compatibility */
+       LWSSTATS_SIZE
+};
+
+#if defined(LWS_WITH_STATS)
+
+LWS_VISIBLE LWS_EXTERN uint64_t
+lws_stats_get(struct lws_context *context, int index);
+LWS_VISIBLE LWS_EXTERN void
+lws_stats_log_dump(struct lws_context *context);
+#else
+static LWS_INLINE uint64_t
+lws_stats_get(struct lws_context *context, int index) { return 0; }
+static LWS_INLINE void
+lws_stats_log_dump(struct lws_context *context) { }
+#endif
+
 #ifdef __cplusplus
 }
 #endif