diff --git a/lib/core-net/close.c b/lib/core-net/close.c index c8893479f..d7b54decf 100644 --- a/lib/core-net/close.c +++ b/lib/core-net/close.c @@ -264,7 +264,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, #endif #if defined(LWS_WITH_HTTP2) - if (wsi->h2_stream_immortal) + if (wsi->mux_stream_immortal) lws_http_close_immortal(wsi); #endif diff --git a/lib/core-net/dummy-callback.c b/lib/core-net/dummy-callback.c index 37d884795..851a2b128 100644 --- a/lib/core-net/dummy-callback.c +++ b/lib/core-net/dummy-callback.c @@ -57,7 +57,7 @@ stream_close(struct lws *wsi) wsi->http.did_stream_close = 1; - if (wsi->http2_substream) { + if (wsi->mux_substream) { if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0, LWS_WRITE_HTTP_FINAL) < 0) { lwsl_info("%s: COMPL_CLIENT_HTTP: h2 fin wr failed\n", @@ -115,7 +115,7 @@ lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason, lws_process_ws_upgrade2(wsi->parent); #if defined(LWS_WITH_HTTP2) - if (wsi->parent->http2_substream) + if (wsi->parent->mux_substream) lwsl_info("%s: proxied h2 -> h1 ws established\n", __func__); #endif break; @@ -330,7 +330,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, } if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) { - if (!wsi->http2_substream) { + if (!wsi->mux_substream) { memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5); lwsl_debug("writing chunk term and exiting\n"); n = lws_write(wsi, (unsigned char *)buf + @@ -508,7 +508,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, proxy_header(parent, wsi, end, 256, WSI_TOKEN_HTTP_LOCATION, &p, end); - if (!parent->http2_substream) + if (!parent->mux_substream) if (lws_add_http_header_by_token(parent, WSI_TOKEN_CONNECTION, (unsigned char *)"close", 5, &p, end)) @@ -522,7 +522,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, * our own chunking since we still don't know the size. */ - if (!parent->http2_substream && + if (!parent->mux_substream && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { lwsl_debug("downstream parent chunked\n"); if (lws_add_http_header_by_token(parent, @@ -661,7 +661,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n", wsi->http.cgi->explicitly_chunked, (uint64_t)wsi->http.cgi->content_length); - if (!(wsi->http.cgi->explicitly_chunked && wsi->http2_substream) && + if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) && !wsi->http.cgi->content_length) { /* send terminating chunk */ lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: ending\n"); @@ -670,7 +670,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3); break; } - if (wsi->http2_substream && !wsi->cgi_stdout_zero_length) + if (wsi->mux_substream && !wsi->cgi_stdout_zero_length) lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0, LWS_WRITE_HTTP_FINAL); diff --git a/lib/core-net/output.c b/lib/core-net/output.c index cc1276ce5..46c5b15f9 100644 --- a/lib/core-net/output.c +++ b/lib/core-net/output.c @@ -93,7 +93,7 @@ lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len) if (!len || !buf) return 0; - if (!wsi->http2_substream && !lws_socket_is_valid(wsi->desc.sockfd)) + if (!wsi->mux_substream && !lws_socket_is_valid(wsi->desc.sockfd)) lwsl_warn("** error invalid sock but expected to send\n"); /* limit sending */ diff --git a/lib/core-net/pollfd.c b/lib/core-net/pollfd.c index 69ea94152..7080838d7 100644 --- a/lib/core-net/pollfd.c +++ b/lib/core-net/pollfd.c @@ -147,7 +147,7 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa) pa->prev_events = pfd->events; pa->events = pfd->events = (pfd->events & ~_and) | _or; - if (wsi->http2_substream) + if (wsi->mux_substream) return 0; #if defined(LWS_WITH_EXTERNAL_POLL) diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 57081fff9..46bf8ceb2 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -29,6 +29,21 @@ #define _POSIX_C_SOURCE 200112L #endif +/* + * Generic pieces needed to manage muxable stream protocols like h2 + */ + +struct lws_muxable { + struct lws *parent_wsi; + struct lws *child_list; + struct lws *sibling_list; + + unsigned int my_sid; + unsigned int child_count; + + uint8_t requested_POLLOUT; +}; + #include "private-lib-roles.h" #ifdef LWS_WITH_IPV6 @@ -576,6 +591,32 @@ struct lws_vhost { void __lws_vhost_destroy2(struct lws_vhost *vh); +#define mux_to_wsi(_m) lws_container_of(_m, struct lws, mux) + +void +lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, int sid); +int +lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi); +struct lws * +lws_wsi_mux_move_child_to_tail(struct lws **wsi2); +int +lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi); + +void +lws_wsi_mux_dump_children(struct lws *wsi); + +void +lws_wsi_mux_close_children(struct lws *wsi, int reason); + +void +lws_wsi_mux_sibling_disconnect(struct lws *wsi); + +void +lws_wsi_mux_dump_waiting_children(struct lws *wsi); + +int +lws_wsi_mux_apply_queue(struct lws *wsi); + /* * struct lws */ @@ -584,47 +625,51 @@ struct lws { /* structs */ #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) - struct _lws_http_mode_related http; + struct _lws_http_mode_related http; #endif #if defined(LWS_ROLE_H2) - struct _lws_h2_related h2; + struct _lws_h2_related h2; #endif #if defined(LWS_ROLE_WS) - struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */ + struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */ #endif #if defined(LWS_ROLE_DBUS) - struct _lws_dbus_mode_related dbus; + struct _lws_dbus_mode_related dbus; +#endif + +#if defined(LWS_ROLE_H2) + struct lws_muxable mux; #endif /* lifetime members */ #if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \ defined(LWS_WITH_LIBEVENT) - struct lws_io_watcher w_read; + struct lws_io_watcher w_read; #endif #if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT) - struct lws_io_watcher w_write; + struct lws_io_watcher w_write; #endif #if defined(LWS_WITH_DETAILED_LATENCY) lws_detlat_t detlat; #endif - lws_sorted_usec_list_t sul_timeout; - lws_sorted_usec_list_t sul_hrtimer; - lws_sorted_usec_list_t sul_validity; + lws_sorted_usec_list_t sul_timeout; + lws_sorted_usec_list_t sul_hrtimer; + lws_sorted_usec_list_t sul_validity; - struct lws_dll2 dll_buflist; /* guys with pending rxflow */ - struct lws_dll2 same_vh_protocol; - struct lws_dll2 vh_awaiting_socket; + struct lws_dll2 dll_buflist; /* guys with pending rxflow */ + struct lws_dll2 same_vh_protocol; + struct lws_dll2 vh_awaiting_socket; #if defined(LWS_WITH_SYS_ASYNC_DNS) - struct lws_dll2 adns; /* on adns list of guys to tell result */ - lws_async_dns_cb_t adns_cb; /* callback with result */ + struct lws_dll2 adns; /* on adns list of guys to tell result */ + lws_async_dns_cb_t adns_cb; /* callback with result */ #endif #if defined(LWS_WITH_CLIENT) - struct lws_dll2 dll_cli_active_conns; - struct lws_dll2_owner dll2_cli_txn_queue_owner; - struct lws_dll2 dll2_cli_txn_queue; + struct lws_dll2 dll_cli_active_conns; + struct lws_dll2 dll2_cli_txn_queue; + struct lws_dll2_owner dll2_cli_txn_queue_owner; #endif #if defined(LWS_WITH_ACCESS_LOG) @@ -632,134 +677,134 @@ struct lws { #endif /* pointers */ - struct lws_context *context; - struct lws_vhost *vhost; - struct lws *parent; /* points to parent, if any */ - struct lws *child_list; /* points to first child */ - struct lws *sibling_list; /* subsequent children at same level */ - const struct lws_role_ops *role_ops; - const struct lws_protocols *protocol; - struct lws_sequencer *seq; /* associated sequencer if any */ - const lws_retry_bo_t *retry_policy; + 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_role_ops *role_ops; + const struct lws_protocols *protocol; + struct lws_sequencer *seq; /* associated sequencer if any */ + const lws_retry_bo_t *retry_policy; #if defined(LWS_WITH_THREADPOOL) - struct lws_threadpool_task *tp_task; + struct lws_threadpool_task *tp_task; #endif #if defined(LWS_WITH_PEER_LIMITS) - struct lws_peer *peer; + struct lws_peer *peer; #endif #if defined(LWS_WITH_UDP) - struct lws_udp *udp; + struct lws_udp *udp; #endif #if defined(LWS_WITH_CLIENT) - struct client_info_stash *stash; - char *cli_hostname_copy; - const struct addrinfo *dns_results; - const struct addrinfo *dns_results_next; + struct client_info_stash *stash; + char *cli_hostname_copy; + const struct addrinfo *dns_results; + const struct addrinfo *dns_results_next; #endif - void *user_space; - void *opaque_parent_data; - void *opaque_user_data; + 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 */ + 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; + struct lws_lws_tls tls; #endif - lws_sock_file_fd_type desc; /* .filefd / .sockfd */ + lws_sock_file_fd_type desc; /* .filefd / .sockfd */ #if defined(LWS_WITH_STATS) uint64_t active_writable_req_us; #if defined(LWS_WITH_TLS) uint64_t accept_start_us; #endif #endif - lws_wsi_state_t wsistate; - lws_wsi_state_t wsistate_pre_close; + lws_wsi_state_t wsistate; + lws_wsi_state_t wsistate_pre_close; /* ints */ #define LWS_NO_FDS_POS (-1) - int position_in_fds_table; + int position_in_fds_table; #if defined(LWS_WITH_CLIENT) - int chunk_remaining; - int flags; + int chunk_remaining; + int flags; #endif - unsigned int cache_secs; + 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_immortal:1; - unsigned int h2_stream_carries_ws:1; /* immortal set as well */ - unsigned int h2_stream_carries_sse:1; /* immortal set as well */ - unsigned int h2_acked_settings:1; - unsigned int seen_nonpseudoheader:1; - unsigned int listener:1; - unsigned int pf_packet:1; - unsigned int do_broadcast: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:1; - unsigned int proxied_ws_parent:1; - unsigned int do_bind:1; - unsigned int oom4:1; - unsigned int validity_hup:1; + unsigned int hdr_parsing_completed:1; + unsigned int mux_substream:1; + unsigned int upgraded_to_http2:1; + unsigned int mux_stream_immortal:1; + unsigned int h2_stream_carries_ws:1; /* immortal set as well */ + unsigned int h2_stream_carries_sse:1; /* immortal set as well */ + unsigned int h2_acked_settings:1; + unsigned int seen_nonpseudoheader:1; + unsigned int listener:1; + unsigned int pf_packet:1; + unsigned int do_broadcast: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:1; + unsigned int proxied_ws_parent:1; + unsigned int do_bind:1; + unsigned int oom4:1; + unsigned int validity_hup:1; - unsigned int could_have_pending:1; /* detect back-to-back writes */ - unsigned int outer_will_close:1; - unsigned int shadow:1; /* we do not control fd lifecycle at all */ + 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; + unsigned int access_log_pending:1; #endif #if defined(LWS_WITH_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 redirected_to_get:1; - unsigned int client_pipeline:1; - unsigned int client_h2_alpn:1; - unsigned int client_h2_substream:1; - unsigned int client_h2_migrated:1; + 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 redirected_to_get:1; + unsigned int client_pipeline:1; + unsigned int client_h2_alpn:1; + unsigned int client_mux_substream:1; + unsigned int client_mux_migrated:1; #endif #ifdef _WIN32 unsigned int sock_send_blocking:1; #endif - uint16_t ocport, c_port; - uint16_t retry; + uint16_t ocport, c_port; + uint16_t retry; /* chars */ @@ -1110,7 +1155,7 @@ lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int len, int meth); #endif void -lws_http_mark_immortal(struct lws *wsi); +lws_mux_mark_immortal(struct lws *wsi); void lws_http_close_immortal(struct lws *wsi); diff --git a/lib/core-net/wsi-timeout.c b/lib/core-net/wsi-timeout.c index e95e84805..f3d14939b 100644 --- a/lib/core-net/wsi-timeout.c +++ b/lib/core-net/wsi-timeout.c @@ -156,8 +156,8 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) if (secs == LWS_TO_KILL_ASYNC) secs = 0; - // assert(!secs || !wsi->h2_stream_immortal); - if (secs && wsi->h2_stream_immortal) + // assert(!secs || !wsi->mux_stream_immortal); + if (secs && wsi->mux_stream_immortal) lwsl_err("%s: on immortal stream %d %d\n", __func__, reason, secs); lws_pt_lock(pt, __func__); diff --git a/lib/core-net/wsi.c b/lib/core-net/wsi.c index d8677b0c4..66b35c3c6 100644 --- a/lib/core-net/wsi.c +++ b/lib/core-net/wsi.c @@ -86,29 +86,29 @@ lws_vhost_unbind_wsi(struct lws *wsi) lws_context_unlock(wsi->context); /* } context ---------- */ } -LWS_VISIBLE struct lws * +struct lws * lws_get_network_wsi(struct lws *wsi) { if (!wsi) return NULL; #if defined(LWS_WITH_HTTP2) - if (!wsi->http2_substream + if (!wsi->mux_substream #if defined(LWS_WITH_CLIENT) - && !wsi->client_h2_substream + && !wsi->client_mux_substream #endif ) return wsi; - while (wsi->h2.parent_wsi) - wsi = wsi->h2.parent_wsi; + while (wsi->mux.parent_wsi) + wsi = wsi->mux.parent_wsi; #endif return wsi; } -LWS_VISIBLE LWS_EXTERN const struct lws_protocols * +const struct lws_protocols * lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name) { int n; @@ -222,7 +222,7 @@ lws_rx_flow_control(struct lws *wsi, int _enable) int en = _enable; // h2 ignores rx flow control atm - if (lwsi_role_h2(wsi) || wsi->http2_substream || + if (lwsi_role_h2(wsi) || wsi->mux_substream || lwsi_role_h2_ENCAPSULATION(wsi)) return 0; // !!! @@ -312,7 +312,7 @@ __lws_rx_flow_control(struct lws *wsi) struct lws *wsic = wsi->child_list; // h2 ignores rx flow control atm - if (lwsi_role_h2(wsi) || wsi->http2_substream || + if (lwsi_role_h2(wsi) || wsi->mux_substream || lwsi_role_h2_ENCAPSULATION(wsi)) return 0; // !!! @@ -898,11 +898,11 @@ lws_http_close_immortal(struct lws *wsi) { struct lws *nwsi; - if (!wsi->http2_substream) + if (!wsi->mux_substream) return; - assert(wsi->h2_stream_immortal); - wsi->h2_stream_immortal = 0; + assert(wsi->mux_stream_immortal); + wsi->mux_stream_immortal = 0; nwsi = lws_get_network_wsi(wsi); lwsl_debug("%s: %p %p %d\n", __func__, wsi, nwsi, @@ -920,15 +920,15 @@ lws_http_close_immortal(struct lws *wsi) } void -lws_http_mark_immortal(struct lws *wsi) +lws_mux_mark_immortal(struct lws *wsi) { struct lws *nwsi; lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); - if (!wsi->http2_substream + if (!wsi->mux_substream #if defined(LWS_WITH_CLIENT) - && !wsi->client_h2_substream + && !wsi->client_mux_substream #endif ) { lwsl_err("%s: not h2 substream\n", __func__); @@ -940,7 +940,7 @@ lws_http_mark_immortal(struct lws *wsi) lwsl_debug("%s: %p %p %d\n", __func__, wsi, nwsi, nwsi->immortal_substream_count); - wsi->h2_stream_immortal = 1; + wsi->mux_stream_immortal = 1; assert(nwsi->immortal_substream_count < 255); /* largest count */ nwsi->immortal_substream_count++; if (nwsi->immortal_substream_count == 1) @@ -952,14 +952,15 @@ int lws_http_mark_sse(struct lws *wsi) { lws_http_headers_detach(wsi); - lws_http_mark_immortal(wsi); + lws_mux_mark_immortal(wsi); - if (wsi->http2_substream) + if (wsi->mux_substream) wsi->h2_stream_carries_sse = 1; return 0; } +#if defined(LWS_WITH_CLIENT) const char * lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx) @@ -975,3 +976,216 @@ lws_wsi_client_stash_item(struct lws *wsi, int stash_idx, int hdr_idx) return NULL; #endif } +#endif + +#if defined(LWS_ROLE_H2) + +void +lws_wsi_mux_insert(struct lws *wsi, struct lws *parent_wsi, int sid) +{ + wsi->mux.my_sid = sid; + wsi->mux.parent_wsi = parent_wsi; + wsi->role_ops = parent_wsi->role_ops; + + /* new guy's sibling is whoever was the first child before */ + wsi->mux.sibling_list = parent_wsi->mux.child_list; + + /* first child is now the new guy */ + parent_wsi->mux.child_list = wsi; + + parent_wsi->mux.child_count++; +} + +struct lws * +lws_wsi_mux_from_id(struct lws *parent_wsi, unsigned int sid) +{ + lws_start_foreach_ll(struct lws *, wsi, parent_wsi->mux.child_list) { + if (wsi->mux.my_sid == sid) + return wsi; + } lws_end_foreach_ll(wsi, mux.sibling_list); + + return NULL; +} + +void +lws_wsi_mux_dump_children(struct lws *wsi) +{ +#if defined(_DEBUG) + if (!wsi->mux.parent_wsi || !lwsl_visible(LLL_INFO)) + return; + + lws_start_foreach_llp(struct lws **, w, + wsi->mux.parent_wsi->mux.child_list) { + lwsl_info(" \\---- child %s %p\n", + (*w)->role_ops ? (*w)->role_ops->name : "?", *w); + } lws_end_foreach_llp(w, mux.sibling_list); +#endif +} + +void +lws_wsi_mux_close_children(struct lws *wsi, int reason) +{ + struct lws *wsi2; + + if (!wsi->mux.child_list) + return; + + lws_start_foreach_llp(struct lws **, w, wsi->mux.child_list) { + lwsl_info(" closing child %p\n", *w); + /* disconnect from siblings */ + wsi2 = (*w)->mux.sibling_list; + (*w)->mux.sibling_list = NULL; + (*w)->socket_is_permanently_unusable = 1; + __lws_close_free_wsi(*w, reason, "mux child recurse"); + *w = wsi2; + continue; + } lws_end_foreach_llp(w, mux.sibling_list); +} + + +void +lws_wsi_mux_sibling_disconnect(struct lws *wsi) +{ + struct lws *wsi2; + + lws_start_foreach_llp(struct lws **, w, + wsi->mux.parent_wsi->mux.child_list) { + + /* disconnect from siblings */ + if (*w == wsi) { + wsi2 = (*w)->mux.sibling_list; + (*w)->mux.sibling_list = NULL; + *w = wsi2; + lwsl_debug(" %p disentangled from sibling %p\n", + wsi, wsi2); + break; + } + } lws_end_foreach_llp(w, mux.sibling_list); + wsi->mux.parent_wsi->mux.child_count--; + wsi->mux.parent_wsi = NULL; +} + +void +lws_wsi_mux_dump_waiting_children(struct lws *wsi) +{ +#if defined(_DEBUG) + lwsl_info("%s: %p: children waiting for POLLOUT service:\n", + __func__, wsi); + + wsi = wsi->mux.child_list; + while (wsi) { + lwsl_info(" %c %p %s %s\n", + wsi->mux.requested_POLLOUT ? '*' : ' ', + wsi, wsi->role_ops->name, wsi->protocol ? + wsi->protocol->name : "noprotocol"); + + wsi = wsi->mux.sibling_list; + } +#endif +} + +int +lws_wsi_mux_mark_parents_needing_writeable(struct lws *wsi) +{ + struct lws *network_wsi = lws_get_network_wsi(wsi), *wsi2; + int already = network_wsi->mux.requested_POLLOUT; + + /* mark everybody above him as requesting pollout */ + + wsi2 = wsi; + while (wsi2) { + wsi2->mux.requested_POLLOUT = 1; + lwsl_info("mark %p pending writable\n", wsi2); + wsi2 = wsi2->mux.parent_wsi; + } + + return already; +} + +struct lws * +lws_wsi_mux_move_child_to_tail(struct lws **wsi2) +{ + struct lws *w = *wsi2; + + while (w) { + if (!w->mux.sibling_list) { /* w is the current last */ + lwsl_debug("w=%p, *wsi2 = %p\n", w, *wsi2); + + if (w == *wsi2) /* we are already last */ + break; + + /* last points to us as new last */ + w->mux.sibling_list = *wsi2; + + /* guy pointing to us until now points to + * our old next */ + *wsi2 = (*wsi2)->mux.sibling_list; + + /* we point to nothing because we are last */ + w->mux.sibling_list->mux.sibling_list = NULL; + + /* w becomes us */ + w = w->mux.sibling_list; + break; + } + w = w->mux.sibling_list; + } + + /* clear the waiting for POLLOUT on the guy that was chosen */ + + if (w) + w->mux.requested_POLLOUT = 0; + + return w; +} + +int +lws_wsi_mux_action_pending_writeable_reqs(struct lws *wsi) +{ + struct lws *w = wsi->mux.child_list; + + while (w) { + if (w->mux.requested_POLLOUT) { + if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) + return -1; + break; + } + w = w->mux.sibling_list; + } + + return 0; +} + +#if defined(LWS_WITH_CLIENT) + +int +lws_wsi_mux_apply_queue(struct lws *wsi) +{ + /* we have a transaction queue that wants to pipeline */ + + 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); + + if (lwsi_role_http(wsi) && + lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) { + lwsl_info("%s: cli pipeq %p to be h2\n", __func__, w); + + /* remove ourselves from client queue */ + lws_dll2_remove(&w->dll2_cli_txn_queue); + + /* attach ourselves as an h2 stream */ + lws_wsi_h2_adopt(wsi, w); + } + + } lws_end_foreach_dll_safe(d, d1); + lws_vhost_unlock(wsi->vhost); + + return 0; +} + +#endif + +#endif diff --git a/lib/roles/cgi/cgi-server.c b/lib/roles/cgi/cgi-server.c index b34a33dad..a0f3bc891 100644 --- a/lib/roles/cgi/cgi-server.c +++ b/lib/roles/cgi/cgi-server.c @@ -597,7 +597,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi) WSI_TOKEN_HTTP_TRANSFER_ENCODING, (unsigned char *)"chunked", 7, &p, end)) return 1; - if (!(wsi->http2_substream)) + if (!(wsi->mux_substream)) if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION, (unsigned char *)"close", 5, @@ -615,7 +615,7 @@ lws_cgi_write_split_stdout_headers(struct lws *wsi) * Let's redo them at headers_pos forward using the * correct coding for http/1 or http/2 */ - if (!wsi->http2_substream) + if (!wsi->mux_substream) goto post_hpack_recode; p = wsi->http.cgi->headers_start; @@ -750,7 +750,7 @@ post_hpack_recode: if (!wsi->http.cgi->headers_buf) { /* if we don't already have a headers buf, cook one */ n = 2048; - if (wsi->http2_substream) + if (wsi->mux_substream) n = 4096; wsi->http.cgi->headers_buf = lws_malloc(n + LWS_PRE, "cgi hdr buf"); @@ -921,7 +921,7 @@ agin: /* payload processing */ - m = !wsi->http.cgi->implied_chunked && !wsi->http2_substream && + m = !wsi->http.cgi->implied_chunked && !wsi->mux_substream && // !wsi->http.cgi->explicitly_chunked && !wsi->http.cgi->content_length; n = lws_get_socket_fd(wsi->http.cgi->stdwsi[LWS_STDOUT]); @@ -936,7 +936,7 @@ agin: if (n > 0) { // lwsl_hexdump_notice(buf, n); - if (!wsi->http2_substream && m) { + if (!wsi->mux_substream && m) { char chdr[LWS_HTTP_CHUNK_HDR_SIZE]; m = lws_snprintf(chdr, LWS_HTTP_CHUNK_HDR_SIZE - 3, "%X\x0d\x0a", n); @@ -948,7 +948,7 @@ agin: #if defined(LWS_WITH_HTTP2) - if (wsi->http2_substream) { + if (wsi->mux_substream) { struct lws *nwsi = lws_get_network_wsi(wsi); __lws_set_timeout(wsi, @@ -974,7 +974,7 @@ agin: wsi->http.cgi->content_length_seen += n; } else { - if (!wsi->http2_substream && m) { + if (!wsi->mux_substream && m) { uint8_t term[LWS_PRE + 6]; lwsl_notice("%s: sent trailer\n", __func__); @@ -991,7 +991,7 @@ agin: if (wsi->cgi_stdout_zero_length) { lwsl_debug("%s: stdout is POLLHUP'd\n", __func__); - if (wsi->http2_substream) + if (wsi->mux_substream) m = lws_write(wsi, (unsigned char *)start, 0, LWS_WRITE_HTTP_FINAL); else diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index cc48aaae6..6007a1a06 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -212,7 +212,7 @@ postbody_completion: if (n) goto bail; - if (wsi->http2_substream) + if (wsi->mux_substream) lwsi_set_state(wsi, LRS_ESTABLISHED); } diff --git a/lib/roles/h2/hpack.c b/lib/roles/h2/hpack.c index 5ca884132..74bc1dcf5 100644 --- a/lib/roles/h2/hpack.c +++ b/lib/roles/h2/hpack.c @@ -1363,7 +1363,7 @@ int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name, if (name[len - 1] == ':') len--; - if (wsi->http2_substream && !strncmp((const char *)name, + if (wsi->mux_substream && !strncmp((const char *)name, "transfer-encoding", len)) { lwsl_header("rejecting %s\n", name); diff --git a/lib/roles/h2/http2.c b/lib/roles/h2/http2.c index 403d013d6..4525b969a 100644 --- a/lib/roles/h2/http2.c +++ b/lib/roles/h2/http2.c @@ -173,7 +173,7 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, } /* no more children allowed by parent */ - if (parent_wsi->h2.child_count + 1 > + if (parent_wsi->mux.child_count + 1 > parent_wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) { lwsl_notice("reached concurrent stream limit\n"); return NULL; @@ -185,19 +185,12 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, } h2n->highest_sid_opened = sid; - wsi->h2.my_sid = sid; - wsi->http2_substream = 1; + + lws_wsi_mux_insert(wsi, parent_wsi, sid); + + wsi->mux_substream = 1; wsi->seen_nonpseudoheader = 0; - wsi->h2.parent_wsi = parent_wsi; - wsi->role_ops = parent_wsi->role_ops; - /* new guy's sibling is whoever was the first child before */ - wsi->h2.sibling_list = parent_wsi->h2.child_list; - /* first child is now the new guy */ - parent_wsi->h2.child_list = wsi; - parent_wsi->h2.child_count++; - - wsi->h2.my_priority = 16; wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE]; wsi->h2.peer_tx_cr_est = nwsi->vhost->h2.set.s[H2SET_INITIAL_WINDOW_SIZE]; @@ -225,8 +218,8 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, bail1: /* undo the insert */ - parent_wsi->h2.child_list = wsi->h2.sibling_list; - parent_wsi->h2.child_count--; + parent_wsi->mux.child_list = wsi->mux.sibling_list; + parent_wsi->mux.child_count--; vh->context->count_wsi_allocated--; @@ -245,7 +238,7 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi) struct lws *nwsi = lws_get_network_wsi(parent_wsi); /* no more children allowed by parent */ - if (parent_wsi->h2.child_count + 1 > + if (parent_wsi->mux.child_count + 1 > parent_wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) { lwsl_notice("reached concurrent stream limit\n"); return NULL; @@ -255,18 +248,12 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi) wsi->seen_nonpseudoheader = 0; #if defined(LWS_WITH_CLIENT) - wsi->client_h2_substream = 1; + wsi->client_mux_substream = 1; #endif wsi->h2.initialized = 1; - wsi->h2.parent_wsi = parent_wsi; - /* new guy's sibling is whoever was the first child before */ - wsi->h2.sibling_list = parent_wsi->h2.child_list; - /* first child is now the new guy */ - parent_wsi->h2.child_list = wsi; - parent_wsi->h2.child_count++; + lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid); - wsi->h2.my_priority = 16; wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE]; wsi->h2.peer_tx_cr_est = nwsi->vhost->h2.set.s[H2SET_INITIAL_WINDOW_SIZE]; @@ -287,8 +274,8 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi) bail1: /* undo the insert */ - parent_wsi->h2.child_list = wsi->h2.sibling_list; - parent_wsi->h2.child_count--; + parent_wsi->mux.child_list = wsi->mux.sibling_list; + parent_wsi->mux.child_count--; if (wsi->user_space) lws_free_set_NULL(wsi->user_space); @@ -326,32 +313,6 @@ int lws_h2_issue_preface(struct lws *wsi) return 0; } -struct lws * -lws_h2_wsi_from_id(struct lws *parent_wsi, unsigned int sid) -{ - lws_start_foreach_ll(struct lws *, wsi, parent_wsi->h2.child_list) { - if (wsi->h2.my_sid == sid) - return wsi; - } lws_end_foreach_ll(wsi, h2.sibling_list); - - return NULL; -} - -int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi) -{ - lws_start_foreach_llp(struct lws **, w, wsi->h2.child_list) { - if (*w == wsi) { - *w = wsi->h2.sibling_list; - (wsi->h2.parent_wsi)->h2.child_count--; - return 0; - } - } lws_end_foreach_llp(w, h2.sibling_list); - - lwsl_err("%s: can't find %p\n", __func__, wsi); - - return 1; -} - void lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps) { @@ -408,9 +369,9 @@ lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason) return 1; lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__, (int)err, - wsi->h2.my_sid, reason); + wsi->mux.my_sid, reason); - pps->u.rs.sid = wsi->h2.my_sid; + pps->u.rs.sid = wsi->mux.my_sid; pps->u.rs.err = err; lws_pps_schedule(wsi, pps); @@ -486,7 +447,7 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings, */ lws_start_foreach_ll(struct lws *, w, - nwsi->h2.child_list) { + nwsi->mux.child_list) { lwsl_info("%s: adi child tc cr %d +%d -> %d", __func__, w->h2.tx_cr, b - (unsigned int)settings->s[a], @@ -496,7 +457,7 @@ lws_h2_settings(struct lws *wsi, struct http2_settings *settings, w->h2.tx_cr <= (int32_t)(b - settings->s[a])) lws_callback_on_writable(w); - } lws_end_foreach_ll(w, h2.sibling_list); + } lws_end_foreach_ll(w, mux.sibling_list); break; case H2SET_MAX_FRAME_SIZE: @@ -553,7 +514,7 @@ lws_h2_tx_cr_get(struct lws *wsi) int c = wsi->h2.tx_cr; struct lws *nwsi = lws_get_network_wsi(wsi); - if (!wsi->http2_substream && !nwsi->upgraded_to_http2) + if (!wsi->mux_substream && !nwsi->upgraded_to_http2) return ~0x80000000; lwsl_info ("%s: %p: own tx credit %d: nwsi credit %d\n", @@ -794,7 +755,7 @@ int lws_h2_do_pps_send(struct lws *wsi) lwsl_info("send %d %d\n", n, m); goto bail; } - cwsi = lws_h2_wsi_from_id(wsi, pps->u.rs.sid); + cwsi = lws_wsi_mux_from_id(wsi, pps->u.rs.sid); if (cwsi) { lwsl_debug("%s: closing cwsi %p %s %s (wsi %p)\n", __func__, cwsi, cwsi->role_ops->name, @@ -870,7 +831,7 @@ lws_h2_parse_frame_header(struct lws *wsi) wsi->vhost->keepalive_timeout : 31); if (h2n->sid) - h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid); + h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid); lwsl_debug("%p (%p): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n", wsi, h2n->swsi, h2n->type, h2n->flags, (unsigned int)h2n->sid, @@ -1127,7 +1088,7 @@ lws_h2_parse_frame_header(struct lws *wsi) #if defined(LWS_WITH_CLIENT) if (wsi->client_h2_alpn) { if (h2n->sid) { - h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid); + h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid); lwsl_info("HEADERS: nwsi %p: sid %u mapped " "to wsi %p\n", wsi, (unsigned int)h2n->sid, h2n->swsi); @@ -1140,7 +1101,7 @@ lws_h2_parse_frame_header(struct lws *wsi) if (!h2n->swsi) { /* no more children allowed by parent */ - if (wsi->h2.child_count + 1 > + if (wsi->mux.child_count + 1 > wsi->h2.h2n->set.s[H2SET_MAX_CONCURRENT_STREAMS]) { lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Another stream not allowed"); @@ -1195,12 +1156,12 @@ lws_h2_parse_frame_header(struct lws *wsi) * transitions to the "closed" state when the first frame for * stream 7 is sent or received. */ - lws_start_foreach_ll(struct lws *, w, wsi->h2.child_list) { - if (w->h2.my_sid < h2n->sid && + lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) { + if (w->mux.my_sid < h2n->sid && w->h2.h2_state == LWS_H2_STATE_IDLE) lws_close_free_wsi(w, 0, "h2 sid close"); - assert(w->h2.sibling_list != w); - } lws_end_foreach_ll(w, h2.sibling_list); + assert(w->mux.sibling_list != w); + } lws_end_foreach_ll(w, mux.sibling_list); if (lws_check_opt(h2n->swsi->vhost->options, LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) { @@ -1210,7 +1171,7 @@ lws_h2_parse_frame_header(struct lws *wsi) * half-closed remote state, allowing immortal long * poll */ - lws_http_mark_immortal(h2n->swsi); + lws_mux_mark_immortal(h2n->swsi); lwsl_info("%s: %p: h2 stream entering long poll\n", __func__, h2n->swsi); @@ -1299,7 +1260,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) h2n->count = 0; if (h2n->sid) - h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid); + h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid); if (h2n->sid > h2n->highest_sid) h2n->highest_sid = h2n->sid; @@ -1322,7 +1283,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) case LWS_H2_FRAME_TYPE_SETTINGS: #if defined(LWS_WITH_CLIENT) - if (wsi->client_h2_alpn && !wsi->client_h2_migrated && + if (wsi->client_h2_alpn && !wsi->client_mux_migrated && !(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) { struct lws_h2_protocol_send *pps; @@ -1331,7 +1292,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) wsi->http.fop_fd = NULL; #endif lwsl_info("%s: migrating\n", __func__); - wsi->client_h2_migrated = 1; + wsi->client_mux_migrated = 1; /* * we need to treat the headers from the upgrade as the * first job. So these need to get shifted to sid 1. @@ -1341,7 +1302,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) return 1; h2n->sid = 1; - assert(lws_h2_wsi_from_id(wsi, 1) == h2n->swsi); + assert(lws_wsi_mux_from_id(wsi, 1) == h2n->swsi); lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS, @@ -1353,7 +1314,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) /* pass on the initial headers to SID 1 */ h2n->swsi->http.ah = wsi->http.ah; - h2n->swsi->client_h2_substream = 1; + h2n->swsi->client_mux_substream = 1; #if defined(LWS_WITH_CLIENT) h2n->swsi->flags = wsi->flags; #endif @@ -1383,39 +1344,20 @@ lws_h2_parse_end_of_frame(struct lws *wsi) lws_callback_on_writable(h2n->swsi); - if (!wsi->h2_acked_settings -#if defined(LWS_WITH_CLIENT) - || !(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) -#endif + if (!wsi->h2_acked_settings || + !(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) ) { pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS); if (!pps) return 1; lws_pps_schedule(wsi, pps); - lwsl_info("%s: scheduled settings ack PPS\n", __func__); + lwsl_info("%s: SETTINGS ack PPS\n", __func__); wsi->h2_acked_settings = 1; } /* also attach any queued guys */ - /* we have a transaction queue that wants to pipeline */ - 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); - - if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) { - lwsl_info("%s: cli pipeq %p to be h2\n", - __func__, w); - /* remove ourselves from client queue */ - lws_dll2_remove(&w->dll2_cli_txn_queue); - - /* attach ourselves as an h2 stream */ - lws_wsi_h2_adopt(wsi, w); - } - } lws_end_foreach_dll_safe(d, d1); - lws_vhost_unlock(wsi->vhost); + lws_wsi_mux_apply_queue(wsi); } #endif break; @@ -1468,7 +1410,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) h2n->swsi->hdr_parsing_completed = 1; #if defined(LWS_WITH_CLIENT) - if (h2n->swsi->client_h2_substream) { + if (h2n->swsi->client_mux_substream) { if (lws_client_interpret_server_handshake(h2n->swsi)) { lwsl_info("%s: cli int serv hs closed it\n", __func__); break; @@ -1538,7 +1480,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) } #if defined(LWS_WITH_CLIENT) - if (h2n->swsi->client_h2_substream) { + if (h2n->swsi->client_mux_substream) { lwsl_info("%s: headers: client path\n", __func__); break; } @@ -1622,7 +1564,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) * send anything else anyway. */ - if (h2n->swsi->client_h2_substream && + if (h2n->swsi->client_mux_substream && (h2n->flags & LWS_H2_FLAG_END_STREAM)) { lwsl_info("%s: %p: DATA: end stream\n", __func__, h2n->swsi); @@ -1719,9 +1661,9 @@ lws_h2_parse_end_of_frame(struct lws *wsi) * It did change sendability... for us and any children waiting * on us... reassess blockage for all children first */ - lws_start_foreach_ll(struct lws *, w, wsi->h2.child_list) { + lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) { lws_callback_on_writable(w); - } lws_end_foreach_ll(w, h2.sibling_list); + } lws_end_foreach_ll(w, mux.sibling_list); if (eff_wsi->h2.skint && lws_h2_tx_cr_get(eff_wsi)) { lwsl_info("%s: %p: skint\n", __func__, wsi); @@ -1974,7 +1916,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, lwsl_debug("---- restricting len to %d vs %ld\n", n, (long)inlen + 1); } #if defined(LWS_WITH_CLIENT) - if (h2n->swsi->client_h2_substream) { + if (h2n->swsi->client_mux_substream) { if (!h2n->swsi->protocol) { lwsl_err("%s: swsi %pdoesn't have protocol\n", __func__, h2n->swsi); m = 1; @@ -2245,10 +2187,10 @@ lws_h2_client_handshake(struct lws *wsi) int sid = nwsi->h2.h2n->highest_sid_opened + 2; nwsi->h2.h2n->highest_sid_opened = sid; - wsi->h2.my_sid = sid; + wsi->mux.my_sid = sid; lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n", - __func__, wsi->h2.my_sid); + __func__, wsi->mux.my_sid); pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW); if (!pps) @@ -2526,7 +2468,7 @@ int lws_h2_client_stream_long_poll_rxonly(struct lws *wsi) { - if (!wsi->http2_substream) + if (!wsi->mux_substream) return 1; /* diff --git a/lib/roles/h2/ops-h2.c b/lib/roles/h2/ops-h2.c index d54bd94da..7e6a02195 100644 --- a/lib/roles/h2/ops-h2.c +++ b/lib/roles/h2/ops-h2.c @@ -164,7 +164,7 @@ rops_handle_POLLIN_h2(struct lws_context_per_thread *pt, struct lws *wsi, #endif } - if (wsi->http2_substream || wsi->upgraded_to_http2) { + if (wsi->mux_substream || wsi->upgraded_to_http2) { wsi1 = lws_get_network_wsi(wsi); if (wsi1 && lws_has_buffered_out(wsi1)) /* @@ -386,7 +386,7 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len, /* if not in a state to send stuff, then just send nothing */ - if (!lwsi_role_ws(wsi) && !wsi->h2_stream_immortal && + if (!lwsi_role_ws(wsi) && !wsi->mux_stream_immortal && base != LWS_WRITE_HTTP && base != LWS_WRITE_HTTP_FINAL && base != LWS_WRITE_HTTP_HEADERS_CONTINUATION && @@ -477,7 +477,7 @@ rops_write_role_protocol_h2(struct lws *wsi, unsigned char *buf, size_t len, wsi->h2.send_END_STREAM = 1; } - n = lws_h2_frame_write(wsi, n, flags, wsi->h2.my_sid, (int)len, buf); + n = lws_h2_frame_write(wsi, n, flags, wsi->mux.my_sid, (int)len, buf); if (n < 0) return n; @@ -500,7 +500,7 @@ rops_check_upgrades_h2(struct lws *wsi) */ p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD); if (!wsi->vhost->h2.set.s[H2SET_ENABLE_CONNECT_PROTOCOL] || - !wsi->http2_substream || !p || strcmp(p, "CONNECT")) + !wsi->mux_substream || !p || strcmp(p, "CONNECT")) return LWS_UPG_RET_CONTINUE; p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_COLON_PROTOCOL); @@ -511,7 +511,7 @@ rops_check_upgrades_h2(struct lws *wsi) wsi->vhost->conn_stats.ws_upg++; #endif lwsl_info("Upgrade h2 to ws\n"); - lws_http_mark_immortal(wsi); + lws_mux_mark_immortal(wsi); wsi->h2_stream_carries_ws = 1; if (lws_process_ws_upgrade(wsi)) @@ -599,7 +599,7 @@ rops_destroy_role_h2(struct lws *wsi) lws_http_compression_destroy(wsi); #endif - if (wsi->upgraded_to_http2 || wsi->http2_substream) { + if (wsi->upgraded_to_http2 || wsi->mux_substream) { lws_hpack_destroy_dynamic_header(wsi); if (wsi->h2.h2n) @@ -612,7 +612,6 @@ rops_destroy_role_h2(struct lws *wsi) static int rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason) { - struct lws *wsi2; #if defined(LWS_WITH_HTTP_PROXY) if (wsi->http.proxy_clientside) { @@ -628,53 +627,28 @@ rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason) } #endif - if (wsi->http2_substream && wsi->h2_stream_carries_ws) + if (wsi->mux_substream && wsi->h2_stream_carries_ws) lws_h2_rst_stream(wsi, 0, "none"); /* else - if (wsi->http2_substream) + if (wsi->mux_substream) lws_h2_rst_stream(wsi, H2_ERR_STREAM_CLOSED, "swsi got closed"); */ - if (wsi->h2.parent_wsi && lwsl_visible(LLL_INFO)) { - lwsl_info(" wsi: %p, his parent %p: siblings:\n", wsi, - wsi->h2.parent_wsi); - lws_start_foreach_llp(struct lws **, w, - wsi->h2.parent_wsi->h2.child_list) { - lwsl_info(" \\---- child %s %p\n", - (*w)->role_ops ? (*w)->role_ops->name : "?", *w); - } lws_end_foreach_llp(w, h2.sibling_list); - } + lwsl_info(" wsi: %p, his parent %p: siblings:\n", wsi, wsi->mux.parent_wsi); + lws_wsi_mux_dump_children(wsi); - if (wsi->upgraded_to_http2 || wsi->http2_substream + if (wsi->upgraded_to_http2 || wsi->mux_substream #if defined(LWS_WITH_CLIENT) - || wsi->client_h2_substream + || wsi->client_mux_substream #endif ) { - lwsl_info("closing %p: parent %p\n", wsi, wsi->h2.parent_wsi); + lwsl_info("closing %p: parent %p\n", wsi, wsi->mux.parent_wsi); - if (wsi->h2.child_list && lwsl_visible(LLL_INFO)) { + if (wsi->mux.child_list && lwsl_visible(LLL_INFO)) { lwsl_info(" parent %p: closing children: list:\n", wsi); - lws_start_foreach_llp(struct lws **, w, - wsi->h2.child_list) { - lwsl_info(" \\---- child %s %p\n", - (*w)->role_ops ? (*w)->role_ops->name : "?", - *w); - } lws_end_foreach_llp(w, h2.sibling_list); - } - if (wsi->h2.child_list) { - /* trigger closing of all of our http2 children first */ - lws_start_foreach_llp(struct lws **, w, - wsi->h2.child_list) { - lwsl_info(" closing child %p\n", *w); - /* disconnect from siblings */ - wsi2 = (*w)->h2.sibling_list; - (*w)->h2.sibling_list = NULL; - (*w)->socket_is_permanently_unusable = 1; - __lws_close_free_wsi(*w, reason, "h2 child recurse"); - *w = wsi2; - continue; - } lws_end_foreach_llp(w, h2.sibling_list); + lws_wsi_mux_dump_children(wsi); } + lws_wsi_mux_close_children(wsi, reason); } if (wsi->upgraded_to_http2) { @@ -691,25 +665,11 @@ rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason) if (( #if defined(LWS_WITH_CLIENT) - wsi->client_h2_substream || + wsi->client_mux_substream || #endif - wsi->http2_substream) && - wsi->h2.parent_wsi) { - lws_start_foreach_llp(struct lws **, w, - wsi->h2.parent_wsi->h2.child_list) { - - /* disconnect from siblings */ - if (*w == wsi) { - wsi2 = (*w)->h2.sibling_list; - (*w)->h2.sibling_list = NULL; - *w = wsi2; - lwsl_debug(" %p disentangled from sibling %p\n", - wsi, wsi2); - break; - } - } lws_end_foreach_llp(w, h2.sibling_list); - wsi->h2.parent_wsi->h2.child_count--; - wsi->h2.parent_wsi = NULL; + wsi->mux_substream) && + wsi->mux.parent_wsi) { + lws_wsi_mux_sibling_disconnect(wsi); if (wsi->h2.pending_status_body) lws_free_set_NULL(wsi->h2.pending_status_body); } @@ -720,7 +680,9 @@ rops_close_kill_connection_h2(struct lws *wsi, enum lws_close_status reason) static int rops_callback_on_writable_h2(struct lws *wsi) { - struct lws *network_wsi, *wsi2; +#if defined(LWS_WITH_CLIENT) + struct lws *network_wsi; +#endif int already; //lwsl_notice("%s: %p (wsistate 0x%x)\n", __func__, wsi, wsi->wsistate); @@ -728,7 +690,7 @@ rops_callback_on_writable_h2(struct lws *wsi) // if (!lwsi_role_h2(wsi) && !lwsi_role_h2_ENCAPSULATION(wsi)) // return 0; - if (wsi->h2.requested_POLLOUT + if (wsi->mux.requested_POLLOUT #if defined(LWS_WITH_CLIENT) && !wsi->client_h2_alpn #endif @@ -755,24 +717,17 @@ rops_callback_on_writable_h2(struct lws *wsi) } wsi->h2.skint = 0; +#if defined(LWS_WITH_CLIENT) network_wsi = lws_get_network_wsi(wsi); - already = network_wsi->h2.requested_POLLOUT; - - /* mark everybody above him as requesting pollout */ - - wsi2 = wsi; - while (wsi2) { - wsi2->h2.requested_POLLOUT = 1; - lwsl_info("mark %p pending writable\n", wsi2); - wsi2 = wsi2->h2.parent_wsi; - } +#endif + already = lws_wsi_mux_mark_parents_needing_writeable(wsi); /* for network action, act only on the network wsi */ if (already #if defined(LWS_WITH_CLIENT) && !network_wsi->client_h2_alpn - && !network_wsi->client_h2_substream + && !network_wsi->client_mux_substream #endif ) return 1; @@ -780,25 +735,6 @@ rops_callback_on_writable_h2(struct lws *wsi) return 0; } -static void -lws_h2_dump_waiting_children(struct lws *wsi) -{ -#if defined(_DEBUG) - lwsl_info("%s: %p: children waiting for POLLOUT service:\n", - __func__, wsi); - - wsi = wsi->h2.child_list; - while (wsi) { - lwsl_info(" %c %p %s %s\n", - wsi->h2.requested_POLLOUT ? '*' : ' ', - wsi, wsi->role_ops->name, wsi->protocol ? - wsi->protocol->name : "noprotocol"); - - wsi = wsi->h2.sibling_list; - } -#endif -} - #if defined(LWS_WITH_SERVER) static int lws_h2_bind_for_post_before_action(struct lws *wsi) @@ -859,7 +795,7 @@ lws_h2_bind_for_post_before_action(struct lws *wsi) static int rops_perform_user_POLLOUT_h2(struct lws *wsi) { - struct lws **wsi2, *wsi2a; + struct lws **wsi2; #if defined(LWS_ROLE_WS) int write_type = LWS_WRITE_PONG; #endif @@ -867,23 +803,23 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) wsi = lws_get_network_wsi(wsi); - wsi->h2.requested_POLLOUT = 0; + wsi->mux.requested_POLLOUT = 0; if (!wsi->h2.initialized) { lwsl_info("pollout on uninitialized http2 conn\n"); return 0; } - lws_h2_dump_waiting_children(wsi); + lws_wsi_mux_dump_waiting_children(wsi); - wsi2 = &wsi->h2.child_list; + wsi2 = &wsi->mux.child_list; if (!*wsi2) return 0; do { struct lws *w, **wa; - wa = &(*wsi2)->h2.sibling_list; - if (!(*wsi2)->h2.requested_POLLOUT) + wa = &(*wsi2)->mux.sibling_list; + if (!(*wsi2)->mux.requested_POLLOUT) goto next_child; /* @@ -893,32 +829,13 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lwsl_debug("servicing child %p\n", *wsi2); - w = *wsi2; - while (w) { - if (!w->h2.sibling_list) { /* w is the current last */ - lwsl_debug("w=%p, *wsi2 = %p\n", w, *wsi2); - if (w == *wsi2) /* we are already last */ - break; - /* last points to us as new last */ - w->h2.sibling_list = *wsi2; - /* guy pointing to us until now points to - * our old next */ - *wsi2 = (*wsi2)->h2.sibling_list; - /* we point to nothing because we are last */ - w->h2.sibling_list->h2.sibling_list = NULL; - /* w becomes us */ - w = w->h2.sibling_list; - break; - } - w = w->h2.sibling_list; - } + w = lws_wsi_mux_move_child_to_tail(wsi2); if (!w) { - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } - w->h2.requested_POLLOUT = 0; lwsl_info("%s: child %p (wsistate 0x%x)\n", __func__, w, (unsigned int)w->wsistate); @@ -930,11 +847,11 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lwsl_info("%s signalling to close\n", __func__); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 end stream 1"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } lws_callback_on_writable(w); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } @@ -956,7 +873,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) "comp write fail"); } lws_callback_on_writable(w); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } #endif @@ -967,7 +884,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) w->socket_is_permanently_unusable = 1; lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 end stream 1"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } @@ -984,7 +901,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lws_free_set_NULL(w->h2.pending_status_body); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 end stream 1"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } @@ -1031,11 +948,11 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lwsl_info("closing stream after h2 action\n"); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 end stream"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; } if (n < 0) - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } @@ -1063,7 +980,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lwsl_debug("Closing POLLOUT child %p\n", w); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 end stream file"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } if (n > 0) @@ -1071,7 +988,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) return -1; if (!n) { lws_callback_on_writable(w); - (w)->h2.requested_POLLOUT = 1; + (w)->mux.requested_POLLOUT = 1; } goto next_child; @@ -1126,12 +1043,12 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lwsi_set_state(w, LRS_RETURNED_CLOSE); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "returned close packet"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; goto next_child; } lws_callback_on_writable(w); - (w)->h2.requested_POLLOUT = 1; + (w)->mux.requested_POLLOUT = 1; /* otherwise for PING, leave POLLOUT active both ways */ goto next_child; @@ -1154,7 +1071,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) &wp)) { lwsl_info("%s: wsi %p: entering ro long poll\n", __func__, w); - lws_http_mark_immortal(w); + lws_mux_mark_immortal(w); } else lwsl_err("%s: wsi %p: failed to set long poll\n", __func__, w); @@ -1166,7 +1083,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) w->h2.send_END_STREAM); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 pollout handle"); - wa = &wsi->h2.child_list; + wa = &wsi->mux.child_list; } else if (w->h2.send_END_STREAM) lws_h2_state(w, LWS_H2_STATE_HALF_CLOSED_LOCAL); @@ -1175,17 +1092,10 @@ next_child: wsi2 = wa; } while (wsi2 && *wsi2 && !lws_send_pipe_choked(wsi)); - // lws_h2_dump_waiting_children(wsi); + // lws_wsi_mux_dump_waiting_children(wsi); - wsi2a = wsi->h2.child_list; - while (wsi2a) { - if (wsi2a->h2.requested_POLLOUT) { - if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) - return -1; - break; - } - wsi2a = wsi2a->h2.sibling_list; - } + if (lws_wsi_mux_action_pending_writeable_reqs(wsi)) + return -1; return 0; } @@ -1193,8 +1103,8 @@ next_child: static struct lws * rops_encapsulation_parent_h2(struct lws *wsi) { - if (wsi->h2.parent_wsi) - return wsi->h2.parent_wsi; + if (wsi->mux.parent_wsi) + return wsi->mux.parent_wsi; return NULL; } diff --git a/lib/roles/h2/private-lib-roles-h2.h b/lib/roles/h2/private-lib-roles-h2.h index 6c3b382d3..82c624bfc 100644 --- a/lib/roles/h2/private-lib-roles-h2.h +++ b/lib/roles/h2/private-lib-roles-h2.h @@ -315,37 +315,25 @@ struct lws_h2_netconn { struct _lws_h2_related { - struct lws_h2_netconn *h2n; /* malloc'd for root net conn */ - struct lws *parent_wsi; - struct lws *child_list; - struct lws *sibling_list; + struct lws_h2_netconn *h2n; /* malloc'd for root net conn */ - char *pending_status_body; + char *pending_status_body; - int tx_cr; - int peer_tx_cr_est; - unsigned int my_sid; - unsigned int child_count; - int my_priority; - uint32_t dependent_on; + int tx_cr; + int peer_tx_cr_est; - uint16_t END_STREAM:1; - uint16_t END_HEADERS:1; - uint16_t send_END_STREAM:1; - uint16_t long_poll:1; - uint16_t GOING_AWAY; - uint16_t requested_POLLOUT:1; - uint16_t skint:1; + uint8_t END_STREAM:1; + uint8_t END_HEADERS:1; + uint8_t send_END_STREAM:1; + uint8_t long_poll:1; + uint8_t GOING_AWAY; + uint8_t skint:1; + uint8_t initialized:1; - uint16_t round_robin_POLLOUT; - uint16_t count_POLLOUT_children; - - uint8_t h2_state; /* the RFC7540 state of the connection */ - uint8_t weight; - uint8_t initialized; + uint8_t h2_state; /* RFC7540 state of the connection */ }; -#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->h2.parent_wsi) +#define HTTP2_IS_TOPLEVEL_WSI(wsi) (!wsi->mux.parent_wsi) int lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason); @@ -363,7 +351,7 @@ LWS_EXTERN int lws_h2_frame_write(struct lws *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf); LWS_EXTERN struct lws * -lws_h2_wsi_from_id(struct lws *wsi, unsigned int sid); +lws_wsi_mux_from_id(struct lws *wsi, unsigned int sid); LWS_EXTERN int lws_hpack_interpret(struct lws *wsi, unsigned char c); LWS_EXTERN int diff --git a/lib/roles/http/client/client-handshake.c b/lib/roles/http/client/client-handshake.c index 496b5315f..83f6301f0 100644 --- a/lib/roles/http/client/client-handshake.c +++ b/lib/roles/http/client/client-handshake.c @@ -1099,7 +1099,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port, lws_free_set_NULL(stash); #if defined(LWS_WITH_HTTP2) - if (wsi->client_h2_substream) + if (wsi->client_mux_substream) wsi->h2.END_STREAM = wsi->h2.END_HEADERS = 0; #endif diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c index a1b8176d8..de3357fd3 100644 --- a/lib/roles/http/client/client-http.c +++ b/lib/roles/http/client/client-http.c @@ -642,7 +642,7 @@ lws_http_transaction_completed_client(struct lws *wsi) n = _lws_generic_transaction_completed_active_conn(wsi); if (wsi->http.ah) { - if (wsi->client_h2_substream) + if (wsi->client_mux_substream) /* * As an h2 client, once we did our transaction, that is * it for us. Further transactions will happen as new @@ -729,7 +729,7 @@ lws_client_interpret_server_handshake(struct lws *wsi) /* we are being an http client... */ #if defined(LWS_ROLE_H2) - if (wsi->client_h2_alpn || wsi->client_h2_substream) { + if (wsi->client_h2_alpn || wsi->client_mux_substream) { lwsl_debug("%s: %p: transitioning to h2 client\n", __func__, wsi); lws_role_transition(wsi, LWSIFR_CLIENT, @@ -767,7 +767,7 @@ lws_client_interpret_server_handshake(struct lws *wsi) */ wsi->http.conn_type = HTTP_CONNECTION_KEEP_ALIVE; - if (!wsi->client_h2_substream) { + if (!wsi->client_mux_substream) { p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP); if (wsi->do_ws && !p) { lwsl_info("no URI\n"); @@ -910,7 +910,7 @@ lws_client_interpret_server_handshake(struct lws *wsi) /* if h1 KA is allowed, enable the queued pipeline guys */ - if (!wsi->client_h2_alpn && !wsi->client_h2_substream && + if (!wsi->client_h2_alpn && !wsi->client_mux_substream && w == wsi) { /* ie, coming to this for the first time */ if (wsi->http.conn_type == HTTP_CONNECTION_KEEP_ALIVE) wsi->keepalive_active = 1; diff --git a/lib/roles/http/header.c b/lib/roles/http/header.c index 167de36b1..adcdc9ead 100644 --- a/lib/roles/http/header.c +++ b/lib/roles/http/header.c @@ -186,7 +186,7 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code, /* there was no length... it normally means CONNECTION_CLOSE */ #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) - if (!wsi->http2_substream && wsi->http.lcs) { + if (!wsi->mux_substream && wsi->http.lcs) { /* so... * - h1 connection * - http compression transform active @@ -208,7 +208,7 @@ lws_add_http_common_headers(struct lws *wsi, unsigned int code, t = 1; } #endif - if (!wsi->http2_substream) { + if (!wsi->mux_substream) { if (lws_add_http_header_by_token(wsi, WSI_TOKEN_CONNECTION, (unsigned char *)ka[t], @@ -437,7 +437,7 @@ lws_return_http_status(struct lws *wsi, unsigned int code, return 1; #if defined(LWS_WITH_HTTP2) - if (wsi->http2_substream) { + if (wsi->mux_substream) { /* * for HTTP/2, the headers must be sent separately, since they diff --git a/lib/roles/http/parsers.c b/lib/roles/http/parsers.c index 985e7d601..4cae75e0a 100644 --- a/lib/roles/http/parsers.c +++ b/lib/roles/http/parsers.c @@ -575,7 +575,7 @@ lws_hdr_custom_length(struct lws *wsi, const char *name, int nlen) { ah_data_idx_t ll; - if (!wsi->http.ah || wsi->http2_substream) + if (!wsi->http.ah || wsi->mux_substream) return -1; ll = wsi->http.ah->unk_ll_head; @@ -601,7 +601,7 @@ lws_hdr_custom_copy(struct lws *wsi, char *dst, int len, const char *name, ah_data_idx_t ll; int n; - if (!wsi->http.ah || wsi->http2_substream) + if (!wsi->http.ah || wsi->mux_substream) return -1; *dst = '\0'; @@ -1085,7 +1085,7 @@ swallow: * a known header, we'll snip this. */ - if (!wsi->http2_substream && !ah->unk_pos) { + if (!wsi->mux_substream && !ah->unk_pos) { ah->unk_pos = ah->pos; /* * Prepare new unknown header linked-list entry @@ -1107,7 +1107,7 @@ swallow: pos = ah->lextable_pos; #if defined(LWS_WITH_CUSTOM_HEADERS) - if (!wsi->http2_substream && pos < 0 && c == ':') { + if (!wsi->mux_substream && pos < 0 && c == ':') { #if defined(_DEBUG) char dotstar[64]; int uhlen; @@ -1181,7 +1181,7 @@ nope: /* b7 = 0, end or 3-byte */ if (lextable[pos] < FAIL_CHAR) { #if defined(LWS_WITH_CUSTOM_HEADERS) - if (!wsi->http2_substream) { + if (!wsi->mux_substream) { /* * We hit a terminal marker, so * we recognized this header... @@ -1227,7 +1227,7 @@ nope: #if !defined(LWS_WITH_CUSTOM_HEADERS) ah->parser_state = WSI_TOKEN_SKIPPING; #endif - if (wsi->http2_substream) + if (wsi->mux_substream) ah->parser_state = WSI_TOKEN_SKIPPING; break; } @@ -1238,7 +1238,7 @@ nope: * We have the method, this is just an * unknown header then */ - if (!wsi->http2_substream) + if (!wsi->mux_substream) goto unknown_hdr; else break; @@ -1266,7 +1266,7 @@ nope: } if (ah->lextable_pos < 0) { #if defined(LWS_WITH_CUSTOM_HEADERS) - if (!wsi->http2_substream) + if (!wsi->mux_substream) goto unknown_hdr; #endif /* @@ -1321,7 +1321,7 @@ nope: unknown_hdr: //ah->parser_state = WSI_TOKEN_SKIPPING; //break; - if (!wsi->http2_substream) + if (!wsi->mux_substream) break; #endif diff --git a/lib/roles/http/server/access-log.c b/lib/roles/http/server/access-log.c index f59dbaabf..0ac261066 100644 --- a/lib/roles/http/server/access-log.c +++ b/lib/roles/http/server/access-log.c @@ -70,7 +70,7 @@ lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int uri_len, int met else strcpy(da, "01/Jan/1970:00:00:00 +0000"); - if (wsi->http2_substream) + if (wsi->mux_substream) me = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD); else me = method_names[meth]; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 303c4af6c..53ee8eacf 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -697,7 +697,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, if (n > (int)strlen(pvo->name) && !strcmp(&path[n - strlen(pvo->name)], pvo->name)) { wsi->interpreting = 1; - if (!wsi->http2_substream) + if (!wsi->mux_substream) wsi->sending_chunked = 1; wsi->protocol_interpret_idx = (char)( @@ -777,7 +777,7 @@ lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len) lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) || lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) || lws_hdr_total_length(wsi, WSI_TOKEN_HEAD_URI) || - (wsi->http2_substream && + (wsi->mux_substream && lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH)) || hm->protocol) && @@ -930,7 +930,7 @@ lws_http_get_uri_and_method(struct lws *wsi, char **puri_ptr, int *puri_len) } if (count != 1 && - !((wsi->http2_substream || wsi->h2_stream_carries_ws) && + !((wsi->mux_substream || wsi->h2_stream_carries_ws) && lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH))) { lwsl_warn("multiple methods?\n"); return -1; @@ -1311,7 +1311,7 @@ lws_http_action(struct lws *wsi) } } - if (wsi->http2_substream) { + if (wsi->mux_substream) { wsi->http.request_version = HTTP_VERSION_2; } else { /* http_version? Default to 1.0, override with token: */ @@ -1359,7 +1359,7 @@ lws_http_action(struct lws *wsi) * if there is content supposed to be coming, * put a timeout on it having arrived */ - if (!wsi->h2_stream_immortal) + if (!wsi->mux_stream_immortal) lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, wsi->context->timeout_secs); #ifdef LWS_WITH_TLS @@ -1659,7 +1659,7 @@ deal_body: /* Prepare to read body if we have a content length: */ lwsl_debug("wsi->http.rx_content_length %lld %d %d\n", (long long)wsi->http.rx_content_length, - wsi->upgraded_to_http2, wsi->http2_substream); + wsi->upgraded_to_http2, wsi->mux_substream); if (wsi->http.content_length_explicitly_zero && lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) { @@ -2265,7 +2265,7 @@ lws_http_transaction_completed(struct lws *wsi) #endif /* if we can't go back to accept new headers, drop the connection */ - if (wsi->http2_substream) + if (wsi->mux_substream) return 1; if (wsi->seen_zero_length_recv) @@ -2414,7 +2414,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL)) return -1; - return !wsi->http2_substream; + return !wsi->mux_substream; } } @@ -2558,7 +2558,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, goto bail; #endif - if (!wsi->http2_substream) { + if (!wsi->mux_substream) { /* for http/1.1 ... */ if (!wsi->sending_chunked #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) @@ -2686,7 +2686,7 @@ LWS_VISIBLE int lws_serve_http_file_fragment(struct lws *wsi) #endif int n, m; - lwsl_debug("wsi->http2_substream %d\n", wsi->http2_substream); + lwsl_debug("wsi->mux_substream %d\n", wsi->mux_substream); do { @@ -2924,7 +2924,7 @@ all_sent: * state, not the root connection at the * network level */ - if (wsi->http2_substream) + if (wsi->mux_substream) return 1; else return -1; diff --git a/lib/roles/ws/client-ws.c b/lib/roles/ws/client-ws.c index fe117bf6a..8f6b9e767 100644 --- a/lib/roles/ws/client-ws.c +++ b/lib/roles/ws/client-ws.c @@ -257,7 +257,7 @@ lws_client_ws_upgrade(struct lws *wsi, const char **cce) wsi->detlat.earliest_write_req_pre_write = 0; #endif - if (wsi->client_h2_substream) {/* !!! client ws-over-h2 not there yet */ + if (wsi->client_mux_substream) {/* !!! client ws-over-h2 not there yet */ lwsl_warn("%s: client ws-over-h2 upgrade not supported yet\n", __func__); *cce = "HS: h2 / ws upgrade unsupported"; diff --git a/lib/roles/ws/ops-ws.c b/lib/roles/ws/ops-ws.c index baf150fa0..012448b99 100644 --- a/lib/roles/ws/ops-ws.c +++ b/lib/roles/ws/ops-ws.c @@ -1052,7 +1052,7 @@ rops_handle_POLLIN_ws(struct lws_context_per_thread *pt, struct lws *wsi, return LWS_HPI_RET_HANDLED; #if defined(LWS_WITH_HTTP2) - if (wsi->http2_substream || wsi->upgraded_to_http2) { + if (wsi->mux_substream || wsi->upgraded_to_http2) { wsi1 = lws_get_network_wsi(wsi); if (wsi1 && lws_has_buffered_out(wsi1)) /* We cannot deal with any kind of new RX @@ -1329,7 +1329,7 @@ int rops_handle_POLLOUT_ws(struct lws *wsi) lwsl_info("%s: issuing ping on wsi %p: %s %s h2: %d\n", __func__, wsi, wsi->role_ops->name, wsi->protocol->name, - wsi->http2_substream); + wsi->mux_substream); wsi->ws->send_check_ping = 0; n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE], 0, LWS_WRITE_PING); @@ -1914,7 +1914,7 @@ rops_close_kill_connection_ws(struct lws *wsi, enum lws_close_status reason) { /* deal with ws encapsulation in h2 */ #if defined(LWS_WITH_HTTP2) - if (wsi->http2_substream && wsi->h2_stream_carries_ws) + if (wsi->mux_substream && wsi->h2_stream_carries_ws) return role_ops_h2.close_kill_connection(wsi, reason); return 0; diff --git a/lib/roles/ws/server-ws.c b/lib/roles/ws/server-ws.c index 3f1813aa5..862564e3d 100644 --- a/lib/roles/ws/server-ws.c +++ b/lib/roles/ws/server-ws.c @@ -420,7 +420,7 @@ lws_process_ws_upgrade(struct lws *wsi) */ #if defined(LWS_WITH_HTTP2) - if (!wsi->http2_substream) { + if (!wsi->mux_substream) { #endif lws_tokenize_init(&ts, buf, LWS_TOKENIZE_F_COMMA_SEP_LIST | diff --git a/minimal-examples/selftests-library.sh b/minimal-examples/selftests-library.sh index 4bd6b06a7..5a924ac16 100755 --- a/minimal-examples/selftests-library.sh +++ b/minimal-examples/selftests-library.sh @@ -57,7 +57,7 @@ dotest() { T=$3 ( { - /usr/bin/time -p /usr/bin/valgrind $1/lws-$MYTEST $4 $5 $6 $7 $8 $9 > $2/$MYTEST/$T.log 2> $2/$MYTEST/$T.log ; + /usr/bin/time -p /usr/bin/valgrind -q $1/lws-$MYTEST $4 $5 $6 $7 $8 $9 > $2/$MYTEST/$T.log 2> $2/$MYTEST/$T.log ; echo $? > $2/$MYTEST/$T.result } 2> $2/$MYTEST/$T.time >/dev/null ) >/dev/null 2> /dev/null &