Page 1 of 1

Captive portal not working

Posted: Wed Feb 23, 2022 4:34 pm
by ArnyminerZ
Hi, I've been trying to set up a captive portal in a ESP32 using the ESP-IDF framework.

I've used the example provided at https://github.com/espressif/esp-idf/tr ... ive_portal. My CMakeLists.txt is:
  1. idf_component_register(
  2.     SRCS "main.c" "dns_server.c"
  3.     INCLUDE_DIRS "../include" "../build/headers"
  4.     EMBED_FILES "../build/www/index.html" "../build/www/login.html" "../build/www/logout.html" "../build/www/reboot.html" "../build/www/scripts.js" "../build/www/styles.css"
  5. )
The build/headers and EMBED_FILES files are for providing the web server data.

Based on the contents of this page https://lemariva.com/blog/2017/11/white ... icropython I've developed:
  1. #pragma once
  2.  
  3. // Espressif functions
  4. #include <esp_err.h>
  5. #include <esp_http_server.h>
  6. #include <esp_log.h>
  7.  
  8. // Own utility functions
  9. #include "consts.h"
  10.  
  11.  
  12. // Microsoft NCSI
  13. static esp_err_t ms_ncsi_handler(httpd_req_t *req) {
  14.     ESP_LOGI(TAG, "Serving Microsoft's NCSI");
  15.     httpd_resp_set_status(req, "200 OK");
  16.     httpd_resp_send(req, "Microsoft NCSI", 14);
  17.     return ESP_OK;
  18. }
  19. static const httpd_uri_t ms_ncsi = {
  20.     .uri = "/ncsi.txt",
  21.     .method = HTTP_GET,
  22.     .handler = ms_ncsi_handler
  23. };
  24.  
  25. // Microsoft Connect Test
  26. static esp_err_t ms_conn_test_handler(httpd_req_t *req) {
  27.     ESP_LOGI(TAG, "Serving Microsoft's Connect Test");
  28.     httpd_resp_set_status(req, "200 OK");
  29.     httpd_resp_send(req, "Microsoft Connect Test", 14);
  30.     return ESP_OK;
  31. }
  32. static const httpd_uri_t ms_conn_test = {
  33.     .uri = "/connecttest.txt",
  34.     .method = HTTP_GET,
  35.     .handler = ms_conn_test_handler
  36. };
  37.  
  38. // Microsoft Redirect
  39. static esp_err_t ms_redirect_handler(httpd_req_t *req) {
  40.     ESP_LOGI(TAG, "Serving Microsoft's Redirect Test");
  41.     httpd_resp_set_status(req, "302 Redirect");
  42.     httpd_resp_send(req, "", 0);
  43.     return ESP_OK;
  44. }
  45. static const httpd_uri_t ms_redirect = {
  46.     .uri = "/redirect",
  47.     .method = HTTP_GET,
  48.     .handler = ms_redirect_handler
  49. };
  50.  
  51.  
  52. // Google Generate 204
  53. static esp_err_t goo_generate_204_handler(httpd_req_t *req) {
  54.     ESP_LOGI(TAG, "Serving Google's Generate 204");
  55.     // Answer 200 since we want to tell the device there's a captive portal
  56.     httpd_resp_set_status(req, "200 OK");
  57.     httpd_resp_send(req, "", 0);
  58.     return ESP_OK;
  59. }
  60. static const httpd_uri_t goo_generate_204 = {
  61.     .uri = "/generate_204",
  62.     .method = HTTP_GET,
  63.     .handler = goo_generate_204_handler
  64. };
  65.  
  66. // Google Gen 204
  67. static esp_err_t goo_gen_204_handler(httpd_req_t *req) {
  68.     ESP_LOGI(TAG, "Serving Google's Gen 204");
  69.     // Answer 302 redirection to the root for showing the captive portal
  70.     httpd_resp_set_status(req, "302 Location: /");
  71.     httpd_resp_send(req, "", 0);
  72.     return ESP_OK;
  73. }
  74. static const httpd_uri_t goo_gen_204 = {
  75.     .uri = "/gen_204",
  76.     .method = HTTP_GET,
  77.     .handler = goo_gen_204_handler
  78. };
  79.  
  80. // Apple hotspot detect
  81. static esp_err_t apple_hotspot_handler(httpd_req_t *req) {
  82.     ESP_LOGI(TAG, "Serving Google's Gen 204");
  83.     httpd_resp_set_status(req, "200 OK");
  84.     httpd_resp_send(req, "", 0);
  85.     return ESP_OK;
  86. }
  87. static const httpd_uri_t apple_hotspot = {
  88.     .uri = "/hotspot-detect.html",
  89.     .method = HTTP_GET,
  90.     .handler = apple_hotspot_handler
  91. };
And then in another file, I call this for initializing the HTTP server:

Code: Select all

static httpd_handle_t server_start(void)
{
#if CONFIG_LOG_ENABLE_SERVER != true
    // Disable logging for HTTP server
    esp_log_level_set("httpd_uri", ESP_LOG_ERROR);
    esp_log_level_set("httpd_txrx", ESP_LOG_ERROR);
    esp_log_level_set("httpd_parse", ESP_LOG_ERROR);
#endif

    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.max_open_sockets = 7;
    config.max_uri_handlers = 16;
    config.lru_purge_enable = true;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
    if (httpd_start(&server, &config) == ESP_OK)
    {
        // Set URI handlers
        ESP_LOGI(TAG, "Registering URI handlers...");
        register_uri_handlers(server);

        ESP_LOGI(TAG, "Registering URI spoofers...");
        httpd_register_uri_handler(server, &ms_ncsi);
        httpd_register_uri_handler(server, &ms_conn_test);
        httpd_register_uri_handler(server, &ms_redirect);
        httpd_register_uri_handler(server, &goo_generate_204);
        httpd_register_uri_handler(server, &goo_gen_204);
        httpd_register_uri_handler(server, &apple_hotspot);

        ESP_LOGI(TAG, "Registering error handlers...");
        httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler);
        return server;
    }

    ESP_LOGI(TAG, "Error starting server!");
    return NULL;
}
I've configured through menuconfig CONFIG_HTTPD_MAX_REQ_HDR_LEN to be 2048 and CONFIG_HTTPD_MAX_URI_LEN to 1024 since it was crashing for Chrome requests.

The ESP is configured to be running as AP, so my idea is to allow devices to connect to it, and then show a configuration page that allow the user to choose between the available networks. I know it's been made before, but haven't found anything I liked outside the Arduino framework.

My issue is that when I try to connect from my Android device, the captive portal opens, but after a second it closes, opens again, and closes definitely disconnecting from the network. Here are some logs:

Code: Select all

I (0) cpu_start: App cpu up.
I (425) cpu_start: Pro cpu start user code
I (425) cpu_start: cpu freq: 160000000
I (425) cpu_start: Application information:
I (429) cpu_start: Project name:     electronic_music_score
I (436) cpu_start: App version:      bd08132-dirty
I (441) cpu_start: Compile time:     Feb 23 2022 17:11:52
I (447) cpu_start: ELF file SHA256:  1147cea3a4860cd5...
I (453) cpu_start: ESP-IDF:          v4.4
I (458) heap_init: Initializing. RAM available for dynamic allocation:
I (465) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (471) heap_init: At 3FFB75A8 len 00028A58 (162 KiB): DRAM
I (478) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (484) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (490) heap_init: At 40094300 len 0000BD00 (47 KiB): IRAM
I (498) spi_flash: detected chip: generic
I (501) spi_flash: flash io: dio
I (506) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (516) emusic: Firmware: v1.0.0-SNAPSHOT
I (516) emusic: This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, 
I (526) emusic: silicon revision 1,
I (536) emusic: 4MB external flash
I (536) emusic: Minimum free heap size: 274384 bytes

I (546) emusic: Booting ...
I (546) emusic: Initializing outputs...
I (546) emusic: Turning on LED_BUILTIN...
I (556) emusic: Initializing NVS...
I (716) emusic: SPIFFS Free: 875.31 KB
I (716) emusic: SPIFFS Used: 0.00 B
I (726) emusic: SPIFFS Total: 875.31 KB
I (726) emusic: Starting Soft AP...
I (736) system_api: Base MAC address is not set
I (736) system_api: read default base MAC address from EFUSE
I (766) wifi_init: rx ba win: 6
I (766) wifi_init: tcpip mbox: 32
I (766) wifi_init: udp mbox: 6
I (766) wifi_init: tcp mbox: 6
I (766) wifi_init: tcp tx win: 5744
I (776) wifi_init: tcp rx win: 5744
I (776) wifi_init: tcp mss: 1440
I (776) wifi_init: WiFi IRAM OP enabled
I (786) wifi_init: WiFi RX IRAM OP enabled
W (796) emusic: Tried to get a non initialized value from NVS. Key: wifi-channel
I (796) emusic: Default WIFI AP channel not set. Setting to 1...
W (806) emusic: Tried to get a non initialized value from NVS. Key: wifi-conn
I (816) emusic: Default WIFI AP max connections not set. Setting to 4...
I (826) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (926) emusic: Initialized WiFi AP. SSID: , channel: 1
I (936) emusic: WiFi AP IP: 192.168.4.1
I (936) emusic: Configuring time...
W (936) emusic: Tried to get a non initialized value from NVS. Key: tz
I (946) emusic: Starting Webserver ...
I (946) emusic: Starting server on port: '80'
I (956) emusic: Registering URI handlers...
I (956) emusic: Registering URI spoofers...
I (966) emusic: Registering error handlers...
I (966) emusic: Starting DNS server...
I (976) emusic: Turning off LED_BUILTIN...
I (976) emusic: Socket created
I (976) emusic: Socket bound, port 53
I (20266) emusic: STA connected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (20666) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2
I (21036) emusic: Serving Google's Generate 204
I (21106) emusic: Serving Google's Gen 204
W (21266) httpd_uri: httpd_uri: URI '/chat' not found
I (21276) emusic: Redirecting to root
W (21276) httpd_parse: parse_block: incomplete (0/123) with parser error = 16
W (21276) httpd_txrx: httpd_resp_send_err: 400 Bad Request - Server unable to understand request due to invalid syntax
I (23646) emusic: Serving Google's Gen 204
W (23736) httpd_uri: httpd_uri: URI '/favicon.ico' not found
I (23736) emusic: Redirecting to root
I (23746) emusic: Serving Google's Generate 204
I (23776) emusic: Serving index.html
I (23846) emusic: Serving Google's Generate 204
I (23976) emusic: STA disconnected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (27416) emusic: STA connected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (27886) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2
I (28146) emusic: Serving Google's Generate 204
I (28226) emusic: Serving Google's Gen 204
W (28626) httpd_uri: httpd_uri: URI '/chat' not found
I (28636) emusic: Redirecting to root
W (28636) httpd_parse: parse_block: incomplete (0/123) with parser error = 16
W (28636) httpd_txrx: httpd_resp_send_err: 400 Bad Request - Server unable to understand request due to invalid syntax
I (31086) emusic: STA disconnected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (41786) emusic: STA connected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (42146) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2
I (42546) emusic: Serving Google's Generate 204
I (42626) emusic: Serving Google's Gen 204
I (43106) emusic: Serving Google's Generate 204
I (43226) emusic: Serving Google's Generate 204
I (44296) emusic: Serving Google's Generate 204
I (44346) emusic: Serving Google's Generate 204
I (45136) emusic: Serving Google's Gen 204
W (45416) httpd_uri: httpd_uri: URI '/favicon.ico' not found
I (45416) emusic: STA disconnected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (45426) emusic: Redirecting to root
I (49056) emusic: STA connected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (49286) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2
I (49526) emusic: Serving Google's Generate 204
I (49606) emusic: Serving Google's Gen 204
W (49886) httpd_txrx: httpd_sock_err: error in recv : 104
I (52456) emusic: STA disconnected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (57596) emusic: STA connected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (57726) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2
I (58186) emusic: Serving Google's Generate 204
I (58546) emusic: Serving Google's Gen 204
W (58636) httpd_uri: httpd_uri: URI '/chat' not found
I (58646) emusic: Redirecting to root
W (58646) httpd_parse: parse_block: incomplete (0/123) with parser error = 16
W (58646) httpd_txrx: httpd_resp_send_err: 400 Bad Request - Server unable to understand request due to invalid syntax
I (58676) emusic: Serving Google's Generate 204
I (58746) emusic: Serving Google's Generate 204
I (59826) emusic: Serving Google's Generate 204
I (59956) emusic: Serving Google's Gen 204
I (59966) emusic: Serving Google's Gen 204
W (60096) httpd_uri: httpd_uri: URI '/favicon.ico' not found
I (60106) emusic: Redirecting to root
I (60116) emusic: Serving Google's Generate 204
I (60166) emusic: Serving index.html
I (60176) emusic: Serving Google's Generate 204
I (60976) emusic: STA disconnected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (64366) emusic: STA connected. Mac: 26:cf:20:be:b8:b1, AID: 1
I (64556) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2
I (64816) emusic: Serving Google's Generate 204
I (64856) emusic: Serving Google's Gen 204
W (65166) httpd_uri: httpd_uri: URI '/chat' not found
I (65176) emusic: Redirecting to root
W (65176) httpd_parse: parse_block: incomplete (0/123) with parser error = 16
W (65176) httpd_txrx: httpd_resp_send_err: 400 Bad Request - Server unable to understand request due to invalid syntax
I (65206) emusic: Serving Google's Generate 204
I (65266) emusic: Serving Google's Generate 204
I (66336) emusic: Serving Google's Generate 204
I (66366) emusic: Serving Google's Generate 204
I (67116) emusic: Serving Google's Gen 204
W (67196) httpd_uri: httpd_uri: URI '/favicon.ico' not found
I (67196) emusic: Redirecting to root
I (67216) emusic: Serving index.html
I (67806) emusic: STA disconnected. Mac: 26:cf:20:be:b8:b1, AID: 1
I believe the main issue comes here:

Code: Select all

W (65176) httpd_parse: parse_block: incomplete (0/123) with parser error = 16
W (65176) httpd_txrx: httpd_resp_send_err: 400 Bad Request - Server unable to understand request due to invalid syntax
Hope you can help me out, and thanks in advance.

Re: Captive portal not working

Posted: Mon May 02, 2022 7:35 am
by bennyslbs
I don't have the same issue, when using the example in <ESP_IDF v. 4.4.1>/examples/protocols/http_server/captive_portal but I have seen when not finishing sending data, but just

Code: Select all

httpd_resp_sendstr_chunk(...)
and no final

Code: Select all

httpd_resp_sendstr(...)
then I get the same behaviour on the "Sign in to <AP-name>" page. Loading the same page in a browser have a small progress bar in top, telling that the page have not been fully loaded.