--- /dev/null
- __lws_sul_check(lws_dll2_owner_t *own, lws_usec_t usnow);
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 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
+ */
+
+#if !defined(__LWS_CORE_NET_PRIVATE_H__)
+#define __LWS_CORE_NET_PRIVATE_H__
+
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+#include "private-lib-roles.h"
+
+#ifdef LWS_WITH_IPV6
+#if defined(WIN32) || defined(_WIN32)
+#include <iphlpapi.h>
+#else
+#include <net/if.h>
+#endif
+#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 */
+};
+
+
+/*
+ *
+ * ------ roles ------
+ *
+ */
+
+/* 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 ------
+ *
+ */
+
+/* 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),
+};
+
+enum lws_parser_return {
+ LPR_OK = 0,
+ LPR_FAIL = -1,
+ LPR_DO_FALLBACK = 2,
+ LPR_FORBIDDEN = -2
+};
+
+enum pmd_return {
+ PMDR_UNKNOWN,
+ PMDR_DID_NOTHING,
+ PMDR_HAS_PENDING,
+ PMDR_EMPTY_NONFINAL,
+ PMDR_EMPTY_FINAL,
+
+ PMDR_FAILED = -1
+};
+
+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
+
+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),
+};
+
+#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;
+ void *opaque_user_data; /* not allocated or freed by lws */
+};
+#endif
+
+#define lws_wsi_is_udp(___wsi) (!!___wsi->udp)
+
+#define LWS_H2_FRAME_HEADER_LENGTH 9
+
+int
+__lws_sul_insert(lws_dll2_owner_t *own, lws_sorted_usec_list_t *sul,
+ lws_usec_t us);
+
+lws_usec_t
- typedef struct lws_dsh lws_dsh_t;
-
++__lws_sul_service_ripe(lws_dll2_owner_t *own, lws_usec_t usnow);
+
+struct lws_timed_vh_protocol {
+ struct lws_timed_vh_protocol *next;
+ lws_sorted_usec_list_t sul;
+ const struct lws_protocols *protocol;
+ struct lws_vhost *vhost; /* only used for pending processing */
+ int reason;
+ int tsi_req;
+};
+
+/*
+ * lws_dsh
+*/
+
+typedef struct lws_dsh_obj_head {
+ lws_dll2_owner_t owner;
+ int kind;
+} lws_dsh_obj_head_t;
+
- typedef struct lws_dsh {
+typedef struct lws_dsh_obj {
+ lws_dll2_t list; /* must be first */
+ lws_dsh_t *dsh; /* invalid when on free list */
+ size_t size; /* invalid when on free list */
+ size_t asize;
+} lws_dsh_obj_t;
+
- } lws_dsh_t;
++struct lws_dsh {
+ lws_dll2_t list;
+ uint8_t *buf;
+ lws_dsh_obj_head_t *oha; /* array of object heads/kind */
+ size_t buffer_size;
+ size_t locally_in_use;
+ size_t locally_free;
+ int count_kinds;
+ uint8_t being_destroyed;
+ /*
+ * Overallocations at create:
+ *
+ * - the buffer itself
+ * - the object heads array
+ */
- unsigned short c_port;
++};
+
+/*
+ * 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_dll2_owner dll_buflist_owner; /* guys with pending rxflow */
+ struct lws_dll2_owner seq_owner; /* list of lws_sequencer-s */
+
+ struct lws_dll2_owner pt_sul_owner;
+
+#if defined (LWS_WITH_SEQUENCER)
+ lws_sorted_usec_list_t sul_seq_heartbeat;
+#endif
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+ lws_sorted_usec_list_t sul_ah_lifecheck;
+#endif
+#if defined(LWS_WITH_TLS) && !defined(LWS_NO_SERVER)
+ lws_sorted_usec_list_t sul_tls;
+#endif
+#if defined(LWS_PLAT_UNIX)
+ lws_sorted_usec_list_t sul_plat;
+#endif
+#if defined(LWS_WITH_STATS)
+ uint64_t lws_stats[LWSSTATS_SIZE];
+ int updated;
+ lws_sorted_usec_list_t sul_stats;
+#endif
+#if defined(LWS_WITH_PEER_LIMITS)
+ lws_sorted_usec_list_t sul_peer_limits;
+#endif
+
+#if defined(LWS_WITH_TLS)
+ struct lws_pt_tls tls;
+#endif
+ struct lws *fake_wsi; /* used for callbacks where there's no wsi */
+
+ 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_pollfd *fds;
+ volatile struct lws_foreign_thread_pollfd * volatile foreign_pfd_list;
+#ifdef _WIN32
+ WSAEVENT events;
+ CRITICAL_SECTION interrupt_lock;
+#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;
+#ifdef _WIN32
+ unsigned char interrupt_requested:1;
+#endif
+};
+
+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;
+};
+
+/*
+ * 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;
+ const char *listen_accept_role;
+ const char *listen_accept_protocol;
+ const char *unix_socket_perms;
+
+ 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_dll2_owner *same_vh_protocol_owner;
+ struct lws_vhost *no_listener_vhost_list;
+ struct lws_dll2_owner abstract_instances_owner;
+
+#if !defined(LWS_NO_CLIENT)
+ struct lws_dll2_owner dll_cli_active_conns_owner;
+#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 allocated_vhost_protocols:1;
+ unsigned int created_vhost_protocols:1;
+ unsigned int being_destroyed:1;
+
+ unsigned char default_protocol_index;
+ unsigned char raw_protocol_index;
+};
+
+void
+__lws_vhost_destroy2(struct lws_vhost *vh);
+
+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 */
+ lws_sorted_usec_list_t sul_ping;
+#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
+
+ lws_sorted_usec_list_t sul_timeout;
+ lws_sorted_usec_list_t sul_hrtimer;
+
+ /* 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_dll2 same_vh_protocol;
+
+ lws_seq_t *seq; /* associated sequencer if any */
+
+ struct lws_dll2 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 *cli_hostname_copy;
+ struct lws_dll2 dll_cli_active_conns;
+ struct lws_dll2_owner dll2_cli_txn_queue_owner;
+ struct lws_dll2 dll2_cli_txn_queue;
+#endif
+ void *user_space;
+ void *opaque_parent_data;
+ void *opaque_user_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
+
+#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 h2_stream_carries_sse: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 close_when_buffered_out_drained:1;
+ unsigned int h1_ws_proxied;
+ unsigned int proxied_ws_parent;
+
+ 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 ocport, c_port;
+#endif
+
+ /* 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;
+ uint8_t bound_vhost_index;
+#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 immortal_substream_count;
+ /* volatile to make sure code is aware other thread can change */
+ volatile char handling_pollout;
+ volatile char leave_pollout_active;
+#if LWS_MAX_SMP > 1
+ volatile char undergoing_init_from_other_pt;
+#endif
+
+};
+
+#define lws_is_flowcontrolled(w) (!!(wsi->rxflow_bitmap))
+
+void
+lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt);
+
+const struct lws_role_ops *
+lws_role_by_name(const char *name);
+
+LWS_EXTERN int
+lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
+ const char *iface, int ipv6_allowed);
+
+#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);
+
+#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);
+}
+#endif
+
+/*
+ * 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,
+ const struct lws_role_ops *ops);
+
+int
+lws_http_to_fallback(struct lws *wsi, unsigned char *buf, size_t len);
+
+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_nonblocking(int fd);
+
+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_WARN_UNUSED_RESULT
+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
+
+LWS_EXTERN int
+__remove_wsi_socket_from_fds(struct lws *wsi);
+
+enum {
+ LWSRXFC_ERROR = -1,
+ LWSRXFC_CACHED = 0,
+ LWSRXFC_ADDITIONAL = 1,
+ LWSRXFC_TRIMMED = 2,
+};
+
++
++int
++_lws_plat_service_forced_tsi(struct lws_context *context, int tsi);
++
+LWS_EXTERN int
+lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len);
+
+LWS_EXTERN int
+lws_service_flag_pending(struct lws_context *context, int tsi);
+
+LWS_EXTERN void
+lws_client_stash_destroy(struct lws *wsi);
+
+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 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);
+
+void
+lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi);
+void
+lws_vhost_unbind_wsi(struct lws *wsi);
+
+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_role_call_client_bind(struct lws *wsi,
+ const struct lws_client_connect_info *i);
+void
+lws_remove_child_from_any_parent(struct lws *wsi);
+
+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);
+
+/* socks */
+int
+socks_generate_msg(struct lws *wsi, enum socks_msg_type type, ssize_t *msg_len);
+
+
+void
+lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs);
+
+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 lws_usec_t
+__lws_seq_timeout_check(struct lws_context_per_thread *pt, lws_usec_t usnow);
+
+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);
+
+
+#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);
+
+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 int
+lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
+ struct lws_pollfd *pfd);
+
+
+int
+lws_plat_pipe_create(struct lws *wsi);
+int
+lws_plat_pipe_signal(struct lws *wsi);
+void
+lws_plat_pipe_close(struct lws *wsi);
+
+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_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 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 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);
+
+void
+lws_seq_destroy_all_on_pt(struct lws_context_per_thread *pt);
+
+LWS_EXTERN int
+lws_broadcast(struct lws_context_per_thread *pt, int reason, void *in, size_t len);
+
+#if defined(LWS_WITH_STATS)
+ void
+ lws_stats_bump(struct lws_context_per_thread *pt, int i, uint64_t bump);
+ void
+ lws_stats_max(struct lws_context_per_thread *pt, int index, uint64_t val);
+#else
+ static LWS_INLINE uint64_t lws_stats_bump(
+ struct lws_context_per_thread *pt, int index, uint64_t bump) {
+ (void)pt; (void)index; (void)bump; return 0; }
+ static LWS_INLINE uint64_t lws_stats_max(
+ struct lws_context_per_thread *pt, int index, uint64_t val) {
+ (void)pt; (void)index; (void)val; return 0; }
+#endif
+
+
+
+#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_wsi_remove_from_sul(struct lws *wsi);
+
+int
+lws_seq_pt_init(struct lws_context_per_thread *pt);
+
+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);
+
+extern const struct lws_protocols protocol_abs_client_raw_skt,
+ protocol_abs_client_unit_test;
+
+void
+lws_inform_client_conn_fail(struct lws *wsi, void *arg, size_t len);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
--- /dev/null
- LWS_EXTERN int get_daemonize_pid();
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010 - 2019 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.h"
+#include "lws_config_private.h"
+
+#if defined(LWS_WITH_CGI) && defined(LWS_HAVE_VFORK) && \
+ !defined(NO_GNU_SOURCE_THIS_TIME)
+ #define _GNU_SOURCE
+#endif
+
+/*
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#ifdef LWS_HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include <assert.h>
+
+#ifdef LWS_HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+#endif
+#if defined(LWS_HAVE_SYS_STAT_H) && !defined(LWS_PLAT_OPTEE)
+ #include <sys/stat.h>
+#endif
+
+#if LWS_MAX_SMP > 1
+ #include <pthread.h>
+#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 "private-lib-plat-esp32.h"
+#else
+ #if defined(WIN32) || defined(_WIN32)
+ #include "private-lib-plat-windows.h"
+ #else
+ #if defined(LWS_PLAT_OPTEE)
+ #include "private-lib-plat.h"
+ #else
+ #include "private-lib-plat-unix.h"
+ #endif
+ #endif
+#endif
+
+ /*
+ *
+ * ------ public api ------
+ *
+ */
+
+#include "libwebsockets.h"
+
+#include "private-lib-tls.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
+ #define strncasecmp _strnicmp
+ #elif !defined(__MINGW32__)
+ #define strcasecmp stricmp
+ #define strncasecmp strnicmp
+ #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
+
+
+
+#if defined(__clang__)
+#define lws_memory_barrier() __sync_synchronize()
+#elif defined(__GNUC__)
+#define lws_memory_barrier() __sync_synchronize()
+#else
+#define lws_memory_barrier()
+#endif
+
+
+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;
+
+#if defined(LWS_WITH_NETWORK)
+#include "private-lib-event-libs.h"
+
+
+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;
+};
+#endif
+
+#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
+
+#if defined(LWS_WITH_NETWORK)
+#include "private-lib-core-net.h"
+#endif
+
+struct lws_deferred_free
+{
+ struct lws_deferred_free *next;
+ time_t deadline;
+ void *payload;
+};
+
+/*
+ * the rest is managed per-context, that includes
+ *
+ * - processwide single fd -> wsi lookup
+ * - contextwide headers pool
+ */
+
+struct lws_context {
+ time_t last_ws_ping_pong_check_s;
+ lws_usec_t time_up; /* monotonic */
+ 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;
+
+ const char *username, *groupname;
+
+#if defined(LWS_WITH_HTTP2)
+ struct http2_settings set;
+#endif
+#if defined(LWS_WITH_ZIP_FOPS)
+ struct lws_plat_file_ops fops_zip;
+#endif
+#if defined(LWS_WITH_NETWORK)
+ struct lws_context_per_thread pt[LWS_MAX_SMP];
+ struct lws_conn_stats conn_stats;
+ struct lws_vhost *vhost_list;
+ struct lws_vhost *no_listener_vhost_list;
+ struct lws_vhost *vhost_pending_destruction_list;
+ struct lws_plugin *plugin_list;
+#ifdef _WIN32
+/* different implementation between unix and windows */
+ struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS];
+#else
+ struct lws **lws_lookup;
+
+#endif
+#endif
+#if LWS_MAX_SMP > 1
+ struct lws_mutex_refcount mr;
+#endif
+
+#if defined(LWS_AMAZON_RTOS)
+ mbedtls_entropy_context mec;
+ mbedtls_ctr_drbg_context mcdc;
+#endif
+
+ 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
+
+ const lws_system_ops_t *system_ops;
+ 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_NETWORK)
+#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;
+#endif
+
+#if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK)
+ 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_ESP32)
+ unsigned long time_last_state_dump;
+ uint32_t last_free_heap;
+#endif
+
+ int max_fds;
+ int count_event_loop_static_asset_handles;
+#if !defined(LWS_NO_DAEMONIZE)
+ pid_t started_with_parent;
+#endif
+ 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;
+ unsigned int max_fds_unrelated_to_ulimit: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;
+
+#if defined(LWS_WITH_STATS)
+ uint8_t updated;
+#endif
+};
+
+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]
+
+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);
+
+
+#if defined(LWS_WITH_ESP32)
+LWS_EXTERN int
+lws_find_string_in_file(const char *filename, const char *str, int stringlen);
+#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 */
+};
+
+
+LWS_EXTERN char *
+lws_strdup(const char *s);
+
+LWS_EXTERN int log_level;
+
+
+
+#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
+
+
+LWS_EXTERN int
+lws_b64_selftest(void);
+
+
+
+
+
+#ifndef LWS_NO_DAEMONIZE
++ LWS_EXTERN pid_t get_daemonize_pid();
+#else
+ #define get_daemonize_pid() (0)
+#endif
+
+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_context_deinit_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
+#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);
+int lws_jwe_selftest(void);
+
+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_protocol_vhost_options *
+lws_vhost_protocol_options(struct lws_vhost *vh, const char *name);
+
+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_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 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_plat_init(struct lws_context *context,
+ const struct lws_context_creation_info *info);
+LWS_EXTERN int
+lws_plat_drop_app_privileges(struct lws_context *context, int actually_drop);
+
+#if defined(LWS_WITH_UNIX_SOCK)
+int
+lws_plat_user_colon_group_to_ids(const char *u_colon_g, uid_t *puid, gid_t *pgid);
+#endif
+
+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);
+
+void
+lws_context_destroy2(struct lws_context *context);
+
+
+#ifdef __cplusplus
+};
+#endif
--- /dev/null
- #if defined(__sun) && !defined(__smartos__)
+/*
+ * 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
+ *
+ * Included from lib/private-lib-core.h if no explicit platform
+ */
+
+#include <fcntl.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <poll.h>
+#include <netdb.h>
+
+#ifndef __cplusplus
+#include <errno.h>
+#endif
+#include <netdb.h>
+#include <signal.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/un.h>
++#if defined(LWS_HAVE_EVENTFD)
++#include <sys/eventfd.h>
++#endif
+
+#if defined(__APPLE__)
+#include <machine/endian.h>
+#endif
+#if defined(__FreeBSD__)
+#include <sys/endian.h>
+#endif
+#if defined(__linux__)
+#include <endian.h>
+#endif
+#if defined(__QNX__)
+ #include <gulliver.h>
+ #if defined(__LITTLEENDIAN__)
+ #define BYTE_ORDER __LITTLEENDIAN__
+ #define LITTLE_ENDIAN __LITTLEENDIAN__
+ #define BIG_ENDIAN 4321 /* to show byte order (taken from gcc); for suppres warning that BIG_ENDIAN is not defined. */
+ #endif
+ #if defined(__BIGENDIAN__)
+ #define BYTE_ORDER __BIGENDIAN__
+ #define LITTLE_ENDIAN 1234 /* to show byte order (taken from gcc); for suppres warning that LITTLE_ENDIAN is not defined. */
+ #define BIG_ENDIAN __BIGENDIAN__
+ #endif
+#endif
+
+#if defined(__sun) && defined(__GNUC__)
+
+#include <arpa/nameser_compat.h>
+
+#if !defined (BYTE_ORDER)
+#define BYTE_ORDER __BYTE_ORDER__
+#endif
+
+#if !defined(LITTLE_ENDIAN)
+#define LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
+#endif
+
+#if !defined(BIG_ENDIAN)
+#define BIG_ENDIAN __ORDER_BIG_ENDIAN__
+#endif
+
+#endif /* sun + GNUC */
+
+#if !defined(BYTE_ORDER)
+#define BYTE_ORDER __BYTE_ORDER
+#endif
+#if !defined(LITTLE_ENDIAN)
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#if !defined(BIG_ENDIAN)
+#define BIG_ENDIAN __BIG_ENDIAN
+#endif
+
+#if defined(LWS_BUILTIN_GETIFADDRS)
+#include "./misc/getifaddrs.h"
+#else
+
+#if defined(__HAIKU__)
+#define _BSD_SOURCE
+#endif
+#include <ifaddrs.h>
+
+#endif
+
+#if defined (__sun) || defined(__HAIKU__) || defined(__QNX__) || defined(__ANDROID__)
+#include <syslog.h>
+
+#if defined(__ANDROID__)
+#include <sys/resource.h>
+#endif
+
+#else
+#include <sys/syslog.h>
+#endif
+
+#ifdef __QNX__
+# include "netinet/tcp_var.h"
+# define TCP_KEEPINTVL TCPCTL_KEEPINTVL
+# define TCP_KEEPIDLE TCPCTL_KEEPIDLE
+# define TCP_KEEPCNT TCPCTL_KEEPCNT
+#endif
+
+#define LWS_ERRNO errno
+#define LWS_EAGAIN EAGAIN
+#define LWS_EALREADY EALREADY
+#define LWS_EINPROGRESS EINPROGRESS
+#define LWS_EINTR EINTR
+#define LWS_EISCONN EISCONN
+#define LWS_ENOTCONN ENOTCONN
+#define LWS_EWOULDBLOCK EWOULDBLOCK
+#define LWS_EADDRINUSE EADDRINUSE
+#define lws_set_blocking_send(wsi)
+#define LWS_SOCK_INVALID (-1)
+
+struct lws_context;
+
+struct lws *
+wsi_from_fd(const struct lws_context *context, int fd);
+
+int
+insert_wsi(const struct lws_context *context, struct lws *wsi);
+
+void
+delete_from_fd(const struct lws_context *context, int fd);
+
+#ifndef LWS_NO_FORK
+#ifdef LWS_HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+#endif
+
+#define compatible_close(x) close(x)
+#define lws_plat_socket_offset() (0)
+
+/*
+ * Mac OSX as well as iOS do not define the MSG_NOSIGNAL flag,
+ * but happily have something equivalent in the SO_NOSIGPIPE flag.
+ */
+#ifdef __APPLE__
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+
+/*
+ * Solaris 11.X only supports POSIX 2001, MSG_NOSIGNAL appears in
+ * POSIX 2008.
+ */
++#if defined(__sun) && !defined(MSG_NOSIGNAL)
+ #define MSG_NOSIGNAL 0
+#endif
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#endif
-#include "core/private.h"
+#include "private-lib-core.h"
+ int
+ _lws_plat_service_forced_tsi(struct lws_context *context, int tsi)
+ {
+ struct lws_context_per_thread *pt = &context->pt[tsi];
+ int m, n;
+
+ lws_service_flag_pending(context, tsi);
+
+ /* any socket with events to service? */
+ for (n = 0; n < (int)pt->fds_count; n++) {
+ if (!pt->fds[n].revents)
+ continue;
+
+ m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
+ if (m < 0)
+ return -1;
+ /* if something closed, retry this slot */
+ if (m)
+ n--;
+ }
+
+ lws_service_do_ripe_rxflow(pt);
+
+ return 0;
+ }
+
+
LWS_EXTERN int
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
--- /dev/null
- *cce = "socks gen msg fail";
+/*
+ * libwebsockets - lib/client/client.c
+ *
+ * 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 "private-lib-core.h"
+
+LWS_VISIBLE LWS_EXTERN void
+lws_client_http_body_pending(struct lws *wsi, int something_left_to_send)
+{
+ wsi->client_http_body_pending = !!something_left_to_send;
+}
+
+/*
+ * return self, or queued client wsi we are acting on behalf of
+ *
+ * That is the TAIL of the queue (new queue elements are added at the HEAD)
+ */
+
+struct lws *
+lws_client_wsi_effective(struct lws *wsi)
+{
+ struct lws_dll2 *tail = lws_dll2_get_tail(&wsi->dll2_cli_txn_queue_owner);
+
+ if (!wsi->transaction_from_pipeline_queue || !tail)
+ return wsi;
+
+ return lws_container_of(tail, struct lws, dll2_cli_txn_queue);
+}
+
+/*
+ * return self or the guy we are queued under
+ *
+ * REQUIRES VHOST LOCK HELD
+ */
+
+static struct lws *
+_lws_client_wsi_master(struct lws *wsi)
+{
+ struct lws_dll2_owner *o = wsi->dll2_cli_txn_queue.owner;
+
+ if (!o)
+ return wsi;
+
+ return lws_container_of(o, struct lws, dll2_cli_txn_queue_owner);
+}
+
+int
+lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd,
+ struct lws *wsi_conn)
+{
+ struct lws_context *context = wsi->context;
+ struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+ char *p = (char *)&pt->serv_buf[0];
+ struct lws *w;
+#if defined(LWS_WITH_TLS)
+ char ebuf[128];
+#endif
+ const char *cce = NULL;
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+ ssize_t len = 0;
+ unsigned char c;
+#endif
+ char *sb = p;
+ int n = 0;
+#if defined(LWS_WITH_SOCKS5)
+ int conn_mode = 0, pending_timeout = 0;
+#endif
+
+ if ((pollfd->revents & LWS_POLLOUT) &&
+ wsi->keepalive_active &&
+ wsi->dll2_cli_txn_queue_owner.head) {
+ struct lws *wfound = NULL;
+
+ lwsl_debug("%s: pollout HANDSHAKE2\n", __func__);
+
+ /*
+ * We have a transaction queued that wants to pipeline.
+ *
+ * We have to allow it to send headers strictly in the order
+ * that it was queued, ie, tail-first.
+ */
+ lws_vhost_lock(wsi->vhost);
+ lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
+ wsi->dll2_cli_txn_queue_owner.head) {
+ struct lws *w = lws_container_of(d, struct lws,
+ dll2_cli_txn_queue);
+
+ lwsl_debug("%s: %p states 0x%lx\n", __func__, w,
+ (unsigned long)w->wsistate);
+ if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2)
+ wfound = w;
+ } lws_end_foreach_dll_safe(d, d1);
+
+ if (wfound) {
+ /*
+ * pollfd has the master sockfd in it... we
+ * need to use that in HANDSHAKE2 to understand
+ * which wsi to actually write on
+ */
+ if (lws_client_socket_service(wfound, pollfd, wsi) < 0) {
+ /* closed */
+
+ lws_vhost_unlock(wsi->vhost);
+
+ return -1;
+ }
+
+ lws_callback_on_writable(wsi);
+ } else
+ lwsl_debug("%s: didn't find anything in txn q in HS2\n",
+ __func__);
+
+ lws_vhost_unlock(wsi->vhost);
+
+ return 0;
+ }
+
+ switch (lwsi_state(wsi)) {
+
+ case LRS_WAITING_CONNECT:
+
+ /*
+ * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+ * timeout protection set in client-handshake.c
+ */
+
+ if (!lws_client_connect_2(wsi)) {
+ /* closed */
+ lwsl_client("closed\n");
+ return -1;
+ }
+
+ /* either still pending connection, or changed mode */
+ return 0;
+
+#if defined(LWS_WITH_SOCKS5)
+ /* SOCKS Greeting Reply */
+ case LRS_WAITING_SOCKS_GREETING_REPLY:
+ case LRS_WAITING_SOCKS_AUTH_REPLY:
+ case LRS_WAITING_SOCKS_CONNECT_REPLY:
+
+ /* handle proxy hung up on us */
+
+ if (pollfd->revents & LWS_POLLHUP) {
+ lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+ cce = "socks conn dead";
+ goto bail3;
+ }
+
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+ if (n < 0) {
+ if (LWS_ERRNO == LWS_EAGAIN) {
+ lwsl_debug("SOCKS read EAGAIN, retrying\n");
+ return 0;
+ }
+ lwsl_err("ERROR reading from SOCKS socket\n");
+ cce = "socks recv fail";
+ goto bail3;
+ }
+
+ switch (lwsi_state(wsi)) {
+
+ case LRS_WAITING_SOCKS_GREETING_REPLY:
+ if (pt->serv_buf[0] != SOCKS_VERSION_5)
+ goto socks_reply_fail;
+
+ if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) {
+ lwsl_client("SOCKS GR: No Auth Method\n");
+ if (socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len))
+ goto socks_send_msg_fail;
+ conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
+ pending_timeout =
+ PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+ goto socks_send;
+ }
+
+ if (pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD) {
+ lwsl_client("SOCKS GR: User/Pw Method\n");
+ if (socks_generate_msg(wsi,
+ SOCKS_MSG_USERNAME_PASSWORD,
+ &len))
+ goto socks_send_msg_fail;
+ conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY;
+ pending_timeout =
+ PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
+ goto socks_send;
+ }
+ goto socks_reply_fail;
+
+ case LRS_WAITING_SOCKS_AUTH_REPLY:
+ if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 ||
+ pt->serv_buf[1] !=
+ SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
+ goto socks_reply_fail;
+
+ lwsl_client("SOCKS password OK, sending connect\n");
+ if (socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len)) {
+socks_send_msg_fail:
- if (strncmp(sb, "HTTP/1.0 200 ", 13) &&
- strncmp(sb, "HTTP/1.1 200 ", 13)) {
++ cce = "socks gen msg fail";
+ goto bail3;
+ }
+ conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY;
+ pending_timeout =
+ PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+socks_send:
+ n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
+ MSG_NOSIGNAL);
+ if (n < 0) {
+ lwsl_debug("ERROR writing to socks proxy\n");
+ cce = "socks write fail";
+ goto bail3;
+ }
+
+ lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
+ lwsi_set_state(wsi, conn_mode);
+ break;
+
+socks_reply_fail:
+ lwsl_notice("socks reply: v%d, err %d\n",
+ pt->serv_buf[0], pt->serv_buf[1]);
+ cce = "socks reply fail";
+ goto bail3;
+
+ case LRS_WAITING_SOCKS_CONNECT_REPLY:
+ if (pt->serv_buf[0] != SOCKS_VERSION_5 ||
+ pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS)
+ goto socks_reply_fail;
+
+ lwsl_client("socks connect OK\n");
+
+ /* free stash since we are done with it */
+ lws_client_stash_destroy(wsi);
+ if (lws_hdr_simple_create(wsi,
+ _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+ wsi->vhost->socks_proxy_address)) {
+ cce = "socks connect fail";
+ goto bail3;
+ }
+
+ wsi->c_port = wsi->vhost->socks_proxy_port;
+
+ /* clear his proxy connection timeout */
+ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+ goto start_ws_handshake;
+ default:
+ break;
+ }
+ break;
+#endif
+
+ case LRS_WAITING_PROXY_REPLY:
+
+ /* handle proxy hung up on us */
+
+ if (pollfd->revents & LWS_POLLHUP) {
+
+ lwsl_warn("Proxy connection %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+
+ cce = "proxy conn dead";
+ goto bail3;
+ }
+
+ n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+ if (n < 0) {
+ if (LWS_ERRNO == LWS_EAGAIN) {
+ lwsl_debug("Proxy read EAGAIN... retrying\n");
+ return 0;
+ }
+ lwsl_err("ERROR reading from proxy socket\n");
+ cce = "proxy read err";
+ goto bail3;
+ }
+
+ pt->serv_buf[13] = '\0';
++ if (n < 13 || (strncmp(sb, "HTTP/1.0 200 ", 13) &&
++ strncmp(sb, "HTTP/1.1 200 ", 13))) {
+ lwsl_err("%s: ERROR proxy did not reply with h1\n",
+ __func__);
++ /* lwsl_hexdump_notice(sb, n); */
+ cce = "proxy not h1";
+ goto bail3;
+ }
+
++ lwsl_info("%s: proxy connection extablished\n", __func__);
++
+ /* clear his proxy connection timeout */
+
+ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+ /* fallthru */
+
+ case LRS_H1C_ISSUE_HANDSHAKE:
+
+ /*
+ * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
+ * timeout protection set in client-handshake.c
+ *
+ * take care of our lws_callback_on_writable
+ * happening at a time when there's no real connection yet
+ */
+#if defined(LWS_WITH_SOCKS5)
+start_ws_handshake:
+#endif
+ if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
+ return -1;
+
+#if defined(LWS_WITH_TLS)
+ /* we can retry this... just cook the SSL BIO the first time */
+
+ if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !wsi->tls.ssl &&
+ lws_ssl_client_bio_create(wsi) < 0) {
+ cce = "bio_create failed";
+ goto bail3;
+ }
+
+ if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+ n = lws_ssl_client_connect1(wsi);
+ if (!n)
+ return 0;
+ if (n < 0) {
+ cce = "lws_ssl_client_connect1 failed";
+ goto bail3;
+ }
+ } else
+ wsi->tls.ssl = NULL;
+
+ /* fallthru */
+
+ case LRS_WAITING_SSL:
+
+ if (wsi->tls.use_ssl & LCCSCF_USE_SSL) {
+ n = lws_ssl_client_connect2(wsi, ebuf, sizeof(ebuf));
+ if (!n)
+ return 0;
+ if (n < 0) {
+ cce = ebuf;
+ goto bail3;
+ }
+ } else
+ wsi->tls.ssl = NULL;
+#endif
+#if defined (LWS_WITH_HTTP2)
+ if (wsi->client_h2_alpn) {
+ /*
+ * We connected to the server and set up tls, and
+ * negotiated "h2".
+ *
+ * So this is it, we are an h2 master client connection
+ * now, not an h1 client connection.
+ */
+#if defined (LWS_WITH_TLS)
+ lws_tls_server_conn_alpn(wsi);
+#endif
+
+ /* send the H2 preface to legitimize the connection */
+ if (lws_h2_issue_preface(wsi)) {
+ cce = "error sending h2 preface";
+ goto bail3;
+ }
+
+ break;
+ }
+#endif
+ lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2);
+ lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
+ context->timeout_secs);
+
+ /* fallthru */
+
+ case LRS_H1C_ISSUE_HANDSHAKE2:
+ p = lws_generate_client_handshake(wsi, p);
+ if (p == NULL) {
+ if (wsi->role_ops == &role_ops_raw_skt ||
+ wsi->role_ops == &role_ops_raw_file)
+ return 0;
+
+ lwsl_err("Failed to generate handshake for client\n");
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+ "chs");
+ return 0;
+ }
+
+ /* send our request to the server */
+ lws_latency_pre(context, wsi);
+
+ w = _lws_client_wsi_master(wsi);
+ lwsl_info("%s: HANDSHAKE2: %p: sending headers on %p "
+ "(wsistate 0x%lx 0x%lx), w sock %d, wsi sock %d\n",
+ __func__, wsi, w, (unsigned long)wsi->wsistate,
+ (unsigned long)w->wsistate, w->desc.sockfd,
+ wsi->desc.sockfd);
+
+ n = lws_ssl_capable_write(w, (unsigned char *)sb, (int)(p - sb));
+ lws_latency(context, wsi, "send lws_issue_raw", n,
+ n == p - sb);
+ switch (n) {
+ case LWS_SSL_CAPABLE_ERROR:
+ lwsl_debug("ERROR writing to client socket\n");
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
+ "cws");
+ return 0;
+ case LWS_SSL_CAPABLE_MORE_SERVICE:
+ lws_callback_on_writable(wsi);
+ break;
+ }
+
+ if (wsi->client_http_body_pending) {
+ lwsl_debug("body pending\n");
+ lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY);
+ lws_set_timeout(wsi,
+ PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
+ context->timeout_secs);
+#if defined(LWS_WITH_HTTP_PROXY)
+ if (wsi->http.proxy_clientside)
+ lws_callback_on_writable(wsi);
+#endif
+ /* user code must ask for writable callback */
+ break;
+ }
+
+ lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+ wsi->hdr_parsing_completed = 0;
+
+ if (lwsi_state(w) == LRS_IDLING) {
+ lwsi_set_state(w, LRS_WAITING_SERVER_REPLY);
+ w->hdr_parsing_completed = 0;
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+ w->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+ w->http.ah->lextable_pos = 0;
+#if defined(LWS_WITH_CUSTOM_HEADERS)
+ w->http.ah->unk_pos = 0;
+#endif
+ /* If we're (re)starting on hdr, need other implied init */
+ wsi->http.ah->ues = URIES_IDLE;
+#endif
+ }
+
+ lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+ wsi->context->timeout_secs);
+
+ lws_callback_on_writable(w);
+
+ goto client_http_body_sent;
+
+ case LRS_ISSUE_HTTP_BODY:
+#if defined(LWS_WITH_HTTP_PROXY)
+ if (wsi->http.proxy_clientside) {
+ lws_callback_on_writable(wsi);
+ break;
+ }
+#endif
+ if (wsi->client_http_body_pending) {
+ //lws_set_timeout(wsi,
+ // PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
+ // context->timeout_secs);
+ /* user code must ask for writable callback */
+ break;
+ }
+client_http_body_sent:
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+ /* prepare ourselves to do the parsing */
+ wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+ wsi->http.ah->lextable_pos = 0;
+#if defined(LWS_WITH_CUSTOM_HEADERS)
+ wsi->http.ah->unk_pos = 0;
+#endif
+#endif
+ lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+ lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+ context->timeout_secs);
+ break;
+
+ case LRS_WAITING_SERVER_REPLY:
+ /*
+ * handle server hanging up on us...
+ * but if there is POLLIN waiting, handle that first
+ */
+ if ((pollfd->revents & (LWS_POLLIN | LWS_POLLHUP)) ==
+ LWS_POLLHUP) {
+
+ lwsl_debug("Server connection %p (fd=%d) dead\n",
+ (void *)wsi, pollfd->fd);
+ cce = "Peer hung up";
+ goto bail3;
+ }
+
+ if (!(pollfd->revents & LWS_POLLIN))
+ break;
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+ /* interpret the server response
+ *
+ * HTTP/1.1 101 Switching Protocols
+ * Upgrade: websocket
+ * Connection: Upgrade
+ * Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
+ * Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
+ * Sec-WebSocket-Protocol: chat
+ *
+ * we have to take some care here to only take from the
+ * socket bytewise. The browser may (and has been seen to
+ * in the case that onopen() performs websocket traffic)
+ * coalesce both handshake response and websocket traffic
+ * in one packet, since at that point the connection is
+ * definitively ready from browser pov.
+ */
+ len = 1;
+ while (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE &&
+ len > 0) {
+ int plen = 1;
+
+ n = lws_ssl_capable_read(wsi, &c, 1);
+ lws_latency(context, wsi, "send lws_issue_raw", n,
+ n == 1);
+ switch (n) {
+ case 0:
+ case LWS_SSL_CAPABLE_ERROR:
+ cce = "read failed";
+ goto bail3;
+ case LWS_SSL_CAPABLE_MORE_SERVICE:
+ return 0;
+ }
+
+ if (lws_parse(wsi, &c, &plen)) {
+ lwsl_warn("problems parsing header\n");
+ cce = "problems parsing header";
+ goto bail3;
+ }
+ }
+
+ /*
+ * hs may also be coming in multiple packets, there is a 5-sec
+ * libwebsocket timeout still active here too, so if parsing did
+ * not complete just wait for next packet coming in this state
+ */
+ if (wsi->http.ah->parser_state != WSI_PARSING_COMPLETE)
+ break;
+
+#endif
+
+ /*
+ * otherwise deal with the handshake. If there's any
+ * packet traffic already arrived we'll trigger poll() again
+ * right away and deal with it that way
+ */
+ return lws_client_interpret_server_handshake(wsi);
+
+bail3:
+ lwsl_info("closing conn at LWS_CONNMODE...SERVER_REPLY\n");
+ if (cce)
+ lwsl_info("reason: %s\n", cce);
+ lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce));
+
+ lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3");
+ return -1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+
+int LWS_WARN_UNUSED_RESULT
+lws_http_transaction_completed_client(struct lws *wsi)
+{
+ struct lws *wsi_eff = lws_client_wsi_effective(wsi);
+
+ lwsl_info("%s: wsi: %p, wsi_eff: %p (%s)\n", __func__, wsi, wsi_eff,
+ wsi_eff->protocol->name);
+
+ if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff,
+ LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
+ wsi_eff->user_space, NULL, 0)) {
+ lwsl_debug("%s: Completed call returned nonzero (role 0x%lx)\n",
+ __func__, (unsigned long)lwsi_role(wsi_eff));
+ return -1;
+ }
+
+ /*
+ * Are we constitutionally capable of having a queue, ie, we are on
+ * the "active client connections" list?
+ *
+ * If not, that's it for us.
+ */
+
+ if (lws_dll2_is_detached(&wsi->dll_cli_active_conns))
+ return -1;
+
+ /* if this was a queued guy, close him and remove from queue */
+
+ if (wsi->transaction_from_pipeline_queue) {
+ lwsl_debug("closing queued wsi %p\n", wsi_eff);
+ /* so the close doesn't trigger a CCE */
+ wsi_eff->already_did_cce = 1;
+ __lws_close_free_wsi(wsi_eff,
+ LWS_CLOSE_STATUS_CLIENT_TRANSACTION_DONE,
+ "queued client done");
+ }
+
+ _lws_header_table_reset(wsi->http.ah);
+
+ /* after the first one, they can only be coming from the queue */
+ wsi->transaction_from_pipeline_queue = 1;
+
+ wsi->http.rx_content_length = 0;
+ wsi->hdr_parsing_completed = 0;
+
+ /* is there a new tail after removing that one? */
+ wsi_eff = lws_client_wsi_effective(wsi);
+
+ /*
+ * Do we have something pipelined waiting?
+ * it's OK if he hasn't managed to send his headers yet... he's next
+ * in line to do that...
+ */
+ if (wsi_eff == wsi) {
+ /*
+ * Nothing pipelined... we should hang around a bit
+ * in case something turns up...
+ */
+ lwsl_info("%s: nothing pipelined waiting\n", __func__);
+ lwsi_set_state(wsi, LRS_IDLING);
+
+ lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_CONN_IDLE, 5);
+
+ return 0;
+ }
+
+ /*
+ * H1: we can serialize the queued guys into the same ah
+ * H2: everybody needs their own ah until their own STREAM_END
+ */
+
+ /* otherwise set ourselves up ready to go again */
+ lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
+
+ wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
+ wsi->http.ah->lextable_pos = 0;
+#if defined(LWS_WITH_CUSTOM_HEADERS)
+ wsi->http.ah->unk_pos = 0;
+#endif
+
+ lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
+ wsi->context->timeout_secs);
+
+ /* If we're (re)starting on headers, need other implied init */
+ wsi->http.ah->ues = URIES_IDLE;
+
+ lwsl_info("%s: %p: new queued transaction as %p\n", __func__, wsi,
+ wsi_eff);
+ lws_callback_on_writable(wsi);
+
+ return 0;
+}
+
+LWS_VISIBLE LWS_EXTERN unsigned int
+lws_http_client_http_response(struct lws *_wsi)
+{
+ struct lws *wsi;
+ unsigned int resp;
+
+ if (_wsi->http.ah && _wsi->http.ah->http_response)
+ return _wsi->http.ah->http_response;
+
+ lws_vhost_lock(_wsi->vhost);
+ wsi = _lws_client_wsi_master(_wsi);
+ resp = wsi->http.ah->http_response;
+ lws_vhost_unlock(_wsi->vhost);
+
+ return resp;
+}
+#endif
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+int
+lws_client_interpret_server_handshake(struct lws *wsi)
+{
+ int n, port = 0, ssl = 0;
+ int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
+ const char *prot, *ads = NULL, *path, *cce = NULL;
+ struct allocated_headers *ah;
+ struct lws *w = lws_client_wsi_effective(wsi);
+ char *p, *q;
+ char new_path[300];
+
+ lws_client_stash_destroy(wsi);
+
+ ah = wsi->http.ah;
+ if (!wsi->do_ws) {
+ /* we are being an http client...
+ */
+#if defined(LWS_ROLE_H2)
+ if (wsi->client_h2_alpn || wsi->client_h2_substream) {
+ lwsl_debug("%s: %p: transitioning to h2 client\n",
+ __func__, wsi);
+ lws_role_transition(wsi, LWSIFR_CLIENT,
+ LRS_ESTABLISHED, &role_ops_h2);
+ } else
+#endif
+ {
+#if defined(LWS_ROLE_H1)
+ {
+ lwsl_debug("%s: %p: transitioning to h1 client\n",
+ __func__, wsi);
+ lws_role_transition(wsi, LWSIFR_CLIENT,
+ LRS_ESTABLISHED, &role_ops_h1);
+ }
+#else
+ return -1;
+#endif
+ }
+
+ wsi->http.ah = ah;
+ ah->http_response = 0;
+ }
+
+ /*
+ * well, what the server sent looked reasonable for syntax.
+ * Now let's confirm it sent all the necessary headers
+ *
+ * http (non-ws) client will expect something like this
+ *
+ * HTTP/1.0.200
+ * server:.libwebsockets
+ * content-type:.text/html
+ * content-length:.17703
+ * set-cookie:.test=LWS_1456736240_336776_COOKIE;Max-Age=360000
+ */
+
+ wsi->http.conn_type = HTTP_CONNECTION_KEEP_ALIVE;
+ if (!wsi->client_h2_substream) {
+ p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
+ if (wsi->do_ws && !p) {
+ lwsl_info("no URI\n");
+ cce = "HS: URI missing";
+ goto bail3;
+ }
+ if (!p) {
+ p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP1_0);
+ wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
+ }
+ if (!p) {
+ cce = "HS: URI missing";
+ lwsl_info("no URI\n");
+ goto bail3;
+ }
+ } else {
+ p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_STATUS);
+ if (!p) {
+ cce = "HS: :status missing";
+ lwsl_info("no status\n");
+ goto bail3;
+ }
+ }
+ n = atoi(p);
+ if (ah)
+ ah->http_response = n;
+
+ if (
+#if defined(LWS_WITH_HTTP_PROXY)
+ !wsi->http.proxy_clientside &&
+#endif
+ (n == 301 || n == 302 || n == 303 || n == 307 || n == 308)) {
+ p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
+ if (!p) {
+ cce = "HS: Redirect code but no Location";
+ goto bail3;
+ }
+
+ /* Relative reference absolute path */
+ if (p[0] == '/') {
+#if defined(LWS_WITH_TLS)
+ ssl = wsi->tls.use_ssl & LCCSCF_USE_SSL;
+#endif
+ ads = lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+ port = wsi->c_port;
+ /* +1 as lws_client_reset expects leading / omitted */
+ path = p + 1;
+ }
+ /* Absolute (Full) URI */
+ else if (strchr(p, ':')) {
+ if (lws_parse_uri(p, &prot, &ads, &port, &path)) {
+ cce = "HS: URI did not parse";
+ goto bail3;
+ }
+
+ if (!strcmp(prot, "wss") || !strcmp(prot, "https"))
+ ssl = 1;
+ }
+ /* Relative reference relative path */
+ else {
+ /* This doesn't try to calculate an absolute path,
+ * that will be left to the server */
+#if defined(LWS_WITH_TLS)
+ ssl = wsi->tls.use_ssl & LCCSCF_USE_SSL;
+#endif
+ ads = lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_PEER_ADDRESS);
+ port = wsi->c_port;
+ /* +1 as lws_client_reset expects leading / omitted */
+ path = new_path + 1;
+ if (lws_hdr_simple_ptr(wsi,_WSI_TOKEN_CLIENT_URI))
+ lws_strncpy(new_path, lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_URI), sizeof(new_path));
+ else {
+ new_path[0] = '/';
+ new_path[1] = '\0';
+ }
+ q = strrchr(new_path, '/');
+ if (q)
+ lws_strncpy(q + 1, p, sizeof(new_path) -
+ (q - new_path) - 1);
+ else
+ path = p;
+ }
+
+#if defined(LWS_WITH_TLS)
+ if ((wsi->tls.use_ssl & LCCSCF_USE_SSL) && !ssl) {
+ cce = "HS: Redirect attempted SSL downgrade";
+ goto bail3;
+ }
+#endif
+
+ if (!ads) /* make coverity happy */ {
+ cce = "no ads";
+ goto bail3;
+ }
+
+ if (!lws_client_reset(&wsi, ssl, ads, port, path, ads)) {
+ /* there are two ways to fail out with NULL return...
+ * simple, early problem where the wsi is intact, or
+ * we went through with the reconnect attempt and the
+ * wsi is already closed. In the latter case, the wsi
+ * has beet set to NULL additionally.
+ */
+ lwsl_err("Redirect failed\n");
+ cce = "HS: Redirect failed";
+ if (wsi)
+ goto bail3;
+
+ return 1;
+ }
+ return 0;
+ }
+
+ if (!wsi->do_ws) {
+
+ /* if h1 KA is allowed, enable the queued pipeline guys */
+
+ if (!wsi->client_h2_alpn && !wsi->client_h2_substream &&
+ w == wsi) { /* ie, coming to this for the first time */
+ if (wsi->http.conn_type == HTTP_CONNECTION_KEEP_ALIVE)
+ wsi->keepalive_active = 1;
+ else {
+ /*
+ * Ugh... now the main http connection has seen
+ * both sides, we learn the server doesn't
+ * support keepalive.
+ *
+ * That means any guys queued on us are going
+ * to have to be restarted from connect2 with
+ * their own connections.
+ */
+
+ /*
+ * stick around telling any new guys they can't
+ * pipeline to this server
+ */
+ wsi->keepalive_rejected = 1;
+
+ lws_vhost_lock(wsi->vhost);
+ lws_start_foreach_dll_safe(struct lws_dll2 *,
+ d, d1,
+ wsi->dll2_cli_txn_queue_owner.head) {
+ struct lws *ww = lws_container_of(d,
+ struct lws,
+ dll2_cli_txn_queue);
+
+ /* remove him from our queue */
+ lws_dll2_remove(&ww->dll2_cli_txn_queue);
+ /* give up on pipelining */
+ ww->client_pipeline = 0;
+
+ /* go back to "trying to connect" state */
+ lws_role_transition(ww, LWSIFR_CLIENT,
+ LRS_UNCONNECTED,
+#if defined(LWS_ROLE_H1)
+ &role_ops_h1);
+#else
+#if defined (LWS_ROLE_H2)
+ &role_ops_h2);
+#else
+ &role_ops_raw);
+#endif
+#endif
+ ww->user_space = NULL;
+ } lws_end_foreach_dll_safe(d, d1);
+ lws_vhost_unlock(wsi->vhost);
+ }
+ }
+
+#ifdef LWS_WITH_HTTP_PROXY
+ wsi->http.perform_rewrite = 0;
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
+ if (!strncmp(lws_hdr_simple_ptr(wsi,
+ WSI_TOKEN_HTTP_CONTENT_TYPE),
+ "text/html", 9))
+ wsi->http.perform_rewrite = 0;
+ }
+#endif
+
+ /* allocate the per-connection user memory (if any) */
+ if (lws_ensure_user_space(wsi)) {
+ lwsl_err("Problem allocating wsi user mem\n");
+ cce = "HS: OOM";
+ goto bail2;
+ }
+
+ /* he may choose to send us stuff in chunked transfer-coding */
+ wsi->chunked = 0;
+ wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
+ if (lws_hdr_total_length(wsi,
+ WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
+ wsi->chunked = !strcmp(lws_hdr_simple_ptr(wsi,
+ WSI_TOKEN_HTTP_TRANSFER_ENCODING),
+ "chunked");
+ /* first thing is hex, after payload there is crlf */
+ wsi->chunk_parser = ELCP_HEX;
+ }
+
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
+ wsi->http.rx_content_length =
+ atoll(lws_hdr_simple_ptr(wsi,
+ WSI_TOKEN_HTTP_CONTENT_LENGTH));
+ lwsl_info("%s: incoming content length %llu\n",
+ __func__, (unsigned long long)
+ wsi->http.rx_content_length);
+ wsi->http.rx_content_remain =
+ wsi->http.rx_content_length;
+ } else /* can't do 1.1 without a content length or chunked */
+ if (!wsi->chunked)
+ wsi->http.conn_type = HTTP_CONNECTION_CLOSE;
+
+ /*
+ * we seem to be good to go, give client last chance to check
+ * headers and OK it
+ */
+ if (w->protocol->callback(w,
+ LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
+ w->user_space, NULL, 0)) {
+
+ cce = "HS: disallowed by client filter";
+ goto bail2;
+ }
+
+ /* clear his proxy connection timeout */
+ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+ wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
+
+ /* call him back to inform him he is up */
+ if (w->protocol->callback(w,
+ LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP,
+ w->user_space, NULL, 0)) {
+ cce = "HS: disallowed at ESTABLISHED";
+ goto bail3;
+ }
+
+ /*
+ * for pipelining, master needs to keep his ah... guys who
+ * queued on him can drop it now though.
+ */
+
+ if (w != wsi)
+ /* free up parsing allocations for queued guy */
+ lws_header_table_detach(w, 0);
+
+ lwsl_info("%s: client connection up\n", __func__);
+
+ /*
+ * Did we get a response from the server with an explicit
+ * content-length of zero? If so, this transaction is already
+ * completed at the end of the header processing...
+ */
+ if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) &&
+ !wsi->http.rx_content_length)
+ return !!lws_http_transaction_completed_client(wsi);
+
+ return 0;
+ }
+
+#if defined(LWS_ROLE_WS)
+ switch (lws_client_ws_upgrade(wsi, &cce)) {
+ case 2:
+ goto bail2;
+ case 3:
+ goto bail3;
+ }
+
+ return 0;
+#endif
+
+bail3:
+ close_reason = LWS_CLOSE_STATUS_NOSTATUS;
+
+bail2:
+ if (wsi->protocol) {
+ n = 0;
+ if (cce)
+ n = (int)strlen(cce);
+
+ lws_inform_client_conn_fail(wsi, (void *)cce, (unsigned int)n);
+ }
+
+ lwsl_info("closing connection (prot %s) "
+ "due to bail2 connection error: %s\n", wsi->protocol ?
+ wsi->protocol->name : "unknown", cce);
+
+ /* closing will free up his parsing allocations */
+ lws_close_free_wsi(wsi, close_reason, "c hs interp");
+
+ return 1;
+}
+#endif
+
+char *
+lws_generate_client_handshake(struct lws *wsi, char *pkt)
+{
+ char *p = pkt;
+ const char *meth;
+ const char *pp = lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
+
+ meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD);
+ if (!meth) {
+ meth = "GET";
+ wsi->do_ws = 1;
+ } else {
+ wsi->do_ws = 0;
+ }
+
+ if (!strcmp(meth, "RAW")) {
+ lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+ lwsl_notice("client transition to raw\n");
+
+ if (pp) {
+ const struct lws_protocols *pr;
+
+ pr = lws_vhost_name_to_protocol(wsi->vhost, pp);
+
+ if (!pr) {
+ lwsl_err("protocol %s not enabled on vhost\n",
+ pp);
+ return NULL;
+ }
+
+ lws_bind_protocol(wsi, pr, __func__);
+ }
+
+ if ((wsi->protocol->callback)(wsi, LWS_CALLBACK_RAW_ADOPT,
+ wsi->user_space, NULL, 0))
+ return NULL;
+
+ lws_role_transition(wsi, LWSIFR_CLIENT, LRS_ESTABLISHED,
+ &role_ops_raw_skt);
+ lws_header_table_detach(wsi, 1);
+
+ return NULL;
+ }
+
+ /*
+ * 04 example client handshake
+ *
+ * GET /chat HTTP/1.1
+ * Host: server.example.com
+ * Upgrade: websocket
+ * Connection: Upgrade
+ * Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
+ * Sec-WebSocket-Origin: http://example.com
+ * Sec-WebSocket-Protocol: chat, superchat
+ * Sec-WebSocket-Version: 4
+ */
+
+ p += lws_snprintf(p, 2048, "%s %s HTTP/1.1\x0d\x0a", meth,
+ lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
+
+ p += lws_snprintf(p, 64, "Pragma: no-cache\x0d\x0a"
+ "Cache-Control: no-cache\x0d\x0a");
+
+ p += lws_snprintf(p, 128, "Host: %s\x0d\x0a",
+ lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
+
+ if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) {
+ if (lws_check_opt(wsi->context->options,
+ LWS_SERVER_OPTION_JUST_USE_RAW_ORIGIN))
+ p += lws_snprintf(p, 128, "Origin: %s\x0d\x0a",
+ lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_ORIGIN));
+ else
+ p += lws_snprintf(p, 128, "Origin: http://%s\x0d\x0a",
+ lws_hdr_simple_ptr(wsi,
+ _WSI_TOKEN_CLIENT_ORIGIN));
+ }
+
+#if defined(LWS_WITH_HTTP_PROXY)
+ if (wsi->parent &&
+ lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
+ p += lws_snprintf(p, 128, "Content-Length: %s\x0d\x0a",
+ lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH));
+ if (atoi(lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)))
+ wsi->client_http_body_pending = 1;
+ }
+ if (wsi->parent &&
+ lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION)) {
+ p += lws_snprintf(p, 128, "Authorization: %s\x0d\x0a",
+ lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_AUTHORIZATION));
+ }
+ if (wsi->parent &&
+ lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
+ p += lws_snprintf(p, 128, "Content-Type: %s\x0d\x0a",
+ lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE));
+ }
+#endif
+
+#if defined(LWS_ROLE_WS)
+ if (wsi->do_ws) {
+ const char *conn1 = "";
+ // if (!wsi->client_pipeline)
+ // conn1 = "close, ";
+ p = lws_generate_client_ws_handshake(wsi, p, conn1);
+ } else
+#endif
+ {
+ if (!wsi->client_pipeline)
+ p += lws_snprintf(p, 64, "connection: close\x0d\x0a");
+ }
+
+ /* give userland a chance to append, eg, cookies */
+
+ if (wsi->protocol->callback(wsi,
+ LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
+ wsi->user_space, &p,
+ (pkt + wsi->context->pt_serv_buf_size) - p - 12))
+ return NULL;
+
+ p += lws_snprintf(p, 4, "\x0d\x0a");
+
+ // puts(pkt);
+
+ return p;
+}
+
+#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
+
+LWS_VISIBLE int
+lws_http_client_read(struct lws *wsi, char **buf, int *len)
+{
+ int rlen, n;
+
+ rlen = lws_ssl_capable_read(wsi, (unsigned char *)*buf, *len);
+ *len = 0;
+
+ // lwsl_notice("%s: rlen %d\n", __func__, rlen);
+
+ /* allow the source to signal he has data again next time */
+ if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
+ return -1;
+
+ if (rlen == LWS_SSL_CAPABLE_ERROR) {
+ lwsl_debug("%s: SSL capable error\n", __func__);
+ return -1;
+ }
+
+ if (rlen <= 0)
+ return 0;
+
+ *len = rlen;
+ wsi->client_rx_avail = 0;
+
+ /*
+ * server may insist on transfer-encoding: chunked,
+ * so http client must deal with it
+ */
+spin_chunks:
+ while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) {
+ switch (wsi->chunk_parser) {
+ case ELCP_HEX:
+ if ((*buf)[0] == '\x0d') {
+ wsi->chunk_parser = ELCP_CR;
+ break;
+ }
+ n = char_to_hex((*buf)[0]);
+ if (n < 0) {
+ lwsl_info("%s: chunking failure\n", __func__);
+ return -1;
+ }
+ wsi->chunk_remaining <<= 4;
+ wsi->chunk_remaining |= n;
+ break;
+ case ELCP_CR:
+ if ((*buf)[0] != '\x0a') {
+ lwsl_info("%s: chunking failure\n", __func__);
+ return -1;
+ }
+ wsi->chunk_parser = ELCP_CONTENT;
+ lwsl_info("chunk %d\n", wsi->chunk_remaining);
+ if (wsi->chunk_remaining)
+ break;
+ lwsl_info("final chunk\n");
+ goto completed;
+
+ case ELCP_CONTENT:
+ break;
+
+ case ELCP_POST_CR:
+ if ((*buf)[0] != '\x0d') {
+ lwsl_info("%s: chunking failure\n", __func__);
+
+ return -1;
+ }
+
+ wsi->chunk_parser = ELCP_POST_LF;
+ break;
+
+ case ELCP_POST_LF:
+ if ((*buf)[0] != '\x0a') {
+ lwsl_info("%s: chunking failure\n", __func__);
+
+ return -1;
+ }
+
+ wsi->chunk_parser = ELCP_HEX;
+ wsi->chunk_remaining = 0;
+ break;
+ }
+ (*buf)++;
+ (*len)--;
+ }
+
+ if (wsi->chunked && !wsi->chunk_remaining)
+ return 0;
+
+ if (wsi->http.rx_content_remain &&
+ wsi->http.rx_content_remain < (unsigned int)*len)
+ n = (int)wsi->http.rx_content_remain;
+ else
+ n = *len;
+
+ if (wsi->chunked && wsi->chunk_remaining &&
+ wsi->chunk_remaining < n)
+ n = wsi->chunk_remaining;
+
+#if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_WITH_HUBBUB)
+ /* hubbub */
+ if (wsi->http.perform_rewrite)
+ lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n);
+ else
+#endif
+ {
+ struct lws *wsi_eff = lws_client_wsi_effective(wsi);
+
+ if (
+#if defined(LWS_WITH_HTTP_PROXY)
+ !wsi_eff->protocol_bind_balance ==
+ !!wsi_eff->http.proxy_clientside &&
+#else
+ !!wsi_eff->protocol_bind_balance &&
+#endif
+ user_callback_handle_rxflow(wsi_eff->protocol->callback,
+ wsi_eff, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ,
+ wsi_eff->user_space, *buf, n)) {
+ lwsl_info("%s: RECEIVE_CLIENT_HTTP_READ returned -1\n",
+ __func__);
+
+ return -1;
+ }
+ }
+
+ if (wsi->chunked && wsi->chunk_remaining) {
+ (*buf) += n;
+ wsi->chunk_remaining -= n;
+ *len -= n;
+ }
+
+ if (wsi->chunked && !wsi->chunk_remaining)
+ wsi->chunk_parser = ELCP_POST_CR;
+
+ if (wsi->chunked && *len)
+ goto spin_chunks;
+
+ if (wsi->chunked)
+ return 0;
+
+ /* if we know the content length, decrement the content remaining */
+ if (wsi->http.rx_content_length > 0)
+ wsi->http.rx_content_remain -= n;
+
+ // lwsl_notice("rx_content_remain %lld, rx_content_length %lld\n",
+ // wsi->http.rx_content_remain, wsi->http.rx_content_length);
+
+ if (wsi->http.rx_content_remain || !wsi->http.rx_content_length)
+ return 0;
+
+completed:
+
+ if (lws_http_transaction_completed_client(wsi)) {
+ lwsl_notice("%s: transaction completed says -1\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif
--- /dev/null
- typedef struct lws_sorted_usec_list lws_sorted_usec_list_t;
-
+/*
+ * 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
+ *
+ * This is included from private-lib-core.h if either H1 or H2 roles are
+ * enabled
+ */
+
+#if defined(LWS_WITH_HUBBUB)
+ #include <hubbub/hubbub.h>
+ #include <hubbub/parser.h>
+ #endif
+
+#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
+#include "private-lib-roles-http-compression.h"
+#endif
+
+#define lwsi_role_http(wsi) (lwsi_role_h1(wsi) || lwsi_role_h2(wsi))
+
+enum http_version {
+ HTTP_VERSION_1_0,
+ HTTP_VERSION_1_1,
+ HTTP_VERSION_2
+};
+
+enum http_conn_type {
+ HTTP_CONNECTION_CLOSE,
+ HTTP_CONNECTION_KEEP_ALIVE
+};
+
+/*
+ * This is totally opaque to code using the library. It's exported as a
+ * forward-reference pointer-only declaration; the user can use the pointer with
+ * other APIs to get information out of it.
+ */
+
+#if defined(LWS_WITH_ESP32)
+typedef uint16_t ah_data_idx_t;
+#else
+typedef uint32_t ah_data_idx_t;
+#endif
+
+struct lws_fragments {
+ ah_data_idx_t offset;
+ uint16_t len;
+ uint8_t nfrag; /* which ah->frag[] continues this content, or 0 */
+ uint8_t flags; /* only http2 cares */
+};
+
+#if defined(LWS_WITH_RANGES)
+enum range_states {
+ LWSRS_NO_ACTIVE_RANGE,
+ LWSRS_BYTES_EQ,
+ LWSRS_FIRST,
+ LWSRS_STARTING,
+ LWSRS_ENDING,
+ LWSRS_COMPLETED,
+ LWSRS_SYNTAX,
+};
+
+struct lws_range_parsing {
+ unsigned long long start, end, extent, agg, budget;
+ const char buf[128];
+ int pos;
+ enum range_states state;
+ char start_valid, end_valid, ctr, count_ranges, did_try, inside, send_ctr;
+};
+
+int
+lws_ranges_init(struct lws *wsi, struct lws_range_parsing *rp,
+ unsigned long long extent);
+int
+lws_ranges_next(struct lws_range_parsing *rp);
+void
+lws_ranges_reset(struct lws_range_parsing *rp);
+#endif
+
+/*
+ * these are assigned from a pool held in the context.
+ * Both client and server mode uses them for http header analysis
+ */
+
+struct allocated_headers {
+ struct allocated_headers *next; /* linked list */
+ struct lws *wsi; /* owner */
+ char *data; /* prepared by context init to point to dedicated storage */
+ ah_data_idx_t data_length;
+ /*
+ * the randomly ordered fragments, indexed by frag_index and
+ * lws_fragments->nfrag for continuation.
+ */
+ struct lws_fragments frags[WSI_TOKEN_COUNT];
+ time_t assigned;
+ /*
+ * for each recognized token, frag_index says which frag[] his data
+ * starts in (0 means the token did not appear)
+ * the actual header data gets dumped as it comes in, into data[]
+ */
+ uint8_t frag_index[WSI_TOKEN_COUNT];
+
+#ifndef LWS_NO_CLIENT
+ char initial_handshake_hash_base64[30];
+#endif
+ int hdr_token_idx;
+
+ ah_data_idx_t pos;
+ ah_data_idx_t http_response;
+ ah_data_idx_t current_token_limit;
+
+#if defined(LWS_WITH_CUSTOM_HEADERS)
+ ah_data_idx_t unk_pos; /* to undo speculative unknown header */
+ ah_data_idx_t unk_value_pos;
+
+ ah_data_idx_t unk_ll_head;
+ ah_data_idx_t unk_ll_tail;
+#endif
+
+ int16_t lextable_pos;
+
+ uint8_t in_use;
+ uint8_t nfrag;
+ char /*enum uri_path_states */ ups;
+ char /*enum uri_esc_states */ ues;
+
+ char esc_stash;
+ char post_literal_equal;
+ uint8_t /* enum lws_token_indexes */ parser_state;
+};
+
+
+
+#if defined(LWS_WITH_HUBBUB)
+struct lws_rewrite {
+ hubbub_parser *parser;
+ hubbub_parser_optparams params;
+ const char *from, *to;
+ int from_len, to_len;
+ unsigned char *p, *end;
+ struct lws *wsi;
+};
+static LWS_INLINE int hstrcmp(hubbub_string *s, const char *p, int len)
+{
+ if ((int)s->len != len)
+ return 1;
+
+ return strncmp((const char *)s->ptr, p, len);
+}
+typedef hubbub_error (*hubbub_callback_t)(const hubbub_token *token, void *pw);
+LWS_EXTERN struct lws_rewrite *
+lws_rewrite_create(struct lws *wsi, hubbub_callback_t cb, const char *from, const char *to);
+LWS_EXTERN void
+lws_rewrite_destroy(struct lws_rewrite *r);
+LWS_EXTERN int
+lws_rewrite_parse(struct lws_rewrite *r, const unsigned char *in, int in_len);
+#endif
+
+struct lws_pt_role_http {
+ struct allocated_headers *ah_list;
+ struct lws *ah_wait_list;
+#ifdef LWS_WITH_CGI
+ struct lws_cgi *cgi_list;
+#endif
+ int ah_wait_list_length;
+ uint32_t ah_pool_length;
+
+ int ah_count_in_use;
+};
+
+struct lws_peer_role_http {
+ uint32_t count_ah;
+ uint32_t total_ah;
+};
+
+struct lws_vhost_role_http {
+ char http_proxy_address[128];
+ const struct lws_http_mount *mount_list;
+ const char *error_document_404;
+ unsigned int http_proxy_port;
+};
+
+#ifdef LWS_WITH_ACCESS_LOG
+struct lws_access_log {
+ char *header_log;
+ char *user_agent;
+ char *referrer;
+ unsigned long sent;
+ int response;
+};
+#endif
+
+#define LWS_HTTP_CHUNK_HDR_MAX_SIZE (6 + 2) /* 6 hex digits and then CRLF */
+#define LWS_HTTP_CHUNK_TRL_MAX_SIZE (2 + 5) /* CRLF, then maybe 0 CRLF CRLF */
+
+struct _lws_http_mode_related {
+ struct lws *new_wsi_list;
+
+ unsigned char *pending_return_headers;
+ size_t pending_return_headers_len;
+ size_t prh_content_length;
+
+#if defined(LWS_WITH_HTTP_PROXY)
+ struct lws_rewrite *rw;
+ struct lws_buflist *buflist_post_body;
+#endif
+ struct allocated_headers *ah;
+ struct lws *ah_wait_list;
+
+ lws_filepos_t filepos;
+ lws_filepos_t filelen;
+ lws_fop_fd_t fop_fd;
+
+#if defined(LWS_WITH_RANGES)
+ struct lws_range_parsing range;
+ char multipart_content_type[64];
+#endif
+
+#ifdef LWS_WITH_ACCESS_LOG
+ struct lws_access_log access_log;
+#endif
+#ifdef LWS_WITH_CGI
+ struct lws_cgi *cgi; /* wsi being cgi master have one of these */
+#endif
+#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
+ struct lws_compression_support *lcs;
+ lws_comp_ctx_t comp_ctx;
+ unsigned char comp_accept_mask;
+#endif
+
+ enum http_version request_version;
+ enum http_conn_type conn_type;
+ lws_filepos_t tx_content_length;
+ lws_filepos_t tx_content_remain;
+ lws_filepos_t rx_content_length;
+ lws_filepos_t rx_content_remain;
+
+#if defined(LWS_WITH_HTTP_PROXY)
+ unsigned int perform_rewrite:1;
+ unsigned int proxy_clientside:1;
+ unsigned int proxy_parent_chunked:1;
+#endif
+ unsigned int deferred_transaction_completed:1;
+ unsigned int content_length_explicitly_zero:1;
+ unsigned int did_stream_close:1;
+};
+
+
+#ifndef LWS_NO_CLIENT
+enum lws_chunk_parser {
+ ELCP_HEX,
+ ELCP_CR,
+ ELCP_CONTENT,
+ ELCP_POST_CR,
+ ELCP_POST_LF,
+};
+#endif
+
+enum lws_parse_urldecode_results {
+ LPUR_CONTINUE,
+ LPUR_SWALLOW,
+ LPUR_FORBID,
+ LPUR_EXCESSIVE,
+};
+
+enum lws_check_basic_auth_results {
+ LCBA_CONTINUE,
+ LCBA_FAILED_AUTH,
+ LCBA_END_TRANSACTION,
+};
+
+enum lws_check_basic_auth_results
+lws_check_basic_auth(struct lws *wsi, const char *basic_auth_login_file);
+
+int
+lws_unauthorised_basic_auth(struct lws *wsi);
+
+int
+lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len);
+
+void
+_lws_header_table_reset(struct allocated_headers *ah);
+
+LWS_EXTERN int
+_lws_destroy_ah(struct lws_context_per_thread *pt, struct allocated_headers *ah);
+
+int
+lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
+ char *uri_ptr, char ws);
+
+void
+lws_sul_http_ah_lifecheck(lws_sorted_usec_list_t *sul);
--- /dev/null
- BIO_write(bio, pem, len);
+/*
+ * libwebsockets - OpenSSL-specific lws apis
+ *
+ * Copyright (C) 2010 - 2019 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 "private-lib-core.h"
+#include "private-lib-tls-openssl.h"
+
+#if !defined(LWS_PLAT_OPTEE)
+static int
+dec(char c)
+{
+ return c - '0';
+}
+#endif
+
+static time_t
+lws_tls_openssl_asn1time_to_unix(ASN1_TIME *as)
+{
+#if !defined(LWS_PLAT_OPTEE)
+
+ const char *p = (const char *)as->data;
+ struct tm t;
+
+ /* [YY]YYMMDDHHMMSSZ */
+
+ memset(&t, 0, sizeof(t));
+
+ if (strlen(p) == 13) {
+ t.tm_year = (dec(p[0]) * 10) + dec(p[1]) + 100;
+ p += 2;
+ } else {
+ t.tm_year = (dec(p[0]) * 1000) + (dec(p[1]) * 100) +
+ (dec(p[2]) * 10) + dec(p[3]);
+ p += 4;
+ }
+ t.tm_mon = (dec(p[0]) * 10) + dec(p[1]) - 1;
+ p += 2;
+ t.tm_mday = (dec(p[0]) * 10) + dec(p[1]) - 1;
+ p += 2;
+ t.tm_hour = (dec(p[0]) * 10) + dec(p[1]);
+ p += 2;
+ t.tm_min = (dec(p[0]) * 10) + dec(p[1]);
+ p += 2;
+ t.tm_sec = (dec(p[0]) * 10) + dec(p[1]);
+ t.tm_isdst = 0;
+
+ return mktime(&t);
+#else
+ return (time_t)-1;
+#endif
+}
+
+int
+lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
+ union lws_tls_cert_info_results *buf, size_t len)
+{
+ X509_NAME *xn;
+#if !defined(LWS_PLAT_OPTEE)
+ char *p;
+#endif
+
+ if (!x509)
+ return -1;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(X509_get_notBefore)
+#define X509_get_notBefore(x) X509_getm_notBefore(x)
+#define X509_get_notAfter(x) X509_getm_notAfter(x)
+#endif
+
+ switch (type) {
+ case LWS_TLS_CERT_INFO_VALIDITY_FROM:
+ buf->time = lws_tls_openssl_asn1time_to_unix(
+ X509_get_notBefore(x509));
+ if (buf->time == (time_t)-1)
+ return -1;
+ break;
+
+ case LWS_TLS_CERT_INFO_VALIDITY_TO:
+ buf->time = lws_tls_openssl_asn1time_to_unix(
+ X509_get_notAfter(x509));
+ if (buf->time == (time_t)-1)
+ return -1;
+ break;
+
+ case LWS_TLS_CERT_INFO_COMMON_NAME:
+#if defined(LWS_PLAT_OPTEE)
+ return -1;
+#else
+ xn = X509_get_subject_name(x509);
+ if (!xn)
+ return -1;
+ X509_NAME_oneline(xn, buf->ns.name, (int)len - 2);
+ p = strstr(buf->ns.name, "/CN=");
+ if (p)
+ memmove(buf->ns.name, p + 4, strlen(p + 4) + 1);
+ buf->ns.len = (int)strlen(buf->ns.name);
+ return 0;
+#endif
+ case LWS_TLS_CERT_INFO_ISSUER_NAME:
+ xn = X509_get_issuer_name(x509);
+ if (!xn)
+ return -1;
+ X509_NAME_oneline(xn, buf->ns.name, (int)len - 1);
+ buf->ns.len = (int)strlen(buf->ns.name);
+ return 0;
+
+ case LWS_TLS_CERT_INFO_USAGE:
+#if defined(LWS_HAVE_X509_get_key_usage)
+ buf->usage = X509_get_key_usage(x509);
+ break;
+#else
+ return -1;
+#endif
+
+ case LWS_TLS_CERT_INFO_OPAQUE_PUBLIC_KEY:
+ {
+#ifndef USE_WOLFSSL
+ size_t klen = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x509), NULL);
+ uint8_t *tmp, *ptmp;
+
+ if (!klen || klen > len)
+ return -1;
+
+ tmp = (uint8_t *)OPENSSL_malloc(klen);
+ if (!tmp)
+ return -1;
+
+ ptmp = tmp;
+ if (i2d_X509_PUBKEY(
+ X509_get_X509_PUBKEY(x509), &ptmp) != (int)klen ||
+ !ptmp || lws_ptr_diff(ptmp, tmp) != (int)klen) {
+ lwsl_info("%s: cert public key extraction failed\n",
+ __func__);
+ if (ptmp)
+ OPENSSL_free(tmp);
+
+ return -1;
+ }
+
+ buf->ns.len = (int)klen;
+ memcpy(buf->ns.name, tmp, klen);
+ OPENSSL_free(tmp);
+#endif
+ return 0;
+ }
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
+ union lws_tls_cert_info_results *buf, size_t len)
+{
+ return lws_tls_openssl_cert_info(x509->cert, type, buf, len);
+}
+
+#if defined(LWS_WITH_NETWORK)
+int
+lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
+ union lws_tls_cert_info_results *buf, size_t len)
+{
+#if defined(LWS_HAVE_SSL_CTX_get0_certificate)
+ X509 *x509 = SSL_CTX_get0_certificate(vhost->tls.ssl_ctx);
+
+ return lws_tls_openssl_cert_info(x509, type, buf, len);
+#else
+ lwsl_notice("openssl is too old to support %s\n", __func__);
+
+ return -1;
+#endif
+}
+
+
+
+int
+lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
+ union lws_tls_cert_info_results *buf, size_t len)
+{
+ int rc = 0;
+ X509 *x509;
+
+ wsi = lws_get_network_wsi(wsi);
+
+ x509 = SSL_get_peer_certificate(wsi->tls.ssl);
+
+ if (!x509) {
+ lwsl_debug("no peer cert\n");
+
+ return -1;
+ }
+
+ switch (type) {
+ case LWS_TLS_CERT_INFO_VERIFIED:
+ buf->verified = SSL_get_verify_result(wsi->tls.ssl) ==
+ X509_V_OK;
+ break;
+ default:
+ rc = lws_tls_openssl_cert_info(x509, type, buf, len);
+ }
+
+ X509_free(x509);
+
+ return rc;
+}
+#endif
+
+int
+lws_x509_create(struct lws_x509_cert **x509)
+{
+ *x509 = lws_malloc(sizeof(**x509), __func__);
+ if (*x509)
+ (*x509)->cert = NULL;
+
+ return !(*x509);
+}
+
+int
+lws_x509_parse_from_pem(struct lws_x509_cert *x509, const void *pem, size_t len)
+{
+ BIO* bio = BIO_new(BIO_s_mem());
+
- BIO_write(bio, pem, len);
++ BIO_write(bio, pem, (int)len);
+ x509->cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (!x509->cert) {
+ lwsl_err("%s: unable to parse PEM cert\n", __func__);
+ lws_tls_err_describe_clear();
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+lws_x509_verify(struct lws_x509_cert *x509, struct lws_x509_cert *trusted,
+ const char *common_name)
+{
+ char c[32], *p;
+ int ret;
+
+ if (common_name) {
+ X509_NAME *xn = X509_get_subject_name(x509->cert);
+ if (!xn)
+ return -1;
+ X509_NAME_oneline(xn, c, (int)sizeof(c) - 2);
+ p = strstr(c, "/CN=");
+ if (p)
+ p = p + 4;
+ else
+ p = c;
+
+ if (strcmp(p, common_name)) {
+ lwsl_err("%s: common name mismatch\n", __func__);
+ return -1;
+ }
+ }
+
+ ret = X509_check_issued(trusted->cert, x509->cert);
+ if (ret != X509_V_OK) {
+ lwsl_err("%s: unable to verify cert relationship\n", __func__);
+ lws_tls_err_describe_clear();
+
+ return -1;
+ }
+
+ return 0;
+}
+
+#if defined(LWS_WITH_JOSE)
+int
+lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509,
+ const char *curves, int rsa_min_bits)
+{
+ int id, n, ret = -1, count;
+ ASN1_OBJECT *obj = NULL;
+ const EC_POINT *ecpoint;
+ const EC_GROUP *ecgroup;
+ EC_KEY *ecpub = NULL;
+ X509_PUBKEY *pubkey;
+ RSA *rsapub = NULL;
+ BIGNUM *mpi[4];
+ EVP_PKEY *pkey;
+
+ memset(jwk, 0, sizeof(*jwk));
+
+ pubkey = X509_get_X509_PUBKEY(x509->cert);
+ if (!pubkey) {
+ lwsl_err("%s: missing pubkey alg in cert\n", __func__);
+
+ goto bail;
+ }
+
+ if (X509_PUBKEY_get0_param(&obj, NULL, NULL, NULL, pubkey) != 1) {
+ lwsl_err("%s: missing pubkey alg in cert\n", __func__);
+
+ goto bail;
+ }
+
+ id = OBJ_obj2nid(obj);
+ if (id == NID_undef) {
+ lwsl_err("%s: missing pubkey alg in cert\n", __func__);
+
+ goto bail;
+ }
+
+ lwsl_debug("%s: key type %d \"%s\"\n", __func__, id, OBJ_nid2ln(id));
+
+ pkey = X509_get_pubkey(x509->cert);
+ if (!pkey) {
+ lwsl_notice("%s: unable to extract pubkey", __func__);
+
+ goto bail;
+ }
+
+ switch (id) {
+ case NID_X9_62_id_ecPublicKey:
+ lwsl_debug("%s: EC key\n", __func__);
+ jwk->kty = LWS_GENCRYPTO_KTY_EC;
+
+ if (!curves) {
+ lwsl_err("%s: ec curves not allowed\n", __func__);
+
+ goto bail1;
+ }
+
+ ecpub = EVP_PKEY_get1_EC_KEY(pkey);
+ if (!ecpub) {
+ lwsl_notice("%s: missing EC pubkey\n", __func__);
+
+ goto bail1;
+ }
+
+ ecpoint = EC_KEY_get0_public_key(ecpub);
+ if (!ecpoint) {
+ lwsl_err("%s: EC_KEY_get0_public_key failed\n", __func__);
+ goto bail2;
+ }
+
+ ecgroup = EC_KEY_get0_group(ecpub);
+ if (!ecgroup) {
+ lwsl_err("%s: EC_KEY_get0_group failed\n", __func__);
+ goto bail2;
+ }
+
+ /* validate the curve against ones we allow */
+
+ if (lws_genec_confirm_curve_allowed_by_tls_id(curves,
+ EC_GROUP_get_curve_name(ecgroup), jwk))
+ /* already logged */
+ goto bail2;
+
+ mpi[LWS_GENCRYPTO_EC_KEYEL_CRV] = NULL;
+ mpi[LWS_GENCRYPTO_EC_KEYEL_X] = BN_new(); /* X */
+ mpi[LWS_GENCRYPTO_EC_KEYEL_D] = NULL;
+ mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = BN_new(); /* Y */
+
+#if defined(LWS_HAVE_EC_POINT_get_affine_coordinates)
+ if (EC_POINT_get_affine_coordinates(ecgroup, ecpoint,
+#else
+ if (EC_POINT_get_affine_coordinates_GFp(ecgroup, ecpoint,
+#endif
+ mpi[LWS_GENCRYPTO_EC_KEYEL_X],
+ mpi[LWS_GENCRYPTO_EC_KEYEL_Y],
+ NULL) != 1) {
+ BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]);
+ BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]);
+ lwsl_err("%s: EC_POINT_get_aff failed\n", __func__);
+ goto bail2;
+ }
+ count = LWS_GENCRYPTO_EC_KEYEL_COUNT;
+ n = LWS_GENCRYPTO_EC_KEYEL_X;
+ break;
+
+ case NID_rsaEncryption:
+ lwsl_debug("%s: rsa key\n", __func__);
+ jwk->kty = LWS_GENCRYPTO_KTY_RSA;
+
+ rsapub = EVP_PKEY_get1_RSA(pkey);
+ if (!rsapub) {
+ lwsl_notice("%s: missing RSA pubkey\n", __func__);
+
+ goto bail1;
+ }
+
+ if ((size_t)RSA_size(rsapub) * 8 < (size_t)rsa_min_bits) {
+ lwsl_err("%s: key bits %d less than minimum %d\n",
+ __func__, RSA_size(rsapub) * 8, rsa_min_bits);
+
+ goto bail2;
+ }
+
+#if defined(LWS_HAVE_RSA_SET0_KEY)
+ /* we don't need d... but the api wants to write it */
+ RSA_get0_key(rsapub,
+ (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_N],
+ (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_E],
+ (const BIGNUM **)&mpi[LWS_GENCRYPTO_RSA_KEYEL_D]);
+#else
+ mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = rsapub->e;
+ mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = rsapub->n;
+ mpi[LWS_GENCRYPTO_RSA_KEYEL_D] = NULL;
+#endif
+ count = LWS_GENCRYPTO_RSA_KEYEL_D;
+ n = LWS_GENCRYPTO_RSA_KEYEL_E;
+ break;
+ default:
+ lwsl_err("%s: unknown NID\n", __func__);
+ goto bail2;
+ }
+
+ for (; n < count; n++) {
+ if (!mpi[n])
+ continue;
+ jwk->e[n].len = BN_num_bytes(mpi[n]);
+ jwk->e[n].buf = lws_malloc(jwk->e[n].len, "certkeyimp");
+ if (!jwk->e[n].buf) {
+ if (id == NID_X9_62_id_ecPublicKey) {
+ BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]);
+ BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]);
+ }
+ goto bail2;
+ }
+ BN_bn2bin(mpi[n], jwk->e[n].buf);
+ }
+
+ if (id == NID_X9_62_id_ecPublicKey) {
+ BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_X]);
+ BN_clear_free(mpi[LWS_GENCRYPTO_EC_KEYEL_Y]);
+ }
+
+ ret = 0;
+
+bail2:
+ if (id == NID_X9_62_id_ecPublicKey)
+ EC_KEY_free(ecpub);
+ else
+ RSA_free(rsapub);
+
+bail1:
+ EVP_PKEY_free(pkey);
+bail:
+ /* jwk destroy will clean any partial state */
+ if (ret)
+ lws_jwk_destroy(jwk);
+
+ return ret;
+}
+
+static int
+lws_x509_jwk_privkey_pem_pp_cb(char *buf, int size, int rwflag, void *u)
+{
+ const char *pp = (const char *)u;
+ int n = strlen(pp);
+
+ if (n > size - 1)
+ return -1;
+
+ memcpy(buf, pp, n + 1);
+
+ return n;
+}
+
+int
+lws_x509_jwk_privkey_pem(struct lws_jwk *jwk, void *pem, size_t len,
+ const char *passphrase)
+{
+ BIO* bio = BIO_new(BIO_s_mem());
+ BIGNUM *mpi, *dummy[6];
+ EVP_PKEY *pkey = NULL;
+ EC_KEY *ecpriv = NULL;
+ RSA *rsapriv = NULL;
+ const BIGNUM *cmpi;
+ int n, m, ret = -1;
+
++ BIO_write(bio, pem, (int)len);
+ PEM_read_bio_PrivateKey(bio, &pkey, lws_x509_jwk_privkey_pem_pp_cb,
+ (void *)passphrase);
+ BIO_free(bio);
+ lws_explicit_bzero((void *)pem, len);
+ if (!pkey) {
+ lwsl_err("%s: unable to parse PEM privkey\n", __func__);
+ lws_tls_err_describe_clear();
+
+ return -1;
+ }
+
+ /* confirm the key type matches the existing jwk situation */
+
+ switch (jwk->kty) {
+ case LWS_GENCRYPTO_KTY_EC:
+ if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
+ lwsl_err("%s: jwk is EC but privkey isn't\n", __func__);
+
+ goto bail;
+ }
+ ecpriv = EVP_PKEY_get1_EC_KEY(pkey);
+ if (!ecpriv) {
+ lwsl_notice("%s: missing EC key\n", __func__);
+
+ goto bail;
+ }
+
+ cmpi = EC_KEY_get0_private_key(ecpriv);
+
+ /* quick size check first */
+
+ n = BN_num_bytes(cmpi);
+ if (jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].len != (uint32_t)n) {
+ lwsl_err("%s: jwk key size doesn't match\n", __func__);
+
+ goto bail1;
+ }
+
+ /* TODO.. check public curve / group + point */
+
+ jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len = n;
+ jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf = lws_malloc(n, "ec");
+ if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf)
+ goto bail1;
+
+ m = BN_bn2binpad(cmpi, jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf,
+ jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len);
+ if ((unsigned int)m != (unsigned int)BN_num_bytes(cmpi))
+ goto bail1;
+
+ break;
+
+ case LWS_GENCRYPTO_KTY_RSA:
+ if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_RSA) {
+ lwsl_err("%s: RSA jwk, non-RSA privkey\n", __func__);
+
+ goto bail;
+ }
+ rsapriv = EVP_PKEY_get1_RSA(pkey);
+ if (!rsapriv) {
+ lwsl_notice("%s: missing RSA key\n", __func__);
+
+ goto bail;
+ }
+
+#if defined(LWS_HAVE_RSA_SET0_KEY)
+ RSA_get0_key(rsapriv, (const BIGNUM **)&dummy[0], /* n */
+ (const BIGNUM **)&dummy[1], /* e */
+ (const BIGNUM **)&mpi); /* d */
+ RSA_get0_factors(rsapriv, (const BIGNUM **)&dummy[4], /* p */
+ (const BIGNUM **)&dummy[5]); /* q */
+#else
+ dummy[0] = rsapriv->n;
+ dummy[1] = rsapriv->e;
+ dummy[4] = rsapriv->p;
+ dummy[5] = rsapriv->q;
+ mpi = rsapriv->d;
+#endif
+
+ /* quick size check first */
+
+ n = BN_num_bytes(mpi);
+ if (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len != (uint32_t)n) {
+ lwsl_err("%s: jwk key size doesn't match\n", __func__);
+
+ goto bail1;
+ }
+
+ /* then check that n & e match what we got from the cert */
+
+ dummy[2] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].buf,
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len,
+ NULL);
+ dummy[3] = BN_bin2bn(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf,
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len,
+ NULL);
+
+ m = BN_cmp(dummy[2], dummy[0]) | BN_cmp(dummy[3], dummy[1]);
+ BN_clear_free(dummy[2]);
+ BN_clear_free(dummy[3]);
+ if (m) {
+ lwsl_err("%s: privkey doesn't match jwk pubkey\n",
+ __func__);
+
+ goto bail1;
+ }
+
+ /* accept d from the PEM privkey into the JWK */
+
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].len = n;
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf = lws_malloc(n, "privjk");
+ if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf)
+ goto bail1;
+
+ BN_bn2bin(mpi, jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf);
+
+ /* accept p and q from the PEM privkey into the JWK */
+
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].len = BN_num_bytes(dummy[4]);
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf = lws_malloc(n, "privjk");
+ if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) {
+ lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf);
+ goto bail1;
+ }
+ BN_bn2bin(dummy[4], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf);
+
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].len = BN_num_bytes(dummy[5]);
+ jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf = lws_malloc(n, "privjk");
+ if (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf) {
+ lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf);
+ lws_free_set_NULL(jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf);
+ goto bail1;
+ }
+ BN_bn2bin(dummy[5], jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf);
+ break;
+ default:
+ lwsl_err("%s: JWK has unknown kty %d\n", __func__, jwk->kty);
+ return -1;
+ }
+
+ ret = 0;
+
+bail1:
+ if (jwk->kty == LWS_GENCRYPTO_KTY_EC)
+ EC_KEY_free(ecpriv);
+ else
+ RSA_free(rsapriv);
+
+bail:
+ EVP_PKEY_free(pkey);
+
+ return ret;
+}
+#endif
+
+void
+lws_x509_destroy(struct lws_x509_cert **x509)
+{
+ if (!*x509)
+ return;
+
+ if ((*x509)->cert) {
+ X509_free((*x509)->cert);
+ (*x509)->cert = NULL;
+ }
+
+ lws_free_set_NULL(*x509);
+}
--- /dev/null
- Version: 3.2.0
+Name: libwebsockets
+Summary: WebSocket Library
++Version: 3.2.3
+Release: 1
+Group: System/Libraries
+License: LGPLv2 with exceptions
+URL: https://github.com/warmcat/libwebsockets
+Source0: %{name}-%{version}.tar.gz
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires: zlib-devel
+BuildRequires: pkgconfig(openssl1.1)
+BuildRequires: openssl1.1
+BuildRequires: cmake
+
+%define _optdeveldir /opt/usr/devel/usr/
+
+%description
+C Websockets Server Library
+
+%package devel
+Summary: Development files for %{name}
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+Development files needed for building websocket clients and servers
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+
+%cmake -DLWS_WITH_SSL=On \
+ -DLWS_WITHOUT_TESTAPPS=ON \
+ -DLWS_WITH_SERVER_STATUS=ON \
+ -DLWS_IPV6=ON \
+ -DLWS_WITH_SO_BINDTODEVICE=ON \
+ -DLWS_WITH_HTTP2=OFF\
+ .
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+%make_install
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libwebsockets*.so.*
+%license LICENSE
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/libwebsockets.h
+%{_includedir}/lws-plugin-ssh.h
+%{_includedir}/lws_config.h
+%{_includedir}/libwebsockets/*
+%{_libdir}/libwebsockets.so
+%{_libdir}/pkgconfig/*
+%{_libdir}/cmake/*