#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
// Visual studio older than 2015 and WIN_CE has only _stricmp
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
#define strcasecmp _stricmp
-#else
+#elif !defined(__MINGW32__)
#define strcasecmp stricmp
#endif
#define getdtablesize() 30000
#define LWS_VISIBLE
#define LWS_WARN_UNUSED_RESULT
#define LWS_WARN_DEPRECATED
+#define LWS_FORMAT(string_index)
#ifdef LWS_DLL
#ifdef LWS_INTERNAL
#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(_MSC_VER) || _MSC_VER < 1900 /* Visual Studio 2015 already defines this in <stdio.h> */
+#if !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER < 1900) /* Visual Studio 2015 already defines this in <stdio.h> */
#define lws_snprintf _snprintf
#endif
#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>
#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)
+#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__)
#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__)
#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
#ifdef _WIN32
#define random rand
#else
+#if !defined(OPTEE_TA)
#include <sys/time.h>
#include <unistd.h>
#endif
+#endif
#ifdef LWS_OPENSSL_SUPPORT
#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
#define CONTEXT_PORT_NO_LISTEN -1
+#define CONTEXT_PORT_NO_LISTEN_SERVER -2
/** \defgroup log Logging
*
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
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
*/
#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
#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
#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
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);
+
///@}
#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>
#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;
}
#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)
#define LWS_POLLOUT (POLLOUT)
#endif
+
+#if (defined(WIN32) || defined(_WIN32)) && !defined(__MINGW32__)
+/* ... */
+#define ssize_t SSIZE_T
+#endif
+
+#if defined(WIN32) && defined(LWS_HAVE__STAT32I64)
+#include <sys/types.h>
+#include <sys/stat.h>
+#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 unsigned long long lws_filepos_t;
+typedef long long lws_fileofs_t;
+typedef uint32_t lws_fop_flags_t;
+
/** struct lws_pollargs - argument structure for all external poll related calls
* passed in via 'in' */
struct lws_pollargs {
*/
///@{
+struct lws_ssl_info {
+ int where;
+ int ret;
+};
/*
* NOTE: These public enums are part of the abi. If you want to add one,
* 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,
* From this callback, when you have sent everything, you should let
* lws know by calling lws_client_http_body_pending(wsi, 0)
*/
+ 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.
+ */
+ 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 */
+ 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*/
/****** 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 */
};
* client and server for how to do.
*/
static LWS_INLINE LWS_WARN_DEPRECATED const struct lws_extension *
-lws_get_internal_extensions() { return NULL; }
+lws_get_internal_extensions(void) { return NULL; }
/**
* lws_ext_parse_options() - deal with parsing negotiated extension options
* 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
* 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 */
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 */
* even if it happened without a debugger in place. You can disable
* that by giving this option.
*/
+ LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN = (1 << 19),
+ /**< For backwards-compatibility reasons, by default
+ * lws prepends "http://" to the origin you give in the client
+ * connection info struct. If you give this flag when you create
+ * 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
*/
struct lws_context_creation_info {
int port;
- /**< VHOST: Port to listen on... you can use CONTEXT_PORT_NO_LISTEN to
- * suppress listening on any port, that's what you want if you are
- * not running a websocket server at all but just using it as a
- * client */
+ /**< VHOST: Port to listen on. Use CONTEXT_PORT_NO_LISTEN to suppress
+ * listening for a client. Use CONTEXT_PORT_NO_LISTEN_SERVER if you are
+ * writing a server but you are using \ref sock-adopt instead of the
+ * built-in listener */
const char *iface;
/**< VHOST: NULL to bind the listen socket to all interfaces, or the
* interface name, eg, "eth2"
/**< 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 */
/**< VHOST: pointer to optional linked list of per-vhost
* canned headers that are added to server responses */
+ const struct lws_protocol_vhost_options *reject_service_keywords;
+ /**< CONTEXT: Optional list of keywords and rejection codes + text.
+ *
+ * The keywords are checked for existing in the user agent string.
+ *
+ * Eg, "badrobot" "404 Not Found"
+ */
+ void *external_baggage_free_on_destroy;
+ /**< CONTEXT: NULL, or pointer to something externally malloc'd, that
+ * should be freed when the context is destroyed. This allows you to
+ * automatically sync the freeing action to the context destruction
+ * action, so there is no need for an external free() if the context
+ * 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
*
* members added above will see 0 (default) even if the app
* was not built against the newer headers.
*/
+ int ssl_info_event_mask;
+ /**< VHOST: mask of ssl events to be reported on LWS_CALLBACK_SSL_INFO
+ * callback for connections on this vhost. The mask values are of
+ * the form SSL_CB_ALERT, defined in openssl/ssl.h. The default of
+ * 0 means no info events will be reported.
+ */
void *_unused[8]; /**< dummy */
};
*
* HTTP requests are sent always to the FIRST protocol in protocol, since
* at that time websocket protocol has not been negotiated. Other
- * protocols after the first one never see any HTTP callack activity.
+ * protocols after the first one never see any HTTP callback activity.
*
* The server created is a simple http server by default; part of the
* websocket standard is upgrading this http connection to a websocket one.
LWS_VISIBLE LWS_EXTERN void
lws_context_destroy(struct lws_context *context);
+LWS_VISIBLE LWS_EXTERN void
+lws_context_destroy2(struct lws_context *context);
+
+typedef int (*lws_reload_func)(void);
+
+/**
+ * lws_context_deprecate() - Deprecate the websocket context
+ * \param context: Websocket context
+ *
+ * This function is used on an existing context before superceding it
+ * with a new context.
+ *
+ * It closes any listen sockets in the context, so new connections are
+ * not possible.
+ *
+ * And it marks the context to be deleted when the number of active
+ * connections into it falls to zero.
+ *
+ * Otherwise if you attach the deprecated context to the replacement
+ * context when it has been created using lws_context_attach_deprecated()
+ * both any deprecated and the new context will service their connections.
+ *
+ * This is aimed at allowing seamless configuration reloads.
+ *
+ * The callback cb will be called after the listen sockets are actually
+ * closed and may be reopened. In the callback the new context should be
+ * configured and created. (With libuv, socket close happens async after
+ * more loop events).
+ */
+LWS_VISIBLE LWS_EXTERN void
+lws_context_deprecate(struct lws_context *context, lws_reload_func cb);
+
+LWS_VISIBLE LWS_EXTERN int
+lws_context_is_deprecated(struct lws_context *context);
+
/**
* lws_set_proxy() - Setups proxy to lws_context.
* \param vhost: pointer to struct lws_vhost you want set proxy for
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;
* \param len: max length of buf
*/
LWS_VISIBLE LWS_EXTERN int
-lws_json_dump_context(const struct lws_context *context, char *buf, int len);
+lws_json_dump_context(const struct lws_context *context, char *buf, int len,
+ int hide_vhosts);
/**
* lws_context_user() - get the user data associated with the context
* served from a filesystem, or it is a cgi etc.
*/
enum lws_mount_protocols {
- LWSMPRO_HTTP = 0, /**< not supported yet */
- LWSMPRO_HTTPS = 1, /**< not supported yet */
+ LWSMPRO_HTTP = 0, /**< http reverse proxy */
+ LWSMPRO_HTTPS = 1, /**< https reverse proxy */
LWSMPRO_FILE = 2, /**< serve from filesystem directory */
LWSMPRO_CGI = 3, /**< pass to CGI to handle */
LWSMPRO_REDIR_HTTP = 4, /**< redirect to http:// url */
unsigned char origin_protocol; /**< one of enum lws_mount_protocols */
unsigned char mountpoint_len; /**< length of mountpoint string */
+
+ const char *basic_auth_login_file;
+ /**<NULL, or filepath to use to check basic auth logins against */
+
+ /* 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[2]; /**< dummy */
};
///@}
///@}
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_SKIP_SERVER_CERT_HOSTNAME_CHECK = (1 << 2),
+ LCCSCF_ALLOW_EXPIRED = (1 << 3)
};
/** struct lws_client_connect_info - parameters to connect with when using
/**< 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 */
* 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 */
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility
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.
+ */
+LWS_VISIBLE LWS_EXTERN unsigned int
+lws_http_client_http_response(struct lws *wsi);
+
LWS_VISIBLE LWS_EXTERN void
lws_client_http_body_pending(struct lws *wsi, int something_left_to_send);
* 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.
+ * happened, or NULL to tell lws to do only timeout servicing.
*
* This function takes a pollfd that has POLLIN or POLLOUT activity and
* services it according to the state of the associated
* 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.
+ *
+ * You should also call this with pollfd = NULL to just allow the
+ * once-per-second global timeout checks; if less than a second since the last
+ * check it returns immediately then.
*/
LWS_VISIBLE LWS_EXTERN int
lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd);
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
+
///@}
/*! \defgroup http HTTP
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);
//@}
enum http_status {
HTTP_STATUS_OK = 200,
HTTP_STATUS_NO_CONTENT = 204,
+ HTTP_STATUS_PARTIAL_CONTENT = 206,
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,
WSI_TOKEN_PROXY = 77,
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
_WSI_TOKEN_CLIENT_HOST,
_WSI_TOKEN_CLIENT_ORIGIN,
_WSI_TOKEN_CLIENT_METHOD,
+ _WSI_TOKEN_CLIENT_IFACE,
/* always last real token index*/
WSI_TOKEN_COUNT,
* 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
*
* \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,
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
*/
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_add_http_header_content_length(struct lws *wsi,
- unsigned long content_length,
+ lws_filepos_t content_length,
unsigned char **p, unsigned char *end);
/**
* lws_finalize_http_header() - terminate header block
LWS_VISIBLE LWS_EXTERN void
lws_libuv_stop(struct lws_context *context);
+LWS_VISIBLE LWS_EXTERN void
+lws_libuv_stop_without_kill(const struct lws_context *context, int tsi);
+
LWS_VISIBLE LWS_EXTERN int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
#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
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,
/****** add new things just above ---^ ******/
};
* allows maximum efficiency of sending data and protocol in a single
* packet while not burdening the user code with any protocol knowledge.
*
- * Return may be -1 for a fatal error needing connection close, or a
- * positive number reflecting the amount of bytes actually sent. This
- * can be less than the requested number of bytes due to OS memory
- * pressure at any given time.
+ * Return may be -1 for a fatal error needing connection close, or the
+ * number of bytes sent.
+ *
+ * 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 will be suppressed.
+ *
+ * This is to handle corner cases where unexpectedly the OS refuses what we
+ * usually expect it to accept. You should try to send in chunks that are
+ * almost always accepted in order to avoid the inefficiency of the buffering.
*/
LWS_VISIBLE LWS_EXTERN int
lws_write(struct lws *wsi, unsigned char *buf, size_t len,
/* 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)
-
///@}
/** \defgroup callback-when-writeable Callback when writeable
* \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,
/**
* 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
*
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 vhost: 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 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.
* \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
*/
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);
+ 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 \param 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 \param readbuf first, before reading from
+ * the socket.
+ *
+ * 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);
///@}
/** \defgroup net Network related helper APIs
*/
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
*
* 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
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
*
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
* useful when integrating with other app poll loop service code.
*/
LWS_VISIBLE LWS_EXTERN int
-lws_read(struct lws *wsi, unsigned char *buf, size_t len);
+lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
/**
* lws_set_allocator() - custom allocator support
*/
LWS_VISIBLE LWS_EXTERN int
lws_is_cgi(struct lws *wsi);
+
+#ifdef LWS_OPENSSL_SUPPORT
+/**
+ * lws_get_ssl() - Return wsi's SSL context structure
+ * \param wsi: websocket connection
+ *
+ * Returns pointer to the SSL library's context structure
+ */
+LWS_VISIBLE LWS_EXTERN SSL*
+lws_get_ssl(struct lws *wsi);
+#endif
///@}
LCHS_LF1,
LCHS_CR2,
LCHS_LF2,
+ LHCS_RESPONSE,
+ LHCS_DUMP_HEADERS,
LHCS_PAYLOAD,
LCHS_SINGLE_0A,
};
* 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;
+
+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 */
};
*/
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
+ *
+ * The vfs_path is scanned for known fops signatures, and the open directed
+ * to any matching fops open.
*
- * \param wsi: connection doing the opening
- * \param filename: filename to open
- * \param filelen: length of file (filled in by call)
- * \param flags: open flags
+ * 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
#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