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;
*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)
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...
}
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)
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];
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:
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;
}
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 */
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:
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);
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;
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++)
#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,
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,