add explicit parent child wsi relationships

wsi can have a full tree relationship with each other using
linked lists.  closing the parent ensures the children are
closed first.

Convert cgi to use this instead of his cgi-specific sub-wsi
management.

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2016-03-02 09:17:22 +08:00
parent fe16003644
commit 494418abac
7 changed files with 91 additions and 24 deletions

View file

@ -149,6 +149,13 @@ There are 4 new related callbacks
LWS_CALLBACK_RECEIVE_CLIENT_HTTP = 46,
LWS_CALLBACK_COMPLETED_CLIENT_HTTP = 47,
6) struct lws_client_connect_info has a new member
const char *parent_wsi
if non-NULL, the client wsi is set to be a child of parent_wsi. This ensures
if parent_wsi closes, then the client child is closed just before.
v1.7.0
======

View file

@ -407,7 +407,12 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
if (wsi && !wsi->user_space && i->userdata) {
wsi->user_space_externally_allocated = 1;
wsi->user_space = i->userdata;
}
} else
/* if we stay in http, we can assign the user space now,
* otherwise do it after the protocol negotiated
*/
if (i->method)
lws_ensure_user_space(wsi);
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = i->ssl_connection;
@ -417,11 +422,6 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
goto bail;
}
#endif
wsi->protocol = &i->context->protocols[0];
if (wsi && !wsi->user_space && i->userdata) {
wsi->user_space_externally_allocated = 1;
wsi->user_space = i->userdata;
}
/* 2) stash the things from connect_info that we can't process without
* an ah. Because if no ah, we will go on the ah waiting list and
@ -469,6 +469,14 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
if (lws_header_table_attach(wsi, 0))
lwsl_debug("%s: went on ah wait list\n", __func__);
if (i->parent_wsi) {
lwsl_info("%s: created child %p of parent %p\n", __func__,
wsi, i->parent_wsi);
wsi->parent = i->parent_wsi;
wsi->sibling_list = i->parent_wsi->child_list;
i->parent_wsi->child_list = wsi;
}
return wsi;
bail:

View file

@ -142,10 +142,11 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
void
lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
{
struct lws_context *context;
struct lws_context_per_thread *pt;
int n, m, ret;
struct lws **pwsi, *wsi1, *wsi2;
struct lws_context *context;
struct lws_tokens eff_buf;
int n, m, ret;
if (!wsi)
return;
@ -153,24 +154,31 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
context = wsi->context;
pt = &context->pt[(int)wsi->tsi];
/* if we have children, close them first */
if (wsi->child_list) {
wsi2 = wsi->child_list;
while (wsi2) {
lwsl_notice("%s: closing %p: close child %p\n",
__func__, wsi, wsi2);
wsi1 = wsi2->sibling_list;
lws_close_free_wsi(wsi2, reason);
wsi2 = wsi1;
}
}
#ifdef LWS_WITH_CGI
if (wsi->mode == LWSCM_CGI) {
/* we are not a network connection, but a handler for CGI io */
assert(wsi->master);
assert(wsi->master->cgi);
assert(wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] == wsi);
if (wsi->parent && wsi->parent->cgi)
/* end the binding between us and master */
wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
wsi->master = NULL;
wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
wsi->socket_is_permanently_unusable = 1;
goto just_kill_connection;
}
if (wsi->cgi) {
/* we have a cgi going, we must kill it and close the
* related stdin/out/err wsis first
*/
/* we have a cgi going, we must kill it */
wsi->cgi->being_closed = 1;
lws_cgi_kill(wsi);
}
@ -327,6 +335,22 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
}
just_kill_connection:
if (wsi->parent) {
/* detach ourselves from parent's child list */
pwsi = &wsi->parent->child_list;
while (*pwsi) {
if (*pwsi == wsi) {
lwsl_notice("%s: detach %p from parent %p\n",
__func__, wsi, wsi->parent);
*pwsi = wsi->sibling_list;
break;
}
pwsi = &(*pwsi)->sibling_list;
}
if (*pwsi)
lwsl_err("%s: failed to detach from parent\n",
__func__);
}
#if LWS_POSIX
/*
@ -1182,6 +1206,18 @@ lws_wsi_user(struct lws *wsi)
return wsi->user_space;
}
LWS_VISIBLE LWS_EXTERN struct lws *
lws_get_parent(const struct lws *wsi)
{
return wsi->parent;
}
LWS_VISIBLE LWS_EXTERN struct lws *
lws_get_child(const struct lws *wsi)
{
return wsi->child_list;
}
LWS_VISIBLE LWS_EXTERN void
lws_close_reason(struct lws *wsi, enum lws_close_status status,
unsigned char *buf, size_t len)
@ -1480,9 +1516,11 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
}
for (n = 0; n < 3; n++) {
cgi->stdwsi[n]->master = wsi;
if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
goto bail3;
cgi->stdwsi[n]->parent = wsi;
cgi->stdwsi[n]->sibling_list = wsi->child_list;
wsi->child_list = cgi->stdwsi[n];
}
lws_change_pollfd(cgi->stdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT);
@ -1496,6 +1534,8 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
/* add us to the pt list of active cgis */
cgi->cgi_list = pt->cgi_list;
pt->cgi_list = cgi;
@ -1633,8 +1673,6 @@ lws_cgi_kill(struct lws *wsi)
if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) {
close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
wsi->cgi->pipe_fds[n][!!(n == 0)] = -1;
lws_close_free_wsi(wsi->cgi->stdwsi[n], 0);
}
}

View file

@ -1410,6 +1410,9 @@ struct lws_context_creation_info {
* @client_exts: array of extensions that may be used on connection
* @method: if non-NULL, do this http method instead of ws[s] upgrade.
* use "GET" to be a simple http client connection
* @parent_wsi: if another wsi is responsible for this connection, give it here.
* this is used to make sure if the parent closes so do any
* child connections first.
*/
struct lws_client_connect_info {
@ -1425,6 +1428,7 @@ struct lws_client_connect_info {
void *userdata;
const struct lws_extension *client_exts;
const char *method;
struct lws *parent_wsi;
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility
@ -1847,6 +1851,12 @@ lws_get_context(const struct lws *wsi);
LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_get_count_threads(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
lws_get_parent(const struct lws *wsi);
LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
lws_get_child(const struct lws *wsi);
#ifdef LWS_WITH_CGI
enum lws_enum_stdinouterr {
LWS_STDIN = 0,

View file

@ -1075,9 +1075,11 @@ struct lws {
/* pointers */
struct lws_context *context;
struct lws *parent; /* points to parent, if any */
struct lws *child_list; /* points to first child */
struct lws *sibling_list; /* subsequent children at same level */
#ifdef LWS_WITH_CGI
struct lws_cgi *cgi; /* wsi being cgi master have one of these */
struct lws *master; /* for stdin/out/err wsi to point to cgi master */
#endif
const struct lws_protocols *protocol;
struct lws *timeout_list;

View file

@ -871,12 +871,12 @@ handle_pending:
}
args.ch = wsi->cgi_channel;
args.stdwsi = &wsi->master->cgi->stdwsi[0];
args.stdwsi = &wsi->parent->cgi->stdwsi[0];
if (user_callback_handle_rxflow(
wsi->master->protocol->callback,
wsi->master, LWS_CALLBACK_CGI,
wsi->master->user_space,
wsi->parent->protocol->callback,
wsi->parent, LWS_CALLBACK_CGI,
wsi->parent->user_space,
(void *)&args, 0))
return 1;

View file

@ -8,6 +8,8 @@ echo "REQUEST_METHOD=$REQUEST_METHOD"
if [ "$REQUEST_METHOD" = "POST" ] ; then
read line
echo "read=\"$line\""
else
cat /proc/meminfo
fi
echo "done"