1
0
Fork 0
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:
Andy Green 2014-10-29 09:39:08 +08:00
parent 7f2878a503
commit 97ee57fa35
7 changed files with 92 additions and 12 deletions

View file

@ -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++)

View file

@ -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
}

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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));