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:
Mahavir Jain
2023-04-03 16:48:19 +08:00
16 changed files with 199 additions and 68 deletions

View File

@@ -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()

View File

@@ -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" {

View File

@@ -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 */

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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 */

View 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

View File

@@ -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);

View File

@@ -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 "."

View File

@@ -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)

View File

@@ -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})

View File

@@ -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);
}
} }

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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)