x google mux implement child close

This implements clean client and server close for mux child connections,
and deals with accounting for parent child lists.

The mux link can then survive constant connection bringup and teardown
found in the new test client.

Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
Andy Green 2011-05-24 22:07:45 +01:00
parent 7448c7ee0b
commit 66a16f393e
6 changed files with 84 additions and 32 deletions

View file

@ -40,6 +40,8 @@ struct libwebsocket * __libwebsocket_client_connect_2(
* prepare the actual connection (to the proxy, if any)
*/
fprintf(stderr, "__libwebsocket_client_connect_2: address %s", wsi->c_address);
server_hostent = gethostbyname(wsi->c_address);
if (server_hostent == NULL) {
fprintf(stderr, "Unable to get host name from %s\n",

View file

@ -342,11 +342,11 @@ bail2:
wsi_child = conn->wsi_children[conn->block_subchannel];
muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS in\n");
muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS in %d\n", conn->length);
libwebsocket_read(context, wsi_child, &c, 1);
if (--conn->length >= 0)
if (--conn->length > 0)
break;
muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS done\n");
@ -359,7 +359,10 @@ bail2:
/* reply with ADDCHANNEL to ack it */
wsi->xor_mask = xor_no_mask;
child_conn = lws_get_extension_user_matching_ext(wsi_child, this_ext);
child_conn->wsi_parent = wsi;
muxdebug("Setting child conn parent to %p\n", (void *)wsi);
// lws_ext_x_google_mux__send_addchannel(context, wsi, wsi_child,
// conn->block_subchannel, "url-parsing-not-done-yet");
@ -450,7 +453,12 @@ bail2:
case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
case LWS_CONNMODE_WS_CLIENT:
// fprintf(stderr, " client\n");
libwebsocket_client_rx_sm(wsi_child, c);
if (libwebsocket_client_rx_sm(wsi_child, c) < 0) {
libwebsocket_close_and_free_session(
context,
wsi_child,
LWS_CLOSE_STATUS_GOINGAWAY);
}
return 0;
@ -458,9 +466,13 @@ bail2:
default:
// fprintf(stderr, " server\n");
if (libwebsocket_rx_sm(wsi_child, c) < 0)
if (libwebsocket_rx_sm(wsi_child, c) < 0) {
fprintf(stderr, "probs\n");
libwebsocket_close_and_free_session(
context,
wsi_child,
LWS_CLOSE_STATUS_GOINGAWAY);
}
break;
}
break;
@ -611,28 +623,17 @@ int lws_extension_callback_x_google_mux(
* connection
*/
conn->wsi_parent = wsi_parent;
parent_conn->wsi_children[
parent_conn->count_children] = wsi;
wsi->candidate_children_list = wsi_parent->candidate_children_list;
wsi_parent->candidate_children_list = wsi;
wsi->mode = LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD;
/*
* and now we have to ask the server to allow us to do
* this
*/
fprintf(stderr, "attaching to existing mux\n");
if (lws_ext_x_google_mux__send_addchannel(context,
wsi_parent, wsi, parent_conn->count_children,
(const char *)in) < 0) {
fprintf(stderr, "Addchannel failed\n");
continue;
}
conn = parent_conn;
wsi = wsi_parent;
parent_conn->count_children++;
goto handle_additions;
fprintf(stderr, "!x-google-mux: muxing connection! CHILD ADD %d to %p\n", parent_conn->count_children - 1, (void *)wsi);
done = 1;
n = mux_ctx->active_conns;
}
/*
@ -663,6 +664,28 @@ int lws_extension_callback_x_google_mux(
case LWS_EXT_CALLBACK_DESTROY:
muxdebug("LWS_EXT_CALLBACK_DESTROY\n");
/*
* remove us from parent if noted in parent
*/
if (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");
break;
}
for (n = 0; n < parent_conn->count_children; n++)
if (parent_conn->wsi_children[n] == wsi) {
parent_conn->count_children--;
while (n < parent_conn->count_children) {
parent_conn->wsi_children[n] = parent_conn->wsi_children[n + 1];
n++;
}
}
}
break;
case LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING:
@ -694,6 +717,7 @@ int lws_extension_callback_x_google_mux(
case LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED:
muxdebug("LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED\n");
handle_additions:
/*
* did this putative parent get x-google-mux authorized in the
* end?
@ -716,7 +740,7 @@ int lws_extension_callback_x_google_mux(
wsi_parent = wsi_temp;
}
break;
return 1;
}
/*
@ -741,7 +765,7 @@ int lws_extension_callback_x_google_mux(
wsi_parent = wsi_temp;
}
wsi->candidate_children_list = NULL;
break;
return 1;
/*
* whenever we receive something on a muxed link
@ -776,8 +800,10 @@ int lws_extension_callback_x_google_mux(
* he's not a child connection of a mux
*/
if (!conn->wsi_parent)
if (!conn->wsi_parent) {
// fprintf(stderr, "conn %p has no parent\n", (void *)conn);
return 0;
}
/*
* get parent / transport mux context
@ -794,8 +820,10 @@ int lws_extension_callback_x_google_mux(
* no more muxified than it already is
*/
if (parent_conn->count_children == 0)
if (parent_conn->count_children == 0) {
// fprintf(stderr, "parent in singular mode\n");
return 0;
}
/*
* otherwise we need to take care of the sending action using

View file

@ -721,7 +721,8 @@ libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi
switch (wsi->mode) {
case LWS_CONNMODE_WS_CLIENT:
for (n = 0; n < len; n++)
libwebsocket_client_rx_sm(wsi, *buf++);
if (libwebsocket_client_rx_sm(wsi, *buf++) < 0)
goto bail;
return 0;
default:

View file

@ -222,6 +222,9 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
if (old_state == WSI_STATE_ESTABLISHED &&
reason != LWS_CLOSE_STATUS_NOSTATUS) {
fprintf(stderr, "sending close indication...\n");
n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING],
0, LWS_WRITE_CLOSE);
if (!n) {
@ -246,6 +249,9 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
}
just_kill_connection:
fprintf(stderr, "libwebsocket_close_and_free_session: just_kill_connection\n");
/*
* we won't be servicing or receiving anything further from this guy
* remove this fd from wsi mapping hashtable
@ -278,9 +284,15 @@ just_kill_connection:
/* tell the user it's all over for this guy */
if (wsi->protocol && wsi->protocol->callback &&
old_state == WSI_STATE_ESTABLISHED)
((old_state == WSI_STATE_ESTABLISHED) ||
(old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) ||
(old_state == WSI_STATE_AWAITING_CLOSE_ACK))) {
fprintf(stderr, "calling back CLOSED\n");
wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
wsi->user_space, NULL, 0);
} else {
fprintf(stderr, "not calling back closed due to old_state=%d\n", old_state);
}
/* deallocate any active extension contexts */
@ -334,9 +346,11 @@ just_kill_connection:
#endif
shutdown(wsi->sock, SHUT_RDWR);
#ifdef WIN32
closesocket(wsi->sock);
if (wsi->sock)
closesocket(wsi->sock);
#else
close(wsi->sock);
if (wsi->sock)
close(wsi->sock);
#endif
#ifdef LWS_OPENSSL_SUPPORT
}

View file

@ -1409,8 +1409,14 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
fprintf(stderr, "Extension reports fatal error\n");
return -1;
}
if (m) /* handled */
if (m) /* handled */ {
// fprintf(stderr, "ext sent it\n");
return 0;
}
}
if (!wsi->sock) {
fprintf(stderr, "** error 0 sock but expected to send\n");
}
/*

View file

@ -192,6 +192,7 @@ dump_handshake_info(struct lws_tokens *lwst)
[WSI_TOKEN_ACCEPT] = "Accept",
[WSI_TOKEN_NONCE] = "Nonce",
[WSI_TOKEN_HTTP] = "Http",
[WSI_TOKEN_MUXURL] = "MuxURL",
};
for (n = 0; n < WSI_TOKEN_COUNT; n++) {