mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
http2 window update
Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
7f2878a503
commit
97ee57fa35
7 changed files with 92 additions and 12 deletions
37
lib/http2.c
37
lib/http2.c
|
@ -74,6 +74,7 @@ lws_create_server_child_wsi(struct libwebsocket_context *context, struct libwebs
|
|||
parent_wsi->u.http2.child_count++;
|
||||
|
||||
wsi->u.http2.my_priority = 16;
|
||||
wsi->u.http2.tx_credit = 65535;
|
||||
|
||||
wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
|
||||
wsi->mode = parent_wsi->mode;
|
||||
|
@ -156,7 +157,13 @@ int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigne
|
|||
*p++ = sid;
|
||||
|
||||
lwsl_info("%s: %p (eff %p). type %d, flags 0x%x, sid=%d, len=%d\n",
|
||||
__func__, wsi, wsi_eff, type, flags, sid, len);
|
||||
__func__, wsi, wsi_eff, type, flags, sid, len, wsi->u.http2.tx_credit);
|
||||
|
||||
if (type == LWS_HTTP2_FRAME_TYPE_DATA) {
|
||||
if (wsi->u.http2.tx_credit < len)
|
||||
lwsl_err("%s: %p: sending payload len %d but tx_credit only %d!\n", len, wsi->u.http2.tx_credit);
|
||||
wsi->u.http2.tx_credit -= len;
|
||||
}
|
||||
|
||||
n = lws_issue_raw(wsi_eff, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH], len + LWS_HTTP2_FRAME_HEADER_LENGTH);
|
||||
if (n >= LWS_HTTP2_FRAME_HEADER_LENGTH)
|
||||
|
@ -195,6 +202,7 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
lwsl_info("http2: %p: established\n", wsi);
|
||||
wsi->state = WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS;
|
||||
wsi->u.http2.count = 0;
|
||||
wsi->u.http2.tx_credit = 65535;
|
||||
|
||||
/*
|
||||
* we must send a settings frame -- empty one is OK...
|
||||
|
@ -255,6 +263,8 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
}
|
||||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE:
|
||||
wsi->u.http2.hpack_e_dep <<= 8;
|
||||
wsi->u.http2.hpack_e_dep |= c;
|
||||
break;
|
||||
}
|
||||
if (wsi->u.http2.count != wsi->u.http2.length)
|
||||
|
@ -264,6 +274,7 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
|
||||
wsi->u.http2.frame_state = 0;
|
||||
wsi->u.http2.count = 0;
|
||||
swsi = wsi->u.http2.stream_wsi;
|
||||
/* set our initial window size */
|
||||
if (!wsi->u.http2.initialized) {
|
||||
wsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE];
|
||||
|
@ -274,7 +285,7 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
case LWS_HTTP2_FRAME_TYPE_HEADERS:
|
||||
/* service the http request itself */
|
||||
lwsl_info("servicing initial http request, wsi=%p, stream wsi=%p\n", wsi, wsi->u.http2.stream_wsi);
|
||||
n = lws_http_action(context, wsi->u.http2.stream_wsi);
|
||||
n = lws_http_action(context, swsi);
|
||||
lwsl_info(" action result %d\n", n);
|
||||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_PING:
|
||||
|
@ -283,6 +294,17 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
lws_set_protocol_write_pending(context, wsi, LWS_PPS_HTTP2_PONG);
|
||||
}
|
||||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE:
|
||||
wsi->u.http2.hpack_e_dep &= ~(1 << 31);
|
||||
if ((long long)swsi->u.http2.tx_credit + (unsigned long long)wsi->u.http2.hpack_e_dep > (~(1 << 31)))
|
||||
return 1; /* actually need to close swsi not the whole show */
|
||||
swsi->u.http2.tx_credit += wsi->u.http2.hpack_e_dep;
|
||||
if (swsi->u.http2.waiting_tx_credit && swsi->u.http2.tx_credit > 0) {
|
||||
lwsl_info("%s: %p: waiting_tx_credit -> wait on writeable\n", __func__, wsi);
|
||||
swsi->u.http2.waiting_tx_credit = 0;
|
||||
libwebsocket_callback_on_writable(context, swsi);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -307,7 +329,6 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
case 8:
|
||||
wsi->u.http2.stream_id <<= 8;
|
||||
wsi->u.http2.stream_id |= c;
|
||||
wsi->u.http2.stream_wsi = wsi;
|
||||
break;
|
||||
}
|
||||
if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { /* frame header complete */
|
||||
|
@ -315,6 +336,9 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
wsi->u.http2.type, wsi->u.http2.flags, wsi->u.http2.stream_id, wsi->u.http2.length);
|
||||
wsi->u.http2.count = 0;
|
||||
|
||||
wsi->u.http2.stream_wsi = wsi;
|
||||
if (wsi->u.http2.stream_id)
|
||||
wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
|
||||
|
||||
switch (wsi->u.http2.type) {
|
||||
case LWS_HTTP2_FRAME_TYPE_SETTINGS:
|
||||
|
@ -342,7 +366,6 @@ lws_http2_parser(struct libwebsocket_context *context,
|
|||
lwsl_info("LWS_HTTP2_FRAME_TYPE_HEADERS: stream_id = %d\n", wsi->u.http2.stream_id);
|
||||
if (!wsi->u.http2.stream_id)
|
||||
return 1;
|
||||
wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
|
||||
if (!wsi->u.http2.stream_wsi)
|
||||
wsi->u.http2.stream_wsi = lws_create_server_child_wsi(context, wsi, wsi->u.http2.stream_id);
|
||||
|
||||
|
@ -374,6 +397,10 @@ update_end_headers:
|
|||
swsi->u.http2.hpack = HPKS_TYPE;
|
||||
lwsl_info("initial hpack state %d\n", swsi->u.http2.hpack);
|
||||
break;
|
||||
case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE:
|
||||
if (wsi->u.http2.length != 4)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
if (wsi->u.http2.length == 0)
|
||||
wsi->u.http2.frame_state = 0;
|
||||
|
@ -391,6 +418,8 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
|
|||
struct libwebsocket *swsi;
|
||||
int n, m = 0;
|
||||
|
||||
lwsl_debug("%s: %p: %d\n", __func__, wsi, wsi->pps);
|
||||
|
||||
switch (wsi->pps) {
|
||||
case LWS_PPS_HTTP2_MY_SETTINGS:
|
||||
for (n = 1; n < LWS_HTTP2_SETTINGS__COUNT; n++)
|
||||
|
|
|
@ -821,7 +821,7 @@ void lws_set_protocol_write_pending(struct libwebsocket_context *context,
|
|||
struct libwebsocket *wsi,
|
||||
enum lws_pending_protocol_send pend)
|
||||
{
|
||||
lwsl_err("setting pps %d\n", pend);
|
||||
lwsl_info("setting pps %d\n", pend);
|
||||
|
||||
if (wsi->pps)
|
||||
lwsl_err("pps overwrite\n");
|
||||
|
@ -829,3 +829,20 @@ void lws_set_protocol_write_pending(struct libwebsocket_context *context,
|
|||
libwebsocket_rx_flow_control(wsi, 0);
|
||||
libwebsocket_callback_on_writable(context, wsi);
|
||||
}
|
||||
|
||||
LWS_VISIBLE size_t
|
||||
lws_get_peer_write_allowance(struct libwebsocket *wsi)
|
||||
{
|
||||
#ifdef LWS_USE_HTTP2
|
||||
/* only if we are using HTTP2 on this connection */
|
||||
if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING)
|
||||
return -1;
|
||||
/* user is only interested in how much he can send, or that he can't */
|
||||
if (wsi->u.http2.tx_credit <= 0)
|
||||
return 0;
|
||||
|
||||
return wsi->u.http2.tx_credit;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -153,9 +153,11 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
|
|||
|
||||
#define LWS_FEATURE_SERVE_HTTP_FILE_HAS_OTHER_HEADERS_ARG
|
||||
|
||||
/* the struct libwebsocket_protocols has the id field present */
|
||||
/* the struct libwebsocket_protocols has the id field present */
|
||||
#define LWS_FEATURE_PROTOCOLS_HAS_ID_FIELD
|
||||
|
||||
/* you can call lws_get_peer_write_allowance */
|
||||
#define LWS_FEATURE_PROTOCOLS_HAS_PEER_WRITE_ALLOWANCE
|
||||
|
||||
enum libwebsocket_context_options {
|
||||
LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2,
|
||||
|
@ -1226,6 +1228,25 @@ libwebsocket_rx_flow_allow_all_protocol(
|
|||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
libwebsockets_remaining_packet_payload(struct libwebsocket *wsi);
|
||||
|
||||
/*
|
||||
* if the protocol does not have any guidence, returns -1. Currently only
|
||||
* http2 connections get send window information from this API. But your code
|
||||
* should use it so it can work properly with any protocol.
|
||||
*
|
||||
* If nonzero return is the amount of payload data the peer or intermediary has
|
||||
* reported it has buffer space for. That has NO relationship with the amount
|
||||
* of buffer space your OS can accept on this connection for a write action.
|
||||
*
|
||||
* This number represents the maximum you could send to the peer or intermediary
|
||||
* on this connection right now without it complaining.
|
||||
*
|
||||
* lws manages accounting for send window updates and payload writes
|
||||
* automatically, so this number reflects the situation at the peer or
|
||||
* intermediary dynamically.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
lws_get_peer_write_allowance(struct libwebsocket *wsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN struct libwebsocket *
|
||||
libwebsocket_client_connect(struct libwebsocket_context *clients,
|
||||
const char *address,
|
||||
|
|
13
lib/pollfd.c
13
lib/pollfd.c
|
@ -207,6 +207,19 @@ libwebsocket_callback_on_writable(struct libwebsocket_context *context,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (wsi->u.http2.tx_credit <= 0) {
|
||||
/*
|
||||
* other side is not able to cope with us sending
|
||||
* anything so no matter if we have POLLOUT on our side.
|
||||
*
|
||||
* Delay waiting for our POLLOUT until peer indicates he has
|
||||
* space for more using tx window command in http2 layer
|
||||
*/
|
||||
lwsl_info("%s: %p: waiting_tx_credit (%d)\n", __func__, wsi, wsi->u.http2.tx_credit);
|
||||
wsi->u.http2.waiting_tx_credit = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
network_wsi = lws_http2_get_network_wsi(wsi);
|
||||
already = network_wsi->u.http2.requested_POLLOUT;
|
||||
|
||||
|
|
|
@ -708,6 +708,7 @@ struct _lws_http2_related {
|
|||
unsigned int send_END_STREAM:1;
|
||||
unsigned int GOING_AWAY;
|
||||
unsigned int requested_POLLOUT:1;
|
||||
unsigned int waiting_tx_credit:1;
|
||||
|
||||
/* hpack */
|
||||
enum http2_hpack_state hpack;
|
||||
|
@ -720,7 +721,8 @@ struct _lws_http2_related {
|
|||
unsigned int huff:1;
|
||||
unsigned int value:1;
|
||||
|
||||
unsigned int tx_credit;
|
||||
/* negative credit is mandated by the spec */
|
||||
int tx_credit;
|
||||
unsigned int my_stream_id;
|
||||
unsigned int child_count;
|
||||
int my_priority;
|
||||
|
|
|
@ -426,9 +426,9 @@ upgrade_h2c:
|
|||
"HTTP/1.1 101 Switching Protocols\x0d\x0a"
|
||||
"Connection: Upgrade\x0d\x0a"
|
||||
"Upgrade: h2c\x0d\x0a\x0d\x0a");
|
||||
n = lws_issue_raw(wsi, (unsigned char *)wsi->protocol->name,
|
||||
strlen(wsi->protocol->name));
|
||||
if (n != strlen(wsi->protocol->name)) {
|
||||
n = lws_issue_raw(wsi, (unsigned char *)protocol_list,
|
||||
strlen(protocol_list));
|
||||
if (n != strlen(protocol_list)) {
|
||||
lwsl_debug("http2 switch: ERROR writing to socket\n");
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -140,8 +140,6 @@ void lws_http2_configure_if_upgraded(struct libwebsocket *wsi)
|
|||
|
||||
ah = wsi->u.hdr.ah;
|
||||
|
||||
wsi->mode = LWS_CONNMODE_HTTP2_SERVING;
|
||||
|
||||
/* union transition */
|
||||
memset(&wsi->u, 0, sizeof(wsi->u));
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue