1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-30 00:00:16 +01:00

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_RECEIVE_CLIENT_HTTP = 46,
LWS_CALLBACK_COMPLETED_CLIENT_HTTP = 47, 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 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) { if (wsi && !wsi->user_space && i->userdata) {
wsi->user_space_externally_allocated = 1; wsi->user_space_externally_allocated = 1;
wsi->user_space = i->userdata; 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 #ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = i->ssl_connection; wsi->use_ssl = i->ssl_connection;
@ -417,11 +422,6 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
goto bail; goto bail;
} }
#endif #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 /* 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 * 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)) if (lws_header_table_attach(wsi, 0))
lwsl_debug("%s: went on ah wait list\n", __func__); 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; return wsi;
bail: bail:

View file

@ -142,10 +142,11 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
void void
lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason) lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
{ {
struct lws_context *context;
struct lws_context_per_thread *pt; struct lws_context_per_thread *pt;
int n, m, ret; struct lws **pwsi, *wsi1, *wsi2;
struct lws_context *context;
struct lws_tokens eff_buf; struct lws_tokens eff_buf;
int n, m, ret;
if (!wsi) if (!wsi)
return; return;
@ -153,24 +154,31 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
context = wsi->context; context = wsi->context;
pt = &context->pt[(int)wsi->tsi]; 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 #ifdef LWS_WITH_CGI
if (wsi->mode == LWSCM_CGI) { if (wsi->mode == LWSCM_CGI) {
/* we are not a network connection, but a handler for CGI io */ /* we are not a network connection, but a handler for CGI io */
assert(wsi->master); if (wsi->parent && wsi->parent->cgi)
assert(wsi->master->cgi);
assert(wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] == wsi);
/* end the binding between us and master */ /* end the binding between us and master */
wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] = NULL; wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
wsi->master = NULL;
wsi->socket_is_permanently_unusable = 1; wsi->socket_is_permanently_unusable = 1;
goto just_kill_connection; goto just_kill_connection;
} }
if (wsi->cgi) { if (wsi->cgi) {
/* we have a cgi going, we must kill it and close the /* we have a cgi going, we must kill it */
* related stdin/out/err wsis first
*/
wsi->cgi->being_closed = 1; wsi->cgi->being_closed = 1;
lws_cgi_kill(wsi); lws_cgi_kill(wsi);
} }
@ -327,6 +335,22 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
} }
just_kill_connection: 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 #if LWS_POSIX
/* /*
@ -1182,6 +1206,18 @@ lws_wsi_user(struct lws *wsi)
return wsi->user_space; 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_VISIBLE LWS_EXTERN void
lws_close_reason(struct lws *wsi, enum lws_close_status status, lws_close_reason(struct lws *wsi, enum lws_close_status status,
unsigned char *buf, size_t len) 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++) { for (n = 0; n < 3; n++) {
cgi->stdwsi[n]->master = wsi;
if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n])) if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
goto bail3; 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); 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); lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
/* add us to the pt list of active cgis */ /* add us to the pt list of active cgis */
cgi->cgi_list = pt->cgi_list; cgi->cgi_list = pt->cgi_list;
pt->cgi_list = cgi; pt->cgi_list = cgi;
@ -1633,8 +1673,6 @@ lws_cgi_kill(struct lws *wsi)
if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) { if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) {
close(wsi->cgi->pipe_fds[n][!!(n == 0)]); close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
wsi->cgi->pipe_fds[n][!!(n == 0)] = -1; 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 * @client_exts: array of extensions that may be used on connection
* @method: if non-NULL, do this http method instead of ws[s] upgrade. * @method: if non-NULL, do this http method instead of ws[s] upgrade.
* use "GET" to be a simple http client connection * 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 { struct lws_client_connect_info {
@ -1425,6 +1428,7 @@ struct lws_client_connect_info {
void *userdata; void *userdata;
const struct lws_extension *client_exts; const struct lws_extension *client_exts;
const char *method; const char *method;
struct lws *parent_wsi;
/* Add new things just above here ---^ /* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility * 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_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_get_count_threads(struct lws_context *context); 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 #ifdef LWS_WITH_CGI
enum lws_enum_stdinouterr { enum lws_enum_stdinouterr {
LWS_STDIN = 0, LWS_STDIN = 0,

View file

@ -1075,9 +1075,11 @@ struct lws {
/* pointers */ /* pointers */
struct lws_context *context; 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 #ifdef LWS_WITH_CGI
struct lws_cgi *cgi; /* wsi being cgi master have one of these */ 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 #endif
const struct lws_protocols *protocol; const struct lws_protocols *protocol;
struct lws *timeout_list; struct lws *timeout_list;

View file

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

View file

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