diff --git a/examples/protocols/http_server/ws_echo_server/main/ws_echo_server.c b/examples/protocols/http_server/ws_echo_server/main/ws_echo_server.c index d4c2433a56..afa618ffd5 100644 --- a/examples/protocols/http_server/ws_echo_server/main/ws_echo_server.c +++ b/examples/protocols/http_server/ws_echo_server/main/ws_echo_server.c @@ -52,6 +52,18 @@ static void ws_async_send(void *arg) free(resp_arg); } +static void ws_ping_send(void *arg) +{ + struct async_resp_arg *resp_arg = arg; + httpd_handle_t hd = resp_arg->hd; + int fd = resp_arg->fd; + httpd_ws_frame_t ping_pkt; + memset(&ping_pkt, 0, sizeof(httpd_ws_frame_t)); + ping_pkt.type = HTTPD_WS_TYPE_PING; + httpd_ws_send_frame_async(hd, fd, &ping_pkt); + free(resp_arg); +} + static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t *req) { struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); @@ -67,6 +79,22 @@ static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t *req) return ret; } + +static esp_err_t trigger_ping_send(httpd_handle_t handle, httpd_req_t *req) +{ + struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); + if (resp_arg == NULL) { + return ESP_ERR_NO_MEM; + } + resp_arg->hd = req->handle; + resp_arg->fd = httpd_req_to_sockfd(req); + esp_err_t ret = httpd_queue_work(handle, ws_ping_send, resp_arg); + if (ret != ESP_OK) { + free(resp_arg); + } + return ret; +} + #ifdef CONFIG_EXAMPLE_ENABLE_WS_PRE_HANDSHAKE_CB static esp_err_t ws_pre_handshake_cb(httpd_req_t *req) { @@ -147,10 +175,14 @@ static esp_err_t echo_handler(httpd_req_t *req) } ESP_LOGI(TAG, "Packet type: %d", ws_pkt.type); if (ws_pkt.type == HTTPD_WS_TYPE_TEXT && - ws_pkt.payload != NULL && - strcmp((char*)ws_pkt.payload,"Trigger async") == 0) { - free(buf); - return trigger_async_send(req->handle, req); + ws_pkt.payload != NULL) { + if (strncmp((char *)ws_pkt.payload, "Trigger async", strlen("Trigger async")) == 0) { + free(buf); + return trigger_async_send(req->handle, req); + } else if (strncmp((char *)ws_pkt.payload, "Ping", strlen("Ping")) == 0) { + free(buf); + return trigger_ping_send(req->handle, req); + } } ret = httpd_ws_send_frame(req, &ws_pkt); @@ -233,7 +265,6 @@ static void connect_handler(void* arg, esp_event_base_t event_base, } } - void app_main(void) { static httpd_handle_t server = NULL; diff --git a/examples/protocols/http_server/ws_echo_server/pytest_ws_server_example.py b/examples/protocols/http_server/ws_echo_server/pytest_ws_server_example.py index 10f029e527..1f76d12480 100644 --- a/examples/protocols/http_server/ws_echo_server/pytest_ws_server_example.py +++ b/examples/protocols/http_server/ws_echo_server/pytest_ws_server_example.py @@ -80,7 +80,6 @@ def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None: logging.info(f'Testing opcode {expected_opcode}: Received opcode:{opcode}, data:{data}') data = data.decode() if expected_opcode == OPCODE_PING: - dut.expect('Got a WS PING frame, Replying PONG') if opcode != OPCODE_PONG or data != DATA: raise RuntimeError(f'Failed to receive correct opcode:{opcode} or data:{data}') continue @@ -89,12 +88,47 @@ def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None: if opcode != expected_opcode or data != DATA or opcode != int(dut_opcode) or (data not in str(dut_data)): raise RuntimeError(f'Failed to receive correct opcode:{opcode} or data:{data}') + # Test async send - server queues the work, so we need to wait for it to be processed + logging.info('Testing async send') ws.write(data='Trigger async', opcode=OPCODE_TEXT) + # Wait for server to receive and queue the async send + dut.expect(r'Got packet with message: Trigger async', timeout=10) + # Now read the async response (server processes work queue asynchronously) opcode, data = ws.read() logging.info(f'Testing async send: Received opcode:{opcode}, data:{data}') data = data.decode() if opcode != OPCODE_TEXT or data != 'Async data': raise RuntimeError(f'Failed to receive correct opcode:{opcode} or data:{data}') + # Test ping from server + logging.info('Testing server-initiated ping') + ws.write(data='Ping', opcode=OPCODE_TEXT) + # Wait for server to receive the message and send a ping + dut.expect(r'Got packet with message: Ping', timeout=10) + # Now read the ping response + opcode, data = ws.read() + logging.info(f'Testing server-initiated ping: Received opcode:{opcode}, data:{data}') + data = data.decode() + if opcode != OPCODE_PING: + raise RuntimeError(f'Failed to receive correct opcode:{opcode}') + # Now we should get a pong in response to our ping + opcode, data = ws.read() + data = data.decode() + if opcode != OPCODE_PONG: + raise RuntimeError(f'Failed to receive correct opcode:{opcode}') + ws.write(data='Ping', opcode=OPCODE_TEXT) + # Wait for server to receive the message and send a ping + dut.expect(r'Got packet with message: Ping', timeout=10) + # Now read the ping response + opcode, data = ws.read() + logging.info(f'Testing server-initiated ping: Received opcode:{opcode}, data:{data}') + data = data.decode() + if opcode != OPCODE_PING: + raise RuntimeError(f'Failed to receive correct opcode:{opcode}') + # Now we should get a pong in response to our ping + opcode, data = ws.read() + data = data.decode() + if opcode != OPCODE_PONG: + raise RuntimeError(f'Failed to receive correct opcode:{opcode}') @pytest.mark.wifi_router