diff --git a/CMakeLists.txt b/CMakeLists.txt index cc50eb3c..de16b5d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -951,7 +951,7 @@ if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_C_COMPILER_ID set (GCOV_FLAGS "-fprofile-arcs -ftest-coverage -O0") endif() if (UNIX AND NOT LWS_WITH_ESP32) - set(CMAKE_C_FLAGS "-O3 -Wall -Wsign-compare -Wignored-qualifiers -Wtype-limits -Wuninitialized -Werror ${VISIBILITY_FLAG} -Wundef ${GCOV_FLAGS} ${CMAKE_C_FLAGS}" ) + set(CMAKE_C_FLAGS "-O0 -Wall -Wsign-compare -Wignored-qualifiers -Wtype-limits -Wuninitialized -Werror ${VISIBILITY_FLAG} -Wundef ${GCOV_FLAGS} ${CMAKE_C_FLAGS}" ) else() set(CMAKE_C_FLAGS "-Wall -Wsign-compare -Wignored-qualifiers -Wtype-limits -Wuninitialized -Werror ${VISIBILITY_FLAG} ${GCOV_FLAGS} ${CMAKE_C_FLAGS}" ) endif() diff --git a/lib/client/client-handshake.c b/lib/client/client-handshake.c index c1bfb54a..35e8075f 100644 --- a/lib/client/client-handshake.c +++ b/lib/client/client-handshake.c @@ -100,8 +100,8 @@ lws_client_connect_2(struct lws *wsi) * going through the queue */ if (w->client_h2_alpn && - (w->state == LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS || - w->state == LWSS_HTTP2_CLIENT_ESTABLISHED)) { + (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS || + lwsi_state(w) == LRS_ESTABLISHED)) { lwsl_info("%s: just join h2 directly\n", __func__); @@ -114,7 +114,7 @@ lws_client_connect_2(struct lws *wsi) #endif lwsl_info("applying %p to txn queue on %p (%d)\n", wsi, w, - w->state); + lwsi_state(w)); /* * ...let's add ourselves to his transaction queue... */ @@ -334,7 +334,7 @@ create_new_conn: goto oom4; } - wsi->mode = LWSCM_WSCL_WAITING_CONNECT; + lwsi_set_state(wsi, LRS_WAITING_CONNECT); lws_libev_accept(wsi, wsi->desc); lws_libuv_accept(wsi, wsi->desc); @@ -449,7 +449,7 @@ create_new_conn: lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE, AWAITING_TIMEOUT); - wsi->mode = LWSCM_WSCL_WAITING_PROXY_REPLY; + lwsi_set_state(wsi, LRS_WAITING_PROXY_REPLY); return wsi; } @@ -467,7 +467,7 @@ create_new_conn: lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY, AWAITING_TIMEOUT); - wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY; + lwsi_set_state(wsi, LRS_WAITING_SOCKS_GREETING_REPLY); return wsi; } @@ -480,13 +480,14 @@ send_hs: * We are pipelining on an already-established connection... * we can skip tls establishment. */ - wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE2; + + lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2); /* * we can't send our headers directly, because they have to * be sent when the parent is writeable. The parent will check * for anybody on his client transaction queue that is in - * LWSCM_WSCL_ISSUE_HANDSHAKE2, and let them write. + * LRS_H1C_ISSUE_HANDSHAKE2, and let them write. * * If we are trying to do this too early, before the master * connection has written his own headers, @@ -495,7 +496,7 @@ send_hs: lwsl_debug("wsi %p: waiting to send headers\n", wsi); } else { /* we are making our own connection */ - wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE; + lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE); /* * provoke service to issue the handshake directly. @@ -546,11 +547,7 @@ oom4: /* we're closing, losing some rx is OK */ lws_header_table_force_to_detachable_state(wsi); - if (wsi->mode == LWSCM_HTTP_CLIENT || - wsi->mode == LWSCM_HTTP2_CLIENT || - wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED || - wsi->mode == LWSCM_HTTP2_CLIENT_ACCEPTED || - wsi->mode == LWSCM_WSCL_WAITING_CONNECT) { + if (lwsi_role_client(wsi) && !(lwsi_state(wsi) & LWSIFS_NOTEST)) { wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, (void *)cce, strlen(cce)); @@ -654,7 +651,7 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port, #endif wsi->desc.sockfd = LWS_SOCK_INVALID; - wsi->state = LWSS_CLIENT_UNCONNECTED; + lwsi_set_state(wsi, LRS_UNCONNECTED); wsi->protocol = NULL; wsi->pending_timeout = NO_PENDING_TIMEOUT; wsi->c_port = port; @@ -878,7 +875,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i) wsi->context = i->context; /* assert the mode and union status (hdr) clearly */ - lws_union_transition(wsi, LWSCM_HTTP_CLIENT); + lws_role_transition(wsi, LWSI_ROLE_H1_CLIENT, LRS_UNCONNECTED); wsi->desc.sockfd = LWS_SOCK_INVALID; /* 1) fill up the wsi with stuff from the connect_info as far as it @@ -903,7 +900,6 @@ lws_client_connect_via_info(struct lws_client_connect_info *i) } wsi->user_space = NULL; - wsi->state = LWSS_CLIENT_UNCONNECTED; wsi->pending_timeout = NO_PENDING_TIMEOUT; wsi->position_in_fds_table = -1; wsi->c_port = i->port; @@ -920,6 +916,9 @@ lws_client_connect_via_info(struct lws_client_connect_info *i) wsi->protocol = &wsi->vhost->protocols[0]; wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE); + /* reasonable place to start */ + lwsi_set_role(wsi, LWSI_ROLE_H1_CLIENT); + /* * 1) for http[s] connection, allow protocol selection by name * 2) for ws[s], if local_protocol_name given also use it for @@ -1093,27 +1092,6 @@ lws_client_connect_via_info2(struct lws *wsi) lws_client_stash_destroy(wsi); #endif - /* - * Check with each extension if it is able to route and proxy this - * connection for us. For example, an extension like x-google-mux - * can handle this and then we don't need an actual socket for this - * connection. - */ - - if (lws_ext_cb_all_exts(wsi->context, wsi, - LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION, - (void *)stash->address, - wsi->c_port) > 0) { - lwsl_client("lws_client_connect: ext handling conn\n"); - - lws_set_timeout(wsi, - PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE, - AWAITING_TIMEOUT); - - wsi->mode = LWSCM_WSCL_WAITING_EXTENSION_CONNECT; - return wsi; - } - lwsl_client("lws_client_connect: direct conn\n"); wsi->context->count_wsi_allocated++; return lws_client_connect_2(wsi); diff --git a/lib/client/client-parser.c b/lib/client/client-parser.c index 9174a528..8c754eb7 100644 --- a/lib/client/client-parser.c +++ b/lib/client/client-parser.c @@ -352,8 +352,8 @@ spill: wsi->ws->rx_ubuf_head - 2)) goto utf8_fail; - /* is this an acknowledgement of our close? */ - if (wsi->state == LWSS_AWAITING_CLOSE_ACK) { + /* is this an acknowledgment of our close? */ + if (lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) { /* * fine he has told us he is closing too, let's * finish our close @@ -404,7 +404,7 @@ spill: &wsi->ws->rx_ubuf[LWS_PRE], wsi->ws->rx_ubuf_head, LWS_WRITE_CLOSE); - wsi->state = LWSS_RETURNED_CLOSE_ALREADY; + lwsi_set_state(wsi, LRS_RETURNED_CLOSE); /* close the connection */ return -1; @@ -573,9 +573,9 @@ utf8_fail: else lws_remove_wsi_from_draining_ext_list(wsi); - if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY || - wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION || - wsi->state == LWSS_AWAITING_CLOSE_ACK) + if (lwsi_state(wsi) == LRS_RETURNED_CLOSE || + lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE || + lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) goto already_done; m = wsi->protocol->callback(wsi, diff --git a/lib/client/client.c b/lib/client/client.c index 0799d83e..46964bfd 100644 --- a/lib/client/client.c +++ b/lib/client/client.c @@ -26,47 +26,43 @@ lws_handshake_client(struct lws *wsi, unsigned char **buf, size_t len) { int m; - switch (wsi->mode) { - case LWSCM_WSCL_WAITING_PROXY_REPLY: - case LWSCM_WSCL_ISSUE_HANDSHAKE: - case LWSCM_WSCL_WAITING_SERVER_REPLY: - case LWSCM_WSCL_WAITING_EXTENSION_CONNECT: - case LWSCM_WS_CLIENT: - while (len) { - /* - * we were accepting input but now we stopped doing so - */ - if (lws_is_flowcontrolled(wsi)) { - lwsl_debug("%s: caching %ld\n", __func__, (long)len); - lws_rxflow_cache(wsi, *buf, 0, (int)len); - return 0; - } - if (wsi->ws->rx_draining_ext) { -#if !defined(LWS_NO_CLIENT) - if (wsi->mode == LWSCM_WS_CLIENT) - m = lws_client_rx_sm(wsi, 0); - else -#endif - m = lws_rx_sm(wsi, 0); - if (m < 0) - return -1; - continue; - } - /* account for what we're using in rxflow buffer */ - if (wsi->rxflow_buffer) - wsi->rxflow_pos++; - - if (lws_client_rx_sm(wsi, *(*buf)++)) { - lwsl_debug("client_rx_sm exited\n"); - return -1; - } - len--; - } - lwsl_debug("%s: finished with %ld\n", __func__, (long)len); + if ((lwsi_state(wsi) != LRS_WAITING_PROXY_REPLY) && + (lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE) && + (lwsi_state(wsi) != LRS_WAITING_SERVER_REPLY) && + !lwsi_role_client(wsi)) return 0; - default: - break; + + while (len) { + /* + * we were accepting input but now we stopped doing so + */ + if (lws_is_flowcontrolled(wsi)) { + lwsl_debug("%s: caching %ld\n", __func__, (long)len); + lws_rxflow_cache(wsi, *buf, 0, (int)len); + return 0; + } + if (wsi->ws->rx_draining_ext) { +#if !defined(LWS_NO_CLIENT) + if (lwsi_role_client(wsi)) + m = lws_client_rx_sm(wsi, 0); + else +#endif + m = lws_rx_sm(wsi, 0); + if (m < 0) + return -1; + continue; + } + /* account for what we're using in rxflow buffer */ + if (wsi->rxflow_buffer) + wsi->rxflow_pos++; + + if (lws_client_rx_sm(wsi, *(*buf)++)) { + lwsl_debug("client_rx_sm exited\n"); + return -1; + } + len--; } + lwsl_debug("%s: finished with %ld\n", __func__, (long)len); return 0; } @@ -163,7 +159,7 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, struct lws *w = lws_container_of(d, struct lws, dll_client_transaction_queue); - if (w->mode == LWSCM_WSCL_ISSUE_HANDSHAKE2) { + if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) { /* * pollfd has the master sockfd in it... we * need to use that in HANDSHAKE2 to understand @@ -179,9 +175,9 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, return 0; } - switch (wsi->mode) { + switch (lwsi_state(wsi)) { - case LWSCM_WSCL_WAITING_CONNECT: + case LRS_WAITING_CONNECT: /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE @@ -199,9 +195,9 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, #if defined(LWS_WITH_SOCKS5) /* SOCKS Greeting Reply */ - case LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY: - case LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY: - case LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY: + case LRS_WAITING_SOCKS_GREETING_REPLY: + case LRS_WAITING_SOCKS_AUTH_REPLY: + case LRS_WAITING_SOCKS_CONNECT_REPLY: /* handle proxy hung up on us */ @@ -221,16 +217,16 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, goto bail3; } - switch (wsi->mode) { + switch (lwsi_state(wsi)) { - case LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY: + case LRS_WAITING_SOCKS_GREETING_REPLY: if (pt->serv_buf[0] != SOCKS_VERSION_5) goto socks_reply_fail; if (pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH) { lwsl_client("SOCKS GR: No Auth Method\n"); socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len); - conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY; + conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY; pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY; goto socks_send; @@ -241,21 +237,21 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, socks_generate_msg(wsi, SOCKS_MSG_USERNAME_PASSWORD, &len); - conn_mode = LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY; + conn_mode = LRS_WAITING_SOCKS_AUTH_REPLY; pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY; goto socks_send; } goto socks_reply_fail; - case LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY: + case LRS_WAITING_SOCKS_AUTH_REPLY: if (pt->serv_buf[0] != SOCKS_SUBNEGOTIATION_VERSION_1 || pt->serv_buf[1] != SOCKS_SUBNEGOTIATION_STATUS_SUCCESS) goto socks_reply_fail; lwsl_client("SOCKS password OK, sending connect\n"); socks_generate_msg(wsi, SOCKS_MSG_CONNECT, &len); - conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY; + conn_mode = LRS_WAITING_SOCKS_CONNECT_REPLY; pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY; socks_send: @@ -267,7 +263,7 @@ socks_send: } lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT); - wsi->mode = conn_mode; + lwsi_set_state(wsi, conn_mode); break; socks_reply_fail: @@ -275,7 +271,7 @@ socks_reply_fail: pt->serv_buf[0], pt->serv_buf[1]); goto bail3; - case LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY: + case LRS_WAITING_SOCKS_CONNECT_REPLY: if (pt->serv_buf[0] != SOCKS_VERSION_5 || pt->serv_buf[1] != SOCKS_REQUEST_REPLY_SUCCESS) goto socks_reply_fail; @@ -298,7 +294,7 @@ socks_reply_fail: break; #endif - case LWSCM_WSCL_WAITING_PROXY_REPLY: + case LRS_WAITING_PROXY_REPLY: /* handle proxy hung up on us */ @@ -333,7 +329,7 @@ socks_reply_fail: /* fallthru */ - case LWSCM_WSCL_ISSUE_HANDSHAKE: + case LRS_H1C_ISSUE_HANDSHAKE: /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE @@ -370,7 +366,7 @@ start_ws_handshake: /* fallthru */ - case LWSCM_WSCL_WAITING_SSL: + case LRS_WAITING_SSL: if (wsi->use_ssl & LCCSCF_USE_SSL) { n = lws_ssl_client_connect2(wsi, ebuf, sizeof(ebuf)); @@ -395,8 +391,8 @@ start_ws_handshake: lwsl_info("client connection upgraded to h2\n"); lws_h2_configure_if_upgraded(wsi); - lws_union_transition(wsi, LWSCM_HTTP2_CLIENT); - wsi->state = LWSS_HTTP2_CLIENT_SEND_SETTINGS; + lws_role_transition(wsi, LWSI_ROLE_H2_CLIENT, + LRS_H2_CLIENT_SEND_SETTINGS); /* send the H2 preface to legitimize the connection */ if (lws_h2_issue_preface(wsi)) { @@ -407,16 +403,16 @@ start_ws_handshake: break; } #endif - wsi->mode = LWSCM_WSCL_ISSUE_HANDSHAKE2; + lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2); lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND, context->timeout_secs); /* fallthru */ - case LWSCM_WSCL_ISSUE_HANDSHAKE2: + case LRS_H1C_ISSUE_HANDSHAKE2: p = lws_generate_client_handshake(wsi, p); if (p == NULL) { - if (wsi->mode == LWSCM_RAW) + if (lwsi_role_raw(wsi)) return 0; lwsl_err("Failed to generate handshake for client\n"); @@ -445,7 +441,7 @@ start_ws_handshake: } if (wsi->client_http_body_pending) { - wsi->mode = LWSCM_WSCL_ISSUE_HTTP_BODY; + lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY); lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD, context->timeout_secs); @@ -457,7 +453,7 @@ start_ws_handshake: goto client_http_body_sent; - case LWSCM_WSCL_ISSUE_HTTP_BODY: + case LRS_ISSUE_HTTP_BODY: if (wsi->client_http_body_pending) { lws_set_timeout(wsi, PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD, @@ -469,12 +465,12 @@ client_http_body_sent: /* prepare ourselves to do the parsing */ wsi->ah->parser_state = WSI_TOKEN_NAME_PART; wsi->ah->lextable_pos = 0; - wsi->mode = LWSCM_WSCL_WAITING_SERVER_REPLY; + lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY); lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, context->timeout_secs); break; - case LWSCM_WSCL_WAITING_SERVER_REPLY: + case LRS_WAITING_SERVER_REPLY: /* * handle server hanging up on us... * but if there is POLLIN waiting, handle that first @@ -556,13 +552,6 @@ bail3: lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "cbail3"); return -1; - case LWSCM_WSCL_WAITING_EXTENSION_CONNECT: - lwsl_ext("LWSCM_WSCL_WAITING_EXTENSION_CONNECT\n"); - break; - - case LWSCM_WSCL_PENDING_CANDIDATE_CHILD: - lwsl_ext("LWSCM_WSCL_PENDING_CANDIDATE_CHILD\n"); - break; default: break; } @@ -598,8 +587,8 @@ lws_http_transaction_completed_client(struct lws *wsi) if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff, LWS_CALLBACK_COMPLETED_CLIENT_HTTP, wsi_eff->user_space, NULL, 0)) { - lwsl_debug("%s: Completed call returned nonzero (mode %d)\n", - __func__, wsi_eff->mode); + lwsl_debug("%s: Completed call returned nonzero (role 0x%x)\n", + __func__, lwsi_role(wsi_eff)); return -1; } @@ -652,17 +641,16 @@ lws_http_transaction_completed_client(struct lws *wsi) /* * H1: we can serialize the queued guys into into the same ah - * (H2: everybody needs their own ah until STREAM_END) + * H2: everybody needs their own ah until their own STREAM_END */ /* otherwise set ourselves up ready to go again */ - wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED; + lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY); wsi->http.rx_content_length = 0; wsi->hdr_parsing_completed = 0; wsi->ah->parser_state = WSI_TOKEN_NAME_PART; wsi->ah->lextable_pos = 0; - wsi->mode = LWSCM_WSCL_WAITING_SERVER_REPLY; lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, wsi->context->timeout_secs); @@ -729,10 +717,12 @@ lws_client_interpret_server_handshake(struct lws *wsi) /* we are being an http client... */ if (wsi->client_h2_alpn) - lws_union_transition(wsi, LWSCM_HTTP2_CLIENT_ACCEPTED); + lws_role_transition(wsi, LWSI_ROLE_H2_CLIENT, + LRS_ESTABLISHED); else - lws_union_transition(wsi, LWSCM_HTTP_CLIENT_ACCEPTED); - wsi->state = LWSS_CLIENT_HTTP_ESTABLISHED; + lws_role_transition(wsi, LWSI_ROLE_H1_CLIENT, + LRS_ESTABLISHED); + wsi->ah = ah; ah->http_response = 0; } @@ -889,9 +879,10 @@ lws_client_interpret_server_handshake(struct lws *wsi) ww->client_pipeline = 0; /* go back to "trying to connect" state */ - lws_union_transition(ww, LWSCM_HTTP_CLIENT); + lws_role_transition(ww, + LWSI_ROLE_H1_CLIENT, + LRS_UNCONNECTED); ww->user_space = NULL; - ww->state = LWSS_CLIENT_UNCONNECTED; } lws_end_foreach_dll_safe(d, d1); lws_vhost_unlock(wsi->vhost); } @@ -1084,7 +1075,7 @@ lws_client_interpret_server_handshake(struct lws *wsi) */ n = 0; /* keep client connection pre-bound protocol */ - if (!(wsi->mode & LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP)) + if (!lwsi_role_client(wsi)) wsi->protocol = NULL; while (wsi->vhost->protocols[n].callback) { @@ -1098,7 +1089,7 @@ lws_client_interpret_server_handshake(struct lws *wsi) if (!wsi->vhost->protocols[n].callback) { /* no match */ /* if server, that's already fatal */ - if (!(wsi->mode & LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP)) { + if (!lwsi_role_client(wsi)) { lwsl_info("%s: fail protocol %s\n", __func__, p); cce = "HS: Cannot match protocol"; goto bail2; @@ -1336,8 +1327,7 @@ check_accept: /* free up his parsing allocations */ lws_header_table_detach(wsi, 0); - lws_union_transition(wsi, LWSCM_WS_CLIENT); - wsi->state = LWSS_ESTABLISHED; + lws_role_transition(wsi, LWSI_ROLE_H1_CLIENT, LRS_ESTABLISHED); lws_restart_ws_ping_pong_timer(wsi); wsi->rxflow_change_to = LWS_RXFLOW_ALLOW; @@ -1370,6 +1360,8 @@ check_accept: } #endif + lwsi_set_role(wsi, LWSI_ROLE_WS1_CLIENT); + lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name); /* call him back to inform him he is up */ @@ -1470,7 +1462,7 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt) return NULL; lws_header_table_force_to_detachable_state(wsi); - lws_union_transition(wsi, LWSCM_RAW); + lws_role_transition(wsi, LWSI_ROLE_RAW_SOCKET, LRS_ESTABLISHED); lws_header_table_detach(wsi, 1); return NULL; diff --git a/lib/client/ssl-client.c b/lib/client/ssl-client.c index fbe7a9b7..82bdb896 100644 --- a/lib/client/ssl-client.c +++ b/lib/client/ssl-client.c @@ -29,8 +29,7 @@ lws_ssl_client_connect1(struct lws *wsi) lws_latency_pre(context, wsi); n = lws_tls_client_connect(wsi); - lws_latency(context, wsi, - "SSL_connect LWSCM_WSCL_ISSUE_HANDSHAKE", n, n > 0); + lws_latency(context, wsi, "SSL_connect hs", n, n > 0); switch (n) { case LWS_SSL_CAPABLE_ERROR: @@ -41,7 +40,7 @@ lws_ssl_client_connect1(struct lws *wsi) lws_callback_on_writable(wsi); /* fallthru */ case LWS_SSL_CAPABLE_MORE_SERVICE_READ: - wsi->mode = LWSCM_WSCL_WAITING_SSL; + lwsi_set_state(wsi, LRS_WAITING_SSL); break; case LWS_SSL_CAPABLE_MORE_SERVICE: break; @@ -55,13 +54,13 @@ lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len) { int n = 0; - if (wsi->mode == LWSCM_WSCL_WAITING_SSL) { + if (lwsi_state(wsi) == LRS_WAITING_SSL) { lws_latency_pre(wsi->context, wsi); n = lws_tls_client_connect(wsi); lwsl_debug("%s: SSL_connect says %d\n", __func__, n); lws_latency(wsi->context, wsi, - "SSL_connect LWSCM_WSCL_WAITING_SSL", n, n > 0); + "SSL_connect LRS_WAITING_SSL", n, n > 0); switch (n) { case LWS_SSL_CAPABLE_ERROR: @@ -73,7 +72,7 @@ lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len) lws_callback_on_writable(wsi); /* fallthru */ case LWS_SSL_CAPABLE_MORE_SERVICE_READ: - wsi->mode = LWSCM_WSCL_WAITING_SSL; + lwsi_set_state(wsi, LRS_WAITING_SSL); /* fallthru */ case LWS_SSL_CAPABLE_MORE_SERVICE: return 0; diff --git a/lib/context.c b/lib/context.c index 33dbbe07..dca7e294 100644 --- a/lib/context.c +++ b/lib/context.c @@ -966,7 +966,7 @@ lws_create_event_pipes(struct lws_context *context) return 1; } wsi->context = context; - wsi->mode = LWSCM_EVENT_PIPE; + lwsi_set_role(wsi, LWSI_ROLE_EVENT_PIPE); wsi->protocol = NULL; wsi->tsi = n; wsi->vhost = NULL; diff --git a/lib/event-libs/libev.c b/lib/event-libs/libev.c index 8f12fb7a..ca8992cc 100644 --- a/lib/event-libs/libev.c +++ b/lib/event-libs/libev.c @@ -185,7 +185,7 @@ lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc) if (!LWS_LIBEV_ENABLED(context)) return; - if (new_wsi->mode == LWSCM_RAW_FILEDESC) + if (lwsi_role(new_wsi) == LWSI_ROLE_RAW_FILE) fd = desc.filefd; else fd = desc.sockfd; diff --git a/lib/event-libs/libevent.c b/lib/event-libs/libevent.c index 61af5d3f..ddd9dde5 100644 --- a/lib/event-libs/libevent.c +++ b/lib/event-libs/libevent.c @@ -174,7 +174,7 @@ lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc) // Initialize the event pt = &context->pt[(int)new_wsi->tsi]; - if (new_wsi->mode == LWSCM_RAW_FILEDESC) + if (lwsi_role(new_wsi) == LWSI_ROLE_RAW_FILE) fd = desc.filefd; else fd = desc.sockfd; diff --git a/lib/event-libs/libuv.c b/lib/event-libs/libuv.c index f84ed458..15f93cc3 100644 --- a/lib/event-libs/libuv.c +++ b/lib/event-libs/libuv.c @@ -429,7 +429,7 @@ lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc) return; wsi->w_read.context = context; - if (wsi->mode == LWSCM_RAW_FILEDESC || wsi->event_pipe) + if (lwsi_role(wsi) == LWSI_ROLE_RAW_FILE || wsi->event_pipe) uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, (int)(long long)desc.filefd); else @@ -543,7 +543,7 @@ lws_libuv_closewsi(uv_handle_t* handle) * We get called back here for every wsi that closes */ - if (wsi->mode == LWSCM_SERVER_LISTENER && + if (lwsi_role(wsi) == LWSI_ROLE_LISTEN_SOCKET && wsi->context->deprecated) { lspd = 1; context->deprecation_pending_listen_close_count--; diff --git a/lib/handshake.c b/lib/handshake.c index 77d0cc1f..2a89fec0 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -65,20 +65,17 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) unsigned char *last_char, *oldbuf = buf; lws_filepos_t body_chunk_len; size_t n; -#if defined(LWS_WITH_HTTP2) - int m; -#endif - // lwsl_notice("%s: state %d\n", __func__, wsi->state); - - switch (wsi->state) { #if defined(LWS_WITH_HTTP2) - case LWSS_HTTP2_CLIENT_ESTABLISHED: - case LWSS_HTTP2_CLIENT_SEND_SETTINGS: - case LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS: - case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: - case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS: - case LWSS_HTTP2_ESTABLISHED: + + if (lwsi_role_h2(wsi) && + !lwsi_role_ws(wsi) && + lwsi_state(wsi) != LRS_BODY) { + int m; + + // lwsl_notice("%s: h2 path: wsistate 0x%x len %d\n", __func__, + // wsi->wsistate, (int)len); + /* * wsi here is always the network connection wsi, not a stream * wsi. Once we unpicked the framing we will find the right @@ -143,23 +140,32 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) len -= body_chunk_len; } // lwsl_debug("%s: used up block\n", __func__); - break; + goto read_ok; + } #endif - case LWSS_HTTP_ISSUING_FILE: + // lwsl_notice("%s: h1 path: wsi state 0x%x\n", __func__, lwsi_state(wsi)); + + switch (lwsi_state(wsi)) { + + case LRS_ISSUING_FILE: return 0; - case LWSS_CLIENT_HTTP_ESTABLISHED: - break; + case LRS_ESTABLISHED: + + if (lwsi_role_non_ws_client(wsi)) + break; + + if (lwsi_role_ws(wsi)) + goto ws_mode; - case LWSS_HTTP: wsi->hdr_parsing_completed = 0; /* fallthru */ - case LWSS_HTTP_HEADERS: + case LRS_HEADERS: if (!wsi->ah) { - lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__); + lwsl_err("%s: LRS_HEADERS: NULL ah\n", __func__); assert(0); } lwsl_parser("issuing %d bytes to parser\n", (int)len); @@ -173,7 +179,7 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) goto bail; /* we might have transitioned to RAW */ - if (wsi->mode == LWSCM_RAW) + if (lwsi_role_raw(wsi)) /* we gave the read buffer to RAW handler already */ goto read_ok; @@ -191,13 +197,13 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) /* More header content on the way */ goto read_ok; - switch (wsi->state) { - case LWSS_HTTP: - case LWSS_HTTP_HEADERS: + switch (lwsi_state(wsi)) { + case LRS_ESTABLISHED: + case LRS_HEADERS: goto read_ok; - case LWSS_HTTP_ISSUING_FILE: + case LRS_ISSUING_FILE: goto read_ok; - case LWSS_HTTP_BODY: + case LRS_BODY: wsi->http.rx_content_remain = wsi->http.rx_content_length; if (wsi->http.rx_content_remain) @@ -210,7 +216,7 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) } break; - case LWSS_HTTP_BODY: + case LRS_BODY: http_postbody: //lwsl_notice("http post body\n"); while (len && wsi->http.rx_content_remain) { @@ -281,24 +287,25 @@ postbody_completion: goto bail; if (wsi->http2_substream) - wsi->state = LWSS_HTTP2_ESTABLISHED; + lwsi_set_state(wsi, LRS_ESTABLISHED); } break; } break; - case LWSS_ESTABLISHED: - case LWSS_AWAITING_CLOSE_ACK: - case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION: - case LWSS_SHUTDOWN: - case LWSS_SHUTDOWN | _LSF_POLLOUT | _LSF_CCB: + case LRS_AWAITING_CLOSE_ACK: + case LRS_WAITING_TO_SEND_CLOSE: + case LRS_SHUTDOWN: + +ws_mode: + if (lws_handshake_client(wsi, &buf, (size_t)len)) goto bail; - switch (wsi->mode) { - case LWSCM_WS_SERVING: - case LWSCM_HTTP2_WS_SERVING: + switch (lwsi_role(wsi)) { + case LWSI_ROLE_WS1_SERVER: + case LWSI_ROLE_WS2_SERVER: /* * for h2 we are on the swsi */ @@ -311,17 +318,20 @@ postbody_completion: } break; - case LWSS_HTTP_DEFERRING_ACTION: - lwsl_debug("%s: LWSS_HTTP_DEFERRING_ACTION\n", __func__); + case LRS_DEFERRING_ACTION: + lwsl_debug("%s: LRS_DEFERRING_ACTION\n", __func__); break; - case LWSS_DEAD_SOCKET: - lwsl_err("%s: Unhandled state LWSS_DEAD_SOCKET\n", __func__); + case LRS_SSL_ACK_PENDING: + break; + + case LRS_DEAD_SOCKET: + lwsl_err("%s: Unhandled state LRS_DEAD_SOCKET\n", __func__); assert(0); /* fallthru */ default: - lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state); + lwsl_err("%s: Unhandled state %d\n", __func__, lwsi_state(wsi)); goto bail; } diff --git a/lib/header.c b/lib/header.c index 7c2ef9b7..1be0f7b9 100644 --- a/lib/header.c +++ b/lib/header.c @@ -38,7 +38,7 @@ lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name, unsigned char **p, unsigned char *end) { #ifdef LWS_WITH_HTTP2 - if (wsi->mode == LWSCM_HTTP2_SERVING || wsi->mode == LWSCM_HTTP2_CLIENT_ACCEPTED) + if (lwsi_role_h2(wsi)) return lws_add_http2_header_by_name(wsi, name, value, length, p, end); #else @@ -66,7 +66,7 @@ int lws_finalize_http_header(struct lws *wsi, unsigned char **p, unsigned char *end) { #ifdef LWS_WITH_HTTP2 - if (wsi->mode == LWSCM_HTTP2_SERVING || wsi->mode == LWSCM_HTTP2_CLIENT_ACCEPTED) + if (lwsi_role_h2(wsi)) return 0; #else (void)wsi; @@ -105,7 +105,7 @@ lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token, { const unsigned char *name; #ifdef LWS_WITH_HTTP2 - if (wsi->mode == LWSCM_HTTP2_SERVING || wsi->mode == LWSCM_HTTP2_CLIENT_ACCEPTED) + if (lwsi_role_h2(wsi)) return lws_add_http2_header_by_token(wsi, token, value, length, p, end); #endif @@ -201,7 +201,7 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code, #endif #ifdef LWS_WITH_HTTP2 - if (wsi->mode == LWSCM_HTTP2_SERVING) + if (lwsi_role_h2(wsi)) return lws_add_http2_header_status(wsi, code, p, end); #endif if (code >= 400 && code < (400 + ARRAY_SIZE(err400))) diff --git a/lib/http2/http2.c b/lib/http2/http2.c index 0cbf996e..0ea20ff3 100644 --- a/lib/http2/http2.c +++ b/lib/http2/http2.c @@ -197,8 +197,8 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, wsi->h2.tx_cr = nwsi->h2.h2n->set.s[H2SET_INITIAL_WINDOW_SIZE]; wsi->h2.peer_tx_cr_est = nwsi->vhost->set.s[H2SET_INITIAL_WINDOW_SIZE]; - wsi->state = LWSS_HTTP2_ESTABLISHED; - wsi->mode = parent_wsi->mode; + lwsi_set_state(wsi, LRS_ESTABLISHED); + lwsi_set_role(wsi, lwsi_role(parent_wsi)); wsi->protocol = &vh->protocols[0]; if (lws_ensure_user_space(wsi)) @@ -258,8 +258,9 @@ lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi) if (lws_ensure_user_space(wsi)) goto bail1; - wsi->state = LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS; - wsi->mode = LWSCM_HTTP2_CLIENT_ACCEPTED; + lwsi_set_role(wsi, LWSI_ROLE_H2_CLIENT); + lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS); + lws_callback_on_writable(wsi); wsi->vhost->conn_stats.h2_subs++; @@ -289,8 +290,9 @@ int lws_h2_issue_preface(struct lws *wsi) (int)strlen(preface)) return 1; - wsi->state = LWSS_HTTP2_CLIENT_ESTABLISHED; - wsi->mode = LWSCM_HTTP2_CLIENT_ACCEPTED; + lwsi_set_role(wsi, LWSI_ROLE_H2_CLIENT); + lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS); + h2n->count = 0; wsi->h2.tx_cr = 65535; @@ -653,8 +655,8 @@ int lws_h2_do_pps_send(struct lws *wsi) goto bail; } /* this is the end of the preface dance then? */ - if (wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS) { - wsi->state = LWSS_HTTP2_ESTABLISHED; + if (lwsi_state(wsi) == LRS_H2_AWAIT_SETTINGS) { + lwsi_set_state(wsi, LRS_ESTABLISHED); wsi->http.fop_fd = NULL; if (lws_is_ssl(lws_get_network_wsi(wsi))) break; @@ -825,7 +827,7 @@ lws_h2_parse_frame_header(struct lws *wsi) lwsl_notice("received oversize frame %d\n", h2n->length); lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, "Peer ignored our frame size setting"); - return 0; + return 1; } if (h2n->swsi) @@ -1198,11 +1200,11 @@ lws_h2_parse_end_of_frame(struct lws *wsi) assert(lws_h2_wsi_from_id(wsi, 1) == h2n->swsi); - wsi->state = LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS; - wsi->mode = LWSCM_HTTP2_CLIENT_ACCEPTED; + lwsi_set_role(wsi, LWSI_ROLE_H2_CLIENT); + lwsi_set_state(wsi, LRS_H2_WAITING_TO_SEND_HEADERS); - h2n->swsi->state = LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS; - h2n->swsi->mode = LWSCM_HTTP2_CLIENT_ACCEPTED; + lwsi_set_role(h2n->swsi, LWSI_ROLE_H2_CLIENT); + lwsi_set_state(h2n->swsi, LRS_H2_WAITING_TO_SEND_HEADERS); /* pass on the initial headers to SID 1 */ h2n->swsi->ah = wsi->ah; @@ -1244,7 +1246,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) struct lws *w = lws_container_of(d, struct lws, dll_client_transaction_queue); - if (w->mode == LWSCM_WSCL_ISSUE_HANDSHAKE2) { + if (lwsi_state(w) == LRS_H1C_ISSUE_HANDSHAKE2) { lwsl_info("%s: client pipeq %p to be h2\n", __func__, w); /* remove ourselves from the client queue */ @@ -1400,7 +1402,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) wsi->vhost->conn_stats.h2_trans++; - h2n->swsi->state = LWSS_HTTP2_DEFERRING_ACTION; + lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION); lws_callback_on_writable(h2n->swsi); break; @@ -1434,8 +1436,14 @@ lws_h2_parse_end_of_frame(struct lws *wsi) h2n->flags & LWS_H2_FLAG_END_STREAM) { lwsl_info("%s: %p: DATA: end stream\n", __func__, h2n->swsi); - if (h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) + if (h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) { lws_h2_state(h2n->swsi, LWS_H2_STATE_HALF_CLOSED_REMOTE); + // lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR, + // "client done"); + + // if (lws_http_transaction_completed_client(h2n->swsi)) + // lwsl_debug("tx completed returned close\n"); + } //if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL) { @@ -1571,8 +1579,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, // lwsl_notice("%s: 0x%x\n", __func__, c); - switch (wsi->state) { - case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: + switch (lwsi_state(wsi)) { + case LRS_H2_AWAIT_PREFACE: if (preface[h2n->count++] != c) goto fail; @@ -1580,7 +1588,7 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, break; lwsl_info("http2: %p: established\n", wsi); - wsi->state = LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS; + lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS); h2n->count = 0; wsi->h2.tx_cr = 65535; @@ -1595,10 +1603,9 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, lws_pps_schedule(wsi, pps); break; - case LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS: - case LWSS_HTTP2_CLIENT_ESTABLISHED: - case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS: - case LWSS_HTTP2_ESTABLISHED: + case LRS_H2_WAITING_TO_SEND_HEADERS: + case LRS_ESTABLISHED: + case LRS_H2_AWAIT_SETTINGS: if (h2n->frame_state != LWS_H2_FRAME_HEADER_LENGTH) goto try_frame_start; @@ -1700,6 +1707,8 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, case LWS_H2_FRAME_TYPE_DATA: + // lwsl_notice("%s: LWS_H2_FRAME_TYPE_DATA\n", __func__); + /* let the network wsi live a bit longer if subs are active... * our frame may take a long time to chew through */ if (!wsi->ws_over_h2_count) @@ -1708,9 +1717,11 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, if (!h2n->swsi) break; - if (h2n->swsi->state == LWSS_HTTP2_ESTABLISHED) { - h2n->swsi->state = LWSS_HTTP_BODY; - lwsl_notice("%s: setting swsi %p to LWSS_HTTP_BODY\n", __func__, h2n->swsi); + if (lwsi_role_http(h2n->swsi) && + lwsi_state(h2n->swsi) == LRS_ESTABLISHED) { + lwsi_set_state(h2n->swsi, LRS_BODY); + lwsl_info("%s: setting swsi %p to LRS_BODY\n", + __func__, h2n->swsi); } if (lws_hdr_total_length(h2n->swsi, @@ -1862,9 +1873,11 @@ lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, } frame_end: - if (h2n->count > h2n->length) + if (h2n->count > h2n->length) { lwsl_notice("%s: count > length %d %d\n", __func__, h2n->count, h2n->length); + goto fail; + } if (h2n->count != h2n->length) break; @@ -1914,8 +1927,10 @@ try_frame_start: if (lws_h2_parse_frame_header(wsi)) goto fail; break; - } + default: + break; + } } *inused = in - oldin; @@ -2031,7 +2046,7 @@ lws_h2_client_handshake(struct lws *wsi) } lws_h2_state(wsi, LWS_H2_STATE_OPEN); - wsi->state = LWSS_HTTP2_CLIENT_ESTABLISHED; + lwsi_set_state(wsi, LRS_ESTABLISHED); return 0; } @@ -2079,7 +2094,7 @@ lws_h2_ws_handshake(struct lws *wsi) * mode / state of the nwsi will get the h2 processing done. */ - wsi->state = LWSS_ESTABLISHED; + lwsi_set_state(wsi, LRS_ESTABLISHED); wsi->lws_rx_parse_state = LWS_RXPS_NEW; uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH); diff --git a/lib/http2/ssl-http2.c b/lib/http2/ssl-http2.c index 035708fc..41dc1127 100644 --- a/lib/http2/ssl-http2.c +++ b/lib/http2/ssl-http2.c @@ -132,8 +132,7 @@ int lws_h2_configure_if_upgraded(struct lws *wsi) ah = wsi->ah; - lws_union_transition(wsi, LWSCM_HTTP2_SERVING); - wsi->state = LWSS_HTTP2_AWAIT_CLIENT_PREFACE; + lws_role_transition(wsi, LWSI_ROLE_H2_SERVER, LRS_H2_AWAIT_PREFACE); /* http2 union member has http union struct at start */ wsi->ah = ah; diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 83e8e745..563b594a 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -58,6 +58,22 @@ static const char * const log_level_names[] = { }; #endif +#if defined (_DEBUG) +void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role) +{ + wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role; + + lwsl_debug("lwsi_set_role(%p, 0x%x)\n", wsi, wsi->wsistate); +} + +void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs) +{ + wsi->wsistate = (wsi->wsistate & (~LRS_MASK)) | lrs; + + lwsl_debug("lwsi_set_state(%p, 0x%x)\n", wsi, wsi->wsistate); +} +#endif + void __lws_free_wsi(struct lws *wsi) { @@ -588,7 +604,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * wsi->child_list = NULL; } - if (wsi->mode == LWSCM_RAW_FILEDESC) { + if (lwsi_role(wsi) == LWSI_ROLE_RAW_FILE) { lws_remove_child_from_any_parent(wsi); __remove_wsi_socket_from_fds(wsi); wsi->protocol->callback(wsi, LWS_CALLBACK_RAW_CLOSE_FILE, @@ -596,10 +612,10 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * goto async_close; } - wsi->state_pre_close = wsi->state; + wsi->wsistate_pre_close = wsi->wsistate; #ifdef LWS_WITH_CGI - if (wsi->mode == LWSCM_CGI) { + if (lwsi_role(wsi) == LWSI_ROLE_CGI) { /* we are not a network connection, but a handler for CGI io */ if (wsi->parent && wsi->parent->cgi) { @@ -622,16 +638,14 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * lws_client_stash_destroy(wsi); #endif - if (wsi->mode == LWSCM_RAW) { + if (lwsi_role(wsi) == LWSI_ROLE_RAW_SOCKET) { wsi->protocol->callback(wsi, LWS_CALLBACK_RAW_CLOSE, wsi->user_space, NULL, 0); wsi->socket_is_permanently_unusable = 1; goto just_kill_connection; } - if ((wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED || - wsi->mode == LWSCM_HTTP2_SERVING) && - wsi->http.fop_fd != NULL) { + if (lwsi_role_http_server(wsi) && wsi->http.fop_fd != NULL) { lws_vfs_file_close(&wsi->http.fop_fd); wsi->vhost->protocols->callback(wsi, LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0); @@ -639,29 +653,29 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * } if (wsi->socket_is_permanently_unusable || reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY || - wsi->state == LWSS_SHUTDOWN) + lwsi_state(wsi) == LRS_SHUTDOWN) goto just_kill_connection; - switch (wsi->state_pre_close) { - case LWSS_DEAD_SOCKET: + switch (wsi->wsistate_pre_close & LRS_MASK) { + case LRS_DEAD_SOCKET: return; /* we tried the polite way... */ - case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION: - case LWSS_AWAITING_CLOSE_ACK: + case LRS_WAITING_TO_SEND_CLOSE: + case LRS_AWAITING_CLOSE_ACK: goto just_kill_connection; - case LWSS_FLUSHING_SEND_BEFORE_CLOSE: + case LRS_FLUSHING_BEFORE_CLOSE: if (wsi->trunc_len) { lws_callback_on_writable(wsi); return; } - lwsl_info("%p: end FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); + lwsl_info("%p: end LRS_FLUSHING_BEFORE_CLOSE\n", wsi); goto just_kill_connection; default: if (wsi->trunc_len) { - lwsl_info("%p: FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi); - wsi->state = LWSS_FLUSHING_SEND_BEFORE_CLOSE; + lwsl_info("%p: LRS_FLUSHING_BEFORE_CLOSE\n", wsi); + lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE); __lws_set_timeout(wsi, PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5); return; @@ -669,13 +683,11 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * break; } - if (wsi->mode == LWSCM_WSCL_WAITING_CONNECT || - wsi->mode == LWSCM_WSCL_ISSUE_HANDSHAKE) + if (lwsi_state(wsi) == LRS_WAITING_CONNECT || + lwsi_state(wsi) == LRS_H1C_ISSUE_HANDSHAKE) goto just_kill_connection; - if (!wsi->told_user_closed && - (wsi->mode == LWSCM_HTTP_SERVING || - wsi->mode == LWSCM_HTTP2_SERVING)) { + if (!wsi->told_user_closed && lwsi_role_http_server(wsi)) { if (wsi->user_space && wsi->protocol_bind_balance) { wsi->vhost->protocols->callback(wsi, LWS_CALLBACK_HTTP_DROP_PROTOCOL, @@ -731,14 +743,14 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * * add any necessary version-specific stuff. If the write fails, * no worries we are closing anyway. If we didn't initiate this * close, then our state has been changed to - * LWSS_RETURNED_CLOSE_ALREADY and we will skip this. + * LRS_RETURNED_CLOSE and we will skip this. * * Likewise if it's a second call to close this connection after we * sent the close indication to the peer already, we are in state - * LWSS_AWAITING_CLOSE_ACK and will skip doing this a second time. + * LRS_AWAITING_CLOSE_ACK and will skip doing this a second time. */ - if (lws_state_is_ws(wsi->state_pre_close) && + if ((wsi->wsistate_pre_close & LWSIFR_WS) && (wsi->ws->close_in_ping_buffer_len || /* already a reason */ (reason != LWS_CLOSE_STATUS_NOSTATUS && (reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY)))) { @@ -755,7 +767,7 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char * lwsl_debug("waiting for chance to send close\n"); wsi->waiting_to_send_close_frame = 1; - wsi->state = LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION; + lwsi_set_state(wsi, LRS_WAITING_TO_SEND_CLOSE); __lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_SEND, 5); lws_callback_on_writable(wsi); @@ -862,21 +874,19 @@ just_kill_connection: wsi->protocol_bind_balance = 0; } - if ((wsi->mode == LWSCM_WSCL_WAITING_SERVER_REPLY || - wsi->mode == LWSCM_WSCL_WAITING_CONNECT) && - !wsi->already_did_cce) + if ((lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY || + lwsi_state(wsi) == LRS_WAITING_CONNECT) && !wsi->already_did_cce) wsi->protocol->callback(wsi, - LWS_CALLBACK_CLIENT_CONNECTION_ERROR, + LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); - if (wsi->mode & LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP) { + if (lwsi_role_client(wsi) && !(lwsi_state(wsi) & LWSIFS_NOTEST)) { const struct lws_protocols *pro = wsi->protocol; if (!wsi->protocol) pro = &wsi->vhost->protocols[0]; - pro->callback(wsi, - LWS_CALLBACK_CLOSED_CLIENT_HTTP, - wsi->user_space, NULL, 0); + pro->callback(wsi, LWS_CALLBACK_CLOSED_CLIENT_HTTP, + wsi->user_space, NULL, 0); wsi->told_user_closed = 1; } @@ -889,10 +899,10 @@ just_kill_connection: * for the POLLIN to show a zero-size rx before coming back and doing * the actual close. */ - if (wsi->mode != LWSCM_RAW && - !(wsi->mode & LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP) && - wsi->state != LWSS_SHUTDOWN && - wsi->state != LWSS_CLIENT_UNCONNECTED && + if (lwsi_role(wsi) != LWSI_ROLE_RAW_SOCKET && + !lwsi_role_client(wsi) && + lwsi_state(wsi) != LRS_SHUTDOWN && + lwsi_state(wsi) != LRS_UNCONNECTED && reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY && !wsi->socket_is_permanently_unusable) { @@ -910,9 +920,9 @@ just_kill_connection: } else #endif { - lwsl_info("%s: shutdown conn: %p (sock %d, state %d)\n", + lwsl_info("%s: shutdown conn: %p (sock %d, state 0x%x)\n", __func__, wsi, (int)(long)wsi->desc.sockfd, - wsi->state); + lwsi_state(wsi)); if (!wsi->socket_is_permanently_unusable && lws_sockfd_valid(wsi->desc.sockfd)) { wsi->socket_is_permanently_unusable = 1; @@ -920,8 +930,8 @@ just_kill_connection: } } if (n) - lwsl_debug("closing: shutdown (state %d) ret %d\n", - wsi->state, LWS_ERRNO); + lwsl_debug("closing: shutdown (state 0x%x) ret %d\n", + lwsi_state(wsi), LWS_ERRNO); /* * This causes problems on WINCE / ESP32 with disconnection @@ -931,10 +941,10 @@ just_kill_connection: /* libuv: no event available to guarantee completion */ if (!wsi->socket_is_permanently_unusable && lws_sockfd_valid(wsi->desc.sockfd) && - wsi->state != ((wsi->state & ~0x1f) | LWSS_SHUTDOWN) && + lwsi_state(wsi) != LRS_SHUTDOWN && !LWS_LIBUV_ENABLED(context)) { __lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN); - wsi->state = (wsi->state & ~0x1f) | LWSS_SHUTDOWN; + lwsi_set_state(wsi, LRS_SHUTDOWN); __lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH, context->timeout_secs); @@ -967,13 +977,10 @@ just_kill_connection: else lws_same_vh_protocol_remove(wsi); - wsi->state = LWSS_DEAD_SOCKET; + lwsi_set_state(wsi, LRS_DEAD_SOCKET); lws_free_set_NULL(wsi->rxflow_buffer); - if (lws_state_is_ws(wsi->state_pre_close) || - wsi->mode == LWSCM_WS_SERVING || - wsi->mode == LWSCM_HTTP2_WS_SERVING || - wsi->mode == LWSCM_WS_CLIENT) { + if ((wsi->wsistate_pre_close & LWSIFR_WS) || lwsi_role_ws(wsi)) { if (wsi->ws->rx_draining_ext) { struct lws **w = &pt->rx_draining_ext_list; @@ -1016,24 +1023,23 @@ just_kill_connection: /* tell the user it's all over for this guy */ - if (wsi->protocol && - !wsi->told_user_closed && + if (wsi->protocol && !wsi->told_user_closed && wsi->protocol->callback && - wsi->mode != LWSCM_RAW && - (wsi->state_pre_close & _LSF_CCB)) { - if (wsi->mode == LWSCM_WS_CLIENT) + lwsi_role(wsi) != LWSI_ROLE_RAW_SOCKET && + !(wsi->wsistate_pre_close & LWSIFS_NOTEST)) { + if (lwsi_role_client(wsi)) wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_CLOSED, wsi->user_space, NULL, 0); else wsi->protocol->callback(wsi, LWS_CALLBACK_CLOSED, wsi->user_space, NULL, 0); - } else if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED) { + } else if (lwsi_role_http_server(wsi)) { lwsl_debug("calling back CLOSED_HTTP\n"); wsi->vhost->protocols->callback(wsi, LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0 ); } else - lwsl_debug("not calling back closed mode=%d state=%d\n", - wsi->mode, wsi->state_pre_close); + lwsl_debug("not calling back closed role=0x%x state=0x%x\n", + lwsi_role(wsi), wsi->wsistate_pre_close); /* deallocate any active extension contexts */ @@ -1051,8 +1057,7 @@ async_close: wsi->socket_is_permanently_unusable = 1; #ifdef LWS_WITH_LIBUV - if (!wsi->parent_carries_io && - lws_sockfd_valid(wsi->desc.sockfd)) + if (!wsi->parent_carries_io && lws_sockfd_valid(wsi->desc.sockfd)) if (LWS_LIBUV_ENABLED(context)) { if (wsi->listener) { lwsl_debug("%s: stop listener poll\n", __func__); @@ -1712,7 +1717,7 @@ lws_rx_flow_control(struct lws *wsi, int _enable) wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !wsi->rxflow_bitmap; - lwsl_info("%s: 0x%p: bitmap 0x%x: en 0x%x, ch 0x%x\n", __func__, wsi, + lwsl_info("%s: %p: bitmap 0x%x: en 0x%x, ch 0x%x\n", __func__, wsi, wsi->rxflow_bitmap, en, wsi->rxflow_change_to); if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW || @@ -2220,7 +2225,7 @@ lws_get_peer_write_allowance(struct lws *wsi) { #ifdef LWS_WITH_HTTP2 /* only if we are using HTTP2 on this connection */ - if (wsi->mode != LWSCM_HTTP2_SERVING) + if (!lwsi_role_h2(wsi)) return -1; return lws_h2_tx_cr_get(wsi); @@ -2231,10 +2236,11 @@ lws_get_peer_write_allowance(struct lws *wsi) } LWS_VISIBLE void -lws_union_transition(struct lws *wsi, enum connection_mode mode) +lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state) { - lwsl_debug("%s: %p: mode %d\n", __func__, wsi, mode); - wsi->mode = mode; + lwsl_debug("%s: %p: role 0x%x, state 0x%x\n", __func__, wsi, role, state); + lwsi_set_role(wsi, role); + lwsi_set_state(wsi, state); } LWS_VISIBLE struct lws_plat_file_ops * @@ -2332,9 +2338,7 @@ lws_close_reason(struct lws *wsi, enum lws_close_status status, unsigned char *p, *start; int budget = sizeof(wsi->ws->ping_payload_buf) - LWS_PRE; - assert(wsi->mode == LWSCM_WS_SERVING || - wsi->mode == LWSCM_HTTP2_WS_SERVING || - wsi->mode == LWSCM_WS_CLIENT); + assert(lwsi_role_ws(wsi)); start = p = &wsi->ws->ping_payload_buf[LWS_PRE]; @@ -2823,7 +2827,7 @@ LWS_EXTERN void lws_restart_ws_ping_pong_timer(struct lws *wsi) { if (!wsi->context->ws_ping_pong_interval || - !lws_state_is_ws(wsi->state)) + !lwsi_role_ws(wsi)) return; wsi->ws->time_next_ping_check = (time_t)lws_now_secs(); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 55115cc9..fd3056cf 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -2162,7 +2162,7 @@ enum lws_extension_callback_reasons { LWS_EXT_CB_HANDSHAKE_REPLY_TX = 14, LWS_EXT_CB_FLUSH_PENDING_TX = 15, LWS_EXT_CB_EXTENDED_PAYLOAD_RX = 16, - LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION = 17, + LWS_EXT_CB_UNUSED1 = 17, LWS_EXT_CB_1HZ = 18, LWS_EXT_CB_REQUEST_ON_WRITEABLE = 19, LWS_EXT_CB_IS_WRITEABLE = 20, @@ -4719,7 +4719,7 @@ enum pending_timeout { PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE = 4, PENDING_TIMEOUT_AWAITING_PING = 5, PENDING_TIMEOUT_CLOSE_ACK = 6, - PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE = 7, + PENDING_TIMEOUT_UNUSED1 = 7, PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE = 8, PENDING_TIMEOUT_SSL_ACCEPT = 9, PENDING_TIMEOUT_HTTP_CONTENT = 10, diff --git a/lib/output.c b/lib/output.c index 92799758..a7a3353e 100644 --- a/lib/output.c +++ b/lib/output.c @@ -77,8 +77,7 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len) if (!len) return 0; /* just ignore sends after we cleared the truncation buffer */ - if (wsi->state == LWSS_FLUSHING_SEND_BEFORE_CLOSE && - !wsi->trunc_len) + if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE && !wsi->trunc_len) return (int)len; if (wsi->trunc_len && (buf < wsi->trunc_alloc || @@ -154,7 +153,7 @@ handle_truncated_send: lwsl_info("** %p partial send completed\n", wsi); /* done with it, but don't free it */ n = (int)real_len; - if (wsi->state == LWSS_FLUSHING_SEND_BEFORE_CLOSE) { + if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { lwsl_info("** %p signalling to close now\n", wsi); return -1; /* retry closing now */ } @@ -216,7 +215,7 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len, enum lws_write_protocol wp) { struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi]; - int masked7 = (wsi->mode == LWSCM_WS_CLIENT); + int masked7 = lwsi_role_client(wsi); unsigned char is_masked_bit = 0; unsigned char *dropmask = NULL; struct lws_tokens eff_buf; @@ -256,7 +255,7 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len, if (wsi->vhost) wsi->vhost->conn_stats.tx += len; - if (wsi->ws && wsi->ws->tx_draining_ext && lws_state_is_ws(wsi->state)) { + if (wsi->ws && wsi->ws->tx_draining_ext && lwsi_role_ws(wsi)) { /* remove us from the list */ struct lws **w = &pt->tx_draining_ext_list; @@ -287,13 +286,13 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len, /* if not in a state to send ws stuff, then just send nothing */ - if (!lws_state_is_ws(wsi->state) && - ((wsi->state != LWSS_RETURNED_CLOSE_ALREADY && - wsi->state != LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION && - wsi->state != LWSS_AWAITING_CLOSE_ACK) || + if (!lwsi_role_ws(wsi) && + ((lwsi_state(wsi) != LRS_RETURNED_CLOSE && + lwsi_state(wsi) != LRS_WAITING_TO_SEND_CLOSE && + lwsi_state(wsi) != LRS_AWAITING_CLOSE_ACK) || wp1f != LWS_WRITE_CLOSE)) { //assert(0); - lwsl_debug("binning %d %d\n", wsi->state, wp1f); + lwsl_debug("binning %d %d\n", lwsi_state(wsi), wp1f); return 0; } @@ -514,9 +513,7 @@ send_raw: /* * ws-over-h2 also ends up here after the ws framing applied */ - if (wsi->mode == LWSCM_HTTP2_SERVING || - wsi->mode == LWSCM_HTTP2_WS_SERVING || - wsi->mode == LWSCM_HTTP2_CLIENT_ACCEPTED) { + if (lwsi_role_h2(wsi)) { unsigned char flags = 0; n = LWS_H2_FRAME_TYPE_DATA; @@ -812,7 +809,7 @@ all_sent: ) #endif { - wsi->state = LWSS_HTTP; + lwsi_set_state(wsi, LRS_ESTABLISHED); /* we might be in keepalive, so close it off here */ lws_vfs_file_close(&wsi->http.fop_fd); diff --git a/lib/pollfd.c b/lib/pollfd.c index d3b26679..d8836e29 100644 --- a/lib/pollfd.c +++ b/lib/pollfd.c @@ -428,7 +428,7 @@ lws_callback_on_writable(struct lws *wsi) #endif int n; - if (wsi->state == LWSS_SHUTDOWN) + if (lwsi_state(wsi) == LRS_SHUTDOWN) return 0; if (wsi->socket_is_permanently_unusable) @@ -462,12 +462,9 @@ lws_callback_on_writable(struct lws *wsi) #endif #ifdef LWS_WITH_HTTP2 - lwsl_info("%s: %p (mode %d)\n", __func__, wsi, wsi->mode); + lwsl_info("%s: %p (role/state 0x%x)\n", __func__, wsi, wsi->wsistate); - if (wsi->mode != LWSCM_HTTP2_SERVING && - wsi->mode != LWSCM_HTTP2_CLIENT && - wsi->mode != LWSCM_HTTP2_CLIENT_ACCEPTED && - wsi->mode != LWSCM_HTTP2_WS_SERVING) + if (!lwsi_role_h2(wsi)) goto network_sock; if (wsi->h2.requested_POLLOUT diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 3061acbc..5dfdb3fb 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -479,55 +479,148 @@ enum lws_websocket_opcodes_07 { }; -enum lws_connection_states { - /* FLAG: one or another kind of ws link */ - _LSF_WEBSOCKET = (1 << 5), - /* FLAG: close callback */ - _LSF_CCB = (1 << 6), - /* FLAG: pollout capable */ - _LSF_POLLOUT = (1 << 7), +typedef uint32_t lws_wsi_state_t; - LWSS_HTTP = _LSF_CCB | 0, - LWSS_HTTP_ISSUING_FILE = 1, - LWSS_HTTP_HEADERS = 2, - LWSS_HTTP_BODY = _LSF_CCB | 3, - LWSS_DEAD_SOCKET = 4, - LWSS_ESTABLISHED = _LSF_CCB | 5 | - _LSF_WEBSOCKET | - _LSF_POLLOUT, - LWSS_CLIENT_HTTP_ESTABLISHED = 6, - LWSS_CLIENT_UNCONNECTED = 7, - LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION = _LSF_CCB | 8 | - _LSF_POLLOUT, - LWSS_RETURNED_CLOSE_ALREADY = _LSF_CCB | 9 | - _LSF_POLLOUT, - LWSS_AWAITING_CLOSE_ACK = _LSF_CCB | 10, - LWSS_FLUSHING_SEND_BEFORE_CLOSE = _LSF_CCB | 11 | - _LSF_POLLOUT, - LWSS_SHUTDOWN = 12, +/* + * 31 16 15 0 + * [ role ] [ state ] + * + * The role part is generally invariant for the lifetime of the wsi, although + * it can change if the connection role itself does, eg, if the connection + * upgrades from H1 -> WS1 the role is changed at that point. + * + * The state part reflects the dynamic connection state, and the states are + * reused between roles. + * + * None of the internal role or state representations are made available outside + * of lws internals. + */ - LWSS_HTTP2_AWAIT_CLIENT_PREFACE = 13, - LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS = 14 | _LSF_POLLOUT, - LWSS_HTTP2_ESTABLISHED = _LSF_CCB | 15 | - _LSF_POLLOUT, - LWSS_HTTP2_ESTABLISHED_WS = _LSF_CCB | 16 | - _LSF_WEBSOCKET | - _LSF_POLLOUT, +#define _RS 16 - LWSS_CGI = 17, +#define LWSIFR_HTTP (0x008 << _RS) +#define LWSIFR_H2 (0x010 << _RS) +#define LWSIFR_CLIENT (0x020 << _RS) +#define LWSIFR_SERVER (0x040 << _RS) +#define LWSIFR_WS (0x080 << _RS) +#define LWSIFR_RAW (0x100 << _RS) - LWSS_HTTP2_DEFERRING_ACTION = _LSF_CCB | 18 | - _LSF_POLLOUT, +enum lwsi_role { + LWSI_ROLE_UNSET = (0 << _RS), - LWSS_HTTP_DEFERRING_ACTION = _LSF_CCB | 19 | - _LSF_POLLOUT, + LWSI_ROLE_H1_SERVER = (LWSIFR_SERVER | LWSIFR_HTTP ), + LWSI_ROLE_H2_SERVER = (LWSIFR_SERVER | LWSIFR_HTTP | LWSIFR_H2), + LWSI_ROLE_H1_CLIENT = (LWSIFR_CLIENT | LWSIFR_HTTP ), + LWSI_ROLE_H2_CLIENT = (LWSIFR_CLIENT | LWSIFR_HTTP | LWSIFR_H2), + LWSI_ROLE_WS1_SERVER = (LWSIFR_SERVER | LWSIFR_WS ), + LWSI_ROLE_WS2_SERVER = (LWSIFR_SERVER | LWSIFR_WS | LWSIFR_H2), + LWSI_ROLE_WS1_CLIENT = (LWSIFR_CLIENT | LWSIFR_WS ), + LWSI_ROLE_WS2_CLIENT = (LWSIFR_CLIENT | LWSIFR_WS | LWSIFR_H2), - LWSS_HTTP2_CLIENT_SEND_SETTINGS = 20 | _LSF_POLLOUT, - LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS = 21 | _LSF_POLLOUT, - LWSS_HTTP2_CLIENT_ESTABLISHED = 22 | _LSF_POLLOUT, + LWSI_ROLE_CGI = (1 << _RS), + LWSI_ROLE_LISTEN_SOCKET = (2 << _RS), + LWSI_ROLE_EVENT_PIPE = (3 << _RS), + LWSI_ROLE_RAW_FILE = (LWSIFR_RAW | (4 << _RS)), + LWSI_ROLE_RAW_SOCKET = (LWSIFR_RAW | (5 << _RS)), + + LWSI_ROLE_MASK = (0xffff << _RS), }; -#define lws_state_is_ws(s) (!!((s) & _LSF_WEBSOCKET)) +#define lwsi_role(wsi) \ + (wsi->wsistate & LWSI_ROLE_MASK) +#if !defined (_DEBUG) +#define lwsi_set_role(wsi, role) wsi->wsistate = \ + (wsi->wsistate & (~LWSI_ROLE_MASK)) | role +#else +void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role); +#endif +#define lwsi_role_ws(wsi) (!!(wsi->wsistate & LWSIFR_WS)) +#define lwsi_role_ws_client(wsi) \ + ((wsi->wsistate & (LWSIFR_CLIENT | LWSIFR_WS))\ + == (LWSIFR_CLIENT | LWSIFR_WS)) +#define lwsi_role_non_ws_client(wsi) \ + ((wsi->wsistate & (LWSIFR_CLIENT | LWSIFR_WS))\ + == (LWSIFR_CLIENT)) +#define lwsi_role_client(wsi) (!!(wsi->wsistate & LWSIFR_CLIENT)) +#define lwsi_role_raw(wsi) (!!(wsi->wsistate & LWSIFR_RAW)) +#define lwsi_role_http_server(wsi) \ + ((wsi->wsistate & (LWSIFR_SERVER | LWSIFR_HTTP))\ + == (LWSIFR_SERVER | LWSIFR_HTTP)) +#define lwsi_role_http_client(wsi) \ + ((wsi->wsistate & (LWSIFR_CLIENT | LWSIFR_HTTP))\ + == (LWSIFR_CLIENT | LWSIFR_HTTP)) +#define lwsi_role_http(wsi) (!!(wsi->wsistate & LWSIFR_HTTP)) +#define lwsi_role_h2(wsi) (!!(wsi->wsistate & LWSIFR_H2)) + +/* Pollout wants a callback in this state */ +#define LWSIFS_POCB (0x100) +/* Before any protocol connection was established */ +#define LWSIFS_NOTEST (0x200) + +enum lwsi_state { + + /* Phase 1: pre-transport */ + + LRS_UNCONNECTED = LWSIFS_NOTEST | 0, + LRS_WAITING_CONNECT = LWSIFS_NOTEST | 1, + + /* Phase 2: establishing intermediaries on top of transport */ + + LRS_WAITING_PROXY_REPLY = LWSIFS_NOTEST | 2, + LRS_WAITING_SSL = LWSIFS_NOTEST | 3, + LRS_WAITING_SOCKS_GREETING_REPLY = LWSIFS_NOTEST | 4, + LRS_WAITING_SOCKS_CONNECT_REPLY = LWSIFS_NOTEST | 5, + LRS_WAITING_SOCKS_AUTH_REPLY = LWSIFS_NOTEST | 6, + + /* Phase 3: establishing tls tunnel */ + + LRS_SSL_INIT = LWSIFS_NOTEST | 7, + LRS_SSL_ACK_PENDING = LWSIFS_NOTEST | 8, + LRS_PRE_WS_SERVING_ACCEPT = LWSIFS_NOTEST | 9, + + /* Phase 4: connected */ + + LRS_WAITING_SERVER_REPLY = LWSIFS_NOTEST | 10, + LRS_H2_AWAIT_PREFACE = LWSIFS_NOTEST | 11, + LRS_H2_AWAIT_SETTINGS = LWSIFS_NOTEST | + LWSIFS_POCB | 12, + + /* Phase 5: protocol logically established */ + + LRS_H2_CLIENT_SEND_SETTINGS = LWSIFS_POCB | 13, + LRS_H2_WAITING_TO_SEND_HEADERS = LWSIFS_POCB | 14, + LRS_DEFERRING_ACTION = LWSIFS_POCB | 15, + LRS_H1C_ISSUE_HANDSHAKE = 16, + LRS_H1C_ISSUE_HANDSHAKE2 = 17, + LRS_ISSUE_HTTP_BODY = 18, + LRS_ISSUING_FILE = 19, + LRS_HEADERS = 20, + LRS_BODY = 21, + LRS_ESTABLISHED = LWSIFS_POCB | 22, + + /* Phase 6: finishing */ + + LRS_WAITING_TO_SEND_CLOSE = LWSIFS_POCB | 23, + LRS_RETURNED_CLOSE = LWSIFS_POCB | 24, + LRS_AWAITING_CLOSE_ACK = 25, + LRS_FLUSHING_BEFORE_CLOSE = LWSIFS_POCB | 26, + LRS_SHUTDOWN = 27, + + /* Phase 7: dead */ + + LRS_DEAD_SOCKET = 28, + + LRS_MASK = 0xffff +}; + +#define lwsi_state(wsi) ((enum lwsi_state)(wsi->wsistate & LRS_MASK)) +#define lwsi_state_est(wsi) (!(wsi->wsistate & LWSIFS_NOTEST)) +#if !defined (_DEBUG) +#define lwsi_set_state(wsi, lrs) wsi->wsistate = \ + (wsi->wsistate & (~LRS_MASK)) | lrs +#else +void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs); +#endif enum http_version { HTTP_VERSION_1_0, @@ -568,54 +661,6 @@ enum lws_rx_parse_state { LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED }; -#define LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP 32 - -enum connection_mode { - LWSCM_HTTP_SERVING, - /* actual HTTP service going on */ - LWSCM_HTTP_SERVING_ACCEPTED, - LWSCM_PRE_WS_SERVING_ACCEPT, - - LWSCM_WS_SERVING, - LWSCM_WS_CLIENT, - - LWSCM_HTTP2_SERVING, - LWSCM_HTTP2_WS_SERVING, - - /* transient, ssl delay hiding */ - LWSCM_SSL_ACK_PENDING, - LWSCM_SSL_INIT, - /* as above, but complete into LWSCM_RAW */ - LWSCM_SSL_ACK_PENDING_RAW, - LWSCM_SSL_INIT_RAW, - - /* special internal types */ - LWSCM_SERVER_LISTENER, - LWSCM_CGI, /* stdin, stdout, stderr for another cgi master wsi */ - LWSCM_RAW, /* raw with bulk handling */ - LWSCM_RAW_FILEDESC, /* raw without bulk handling */ - LWSCM_EVENT_PIPE, /* event pipe with no vhost or protocol binding */ - - /* HTTP Client related */ - LWSCM_HTTP_CLIENT = LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP, - LWSCM_HTTP_CLIENT_ACCEPTED, /* actual HTTP service going on */ - LWSCM_HTTP2_CLIENT, - LWSCM_HTTP2_CLIENT_ACCEPTED, - LWSCM_WSCL_WAITING_CONNECT, - LWSCM_WSCL_WAITING_PROXY_REPLY, - LWSCM_WSCL_ISSUE_HANDSHAKE, - LWSCM_WSCL_ISSUE_HANDSHAKE2, - LWSCM_WSCL_ISSUE_HTTP_BODY, - LWSCM_WSCL_WAITING_SSL, - LWSCM_WSCL_WAITING_SERVER_REPLY, - LWSCM_WSCL_WAITING_EXTENSION_CONNECT, - LWSCM_WSCL_PENDING_CANDIDATE_CHILD, - LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY, - LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY, - LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY, - - /****** add new things just above ---^ ******/ -}; /* enums of socks version */ enum socks_version { @@ -1966,6 +2011,9 @@ struct lws { time_t pending_timeout_set; + lws_wsi_state_t wsistate; + lws_wsi_state_t wsistate_pre_close; + /* ints */ int position_in_fds_table; uint32_t rxflow_len; @@ -2048,14 +2096,11 @@ struct lws { #endif unsigned short pending_timeout_limit; - uint8_t state; /* enum lws_connection_states */ - uint8_t mode; /* enum connection_mode */ - /* chars */ #if !defined(LWS_WITHOUT_EXTENSIONS) uint8_t count_act_ext; #endif - uint8_t state_pre_close; + char lws_rx_parse_state; /* enum lws_rx_parse_state */ char rx_frame_type; /* enum lws_write_protocol */ char pending_timeout; /* enum pending_timeout */ @@ -2237,7 +2282,7 @@ LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len); LWS_EXTERN void -lws_union_transition(struct lws *wsi, enum connection_mode mode); +lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state); LWS_EXTERN int LWS_WARN_UNUSED_RESULT user_callback_handle_rxflow(lws_callback_function, struct lws *wsi, diff --git a/lib/server/cgi.c b/lib/server/cgi.c index ee695847..e1cbc12b 100644 --- a/lib/server/cgi.c +++ b/lib/server/cgi.c @@ -88,8 +88,8 @@ lws_create_basic_wsi(struct lws_context *context, int tsi) /* initialize the instance struct */ - new_wsi->state = LWSS_CGI; - new_wsi->mode = LWSCM_CGI; + lws_role_transition(new_wsi, LWSI_ROLE_CGI, LRS_ESTABLISHED); + new_wsi->hdr_parsing_completed = 0; new_wsi->position_in_fds_table = -1; diff --git a/lib/server/parsers.c b/lib/server/parsers.c index dffd75ea..7577d753 100644 --- a/lib/server/parsers.c +++ b/lib/server/parsers.c @@ -272,7 +272,7 @@ reset: lws_pt_unlock(pt); #ifndef LWS_NO_CLIENT - if (wsi->state == LWSS_CLIENT_UNCONNECTED) + if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) if (!lws_client_connect_via_info2(wsi)) /* our client connect has failed, the wsi * has been closed @@ -345,10 +345,10 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice) * unreasonably long time */ lwsl_debug("%s: wsi %p: ah held %ds, " - "ah.rxpos %d, ah.rxlen %d, mode/state %d %d," + "ah.rxpos %d, ah.rxlen %d, role/state 0x%x 0x%x," "\n", __func__, wsi, (int)(now - ah->assigned), - ah->rxpos, ah->rxlen, wsi->mode, wsi->state); + ah->rxpos, ah->rxlen, lwsi_role(wsi), lwsi_state(wsi)); } ah->assigned = 0; @@ -429,7 +429,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice) pt->ah_wait_list_length--; #ifndef LWS_NO_CLIENT - if (wsi->state == LWSS_CLIENT_UNCONNECTED) { + if (lwsi_role_client(wsi) && lwsi_state(wsi) == LRS_UNCONNECTED) { lws_pt_unlock(pt); if (!lws_client_connect_via_info2(wsi)) { @@ -991,8 +991,8 @@ swallow: /* collecting and checking a name part */ case WSI_TOKEN_NAME_PART: - lwsl_parser("WSI_TOKEN_NAME_PART '%c' 0x%02X (mode=%d) " - "wsi->lextable_pos=%d\n", c, c, wsi->mode, + lwsl_parser("WSI_TOKEN_NAME_PART '%c' 0x%02X (role=0x%x) " + "wsi->lextable_pos=%d\n", c, c, lwsi_role(wsi), ah->lextable_pos); if (c >= 'A' && c <= 'Z') @@ -1037,10 +1037,11 @@ nope: } /* - * Server needs to look out for unknown methods... + * If it's h1, server needs to look out for unknown + * methods... */ if (ah->lextable_pos < 0 && - (wsi->mode == LWSCM_HTTP_SERVING)) { + lwsi_role(wsi) == LWSI_ROLE_H1_SERVER) { /* this is not a header we know about */ for (m = 0; m < ARRAY_SIZE(methods); m++) if (ah->frag_index[methods[m]]) { @@ -1571,7 +1572,7 @@ spill: case LWSWSOPC_CLOSE: /* is this an acknowledgment of our close? */ - if (wsi->state == LWSS_AWAITING_CLOSE_ACK) { + if (lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) { /* * fine he has told us he is closing too, let's * finish our close @@ -1579,7 +1580,7 @@ spill: lwsl_parser("seen client close ack\n"); return -1; } - if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY) + if (lwsi_state(wsi) == LRS_RETURNED_CLOSE) /* if he sends us 2 CLOSE, kill him */ return -1; @@ -1603,7 +1604,7 @@ spill: return -1; lwsl_parser("server sees client close packet\n"); - wsi->state = LWSS_RETURNED_CLOSE_ALREADY; + lwsi_set_state(wsi, LRS_RETURNED_CLOSE); /* deal with the close packet contents as a PONG */ wsi->ws->payload_is_close = 1; goto process_as_ping; @@ -1700,8 +1701,8 @@ ping_drop: drain_extension: lwsl_ext("%s: passing %d to ext\n", __func__, eff_buf.token_len); - if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY || - wsi->state == LWSS_AWAITING_CLOSE_ACK) + if (lwsi_state(wsi) == LRS_RETURNED_CLOSE || + lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) goto already_done; #if !defined(LWS_WITHOUT_EXTENSIONS) n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0); diff --git a/lib/server/server-handshake.c b/lib/server/server-handshake.c index 0cf54919..c3590cb3 100644 --- a/lib/server/server-handshake.c +++ b/lib/server/server-handshake.c @@ -339,7 +339,7 @@ handshake_0405(struct lws_context *context, struct lws *wsi) /* alright clean up and set ourselves into established state */ - wsi->state = LWSS_ESTABLISHED; + lwsi_set_state(wsi, LRS_ESTABLISHED); wsi->lws_rx_parse_state = LWS_RXPS_NEW; { diff --git a/lib/server/server.c b/lib/server/server.c index 62944a5e..a99b1149 100644 --- a/lib/server/server.c +++ b/lib/server/server.c @@ -243,7 +243,7 @@ done_list: } wsi->context = vhost->context; wsi->desc.sockfd = sockfd; - wsi->mode = LWSCM_SERVER_LISTENER; + lwsi_set_role(wsi, LWSI_ROLE_LISTEN_SOCKET); wsi->protocol = vhost->protocols; wsi->tsi = m; wsi->vhost = vhost; @@ -488,7 +488,7 @@ lws_http_serve(struct lws *wsi, char *uri, const char *origin, wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops, path, vpath, &fflags); if (!wsi->http.fop_fd) { - lwsl_err("Unable to open '%s': errno %d\n", path, errno); + lwsl_info("Unable to open '%s': errno %d\n", path, errno); return -1; } @@ -806,7 +806,7 @@ lws_server_init_wsi_for_ws(struct lws *wsi) { int n; - wsi->state = LWSS_ESTABLISHED; + lwsi_set_state(wsi, LRS_ESTABLISHED); lws_restart_ws_ping_pong_timer(wsi); /* @@ -1016,9 +1016,9 @@ lws_process_ws_upgrade(struct lws *wsi) lws_pt_lock(pt, __func__); if (wsi->h2_stream_carries_ws) - lws_union_transition(wsi, LWSCM_HTTP2_WS_SERVING); + lws_role_transition(wsi, LWSI_ROLE_WS2_SERVER, LRS_ESTABLISHED); else - lws_union_transition(wsi, LWSCM_WS_SERVING); + lws_role_transition(wsi, LWSI_ROLE_WS1_SERVER, LRS_ESTABLISHED); /* * Because rxpos/rxlen shows something in the ah, we will get * service guaranteed next time around the event loop @@ -1592,15 +1592,15 @@ deal_body: * In any case, return 0 and let lws_read decide how to * proceed based on state */ - if (wsi->state != LWSS_HTTP_ISSUING_FILE) { + if (lwsi_state(wsi) != LRS_ISSUING_FILE) { /* Prepare to read body if we have a content length: */ lwsl_debug("wsi->http.rx_content_length %lld %d %d\n", (long long)wsi->http.rx_content_length, wsi->upgraded_to_http2, wsi->http2_substream); if (wsi->http.rx_content_length > 0) { - lwsl_info("%s: %p: LWSS_HTTP_BODY state set\n", - __func__, wsi); - wsi->state = LWSS_HTTP_BODY; + lwsi_set_state(wsi, LRS_BODY); + lwsl_info("%s: %p: LRS_BODY state set (0x%x)\n", + __func__, wsi, wsi->wsistate); wsi->http.rx_content_remain = wsi->http.rx_content_length; } @@ -1645,10 +1645,9 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) } while (len) { - if (wsi->mode != LWSCM_HTTP_SERVING && - wsi->mode != LWSCM_HTTP2_SERVING && - wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED) { - lwsl_err("%s: bad wsi mode %d\n", __func__, wsi->mode); + if (!lwsi_role_http_server(wsi)) { + lwsl_err("%s: bad wsi role 0x%x\n", __func__, + lwsi_role(wsi)); goto bail_nuke_ah; } @@ -1677,7 +1676,8 @@ raw_transition: goto bail_nuke_ah; lws_header_table_force_to_detachable_state(wsi); - lws_union_transition(wsi, LWSCM_RAW); + lws_role_transition(wsi, LWSI_ROLE_RAW_SOCKET, + LRS_ESTABLISHED); lws_header_table_detach(wsi, 1); if (m == 2 && (wsi->protocol->callback)(wsi, @@ -1708,7 +1708,7 @@ raw_transition: } else lwsl_info("no host\n"); - if (wsi->mode != LWSCM_HTTP2_SERVING) { + if (lwsi_role(wsi) != LWSI_ROLE_H2_SERVER) { wsi->vhost->conn_stats.h1_trans++; if (!wsi->conn_stat_done) { wsi->vhost->conn_stats.h1_conn++; @@ -1769,7 +1769,7 @@ raw_transition: goto raw_transition; } - wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT; + lwsi_set_state(wsi, LRS_PRE_WS_SERVING_ACCEPT); lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* is this websocket protocol or normal http 1.0? */ @@ -1800,8 +1800,7 @@ raw_transition: lwsl_info("No upgrade\n"); - lws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED); - wsi->state = LWSS_HTTP; + lwsi_set_state(wsi, LRS_ESTABLISHED); wsi->http.fop_fd = NULL; lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi, @@ -1830,8 +1829,6 @@ upgrade_h2c: /* adopt the header info */ - lws_union_transition(wsi, LWSCM_HTTP2_SERVING); - if (!wsi->h2.h2n) { wsi->h2.h2n = lws_zalloc(sizeof(*wsi->h2.h2n), "h2n"); @@ -1858,7 +1855,7 @@ upgrade_h2c: return 1; } - wsi->state = LWSS_HTTP2_AWAIT_CLIENT_PREFACE; + lwsi_set_state(wsi, LRS_H2_AWAIT_PREFACE); wsi->upgraded_to_http2 = 1; return 0; @@ -1930,8 +1927,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost) /* initialize the instance struct */ - new_wsi->state = LWSS_HTTP; - new_wsi->mode = LWSCM_HTTP_SERVING; + lwsi_set_state(new_wsi, LRS_UNCONNECTED); new_wsi->hdr_parsing_completed = 0; #ifdef LWS_OPENSSL_SUPPORT @@ -1997,7 +1993,7 @@ lws_http_transaction_completed(struct lws *wsi) * until we can verify POLLOUT. The part of this that confirms POLLOUT * with no partials is in lws_server_socket_service() below. */ - wsi->state = LWSS_HTTP_DEFERRING_ACTION; + lwsi_set_state(wsi, LRS_DEFERRING_ACTION); wsi->http.tx_content_length = 0; wsi->http.tx_content_remain = 0; wsi->hdr_parsing_completed = 0; @@ -2056,8 +2052,7 @@ lws_http_transaction_completed(struct lws *wsi) if (wsi->ah) wsi->ah->ues = URIES_IDLE; - if (wsi->mode == LWSCM_HTTP_SERVING_ACCEPTED) - wsi->mode = LWSCM_HTTP_SERVING; + lwsi_set_state(wsi, LRS_ESTABLISHED); } else if (wsi->preamble_rx) if (lws_header_table_attach(wsi, 0)) @@ -2139,7 +2134,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, new_wsi->desc.sockfd = LWS_SOCK_INVALID; lwsl_debug("binding to %s\n", new_wsi->protocol->name); lws_bind_protocol(new_wsi, new_wsi->protocol); - lws_union_transition(new_wsi, LWSCM_WS_SERVING); + lws_role_transition(new_wsi, LWSI_ROLE_WS1_SERVER, LRS_ESTABLISHED); /* allocate the ws struct for the wsi */ new_wsi->ws = lws_zalloc(sizeof(*new_wsi->ws), "ws struct"); if (!new_wsi->ws) { @@ -2157,7 +2152,8 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, else { /* this is the only time he will transition */ lws_bind_protocol(new_wsi, &vh->protocols[vh->raw_protocol_index]); - lws_union_transition(new_wsi, LWSCM_RAW); + lws_role_transition(new_wsi, LWSI_ROLE_RAW_SOCKET, + LRS_ESTABLISHED); } if (type & LWS_ADOPT_SOCKET) { /* socket desc */ @@ -2201,20 +2197,26 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, /* non-SSL */ if (!(type & LWS_ADOPT_HTTP)) { if (!(type & LWS_ADOPT_SOCKET)) - new_wsi->mode = LWSCM_RAW_FILEDESC; + lwsi_set_role(new_wsi, LWSI_ROLE_RAW_FILE); else - new_wsi->mode = LWSCM_RAW; + lwsi_set_role(new_wsi, LWSI_ROLE_RAW_SOCKET); + } else { + lwsi_set_role(new_wsi, LWSI_ROLE_H1_SERVER); + lwsi_set_state(new_wsi, LRS_HEADERS); } } else { /* SSL */ if (!(type & LWS_ADOPT_HTTP)) - new_wsi->mode = LWSCM_SSL_INIT_RAW; + lwsi_set_role(new_wsi, LWSI_ROLE_RAW_SOCKET); else - new_wsi->mode = LWSCM_SSL_INIT; + lwsi_set_role(new_wsi, LWSI_ROLE_H1_SERVER); + lwsi_set_state(new_wsi, LRS_SSL_INIT); ssl = 1; } + lwsl_debug("new wsi wsistate 0x%x\n", new_wsi->wsistate); + lws_libev_accept(new_wsi, new_wsi->desc); lws_libuv_accept(new_wsi, new_wsi->desc); lws_libevent_accept(new_wsi, new_wsi->desc); @@ -2394,12 +2396,12 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, #endif int n, len; - switch (wsi->mode) { + switch (lwsi_role(wsi)) { - case LWSCM_HTTP_SERVING: - case LWSCM_HTTP_SERVING_ACCEPTED: - case LWSCM_HTTP2_SERVING: - case LWSCM_RAW: + case LWSI_ROLE_H1_SERVER: + case LWSI_ROLE_H2_SERVER: + case LWSI_ROLE_RAW_SOCKET: + case LWSI_ROLE_RAW_FILE: /* handle http headers coming in */ @@ -2421,7 +2423,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, break; } - if (wsi->state == LWSS_HTTP_DEFERRING_ACTION) + if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) goto try_pollout; /* any incoming data ready? */ @@ -2442,11 +2444,19 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, goto try_pollout; } + /* + * We haven't processed that the tunnel is set up yet, so + * defer reading + */ + if (lwsi_state(wsi) == LRS_SSL_ACK_PENDING) + break; + /* these states imply we MUST have an ah attached */ - if (wsi->mode != LWSCM_RAW && (wsi->state == LWSS_HTTP || - wsi->state == LWSS_HTTP_ISSUING_FILE || - wsi->state == LWSS_HTTP_HEADERS)) { + if (!lwsi_role_raw(wsi) && + (lwsi_state(wsi) == LRS_ESTABLISHED || + lwsi_state(wsi) == LRS_ISSUING_FILE || + lwsi_state(wsi) == LRS_HEADERS)) { if (!wsi->ah) { /* no autoservice beacuse we will do it next */ if (lws_header_table_attach(wsi, 0)) { @@ -2488,9 +2498,6 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, } } - // lwsl_notice("new read, rxpos %d / rxlen %d\n", ah->rxpos, ah->rxlen); - // lwsl_hexdump_level(LLL_NOTICE, ah->rx, ah->rxlen); - if (!(ah->rxpos != ah->rxlen && ah->rxlen)) { lwsl_err("%s: assert: rxpos %d, rxlen %d\n", __func__, ah->rxpos, ah->rxlen); @@ -2499,8 +2506,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, } /* just ignore incoming if waiting for close */ - if (wsi->state == LWSS_FLUSHING_SEND_BEFORE_CLOSE || - wsi->state == LWSS_HTTP_ISSUING_FILE) + if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE || + lwsi_state(wsi) == LRS_ISSUING_FILE) goto try_pollout; /* @@ -2523,9 +2530,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, wsi->ah->rxlen); if (lws_header_table_is_in_detachable_state(wsi) && - (wsi->mode != LWSCM_HTTP_SERVING && - wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED && - wsi->mode != LWSCM_HTTP2_SERVING)) + lwsi_role_raw(wsi)) // ??? lws_header_table_detach(wsi, 1); break; @@ -2546,7 +2551,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, len = lws_ssl_capable_read(wsi, pt->serv_buf, context->pt_serv_buf_size); - lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len); + lwsl_debug("%s: wsi %p read %d (wsistate 0x%x)\n", + __func__, wsi, len, wsi->wsistate); switch (len) { case 0: lwsl_info("%s: read 0 len b\n", __func__); @@ -2561,7 +2567,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, if (len < 0) /* coverity */ goto fail; } - if (wsi->mode == LWSCM_RAW) { + if (lwsi_role_raw(wsi)) { n = user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_RAW_RX, wsi->user_space, @@ -2574,8 +2580,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, } /* just ignore incoming if waiting for close */ - if (wsi->state != LWSS_FLUSHING_SEND_BEFORE_CLOSE && - wsi->state != LWSS_HTTP_ISSUING_FILE) { + if (lwsi_state(wsi) != LRS_FLUSHING_BEFORE_CLOSE && + lwsi_state(wsi) != LRS_ISSUING_FILE) { /* * this may want to send * (via HTTP callback for example) @@ -2637,21 +2643,21 @@ try_pollout: /* clear back-to-back write detection */ wsi->could_have_pending = 0; - if (wsi->state == LWSS_HTTP_DEFERRING_ACTION) { - lwsl_debug("%s: LWSS_HTTP_DEFERRING_ACTION now writable\n", + if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) { + lwsl_debug("%s: LRS_DEFERRING_ACTION now writable\n", __func__); if (wsi->ah) lwsl_debug(" existing ah rxpos %d / rxlen %d\n", wsi->ah->rxpos, wsi->ah->rxlen); - wsi->state = LWSS_HTTP; + lwsi_set_state(wsi, LRS_ESTABLISHED); if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_info("failed at set pollfd\n"); goto fail; } } - if (wsi->mode == LWSCM_RAW) { + if (lwsi_role_raw(wsi)) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1); #if defined(LWS_WITH_STATS) @@ -2679,7 +2685,7 @@ try_pollout: if (!wsi->hdr_parsing_completed) break; - if (wsi->state != LWSS_HTTP_ISSUING_FILE) { + if (lwsi_state(wsi) != LRS_ISSUING_FILE) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1); @@ -2718,7 +2724,7 @@ try_pollout: break; - case LWSCM_SERVER_LISTENER: + case LWSI_ROLE_LISTEN_SOCKET: #if LWS_POSIX /* pollin means a client has connected to us then @@ -2876,7 +2882,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, wsi->http.fop_fd = fops->LWS_FOP_OPEN(wsi->context->fops, file, vpath, &fflags); if (!wsi->http.fop_fd) { - lwsl_err("Unable to open: '%s': errno %d\n", file, errno); + lwsl_info("Unable to open: '%s': errno %d\n", file, errno); return -1; } @@ -3056,7 +3062,7 @@ lws_serve_http_file(struct lws *wsi, const char *file, const char *content_type, } wsi->http.filepos = 0; - wsi->state = LWSS_HTTP_ISSUING_FILE; + lwsi_set_state(wsi, LRS_ISSUING_FILE); lws_callback_on_writable(wsi); diff --git a/lib/server/ssl-server.c b/lib/server/ssl-server.c index 5a133814..c2a16f7d 100644 --- a/lib/server/ssl-server.c +++ b/lib/server/ssl-server.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010-2017 Andy Green + * Copyright (C) 2010-2018 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -118,9 +118,9 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) if (!LWS_SSL_ENABLED(wsi->vhost)) return 0; - switch (wsi->mode) { - case LWSCM_SSL_INIT: - case LWSCM_SSL_INIT_RAW: + switch (lwsi_state(wsi)) { + case LRS_SSL_INIT: + if (wsi->ssl) lwsl_err("%s: leaking ssl\n", __func__); if (accept_fd == LWS_SOCK_INVALID) @@ -144,10 +144,6 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) /* that was the last allowed SSL connection */ lws_gate_accepts(context, 0); - //lwsl_notice("%s: ssl restr %d, simul %d\n", __func__, - // context->simultaneous_ssl_restriction, - // context->simultaneous_ssl); - #if defined(LWS_WITH_STATS) context->updated = 1; #endif @@ -156,10 +152,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) * as a live connection. That way we can retry when more * pieces come if we're not sorted yet */ - if (wsi->mode == LWSCM_SSL_INIT) - wsi->mode = LWSCM_SSL_ACK_PENDING; - else - wsi->mode = LWSCM_SSL_ACK_PENDING_RAW; + lwsi_set_state(wsi, LRS_SSL_ACK_PENDING); lws_pt_lock(pt, __func__); if (__insert_wsi_socket_into_fds(context, wsi)) { @@ -175,8 +168,8 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) /* fallthru */ - case LWSCM_SSL_ACK_PENDING: - case LWSCM_SSL_ACK_PENDING_RAW: + case LRS_SSL_ACK_PENDING: + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { lwsl_err("%s: lws_change_pollfd failed\n", __func__); goto fail; @@ -258,7 +251,7 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd) LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN, 1); n = lws_tls_server_accept(wsi); lws_latency(context, wsi, - "SSL_accept LWSCM_SSL_ACK_PENDING\n", n, n == 1); + "SSL_accept LRS_SSL_ACK_PENDING\n", n, n == 1); lwsl_info("SSL_accept says %d\n", n); switch (n) { case LWS_SSL_CAPABLE_DONE: @@ -302,16 +295,17 @@ accepted: lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); - if (wsi->mode == LWSCM_SSL_ACK_PENDING_RAW) - wsi->mode = LWSCM_RAW; - else - wsi->mode = LWSCM_HTTP_SERVING; + lwsi_set_state(wsi, LRS_ESTABLISHED); + #if defined(LWS_WITH_HTTP2) if (lws_h2_configure_if_upgraded(wsi)) goto fail; #endif lwsl_debug("accepted new SSL conn\n"); break; + + default: + break; } return 0; diff --git a/lib/service.c b/lib/service.c index a82c1cb8..c9210a2e 100644 --- a/lib/service.c +++ b/lib/service.c @@ -41,23 +41,23 @@ lws_calllback_as_writeable(struct lws *wsi) } #endif - switch (wsi->mode) { - case LWSCM_RAW: + switch (lwsi_role(wsi)) { + case LWSI_ROLE_RAW_SOCKET: n = LWS_CALLBACK_RAW_WRITEABLE; break; - case LWSCM_RAW_FILEDESC: + case LWSI_ROLE_RAW_FILE: n = LWS_CALLBACK_RAW_WRITEABLE_FILE; break; - case LWSCM_WS_CLIENT: + case LWSI_ROLE_WS1_CLIENT: + case LWSI_ROLE_WS2_CLIENT: n = LWS_CALLBACK_CLIENT_WRITEABLE; break; - case LWSCM_WSCL_ISSUE_HTTP_BODY: - case LWSCM_HTTP2_CLIENT: - case LWSCM_HTTP2_CLIENT_ACCEPTED: + case LWSI_ROLE_H1_CLIENT: + case LWSI_ROLE_H2_CLIENT: n = LWS_CALLBACK_CLIENT_HTTP_WRITEABLE; break; - case LWSCM_HTTP2_WS_SERVING: - case LWSCM_WS_SERVING: + case LWSI_ROLE_WS1_SERVER: + case LWSI_ROLE_WS2_SERVER: n = LWS_CALLBACK_SERVER_WRITEABLE; break; default: @@ -117,12 +117,12 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) /* leave POLLOUT active either way */ goto bail_ok; } else - if (wsi->state == LWSS_FLUSHING_SEND_BEFORE_CLOSE) { + if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { wsi->socket_is_permanently_unusable = 1; goto bail_die; /* retry closing now */ } - if (wsi->mode == LWSCM_WSCL_ISSUE_HTTP_BODY) + if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY) goto user_service; #ifdef LWS_WITH_HTTP2 @@ -167,14 +167,14 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) * 3a: close notification packet requested from close api */ - if (wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) { + if (lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE) { lwsl_debug("sending close packet\n"); wsi->waiting_to_send_close_frame = 0; n = lws_write(wsi, &wsi->ws->ping_payload_buf[LWS_PRE], wsi->ws->close_in_ping_buffer_len, LWS_WRITE_CLOSE); if (n >= 0) { - wsi->state = LWSS_AWAITING_CLOSE_ACK; + lwsi_set_state(wsi, LRS_AWAITING_CLOSE_ACK); lws_set_timeout(wsi, PENDING_TIMEOUT_CLOSE_ACK, 5); lwsl_debug("sent close indication, awaiting ack\n"); @@ -186,8 +186,8 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) /* else, the send failed and we should just hang up */ - if ((lws_state_is_ws(wsi->state) && wsi->ws->ping_pending_flag) || - (wsi->state == LWSS_RETURNED_CLOSE_ALREADY && + if ((lwsi_role_ws(wsi) && wsi->ws->ping_pending_flag) || + (lwsi_state(wsi) == LRS_RETURNED_CLOSE && wsi->ws->payload_is_close)) { if (wsi->ws->payload_is_close) @@ -210,7 +210,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) goto bail_ok; } - if (lws_state_is_ws(wsi->state) && !wsi->socket_is_permanently_unusable && + if (lwsi_role_ws_client(wsi) && !wsi->socket_is_permanently_unusable && wsi->ws->send_check_ping) { lwsl_info("issuing ping on wsi %p\n", wsi); @@ -235,7 +235,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) /* Priority 4: if we are closing, not allowed to send more data frags * which means user callback or tx ext flush banned now */ - if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY) + if (lwsi_state(wsi) == LRS_RETURNED_CLOSE) goto user_service; /* Priority 5: Tx path extension with more to send @@ -245,7 +245,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) * payload ordering, but since they are always complete * fragments control packets can interleave OK. */ - if (lws_state_is_ws(wsi->state) && wsi->ws->tx_draining_ext) { + if (lwsi_role_ws_client(wsi) && wsi->ws->tx_draining_ext) { lwsl_ext("SERVICING TX EXT DRAINING\n"); if (lws_write(wsi, NULL, 0, LWS_WRITE_CONTINUATION) < 0) goto bail_die; @@ -272,7 +272,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) */ ret = 1; - if (wsi->mode == LWSCM_RAW || wsi->mode == LWSCM_RAW_FILEDESC) + if (lwsi_role_raw(wsi)) ret = 0; while (ret == 1) { @@ -384,9 +384,8 @@ user_service: vwsi->leave_pollout_active = 0; } - if (wsi->mode != LWSCM_WSCL_ISSUE_HTTP_BODY && - wsi->mode != LWSCM_HTTP2_CLIENT_ACCEPTED && - !wsi->hdr_parsing_completed) + if (lwsi_role_client(wsi) && !wsi->hdr_parsing_completed && + lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS) goto bail_ok; @@ -408,10 +407,7 @@ user_service_go_again: * notifications, so we can't hold pointers */ - if (wsi->mode != LWSCM_HTTP2_SERVING && - wsi->mode != LWSCM_HTTP2_WS_SERVING && - wsi->mode != LWSCM_HTTP2_CLIENT && - wsi->mode != LWSCM_HTTP2_CLIENT_ACCEPTED) { + if (!lwsi_role_h2(wsi)) { lwsl_info("%s: non http2\n", __func__); goto notify; } @@ -479,7 +475,7 @@ user_service_go_again: } w->h2.requested_POLLOUT = 0; - lwsl_info("%s: child %p (state %d)\n", __func__, w, w->state); + lwsl_info("%s: child %p (state %d)\n", __func__, w, lwsi_state(w)); /* if we arrived here, even by looping, we checked choked */ w->could_have_pending = 0; @@ -497,14 +493,14 @@ user_service_go_again: goto next_child; } - if (w->state == LWSS_HTTP2_CLIENT_WAITING_TO_SEND_HEADERS) { + if (lwsi_state(w) == LRS_H2_WAITING_TO_SEND_HEADERS) { if (lws_h2_client_handshake(w)) return -1; goto next_child; } - if (w->state == LWSS_HTTP2_DEFERRING_ACTION) { + if (lwsi_state(w) == LRS_DEFERRING_ACTION) { /* * we had to defer the http_action to the POLLOUT @@ -513,7 +509,7 @@ user_service_go_again: * that there is no partial pending on the network wsi. */ - w->state = LWSS_HTTP2_ESTABLISHED; + lwsi_set_state(w, LRS_ESTABLISHED); lwsl_info(" h2 action start...\n"); n = lws_http_action(w); @@ -536,7 +532,7 @@ user_service_go_again: goto next_child; } - if (w->state == LWSS_HTTP_ISSUING_FILE) { + if (lwsi_state(w) == LRS_ISSUING_FILE) { ((volatile struct lws *)w)->leave_pollout_active = 0; @@ -572,14 +568,14 @@ user_service_go_again: /* Notify peer that we decided to close */ - if (w->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION) { + if (lwsi_state(w) == LRS_WAITING_TO_SEND_CLOSE) { lwsl_debug("sending close packet\n"); w->waiting_to_send_close_frame = 0; n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE], w->ws->close_in_ping_buffer_len, LWS_WRITE_CLOSE); if (n >= 0) { - w->state = LWSS_AWAITING_CLOSE_ACK; + lwsi_set_state(w, LRS_AWAITING_CLOSE_ACK); lws_set_timeout(w, PENDING_TIMEOUT_CLOSE_ACK, 5); lwsl_debug("sent close indication, awaiting ack\n"); } @@ -590,12 +586,13 @@ user_service_go_again: /* Acknowledge receipt of peer's notification he closed, * then logically close ourself */ - if ((lws_state_is_ws(w->state) && w->ws->ping_pending_flag) || - (w->state == LWSS_RETURNED_CLOSE_ALREADY && + if ((lwsi_role_ws(w) && w->ws->ping_pending_flag) || + (lwsi_state(w) == LRS_RETURNED_CLOSE && w->ws->payload_is_close)) { if (w->ws->payload_is_close) - write_type = LWS_WRITE_CLOSE | LWS_WRITE_H2_STREAM_END; + write_type = LWS_WRITE_CLOSE | + LWS_WRITE_H2_STREAM_END; n = lws_write(w, &w->ws->ping_payload_buf[LWS_PRE], w->ws->ping_payload_len, write_type); @@ -608,7 +605,7 @@ user_service_go_again: /* oh... a close frame was it... then we are done */ lwsl_debug("Acknowledged peer's close packet\n"); w->ws->payload_is_close = 0; - w->state = LWSS_RETURNED_CLOSE_ALREADY; + lwsi_set_state(w, LRS_RETURNED_CLOSE); lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS, "returned close packet"); wa = &wsi->h2.child_list; goto next_child; @@ -741,7 +738,7 @@ __lws_service_timeout_check(struct lws *wsi, time_t sec) * cleanup like flush partials. */ wsi->socket_is_permanently_unusable = 1; - if (wsi->mode == LWSCM_WSCL_WAITING_SSL && wsi->protocol) + if (lwsi_state(wsi) == LRS_WAITING_SSL && wsi->protocol) wsi->protocol->callback(wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, @@ -1092,7 +1089,7 @@ lws_is_ws_with_ext(struct lws *wsi) #if defined(LWS_WITHOUT_EXTENSIONS) return 0; #else - return lws_state_is_ws(wsi->state) && !!wsi->count_act_ext; + return lwsi_role_ws(wsi) && !!wsi->count_act_ext; #endif } @@ -1368,7 +1365,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, wsi = vh->same_vh_protocol_list[n]; while (wsi) { - if (lws_state_is_ws(wsi->state) && + if (lwsi_role_ws(wsi) && !wsi->socket_is_permanently_unusable && !wsi->ws->send_check_ping && wsi->ws->time_next_ping_check && @@ -1452,7 +1449,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, } #ifdef LWS_OPENSSL_SUPPORT - if (wsi->state == LWSS_SHUTDOWN && lws_is_ssl(wsi) && wsi->ssl) { + if (lwsi_state(wsi) == LRS_SHUTDOWN && lws_is_ssl(wsi) && wsi->ssl) { n = 0; switch (__lws_tls_shutdown(wsi)) { case LWS_SSL_CAPABLE_DONE: @@ -1470,8 +1467,10 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, /* okay, what we came here to do... */ - switch (wsi->mode) { - case LWSCM_EVENT_PIPE: + // lwsl_err("x 0x%x\n", wsi->wsistate); + + switch (lwsi_role(wsi)) { + case LWSI_ROLE_EVENT_PIPE: { #if !defined(WIN32) && !defined(_WIN32) char s[10]; @@ -1500,16 +1499,17 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, goto handled; } - case LWSCM_HTTP_SERVING: - case LWSCM_HTTP_CLIENT: - case LWSCM_HTTP_SERVING_ACCEPTED: - case LWSCM_SERVER_LISTENER: - case LWSCM_SSL_ACK_PENDING: - case LWSCM_SSL_ACK_PENDING_RAW: - if (wsi->state == LWSS_CLIENT_HTTP_ESTABLISHED) + case LWSI_ROLE_H1_CLIENT: + + if (lwsi_state(wsi) == LRS_ESTABLISHED) goto handled; + goto do_client; + + case LWSI_ROLE_H1_SERVER: + case LWSI_ROLE_LISTEN_SOCKET: + #ifdef LWS_WITH_CGI if (wsi->cgi && (pollfd->revents & LWS_POLLOUT)) { n = lws_handle_POLLOUT_event(wsi, pollfd); @@ -1519,13 +1519,13 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, } #endif /* fallthru */ - case LWSCM_RAW: + case LWSI_ROLE_RAW_SOCKET: n = lws_server_socket_service(context, wsi, pollfd); if (n) /* closed by above */ return 1; goto handled; - case LWSCM_RAW_FILEDESC: + case LWSI_ROLE_RAW_FILE: if (pollfd->revents & LWS_POLLOUT) { n = lws_calllback_as_writeable(wsi); @@ -1537,14 +1537,13 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, goto close_and_handled; } n = LWS_CALLBACK_RAW_RX; - if (wsi->mode == LWSCM_RAW_FILEDESC) + if (lwsi_role(wsi) == LWSI_ROLE_RAW_FILE) n = LWS_CALLBACK_RAW_RX_FILE; if (pollfd->revents & LWS_POLLIN) { if (user_callback_handle_rxflow( wsi->protocol->callback, - wsi, n, - wsi->user_space, NULL, 0)) { + wsi, n, wsi->user_space, NULL, 0)) { lwsl_debug("raw rx callback closed it\n"); goto close_and_handled; } @@ -1555,32 +1554,44 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, n = 0; goto handled; - case LWSCM_WS_SERVING: - case LWSCM_WS_CLIENT: - case LWSCM_HTTP2_SERVING: - case LWSCM_HTTP2_WS_SERVING: - case LWSCM_HTTP_CLIENT_ACCEPTED: - case LWSCM_HTTP2_CLIENT_ACCEPTED: - case LWSCM_HTTP2_CLIENT: + case LWSI_ROLE_WS1_SERVER: + case LWSI_ROLE_WS1_CLIENT: + case LWSI_ROLE_H2_SERVER: + case LWSI_ROLE_WS2_SERVER: + case LWSI_ROLE_H2_CLIENT: + case LWSI_ROLE_WS2_CLIENT: - // lwsl_notice("%s: mode %d, state %d\n", __func__, wsi->mode, wsi->state); + lwsl_info("%s: wsistate 0x%x, pollout %d\n", __func__, + wsi->wsistate, pollfd->revents & LWS_POLLOUT); + + /* + * something went wrong with parsing the handshake, and + * we ended up back in the event loop without completing it + */ + if (lwsi_state(wsi) == LRS_PRE_WS_SERVING_ACCEPT) { + wsi->socket_is_permanently_unusable = 1; + goto close_and_handled; + } + + if (lwsi_state(wsi) == LRS_WAITING_CONNECT) + goto do_client; /* 1: something requested a callback when it was OK to write */ if ((pollfd->revents & LWS_POLLOUT) && - (wsi->state & _LSF_POLLOUT) /* ...our state cares ... */ && + (lwsi_state(wsi) & LWSIFS_POCB) /* ...our state cares ... */ && lws_handle_POLLOUT_event(wsi, pollfd)) { - if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY) - wsi->state = LWSS_FLUSHING_SEND_BEFORE_CLOSE; + if (lwsi_state(wsi) == LRS_RETURNED_CLOSE) + lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE); // lwsl_notice("lws_service_fd: closing\n"); /* the write failed... it's had it */ wsi->socket_is_permanently_unusable = 1; goto close_and_handled; } - if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY || - wsi->state == LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION || - wsi->state == LWSS_AWAITING_CLOSE_ACK) { + if (lwsi_state(wsi) == LRS_RETURNED_CLOSE || + lwsi_state(wsi) == LRS_WAITING_TO_SEND_CLOSE || + lwsi_state(wsi) == LRS_AWAITING_CLOSE_ACK) { /* * we stopped caring about anything except control * packets. Force flow control off, defeat tx @@ -1624,11 +1635,11 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, /* 2: RX Extension needs to be drained */ - if (lws_state_is_ws(wsi->state) && wsi->ws->rx_draining_ext) { + if (lwsi_role_ws(wsi) && wsi->ws && wsi->ws->rx_draining_ext) { lwsl_ext("%s: RX EXT DRAINING: Service\n", __func__); #ifndef LWS_NO_CLIENT - if (wsi->mode == LWSCM_WS_CLIENT) { + if (lwsi_role_ws_client(wsi)) { n = lws_client_rx_sm(wsi, 0); if (n < 0) /* we closed wsi */ @@ -1687,6 +1698,7 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) break; + read: if (lws_is_flowcontrolled(wsi)) { lwsl_info("%s: %p should be rxflow (bm 0x%x)..\n", @@ -1695,13 +1707,16 @@ read: } if (wsi->ah && wsi->ah->rxlen - wsi->ah->rxpos) { - lwsl_info("%s: %p: inherited ah rx %d\n", __func__, wsi, wsi->ah->rxlen - wsi->ah->rxpos); + lwsl_info("%s: %p: inherited ah rx %d\n", __func__, + wsi, wsi->ah->rxlen - wsi->ah->rxpos); eff_buf.token_len = wsi->ah->rxlen - wsi->ah->rxpos; eff_buf.token = (char *)wsi->ah->rx + wsi->ah->rxpos; } else { - if (wsi->mode != LWSCM_HTTP_CLIENT_ACCEPTED) { + if (!(lwsi_role_client(wsi) && + (lwsi_state(wsi) != LRS_ESTABLISHED && + lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS))) { /* * extension may not consume everything * (eg, pmd may be constrained @@ -1767,8 +1782,8 @@ read: drain: #ifndef LWS_NO_CLIENT - if ((wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED || - wsi->mode == LWSS_HTTP2_CLIENT_ESTABLISHED) && + if (lwsi_role_http_client(wsi) && + wsi->hdr_parsing_completed && !wsi->told_user_closed) { /* @@ -1848,7 +1863,7 @@ drain: && !wsi->client_h2_alpn #endif ) { - lwsl_notice("%s: %p: detaching ah\n", __func__, wsi); + lwsl_info("%s: %p: detaching ah\n", __func__, wsi); lws_header_table_force_to_detachable_state(wsi); lws_header_table_detach(wsi, 0); } @@ -1878,7 +1893,7 @@ drain: break; #ifdef LWS_WITH_CGI - case LWSCM_CGI: /* we exist to handle a cgi's stdin/out/err data... + case LWSI_ROLE_CGI: /* we exist to handle a cgi's stdin/out/err data... * do the callback on our master wsi */ { @@ -1901,9 +1916,9 @@ drain: args.stdwsi = &wsi->parent->cgi->stdwsi[0]; args.hdr_state = wsi->hdr_state; - lwsl_debug("CGI LWS_STDOUT %p mode %d state %d\n", - wsi->parent, wsi->parent->mode, - wsi->parent->state); + lwsl_debug("CGI LWS_STDOUT %p role 0x%x state 0x%x\n", + wsi->parent, lwsi_role(wsi->parent), + lwsi_state(wsi->parent)); if (user_callback_handle_rxflow( wsi->parent->protocol->callback, @@ -1914,35 +1929,26 @@ drain: break; } -#endif - /* - * something went wrong with parsing the handshake, and - * we ended up back in the event loop without completing it - */ - case LWSCM_PRE_WS_SERVING_ACCEPT: - wsi->socket_is_permanently_unusable = 1; - goto close_and_handled; - - default: -#ifdef LWS_NO_CLIENT - break; -#else - if ((pollfd->revents & LWS_POLLOUT) && - lws_handle_POLLOUT_event(wsi, pollfd)) { - lwsl_debug("POLLOUT event closed it\n"); - goto close_and_handled; - } - - n = lws_client_socket_service(wsi, pollfd, NULL); - if (n) - return 1; - goto handled; #endif } n = 0; goto handled; +do_client: +#if !defined(LWS_NO_CLIENT) + if ((pollfd->revents & LWS_POLLOUT) && + lws_handle_POLLOUT_event(wsi, pollfd)) { + lwsl_debug("POLLOUT event closed it\n"); + goto close_and_handled; + } + + n = lws_client_socket_service(wsi, pollfd, NULL); + if (n) + return 1; +#endif + goto handled; + close_and_handled: lwsl_debug("%p: Close and handled\n", wsi); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "close_and_handled"); diff --git a/lib/tls/mbedtls/ssl.c b/lib/tls/mbedtls/ssl.c index 3ecfa8db..7bf33a01 100644 --- a/lib/tls/mbedtls/ssl.c +++ b/lib/tls/mbedtls/ssl.c @@ -257,16 +257,13 @@ lws_ssl_close(struct lws *wsi) SSL_free(wsi->ssl); wsi->ssl = NULL; - if (!(wsi->mode & LWSCM_FLAG_IMPLIES_CALLBACK_CLOSED_CLIENT_HTTP) && + if (!lwsi_role_client(wsi) && wsi->context->simultaneous_ssl_restriction && wsi->context->simultaneous_ssl-- == wsi->context->simultaneous_ssl_restriction) /* we made space and can do an accept */ lws_gate_accepts(wsi->context, 1); - //lwsl_notice("%s: ssl restr %d, simul %d\n", __func__, - // wsi->context->simultaneous_ssl_restriction, - // wsi->context->simultaneous_ssl); #if defined(LWS_WITH_STATS) wsi->context->updated = 1; #endif diff --git a/lib/tls/openssl/ssl.c b/lib/tls/openssl/ssl.c index 62ce4886..3f37a9bf 100644 --- a/lib/tls/openssl/ssl.c +++ b/lib/tls/openssl/ssl.c @@ -659,7 +659,7 @@ lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type, x509 = SSL_get_peer_certificate(wsi->ssl); if (!x509) { - lwsl_notice("no peer cert\n"); + lwsl_debug("no peer cert\n"); return -1; } diff --git a/minimal-examples/http-client/minimal-http-client/minimal-http-client.c b/minimal-examples/http-client/minimal-http-client/minimal-http-client.c index 6796346f..30562833 100644 --- a/minimal-examples/http-client/minimal-http-client/minimal-http-client.c +++ b/minimal-examples/http-client/minimal-http-client/minimal-http-client.c @@ -88,22 +88,39 @@ sigint_handler(int sig) interrupted = 1; } +static int findswitch(int argc, char **argv, const char *val) +{ + while (--argc > 0) { + if (!strcmp(argv[argc], val)) + return argc; + } + + return 0; +} + int main(int argc, char **argv) { struct lws_context_creation_info info; struct lws_client_connect_info i; struct lws_context *context; - int n = 0; + int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE + /* + * For LLL_ verbosity above NOTICE to be built into lws, + * lws must have been configured and built with + * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE + * + * | LLL_INFO | LLL_PARSER | LLL_HEADER | LLL_EXT | + * LLL_CLIENT | LLL_LATENCY | LLL_DEBUG + */ ; + int n = 0, m; signal(SIGINT, sigint_handler); - lws_set_log_level(LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE - /* for LLL_ verbosity above NOTICE to be built into lws, - * lws must have been configured and built with - * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ - /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ - /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ - /* | LLL_DEBUG */, NULL); + /* you can set the log level on commandline with, eg, -d 15 */ + m = findswitch(argc, argv, "-d"); + if (m && m + 1 < argc) + logs = atoi(argv[m + 1]); + lws_set_log_level(logs, NULL); lwsl_user("LWS minimal http client\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ diff --git a/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c b/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c index be3e74d0..98199572 100644 --- a/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c +++ b/minimal-examples/raw/minimal-raw-file/minimal-raw-file.c @@ -54,7 +54,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_PROTOCOL_DESTROY: - if (vhd->u.filefd != -1) + if (vhd && vhd->u.filefd != -1) close(vhd->u.filefd); break; diff --git a/minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c b/minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c index 8c1b2ff7..7989c2c4 100644 --- a/minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c +++ b/minimal-examples/raw/minimal-raw-vhost/minimal-raw-vhost.c @@ -131,7 +131,7 @@ int main(int argc, char **argv) /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */, NULL); - lwsl_user("LWS minimal raw vhost\n"); + lwsl_user("LWS minimal raw vhost | nc localhost 7681\n"); context = lws_create_context(&info); if (!context) { diff --git a/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/minimal-ws-client-pmd-bulk.c b/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/minimal-ws-client-pmd-bulk.c index b5825e3c..2f3c331c 100644 --- a/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/minimal-ws-client-pmd-bulk.c +++ b/minimal-examples/ws-client/minimal-ws-client-pmd-bulk/minimal-ws-client-pmd-bulk.c @@ -76,7 +76,7 @@ static int findswitch(int argc, char **argv, const char *val) { while (--argc > 0) { if (!strcmp(argv[argc], val)) - return 1; + return argc; } return 0; @@ -110,6 +110,7 @@ int main(int argc, char **argv) /* | LLL_DEBUG */, NULL); lwsl_user("LWS minimal ws client + permessage-deflate + multifragment bulk message\n"); + lwsl_user(" needs minimal-ws-server-pmd-bulk running to communicate with\n"); lwsl_user(" %s [-n (no exts)] [-c (compressible)]\n", argv[0]); context = lws_create_context(&info); if (!context) { diff --git a/minimal-examples/ws-client/minimal-ws-client-rx/minimal-ws-client.c b/minimal-examples/ws-client/minimal-ws-client-rx/minimal-ws-client.c index 5c82597a..a7ff86ae 100644 --- a/minimal-examples/ws-client/minimal-ws-client-rx/minimal-ws-client.c +++ b/minimal-examples/ws-client/minimal-ws-client-rx/minimal-ws-client.c @@ -82,7 +82,7 @@ int main(int argc, char **argv) /* for LLL_ verbosity above NOTICE to be built into lws, * lws must have been configured and built with * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ - | LLL_INFO /* | LLL_PARSER */ /* | LLL_HEADER */ + /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ /* | LLL_DEBUG */, NULL); diff --git a/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/index.html b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/index.html index 29954f44..f6a22f8d 100644 --- a/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/index.html +++ b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/index.html @@ -58,10 +58,10 @@ try { document.getElementById("status").textContent = "ws open "+ ws.extensions; } - ws.onmessage =function got_packet(msg) { - console.log("Received ws message len " + msg.data.length); + ws.onmessage = function got_packet(msg) { + console.log("Received ws message len " + msg.data.size); document.getElementById("r").value = - document.getElementById("r").value + "\nReceived: " + msg.data.length + " bytes\n"; + document.getElementById("r").value + "\nReceived: " + msg.data.size + " bytes\n"; document.getElementById("r").scrollTop = document.getElementById("r").scrollHeight; diff --git a/minimal-examples/ws-server/minimal-ws-server-threads/CMakeLists.txt b/minimal-examples/ws-server/minimal-ws-server-threads/CMakeLists.txt index 4f232053..cbfee936 100644 --- a/minimal-examples/ws-server/minimal-ws-server-threads/CMakeLists.txt +++ b/minimal-examples/ws-server/minimal-ws-server-threads/CMakeLists.txt @@ -82,9 +82,9 @@ if (requirements) add_executable(${SAMP} ${SRCS}) if (websockets_shared) - target_link_libraries(${SAMP} websockets_shared) + target_link_libraries(${SAMP} websockets_shared pthread) add_dependencies(${SAMP} websockets_shared) else() - target_link_libraries(${SAMP} websockets) + target_link_libraries(${SAMP} websockets pthread) endif() -endif() \ No newline at end of file +endif() diff --git a/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/index.html b/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/index.html index 5f6b28e4..928eaf90 100644 --- a/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/index.html +++ b/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/index.html @@ -54,8 +54,7 @@ function new_ws(urlpath, protocol) ws = new_ws(get_appropriate_ws_url(""), "lws-minimal"); try { ws.onopen = function() { - document.getElementById("m").disabled = 0; - document.getElementById("b").disabled = 0; + document.getElementById("r").disabled = 0; } ws.onmessage =function got_packet(msg) { @@ -78,8 +77,7 @@ try { } ws.onclose = function(){ - document.getElementById("m").disabled = 1; - document.getElementById("b").disabled = 1; + document.getElementById("r").disabled = 1; } } catch(exception) { alert('

Error' + exception); diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index 3c53f55f..bee87fb6 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -1724,7 +1724,7 @@ again: if (ch->peer_window_est < 32768) { write_task(pss, ch, SSH_WT_WINDOW_ADJUST); ch->peer_window_est += 32768; - lwsl_notice("extra peer WINDOW_ADJUST (~ %d)\n", + lwsl_info("extra peer WINDOW_ADJUST (~ %d)\n", ch->peer_window_est); } diff --git a/test-apps/attack.sh b/test-apps/attack.sh index 554ac4db..672ff646 100755 --- a/test-apps/attack.sh +++ b/test-apps/attack.sh @@ -779,6 +779,8 @@ echo echo "--- survived OK ---" kill -2 $CPID +exit 0 + # coverage... # run the test client against mirror for one period and exit killall libwebsockets-test-server 2>/dev/null diff --git a/test-apps/test-client.c b/test-apps/test-client.c index 784d4e0d..88bc8de6 100644 --- a/test-apps/test-client.c +++ b/test-apps/test-client.c @@ -365,6 +365,7 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_CLIENT_WRITEABLE: + lwsl_user("LWS_CALLBACK_CLIENT_WRITEABLE\n"); if (flag_no_mirror_traffic) return 0; diff --git a/test-apps/test-server.c b/test-apps/test-server.c index f3a5fce6..9e75a0fa 100644 --- a/test-apps/test-server.c +++ b/test-apps/test-server.c @@ -253,6 +253,7 @@ int main(int argc, char **argv) #ifndef LWS_NO_DAEMONIZE int daemonize = 0; #endif + char no_dumb_send = 0; /* * take care to zero down the info struct, he contains random garbaage @@ -262,7 +263,7 @@ int main(int argc, char **argv) info.port = 7681; while (n >= 0) { - n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:kU:", options, NULL); + n = getopt_long(argc, argv, "eci:hsap:d:Dr:C:K:A:R:vu:g:P:kU:n", options, NULL); if (n < 0) continue; switch (n) { @@ -286,6 +287,9 @@ int main(int argc, char **argv) case 'd': debug_level = atoi(optarg); break; + case 'n': + no_dumb_send = 1; + break; case 's': use_ssl = 1; opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; @@ -501,8 +505,9 @@ int main(int argc, char **argv) ms = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); if ((ms - oldms) > 50) { - lws_callback_on_writable_all_protocol(context, - &protocols[PROTOCOL_DUMB_INCREMENT]); + if (!no_dumb_send) + lws_callback_on_writable_all_protocol(context, + &protocols[PROTOCOL_DUMB_INCREMENT]); oldms = ms; }