forked from espressif/esp-idf
Merge branch 'feature/esp_http_server_on_linux' into 'master'
Feature/esp http server on linux Closes IDF-6608 See merge request espressif/esp-idf!21960
This commit is contained in:
@@ -1,3 +1,16 @@
|
|||||||
|
set(priv_req mbedtls)
|
||||||
|
set(priv_inc_dir "src/util")
|
||||||
|
set(requires http_parser)
|
||||||
|
if(NOT ${IDF_TARGET} STREQUAL "linux")
|
||||||
|
list(APPEND priv_req lwip esp_timer)
|
||||||
|
list(APPEND priv_inc_dir "src/port/esp32")
|
||||||
|
list(APPEND requires esp_event)
|
||||||
|
else()
|
||||||
|
list(APPEND priv_inc_dir "src/port/linux")
|
||||||
|
list(APPEND priv_req pthread)
|
||||||
|
list(APPEND requires linux)
|
||||||
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS "src/httpd_main.c"
|
idf_component_register(SRCS "src/httpd_main.c"
|
||||||
"src/httpd_parse.c"
|
"src/httpd_parse.c"
|
||||||
"src/httpd_sess.c"
|
"src/httpd_sess.c"
|
||||||
@@ -6,6 +19,15 @@ idf_component_register(SRCS "src/httpd_main.c"
|
|||||||
"src/httpd_ws.c"
|
"src/httpd_ws.c"
|
||||||
"src/util/ctrl_sock.c"
|
"src/util/ctrl_sock.c"
|
||||||
INCLUDE_DIRS "include"
|
INCLUDE_DIRS "include"
|
||||||
PRIV_INCLUDE_DIRS "src/port/esp32" "src/util"
|
PRIV_INCLUDE_DIRS ${priv_inc_dir}
|
||||||
REQUIRES esp_event http_parser # for http_parser.h
|
REQUIRES ${requires}
|
||||||
PRIV_REQUIRES lwip mbedtls esp_timer)
|
PRIV_REQUIRES ${priv_req})
|
||||||
|
|
||||||
|
if(${IDF_TARGET} STREQUAL "linux")
|
||||||
|
find_library(LIB_BSD bsd)
|
||||||
|
if(LIB_BSD)
|
||||||
|
target_link_libraries(${COMPONENT_LIB} PRIVATE ${LIB_BSD})
|
||||||
|
elseif(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
|
message(WARNING "Missing LIBBSD library. Install libbsd-dev package and/or check linker directories.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <sdkconfig.h>
|
#include <sdkconfig.h>
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
#include <esp_event.h>
|
#include <esp_event.h>
|
||||||
|
#include <esp_event_base.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@@ -22,6 +22,14 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_NEWLIB_NANO_FORMAT
|
||||||
|
#define NEWLIB_NANO_COMPAT_FORMAT PRIu32
|
||||||
|
#define NEWLIB_NANO_COMPAT_CAST(size_t_var) (uint32_t)size_t_var
|
||||||
|
#else
|
||||||
|
#define NEWLIB_NANO_COMPAT_FORMAT "zu"
|
||||||
|
#define NEWLIB_NANO_COMPAT_CAST(size_t_var) size_t_var
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Size of request data block/chunk (not to be confused with chunked encoded data)
|
/* Size of request data block/chunk (not to be confused with chunked encoded data)
|
||||||
* that is received and parsed in one turn of the parsing process. This should not
|
* that is received and parsed in one turn of the parsing process. This should not
|
||||||
* exceed the scratch buffer size and should at least be 8 bytes */
|
* exceed the scratch buffer size and should at least be 8 bytes */
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
#include <esp_http_server.h>
|
#include <esp_http_server.h>
|
||||||
#include "esp_httpd_priv.h"
|
#include "esp_httpd_priv.h"
|
||||||
@@ -19,6 +20,13 @@
|
|||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_LWIP_MAX_SOCKETS)
|
||||||
|
#define HTTPD_MAX_SOCKETS CONFIG_LWIP_MAX_SOCKETS
|
||||||
|
#else
|
||||||
|
/* LwIP component is not included into the build, use a default value */
|
||||||
|
#define HTTPD_MAX_SOCKETS 15
|
||||||
|
#endif
|
||||||
|
|
||||||
static const int DEFAULT_KEEP_ALIVE_IDLE = 5;
|
static const int DEFAULT_KEEP_ALIVE_IDLE = 5;
|
||||||
static const int DEFAULT_KEEP_ALIVE_INTERVAL= 5;
|
static const int DEFAULT_KEEP_ALIVE_INTERVAL= 5;
|
||||||
static const int DEFAULT_KEEP_ALIVE_COUNT= 3;
|
static const int DEFAULT_KEEP_ALIVE_COUNT= 3;
|
||||||
@@ -476,10 +484,10 @@ esp_err_t httpd_start(httpd_handle_t *handle, const httpd_config_t *config)
|
|||||||
* 3) for receiving control messages over UDP
|
* 3) for receiving control messages over UDP
|
||||||
* So the total number of required sockets is max_open_sockets + 3
|
* So the total number of required sockets is max_open_sockets + 3
|
||||||
*/
|
*/
|
||||||
if (CONFIG_LWIP_MAX_SOCKETS < config->max_open_sockets + 3) {
|
if (HTTPD_MAX_SOCKETS < config->max_open_sockets + 3) {
|
||||||
ESP_LOGE(TAG, "Config option max_open_sockets is too large (max allowed %d, 3 sockets used by HTTP server internally)\n\t"
|
ESP_LOGE(TAG, "Config option max_open_sockets is too large (max allowed %d, 3 sockets used by HTTP server internally)\n\t"
|
||||||
"Either decrease this or configure LWIP_MAX_SOCKETS to a larger value",
|
"Either decrease this or configure LWIP_MAX_SOCKETS to a larger value",
|
||||||
CONFIG_LWIP_MAX_SOCKETS - 3);
|
HTTPD_MAX_SOCKETS - 3);
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#if __has_include(<bsd/string.h>)
|
||||||
|
// for strlcpy
|
||||||
|
#include <bsd/string.h>
|
||||||
|
#endif
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
@@ -72,8 +77,8 @@ static esp_err_t verify_url (http_parser *parser)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sizeof(r->uri) < (length + 1)) {
|
if (sizeof(r->uri) < (length + 1)) {
|
||||||
ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
|
ESP_LOGW(TAG, LOG_FMT("URI length (%"NEWLIB_NANO_COMPAT_FORMAT") greater than supported (%"NEWLIB_NANO_COMPAT_FORMAT")"),
|
||||||
length, sizeof(r->uri));
|
NEWLIB_NANO_COMPAT_CAST(length), NEWLIB_NANO_COMPAT_CAST(sizeof(r->uri)));
|
||||||
parser_data->error = HTTPD_414_URI_TOO_LONG;
|
parser_data->error = HTTPD_414_URI_TOO_LONG;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -126,12 +131,12 @@ static esp_err_t cb_url(http_parser *parser,
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("processing url = %.*s"), length, at);
|
ESP_LOGD(TAG, LOG_FMT("processing url = %.*s"), (int)length, at);
|
||||||
|
|
||||||
/* Update length of URL string */
|
/* Update length of URL string */
|
||||||
if ((parser_data->last.length += length) > HTTPD_MAX_URI_LEN) {
|
if ((parser_data->last.length += length) > HTTPD_MAX_URI_LEN) {
|
||||||
ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
|
ESP_LOGW(TAG, LOG_FMT("URI length (%"NEWLIB_NANO_COMPAT_FORMAT") greater than supported (%d)"),
|
||||||
parser_data->last.length, HTTPD_MAX_URI_LEN);
|
NEWLIB_NANO_COMPAT_CAST(parser_data->last.length), HTTPD_MAX_URI_LEN);
|
||||||
parser_data->error = HTTPD_414_URI_TOO_LONG;
|
parser_data->error = HTTPD_414_URI_TOO_LONG;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
@@ -149,7 +154,7 @@ static esp_err_t pause_parsing(http_parser *parser, const char* at)
|
|||||||
* and hence needs to be read again later for parsing */
|
* and hence needs to be read again later for parsing */
|
||||||
ssize_t unparsed = parser_data->raw_datalen - (at - ra->scratch);
|
ssize_t unparsed = parser_data->raw_datalen - (at - ra->scratch);
|
||||||
if (unparsed < 0) {
|
if (unparsed < 0) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("parsing beyond valid data = %d"), -unparsed);
|
ESP_LOGE(TAG, LOG_FMT("parsing beyond valid data = %d"), (int)(-unparsed));
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +162,7 @@ static esp_err_t pause_parsing(http_parser *parser, const char* at)
|
|||||||
* receiving again with httpd_recv_with_opt() later when
|
* receiving again with httpd_recv_with_opt() later when
|
||||||
* read_block() executes */
|
* read_block() executes */
|
||||||
if (unparsed && (unparsed != httpd_unrecv(r, at, unparsed))) {
|
if (unparsed && (unparsed != httpd_unrecv(r, at, unparsed))) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("data too large for un-recv = %d"), unparsed);
|
ESP_LOGE(TAG, LOG_FMT("data too large for un-recv = %d"), (int)unparsed);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +186,7 @@ static size_t continue_parsing(http_parser *parser, size_t length)
|
|||||||
* so we must skip that before parsing resumes */
|
* so we must skip that before parsing resumes */
|
||||||
length = MIN(length, data->pre_parsed);
|
length = MIN(length, data->pre_parsed);
|
||||||
data->pre_parsed -= length;
|
data->pre_parsed -= length;
|
||||||
ESP_LOGD(TAG, LOG_FMT("skip pre-parsed data of size = %d"), length);
|
ESP_LOGD(TAG, LOG_FMT("skip pre-parsed data of size = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(length));
|
||||||
|
|
||||||
http_parser_pause(parser, 0);
|
http_parser_pause(parser, 0);
|
||||||
data->paused = false;
|
data->paused = false;
|
||||||
@@ -241,7 +246,7 @@ static esp_err_t cb_header_field(http_parser *parser, const char *at, size_t len
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("processing field = %.*s"), length, at);
|
ESP_LOGD(TAG, LOG_FMT("processing field = %.*s"), (int)length, at);
|
||||||
|
|
||||||
/* Update length of header string */
|
/* Update length of header string */
|
||||||
parser_data->last.length += length;
|
parser_data->last.length += length;
|
||||||
@@ -285,7 +290,7 @@ static esp_err_t cb_header_value(http_parser *parser, const char *at, size_t len
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("processing value = %.*s"), length, at);
|
ESP_LOGD(TAG, LOG_FMT("processing value = %.*s"), (int)length, at);
|
||||||
|
|
||||||
/* Update length of header string */
|
/* Update length of header string */
|
||||||
parser_data->last.length += length;
|
parser_data->last.length += length;
|
||||||
@@ -366,7 +371,7 @@ static esp_err_t cb_headers_complete(http_parser *parser)
|
|||||||
parser->content_length : 0);
|
parser->content_length : 0);
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("bytes read = %" PRId32 ""), parser->nread);
|
ESP_LOGD(TAG, LOG_FMT("bytes read = %" PRId32 ""), parser->nread);
|
||||||
ESP_LOGD(TAG, LOG_FMT("content length = %zu"), r->content_len);
|
ESP_LOGD(TAG, LOG_FMT("content length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(r->content_len));
|
||||||
|
|
||||||
/* Handle upgrade requests - only WebSocket is supported for now */
|
/* Handle upgrade requests - only WebSocket is supported for now */
|
||||||
if (parser->upgrade) {
|
if (parser->upgrade) {
|
||||||
@@ -582,14 +587,14 @@ static int parse_block(http_parser *parser, size_t offset, size_t length)
|
|||||||
/* http_parser error */
|
/* http_parser error */
|
||||||
data->error = HTTPD_400_BAD_REQUEST;
|
data->error = HTTPD_400_BAD_REQUEST;
|
||||||
data->status = PARSING_FAILED;
|
data->status = PARSING_FAILED;
|
||||||
ESP_LOGW(TAG, LOG_FMT("incomplete (%d/%d) with parser error = %d"),
|
ESP_LOGW(TAG, LOG_FMT("incomplete (%"NEWLIB_NANO_COMPAT_FORMAT"/%"NEWLIB_NANO_COMPAT_FORMAT") with parser error = %d"),
|
||||||
nparsed, length, parser->http_errno);
|
NEWLIB_NANO_COMPAT_CAST(nparsed), NEWLIB_NANO_COMPAT_CAST(length), parser->http_errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return with the total length of the request packet
|
/* Return with the total length of the request packet
|
||||||
* that has been parsed till now */
|
* that has been parsed till now */
|
||||||
ESP_LOGD(TAG, LOG_FMT("parsed block size = %d"), offset + nparsed);
|
ESP_LOGD(TAG, LOG_FMT("parsed block size = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST((offset + nparsed)));
|
||||||
return offset + nparsed;
|
return offset + nparsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <esp_http_server.h>
|
#include <esp_http_server.h>
|
||||||
#include "esp_httpd_priv.h"
|
#include "esp_httpd_priv.h"
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
static const char *TAG = "httpd_txrx";
|
static const char *TAG = "httpd_txrx";
|
||||||
|
|
||||||
@@ -96,14 +97,14 @@ static size_t httpd_recv_pending(httpd_req_t *r, char *buf, size_t buf_len)
|
|||||||
|
|
||||||
int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_after_pending)
|
int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_after_pending)
|
||||||
{
|
{
|
||||||
ESP_LOGD(TAG, LOG_FMT("requested length = %d"), buf_len);
|
ESP_LOGD(TAG, LOG_FMT("requested length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(buf_len));
|
||||||
|
|
||||||
size_t pending_len = 0;
|
size_t pending_len = 0;
|
||||||
struct httpd_req_aux *ra = r->aux;
|
struct httpd_req_aux *ra = r->aux;
|
||||||
|
|
||||||
/* First fetch pending data from local buffer */
|
/* First fetch pending data from local buffer */
|
||||||
if (ra->sd->pending_len > 0) {
|
if (ra->sd->pending_len > 0) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("pending length = %d"), ra->sd->pending_len);
|
ESP_LOGD(TAG, LOG_FMT("pending length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(ra->sd->pending_len));
|
||||||
pending_len = httpd_recv_pending(r, buf, buf_len);
|
pending_len = httpd_recv_pending(r, buf, buf_len);
|
||||||
buf += pending_len;
|
buf += pending_len;
|
||||||
buf_len -= pending_len;
|
buf_len -= pending_len;
|
||||||
@@ -132,7 +133,7 @@ int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_aft
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret + pending_len);
|
ESP_LOGD(TAG, LOG_FMT("received length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST((ret + pending_len)));
|
||||||
return ret + pending_len;
|
return ret + pending_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +152,7 @@ size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len)
|
|||||||
* such that it is right aligned inside the buffer */
|
* such that it is right aligned inside the buffer */
|
||||||
size_t offset = sizeof(ra->sd->pending_data) - ra->sd->pending_len;
|
size_t offset = sizeof(ra->sd->pending_data) - ra->sd->pending_len;
|
||||||
memcpy(ra->sd->pending_data + offset, buf, ra->sd->pending_len);
|
memcpy(ra->sd->pending_data + offset, buf, ra->sd->pending_len);
|
||||||
ESP_LOGD(TAG, LOG_FMT("length = %d"), ra->sd->pending_len);
|
ESP_LOGD(TAG, LOG_FMT("length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(ra->sd->pending_len));
|
||||||
return ra->sd->pending_len;
|
return ra->sd->pending_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +361,7 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len
|
|||||||
|
|
||||||
/* Sending chunked content */
|
/* Sending chunked content */
|
||||||
char len_str[10];
|
char len_str[10];
|
||||||
snprintf(len_str, sizeof(len_str), "%x\r\n", buf_len);
|
snprintf(len_str, sizeof(len_str), "%lx\r\n", (long)buf_len);
|
||||||
if (httpd_send_all(r, len_str, strlen(len_str)) != ESP_OK) {
|
if (httpd_send_all(r, len_str, strlen(len_str)) != ESP_OK) {
|
||||||
return ESP_ERR_HTTPD_RESP_SEND;
|
return ESP_ERR_HTTPD_RESP_SEND;
|
||||||
}
|
}
|
||||||
@@ -529,7 +530,7 @@ int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct httpd_req_aux *ra = r->aux;
|
struct httpd_req_aux *ra = r->aux;
|
||||||
ESP_LOGD(TAG, LOG_FMT("remaining length = %d"), ra->remaining_len);
|
ESP_LOGD(TAG, LOG_FMT("remaining length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(ra->remaining_len));
|
||||||
|
|
||||||
if (buf_len > ra->remaining_len) {
|
if (buf_len > ra->remaining_len) {
|
||||||
buf_len = ra->remaining_len;
|
buf_len = ra->remaining_len;
|
||||||
|
@@ -153,7 +153,7 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor
|
|||||||
|
|
||||||
char subprotocol[50] = { '\0' };
|
char subprotocol[50] = { '\0' };
|
||||||
if (httpd_req_get_hdr_value_str(req, "Sec-WebSocket-Protocol", subprotocol, sizeof(subprotocol) - 1) == ESP_ERR_HTTPD_RESULT_TRUNC) {
|
if (httpd_req_get_hdr_value_str(req, "Sec-WebSocket-Protocol", subprotocol, sizeof(subprotocol) - 1) == ESP_ERR_HTTPD_RESULT_TRUNC) {
|
||||||
ESP_LOGW(TAG, "Sec-WebSocket-Protocol length exceeded buffer size of %d, was trunctated", sizeof(subprotocol));
|
ESP_LOGW(TAG, "Sec-WebSocket-Protocol length exceeded buffer size of %"NEWLIB_NANO_COMPAT_FORMAT", was trunctated", NEWLIB_NANO_COMPAT_CAST(sizeof(subprotocol)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor
|
|||||||
int r = snprintf(tx_buf + fmt_len, sizeof(tx_buf) - fmt_len, "Sec-WebSocket-Protocol: %s\r\n", supported_subprotocol);
|
int r = snprintf(tx_buf + fmt_len, sizeof(tx_buf) - fmt_len, "Sec-WebSocket-Protocol: %s\r\n", supported_subprotocol);
|
||||||
if (r <= 0) {
|
if (r <= 0) {
|
||||||
ESP_LOGE(TAG, "Error in response generation"
|
ESP_LOGE(TAG, "Error in response generation"
|
||||||
"(snprintf of subprotocol returned %d, buffer size: %d", r, sizeof(tx_buf));
|
"(snprintf of subprotocol returned %d, buffer size: %"NEWLIB_NANO_COMPAT_FORMAT, r, NEWLIB_NANO_COMPAT_CAST(sizeof(tx_buf)));
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor
|
|||||||
|
|
||||||
if (fmt_len >= sizeof(tx_buf)) {
|
if (fmt_len >= sizeof(tx_buf)) {
|
||||||
ESP_LOGE(TAG, "Error in response generation"
|
ESP_LOGE(TAG, "Error in response generation"
|
||||||
"(snprintf of subprotocol returned %d, desired response len: %d, buffer size: %d", r, fmt_len, sizeof(tx_buf));
|
"(snprintf of subprotocol returned %d, desired response len: %d, buffer size: %"NEWLIB_NANO_COMPAT_FORMAT, r, fmt_len, NEWLIB_NANO_COMPAT_CAST(sizeof(tx_buf)));
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,13 +191,13 @@ esp_err_t httpd_ws_respond_server_handshake(httpd_req_t *req, const char *suppor
|
|||||||
int r = snprintf(tx_buf + fmt_len, sizeof(tx_buf) - fmt_len, "\r\n");
|
int r = snprintf(tx_buf + fmt_len, sizeof(tx_buf) - fmt_len, "\r\n");
|
||||||
if (r <= 0) {
|
if (r <= 0) {
|
||||||
ESP_LOGE(TAG, "Error in response generation"
|
ESP_LOGE(TAG, "Error in response generation"
|
||||||
"(snprintf of subprotocol returned %d, buffer size: %d", r, sizeof(tx_buf));
|
"(snprintf of subprotocol returned %d, buffer size: %"NEWLIB_NANO_COMPAT_FORMAT, r, NEWLIB_NANO_COMPAT_CAST(sizeof(tx_buf)));
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
fmt_len += r;
|
fmt_len += r;
|
||||||
if (fmt_len >= sizeof(tx_buf)) {
|
if (fmt_len >= sizeof(tx_buf)) {
|
||||||
ESP_LOGE(TAG, "Error in response generation"
|
ESP_LOGE(TAG, "Error in response generation"
|
||||||
"(snprintf of header terminal returned %d, desired response len: %d, buffer size: %d", r, fmt_len, sizeof(tx_buf));
|
"(snprintf of header terminal returned %d, desired response len: %d, buffer size: %"NEWLIB_NANO_COMPAT_FORMAT, r, fmt_len, NEWLIB_NANO_COMPAT_CAST(sizeof(tx_buf)));
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +354,7 @@ esp_err_t httpd_ws_recv_frame(httpd_req_t *req, httpd_ws_frame_t *frame, size_t
|
|||||||
offset += read_len;
|
offset += read_len;
|
||||||
left_len -= read_len;
|
left_len -= read_len;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Frame length: %d, Bytes Read: %d", frame->len, offset);
|
ESP_LOGD(TAG, "Frame length: %"NEWLIB_NANO_COMPAT_FORMAT", Bytes Read: %"NEWLIB_NANO_COMPAT_FORMAT, NEWLIB_NANO_COMPAT_CAST(frame->len), NEWLIB_NANO_COMPAT_CAST(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unmask payload */
|
/* Unmask payload */
|
||||||
|
55
components/esp_http_server/src/port/linux/osal.h
Normal file
55
components/esp_http_server/src/port/linux/osal.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pthread.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)
|
||||||
|
{
|
||||||
|
pthread_attr_t thread_attr;
|
||||||
|
pthread_attr_init(&thread_attr);
|
||||||
|
pthread_attr_setstacksize(&thread_attr, stacksize);
|
||||||
|
int ret = pthread_create((pthread_t *)thread, &thread_attr, (void*)thread_routine, arg);
|
||||||
|
if (ret == 0) {
|
||||||
|
return OS_SUCCESS;
|
||||||
|
}
|
||||||
|
return OS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only self delete is supported */
|
||||||
|
static inline void httpd_os_thread_delete(void)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
pthread_exit((void *)&x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void httpd_os_thread_sleep(int msecs)
|
||||||
|
{
|
||||||
|
usleep(msecs * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline othread_t httpd_os_thread_handle(void)
|
||||||
|
{
|
||||||
|
return (othread_t)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@@ -10,9 +10,18 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#include "ctrl_sock.h"
|
#include "ctrl_sock.h"
|
||||||
|
|
||||||
|
#if CONFIG_IDF_TARGET_LINUX
|
||||||
|
#define IPV4_ENABLED 1
|
||||||
|
#define IPV6_ENABLED 1
|
||||||
|
#else // CONFIG_IDF_TARGET_LINUX
|
||||||
|
#define IPV4_ENABLED CONFIG_LWIP_IPV4
|
||||||
|
#define IPV6_ENABLED CONFIG_LWIP_IPV6
|
||||||
|
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||||
|
|
||||||
/* Control socket, because in some network stacks select can't be woken up any
|
/* Control socket, because in some network stacks select can't be woken up any
|
||||||
* other way
|
* other way
|
||||||
*/
|
*/
|
||||||
@@ -25,7 +34,7 @@ int cs_create_ctrl_sock(int port)
|
|||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
struct sockaddr_storage addr = {};
|
struct sockaddr_storage addr = {};
|
||||||
#ifdef CONFIG_LWIP_IPV4
|
#if IPV4_ENABLED
|
||||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
|
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
|
||||||
addr4->sin_family = AF_INET;
|
addr4->sin_family = AF_INET;
|
||||||
addr4->sin_port = htons(port);
|
addr4->sin_port = htons(port);
|
||||||
@@ -53,7 +62,7 @@ int cs_send_to_ctrl_sock(int send_fd, int port, void *data, unsigned int data_le
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct sockaddr_storage to_addr = {};
|
struct sockaddr_storage to_addr = {};
|
||||||
#ifdef CONFIG_LWIP_IPV4
|
#if IPV4_ENABLED
|
||||||
struct sockaddr_in *addr4 = (struct sockaddr_in *)&to_addr;
|
struct sockaddr_in *addr4 = (struct sockaddr_in *)&to_addr;
|
||||||
addr4->sin_family = AF_INET;
|
addr4->sin_family = AF_INET;
|
||||||
addr4->sin_port = htons(port);
|
addr4->sin_port = htons(port);
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
# (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
|
# (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
|
||||||
set(requires "")
|
set(requires "")
|
||||||
if(${IDF_TARGET} STREQUAL "linux")
|
if(${IDF_TARGET} STREQUAL "linux")
|
||||||
list(APPEND requires esp_stubs esp-tls esp_http_client protocol_examples_common)
|
list(APPEND requires esp_stubs esp-tls esp_http_client protocol_examples_common nvs_flash)
|
||||||
endif()
|
endif()
|
||||||
idf_component_register(SRCS "esp_http_client_example.c"
|
idf_component_register(SRCS "esp_http_client_example.c"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
|
@@ -2,9 +2,13 @@
|
|||||||
# in this exact order for cmake to work correctly
|
# in this exact order for cmake to work correctly
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
# (Not part of the boilerplate)
|
|
||||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
|
||||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||||
|
|
||||||
|
if(${IDF_TARGET} STREQUAL "linux")
|
||||||
|
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/"
|
||||||
|
"$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs")
|
||||||
|
set(COMPONENTS main)
|
||||||
|
endif()
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(simple)
|
project(simple)
|
||||||
|
@@ -1,2 +1,7 @@
|
|||||||
|
set(requires "")
|
||||||
|
if(${IDF_TARGET} STREQUAL "linux")
|
||||||
|
list(APPEND requires esp_stubs esp-tls esp_http_server protocol_examples_common nvs_flash)
|
||||||
|
endif()
|
||||||
idf_component_register(SRCS "main.c"
|
idf_component_register(SRCS "main.c"
|
||||||
INCLUDE_DIRS ".")
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES ${requires})
|
||||||
|
@@ -7,19 +7,27 @@
|
|||||||
CONDITIONS OF ANY KIND, either express or implied.
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <esp_wifi.h>
|
#include <string.h>
|
||||||
#include <esp_event.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <esp_system.h>
|
|
||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "esp_eth.h"
|
|
||||||
#include "protocol_examples_common.h"
|
#include "protocol_examples_common.h"
|
||||||
#include "protocol_examples_utils.h"
|
#include "protocol_examples_utils.h"
|
||||||
#include "esp_tls_crypto.h"
|
#include "esp_tls_crypto.h"
|
||||||
#include <esp_http_server.h>
|
#include <esp_http_server.h>
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_tls.h"
|
||||||
|
|
||||||
|
#if !CONFIG_IDF_TARGET_LINUX
|
||||||
|
#include <esp_wifi.h>
|
||||||
|
#include <esp_system.h>
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "esp_eth.h"
|
||||||
|
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||||
|
|
||||||
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
|
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
|
||||||
|
|
||||||
@@ -40,11 +48,16 @@ typedef struct {
|
|||||||
|
|
||||||
static char *http_auth_basic(const char *username, const char *password)
|
static char *http_auth_basic(const char *username, const char *password)
|
||||||
{
|
{
|
||||||
int out;
|
size_t out;
|
||||||
char *user_info = NULL;
|
char *user_info = NULL;
|
||||||
char *digest = NULL;
|
char *digest = NULL;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
asprintf(&user_info, "%s:%s", username, password);
|
int rc = asprintf(&user_info, "%s:%s", username, password);
|
||||||
|
if (rc < 0) {
|
||||||
|
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!user_info) {
|
if (!user_info) {
|
||||||
ESP_LOGE(TAG, "No enough memory for user information");
|
ESP_LOGE(TAG, "No enough memory for user information");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -58,7 +71,7 @@ static char *http_auth_basic(const char *username, const char *password)
|
|||||||
digest = calloc(1, 6 + n + 1);
|
digest = calloc(1, 6 + n + 1);
|
||||||
if (digest) {
|
if (digest) {
|
||||||
strcpy(digest, "Basic ");
|
strcpy(digest, "Basic ");
|
||||||
esp_crypto_base64_encode((unsigned char *)digest + 6, n, (size_t *)&out, (const unsigned char *)user_info, strlen(user_info));
|
esp_crypto_base64_encode((unsigned char *)digest + 6, n, &out, (const unsigned char *)user_info, strlen(user_info));
|
||||||
}
|
}
|
||||||
free(user_info);
|
free(user_info);
|
||||||
return digest;
|
return digest;
|
||||||
@@ -105,7 +118,12 @@ static esp_err_t basic_auth_get_handler(httpd_req_t *req)
|
|||||||
httpd_resp_set_status(req, HTTPD_200);
|
httpd_resp_set_status(req, HTTPD_200);
|
||||||
httpd_resp_set_type(req, "application/json");
|
httpd_resp_set_type(req, "application/json");
|
||||||
httpd_resp_set_hdr(req, "Connection", "keep-alive");
|
httpd_resp_set_hdr(req, "Connection", "keep-alive");
|
||||||
asprintf(&basic_auth_resp, "{\"authenticated\": true,\"user\": \"%s\"}", basic_auth_info->username);
|
int rc = asprintf(&basic_auth_resp, "{\"authenticated\": true,\"user\": \"%s\"}", basic_auth_info->username);
|
||||||
|
if (rc < 0) {
|
||||||
|
ESP_LOGE(TAG, "asprintf() returned: %d", rc);
|
||||||
|
free(auth_credentials);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
if (!basic_auth_resp) {
|
if (!basic_auth_resp) {
|
||||||
ESP_LOGE(TAG, "No enough memory for basic authorization response");
|
ESP_LOGE(TAG, "No enough memory for basic authorization response");
|
||||||
free(auth_credentials);
|
free(auth_credentials);
|
||||||
@@ -351,6 +369,13 @@ static httpd_handle_t start_webserver(void)
|
|||||||
{
|
{
|
||||||
httpd_handle_t server = NULL;
|
httpd_handle_t server = NULL;
|
||||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||||
|
#if CONFIG_IDF_TARGET_LINUX
|
||||||
|
// Setting port as 8001 when building for Linux. Port 80 can be used only by a priviliged user in linux.
|
||||||
|
// So when a unpriviliged user tries to run the application, it throws bind error and the server is not started.
|
||||||
|
// Port 8001 can be used by an unpriviliged user as well. So the application will not throw bind error and the
|
||||||
|
// server will be started.
|
||||||
|
config.server_port = 8001;
|
||||||
|
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||||
config.lru_purge_enable = true;
|
config.lru_purge_enable = true;
|
||||||
|
|
||||||
// Start the httpd server
|
// Start the httpd server
|
||||||
@@ -371,6 +396,7 @@ static httpd_handle_t start_webserver(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !CONFIG_IDF_TARGET_LINUX
|
||||||
static esp_err_t stop_webserver(httpd_handle_t server)
|
static esp_err_t stop_webserver(httpd_handle_t server)
|
||||||
{
|
{
|
||||||
// Stop the httpd server
|
// Stop the httpd server
|
||||||
@@ -400,7 +426,7 @@ static void connect_handler(void* arg, esp_event_base_t event_base,
|
|||||||
*server = start_webserver();
|
*server = start_webserver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
@@ -419,6 +445,7 @@ void app_main(void)
|
|||||||
/* Register event handlers to stop the server when Wi-Fi or Ethernet is disconnected,
|
/* Register event handlers to stop the server when Wi-Fi or Ethernet is disconnected,
|
||||||
* and re-start it upon connection.
|
* and re-start it upon connection.
|
||||||
*/
|
*/
|
||||||
|
#if !CONFIG_IDF_TARGET_LINUX
|
||||||
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
|
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
|
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
|
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
|
||||||
@@ -427,7 +454,12 @@ void app_main(void)
|
|||||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
|
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
|
||||||
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));
|
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));
|
||||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||||
|
#endif // !CONFIG_IDF_TARGET_LINUX
|
||||||
|
|
||||||
/* Start the server for the first time */
|
/* Start the server for the first time */
|
||||||
server = start_webserver();
|
server = start_webserver();
|
||||||
|
|
||||||
|
while (server) {
|
||||||
|
sleep(5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,12 +15,7 @@ esp_err_t esp_netif_init(void)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t nvs_flash_init(void)
|
esp_err_t example_connect(void)
|
||||||
{
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t nvs_flash_erase(void)
|
|
||||||
{
|
{
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
|
||||||
*/
|
|
||||||
#include "esp_err.h"
|
|
||||||
|
|
||||||
#define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */
|
|
||||||
#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */
|
|
||||||
#define ESP_ERR_NVS_NEW_VERSION_FOUND (ESP_ERR_NVS_BASE + 0x10) /*!< NVS partition contains data in new format and cannot be recognized by this version of code */
|
|
||||||
|
|
||||||
esp_err_t nvs_flash_init(void);
|
|
||||||
|
|
||||||
esp_err_t nvs_flash_erase(void);
|
|
@@ -1,5 +1,5 @@
|
|||||||
if(${IDF_TARGET} STREQUAL "linux")
|
if(${IDF_TARGET} STREQUAL "linux")
|
||||||
set(requires esp_stubs protocol_examples_common)
|
set(requires esp_stubs protocol_examples_common nvs_flash)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if("${CONFIG_EXAMPLE_IPV4}" STREQUAL y)
|
if("${CONFIG_EXAMPLE_IPV4}" STREQUAL y)
|
||||||
|
Reference in New Issue
Block a user