mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-07 03:57:07 +03:00
move to stock esp_http_server but keep it under control
- means 3 sockets are used (data + 2 for control) - but LRU is activated (uses the 2 extra sockets to wake from select) - backlog is just 1 (listen) - only 3 sockets can be consumed before LRU activates - for now, connections are kept-alive
This commit is contained in:
10
components/esp_http_server/CMakeLists.txt
Normal file
10
components/esp_http_server/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
idf_build_get_property(prefix IDF_PATH)
|
||||
string(CONCAT prefix "${prefix}" "/components/esp_http_server")
|
||||
|
||||
idf_component_register(
|
||||
SRC_DIRS "${prefix}/src" "${prefix}/src/util"
|
||||
INCLUDE_DIRS "${prefix}/include"
|
||||
PRIV_INCLUDE_DIRS "." "${prefix}/src/port/esp32" "${prefix}/src/util"
|
||||
REQUIRES nghttp # for http_parser.h
|
||||
PRIV_REQUIRES lwip
|
||||
)
|
||||
1
components/esp_http_server/Kconfig
Normal file
1
components/esp_http_server/Kconfig
Normal file
@@ -0,0 +1 @@
|
||||
source "$IDF_PATH/components/esp_http_server/Kconfig"
|
||||
68
components/esp_http_server/osal.h
Normal file
68
components/esp_http_server/osal.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _OSAL_H_
|
||||
#define _OSAL_H_
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OS_SUCCESS ESP_OK
|
||||
#define OS_FAIL ESP_FAIL
|
||||
|
||||
typedef TaskHandle_t othread_t;
|
||||
|
||||
static inline int httpd_os_thread_create(othread_t *thread,
|
||||
const char *name, uint16_t stacksize, int prio,
|
||||
void (*thread_routine)(void *arg), void *arg,
|
||||
BaseType_t core_id)
|
||||
{
|
||||
StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
|
||||
StackType_t *xStack = heap_caps_malloc(stacksize,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT));
|
||||
|
||||
*thread = xTaskCreateStaticPinnedToCore(thread_routine, name, stacksize, arg, prio, xStack,xTaskBuffer,core_id);
|
||||
if (*thread) {
|
||||
return OS_SUCCESS;
|
||||
}
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
/* Only self delete is supported */
|
||||
static inline void httpd_os_thread_delete(void)
|
||||
{
|
||||
vTaskDelete(xTaskGetCurrentTaskHandle());
|
||||
}
|
||||
|
||||
static inline void httpd_os_thread_sleep(int msecs)
|
||||
{
|
||||
vTaskDelay(msecs / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
static inline othread_t httpd_os_thread_handle(void)
|
||||
{
|
||||
return xTaskGetCurrentTaskHandle();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! _OSAL_H_ */
|
||||
@@ -1,15 +1,12 @@
|
||||
/*
|
||||
* AirCast: Chromecast to AirPlay
|
||||
*
|
||||
* (c) Philippe 2016-2017, philippe_44@outlook.com
|
||||
* (c) Philippe 2020, philippe_44@outlook.com
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RAOP_H
|
||||
#define __RAOP_H
|
||||
#pragma once
|
||||
|
||||
#include "platform.h"
|
||||
#include "raop_sink.h"
|
||||
@@ -20,4 +17,3 @@ void raop_delete(struct raop_ctx_s *ctx);
|
||||
void raop_abort(struct raop_ctx_s *ctx);
|
||||
bool raop_cmd(struct raop_ctx_s *ctx, raop_event_t event, void *param);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -67,12 +67,12 @@ static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(
|
||||
static const char * TAG = "audio controls";
|
||||
static actrls_config_t *json_config;
|
||||
cJSON * control_profiles = NULL;
|
||||
static actrls_t default_controls, current_controls;
|
||||
static EXT_RAM_ATTR actrls_t default_controls, current_controls;
|
||||
static actrls_hook_t *default_hook, *current_hook;
|
||||
static bool default_raw_controls, current_raw_controls;
|
||||
static actrls_ir_handler_t *default_ir_handler, *current_ir_handler;
|
||||
|
||||
static struct {
|
||||
static EXT_RAM_ATTR struct {
|
||||
bool long_state;
|
||||
bool volume_lock;
|
||||
TimerHandle_t timer;
|
||||
|
||||
@@ -370,7 +370,7 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
|
||||
// memory still used but at least task is not created
|
||||
if (stats) {
|
||||
// we allocate TCB but stack is staic to avoid SPIRAM fragmentation
|
||||
// we allocate TCB but stack is static to avoid SPIRAM fragmentation
|
||||
StaticTask_t* xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
static EXT_RAM_ATTR StackType_t xStack[STAT_STACK_SIZE] __attribute__ ((aligned (4)));
|
||||
stats_task = xTaskCreateStatic( (TaskFunction_t) output_thread_i2s_stats, "output_i2s_sts", STAT_STACK_SIZE,
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
#include <stdlib.h> // for malloc and free
|
||||
void* operator new(unsigned int size) { return malloc(size); }
|
||||
void operator delete(void* ptr) { if (ptr) free(ptr); }
|
||||
#include <memory>
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
void* operator new(std::size_t count) {
|
||||
return heap_caps_malloc(count, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr) noexcept {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
// C++17 only
|
||||
void* operator new (std::size_t count, std::align_val_t alignment) {
|
||||
return heap_caps_malloc(count, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
// C++17 only
|
||||
void operator delete(void* ptr, std::align_val_t alignment) noexcept {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
|
||||
set( WEBPACK_DIR webapp/webpack/dist )
|
||||
idf_component_register( SRC_DIRS . webapp
|
||||
INCLUDE_DIRS . webapp ${IDF_PATH}/components/esp_http_server/src ${IDF_PATH}/components/esp_http_server/src/port/esp32 ${IDF_PATH}/components/esp_http_server/src/util ${IDF_PATH}/components/esp_http_server/src/
|
||||
REQUIRES squeezelite-ota json mdns
|
||||
PRIV_REQUIRES tools services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt
|
||||
)
|
||||
|
||||
idf_component_register( SRC_DIRS . webapp
|
||||
INCLUDE_DIRS . webapp
|
||||
REQUIRES squeezelite-ota json mdns
|
||||
PRIV_REQUIRES tools services platform_config esp_common json newlib freertos spi_flash nvs_flash mdns pthread wpa_supplicant platform_console esp_http_server console driver_bt
|
||||
)
|
||||
|
||||
include(webapp/webapp.cmake)
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __ESP_HTTP_SERVER_H_
|
||||
#define __ESP_HTTP_SERVER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <http_parser.h>
|
||||
#include <sdkconfig.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Starts the web server
|
||||
*
|
||||
* Create an instance of HTTP server and allocate memory/resources for it
|
||||
* depending upon the specified configuration.
|
||||
*
|
||||
* Example usage:
|
||||
* @code{c}
|
||||
*
|
||||
* //Function for starting the webserver
|
||||
* httpd_handle_t start_webserver(void)
|
||||
* {
|
||||
* // Generate default configuration
|
||||
* httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
*
|
||||
* // Empty handle to http_server
|
||||
* httpd_handle_t server = NULL;
|
||||
*
|
||||
* // Start the httpd server
|
||||
* if (httpd_start(&server, &config) == ESP_OK) {
|
||||
* // Register URI handlers
|
||||
* httpd_register_uri_handler(server, &uri_get);
|
||||
* httpd_register_uri_handler(server, &uri_post);
|
||||
* }
|
||||
* // If server failed to start, handle will be NULL
|
||||
* return server;
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] config Configuration for new instance of the server
|
||||
* @param[out] handle Handle to newly created instance of the server. NULL on error
|
||||
* @return
|
||||
* - ESP_OK : Instance created successfully
|
||||
* - ESP_ERR_INVALID_ARG : Null argument(s)
|
||||
* - ESP_ERR_HTTPD_ALLOC_MEM : Failed to allocate memory for instance
|
||||
* - ESP_ERR_HTTPD_TASK : Failed to launch server task
|
||||
*/
|
||||
esp_err_t __httpd_start(httpd_handle_t *handle, const httpd_config_t *config);
|
||||
static inline int __httpd_os_thread_create_static(TaskHandle_t *thread,
|
||||
const char *name, uint16_t stacksize, int prio,
|
||||
void (*thread_routine)(void *arg), void *arg,
|
||||
BaseType_t core_id)
|
||||
{
|
||||
|
||||
|
||||
StaticTask_t *xTaskBuffer = (StaticTask_t*) heap_caps_malloc(sizeof(StaticTask_t), (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT));
|
||||
StackType_t *xStack = heap_caps_malloc(stacksize,(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT));
|
||||
|
||||
|
||||
//
|
||||
*thread = xTaskCreateStaticPinnedToCore(thread_routine, name, stacksize, arg, prio, xStack,xTaskBuffer,core_id);
|
||||
if (*thread) {
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ! _ESP_HTTP_SERVER_H_ */
|
||||
@@ -1,341 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <esp_http_server.h>
|
||||
#include <_esp_http_server.h>
|
||||
#include "esp_httpd_priv.h"
|
||||
#include "ctrl_sock.h"
|
||||
|
||||
static const char *TAG = "_httpd";
|
||||
|
||||
|
||||
struct httpd_ctrl_data {
|
||||
enum httpd_ctrl_msg {
|
||||
HTTPD_CTRL_SHUTDOWN,
|
||||
HTTPD_CTRL_WORK,
|
||||
} hc_msg;
|
||||
httpd_work_fn_t hc_work;
|
||||
void *hc_work_arg;
|
||||
};
|
||||
|
||||
|
||||
static esp_err_t _httpd_server_init(struct httpd_data *hd)
|
||||
{
|
||||
int fd = socket(PF_INET6, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in socket (%d)"), errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
struct in6_addr inaddr_any = IN6ADDR_ANY_INIT;
|
||||
struct sockaddr_in6 serv_addr = {
|
||||
.sin6_family = PF_INET6,
|
||||
.sin6_addr = inaddr_any,
|
||||
.sin6_port = htons(hd->config.server_port)
|
||||
};
|
||||
|
||||
/* Enable SO_REUSEADDR to allow binding to the same
|
||||
* address and port when restarting the server */
|
||||
int enable = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
|
||||
/* This will fail if CONFIG_LWIP_SO_REUSE is not enabled. But
|
||||
* it does not affect the normal working of the HTTP Server */
|
||||
ESP_LOGW(TAG, LOG_FMT("error enabling SO_REUSEADDR (%d)"), errno);
|
||||
}
|
||||
|
||||
int ret = bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in bind (%d)"), errno);
|
||||
close(fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ret = listen(fd, hd->config.backlog_conn);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in listen (%d)"), errno);
|
||||
close(fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int ctrl_fd = cs_create_ctrl_sock(hd->config.ctrl_port);
|
||||
if (ctrl_fd < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in creating ctrl socket (%d)"), errno);
|
||||
close(fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int msg_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (msg_fd < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in creating msg socket (%d)"), errno);
|
||||
close(fd);
|
||||
close(ctrl_fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
hd->listen_fd = fd;
|
||||
hd->ctrl_fd = ctrl_fd;
|
||||
hd->msg_fd = msg_fd;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t _httpd_accept_conn(struct httpd_data *hd, int listen_fd)
|
||||
{
|
||||
/* If no space is available for new session, close the least recently used one */
|
||||
if (hd->config.lru_purge_enable == true) {
|
||||
if (!httpd_is_sess_available(hd)) {
|
||||
/* Queue asynchronous closure of the least recently used session */
|
||||
return httpd_sess_close_lru(hd);
|
||||
/* Returning from this allowes the main server thread to process
|
||||
* the queued asynchronous control message for closing LRU session.
|
||||
* Since connection request hasn't been addressed yet using accept()
|
||||
* therefore _httpd_accept_conn() will be called again, but this time
|
||||
* with space available for one session
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in addr_from;
|
||||
socklen_t addr_from_len = sizeof(addr_from);
|
||||
int new_fd = accept(listen_fd, (struct sockaddr *)&addr_from, &addr_from_len);
|
||||
if (new_fd < 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("error in accept (%d)"), errno);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGD(TAG, LOG_FMT("newfd = %d"), new_fd);
|
||||
|
||||
struct timeval tv;
|
||||
/* Set recv timeout of this fd as per config */
|
||||
tv.tv_sec = hd->config.recv_wait_timeout;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
|
||||
|
||||
/* Set send timeout of this fd as per config */
|
||||
tv.tv_sec = hd->config.send_wait_timeout;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(new_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&tv, sizeof(tv));
|
||||
|
||||
if (ESP_OK != httpd_sess_new(hd, new_fd)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("session creation failed"));
|
||||
close(new_fd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGD(TAG, LOG_FMT("complete"));
|
||||
return ESP_OK;
|
||||
}
|
||||
/* Manage in-coming connection or data requests */
|
||||
static esp_err_t _httpd_server(struct httpd_data *hd)
|
||||
{
|
||||
fd_set read_set;
|
||||
FD_ZERO(&read_set);
|
||||
if (hd->config.lru_purge_enable || httpd_is_sess_available(hd)) {
|
||||
/* Only listen for new connections if server has capacity to
|
||||
* handle more (or when LRU purge is enabled, in which case
|
||||
* older connections will be closed) */
|
||||
FD_SET(hd->listen_fd, &read_set);
|
||||
}
|
||||
|
||||
int maxfd;
|
||||
httpd_sess_set_descriptors(hd, &read_set, &maxfd);
|
||||
maxfd = MAX(hd->listen_fd, maxfd);
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("doing select maxfd+1 = %d"), maxfd + 1);
|
||||
int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
|
||||
if (active_cnt < 0) {
|
||||
ESP_LOGE(TAG, LOG_FMT("error in select (%d)"), errno);
|
||||
httpd_sess_delete_invalid(hd);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Case0: Do we have a control message? */
|
||||
if (FD_ISSET(hd->ctrl_fd, &read_set)) {
|
||||
ESP_LOGD(TAG, LOG_FMT("processing ctrl message"));
|
||||
_httpd_process_ctrl_msg(hd);
|
||||
if (hd->hd_td.status == THREAD_STOPPING) {
|
||||
ESP_LOGD(TAG, LOG_FMT("stopping thread"));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Case1: Do we have any activity on the current data
|
||||
* sessions? */
|
||||
int fd = -1;
|
||||
while ((fd = httpd_sess_iterate(hd, fd)) != -1) {
|
||||
if (FD_ISSET(fd, &read_set) || (httpd_sess_pending(hd, fd))) {
|
||||
ESP_LOGD(TAG, LOG_FMT("processing socket %d"), fd);
|
||||
if (httpd_sess_process(hd, fd) != ESP_OK) {
|
||||
ESP_LOGD(TAG, LOG_FMT("closing socket %d"), fd);
|
||||
close(fd);
|
||||
/* Delete session and update fd to that
|
||||
* preceding the one being deleted */
|
||||
fd = httpd_sess_delete(hd, fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Case2: Do we have any incoming connection requests to
|
||||
* process? */
|
||||
if (FD_ISSET(hd->listen_fd, &read_set)) {
|
||||
ESP_LOGD(TAG, LOG_FMT("processing listen socket %d"), hd->listen_fd);
|
||||
if (_httpd_accept_conn(hd, hd->listen_fd) != ESP_OK) {
|
||||
ESP_LOGW(TAG, LOG_FMT("error accepting new connection"));
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void _httpd_close_all_sessions(struct httpd_data *hd)
|
||||
{
|
||||
int fd = -1;
|
||||
while ((fd = httpd_sess_iterate(hd, fd)) != -1) {
|
||||
ESP_LOGD(TAG, LOG_FMT("cleaning up socket %d"), fd);
|
||||
httpd_sess_delete(hd, fd);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
/* The main HTTPD thread */
|
||||
static void _httpd_thread(void *arg)
|
||||
{
|
||||
int ret;
|
||||
struct httpd_data *hd = (struct httpd_data *) arg;
|
||||
hd->hd_td.status = THREAD_RUNNING;
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("web server started"));
|
||||
while (1) {
|
||||
ret = _httpd_server(hd);
|
||||
if (ret != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("web server exiting"));
|
||||
close(hd->msg_fd);
|
||||
cs_free_ctrl_sock(hd->ctrl_fd);
|
||||
_httpd_close_all_sessions(hd);
|
||||
close(hd->listen_fd);
|
||||
hd->hd_td.status = THREAD_STOPPED;
|
||||
httpd_os_thread_delete();
|
||||
}
|
||||
static struct httpd_data *__httpd_create(const httpd_config_t *config)
|
||||
{
|
||||
/* Allocate memory for httpd instance data */
|
||||
struct httpd_data *hd = calloc(1, sizeof(struct httpd_data));
|
||||
if (!hd) {
|
||||
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
|
||||
return NULL;
|
||||
}
|
||||
hd->hd_calls = calloc(config->max_uri_handlers, sizeof(httpd_uri_t *));
|
||||
if (!hd->hd_calls) {
|
||||
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
|
||||
free(hd);
|
||||
return NULL;
|
||||
}
|
||||
hd->hd_sd = calloc(config->max_open_sockets, sizeof(struct sock_db));
|
||||
if (!hd->hd_sd) {
|
||||
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
|
||||
free(hd->hd_calls);
|
||||
free(hd);
|
||||
return NULL;
|
||||
}
|
||||
struct httpd_req_aux *ra = &hd->hd_req_aux;
|
||||
ra->resp_hdrs = calloc(config->max_resp_headers, sizeof(struct resp_hdr));
|
||||
if (!ra->resp_hdrs) {
|
||||
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
|
||||
free(hd->hd_sd);
|
||||
free(hd->hd_calls);
|
||||
free(hd);
|
||||
return NULL;
|
||||
}
|
||||
hd->err_handler_fns = calloc(HTTPD_ERR_CODE_MAX, sizeof(httpd_err_handler_func_t));
|
||||
if (!hd->err_handler_fns) {
|
||||
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
|
||||
free(ra->resp_hdrs);
|
||||
free(hd->hd_sd);
|
||||
free(hd->hd_calls);
|
||||
free(hd);
|
||||
return NULL;
|
||||
}
|
||||
/* Save the configuration for this instance */
|
||||
hd->config = *config;
|
||||
return hd;
|
||||
}
|
||||
static void _httpd_delete(struct httpd_data *hd)
|
||||
{
|
||||
struct httpd_req_aux *ra = &hd->hd_req_aux;
|
||||
/* Free memory of httpd instance data */
|
||||
free(hd->err_handler_fns);
|
||||
free(ra->resp_hdrs);
|
||||
free(hd->hd_sd);
|
||||
|
||||
/* Free registered URI handlers */
|
||||
httpd_unregister_all_uri_handlers(hd);
|
||||
free(hd->hd_calls);
|
||||
free(hd);
|
||||
}
|
||||
esp_err_t __httpd_start(httpd_handle_t *handle, const httpd_config_t *config)
|
||||
{
|
||||
if (handle == NULL || config == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Sanity check about whether LWIP is configured for providing the
|
||||
* maximum number of open sockets sufficient for the server. Though,
|
||||
* this check doesn't guarantee that many sockets will actually be
|
||||
* available at runtime as other processes may use up some sockets.
|
||||
* Note that server also uses 3 sockets for its internal use :
|
||||
* 1) listening for new TCP connections
|
||||
* 2) for sending control messages over UDP
|
||||
* 3) for receiving control messages over UDP
|
||||
* So the total number of required sockets is max_open_sockets + 3
|
||||
*/
|
||||
if (CONFIG_LWIP_MAX_SOCKETS < config->max_open_sockets + 3) {
|
||||
ESP_LOGE(TAG, "Configuration option max_open_sockets is too large (max allowed %d)\n\t"
|
||||
"Either decrease this or configure LWIP_MAX_SOCKETS to a larger value",
|
||||
CONFIG_LWIP_MAX_SOCKETS - 3);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
struct httpd_data *hd = __httpd_create(config);
|
||||
if (hd == NULL) {
|
||||
/* Failed to allocate memory */
|
||||
return ESP_ERR_HTTPD_ALLOC_MEM;
|
||||
}
|
||||
|
||||
if (_httpd_server_init(hd) != ESP_OK) {
|
||||
_httpd_delete(hd);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
httpd_sess_init(hd);
|
||||
if (__httpd_os_thread_create_static(&hd->hd_td.handle, "httpd",
|
||||
hd->config.stack_size,
|
||||
hd->config.task_priority,
|
||||
_httpd_thread, hd,
|
||||
hd->config.core_id) != ESP_OK) {
|
||||
/* Failed to launch task */
|
||||
_httpd_delete(hd);
|
||||
return ESP_ERR_HTTPD_TASK;
|
||||
}
|
||||
|
||||
*handle = (httpd_handle_t *)hd;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -353,6 +353,8 @@ static esp_err_t set_content_type_from_req(httpd_req_t *req)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
set_content_type_from_file(req, filename);
|
||||
// we might have to disallow keep-alive in the future
|
||||
// httpd_resp_set_hdr(req, "Connection", "close");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "http_server_handlers.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "_esp_http_server.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -135,14 +134,16 @@ esp_err_t http_server_start()
|
||||
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.max_uri_handlers = 25;
|
||||
config.max_open_sockets = 8;
|
||||
config.max_open_sockets = 3;
|
||||
config.lru_purge_enable = true;
|
||||
config.backlog_conn = 1;
|
||||
config.uri_match_fn = httpd_uri_match_wildcard;
|
||||
config.task_priority = ESP_TASK_PRIO_MIN;
|
||||
//todo: use the endpoint below to configure session token?
|
||||
// config.open_fn
|
||||
|
||||
ESP_LOGD(TAG, "Starting HTTP Server");
|
||||
esp_err_t err= __httpd_start(&_server, &config);
|
||||
esp_err_t err= httpd_start(&_server, &config);
|
||||
if(err != ESP_OK){
|
||||
ESP_LOGE_LOC(TAG,"Start server failed");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user