Merge branch 'bugfix/httpd_session_close_lru' into 'master'

esp_http_server: Add flag in sock_db to identify httpd_sess_close is called from httpd_session_close_lru

Closes IDF-2443

See merge request espressif/esp-idf!11543
This commit is contained in:
Mahavir Jain 2021-01-15 20:06:00 +08:00
commit 526f682397
5 changed files with 76 additions and 3 deletions

View File

@ -69,6 +69,7 @@ struct sock_db {
httpd_recv_func_t recv_fn; /*!< Receive function for this socket */
httpd_pending_func_t pending_fn; /*!< Pending function for this socket */
uint64_t lru_counter; /*!< LRU Counter indicating when the socket was last used */
bool lru_socket; /*!< Flag indicating LRU socket */
char pending_data[PARSER_BLOCK_SIZE]; /*!< Buffer for pending data to be received */
size_t pending_len; /*!< Length of pending data to be received */
#ifdef CONFIG_HTTPD_WS_SUPPORT

View File

@ -67,8 +67,6 @@ static esp_err_t httpd_accept_conn(struct httpd_data *hd, int listen_fd)
close(new_fd);
return ESP_FAIL;
}
httpd_sess_update_lru_counter(hd->hd_sd->handle, new_fd);
ESP_LOGD(TAG, LOG_FMT("complete"));
return ESP_OK;
}

View File

@ -350,6 +350,8 @@ esp_err_t httpd_sess_close_lru(struct httpd_data *hd)
}
}
ESP_LOGD(TAG, LOG_FMT("fd = %d"), lru_fd);
struct sock_db *sd = httpd_sess_get(hd, lru_fd);
sd->lru_socket = true;
return httpd_sess_trigger_close(hd, lru_fd);
}
@ -380,11 +382,12 @@ static void httpd_sess_close(void *arg)
{
struct sock_db *sock_db = (struct sock_db *)arg;
if (sock_db) {
if (sock_db->lru_counter == 0) {
if (sock_db->lru_counter == 0 && !sock_db->lru_socket) {
ESP_LOGD(TAG, "Skipping session close for %d as it seems to be a race condition", sock_db->fd);
return;
}
int fd = sock_db->fd;
sock_db->lru_socket = false;
struct httpd_data *hd = (struct httpd_data *) sock_db->handle;
httpd_sess_delete(hd, fd);
close(fd);

View File

@ -23,11 +23,42 @@ import os
import string
import random
import threading
import time
import socket
from tiny_test_fw import Utility
import ttfw_idf
from idf_http_server_test import client
class http_client_thread(threading.Thread):
def __init__(self, ip, port, delay):
threading.Thread.__init__(self)
self.ip = ip
self.port = port
self.delay = delay
self.exc = None
# Thread function used to open a socket and wait for specific amount of time before returning
def open_connection(self, ip, port, delay):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(delay)
s.connect((ip, port))
time.sleep(delay)
def run(self):
try:
self.open_connection(self.ip, self.port, self.delay)
except socket.timeout as e:
self.exc = e
def join(self, timeout=None):
threading.Thread.join(self)
if self.exc:
raise self.exc
# When running on local machine execute the following before running this script
# > make app bootloader
# > make print_flash_cmd | tail -n 1 > build/download.config
@ -100,5 +131,44 @@ def test_examples_protocol_http_server_simple(env, extra_data):
dut1.expect("Found URL query => " + query, timeout=30)
@ttfw_idf.idf_example_test(env_tag="Example_WIFI")
def test_examples_protocol_http_server_lru_purge_enable(env, extra_data):
# Acquire DUT
dut1 = env.get_dut("http_server", "examples/protocols/http_server/simple", dut_class=ttfw_idf.ESP32DUT)
# Get binary file
binary_file = os.path.join(dut1.app.binary_path, "simple.bin")
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance("http_server_bin_size", "{}KB".format(bin_size // 1024))
# Upload binary and start testing
Utility.console_log("Starting http_server simple test app")
dut1.start_app()
# Parse IP address of STA
Utility.console_log("Waiting to connect with AP")
got_ip = dut1.expect(re.compile(r"(?:[\s\S]*)IPv4 address: (\d+.\d+.\d+.\d+)"), timeout=30)[0]
got_port = dut1.expect(re.compile(r"(?:[\s\S]*)Starting server on port: '(\d+)'"), timeout=30)[0]
Utility.console_log("Got IP : " + got_ip)
Utility.console_log("Got Port : " + got_port)
# Expected Logs
dut1.expect("Registering URI handlers", timeout=30)
threads = []
# Open 20 sockets, one from each thread
for _ in range(20):
try:
thread = http_client_thread(got_ip, (int(got_port)), 20)
thread.start()
threads.append(thread)
except OSError as err:
Utility.console_log("Error: unable to start thread, " + err)
for t in threads:
t.join()
if __name__ == '__main__':
test_examples_protocol_http_server_simple()
test_examples_protocol_http_server_lru_purge_enable()

View File

@ -223,6 +223,7 @@ static httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.lru_purge_enable = true;
// Start the httpd server
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);