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
======
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;
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
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:
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;
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);
}
}
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
/*
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)
}
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);
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;
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);
}
}
* @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 {
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
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,
/* 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;
}
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;
if [ "$REQUEST_METHOD" = "POST" ] ; then
read line
echo "read=\"$line\""
+else
+ cat /proc/meminfo
fi
echo "done"