ctcpwifiesp32esp-idf

Make Connection Not Reset When STA Connects To a New Network


I am making a device that requires web interface and this is how I setup WiFi (inspired by my smart plug):

I have been running into an issue where the connection resets (httpd_txrx: httpd_sock_err: error in send : 113) when the STA successfully connect to a WiFi, if it doesn't, it works like normal. Is there anyway to fix this? Code for storing and responding the request:

esp_err_t connect_post_handler(httpd_req_t *req) 
{
    size_t size = req->content_len;
    if (size > 1024) {
        // too big
        const char* response = "Content too massive, but you know what else is massive?";
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, response);

        return ESP_OK;
    }

    char content[1024];

    int bytes_read = httpd_req_recv(req, content, size);
    if (bytes_read == 0) {
        // connection closed
        return ESP_ERR_HTTPD_INVALID_REQ;
    }

    cJSON* jsonData = cJSON_ParseWithLength(content, size);
    if (jsonData == NULL) {
        // json parsing failed, bad request
        const char* response = "Bad JSON format";
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, response);
        return ESP_OK;
    }
    char* ssid = cJSON_GetObjectItem(jsonData, "ssid")->valuestring;
    char* password = cJSON_GetObjectItem(jsonData, "password")->valuestring;
    reconnect_callback(ssid, password);
    httpd_req_async_handler_begin(req, &request); // <--- this!!!
    cJSON_Delete(jsonData);

    return ESP_OK;
}
void wifi_setup_handle_response(bool boolean, const char * response) 
{
    cJSON* response_data = cJSON_CreateObject();
    cJSON_AddBoolToObject(response_data, "success", boolean);
    cJSON_AddStringToObject(response_data, "message", response);
    

    char* response_string = cJSON_Print(response_data);

    printf(response_string);

    if (response_string == NULL) {
        // failed
        ESP_LOGE(LOG_TAG, "Could not write wifi connect response to string");
        httpd_resp_send_500(request);
        cJSON_Delete(response_data);
        return;
    }


    httpd_resp_send(request, response_string, strlen(response_string));
    httpd_req_async_handler_complete(request);

    free(response_string);
    cJSON_Delete(response_data);
}
httpd_req_t* request;

Is there a workaround for this by any chance or this is a bad way to setup or even use and I should use Bluetooth for setup (and use) instead of WiFi?


Solution

  • The device can't respond to the request once it's on a different network, because 1) the device now has a different IP address on the new network, and 2) the client isn't yet on the new WiFi network at all – it is only about to realize that the previous (device AP) network has disappeared, and 3) if the client were on the new WiFi network, it would also have a different IP address than what it had previously.

    If 113 means EHOSTUNREACH "No route to host" like it does on Linux, then it is caused mainly by 2) or 3), i.e. the device didn't receive an ARP response for the client's old IP address on the new network, because either the client isn't on the new network at all, or it doesn't have the old IP address anymore.

    You have to respond to the request first, close the TCP connection, and only then switch networks.

    Once both the device and the client switch to the new network, where addressing is in control of an existing router, the client will no longer be able to reach the hardcoded 6.6.6.6 address anymore, so the client has to discover the device using other means – e.g. mDNS/DNS-SD (preferably), or a custom UDP broadcast probe. And once you have that implemented, you should no longer need to have a hardcoded address for the initial configuration either, just have the client always discover the device using the same method.