summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/extension-x-google-mux.c154
-rw-r--r--lib/extension-x-google-mux.h1
-rw-r--r--lib/libwebsockets.c32
-rw-r--r--lib/libwebsockets.h1
4 files changed, 162 insertions, 26 deletions
diff --git a/lib/extension-x-google-mux.c b/lib/extension-x-google-mux.c
index e8ceec2..4b1a2ab 100644
--- a/lib/extension-x-google-mux.c
+++ b/lib/extension-x-google-mux.c
@@ -660,8 +660,8 @@ int lws_extension_callback_x_google_mux(
}
if (parent_conn->highest_child_subchannel >=
- sizeof(parent_conn->wsi_children) /
- sizeof(parent_conn->wsi_children[0])) {
+ (sizeof(parent_conn->wsi_children) /
+ sizeof(parent_conn->wsi_children[0]))) {
fprintf(stderr, "Can't add any more children\n");
continue;
}
@@ -710,6 +710,53 @@ int lws_extension_callback_x_google_mux(
conn->state = LWS_EXT_XGM_STATE__MUX_BLOCK_1;
break;
+ case LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE:
+ muxdebug("LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE\n");
+
+ if (conn->subchannel == 1) {
+
+ /*
+ * special case of original mux parent channel closing
+ */
+
+ conn->original_ch1_closed = 1;
+
+ fprintf(stderr, "original mux parent channel closing\n");
+
+ parent_conn = conn;
+ } else {
+
+ parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext);
+ if (parent_conn == 0) {
+ fprintf(stderr, "failed to get parent conn\n");
+ break;
+ }
+ }
+
+ /* see if that was the end of the mux entirely */
+
+ if (!parent_conn->original_ch1_closed)
+ break;
+
+ done = 0;
+ for (n = 0; n < !done && parent_conn->highest_child_subchannel; n++)
+ if (parent_conn->wsi_children[n])
+ done = 1;
+
+ /* if he has children, don't let him close for real! */
+
+ if (done) {
+ fprintf(stderr, "VETO closure\n");
+ return 1;
+ }
+
+ /* no children, ch1 is closed, let him destroy himself */
+
+ if (conn->subchannel == 1)
+ fprintf(stderr, "ALLOW closure of mux parent\n");
+
+ break;
+
case LWS_EXT_CALLBACK_DESTROY:
muxdebug("LWS_EXT_CALLBACK_DESTROY\n");
@@ -717,8 +764,21 @@ int lws_extension_callback_x_google_mux(
* remove us from parent if noted in parent
*/
- if (conn->wsi_parent) {
+ if (conn->subchannel == 1) {
+
+ /*
+ * special case of original mux parent channel closing
+ */
+
+ conn->original_ch1_closed = 1;
+
+ fprintf(stderr, "original mux parent channel closing\n");
+ parent_conn = conn;
+ wsi_parent = wsi;
+ } else {
+
+ wsi_parent = conn->wsi_parent;
parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext);
if (parent_conn == 0) {
fprintf(stderr, "failed to get parent conn\n");
@@ -729,6 +789,26 @@ int lws_extension_callback_x_google_mux(
parent_conn->wsi_children[n] = NULL;
}
+ /* see if that was the end of the mux entirely */
+
+ if (!parent_conn->original_ch1_closed)
+ break;
+
+ done = 0;
+ for (n = 0; n < !done && parent_conn->highest_child_subchannel; n++)
+ if (parent_conn->wsi_children[n])
+ done = 1;
+
+ if (done == 0)
+ if (parent_conn != conn)
+
+ /*
+ * parent closed last and no children left
+ * ... and we are not parent already ourselves
+ */
+
+ libwebsocket_close_and_free_session(context, wsi_parent, LWS_CLOSE_STATUS_NORMAL);
+
break;
case LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING:
@@ -863,33 +943,55 @@ handle_additions:
pin = *((unsigned char **)in);
basepin = pin;
- /*
- * he's not a child connection of a mux
- */
+ wsi_parent = conn->wsi_parent;
- if (!conn->wsi_parent) {
-// fprintf(stderr, "conn %p has no parent\n", (void *)conn);
- return 0;
- }
+ if (conn->subchannel == 1) {
- /*
- * get parent / transport mux context
- */
+ /*
+ * if we weren't 'closed', then we were the original
+ * connection that established this link, ie, it's
+ * the parent wsi
+ */
- parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext);
- if (parent_conn == 0) {
- fprintf(stderr, "failed to get parent conn\n");
- return 0;
- }
+ if (conn->original_ch1_closed) {
+ fprintf(stderr, "Trying to send on dead original ch1\n");
+ return 0;
+ }
- /*
- * mux transport is in singular mode, let the caller send it
- * no more muxified than it already is
- */
+ /* send on ourselves */
- if (!parent_conn->sticky_mux_used) {
-// fprintf(stderr, "parent in singular mode\n");
- return 0;
+ wsi_parent = wsi;
+
+ } else {
+
+ /*
+ * he's not a child connection of a mux
+ */
+
+ if (!conn->wsi_parent) {
+ // fprintf(stderr, "conn %p has no parent\n", (void *)conn);
+ return 0;
+ }
+
+ /*
+ * get parent / transport mux context
+ */
+
+ parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext);
+ if (parent_conn == 0) {
+ fprintf(stderr, "failed to get parent conn\n");
+ return 0;
+ }
+
+ /*
+ * mux transport is in singular mode, let the caller send it
+ * no more muxified than it already is
+ */
+
+ if (!parent_conn->sticky_mux_used) {
+ // fprintf(stderr, "parent in singular mode\n");
+ return 0;
+ }
}
if (!conn->defeat_mux_opcode_wrapping) {
@@ -919,7 +1021,7 @@ handle_additions:
* recurse to allow nesting
*/
- lws_issue_raw(conn->wsi_parent, basepin, (pin - basepin) + len);
+ lws_issue_raw(wsi_parent, basepin, (pin - basepin) + len);
return 1; /* handled */
diff --git a/lib/extension-x-google-mux.h b/lib/extension-x-google-mux.h
index 6626bea..bc4b05f 100644
--- a/lib/extension-x-google-mux.h
+++ b/lib/extension-x-google-mux.h
@@ -84,6 +84,7 @@ struct lws_ext_x_google_mux_conn {
int count_children_needing_POLLOUT;
int sticky_mux_used;
int defeat_mux_opcode_wrapping;
+ int original_ch1_closed;
};
extern int
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 0a448d9..0021eb4 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -166,6 +166,35 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
wsi->close_reason = reason;
/*
+ * are his extensions okay with him closing? Eg he might be a mux
+ * parent and just his ch1 aspect is closing?
+ */
+
+
+ for (n = 0; n < wsi->count_active_extensions; n++) {
+ if (!wsi->active_extensions[n]->callback)
+ continue;
+
+ m = wsi->active_extensions[n]->callback(context,
+ wsi->active_extensions[n], wsi,
+ LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE,
+ wsi->active_extensions_user[n], NULL, 0);
+
+ /*
+ * if somebody vetoed actually closing him at this time....
+ * up to the extension to track the attempted close, let's
+ * just bail
+ */
+
+ if (m) {
+ fprintf(stderr, "extension vetoed close\n");
+ return;
+ }
+ }
+
+
+
+ /*
* flush any tx pending from extensions, since we may send close packet
* if there are problems with send, just nuke the connection
*/
@@ -2145,6 +2174,9 @@ lws_get_extension_user_matching_ext(struct libwebsocket *wsi,
{
int n = 0;
+ if (wsi == NULL)
+ return NULL;
+
while (n < wsi->count_active_extensions) {
if (wsi->active_extensions[n] != ext) {
n++;
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 9dfd41c..49bf648 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -82,6 +82,7 @@ enum libwebsocket_extension_callback_reasons {
LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT,
LWS_EXT_CALLBACK_CONSTRUCT,
LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
+ LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE,
LWS_EXT_CALLBACK_DESTROY,
LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING,
LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED,