mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
h2 ws: fixes against chrome
This commit is contained in:
parent
0e39e7f5c6
commit
302f8fad82
15 changed files with 598 additions and 397 deletions
17
README.md
17
README.md
|
@ -8,6 +8,23 @@ libwebsockets
|
|||
News
|
||||
----
|
||||
|
||||
## Lws has the first official ws-over-h2 server support
|
||||
|
||||
There's a new standard on the RFC track that enabled multiplexing ws connections
|
||||
over an http/2 link. Compared to making individual tcp and tls connections for
|
||||
each ws link back to the same server, this makes your site start up radically
|
||||
faster, and since all the connections are in one tls tunnel, with much memory
|
||||
reduction serverside.
|
||||
|
||||
To enable it on master you just need -DLWS_WITH_HTTP2=1 at cmake. No changes to
|
||||
existing code are necessary for either http/2 (if you use the official header creation
|
||||
apis if you return your own headers, as shown in the test apps for several versions)
|
||||
or to take advantage of ws-over-h2. When built with http/2 support, it automatically
|
||||
falls back to http/1 and traditional ws upgrade if that's all the client can handle.
|
||||
|
||||
Currently only Chrome Canary v67 supports this ws-over-h2 encapsulation but the other
|
||||
browsers will catch up soon.
|
||||
|
||||
## New "minimal examples"
|
||||
|
||||
https://github.com/warmcat/libwebsockets/tree/master/minimal-examples
|
||||
|
|
|
@ -65,9 +65,12 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
|||
unsigned char *last_char, *oldbuf = buf;
|
||||
lws_filepos_t body_chunk_len;
|
||||
size_t n;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
int m;
|
||||
#endif
|
||||
|
||||
switch (wsi->state) {
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
case LWSS_HTTP2_AWAIT_CLIENT_PREFACE:
|
||||
case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS:
|
||||
case LWSS_HTTP2_ESTABLISHED:
|
||||
|
@ -113,10 +116,17 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
|
|||
* file transfers operate.
|
||||
*/
|
||||
|
||||
if (lws_h2_parser(wsi, buf, len, &body_chunk_len)) {
|
||||
m = lws_h2_parser(wsi, buf, len, &body_chunk_len);
|
||||
if (m && m != 2) {
|
||||
lwsl_debug("%s: http2_parser bailed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
if (m && m == 2) {
|
||||
/* swsi has been closed */
|
||||
buf += body_chunk_len;
|
||||
len -= body_chunk_len;
|
||||
goto read_ok;
|
||||
}
|
||||
|
||||
/* account for what we're using in rxflow buffer */
|
||||
if (wsi->rxflow_buffer) {
|
||||
|
@ -277,12 +287,16 @@ postbody_completion:
|
|||
case LWSS_AWAITING_CLOSE_ACK:
|
||||
case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
|
||||
case LWSS_SHUTDOWN:
|
||||
case LWSS_SHUTDOWN | _LSF_POLLOUT | _LSF_CCB:
|
||||
if (lws_handshake_client(wsi, &buf, (size_t)len))
|
||||
goto bail;
|
||||
|
||||
switch (wsi->mode) {
|
||||
case LWSCM_WS_SERVING:
|
||||
case LWSCM_HTTP2_WS_SERVING:
|
||||
|
||||
/*
|
||||
* for h2 we are on the swsi
|
||||
*/
|
||||
if (lws_interpret_incoming_packet(wsi, &buf,
|
||||
(size_t)len) < 0) {
|
||||
lwsl_info("interpret_incoming_packet bailed\n");
|
||||
|
@ -296,6 +310,11 @@ postbody_completion:
|
|||
lwsl_debug("%s: LWSS_HTTP_DEFERRING_ACTION\n", __func__);
|
||||
break;
|
||||
|
||||
case LWSS_DEAD_SOCKET:
|
||||
lwsl_err("%s: Unhandled state LWSS_DEAD_SOCKET\n", __func__);
|
||||
assert(0);
|
||||
/* fallthru */
|
||||
|
||||
default:
|
||||
lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state);
|
||||
goto bail;
|
||||
|
@ -311,8 +330,10 @@ read_ok:
|
|||
bail:
|
||||
/*
|
||||
* h2 / h2-ws calls us recursively in lws_read()->lws_h2_parser()->
|
||||
* lws_read() pattern. Make sure that only the outer lws_read() does
|
||||
* the wsi close.
|
||||
* lws_read() pattern, having stripped the h2 framing in the middle.
|
||||
*
|
||||
* When taking down the whole connection, make sure that only the
|
||||
* outer lws_read() does the wsi close.
|
||||
*/
|
||||
if (!wsi->outer_will_close)
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "lws_read bail");
|
||||
|
|
|
@ -99,6 +99,8 @@ static const char * const h2_setting_names[] = {
|
|||
"H2SET_INITIAL_WINDOW_SIZE",
|
||||
"H2SET_MAX_FRAME_SIZE",
|
||||
"H2SET_MAX_HEADER_LIST_SIZE",
|
||||
"reserved",
|
||||
"H2SET_ENABLE_CONNECT_PROTOCOL"
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -465,6 +467,9 @@ int lws_h2_frame_write(struct lws *wsi, int type, int flags,
|
|||
unsigned char *p = &buf[-LWS_H2_FRAME_HEADER_LENGTH];
|
||||
int n;
|
||||
|
||||
//if (wsi->h2_stream_carries_ws)
|
||||
// lwsl_hexdump_level(LLL_NOTICE, buf, len);
|
||||
|
||||
*p++ = len >> 16;
|
||||
*p++ = len >> 8;
|
||||
*p++ = len;
|
||||
|
@ -658,7 +663,7 @@ int lws_h2_do_pps_send(struct lws *wsi)
|
|||
break;
|
||||
|
||||
case LWS_H2_PPS_UPDATE_WINDOW:
|
||||
lwsl_notice("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
|
||||
lwsl_debug("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n",
|
||||
pps->u.update_window.sid,
|
||||
pps->u.update_window.credit);
|
||||
*p++ = pps->u.update_window.credit >> 24;
|
||||
|
@ -714,10 +719,8 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
}
|
||||
|
||||
/* let the network wsi live a bit longer if subs are active */
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
|
||||
/* let the network wsi live a bit longer if subs are active */
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
if (!wsi->ws_over_h2_count)
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
|
||||
if (h2n->sid)
|
||||
h2n->swsi = lws_h2_wsi_from_id(wsi, h2n->sid);
|
||||
|
@ -737,6 +740,7 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
* peer sent us something bigger than we told
|
||||
* it we would allow
|
||||
*/
|
||||
lwsl_notice("received oversize frame %d\n", h2n->length);
|
||||
lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR,
|
||||
"Peer ignored our frame size setting");
|
||||
return 0;
|
||||
|
@ -749,9 +753,14 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
else {
|
||||
/* if it's data, either way no swsi means CLOSED state */
|
||||
if (h2n->type == LWS_H2_FRAME_TYPE_DATA) {
|
||||
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
|
||||
if (h2n->sid <= h2n->highest_sid_opened) {
|
||||
lwsl_notice("ignoring straggling data\n");
|
||||
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
||||
} else {
|
||||
lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED,
|
||||
"Data for nonexistent sid");
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* if the sid is credible, treat as wsi for it closed */
|
||||
if (h2n->sid > h2n->highest_sid_opened &&
|
||||
|
@ -838,6 +847,7 @@ lws_h2_parse_frame_header(struct lws *wsi)
|
|||
break;
|
||||
|
||||
case LWS_H2_FRAME_TYPE_GOAWAY:
|
||||
lwsl_debug("LWS_H2_FRAME_TYPE_GOAWAY received\n");
|
||||
break;
|
||||
|
||||
case LWS_H2_FRAME_TYPE_RST_STREAM:
|
||||
|
@ -1023,6 +1033,8 @@ update_end_headers:
|
|||
}
|
||||
lwsl_info("LWS_H2_FRAME_TYPE_WINDOW_UPDATE\n");
|
||||
break;
|
||||
case LWS_H2_FRAME_TYPE_COUNT:
|
||||
break;
|
||||
default:
|
||||
lwsl_info("%s: ILLEGAL FRAME TYPE %d\n", __func__, h2n->type);
|
||||
h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */
|
||||
|
@ -1303,6 +1315,11 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
|
||||
return 1;
|
||||
|
||||
case LWS_H2_FRAME_TYPE_RST_STREAM:
|
||||
lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %d: reason 0x%x\n",
|
||||
h2n->sid, h2n->hpack_e_dep);
|
||||
break;
|
||||
|
||||
case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */
|
||||
break;
|
||||
}
|
||||
|
@ -1322,6 +1339,9 @@ lws_h2_parse_end_of_frame(struct lws *wsi)
|
|||
* Therefore if we will send non-PPS, ie, lws_http_action() for a stream
|
||||
* wsi, we must change its state and handle it as a priority in the
|
||||
* POLLOUT handler instead of writing it here.
|
||||
*
|
||||
* About closing... for the main network wsi, it should return nonzero to
|
||||
* close it all. If it needs to close an swsi, it can do it here.
|
||||
*/
|
||||
int
|
||||
lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
||||
|
@ -1468,7 +1488,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|||
|
||||
/* let the network wsi live a bit longer if subs are active...
|
||||
* our frame may take a long time to chew through */
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
if (!wsi->ws_over_h2_count)
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
|
||||
if (!h2n->swsi)
|
||||
break;
|
||||
|
@ -1505,8 +1526,13 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|||
* can return 0 in POST body with content len
|
||||
* exhausted somehow.
|
||||
*/
|
||||
if (n <= 0)
|
||||
goto fail;
|
||||
if (n <= 0) {
|
||||
in += h2n->length - h2n->count;
|
||||
h2n->inside = h2n->length;
|
||||
h2n->count = h2n->length - 1;
|
||||
lwsl_debug("%s: lws_read told %d\n", __func__, n);
|
||||
goto close_swsi_and_return;
|
||||
}
|
||||
|
||||
inlen -= n - 1;
|
||||
in += n - 1;
|
||||
|
@ -1562,6 +1588,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|||
break;
|
||||
|
||||
case LWS_H2_FRAME_TYPE_RST_STREAM:
|
||||
h2n->hpack_e_dep <<= 8;
|
||||
h2n->hpack_e_dep |= c;
|
||||
break;
|
||||
|
||||
case LWS_H2_FRAME_TYPE_PUSH_PROMISE:
|
||||
|
@ -1593,7 +1621,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen,
|
|||
|
||||
frame_end:
|
||||
if (h2n->count > h2n->length)
|
||||
lwsl_notice("%d %d\n", h2n->count, h2n->length);
|
||||
lwsl_notice("%s: count > length %d %d\n",
|
||||
__func__, h2n->count, h2n->length);
|
||||
if (h2n->count != h2n->length)
|
||||
break;
|
||||
|
||||
|
@ -1651,6 +1680,17 @@ try_frame_start:
|
|||
|
||||
return 0;
|
||||
|
||||
close_swsi_and_return:
|
||||
|
||||
lws_close_free_wsi(h2n->swsi, 0, "close_swsi_and_return");
|
||||
h2n->swsi = NULL;
|
||||
h2n->frame_state = 0;
|
||||
h2n->count = 0;
|
||||
|
||||
*inused = in - oldin;
|
||||
|
||||
return 2;
|
||||
|
||||
fail:
|
||||
*inused = in - oldin;
|
||||
|
||||
|
@ -1660,10 +1700,11 @@ fail:
|
|||
int
|
||||
lws_h2_ws_handshake(struct lws *wsi)
|
||||
{
|
||||
uint8_t buf[256], *p = buf, *start = p, *end = &buf[sizeof(buf) - 1];
|
||||
uint8_t buf[LWS_PRE + 384], *p = buf + LWS_PRE, *start = p,
|
||||
*end = &buf[sizeof(buf) - 1];
|
||||
const struct lws_http_mount *hit;
|
||||
const char * uri_ptr;
|
||||
int n;
|
||||
int n, m;
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end))
|
||||
return -1;
|
||||
|
@ -1678,18 +1719,18 @@ lws_h2_ws_handshake(struct lws *wsi)
|
|||
wsi->protocol->name && wsi->protocol->name[0]) {
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL,
|
||||
(unsigned char *)wsi->protocol->name,
|
||||
(int)strlen(wsi->protocol->name), &p, end))
|
||||
(int)strlen(wsi->protocol->name),
|
||||
&p, end))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_finalize_http_header(wsi, &p, end))
|
||||
return -1;
|
||||
|
||||
n = lws_write(wsi, start, lws_ptr_diff(p, start),
|
||||
LWS_WRITE_HTTP_HEADERS);
|
||||
if (n != lws_ptr_diff(p, start)) {
|
||||
lwsl_err("_write returned %d from %d\n", n,
|
||||
lws_ptr_diff(p, start));
|
||||
m = lws_ptr_diff(p, start);
|
||||
n = lws_write(wsi, start, m, LWS_WRITE_HTTP_HEADERS);
|
||||
if (n != m) {
|
||||
lwsl_err("_write returned %d from %d\n", n, m);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -389,7 +389,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
|
|||
struct lws_tokens eff_buf;
|
||||
int n, m, ret;
|
||||
|
||||
lwsl_debug("%s: %p: caller: %s\n", __func__, wsi, caller);
|
||||
lwsl_info("%s: %p: caller: %s\n", __func__, wsi, caller);
|
||||
|
||||
if (!wsi)
|
||||
return;
|
||||
|
@ -411,88 +411,16 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
|
|||
wsi2->parent = NULL;
|
||||
/* stop it doing shutdown processing */
|
||||
wsi2->socket_is_permanently_unusable = 1;
|
||||
lws_close_free_wsi(wsi2, reason, "general child recurse");
|
||||
__lws_close_free_wsi(wsi2, reason, "general child recurse");
|
||||
wsi2 = wsi1;
|
||||
}
|
||||
wsi->child_list = NULL;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
|
||||
if (wsi->h2.parent_wsi) {
|
||||
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 %p\n", *w);
|
||||
} lws_end_foreach_llp(w, h2.sibling_list);
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2 || wsi->http2_substream) {
|
||||
lwsl_info("closing %p: parent %p\n", wsi, wsi->h2.parent_wsi);
|
||||
|
||||
if (wsi->h2.child_list) {
|
||||
lwsl_info(" parent %p: closing children: list:\n", wsi);
|
||||
lws_start_foreach_llp(struct lws **, w,
|
||||
wsi->h2.child_list) {
|
||||
lwsl_info(" \\---- child %p\n", *w);
|
||||
} lws_end_foreach_llp(w, h2.sibling_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2) {
|
||||
/* remove pps */
|
||||
struct lws_h2_protocol_send *w = wsi->h2.h2n->pps, *w1;
|
||||
while (w) {
|
||||
w1 = w->next;
|
||||
free(w);
|
||||
w = w1;
|
||||
}
|
||||
wsi->h2.h2n->pps = NULL;
|
||||
}
|
||||
|
||||
if (wsi->http2_substream && wsi->h2.parent_wsi) {
|
||||
lwsl_info(" %p: disentangling from siblings\n", 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_info(" %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;
|
||||
if (wsi->h2.pending_status_body)
|
||||
lws_free_set_NULL(wsi->h2.pending_status_body);
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2 && wsi->h2.h2n &&
|
||||
wsi->h2.h2n->rx_scratch)
|
||||
lws_free_set_NULL(wsi->h2.h2n->rx_scratch);
|
||||
#endif
|
||||
|
||||
if (wsi->mode == LWSCM_RAW_FILEDESC) {
|
||||
lws_remove_child_from_any_parent(wsi);
|
||||
__remove_wsi_socket_from_fds(wsi);
|
||||
wsi->protocol->callback(wsi,
|
||||
LWS_CALLBACK_RAW_CLOSE_FILE,
|
||||
wsi->protocol->callback(wsi, LWS_CALLBACK_RAW_CLOSE_FILE,
|
||||
wsi->user_space, NULL, 0);
|
||||
goto async_close;
|
||||
}
|
||||
|
@ -563,7 +491,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
|
|||
if (wsi->trunc_len) {
|
||||
lwsl_info("%p: FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi);
|
||||
wsi->state = LWSS_FLUSHING_SEND_BEFORE_CLOSE;
|
||||
lws_set_timeout(wsi,
|
||||
__lws_set_timeout(wsi,
|
||||
PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5);
|
||||
return;
|
||||
}
|
||||
|
@ -662,7 +590,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
|
|||
lwsl_debug("waiting for chance to send close\n");
|
||||
wsi->waiting_to_send_close_frame = 1;
|
||||
wsi->state = LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 2);
|
||||
__lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 5);
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return;
|
||||
|
@ -670,6 +598,90 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *
|
|||
|
||||
just_kill_connection:
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
|
||||
if (wsi->http2_substream && wsi->h2_stream_carries_ws)
|
||||
lws_h2_rst_stream(wsi, 0, "none");
|
||||
|
||||
if (wsi->h2.parent_wsi) {
|
||||
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 %p\n", *w);
|
||||
} lws_end_foreach_llp(w, h2.sibling_list);
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2 || wsi->http2_substream) {
|
||||
lwsl_info("closing %p: parent %p\n", wsi, wsi->h2.parent_wsi);
|
||||
|
||||
if (wsi->h2.child_list) {
|
||||
lwsl_info(" parent %p: closing children: list:\n", wsi);
|
||||
lws_start_foreach_llp(struct lws **, w,
|
||||
wsi->h2.child_list) {
|
||||
lwsl_info(" \\---- child %p\n", *w);
|
||||
} lws_end_foreach_llp(w, h2.sibling_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);
|
||||
}
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2) {
|
||||
/* remove pps */
|
||||
struct lws_h2_protocol_send *w = wsi->h2.h2n->pps, *w1;
|
||||
while (w) {
|
||||
w1 = w->next;
|
||||
free(w);
|
||||
w = w1;
|
||||
}
|
||||
wsi->h2.h2n->pps = NULL;
|
||||
}
|
||||
|
||||
if (wsi->http2_substream && wsi->h2.parent_wsi) {
|
||||
lwsl_info(" %p: disentangling from siblings\n", 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_info(" %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;
|
||||
if (wsi->h2.pending_status_body)
|
||||
lws_free_set_NULL(wsi->h2.pending_status_body);
|
||||
}
|
||||
|
||||
if (wsi->h2_stream_carries_ws) {
|
||||
struct lws *nwsi = lws_get_network_wsi(wsi);
|
||||
|
||||
nwsi->ws_over_h2_count++;
|
||||
/* if no ws, then put a timeout on the parent wsi */
|
||||
if (!nwsi->ws_over_h2_count)
|
||||
__lws_set_timeout(nwsi,
|
||||
PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, 31);
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2 && wsi->h2.h2n &&
|
||||
wsi->h2.h2n->rx_scratch)
|
||||
lws_free_set_NULL(wsi->h2.h2n->rx_scratch);
|
||||
#endif
|
||||
|
||||
lws_remove_child_from_any_parent(wsi);
|
||||
n = 0;
|
||||
|
||||
|
@ -719,7 +731,7 @@ just_kill_connection:
|
|||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
if (lws_is_ssl(wsi) && wsi->ssl) {
|
||||
n = 0;
|
||||
switch (lws_tls_shutdown(wsi)) {
|
||||
switch (__lws_tls_shutdown(wsi)) {
|
||||
case LWS_SSL_CAPABLE_DONE:
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
|
||||
|
@ -753,9 +765,9 @@ just_kill_connection:
|
|||
lws_sockfd_valid(wsi->desc.sockfd) &&
|
||||
wsi->state != ((wsi->state & ~0x1f) | LWSS_SHUTDOWN) &&
|
||||
!LWS_LIBUV_ENABLED(context)) {
|
||||
lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
|
||||
__lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
|
||||
wsi->state = (wsi->state & ~0x1f) | LWSS_SHUTDOWN;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
|
||||
__lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
|
||||
context->timeout_secs);
|
||||
|
||||
return;
|
||||
|
@ -790,7 +802,9 @@ just_kill_connection:
|
|||
lws_free_set_NULL(wsi->rxflow_buffer);
|
||||
|
||||
if (lws_state_is_ws(wsi->state_pre_close) ||
|
||||
wsi->mode == LWSCM_WS_SERVING || wsi->mode == LWSCM_WS_CLIENT) {
|
||||
wsi->mode == LWSCM_WS_SERVING ||
|
||||
wsi->mode == LWSCM_HTTP2_WS_SERVING ||
|
||||
wsi->mode == LWSCM_WS_CLIENT) {
|
||||
|
||||
if (wsi->ws->rx_draining_ext) {
|
||||
struct lws **w = &pt->rx_draining_ext_list;
|
||||
|
@ -833,8 +847,11 @@ just_kill_connection:
|
|||
|
||||
/* tell the user it's all over for this guy */
|
||||
|
||||
if (wsi->protocol && !wsi->told_user_closed && wsi->protocol->callback &&
|
||||
wsi->mode != LWSCM_RAW && (wsi->state_pre_close & _LSF_CCB)) {
|
||||
if (wsi->protocol &&
|
||||
!wsi->told_user_closed &&
|
||||
wsi->protocol->callback &&
|
||||
wsi->mode != LWSCM_RAW &&
|
||||
(wsi->state_pre_close & _LSF_CCB)) {
|
||||
wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED,
|
||||
wsi->user_space, NULL, 0);
|
||||
} else if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED) {
|
||||
|
@ -2136,7 +2153,9 @@ lws_close_reason(struct lws *wsi, enum lws_close_status status,
|
|||
unsigned char *p, *start;
|
||||
int budget = sizeof(wsi->ws->ping_payload_buf) - LWS_PRE;
|
||||
|
||||
assert(wsi->mode == LWSCM_WS_SERVING || wsi->mode == LWSCM_WS_CLIENT);
|
||||
assert(wsi->mode == LWSCM_WS_SERVING ||
|
||||
wsi->mode == LWSCM_HTTP2_WS_SERVING ||
|
||||
wsi->mode == LWSCM_WS_CLIENT);
|
||||
|
||||
start = p = &wsi->ws->ping_payload_buf[LWS_PRE];
|
||||
|
||||
|
|
|
@ -347,10 +347,10 @@ lwsl_timestamp(int level, char *p, int len);
|
|||
* lwsl_hexdump() - helper to hexdump a buffer
|
||||
*
|
||||
* \param level: one of LLL_ constants
|
||||
* \param buf: buffer start to dump
|
||||
* \param vbuf: buffer start to dump
|
||||
* \param len: length of buffer to dump
|
||||
*
|
||||
* If \p level is visible, does a nice hexdump -C style dump of \p buf for
|
||||
* If \p level is visible, does a nice hexdump -C style dump of \p vbuf for
|
||||
* \p len bytes. This can be extremely convenient while debugging.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
|
@ -925,7 +925,11 @@ enum lws_callback_reasons {
|
|||
LWS_CALLBACK_ESTABLISHED = 0,
|
||||
/**< (VH) after the server completes a handshake with an incoming
|
||||
* client. If you built the library with ssl support, in is a
|
||||
* pointer to the ssl struct associated with the connection or NULL.*/
|
||||
* pointer to the ssl struct associated with the connection or NULL.
|
||||
*
|
||||
* b0 of len is set if the connection was made using ws-over-h2
|
||||
*
|
||||
* */
|
||||
LWS_CALLBACK_CLIENT_CONNECTION_ERROR = 1,
|
||||
/**< the request client connection has been unable to complete a
|
||||
* handshake with the remote server. If in is non-NULL, you can
|
||||
|
|
14
lib/output.c
14
lib/output.c
|
@ -274,14 +274,15 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
|
|||
wp1f == LWS_WRITE_HTTP_HEADERS)
|
||||
goto send_raw;
|
||||
|
||||
/* if not in a state to send stuff, then just send nothing */
|
||||
/* if not in a state to send ws stuff, then just send nothing */
|
||||
|
||||
if (!lws_state_is_ws(wsi->state) &&
|
||||
((wsi->state != LWSS_RETURNED_CLOSE_ALREADY &&
|
||||
wsi->state != LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION &&
|
||||
wsi->state != LWSS_AWAITING_CLOSE_ACK) ||
|
||||
wp != LWS_WRITE_CLOSE)) {
|
||||
lwsl_debug("binning\n");
|
||||
wp1f != LWS_WRITE_CLOSE)) {
|
||||
//assert(0);
|
||||
lwsl_debug("binning %d %d\n", wsi->state, wp1f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -483,6 +484,12 @@ do_more_inside_frame:
|
|||
|
||||
send_raw:
|
||||
switch (wp1f) {
|
||||
case LWS_WRITE_TEXT:
|
||||
case LWS_WRITE_BINARY:
|
||||
case LWS_WRITE_CONTINUATION:
|
||||
if (!wsi->h2_stream_carries_ws)
|
||||
break;
|
||||
/* fallthru */
|
||||
case LWS_WRITE_CLOSE:
|
||||
/* lwsl_hexdump(&buf[-pre], len); */
|
||||
case LWS_WRITE_HTTP:
|
||||
|
@ -895,6 +902,7 @@ lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
|
|||
|
||||
lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n",
|
||||
len, wsi->desc.sockfd, n, LWS_ERRNO);
|
||||
|
||||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -462,7 +462,7 @@ lws_callback_on_writable(struct lws *wsi)
|
|||
#endif
|
||||
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
lwsl_info("%s: %p\n", __func__, wsi);
|
||||
lwsl_info("%s: %p (mode %d)\n", __func__, wsi, wsi->mode);
|
||||
|
||||
if (wsi->mode != LWSCM_HTTP2_SERVING &&
|
||||
wsi->mode != LWSCM_HTTP2_WS_SERVING)
|
||||
|
|
|
@ -509,7 +509,8 @@ enum lws_connection_states {
|
|||
LWSS_HTTP2_ESTABLISHED = _LSF_CCB | 15 |
|
||||
_LSF_POLLOUT,
|
||||
LWSS_HTTP2_ESTABLISHED_WS = _LSF_CCB | 16 |
|
||||
_LSF_WEBSOCKET,
|
||||
_LSF_WEBSOCKET |
|
||||
_LSF_POLLOUT,
|
||||
|
||||
LWSS_CGI = 17,
|
||||
|
||||
|
@ -520,7 +521,7 @@ enum lws_connection_states {
|
|||
_LSF_POLLOUT,
|
||||
};
|
||||
|
||||
#define lws_state_is_ws(s) (!!(s & _LSF_WEBSOCKET))
|
||||
#define lws_state_is_ws(s) (!!((s) & _LSF_WEBSOCKET))
|
||||
|
||||
enum http_version {
|
||||
HTTP_VERSION_1_0,
|
||||
|
@ -872,6 +873,7 @@ struct lws_context_per_thread {
|
|||
|
||||
short ah_count_in_use;
|
||||
unsigned char tid;
|
||||
unsigned char lock_depth;
|
||||
#if LWS_MAX_SMP > 1
|
||||
pthread_t lock_owner;
|
||||
#endif
|
||||
|
@ -2018,6 +2020,7 @@ struct lws {
|
|||
#if defined(LWS_WITH_STATS) && defined(LWS_OPENSSL_SUPPORT)
|
||||
char seen_rx;
|
||||
#endif
|
||||
uint8_t ws_over_h2_count;
|
||||
/* volatile to make sure code is aware other thread can change */
|
||||
volatile char handling_pollout;
|
||||
volatile char leave_pollout_active;
|
||||
|
@ -2188,6 +2191,8 @@ user_callback_handle_rxflow(lws_callback_function, struct lws *wsi,
|
|||
enum lws_callback_reasons reason, void *user,
|
||||
void *in, size_t len);
|
||||
#ifdef LWS_WITH_HTTP2
|
||||
int
|
||||
lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason);
|
||||
struct lws * lws_h2_get_nth_child(struct lws *wsi, int n);
|
||||
LWS_EXTERN void lws_h2_init(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
|
@ -2428,7 +2433,7 @@ LWS_EXTERN enum lws_ssl_capable_status
|
|||
lws_tls_server_abort_connection(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_shutdown(struct lws *wsi);
|
||||
__lws_tls_shutdown(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_client_connect(struct lws *wsi);
|
||||
|
@ -2477,8 +2482,8 @@ static LWS_INLINE void
|
|||
lws_pt_lock(struct lws_context_per_thread *pt, const char *reason)
|
||||
{
|
||||
if (pt->lock_owner == pthread_self()) {
|
||||
lwsl_err("tid %d: lock collision: already held for %s, reacquiring for %s\n", pt->tid, pt->last_lock_reason, reason);
|
||||
assert(0);
|
||||
pt->lock_depth++;
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&pt->lock);
|
||||
pt->last_lock_reason = reason;
|
||||
|
@ -2489,6 +2494,10 @@ lws_pt_lock(struct lws_context_per_thread *pt, const char *reason)
|
|||
static LWS_INLINE void
|
||||
lws_pt_unlock(struct lws_context_per_thread *pt)
|
||||
{
|
||||
if (pt->lock_depth) {
|
||||
pt->lock_depth--;
|
||||
return;
|
||||
}
|
||||
pt->last_lock_reason ="free";
|
||||
pt->lock_owner = 0;
|
||||
//lwsl_notice("tid %d: unlock %s\n", pt->tid, pt->last_lock_reason);
|
||||
|
|
|
@ -1567,7 +1567,7 @@ spill:
|
|||
switch (wsi->ws->opcode) {
|
||||
case LWSWSOPC_CLOSE:
|
||||
|
||||
/* is this an acknowledgement of our close? */
|
||||
/* is this an acknowledgment of our close? */
|
||||
if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
|
||||
/*
|
||||
* fine he has told us he is closing too, let's
|
||||
|
@ -1729,7 +1729,6 @@ drain_extension:
|
|||
eff_buf.token[eff_buf.token_len] = '\0';
|
||||
|
||||
if (wsi->protocol->callback) {
|
||||
|
||||
if (callback_action == LWS_CALLBACK_RECEIVE_PONG)
|
||||
lwsl_info("Doing pong callback\n");
|
||||
|
||||
|
|
|
@ -716,6 +716,244 @@ int lws_clean_url(char *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_server_init_wsi_for_ws(struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
wsi->state = LWSS_ESTABLISHED;
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, use
|
||||
* a big default for compatibility
|
||||
*/
|
||||
|
||||
n = (int)wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = wsi->context->pt_serv_buf_size;
|
||||
n += LWS_PRE;
|
||||
wsi->ws->rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */, "rx_ubuf");
|
||||
if (!wsi->ws->rx_ubuf) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
wsi->ws->rx_ubuf_alloc = n;
|
||||
lwsl_debug("Allocating RX buffer %d\n", n);
|
||||
|
||||
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
if (!wsi->parent_carries_io &&
|
||||
!wsi->h2_stream_carries_ws)
|
||||
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
|
||||
(const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* notify user code that we're ready to roll */
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
|
||||
wsi->user_space,
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->ssl,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
wsi->h2_stream_carries_ws))
|
||||
return 1;
|
||||
|
||||
lwsl_debug("ws established\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_process_ws_upgrade(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
char protocol_list[128], protocol_name[64], *p;
|
||||
int protocol_len, hit, n = 0, non_space_char_found = 0;
|
||||
|
||||
if (!wsi->protocol)
|
||||
lwsl_err("NULL protocol at lws_read\n");
|
||||
|
||||
/*
|
||||
* It's either websocket or h2->websocket
|
||||
*
|
||||
* Select the first protocol we support from the list
|
||||
* the client sent us.
|
||||
*
|
||||
* Copy it to remove header fragmentation
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,
|
||||
WSI_TOKEN_PROTOCOL) < 0) {
|
||||
lwsl_err("protocol list too long");
|
||||
return 1;
|
||||
}
|
||||
|
||||
protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
|
||||
protocol_list[protocol_len] = '\0';
|
||||
p = protocol_list;
|
||||
hit = 0;
|
||||
|
||||
while (*p && !hit) {
|
||||
n = 0;
|
||||
non_space_char_found = 0;
|
||||
while (n < (int)sizeof(protocol_name) - 1 &&
|
||||
*p && *p != ',') {
|
||||
/* ignore leading spaces */
|
||||
if (!non_space_char_found && *p == ' ') {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
non_space_char_found = 1;
|
||||
protocol_name[n++] = *p++;
|
||||
}
|
||||
protocol_name[n] = '\0';
|
||||
if (*p)
|
||||
p++;
|
||||
|
||||
lwsl_debug("checking %s\n", protocol_name);
|
||||
|
||||
n = 0;
|
||||
while (wsi->vhost->protocols[n].callback) {
|
||||
lwsl_debug("try %s\n",
|
||||
wsi->vhost->protocols[n].name);
|
||||
|
||||
if (wsi->vhost->protocols[n].name &&
|
||||
!strcmp(wsi->vhost->protocols[n].name,
|
||||
protocol_name)) {
|
||||
wsi->protocol = &wsi->vhost->protocols[n];
|
||||
hit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
/* we didn't find a protocol he wanted? */
|
||||
|
||||
if (!hit) {
|
||||
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
|
||||
lwsl_notice("No protocol from \"%s\" supported\n",
|
||||
protocol_list);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* some clients only have one protocol and
|
||||
* do not send the protocol list header...
|
||||
* allow it and match to the vhost's default
|
||||
* protocol (which itself defaults to zero)
|
||||
*/
|
||||
lwsl_info("defaulting to prot handler %d\n",
|
||||
wsi->vhost->default_protocol_index);
|
||||
n = wsi->vhost->default_protocol_index;
|
||||
wsi->protocol = &wsi->vhost->protocols[
|
||||
(int)wsi->vhost->default_protocol_index];
|
||||
}
|
||||
|
||||
/* allocate the ws struct for the wsi */
|
||||
wsi->ws = lws_zalloc(sizeof(*wsi->ws), "ws struct");
|
||||
if (!wsi->ws) {
|
||||
lwsl_notice("OOM\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
|
||||
wsi->ws->ietf_spec_revision =
|
||||
atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
|
||||
|
||||
/* allocate wsi->user storage */
|
||||
if (lws_ensure_user_space(wsi)) {
|
||||
lwsl_notice("problem with user space\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give the user code a chance to study the request and
|
||||
* have the opportunity to deny it
|
||||
*/
|
||||
if ((wsi->protocol->callback)(wsi,
|
||||
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
|
||||
wsi->user_space,
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
|
||||
lwsl_warn("User code denied connection\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the handshake according to the protocol version the
|
||||
* client announced
|
||||
*/
|
||||
|
||||
switch (wsi->ws->ietf_spec_revision) {
|
||||
default:
|
||||
lwsl_notice("Unknown client spec version %d\n",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
wsi->ws->ietf_spec_revision = 13;
|
||||
//return 1;
|
||||
/* fallthru */
|
||||
case 13:
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->h2_stream_carries_ws) {
|
||||
if (lws_h2_ws_handshake(wsi)) {
|
||||
lwsl_notice("h2 ws handshake failed\n");
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
lwsl_parser("lws_parse calling handshake_04\n");
|
||||
if (handshake_0405(wsi->context, wsi)) {
|
||||
lwsl_notice("hs0405 has failed the connection\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
lws_same_vh_protocol_insert(wsi, n);
|
||||
|
||||
/* we are upgrading to ws, so http/1.1 + h2 and keepalive +
|
||||
* pipelined header considerations about keeping the ah around
|
||||
* no longer apply. However it's common for the first ws
|
||||
* protocol data to have been coalesced with the browser
|
||||
* upgrade request and to already be in the ah rx buffer.
|
||||
*/
|
||||
|
||||
lwsl_debug("%s: %p: inheriting ws ah (rxpos:%d, rxlen:%d)\n",
|
||||
__func__, wsi, wsi->ah->rxpos, wsi->ah->rxlen);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
if (wsi->h2_stream_carries_ws)
|
||||
lws_union_transition(wsi, LWSCM_HTTP2_WS_SERVING);
|
||||
else
|
||||
lws_union_transition(wsi, LWSCM_WS_SERVING);
|
||||
/*
|
||||
* Because rxpos/rxlen shows something in the ah, we will get
|
||||
* service guaranteed next time around the event loop
|
||||
*/
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_server_init_wsi_for_ws(wsi);
|
||||
lwsl_parser("accepted v%02d connection\n",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
|
||||
/* !!! drop ah unreservedly after ESTABLISHED */
|
||||
if (wsi->ah->rxpos == wsi->ah->rxlen ) {
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const unsigned char methods[] = {
|
||||
WSI_TOKEN_GET_URI,
|
||||
|
@ -773,6 +1011,9 @@ lws_http_action(struct lws *wsi)
|
|||
unsigned int n;
|
||||
char http_version_str[10];
|
||||
char http_conn_str[20];
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
char *p;
|
||||
#endif
|
||||
int http_version_len;
|
||||
char *uri_ptr = NULL, *s;
|
||||
int uri_len = 0, meth;
|
||||
|
@ -795,6 +1036,37 @@ lws_http_action(struct lws *wsi)
|
|||
lwsl_info("Method: '%s' (%d), request for '%s'\n", method_names[meth],
|
||||
meth, uri_ptr);
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
/*
|
||||
* with H2 there's also a way to upgrade a stream to something
|
||||
* else... :method is CONNECT and :protocol says the name of
|
||||
* the new protocol we want to carry. We have to have sent a
|
||||
* SETTINGS saying that we support it though.
|
||||
*/
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
|
||||
if (wsi->vhost->set.s[H2SET_ENABLE_CONNECT_PROTOCOL] &&
|
||||
wsi->http2_substream && p && !strcmp(p, "CONNECT")) {
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_COLON_PROTOCOL);
|
||||
if (p && !strcmp(p, "websocket")) {
|
||||
struct lws *nwsi = lws_get_network_wsi(wsi);
|
||||
|
||||
wsi->vhost->conn_stats.ws_upg++;
|
||||
lwsl_info("Upgrade h2 to ws\n");
|
||||
wsi->h2_stream_carries_ws = 1;
|
||||
nwsi->ws_over_h2_count++;
|
||||
if (lws_process_ws_upgrade(wsi))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
if (nwsi->ws_over_h2_count == 1)
|
||||
lws_set_timeout(nwsi, NO_PENDING_TIMEOUT, 0);
|
||||
|
||||
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
|
||||
lwsl_info("Upgraded h2 to ws OK\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lws_ensure_user_space(wsi))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
|
@ -1264,69 +1536,16 @@ transaction_result_n:
|
|||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
lws_server_init_wsi_for_ws(struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
wsi->state = LWSS_ESTABLISHED;
|
||||
lws_restart_ws_ping_pong_timer(wsi);
|
||||
|
||||
/*
|
||||
* create the frame buffer for this connection according to the
|
||||
* size mentioned in the protocol definition. If 0 there, use
|
||||
* a big default for compatibility
|
||||
*/
|
||||
|
||||
n = (int)wsi->protocol->rx_buffer_size;
|
||||
if (!n)
|
||||
n = wsi->context->pt_serv_buf_size;
|
||||
n += LWS_PRE;
|
||||
wsi->ws->rx_ubuf = lws_malloc(n + 4 /* 0x0000ffff zlib */, "rx_ubuf");
|
||||
if (!wsi->ws->rx_ubuf) {
|
||||
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
|
||||
return 1;
|
||||
}
|
||||
wsi->ws->rx_ubuf_alloc = n;
|
||||
lwsl_debug("Allocating RX buffer %d\n", n);
|
||||
|
||||
#if LWS_POSIX && !defined(LWS_WITH_ESP32)
|
||||
if (!wsi->parent_carries_io &&
|
||||
!wsi->h2_stream_carries_ws)
|
||||
if (setsockopt(wsi->desc.sockfd, SOL_SOCKET, SO_SNDBUF,
|
||||
(const char *)&n, sizeof n)) {
|
||||
lwsl_warn("Failed to set SNDBUF to %d", n);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* notify user code that we're ready to roll */
|
||||
|
||||
if (wsi->protocol->callback)
|
||||
if (wsi->protocol->callback(wsi, LWS_CALLBACK_ESTABLISHED,
|
||||
wsi->user_space,
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->ssl,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int protocol_len, n = 0, hit, non_space_char_found = 0, m, i;
|
||||
unsigned char *obuf = *buf;
|
||||
char protocol_list[128];
|
||||
char protocol_name[64];
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
char tbuf[128], *p;
|
||||
#endif
|
||||
size_t olen = len;
|
||||
char *p;
|
||||
int n = 0, m, i;
|
||||
|
||||
if (len >= 10000000) {
|
||||
lwsl_err("%s: assert: len %ld\n", __func__, (long)len);
|
||||
|
@ -1349,6 +1568,7 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len)
|
|||
i = (int)len;
|
||||
m = lws_parse(wsi, *buf, &i);
|
||||
(*buf) += (int)len - i;
|
||||
len = i;
|
||||
if (m) {
|
||||
if (m == 2) {
|
||||
/*
|
||||
|
@ -1489,27 +1709,6 @@ raw_transition:
|
|||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
/*
|
||||
* with H2 there's also a way to upgrade a stream to something
|
||||
* else... :method is CONNECT and :protocol says the name of
|
||||
* the new protocol we want to carry. We have to have sent a
|
||||
* SETTINGS saying that we support it though.
|
||||
*/
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD);
|
||||
if (wsi->h2.h2n &&
|
||||
wsi->h2.h2n->set.s[H2SET_ENABLE_CONNECT_PROTOCOL] &&
|
||||
p && !strcmp(p, "CONNECT")) {
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_COLON_PROTOCOL);
|
||||
if (p && !strcmp(p, "websocket")) {
|
||||
wsi->vhost->conn_stats.ws_upg++;
|
||||
lwsl_info("Upgrade h2 to ws\n");
|
||||
wsi->h2_stream_carries_ws = 1;
|
||||
goto upgrade_ws;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* no upgrade ack... he remained as HTTP */
|
||||
|
||||
lwsl_info("No upgrade\n");
|
||||
|
@ -1536,8 +1735,7 @@ upgrade_h2c:
|
|||
|
||||
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP2_SETTINGS);
|
||||
/* convert the peer's HTTP-Settings */
|
||||
n = lws_b64_decode_string(p, protocol_list,
|
||||
sizeof(protocol_list));
|
||||
n = lws_b64_decode_string(p, tbuf, sizeof(tbuf));
|
||||
if (n < 0) {
|
||||
lwsl_parser("HTTP2_SETTINGS too long\n");
|
||||
return 1;
|
||||
|
@ -1558,18 +1756,17 @@ upgrade_h2c:
|
|||
|
||||
/* HTTP2 union */
|
||||
|
||||
lws_h2_settings(wsi, &wsi->h2.h2n->set,
|
||||
(unsigned char *)protocol_list, n);
|
||||
lws_h2_settings(wsi, &wsi->h2.h2n->set, (unsigned char *)tbuf, n);
|
||||
|
||||
lws_hpack_dynamic_size(wsi, wsi->h2.h2n->set.s[
|
||||
H2SET_HEADER_TABLE_SIZE]);
|
||||
|
||||
strcpy(protocol_list, "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 *)protocol_list,
|
||||
strlen(protocol_list));
|
||||
if (n != (int)strlen(protocol_list)) {
|
||||
strcpy(tbuf, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
|
||||
"Connection: Upgrade\x0d\x0a"
|
||||
"Upgrade: h2c\x0d\x0a\x0d\x0a");
|
||||
m = (int)strlen(tbuf);
|
||||
n = lws_issue_raw(wsi, (unsigned char *)tbuf, m);
|
||||
if (n != m) {
|
||||
lwsl_debug("http2 switch: ERROR writing to socket\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -1581,177 +1778,11 @@ upgrade_h2c:
|
|||
#endif
|
||||
|
||||
upgrade_ws:
|
||||
if (!wsi->protocol)
|
||||
lwsl_err("NULL protocol at lws_read\n");
|
||||
|
||||
/*
|
||||
* It's either websocket or h2->websocket
|
||||
*
|
||||
* Select the first protocol we support from the list
|
||||
* the client sent us.
|
||||
*
|
||||
* Copy it to remove header fragmentation
|
||||
*/
|
||||
|
||||
if (lws_hdr_copy(wsi, protocol_list, sizeof(protocol_list) - 1,
|
||||
WSI_TOKEN_PROTOCOL) < 0) {
|
||||
lwsl_err("protocol list too long");
|
||||
if (lws_process_ws_upgrade(wsi))
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
protocol_len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
|
||||
protocol_list[protocol_len] = '\0';
|
||||
p = protocol_list;
|
||||
hit = 0;
|
||||
|
||||
while (*p && !hit) {
|
||||
n = 0;
|
||||
non_space_char_found = 0;
|
||||
while (n < (int)sizeof(protocol_name) - 1 &&
|
||||
*p && *p != ',') {
|
||||
/* ignore leading spaces */
|
||||
if (!non_space_char_found && *p == ' ') {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
non_space_char_found = 1;
|
||||
protocol_name[n++] = *p++;
|
||||
}
|
||||
protocol_name[n] = '\0';
|
||||
if (*p)
|
||||
p++;
|
||||
|
||||
lwsl_info("checking %s\n", protocol_name);
|
||||
|
||||
n = 0;
|
||||
while (wsi->vhost->protocols[n].callback) {
|
||||
lwsl_info("try %s\n",
|
||||
wsi->vhost->protocols[n].name);
|
||||
|
||||
if (wsi->vhost->protocols[n].name &&
|
||||
!strcmp(wsi->vhost->protocols[n].name,
|
||||
protocol_name)) {
|
||||
wsi->protocol = &wsi->vhost->protocols[n];
|
||||
hit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
/* we didn't find a protocol he wanted? */
|
||||
|
||||
if (!hit) {
|
||||
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) {
|
||||
lwsl_info("No protocol from \"%s\" supported\n",
|
||||
protocol_list);
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
/*
|
||||
* some clients only have one protocol and
|
||||
* do not send the protocol list header...
|
||||
* allow it and match to the vhost's default
|
||||
* protocol (which itself defaults to zero)
|
||||
*/
|
||||
lwsl_info("defaulting to prot handler %d\n",
|
||||
wsi->vhost->default_protocol_index);
|
||||
n = wsi->vhost->default_protocol_index;
|
||||
wsi->protocol = &wsi->vhost->protocols[
|
||||
(int)wsi->vhost->default_protocol_index];
|
||||
}
|
||||
|
||||
/* allocate the ws struct for the wsi */
|
||||
wsi->ws = lws_zalloc(sizeof(*wsi->ws), "ws struct");
|
||||
if (!wsi->ws) {
|
||||
lwsl_notice("OOM\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
/* set it from the parser temp */
|
||||
wsi->ws->ietf_spec_revision = wsi->rx_frame_type;
|
||||
|
||||
/* allocate wsi->user storage */
|
||||
if (lws_ensure_user_space(wsi))
|
||||
goto bail_nuke_ah;
|
||||
|
||||
/*
|
||||
* Give the user code a chance to study the request and
|
||||
* have the opportunity to deny it
|
||||
*/
|
||||
if ((wsi->protocol->callback)(wsi,
|
||||
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
|
||||
wsi->user_space,
|
||||
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
|
||||
lwsl_warn("User code denied connection\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the handshake according to the protocol version the
|
||||
* client announced
|
||||
*/
|
||||
|
||||
switch (wsi->ws->ietf_spec_revision) {
|
||||
case 13:
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
if (wsi->h2_stream_carries_ws) {
|
||||
if (lws_h2_ws_handshake(wsi)) {
|
||||
lwsl_info("h2 ws handshake failed\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
lwsl_parser("lws_parse calling handshake_04\n");
|
||||
if (handshake_0405(context, wsi)) {
|
||||
lwsl_info("hs0405 has failed the connection\n");
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
lwsl_info("Unknown client spec version %d\n",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
goto bail_nuke_ah;
|
||||
}
|
||||
|
||||
lws_same_vh_protocol_insert(wsi, n);
|
||||
|
||||
/* we are upgrading to ws, so http/1.1 + h2 and keepalive +
|
||||
* pipelined header considerations about keeping the ah around
|
||||
* no longer apply. However it's common for the first ws
|
||||
* protocol data to have been coalesced with the browser
|
||||
* upgrade request and to already be in the ah rx buffer.
|
||||
*/
|
||||
|
||||
lwsl_info("%s: %p: inheriting ws ah (rxpos:%d, rxlen:%d)\n",
|
||||
__func__, wsi, wsi->ah->rxpos, wsi->ah->rxlen);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
if (wsi->h2_stream_carries_ws)
|
||||
lws_union_transition(wsi, LWSCM_HTTP2_WS_SERVING);
|
||||
else
|
||||
lws_union_transition(wsi, LWSCM_WS_SERVING);
|
||||
/*
|
||||
* Because rxpos/rxlen shows something in the ah, we will get
|
||||
* service guaranteed next time around the event loop
|
||||
*/
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_server_init_wsi_for_ws(wsi);
|
||||
lwsl_parser("accepted v%02d connection\n",
|
||||
wsi->ws->ietf_spec_revision);
|
||||
|
||||
/* !!! drop ah unreservedly after ESTABLISHED */
|
||||
if (wsi->ah->rxpos == wsi->ah->rxlen ) {
|
||||
lws_header_table_force_to_detachable_state(wsi);
|
||||
lws_header_table_detach(wsi, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} /* while all chars are handled */
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -54,6 +54,7 @@ lws_calllback_as_writeable(struct lws *wsi)
|
|||
case LWSCM_WSCL_ISSUE_HTTP_BODY:
|
||||
n = LWS_CALLBACK_CLIENT_HTTP_WRITEABLE;
|
||||
break;
|
||||
case LWSCM_HTTP2_WS_SERVING:
|
||||
case LWSCM_WS_SERVING:
|
||||
n = LWS_CALLBACK_SERVER_WRITEABLE;
|
||||
break;
|
||||
|
@ -162,7 +163,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
LWS_WRITE_CLOSE);
|
||||
if (n >= 0) {
|
||||
wsi->state = LWSS_AWAITING_CLOSE_ACK;
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 1);
|
||||
lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 5);
|
||||
lwsl_debug("sent close indication, awaiting ack\n");
|
||||
|
||||
goto bail_ok;
|
||||
|
@ -187,9 +188,11 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
|
|||
|
||||
/* well he is sent, mark him done */
|
||||
wsi->ws->ping_pending_flag = 0;
|
||||
if (wsi->ws->payload_is_close)
|
||||
if (wsi->ws->payload_is_close) {
|
||||
// assert(0);
|
||||
/* oh... a close frame was it... then we are done */
|
||||
goto bail_die;
|
||||
}
|
||||
|
||||
/* otherwise for PING, leave POLLOUT active either way */
|
||||
goto bail_ok;
|
||||
|
@ -412,9 +415,9 @@ user_service_go_again:
|
|||
wsi2a = wsi->h2.child_list;
|
||||
while (wsi2a) {
|
||||
if (wsi2a->h2.requested_POLLOUT)
|
||||
lwsl_debug(" * %p\n", wsi2a);
|
||||
lwsl_debug(" * %p %s\n", wsi2a, wsi2a->protocol->name);
|
||||
else
|
||||
lwsl_debug(" %p\n", wsi2a);
|
||||
lwsl_debug(" %p %s\n", wsi2a, wsi2a->protocol->name);
|
||||
|
||||
wsi2a = wsi2a->h2.sibling_list;
|
||||
}
|
||||
|
@ -427,10 +430,8 @@ user_service_go_again:
|
|||
struct lws *w, **wa;
|
||||
|
||||
wa = &(*wsi2)->h2.sibling_list;
|
||||
if (!(*wsi2)->h2.requested_POLLOUT) {
|
||||
lwsl_debug(" child %p doesn't want POLLOUT\n", *wsi2);
|
||||
if (!(*wsi2)->h2.requested_POLLOUT)
|
||||
goto next_child;
|
||||
}
|
||||
|
||||
/*
|
||||
* we're going to do writable callback for this child.
|
||||
|
@ -545,6 +546,57 @@ user_service_go_again:
|
|||
goto next_child;
|
||||
}
|
||||
|
||||
/* Notify peer that we decided to close */
|
||||
|
||||
if (w->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) {
|
||||
lwsl_debug("sending close packet\n");
|
||||
w->waiting_to_send_close_frame = 0;
|
||||
n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE],
|
||||
w->ws->close_in_ping_buffer_len,
|
||||
LWS_WRITE_CLOSE);
|
||||
if (n >= 0) {
|
||||
w->state = LWSS_AWAITING_CLOSE_ACK;
|
||||
lws_set_timeout(w, PENDING_TIMEOUT_CLOSE_ACK, 5);
|
||||
lwsl_debug("sent close indication, awaiting ack\n");
|
||||
}
|
||||
|
||||
goto next_child;
|
||||
}
|
||||
|
||||
/* Acknowledge receipt of peer's notification he closed,
|
||||
* then logically close ourself */
|
||||
|
||||
if ((lws_state_is_ws(w->state) && w->ws->ping_pending_flag) ||
|
||||
(w->state == LWSS_RETURNED_CLOSE_ALREADY &&
|
||||
w->ws->payload_is_close)) {
|
||||
|
||||
if (w->ws->payload_is_close)
|
||||
write_type = LWS_WRITE_CLOSE | LWS_WRITE_H2_STREAM_END;
|
||||
|
||||
n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE],
|
||||
w->ws->ping_payload_len, write_type);
|
||||
if (n < 0)
|
||||
goto bail_die;
|
||||
|
||||
/* well he is sent, mark him done */
|
||||
w->ws->ping_pending_flag = 0;
|
||||
if (w->ws->payload_is_close) {
|
||||
/* oh... a close frame was it... then we are done */
|
||||
lwsl_debug("Acknowledged peer's close packet\n");
|
||||
w->ws->payload_is_close = 0;
|
||||
w->state = LWSS_RETURNED_CLOSE_ALREADY;
|
||||
lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "returned close packet");
|
||||
wa = &wsi->h2.child_list;
|
||||
goto next_child;
|
||||
}
|
||||
|
||||
lws_callback_on_writable(w);
|
||||
(w)->h2.requested_POLLOUT = 1;
|
||||
|
||||
/* otherwise for PING, leave POLLOUT active either way */
|
||||
goto next_child;
|
||||
}
|
||||
|
||||
if (lws_calllback_as_writeable(w) || w->h2.send_END_STREAM) {
|
||||
lwsl_debug("Closing POLLOUT child\n");
|
||||
lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "h2 pollout handle");
|
||||
|
@ -638,7 +690,7 @@ __lws_service_timeout_check(struct lws *wsi, time_t sec)
|
|||
if (wsi->protocol &&
|
||||
wsi->protocol->callback(wsi, LWS_CALLBACK_TIMER,
|
||||
wsi->user_space, NULL, 0)) {
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
__lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
|
||||
"timer cb errored");
|
||||
|
||||
return 1;
|
||||
|
@ -1382,7 +1434,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
|
|||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
if (wsi->state == LWSS_SHUTDOWN && lws_is_ssl(wsi) && wsi->ssl) {
|
||||
n = 0;
|
||||
switch (lws_tls_shutdown(wsi)) {
|
||||
switch (__lws_tls_shutdown(wsi)) {
|
||||
case LWS_SSL_CAPABLE_DONE:
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto close_and_handled;
|
||||
|
|
|
@ -278,7 +278,7 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd)
|
|||
int
|
||||
lws_tls_server_abort_connection(struct lws *wsi)
|
||||
{
|
||||
lws_tls_shutdown(wsi);
|
||||
__lws_tls_shutdown(wsi);
|
||||
SSL_free(wsi->ssl);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -302,7 +302,7 @@ lws_tls_ctx_from_wsi(struct lws *wsi)
|
|||
}
|
||||
|
||||
enum lws_ssl_capable_status
|
||||
lws_tls_shutdown(struct lws *wsi)
|
||||
__lws_tls_shutdown(struct lws *wsi)
|
||||
{
|
||||
int n = SSL_shutdown(wsi->ssl);
|
||||
|
||||
|
@ -314,7 +314,7 @@ lws_tls_shutdown(struct lws *wsi)
|
|||
return LWS_SSL_CAPABLE_DONE;
|
||||
|
||||
case 0: /* needs a retry */
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
default: /* fatal error, or WANT */
|
||||
|
@ -322,12 +322,12 @@ lws_tls_shutdown(struct lws *wsi)
|
|||
if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
|
||||
if (SSL_want_read(wsi->ssl)) {
|
||||
lwsl_debug("(wants read)\n");
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
|
||||
}
|
||||
if (SSL_want_write(wsi->ssl)) {
|
||||
lwsl_debug("(wants write)\n");
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLOUT);
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLOUT);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -463,7 +463,7 @@ lws_tls_ctx_from_wsi(struct lws *wsi)
|
|||
}
|
||||
|
||||
enum lws_ssl_capable_status
|
||||
lws_tls_shutdown(struct lws *wsi)
|
||||
__lws_tls_shutdown(struct lws *wsi)
|
||||
{
|
||||
int n;
|
||||
|
||||
|
@ -475,7 +475,7 @@ lws_tls_shutdown(struct lws *wsi)
|
|||
return LWS_SSL_CAPABLE_DONE;
|
||||
|
||||
case 0: /* needs a retry */
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE;
|
||||
|
||||
default: /* fatal error, or WANT */
|
||||
|
@ -483,12 +483,12 @@ lws_tls_shutdown(struct lws *wsi)
|
|||
if (n != SSL_ERROR_SYSCALL && n != SSL_ERROR_SSL) {
|
||||
if (SSL_want_read(wsi->ssl)) {
|
||||
lwsl_debug("(wants read)\n");
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLIN);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
|
||||
}
|
||||
if (SSL_want_write(wsi->ssl)) {
|
||||
lwsl_debug("(wants write)\n");
|
||||
lws_change_pollfd(wsi, 0, LWS_POLLOUT);
|
||||
__lws_change_pollfd(wsi, 0, LWS_POLLOUT);
|
||||
return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -376,7 +376,7 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
/* tell the library what debug level to emit and to send it to syslog */
|
||||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
lws_set_log_level(debug_level, NULL);
|
||||
|
||||
lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n");
|
||||
lwsl_notice("(C) Copyright 2010-2017 Andy Green <andy@warmcat.com>\n");
|
||||
|
|
Loading…
Add table
Reference in a new issue