Merge tag 'upstream/3.2.3' into tizen 13/253613/4 accepted/tizen_6.5_unified tizen_6.5 accepted/tizen/6.5/unified/20211029.014320 accepted/tizen/unified/20210217.120515 submit/tizen/20210216.094343 submit/tizen_6.5/20211028.163501 tizen_6.5.m2_release
authorCheoleun Moon <chleun.moon@samsung.com>
Tue, 16 Feb 2021 04:48:48 +0000 (13:48 +0900)
committerCheoleun Moon <chleun.moon@samsung.com>
Tue, 16 Feb 2021 04:50:13 +0000 (13:50 +0900)
Change-Id: I538a1ab537c64150323a469f40078bf001a42c33

46 files changed:
1  2 
CMakeLists.txt
lib/core-net/close.c
lib/core-net/connect.c
lib/core-net/dummy-callback.c
lib/core-net/lws-dsh.c
lib/core-net/output.c
lib/core-net/private-lib-core-net.h
lib/core-net/sequencer.c
lib/core-net/sorted-usec-list.c
lib/core-net/vhost.c
lib/core-net/wsi-timeout.c
lib/core/context.c
lib/core/private-lib-core.h
lib/event-libs/libev/libev.c
lib/event-libs/libevent/libevent.c
lib/event-libs/libuv/libuv.c
lib/jose/jws/jws.c
lib/misc/daemonize.c
lib/plat/esp32/esp32-service.c
lib/plat/optee/network.c
lib/plat/unix/private-lib-plat-unix.h
lib/plat/unix/unix-init.c
lib/plat/unix/unix-misc.c
lib/plat/unix/unix-pipe.c
lib/plat/unix/unix-service.c
lib/plat/windows/windows-service.c
lib/plat/windows/windows-sockets.c
lib/roles/cgi/cgi-server.c
lib/roles/h1/ops-h1.c
lib/roles/h2/http2.c
lib/roles/http/client/client-handshake.c
lib/roles/http/client/client-http.c
lib/roles/http/private-lib-roles-http.h
lib/roles/http/server/lws-spa.c
lib/roles/http/server/server.c
lib/roles/listen/ops-listen.c
lib/roles/pipe/ops-pipe.c
lib/roles/ws/client-ws.c
lib/roles/ws/ops-ws.c
lib/tls/lws-gencrypto-common.c
lib/tls/mbedtls/lws-genec.c
lib/tls/openssl/openssl-client.c
lib/tls/openssl/openssl-x509.c
lib/tls/tls-client.c
lib/tls/tls.c
packaging/libwebsockets.spec

diff --cc CMakeLists.txt
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 16ca46cf95b067c34768c2d69bb5d7516bfe809b,0000000000000000000000000000000000000000..6894c88260f25dc0d89b9a9d3a8c244257c1e9c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,1166 -1,0 +1,1168 @@@
- __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
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 4fcc6071c73e63bc67e02bd5688afc9d99f922d8,0000000000000000000000000000000000000000..ca8e90db3168292aa3145537b64277d0ae832f0f
mode 100644,000000..100644
--- /dev/null
@@@ -1,621 -1,0 +1,621 @@@
-  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
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 6aefa5c9051436255781f07c776b7bca0625f24e,0000000000000000000000000000000000000000..97ff5bad69face872f224c713172d1c56851d747
mode 100644,000000..100644
--- /dev/null
@@@ -1,173 -1,0 +1,176 @@@
- #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
Simple merge
Simple merge
Simple merge
Simple merge
index cb2aba0860ffbeb0a7cc2ca564300c4bf64a51ef,4036528fdcf00efdbfd51b5c7c475279505a0da4..7e35daa745c18f151185db5f522c5e2a2c0a693a
  #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)
  {
Simple merge
Simple merge
Simple merge
Simple merge
index d0052cc9d180d67f399a7173f73533606f19ce65,0000000000000000000000000000000000000000..f611f1a9245d3d855fc7e327001649a7bef1922a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1334 -1,0 +1,1337 @@@
-                               *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
index 73a74d9cd3f75526a440137057524a6a9d1c9f81,0000000000000000000000000000000000000000..a9108a8ab0a59c31524ecfaaaa3d47c5fed5d2b7
mode 100644,000000..100644
--- /dev/null
@@@ -1,308 -1,0 +1,306 @@@
- 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);
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 3dee44e7a325ec9181fd8e7bd8b10bfdd5117d57,0000000000000000000000000000000000000000..79c34580d2998c984c2b49e43a3f44245fe9dd58
mode 100644,000000..100644
--- /dev/null
@@@ -1,664 -1,0 +1,664 @@@
-       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);
 +}
Simple merge
diff --cc lib/tls/tls.c
Simple merge
index 031d1b4ae1811efe8a62c7e1b4d37d9fba5ea485,0000000000000000000000000000000000000000..920e61177f7b97f796b3236aab38935b47ef7784
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,67 @@@
- 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/*