/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 - 2018 Andy Green * * 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.h" #include "lws_config_private.h" #if defined(LWS_WITH_CGI) && defined(LWS_HAVE_VFORK) #define _GNU_SOURCE #endif #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; #endif #include #include #include #include #include #include #include #include #include #ifdef LWS_HAVE_SYS_TYPES_H #include #endif #ifdef LWS_HAVE_SYS_STAT_H #include #endif #if LWS_MAX_SMP > 1 #include #endif #ifndef LWS_DEF_HEADER_LEN #define LWS_DEF_HEADER_LEN 4096 #endif #ifndef LWS_DEF_HEADER_POOL #define LWS_DEF_HEADER_POOL 4 #endif #ifndef LWS_MAX_PROTOCOLS #define LWS_MAX_PROTOCOLS 5 #endif #ifndef LWS_MAX_EXTENSIONS_ACTIVE #define LWS_MAX_EXTENSIONS_ACTIVE 1 #endif #ifndef LWS_MAX_EXT_OFFERS #define LWS_MAX_EXT_OFFERS 8 #endif #ifndef SPEC_LATEST_SUPPORTED #define SPEC_LATEST_SUPPORTED 13 #endif #ifndef AWAITING_TIMEOUT #define AWAITING_TIMEOUT 20 #endif #ifndef CIPHERS_LIST_STRING #define CIPHERS_LIST_STRING "DEFAULT" #endif #ifndef LWS_SOMAXCONN #define LWS_SOMAXCONN SOMAXCONN #endif #define MAX_WEBSOCKET_04_KEY_LEN 128 #ifndef SYSTEM_RANDOM_FILEPATH #define SYSTEM_RANDOM_FILEPATH "/dev/urandom" #endif #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" /* 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 { #ifdef LWS_WITH_LIBEV struct lws_io_watcher_libev ev; #endif #ifdef LWS_WITH_LIBUV struct lws_io_watcher_libuv uv; #endif #ifdef LWS_WITH_LIBEVENT struct lws_io_watcher_libevent event; #endif struct lws_context *context; uint8_t actual_events; }; struct lws_signal_watcher { #ifdef LWS_WITH_LIBEV struct lws_signal_watcher_libev ev; #endif #ifdef LWS_WITH_LIBUV struct lws_signal_watcher_libuv uv; #endif #ifdef LWS_WITH_LIBEVENT struct lws_signal_watcher_libevent event; #endif struct lws_context *context; }; 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 { #if LWS_MAX_SMP > 1 pthread_mutex_t lock_stats; struct lws_mutex_refcount mr; pthread_t self; #endif 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; #endif struct lws_pollfd *fds; 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 --- */ #if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS) struct lws_pt_role_ws ws; #endif #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 /* --- event library based members --- */ #if defined(LWS_WITH_LIBEV) struct lws_pt_eventlibs_libev ev; #endif #if defined(LWS_WITH_LIBUV) struct lws_pt_eventlibs_libuv uv; #endif #if defined(LWS_WITH_LIBEVENT) struct lws_pt_eventlibs_libevent event; #endif #if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \ defined(LWS_WITH_LIBEVENT) struct lws_signal_watcher w_sigint; #endif /* --- */ unsigned long count_conns; 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 tid; unsigned char inside_service:1; unsigned char event_loop_foreign:1; unsigned char event_loop_destroy_processing_done:1; }; struct lws_conn_stats { unsigned long long rx, tx; 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 */ time_t time; int reason; int tsi_req; }; /* * virtual host -related context information * vhostwide SSL context * vhostwide proxy * * hierarchy: * * 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 */ struct lws_vhost { #if !defined(LWS_WITHOUT_CLIENT) char proxy_basic_auth_token[128]; #endif #if LWS_MAX_SMP > 1 pthread_mutex_t lock; char close_flow_vs_tsi[LWS_MAX_SMP]; #endif #if defined(LWS_ROLE_H2) struct lws_vhost_role_h2 h2; #endif #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) 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; #endif struct lws_conn_stats conn_stats; struct lws_context *context; struct lws_vhost *vhost_next; 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_protocols *protocols; void **protocol_vh_privs; 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 #if defined(LWS_WITH_TLS) struct lws_vhost_tls tls; #endif struct lws_timed_vh_protocol *timed_vh_protocol_list; void *user; int listen_port; #if defined(LWS_WITH_SOCKS5) unsigned int socks_proxy_port; #endif unsigned int options; int count_protocols; int ka_time; int ka_probes; int ka_interval; int keepalive_timeout; int timeout_secs_ah_idle; int count_bound_wsi; #ifdef LWS_WITH_ACCESS_LOG int log_fd; #endif unsigned int created_vhost_protocols:1; unsigned int being_destroyed:1; unsigned char default_protocol_index; 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; }; typedef union { #ifdef LWS_WITH_IPV6 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; #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) struct lws_peer_role_http http; #endif uint8_t af; }; #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 last_ws_ping_pong_check_s; time_t time_up; time_t time_discontiguity; time_t time_fixup; const struct lws_plat_file_ops *fops; struct lws_plat_file_ops fops_platform; 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 struct lws_context_per_thread pt[LWS_MAX_SMP]; struct lws_conn_stats conn_stats; #if LWS_MAX_SMP > 1 struct lws_mutex_refcount mr; #endif #ifdef _WIN32 /* different implementation between unix and windows */ struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS]; #else struct lws **lws_lookup; /* fd to wsi */ #endif struct lws_vhost *vhost_list; struct lws_vhost *no_listener_vhost_list; struct lws_vhost *vhost_pending_destruction_list; struct lws_plugin *plugin_list; struct lws_deferred_free *deferred_free_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; lws_reload_func deprecation_cb; 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 #if defined(LWS_WITH_LIBEV) struct lws_context_eventlibs_libev ev; #endif #if defined(LWS_WITH_LIBUV) struct lws_context_eventlibs_libuv uv; #endif #if defined(LWS_WITH_LIBEVENT) struct lws_context_eventlibs_libevent event; #endif struct lws_event_loop_ops *event_loop_ops; #if defined(LWS_WITH_TLS) struct lws_context_tls tls; #endif char canonical_hostname[128]; 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 max_fds; int count_event_loop_static_asset_handles; int started_with_parent; int uid, gid; int fd_random; int count_wsi_allocated; int count_cgi_spawned; unsigned int options; unsigned int fd_limit_per_thread; unsigned int timeout_secs; 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; short count_threads; short plugin_protocol_count; short plugin_extension_count; short server_string_len; unsigned short ws_ping_pong_interval; unsigned short deprecation_pending_listen_close_count; uint8_t max_fi; }; int 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_close_free_wsi_final(struct lws *wsi); LWS_EXTERN void lws_libuv_closehandle(struct lws *wsi); LWS_EXTERN int lws_libuv_check_watcher_active(struct lws *wsi); LWS_VISIBLE LWS_EXTERN int 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), LWS_EV_PREPARE_DELETION = (1u << 31), }; #if defined(LWS_WITH_ESP32) LWS_EXTERN int lws_find_string_in_file(const char *filename, const char *str, int stringlen); #endif #ifdef LWS_WITH_IPV6 #define LWS_IPV6_ENABLED(vh) \ (!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 #ifdef LWS_WITH_UNIX_SOCK #define LWS_UNIX_SOCK_ENABLED(vhost) \ (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK) #else #define LWS_UNIX_SOCK_ENABLED(vhost) (0) #endif 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; char *alpn; }; #endif 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_wsi_is_udp(___wsi) (!!___wsi->udp) #define LWS_H2_FRAME_HEADER_LENGTH 9 struct lws { /* structs */ #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) struct _lws_http_mode_related http; #endif #if defined(LWS_ROLE_H2) struct _lws_h2_related h2; #endif #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; /* lifetime members */ #if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \ defined(LWS_WITH_LIBEVENT) struct lws_io_watcher w_read; #endif #if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT) struct lws_io_watcher w_write; #endif /* pointers */ struct lws_context *context; struct lws_vhost *vhost; 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; #endif struct lws_udp *udp; #ifndef LWS_NO_CLIENT struct client_info_stash *stash; char *client_hostname_copy; 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; #endif void *user_space; void *opaque_parent_data; struct lws_buflist *buflist; /* input-side buflist */ struct lws_buflist *buflist_out; /* output-side buflist */ #if defined(LWS_WITH_TLS) struct lws_lws_tls tls; #endif lws_sock_file_fd_type desc; /* .filefd / .sockfd */ #if defined(LWS_WITH_STATS) uint64_t active_writable_req_us; #if defined(LWS_WITH_TLS) uint64_t accept_start_us; #endif #endif 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 /* ints */ #define LWS_NO_FDS_POS (-1) int position_in_fds_table; #ifndef LWS_NO_CLIENT int chunk_remaining; #endif unsigned int cache_secs; unsigned int hdr_parsing_completed:1; unsigned int http2_substream:1; unsigned int upgraded_to_http2:1; unsigned int h2_stream_carries_ws:1; unsigned int seen_nonpseudoheader:1; unsigned int listener:1; unsigned int user_space_externally_allocated:1; unsigned int socket_is_permanently_unusable:1; unsigned int rxflow_change_to:2; unsigned int conn_stat_done:1; unsigned int cache_reuse:1; unsigned int cache_revalidate:1; unsigned int cache_intermediaries:1; unsigned int favoured_pollin:1; unsigned int sending_chunked:1; unsigned int interpreting:1; unsigned int already_did_cce:1; unsigned int told_user_closed:1; unsigned int told_event_loop_closed:1; unsigned int waiting_to_send_close_frame:1; unsigned int close_needs_ack:1; unsigned int ipv6:1; unsigned int parent_pending_cb_on_writable:1; unsigned int cgi_stdout_zero_length:1; unsigned int seen_zero_length_recv:1; unsigned int rxflow_will_be_applied:1; unsigned int event_pipe:1; unsigned int handling_404:1; unsigned int protocol_bind_balance:1; unsigned int unix_skt:1; unsigned int could_have_pending:1; /* detect back-to-back writes */ unsigned int outer_will_close:1; 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_rx_avail:1; 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; #endif #ifdef _WIN32 unsigned int sock_send_blocking:1; #endif #ifndef LWS_NO_CLIENT unsigned short c_port; #endif unsigned short pending_timeout_limit; /* chars */ char lws_rx_parse_state; /* enum lws_rx_parse_state */ char rx_frame_type; /* enum lws_write_protocol */ char pending_timeout; /* enum pending_timeout */ char tsi; /* thread service index we belong to */ char protocol_interpret_idx; char redirects; uint8_t rxflow_bitmap; #ifdef LWS_WITH_CGI char cgi_channel; /* which of stdin/out/err */ char hdr_state; #endif #ifndef LWS_NO_CLIENT char chunk_parser; /* enum lws_chunk_parser */ #endif #if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT) char reason_bf; /* internal writeable callback reason bitfield */ #endif #if defined(LWS_WITH_STATS) && defined(LWS_WITH_TLS) char seen_rx; #endif uint8_t ws_over_h2_count; /* volatile to make sure code is aware other thread can change */ volatile char handling_pollout; volatile char leave_pollout_active; }; LWS_EXTERN char * lws_strdup(const char *s); #define lws_is_flowcontrolled(w) (!!(wsi->rxflow_bitmap)) void lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt); LWS_EXTERN int log_level; LWS_EXTERN int lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, const char *iface); #if defined(LWS_WITH_IPV6) LWS_EXTERN unsigned long lws_get_addr_scope(const char *ipaddr); #endif LWS_EXTERN void lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller); LWS_EXTERN void __lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller); LWS_EXTERN void __lws_free_wsi(struct lws *wsi); LWS_EXTERN int __remove_wsi_socket_from_fds(struct lws *wsi); LWS_EXTERN int lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len); #ifndef LWS_LATENCY static LWS_INLINE void lws_latency(struct lws_context *context, struct lws *wsi, const char *action, int ret, int completion) { do { (void)context; (void)wsi; (void)action; (void)ret; (void)completion; } while (0); } static LWS_INLINE void lws_latency_pre(struct lws_context *context, struct lws *wsi) { do { (void)context; (void)wsi; } while (0); } #else #define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0) extern void lws_latency(struct lws_context *context, struct lws *wsi, const char *action, int ret, int completion); #endif static LWS_INLINE int lws_has_buffered_out(struct lws *wsi) { return !!wsi->buflist_out; } LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ws_client_rx_sm(struct lws *wsi, unsigned char c); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_parse(struct lws *wsi, unsigned char *buf, int *len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_parse_urldecode(struct lws *wsi, uint8_t *_c); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_http_action(struct lws *wsi); LWS_EXTERN int lws_b64_selftest(void); LWS_EXTERN int lws_service_flag_pending(struct lws_context *context, int tsi); LWS_EXTERN int __lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p); LWS_EXTERN int LWS_WARN_UNUSED_RESULT __insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len); LWS_EXTERN void lws_remove_from_timeout_list(struct lws *wsi); LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_client_connect_2(struct lws *wsi); LWS_VISIBLE struct lws * LWS_WARN_UNUSED_RESULT lws_client_reset(struct lws **wsi, int ssl, const char *address, int port, const char *path, const char *host); LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi); LWS_EXTERN char * LWS_WARN_UNUSED_RESULT lws_generate_client_handshake(struct lws *wsi, char *pkt); LWS_EXTERN int lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd); LWS_EXTERN struct lws * lws_http_client_connect_via_info2(struct lws *wsi); LWS_EXTERN void lws_client_stash_destroy(struct lws *wsi); /* * EXTENSIONS */ #if defined(LWS_WITHOUT_EXTENSIONS) #define lws_any_extension_handled(_a, _b, _c, _d) (0) #define lws_ext_cb_active(_a, _b, _c, _d) (0) #define lws_ext_cb_all_exts(_a, _b, _c, _d, _e) (0) #define lws_issue_raw_ext_access lws_issue_raw #define lws_context_init_extensions(_a, _b) #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_client_interpret_server_handshake(struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len); LWS_EXTERN void lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state, struct lws_role_ops *ops); LWS_EXTERN int LWS_WARN_UNUSED_RESULT user_callback_handle_rxflow(lws_callback_function, struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); LWS_EXTERN int lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd, int unix_skt); LWS_EXTERN int lws_plat_check_connection_error(struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_header_table_attach(struct lws *wsi, int autoservice); LWS_EXTERN int lws_header_table_detach(struct lws *wsi, int autoservice); LWS_EXTERN int __lws_header_table_detach(struct lws *wsi, int autoservice); LWS_EXTERN void lws_header_table_reset(struct lws *wsi, int autoservice); void __lws_header_table_reset(struct lws *wsi, int autoservice); LWS_EXTERN char * LWS_WARN_UNUSED_RESULT lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ensure_user_space(struct lws *wsi); LWS_EXTERN int lws_change_pollfd(struct lws *wsi, int _and, int _or); #ifndef LWS_NO_SERVER int _lws_vhost_init_server(const struct lws_context_creation_info *info, struct lws_vhost *vhost); LWS_EXTERN struct lws_vhost * lws_select_vhost(struct lws_context *context, int port, const char *servername); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len); LWS_EXTERN void lws_server_get_canonical_hostname(struct lws_context *context, const struct lws_context_creation_info *info); #else #define _lws_vhost_init_server(_a, _b) (0) #define lws_parse_ws(_a, _b, _c) (0) #define lws_server_get_canonical_hostname(_a, _b) #endif #ifndef LWS_NO_DAEMONIZE LWS_EXTERN int get_daemonize_pid(); #else #define get_daemonize_pid() (0) #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT interface_to_sa(struct lws_vhost *vh, const char *ifname, struct sockaddr_in *addr, size_t addrlen); LWS_EXTERN void lwsl_emit_stderr(int level, const char *line); #if !defined(LWS_WITH_TLS) #define LWS_SSL_ENABLED(context) (0) #define lws_context_init_server_ssl(_a, _b) (0) #define lws_ssl_destroy(_a) #define lws_context_init_alpn(_a) #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl #define lws_ssl_pending lws_ssl_pending_no_ssl #define lws_server_socket_service_ssl(_b, _c) (0) #define lws_ssl_close(_a) (0) #define lws_ssl_context_destroy(_a) #define lws_ssl_SSL_CTX_destroy(_a) #define lws_ssl_remove_wsi_from_buffered_list(_a) #define __lws_ssl_remove_wsi_from_buffered_list(_a) #define lws_context_init_ssl_library(_a) #define lws_tls_check_all_cert_lifetimes(_a) #define lws_tls_acme_sni_cert_destroy(_a) #endif #if LWS_MAX_SMP > 1 static LWS_INLINE void lws_pt_mutex_init(struct lws_context_per_thread *pt) { lws_mutex_refcount_init(&pt->mr); pthread_mutex_init(&pt->lock_stats, NULL); } static LWS_INLINE void lws_pt_mutex_destroy(struct lws_context_per_thread *pt) { pthread_mutex_destroy(&pt->lock_stats); lws_mutex_refcount_destroy(&pt->mr); } #define lws_pt_lock(pt, reason) lws_mutex_refcount_lock(&pt->mr, reason) #define lws_pt_unlock(pt) lws_mutex_refcount_unlock(&pt->mr) static LWS_INLINE void lws_pt_stats_lock(struct lws_context_per_thread *pt) { pthread_mutex_lock(&pt->lock_stats); } static LWS_INLINE void lws_pt_stats_unlock(struct lws_context_per_thread *pt) { pthread_mutex_unlock(&pt->lock_stats); } #define lws_context_lock(c, reason) lws_mutex_refcount_lock(&c->mr, reason) #define lws_context_unlock(c) lws_mutex_refcount_unlock(&c->mr) static LWS_INLINE void lws_vhost_lock(struct lws_vhost *vhost) { pthread_mutex_lock(&vhost->lock); } static LWS_INLINE void lws_vhost_unlock(struct lws_vhost *vhost) { pthread_mutex_unlock(&vhost->lock); } #else #define lws_pt_mutex_init(_a) (void)(_a) #define lws_pt_mutex_destroy(_a) (void)(_a) #define lws_pt_lock(_a, b) (void)(_a) #define lws_pt_unlock(_a) (void)(_a) #define lws_context_lock(_a, _b) (void)(_a) #define lws_context_unlock(_a) (void)(_a) #define lws_vhost_lock(_a) (void)(_a) #define lws_vhost_unlock(_a) (void)(_a) #define lws_pt_stats_lock(_a) (void)(_a) #define lws_pt_stats_unlock(_a) (void)(_a) #endif LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_ssl_pending_no_ssl(struct lws *wsi); int lws_tls_check_cert_lifetime(struct lws_vhost *vhost); int lws_jws_selftest(void); #ifndef LWS_NO_CLIENT LWS_EXTERN int lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, struct lws *wsi_conn); LWS_EXTERN struct lws * lws_client_wsi_effective(struct lws *wsi); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_http_transaction_completed_client(struct lws *wsi); #if !defined(LWS_WITH_TLS) #define lws_context_init_client_ssl(_a, _b) (0) #endif LWS_EXTERN void lws_decode_ssl_error(void); #else #define lws_context_init_client_ssl(_a, _b) (0) #endif LWS_EXTERN int __lws_rx_flow_control(struct lws *wsi); LWS_EXTERN int _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa); #ifndef LWS_NO_SERVER LWS_EXTERN int lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len); #else #define lws_server_socket_service(_b, _c) (0) #define lws_handshake_server(_a, _b, _c) (0) #endif #ifdef LWS_WITH_ACCESS_LOG LWS_EXTERN int lws_access_log(struct lws *wsi); LWS_EXTERN void lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int len, int meth); #else #define lws_access_log(_a) #endif LWS_EXTERN int lws_cgi_kill_terminated(struct lws_context_per_thread *pt); LWS_EXTERN void lws_cgi_remove_and_kill(struct lws *wsi); int lws_protocol_init(struct lws_context *context); int lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p, const char *reason); const struct lws_http_mount * lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len); /* * custom allocator */ LWS_EXTERN void * lws_realloc(void *ptr, size_t size, const char *reason); LWS_EXTERN void * LWS_WARN_UNUSED_RESULT lws_zalloc(size_t size, const char *reason); #ifdef LWS_PLAT_OPTEE void *lws_malloc(size_t size, const char *reason); void lws_free(void *p); #define lws_free_set_NULL(P) do { lws_free(P); (P) = NULL; } while(0) #else #define lws_malloc(S, R) lws_realloc(NULL, S, R) #define lws_free(P) lws_realloc(P, 0, "lws_free") #define lws_free_set_NULL(P) do { lws_realloc(P, 0, "free"); (P) = NULL; } while(0) #endif int lws_plat_pipe_create(struct lws *wsi); int lws_plat_pipe_signal(struct lws *wsi); void lws_plat_pipe_close(struct lws *wsi); int lws_create_event_pipes(struct lws_context *context); int lws_plat_apply_FD_CLOEXEC(int n); const struct lws_plat_file_ops * lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path, const char **vpath); /* lws_plat_ */ LWS_EXTERN void lws_plat_delete_socket_from_fds(struct lws_context *context, struct lws *wsi, int m); LWS_EXTERN void lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi); LWS_EXTERN void lws_plat_service_periodic(struct lws_context *context); LWS_EXTERN int lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi, struct lws_pollfd *pfd); LWS_EXTERN void lws_add_wsi_to_draining_ext_list(struct lws *wsi); LWS_EXTERN void lws_remove_wsi_from_draining_ext_list(struct lws *wsi); LWS_EXTERN int lws_plat_context_early_init(void); LWS_EXTERN void lws_plat_context_early_destroy(struct lws_context *context); LWS_EXTERN void lws_plat_context_late_destroy(struct lws_context *context); LWS_EXTERN int lws_poll_listen_fd(struct lws_pollfd *fd); LWS_EXTERN int lws_plat_service(struct lws_context *context, int timeout_ms); LWS_EXTERN LWS_VISIBLE int _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi); LWS_EXTERN int lws_pthread_self_to_tsi(struct lws_context *context); LWS_EXTERN int lws_plat_init(struct lws_context *context, const struct lws_context_creation_info *info); LWS_EXTERN void lws_plat_drop_app_privileges(const struct lws_context_creation_info *info); LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_plat_inet_pton(int af, const char *src, void *dst); LWS_EXTERN int lws_check_byte_utf8(unsigned char state, unsigned char c); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len); LWS_EXTERN int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf, lws_filepos_t *amount); LWS_EXTERN void lws_same_vh_protocol_remove(struct lws *wsi); LWS_EXTERN void __lws_same_vh_protocol_remove(struct lws *wsi); LWS_EXTERN void lws_same_vh_protocol_insert(struct lws *wsi, int n); LWS_EXTERN int lws_broadcast(struct lws_context *context, int reason, void *in, size_t len); #if defined(LWS_WITH_STATS) void lws_stats_atomic_bump(struct lws_context * context, struct lws_context_per_thread *pt, int index, uint64_t bump); void lws_stats_atomic_max(struct lws_context * context, struct lws_context_per_thread *pt, int index, uint64_t val); #else static LWS_INLINE uint64_t lws_stats_atomic_bump(struct lws_context * context, struct lws_context_per_thread *pt, int index, uint64_t bump) { (void)context; (void)pt; (void)index; (void)bump; return 0; } static LWS_INLINE uint64_t lws_stats_atomic_max(struct lws_context * context, struct lws_context_per_thread *pt, int index, uint64_t val) { (void)context; (void)pt; (void)index; (void)val; return 0; } #endif /* socks */ void socks_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len); #if defined(LWS_WITH_PEER_LIMITS) void lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer); int lws_peer_confirm_ah_attach_ok(struct lws_context *context, struct lws_peer *peer); void lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer); void lws_peer_cull_peer_wait_list(struct lws_context *context); struct lws_peer * lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd); void lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer, struct lws *wsi); void lws_peer_dump_from_wsi(struct lws *wsi); #endif #ifdef LWS_WITH_HUBBUB hubbub_error html_parser_cb(const hubbub_token *token, void *pw); #endif int lws_threadpool_tsi_context(struct lws_context *context, int tsi); void __lws_remove_from_timeout_list(struct lws *wsi); lws_usec_t __lws_hrtimer_service(struct lws_context_per_thread *pt); void __lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs); int __lws_change_pollfd(struct lws *wsi, int _and, int _or); int lws_callback_as_writeable(struct lws *wsi); int lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi, struct lws_tokens *ebuf); int lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used, int buffered); char * lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1); int lws_client_ws_upgrade(struct lws *wsi, const char **cce); int lws_create_client_ws_object(const struct lws_client_connect_info *i, struct lws *wsi); int lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len); int lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn); int lws_tls_server_conn_alpn(struct lws *wsi); int lws_ws_client_rx_sm_block(struct lws *wsi, unsigned char **buf, size_t len); void lws_destroy_event_pipe(struct lws *wsi); void lws_context_destroy2(struct lws_context *context); int lws_role_call_client_bind(struct lws *wsi, const struct lws_client_connect_info *i); void lws_remove_child_from_any_parent(struct lws *wsi); #ifdef __cplusplus }; #endif