Add a 'esp_https_server' component allowing to use http_server with OpenSSL

This commit is contained in:
Ondřej Hruška 2018-10-31 23:17:00 +01:00 committed by bot
parent a10fc02dd9
commit 4dd0fa61e9
15 changed files with 651 additions and 0 deletions

View File

@ -0,0 +1,7 @@
set(COMPONENT_ADD_INCLUDEDIRS include)
set(COMPONENT_SRCS "src/https_server.c")
set(COMPONENT_REQUIRES esp_http_server openssl)
set(COMPONENT_PRIV_REQUIRES lwip)
register_component()

View File

@ -0,0 +1,44 @@
# HTTPS server
This component is built on top of `esp_http_server`. The HTTPS server takes advantage of hooks and
function overrides in the regular HTTP server to provide encryption using OpenSSL.
All documentation for `esp_http_server` applies also to a server you create this way.
## Used APIs
The following API of `esp_http_server` should not be used with `esp_https_server`, as they are
used internally to handle secure sessions and to maintain internal state:
- "send", "receive" and "pending" function overrides - secure socket handling
- `httpd_set_sess_send_override()`
- `httpd_set_sess_recv_override()`
- `httpd_set_sess_pending_override()`
- `httpd_set_send_override()`
- `httpd_set_recv_override()`
- `httpd_set_pending_override()`
- "transport context" - both global and session
- `httpd_sess_get_transport_ctx()` - returns SSL used for the session
- `httpd_sess_set_transport_ctx()`
- `httpd_get_global_transport_ctx()` - returns the shared SSL context
- `httpd_config_t.global_transport_ctx`
- `httpd_config_t.global_transport_ctx_free_fn`
- `httpd_config_t.open_fn` - used to set up secure sockets
Everything else can be used without limitations.
## Usage
Please see the example `protocols/https_server` to learn how to set up a secure server.
Basically all you need is to generate a certificate, embed it in the firmware, and provide
its pointers and lengths to the start function via the init struct.
The server can be started with or without SSL by changing a flag in the init struct.
This could be used e.g. for testing or in trusted environments where you prefer speed over security.
## Performance
The initial session setup can take about two seconds, or more with slower clock speeds or more
verbose logging. Subsequent requests through the open secure socket are much faster (down to under
100 ms).

View File

@ -0,0 +1,2 @@
COMPONENT_SRCDIRS := src
COMPONENT_ADD_INCLUDEDIRS := include

View File

@ -0,0 +1,112 @@
// 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_HTTPS_SERVER_H_
#define _ESP_HTTPS_SERVER_H_
#include <stdbool.h>
#include "esp_err.h"
#include "esp_http_server.h"
/**
* HTTPS server config struct
*
* Please use HTTPD_SSL_CONFIG_DEFAULT() to initialize it.
*/
struct httpd_ssl_config {
/**
* Underlying HTTPD server config
*
* Parameters like task stack size and priority can be adjusted here.
*/
httpd_config_t httpd;
/** CA certificate */
const uint8_t *cacert_pem;
/** CA certificate byte length */
size_t cacert_len;
/** Private key */
const uint8_t *prvtkey_pem;
/** Private key byte length */
size_t prvtkey_len;
/** Enable SSL (default true) */
bool secure_enable;
/** Port used when SSL is enabled (default 443) */
uint16_t port_secure;
/** Port used when SSL is disabled (default 80) */
uint16_t port_insecure;
};
typedef struct httpd_ssl_config httpd_ssl_config_t;
/**
* Default config struct init
*
* (http_server default config had to be copied for customization)
*
* Notes:
* - port is set when starting the server, according to 'secure_enable'
* - one socket uses ~ 40kB RAM with SSL, we reduce the default socket count to 4
* - SSL sockets are usually long-lived, closing LRU prevents pool exhaustion DOS
* - Stack size may need adjustments depending on the user application
*/
#define HTTPD_SSL_CONFIG_DEFAULT() { \
.httpd = { \
.task_priority = tskIDLE_PRIORITY+5, \
.stack_size = 10240, \
.server_port = 0, \
.ctrl_port = 32768, \
.max_open_sockets = 4, \
.max_uri_handlers = 8, \
.max_resp_headers = 8, \
.backlog_conn = 5, \
.lru_purge_enable = true, \
.recv_wait_timeout = 5, \
.send_wait_timeout = 5, \
.global_user_ctx = NULL, \
.global_user_ctx_free_fn = NULL, \
.global_transport_ctx = NULL, \
.global_transport_ctx_free_fn = NULL, \
.open_fn = NULL, \
.close_fn = NULL, \
}, \
.secure_enable = true, \
.port_secure = 443, \
.port_insecure = 80, \
}
/**
* Create a SSL capable HTTP server (secure mode may be disabled in config)
*
* @param[in,out] config - server config, must not be const. Does not have to stay valid after
* calling this function.
* @param[out] handle - storage for the server handle, must be a valid pointer
* @return success
*/
esp_err_t httpd_ssl_start(httpd_handle_t *handle, httpd_ssl_config_t *config);
/**
* Stop the server. Blocks until the server is shut down.
*
* @param[in] handle
*/
void httpd_ssl_stop(httpd_handle_t handle);
#endif // _ESP_HTTPS_SERVER_H_

View File

@ -0,0 +1,220 @@
// 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 "esp_https_server.h"
#include "openssl/ssl.h"
#include "esp_log.h"
#include "sdkconfig.h"
const static char *TAG = "esp_https_server";
/**
* SSL socket close handler
*
* @param[in] ctx - session transport context (SSL context we stored there)
*/
static void httpd_ssl_close(void *ctx)
{
assert(ctx != NULL);
SSL_shutdown(ctx);
SSL_free(ctx);
ESP_LOGD(TAG, "Secure socket closed");
}
/**
* SSL socket pending-check function
*
* @param server
* @param sockfd
* @return number of pending bytes, negative on error
*/
static int httpd_ssl_pending(httpd_handle_t server, int sockfd)
{
SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
assert(ssl != NULL);
return SSL_pending(ssl);
}
/**
* Receive from a SSL socket
*
* @param server
* @param sockfd
* @param buf
* @param buf_len
* @param flags
* @return bytes read, negative on error
*/
static int httpd_ssl_recv(httpd_handle_t server, int sockfd, char *buf, size_t buf_len, int flags)
{
SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
assert(ssl != NULL);
return SSL_read(ssl, buf, buf_len);
}
/**
* Send to a SSL socket
*
* @param server
* @param sockfd
* @param buf
* @param buf_len
* @param flags
* @return bytes sent, negative on error
*/
static int httpd_ssl_send(httpd_handle_t server, int sockfd, const char *buf, size_t buf_len, int flags)
{
SSL *ssl = httpd_sess_get_transport_ctx(server, sockfd);
assert(ssl != NULL);
return SSL_write(ssl, buf, buf_len);
}
/**
* Open a SSL socket for the server.
* The fd is already open and ready to read / write raw data.
*
* @param server
* @param sockfd - raw socket fd
* @return success
*/
static esp_err_t httpd_ssl_open(httpd_handle_t server, int sockfd)
{
assert(server != NULL);
// Retrieve the SSL context from the global context field (set in config)
SSL_CTX *global_ctx = httpd_get_global_transport_ctx(server);
assert(global_ctx != NULL);
SSL *ssl = SSL_new(global_ctx);
if (NULL == ssl) {
ESP_LOGE(TAG, "SSL_new ret NULL (out of memory)");
return ESP_ERR_NO_MEM;
}
if (1 != SSL_set_fd(ssl, sockfd)) {
ESP_LOGE(TAG, "fail to set SSL fd");
goto teardown;
}
ESP_LOGD(TAG, "SSL accept");
if (1 != SSL_accept(ssl)) {
ESP_LOGW(TAG, "fail to SSL_accept - handshake error");
goto teardown;
}
// Store the SSL session into the context field of the HTTPD session object
httpd_sess_set_transport_ctx(server, sockfd, ssl, httpd_ssl_close);
// Set rx/tx/pending override functions
httpd_set_sess_send_override(server, sockfd, httpd_ssl_send);
httpd_set_sess_recv_override(server, sockfd, httpd_ssl_recv);
httpd_set_sess_pending_override(server, sockfd, httpd_ssl_pending);
// all access should now go through SSL
ESP_LOGD(TAG, "Secure socket open");
return ESP_OK;
teardown:
SSL_free(ssl);
return ESP_FAIL;
}
/**
* Tear down the HTTPD global transport context
*
* @param ctx
*/
static void free_secure_context(void *ctx)
{
assert(ctx != NULL);
ESP_LOGI(TAG, "Server shuts down, releasing SSL context");
SSL_CTX_free(ctx);
}
/**
* Create and perform basic init of a SSL_CTX, or return NULL on failure
*
* @return ctx or null
*/
static SSL_CTX *create_secure_context(const struct httpd_ssl_config *config)
{
SSL_CTX *ctx = NULL;
ESP_LOGD(TAG, "SSL server context create");
ctx = SSL_CTX_new(TLS_server_method());
if (NULL != ctx) {
//region SSL ctx alloc'd
ESP_LOGD(TAG, "SSL ctx set own cert");
if (SSL_CTX_use_certificate_ASN1(ctx, config->cacert_len, config->cacert_pem)
&& SSL_CTX_use_PrivateKey_ASN1(0, ctx, config->prvtkey_pem, (long) config->prvtkey_len)) {
return ctx;
}
else {
ESP_LOGE(TAG, "Failed to set certificate");
SSL_CTX_free(ctx);
ctx = NULL;
}
} else {
ESP_LOGE(TAG, "Failed to create SSL context");
}
return NULL;
}
/** Start the server */
esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *config)
{
assert(config != NULL);
assert(pHandle != NULL);
ESP_LOGI(TAG, "Starting server");
if (config->secure_enable) {
SSL_CTX *ctx = create_secure_context(config);
if (!ctx) {
return ESP_FAIL;
}
ESP_LOGD(TAG, "SSL context ready");
// set SSL specific config
config->httpd.global_transport_ctx = ctx;
config->httpd.global_transport_ctx_free_fn = free_secure_context;
config->httpd.open_fn = httpd_ssl_open; // the open function configures the created SSL sessions
config->httpd.server_port = config->port_secure;
} else {
ESP_LOGD(TAG, "SSL disabled, using plain HTTP");
config->httpd.server_port = config->port_insecure;
}
httpd_handle_t handle = NULL;
esp_err_t ret = httpd_start(&handle, &config->httpd);
if (ret != ESP_OK) return ret;
*pHandle = handle;
ESP_LOGI(TAG, "Server listening on port %d", config->httpd.server_port);
return ESP_OK;
}
/** Stop the server */
void httpd_ssl_stop(httpd_handle_t handle)
{
httpd_stop(handle);
}

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(https_server)

View File

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := https_server
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,15 @@
# HTTP server with SSL support using OpenSSL
This example creates a SSL server that returns a simple HTML page when you visit its root URL.
See the `esp_https_server` component documentation for details.
## Certificates
You will need to approve a security exception in your browser. This is because of a self signed
certificate; this will be always the case, unless you preload the CA root into your browser/system
as trusted.
You can generate a new certificate using the OpenSSL command line tool as shown in the script
`main/certs/gencert.sh`. It is **strongly recommended** to not reuse the example certificate in
your application; it is included only for demonstration.

View File

@ -0,0 +1,8 @@
set(COMPONENT_SRCS "main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
set(COMPONENT_EMBED_TXTFILES
"certs/cacert.pem"
"certs/prvtkey.pem")
register_component()

View File

@ -0,0 +1,16 @@
menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
endmenu

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL
BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx
MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ
UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T
sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k
qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd
GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4
sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb
jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/
ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3
emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY
W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx
bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN
ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl
hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=
-----END CERTIFICATE-----

View File

@ -0,0 +1,8 @@
#!/bin/bash
# Example command to generate a new certificate in the correct format.
# Expiry time and metadata fields can be adjusted in the invocation.
# Please see the openssl man pages (man openssl-req) for more details
openssl req -newkey rsa:2048 -nodes -keyout prvtkey.pem -x509 -days 3650 -out cacert.pem -subj "/CN=ESP32 HTTPS server example"

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH
JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw
h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT
aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al
3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg
0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB
vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui
f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9
Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y
JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX
49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc
+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6
pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D
0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG
YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV
MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL
CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin
7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1
noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8
4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g
Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/
nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3
q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2
lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB
jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr
v/t+MeGJP/0Zw8v/X2CFll96
-----END PRIVATE KEY-----

View File

@ -0,0 +1,7 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_EMBED_TXTFILES := certs/cacert.pem
COMPONENT_EMBED_TXTFILES += certs/prvtkey.pem

View File

@ -0,0 +1,150 @@
/* Simple HTTP + SSL Server Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <esp_wifi.h>
#include <esp_event_loop.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include <esp_https_server.h>
/* A simple example that demonstrates how to create GET and POST
* handlers for the web server.
* The examples use simple WiFi configuration that you can set via
* 'make menuconfig'.
* If you'd rather not, just change the below entries to strings
* with the config you want -
* ie. #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
static const char *TAG="APP";
/* An HTTP GET handler */
esp_err_t root_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, "<h1>Hello Secure World!</h1>", -1); // -1 = use strlen()
return ESP_OK;
}
const httpd_uri_t root = {
.uri = "/",
.method = HTTP_GET,
.handler = root_get_handler
};
httpd_handle_t start_webserver(void)
{
httpd_handle_t server = NULL;
// Start the httpd server
ESP_LOGI(TAG, "Starting server");
httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
conf.cacert_pem = cacert_pem_start;
conf.cacert_len = cacert_pem_end - cacert_pem_start;
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
conf.prvtkey_pem = prvtkey_pem_start;
conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
esp_err_t ret = httpd_ssl_start(&server, &conf);
if (ESP_OK != ret) {
ESP_LOGI(TAG, "Error starting server!");
return NULL;
}
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &root);
return server;
}
void stop_webserver(httpd_handle_t server)
{
// Stop the httpd server
httpd_ssl_stop(server);
}
// ------------------------- application boilerplate ------------------------
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
httpd_handle_t *server = (httpd_handle_t *) ctx;
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
ESP_ERROR_CHECK(esp_wifi_connect());
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
ESP_LOGI(TAG, "Got IP: '%s'",
ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
/* Start the web server */
if (*server == NULL) {
*server = start_webserver();
}
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
ESP_ERROR_CHECK(esp_wifi_connect());
/* Stop the web server */
if (*server) {
stop_webserver(*server);
*server = NULL;
}
break;
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void *arg)
{
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, arg));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
}
void app_main()
{
static httpd_handle_t server = NULL;
ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi(&server);
}