mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
ss: enforce balanced CONNECT vs DISCONNECT
This commit is contained in:
parent
b5d656058f
commit
93f54c61c5
14 changed files with 145 additions and 38 deletions
|
@ -318,7 +318,9 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
i->opaque_user_data;
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
wsi->for_ss = !!(i->ssl_connection & LCCSCF_SECSTREAM_CLIENT);
|
||||
wsi->for_ss = !!(i->ssl_connection & (LCCSCF_SECSTREAM_CLIENT | LCCSCF_SECSTREAM_PROXY_LINK | LCCSCF_SECSTREAM_PROXY_ONWARD));
|
||||
|
||||
wsi->client_bound_sspc = !!(i->ssl_connection & LCCSCF_SECSTREAM_PROXY_LINK); /* so wsi close understands need to remove sspc ptr to wsi */
|
||||
/* implies our opaque user ptr is the ss handle */
|
||||
if (wsi->for_ss) {
|
||||
/* it's related to ss... the options are
|
||||
|
@ -335,6 +337,9 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
|
|||
#endif
|
||||
&wsi->lc, "%s/%s/%s/(%s)", i->method ? i->method : "WS",
|
||||
wsi->role_ops->name, i->address,
|
||||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
wsi->client_bound_sspc ? lws_sspc_tag((lws_sspc_handle_t *)i->opaque_user_data) :
|
||||
#endif
|
||||
lws_ss_tag(((lws_ss_handle_t *)i->opaque_user_data)));
|
||||
} else
|
||||
#endif
|
||||
|
|
|
@ -520,11 +520,27 @@ just_kill_connection:
|
|||
* good, but we have to invalidate any pointer the related ss
|
||||
* handle may be holding on us
|
||||
*/
|
||||
lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
|
||||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
if (wsi->client_bound_sspc) {
|
||||
lws_sspc_handle_t *h = (lws_sspc_handle_t *)wsi->a.opaque_user_data;
|
||||
|
||||
if (h && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
|
||||
h->wsi = NULL;
|
||||
wsi->a.opaque_user_data = NULL;
|
||||
if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
|
||||
h->cwsi = NULL;
|
||||
wsi->a.opaque_user_data = NULL;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
lws_ss_handle_t *h = (lws_ss_handle_t *)wsi->a.opaque_user_data;
|
||||
|
||||
if (h) { // && (h->info.flags & LWSSSINFLAGS_ACCEPTED)) {
|
||||
|
||||
if (h->ss_dangling_connected)
|
||||
(void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
|
||||
|
||||
h->wsi = NULL;
|
||||
wsi->a.opaque_user_data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -843,6 +843,8 @@ struct lws {
|
|||
unsigned int shadow:1; /* we do not control fd lifecycle at all */
|
||||
#if defined(LWS_WITH_SECURE_STREAMS)
|
||||
unsigned int for_ss:1;
|
||||
unsigned int bound_ss_proxy_conn:1;
|
||||
unsigned int client_bound_sspc:1;
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_ACCESS_LOG
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
const char *
|
||||
lws_wsi_tag(struct lws *wsi)
|
||||
{
|
||||
if (!wsi)
|
||||
return "[null wsi]";
|
||||
return lws_lc_tag(&wsi->lc);
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,7 @@ typedef struct lws_ss_handle {
|
|||
uint8_t inside_msg:1;
|
||||
uint8_t being_serialized:1; /* we are not the consumer */
|
||||
uint8_t destroying:1;
|
||||
uint8_t ss_dangling_connected:1;
|
||||
} lws_ss_handle_t;
|
||||
|
||||
/* connection helper that doesn't need to hang around after connection starts */
|
||||
|
@ -300,6 +301,7 @@ typedef struct lws_sspc_handle {
|
|||
uint8_t pending_timeout_update:1;
|
||||
uint8_t pending_writeable_len:1;
|
||||
uint8_t creating_cb_done:1;
|
||||
uint8_t ss_dangling_connected:1;
|
||||
} lws_sspc_handle_t;
|
||||
|
||||
typedef struct backoffs {
|
||||
|
|
|
@ -394,6 +394,10 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_CLIENT_HTTP_REDIRECT:
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
if (h->policy->u.http.fail_redirect)
|
||||
lws_system_cpd_set(lws_get_context(wsi),
|
||||
LWS_CPD_CAPTIVE_PORTAL);
|
||||
|
@ -435,7 +439,11 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
||||
status = lws_http_client_http_response(wsi);
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
status = (int)lws_http_client_http_response(wsi);
|
||||
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: %d\n", __func__, status);
|
||||
// if (!status)
|
||||
/* it's just telling use we connected / joined the nwsi */
|
||||
|
@ -587,6 +595,8 @@ malformed:
|
|||
#endif
|
||||
|
||||
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
|
||||
if (!h)
|
||||
return -1;
|
||||
if (h->writeable_len)
|
||||
wsi->http.writeable_len = h->writeable_len;
|
||||
|
||||
|
@ -706,6 +716,10 @@ malformed:
|
|||
|
||||
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
||||
lwsl_debug("%s: LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n", __func__);
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
if (h->hanging_som) {
|
||||
h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
|
||||
h->hanging_som = 0;
|
||||
|
@ -859,6 +873,9 @@ malformed:
|
|||
#if defined(LWS_WITH_SERVER)
|
||||
case LWS_CALLBACK_HTTP:
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
lwsl_notice("%s: LWS_CALLBACK_HTTP\n", __func__);
|
||||
{
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
|
||||
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
|
||||
if (h->being_serialized) {
|
||||
/*
|
||||
|
@ -68,6 +71,10 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
// lwsl_err("%s: h2 COMPLETED_CLIENT_HTTP\n", __func__);
|
||||
if (h->hanging_som)
|
||||
r = h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
|
||||
|
@ -81,6 +88,10 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
break;
|
||||
|
||||
case LWS_CALLBACK_WSI_TX_CREDIT_GET:
|
||||
|
||||
if (!h)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* The peer has sent us additional tx credit...
|
||||
*/
|
||||
|
|
|
@ -535,6 +535,11 @@ lws_sspc_destroy(lws_sspc_handle_t **ph)
|
|||
|
||||
h->destroying = 1;
|
||||
|
||||
if (h->ss_dangling_connected && h->ssi.state) {
|
||||
h->ssi.state(m, NULL, LWSSSCS_DISCONNECTED, 0);
|
||||
h->ss_dangling_connected = 0;
|
||||
}
|
||||
|
||||
lws_sul_cancel(&h->sul_retry);
|
||||
lws_dll2_remove(&h->client_list);
|
||||
|
||||
|
@ -843,5 +848,7 @@ lws_sspc_change_handlers(struct lws_sspc_handle *h,
|
|||
const char *
|
||||
lws_sspc_tag(struct lws_sspc_handle *h)
|
||||
{
|
||||
if (!h)
|
||||
return "[null sspc]";
|
||||
return lws_lc_tag(&h->lc);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,9 @@
|
|||
* Because both sides of the connection share the conn, we allocate it
|
||||
* during accepted adoption, and both sides point to it.
|
||||
*
|
||||
* When .ss or .wsi close, they must NULL their entry here so no dangling
|
||||
* refereneces.
|
||||
*
|
||||
* The last one of the accepted side and the onward side to close frees it.
|
||||
*/
|
||||
|
||||
|
@ -62,7 +65,7 @@ struct conn {
|
|||
struct lws_ss_serialization_parser parser;
|
||||
|
||||
lws_dsh_t *dsh; /* unified buffer for both sides */
|
||||
struct lws *wsi; /* the client side */
|
||||
struct lws *wsi; /* the proxy's client side */
|
||||
lws_ss_handle_t *ss; /* the onward, ss side */
|
||||
|
||||
lws_ss_conn_states_t state;
|
||||
|
@ -284,6 +287,7 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
}
|
||||
|
||||
pss->conn->wsi = wsi;
|
||||
wsi->bound_ss_proxy_conn = 1;
|
||||
pss->conn->state = LPCSPROX_WAIT_INITIAL_TX;
|
||||
|
||||
/*
|
||||
|
@ -310,17 +314,39 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
* still live...
|
||||
*/
|
||||
|
||||
assert(conn->wsi == wsi);
|
||||
conn->wsi = NULL;
|
||||
|
||||
lwsl_notice("%s: cli->prox link %s closing\n",
|
||||
__func__, lws_wsi_tag(wsi));
|
||||
|
||||
/* sever relationship with conn */
|
||||
lws_set_opaque_user_data(wsi, NULL);
|
||||
|
||||
/*
|
||||
* The current wsi is decoupled from the pss / conn and
|
||||
* the conn no longer has a pointer on it
|
||||
*/
|
||||
|
||||
if (conn->ss) {
|
||||
struct lws *cw = conn->ss->wsi;
|
||||
/*
|
||||
* The onward connection is around
|
||||
* conn->ss is the onward connection SS
|
||||
*/
|
||||
|
||||
lwsl_info("%s: destroying %s, wsi %s\n",
|
||||
__func__, lws_ss_tag(conn->ss),
|
||||
lws_wsi_tag(conn->ss->wsi));
|
||||
/* sever relationship with ss about to be deleted */
|
||||
lws_set_opaque_user_data(wsi, NULL);
|
||||
if (cw && wsi != cw)
|
||||
conn->ss->wsi = NULL;
|
||||
|
||||
if (cw && wsi != cw) {
|
||||
|
||||
/* disconnect onward SS from its wsi */
|
||||
|
||||
lws_set_opaque_user_data(cw, NULL);
|
||||
|
||||
/*
|
||||
* The wsi doing the onward connection can no
|
||||
* longer relate to the conn... otherwise when
|
||||
|
@ -328,11 +354,13 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
* the ss we are about to delete
|
||||
*/
|
||||
lws_wsi_close(cw, LWS_TO_KILL_ASYNC);
|
||||
conn->wsi = NULL;
|
||||
conn->ss->wsi = NULL;
|
||||
}
|
||||
|
||||
lws_ss_destroy(&conn->ss);
|
||||
/* conn may have gone */
|
||||
/*
|
||||
* Conn may have gone, at ss destroy handler in
|
||||
* ssi.state for proxied ss
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1311,15 +1311,25 @@ payload_ff:
|
|||
h->creating_cb_done = 1;
|
||||
}
|
||||
|
||||
n = ssi->state(client_pss_to_userdata(pss),
|
||||
NULL, par->ctr, par->flags);
|
||||
switch (n) {
|
||||
case LWSSSSRET_OK:
|
||||
break;
|
||||
case LWSSSSRET_DISCONNECT_ME:
|
||||
goto hangup;
|
||||
case LWSSSSRET_DESTROY_ME:
|
||||
return LWSSSSRET_DESTROY_ME;
|
||||
if (ssi->state) {
|
||||
h = lws_container_of(par, lws_sspc_handle_t, parser);
|
||||
lws_ss_constate_t cs = (lws_ss_constate_t)par->ctr;
|
||||
|
||||
if (cs == LWSSSCS_CONNECTED)
|
||||
h->ss_dangling_connected = 1;
|
||||
if (cs == LWSSSCS_DISCONNECTED)
|
||||
h->ss_dangling_connected = 0;
|
||||
|
||||
n = ssi->state(client_pss_to_userdata(pss),
|
||||
NULL, (lws_ss_constate_t)par->ctr, par->flags);
|
||||
switch (n) {
|
||||
case LWSSSSRET_OK:
|
||||
break;
|
||||
case LWSSSSRET_DISCONNECT_ME:
|
||||
goto hangup;
|
||||
case LWSSSSRET_DESTROY_ME:
|
||||
return LWSSSSRET_DESTROY_ME;
|
||||
}
|
||||
}
|
||||
|
||||
swallow:
|
||||
|
|
|
@ -88,6 +88,11 @@ lws_ss_event_helper(lws_ss_handle_t *h, lws_ss_constate_t cs)
|
|||
if (!h)
|
||||
return LWSSSSRET_OK;
|
||||
|
||||
if (cs == LWSSSCS_CONNECTED)
|
||||
h->ss_dangling_connected = 1;
|
||||
if (cs == LWSSSCS_DISCONNECTED)
|
||||
h->ss_dangling_connected = 0;
|
||||
|
||||
#if defined(LWS_WITH_SEQUENCER)
|
||||
/*
|
||||
* A parent sequencer for the ss is optional, if we have one, keep it
|
||||
|
@ -904,6 +909,9 @@ lws_ss_destroy(lws_ss_handle_t **ppss)
|
|||
v = lws_get_vhost_by_name(h->context, h->policy->streamtype);
|
||||
#endif
|
||||
|
||||
if (h->ss_dangling_connected)
|
||||
(void)lws_ss_event_helper(h, LWSSSCS_DISCONNECTED);
|
||||
|
||||
(void)lws_ss_event_helper(h, LWSSSCS_DESTROYING);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
@ -1174,5 +1182,7 @@ lws_ss_change_handlers(struct lws_ss_handle *h,
|
|||
const char *
|
||||
lws_ss_tag(struct lws_ss_handle *h)
|
||||
{
|
||||
if (!h)
|
||||
return "[null ss]";
|
||||
return lws_lc_tag(&h->lc);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ lws_ss_sys_auth_api_amazon_com_kick(lws_sorted_usec_list_t *sul)
|
|||
struct lws_context *context = lws_container_of(sul, struct lws_context,
|
||||
sul_api_amazon_com_kick);
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
lws_state_transition_steps(&context->mgr_system,
|
||||
LWS_SYSTATE_OPERATIONAL);
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
|||
ab = lws_system_get_blob(context, LWS_SYSBLOB_TYPE_AUTH, AUTH_IDX_LWA);
|
||||
/* coverity */
|
||||
if (!ab)
|
||||
return -1;
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
|
||||
if (buf) {
|
||||
if (flags & LWSSS_FLAG_SOM) {
|
||||
|
@ -140,11 +141,11 @@ ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
|||
LWS_SYSBLOB_TYPE_AUTH,
|
||||
AUTH_IDX_LWA));
|
||||
|
||||
return -1;
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
}
|
||||
}
|
||||
if (!(flags & LWSSS_FLAG_EOM))
|
||||
return 0;
|
||||
return LWSSSSRET_OK;
|
||||
|
||||
/* we should have the auth token now */
|
||||
|
||||
|
@ -156,7 +157,7 @@ ss_api_amazon_auth_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
|||
|
||||
/* we move the system state at auth connection close */
|
||||
|
||||
return 0;
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
}
|
||||
|
||||
static lws_ss_state_return_t
|
||||
|
@ -182,7 +183,7 @@ ss_api_amazon_auth_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
|
|||
|
||||
n = lws_system_blob_get(ab, buf, len, m->pos);
|
||||
if (n < 0)
|
||||
return 1;
|
||||
return LWSSSSRET_TX_DONT_SEND;
|
||||
|
||||
if (!m->pos)
|
||||
*flags |= LWSSS_FLAG_SOM;
|
||||
|
@ -194,7 +195,7 @@ ss_api_amazon_auth_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
|
|||
m->pos = 0; /* for next time */
|
||||
}
|
||||
|
||||
return 0;
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
static lws_ss_state_return_t
|
||||
|
@ -253,7 +254,7 @@ ss_api_amazon_auth_state(void *userobj, void *sh, lws_ss_constate_t state,
|
|||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -56,14 +56,14 @@ ss_fetch_policy_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
|||
if (flags & LWSSS_FLAG_EOM)
|
||||
m->partway = 2;
|
||||
|
||||
return 0;
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
static lws_ss_state_return_t
|
||||
ss_fetch_policy_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
|
||||
size_t *len, int *flags)
|
||||
{
|
||||
return 1;
|
||||
return LWSSSSRET_TX_DONT_SEND;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -111,20 +111,16 @@ ss_fetch_policy_state(void *userobj, void *sh, lws_ss_constate_t state,
|
|||
switch (m->partway) {
|
||||
case 2:
|
||||
lws_sul_schedule(context, 0, &m->sul, policy_set, 1);
|
||||
m->partway = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWSSSCS_DISCONNECTED:
|
||||
lwsl_notice("%s: DISCONNECTED\n", __func__);
|
||||
switch (m->partway) {
|
||||
case 1:
|
||||
if (m->partway == 1) {
|
||||
lws_ss_policy_parse_abandon(context);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
lws_sul_schedule(context, 0, &m->sul, policy_set, 1);
|
||||
break;
|
||||
}
|
||||
m->partway = 0;
|
||||
break;
|
||||
|
@ -133,7 +129,7 @@ ss_fetch_policy_state(void *userobj, void *sh, lws_ss_constate_t state,
|
|||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -472,7 +472,7 @@ struct tests_seq {
|
|||
|
||||
{
|
||||
"h1:80 NXDOMAIN",
|
||||
"nxd_h1", 35 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE,
|
||||
"nxd_h1", 65 * LWS_US_PER_SEC, LWSSSCS_UNREACHABLE,
|
||||
(1 << LWSSSCS_QOS_ACK_REMOTE) | (1 << LWSSSCS_QOS_NACK_REMOTE) |
|
||||
(1 << LWSSSCS_TIMEOUT) | (1 << LWSSSCS_ALL_RETRIES_FAILED)
|
||||
},
|
||||
|
|
Loading…
Add table
Reference in a new issue