Newer
Older
/*
* libwebsockets - small server side websockets and web server implementation
* Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "lws_config_private.h"
#if defined(__COVERITY__) && !defined(LWS_COVERITY_WORKAROUND)
#define LWS_COVERITY_WORKAROUND
typedef float _Float32;
typedef float _Float64;
typedef float _Float128;
typedef float _Float32x;
typedef float _Float64x;
typedef float _Float128x;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if LWS_MAX_SMP > 1
#include <pthread.h>
#define LWS_DEF_HEADER_LEN 4096
#define LWS_DEF_HEADER_POOL 4
#ifndef LWS_MAX_PROTOCOLS
#endif
#ifndef LWS_MAX_EXTENSIONS_ACTIVE
#ifndef LWS_MAX_EXT_OFFERS
#define LWS_MAX_EXT_OFFERS 8
#endif
#ifndef SPEC_LATEST_SUPPORTED
#endif
#ifndef AWAITING_TIMEOUT
#endif
#ifndef CIPHERS_LIST_STRING
#define CIPHERS_LIST_STRING "DEFAULT"
#ifndef LWS_SOMAXCONN
#define LWS_SOMAXCONN SOMAXCONN
#endif
#ifndef SYSTEM_RANDOM_FILEPATH
#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
#define LWS_H2_RX_SCRATCH_SIZE 512
#define lws_socket_is_valid(x) (x != LWS_SOCK_INVALID)
#ifndef LWS_HAVE_STRERROR
#define strerror(x) ""
#endif
/*
*
* ------ private platform defines ------
*
*/
#if defined(LWS_WITH_ESP32)
#include "plat/esp32/private.h"
#else
#if defined(WIN32) || defined(_WIN32)
#include "plat/windows/private.h"
#else
#if defined(LWS_PLAT_OPTEE)
#include "plat/optee/private.h"
#else
#include "plat/unix/private.h"
#endif
#endif
#endif
#ifndef LWS_HAVE_BZERO
#ifndef bzero
#define bzero(b, len) (memset((b), '\0', (len)), (void) 0)
#endif
#endif
/*
*
* ------ public api ------
*
*/
#include "libwebsockets.h"
#include "tls/private.h"
#if defined(WIN32) || defined(_WIN32)
// Visual studio older than 2015 and WIN_CE has only _stricmp
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
#define strcasecmp _stricmp
#elif !defined(__MINGW32__)
#define strcasecmp stricmp
#endif
#define getdtablesize() 30000
#endif
#ifndef LWS_ARRAY_SIZE
#define LWS_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* All lws_tls...() functions must return this type, converting the
* native backend result and doing the extra work to determine which one
* as needed.
*
* Native TLS backend return codes are NOT ALLOWED outside the backend.
*
* Non-SSL mode also uses these types.
*/
enum lws_ssl_capable_status {
LWS_SSL_CAPABLE_ERROR = -1, /* it failed */
LWS_SSL_CAPABLE_DONE = 0, /* it succeeded */
LWS_SSL_CAPABLE_MORE_SERVICE_READ = -2, /* retry WANT_READ */
LWS_SSL_CAPABLE_MORE_SERVICE_WRITE = -3, /* retry WANT_WRITE */
LWS_SSL_CAPABLE_MORE_SERVICE = -4, /* general retry */
#if defined(__clang__)
#define lws_memory_barrier() __sync_synchronize()
#elif defined(__GNUC__)
#define lws_memory_barrier() __sync_synchronize()
#else
#define lws_memory_barrier()
#endif
* ------ roles ------
#include "roles/private.h"
/* null-terminated array of pointers to roles lws built with */
extern const struct lws_role_ops *available_roles[];
#define LWS_FOR_EVERY_AVAILABLE_ROLE_START(xx) { \
const struct lws_role_ops **ppxx = available_roles; \
while (*ppxx) { \
const struct lws_role_ops *xx = *ppxx++;
#define LWS_FOR_EVERY_AVAILABLE_ROLE_END }}
/*
*
* ------ event_loop ops ------
*
*/
#include "event-libs/private.h"
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/* enums of socks version */
enum socks_version {
SOCKS_VERSION_4 = 4,
SOCKS_VERSION_5 = 5
};
/* enums of subnegotiation version */
enum socks_subnegotiation_version {
SOCKS_SUBNEGOTIATION_VERSION_1 = 1,
};
/* enums of socks commands */
enum socks_command {
SOCKS_COMMAND_CONNECT = 1,
SOCKS_COMMAND_BIND = 2,
SOCKS_COMMAND_UDP_ASSOCIATE = 3
};
/* enums of socks address type */
enum socks_atyp {
SOCKS_ATYP_IPV4 = 1,
SOCKS_ATYP_DOMAINNAME = 3,
SOCKS_ATYP_IPV6 = 4
};
/* enums of socks authentication methods */
enum socks_auth_method {
SOCKS_AUTH_NO_AUTH = 0,
SOCKS_AUTH_GSSAPI = 1,
SOCKS_AUTH_USERNAME_PASSWORD = 2
};
/* enums of subnegotiation status */
enum socks_subnegotiation_status {
SOCKS_SUBNEGOTIATION_STATUS_SUCCESS = 0,
};
/* enums of socks request reply */
enum socks_request_reply {
SOCKS_REQUEST_REPLY_SUCCESS = 0,
SOCKS_REQUEST_REPLY_FAILURE_GENERAL = 1,
SOCKS_REQUEST_REPLY_CONNECTION_NOT_ALLOWED = 2,
SOCKS_REQUEST_REPLY_NETWORK_UNREACHABLE = 3,
SOCKS_REQUEST_REPLY_HOST_UNREACHABLE = 4,
SOCKS_REQUEST_REPLY_CONNECTION_REFUSED = 5,
SOCKS_REQUEST_REPLY_TTL_EXPIRED = 6,
SOCKS_REQUEST_REPLY_COMMAND_NOT_SUPPORTED = 7,
SOCKS_REQUEST_REPLY_ATYP_NOT_SUPPORTED = 8
};
/* enums used to generate socks messages */
enum socks_msg_type {
/* greeting */
SOCKS_MSG_GREETING,
/* credential, user name and password */
SOCKS_MSG_USERNAME_PASSWORD,
/* connect command */
SOCKS_MSG_CONNECT
};
enum {
LWS_RXFLOW_ALLOW = (1 << 0),
LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
};
struct lws_ring {
void *buf;
void (*destroy_element)(void *element);
uint32_t buflen;
uint32_t element_len;
uint32_t head;
uint32_t oldest_tail;
};
struct lws_protocols;
struct lws;
struct lws_io_watcher_libev ev;
struct lws_io_watcher_libuv uv;
struct lws_io_watcher_libevent event;
struct lws_signal_watcher_libev ev;
struct lws_signal_watcher_libuv uv;
struct lws_signal_watcher_libevent event;
struct lws_foreign_thread_pollfd {
struct lws_foreign_thread_pollfd *next;
int fd_index;
int _and;
int _or;
};
#if LWS_MAX_SMP > 1
struct lws_mutex_refcount {
pthread_mutex_t lock;
pthread_t lock_owner;
const char *last_lock_reason;
char lock_depth;
char metadata;
};
void
lws_mutex_refcount_init(struct lws_mutex_refcount *mr);
void
lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr);
void
lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason);
void
lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr);
#endif
#define LWS_HRTIMER_NOWAIT (0x7fffffffffffffffll)
/*
* so we can have n connections being serviced simultaneously,
* these things need to be isolated per-thread.
*/
struct lws_context_per_thread {
pthread_t self;
struct lws_context *context;
/*
* usable by anything in the service code, but only if the scope
* does not last longer than the service action (since next service
* of any socket can likewise use it and overwrite)
*/
unsigned char *serv_buf;
struct lws_dll_lws dll_head_timeout;
struct lws_dll_lws dll_head_hrtimer;
struct lws_dll_lws dll_head_buflist; /* guys with pending rxflow */
#if defined(LWS_WITH_TLS)
struct lws_pt_tls tls;
volatile struct lws_foreign_thread_pollfd * volatile foreign_pfd_list;
#ifdef _WIN32
WSAEVENT events;
#endif
lws_sockfd_type dummy_pipe_fds[2];
struct lws *pipe_wsi;
/* --- role based members --- */
Andy Green
committed
#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
struct lws_pt_role_ws ws;
Andy Green
committed
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
struct lws_pt_role_http http;
#endif
#if defined(LWS_ROLE_DBUS)
struct lws_pt_role_dbus dbus;
#endif
Andy Green
committed
/* --- event library based members --- */
Andy Green
committed
struct lws_pt_eventlibs_libev ev;
struct lws_pt_eventlibs_libuv uv;
#if defined(LWS_WITH_LIBEVENT)
struct lws_pt_eventlibs_libevent event;
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
defined(LWS_WITH_LIBEVENT)
/* --- */
unsigned int fds_count;
/*
* set to the Thread ID that's doing the service loop just before entry
* to poll indicates service thread likely idling in poll()
* volatile because other threads may check it as part of processing
* for pollfd event change.
*/
volatile int service_tid;
int service_tid_detected;
volatile unsigned char inside_poll;
volatile unsigned char foreign_spinlock;
unsigned char inside_service:1;
unsigned char event_loop_foreign:1;
unsigned char event_loop_destroy_processing_done:1;
unsigned long h1_conn, h1_trans, h2_trans, ws_upg, h2_alpn, h2_subs,
h2_upg, rejected;
};
void
lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs);
struct lws_timed_vh_protocol {
struct lws_timed_vh_protocol *next;
const struct lws_protocols *protocol;
struct lws_vhost *vhost; /* only used for pending processing */
int tsi_req;
/*
* virtual host -related context information
* vhostwide SSL context
* vhostwide proxy
*
*
* context -> vhost -> wsi
*
* incoming connection non-SSL vhost binding:
*
* listen socket -> wsi -> select vhost after first headers
*
* incoming connection SSL vhost binding:
*
* SSL SNI -> wsi -> bind after SSL negotiation
*/
#if !defined(LWS_WITHOUT_CLIENT)
char close_flow_vs_tsi[LWS_MAX_SMP];
Andy Green
committed
#if defined(LWS_ROLE_H2)
struct lws_vhost_role_h2 h2;
Andy Green
committed
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
struct lws_vhost_role_http http;
#endif
#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
Andy Green
committed
struct lws_vhost_role_ws ws;
#endif
#if defined(LWS_WITH_SOCKS5)
char socks_proxy_address[128];
char socks_user[96];
char socks_password[96];
#endif
#if defined(LWS_WITH_LIBEV)
struct lws_io_watcher w_accept;
struct lws_context *context;
struct lws_vhost *vhost_next;
Andy Green
committed
struct lws *lserv_wsi;
const char *name;
const char *iface;
void (*finalize)(struct lws_vhost *vh, void *arg);
void *finalize_arg;
#if !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
int bind_iface;
#endif
const struct lws_protocol_vhost_options *pvo;
const struct lws_protocol_vhost_options *headers;
struct lws_dll_lws *same_vh_protocol_heads;
struct lws_vhost *no_listener_vhost_list;
#if !defined(LWS_NO_CLIENT)
struct lws_dll_lws dll_active_client_conns;
#endif
Andy Green
committed
struct lws_vhost_tls tls;
Andy Green
committed
struct lws_timed_vh_protocol *timed_vh_protocol_list;
Andy Green
committed
#if defined(LWS_WITH_SOCKS5)
unsigned int socks_proxy_port;
#endif
int count_protocols;
int ka_time;
int ka_probes;
int ka_interval;
int count_bound_wsi;
#ifdef LWS_WITH_ACCESS_LOG
int log_fd;
#endif
unsigned int created_vhost_protocols:1;
unsigned char raw_protocol_index;
void
lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi);
void
lws_vhost_unbind_wsi(struct lws *wsi);
void
__lws_vhost_destroy2(struct lws_vhost *vh);
struct lws_deferred_free
{
struct lws_deferred_free *next;
time_t deadline;
void *payload;
};
struct sockaddr_in6 sa6;
#endif
struct sockaddr_in sa4;
} sockaddr46;
#if defined(LWS_WITH_PEER_LIMITS)
struct lws_peer {
struct lws_peer *next;
struct lws_peer *peer_wait_list;
time_t time_created;
time_t time_closed_all;
uint8_t addr[32];
uint32_t hash;
uint32_t count_wsi;
uint32_t total_wsi;
Andy Green
committed
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
struct lws_peer_role_http http;
#endif
/*
* the rest is managed per-context, that includes
*
* - processwide single fd -> wsi lookup
* - contextwide headers pool
*/
struct lws_context {
time_t last_timeout_check_s;
time_t time_discontiguity;
time_t time_fixup;
Andy Green
committed
const struct lws_plat_file_ops *fops;
struct lws_context **pcontext_finalize;
const struct lws_tls_ops *tls_ops;
#if defined(LWS_WITH_HTTP2)
struct http2_settings set;
#endif
#if defined(LWS_WITH_ZIP_FOPS)
struct lws_plat_file_ops fops_zip;
#endif
#ifdef _WIN32
/* different implementation between unix and windows */
struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS];
struct lws **lws_lookup; /* fd to wsi */
struct lws_vhost *no_listener_vhost_list;
#if defined(LWS_WITH_THREADPOOL)
struct lws_threadpool *tp_list_head;
#endif
#if defined(LWS_WITH_PEER_LIMITS)
struct lws_peer **pl_hash_table;
struct lws_peer *peer_wait_list;
time_t next_cull;
#endif
void *external_baggage_free_on_destroy;
const struct lws_token_limits *token_limits;
void *user_space;
const struct lws_protocol_vhost_options *reject_service_keywords;
void (*eventlib_signal_cb)(void *event_lib_handle, int signum);
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
cap_value_t caps[4];
char count_caps;
#endif
struct lws_context_eventlibs_libev ev;
struct lws_context_eventlibs_libuv uv;
#if defined(LWS_WITH_LIBEVENT)
struct lws_context_eventlibs_libevent event;
struct lws_event_loop_ops *event_loop_ops;
#if defined(LWS_WITH_TLS)
struct lws_context_tls tls;
#endif
const char *server_string;
#ifdef LWS_LATENCY
unsigned long worst_latency;
char worst_latency_info[256];
#endif
#if defined(LWS_WITH_STATS)
uint64_t lws_stats[LWSSTATS_SIZE];
uint64_t last_dump;
int updated;
#endif
#if defined(LWS_WITH_ESP32)
unsigned long time_last_state_dump;
uint32_t last_free_heap;
#endif
int count_event_loop_static_asset_handles;
unsigned int pt_serv_buf_size;
int max_http_header_data;
int max_http_header_pool;
int simultaneous_ssl_restriction;
int simultaneous_ssl;
#if defined(LWS_WITH_PEER_LIMITS)
uint32_t pl_hash_elements; /* protected by context->lock */
uint32_t count_peers; /* protected by context->lock */
unsigned short ip_limit_ah;
unsigned short ip_limit_wsi;
#endif
unsigned int deprecated:1;
unsigned int being_destroyed:1;
unsigned int being_destroyed1:1;
unsigned int being_destroyed2:1;
unsigned int requested_kill:1;
unsigned int protocol_init_done:1;
unsigned int doing_protocol_init:1;
unsigned int done_protocol_destroy_cb:1;
unsigned int finalize_destroy_after_internal_loops_stopped:1;
Patrick Gansterer
committed
lws_check_deferred_free(struct lws_context *context, int tsi, int force);
#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
#define lws_get_vh_protocol(vh, x) vh->protocols[x]
LWS_EXTERN void
lws_libuv_closehandle(struct lws *wsi);
LWS_EXTERN int
lws_libuv_check_watcher_active(struct lws *wsi);
lws_plat_plugins_init(struct lws_context * context, const char * const *d);
LWS_VISIBLE LWS_EXTERN int
lws_plat_plugins_destroy(struct lws_context * context);
LWS_EXTERN void
lws_restart_ws_ping_pong_timer(struct lws *wsi);
struct lws *
lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
int
lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
void
lws_vhost_destroy1(struct lws_vhost *vh);
enum {
LWS_EV_READ = (1 << 0),
LWS_EV_WRITE = (1 << 1),
LWS_EV_START = (1 << 2),
LWS_EV_STOP = (1 << 3),
#if defined(LWS_WITH_ESP32)
LWS_EXTERN int
lws_find_string_in_file(const char *filename, const char *str, int stringlen);
(!lws_check_opt(vh->context->options, LWS_SERVER_OPTION_DISABLE_IPV6) && \
!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_IPV6))
#else
#define LWS_IPV6_ENABLED(context) (0)
#endif
#define LWS_UNIX_SOCK_ENABLED(vhost) \
(vhost->options & LWS_SERVER_OPTION_UNIX_SOCK)
enum uri_path_states {
URIPS_IDLE,
URIPS_SEEN_SLASH,
URIPS_SEEN_SLASH_DOT,
URIPS_SEEN_SLASH_DOT_DOT,
};
enum uri_esc_states {
URIES_IDLE,
URIES_SEEN_PERCENT,
URIES_SEEN_PERCENT_H1,
};
#ifndef LWS_NO_CLIENT
struct client_info_stash {
char *address;
char *path;
char *host;
char *origin;
char *protocol;
char *method;
char *iface;
signed char char_to_hex(const char c);
struct lws_buflist {
struct lws_buflist *next;
size_t len;
size_t pos;
uint8_t buf[1]; /* true length of this is set by the oversize malloc */
};
#define LWS_H2_FRAME_HEADER_LENGTH 9
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
#endif
#if defined(LWS_ROLE_H2)
#if defined(LWS_ROLE_WS)
struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */
#endif
#if defined(LWS_ROLE_DBUS)
struct _lws_dbus_mode_related dbus;
#endif
const struct lws_role_ops *role_ops;
lws_wsi_state_t wsistate;
lws_wsi_state_t wsistate_pre_close;
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
defined(LWS_WITH_LIBEVENT)
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT)
struct lws *parent; /* points to parent, if any */
struct lws *child_list; /* points to first child */
struct lws *sibling_list; /* subsequent children at same level */
const struct lws_protocols *protocol;
struct lws_dll_lws same_vh_protocol;
struct lws_dll_lws dll_timeout;
struct lws_dll_lws dll_hrtimer;
struct lws_dll_lws dll_buflist; /* guys with pending rxflow */
#if defined(LWS_WITH_THREADPOOL)
struct lws_threadpool_task *tp_task;
#endif
#if defined(LWS_WITH_PEER_LIMITS)
struct lws_peer *peer;
Andy Green
committed
#ifndef LWS_NO_CLIENT
struct client_info_stash *stash;
struct lws_dll_lws dll_active_client_conns;
struct lws_dll_lws dll_client_transaction_queue_head;
struct lws_dll_lws dll_client_transaction_queue;
struct lws_buflist *buflist; /* input-side buflist */
struct lws_buflist *buflist_out; /* output-side buflist */
struct lws_lws_tls tls;
lws_sock_file_fd_type desc; /* .filefd / .sockfd */
#if defined(LWS_WITH_STATS)
uint64_t active_writable_req_us;
lws_usec_t pending_timer; /* hrtimer fires */
time_t pending_timeout_set; /* second-resolution timeout start */
#ifdef LWS_LATENCY
unsigned long action_start;
unsigned long latency_start;
#endif
#define LWS_NO_FDS_POS (-1)
#ifndef LWS_NO_CLIENT
int chunk_remaining;
#endif
unsigned int hdr_parsing_completed:1;
unsigned int user_space_externally_allocated:1;
unsigned int socket_is_permanently_unusable:1;
unsigned int cache_reuse:1;
unsigned int cache_revalidate:1;
unsigned int cache_intermediaries:1;
unsigned int interpreting:1;
unsigned int told_user_closed:1;
unsigned int waiting_to_send_close_frame:1;
unsigned int seen_zero_length_recv:1;
unsigned int rxflow_will_be_applied:1;
unsigned int event_pipe:1;
unsigned int protocol_bind_balance:1;
Andy Green
committed
unsigned int could_have_pending:1; /* detect back-to-back writes */
unsigned int shadow:1; /* we do not control fd lifecycle at all */
#ifdef LWS_WITH_ACCESS_LOG
unsigned int access_log_pending:1;
#endif
#ifndef LWS_NO_CLIENT
unsigned int do_ws:1; /* whether we are doing http or ws flow */
unsigned int chunked:1; /* if the clientside connection is chunked */
unsigned int client_http_body_pending:1;
unsigned int transaction_from_pipeline_queue:1;
unsigned int keepalive_active:1;
unsigned int keepalive_rejected:1;
unsigned int client_pipeline:1;
unsigned int client_h2_alpn:1;
unsigned int client_h2_substream:1;
Andy Green
committed
#ifdef _WIN32
unsigned int sock_send_blocking:1;
#endif
#ifndef LWS_NO_CLIENT
unsigned short c_port;
#endif
unsigned short pending_timeout_limit;