Help with TLS Socket Creation on Thingy53 - ENOMEM (Error 23)

I'm working on a Thingy53 project with Zephyr RTOS that requires TLS connections, but I'm encountering persistent "Failed to create TLS socket: 23" errors (ENOMEM - out of memory). I've implemented several memory optimizations and error handling strategies but still face issues with TLS socket creation.

  1. Initial Problem Identification

    • Thingy53 device experiencing ENOMEM errors during TLS socket creation
    • Memory allocation test function using undefined k_malloc_free_get
  2. Configuration Optimization

    • Consolidated duplicate definitions in prj.conf
    • Increased heap memory (CONFIG_HEAP_MEM_POOL_SIZE=180000)
    • Increased mbedTLS heap (CONFIG_MBEDTLS_HEAP_SIZE=80000)
    • Restored GPIO and WiFi management configurations
  3. TLS Cipher Configuration Issues

    • Identified problematic CONFIG_MBEDTLS_SSL_CIPHERSUITES configuration
    • Attempted various syntax fixes (removing quotes, escaping quotes)
    • Ultimately removed the problematic configuration to allow builds to proceed
  4. First Socket Implementation Approach

    • Tried incremental approach: TCP socket → Connect → TLS upgrade
    • Failed with ENOBUFS (error 109) when setting TLS_SEC_TAG_LIST
  5. Second Socket Implementation Approach

    • Created TLS socket directly using IPPROTO_TLS_1_2
    • Set all TLS options before connecting
    • Eliminated socket reconfiguration to allow proper resource allocation
  6. Memory Management Improvements

    • Implemented socket tracking system to prevent resource leaks
    • Added retry mechanism with increasing delays
    • Added specific ENOMEM error handling with resource cleanup
    • Improved TLS configuration sequence (hostname before security tags)
  7. Current Status

    • Despite improvements, still encountering ENOMEM (error 23)
    • Memory allocation test succeeds but TLS socket creation fails
    • Implemented more aggressive resource management with k_yield() and socket tracking
static int create_tls_socket(const char *hostname, struct sockaddr_in *server_addr)
{
    int sock;
    int ret;
    int retry_count = 0;
    const int retry_delay_ms = 1000;
    
    /* Check memory status before attempting socket creation */
    check_memory_status("before TLS socket creation");
    
    /* We'll try a different approach if the previous one keeps failing with ENOMEM */
    while (retry_count < MAX_SOCKET_RETRIES) {
        /* First, ensure any previous socket resources are fully released */
        k_sleep(K_MSEC(retry_delay_ms));
        k_yield();  /* Allow other threads to run and potentially free resources */
        
        /* Create TLS socket */
        sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
        if (sock < 0) {
            if (errno == ENOMEM) {
                LOG_ERR("Failed to create TLS socket: Out of memory (ENOMEM)");
                /* Try to release memory by forcing a garbage collection */
                close_all_sockets();
                retry_count++;
                continue;
            } else {
                LOG_ERR("Failed to create TLS socket: %d", errno);
                retry_count++;
                continue;
            }
        }
        
        LOG_INF("TLS socket created successfully");
        track_socket(sock);
        
        /* Set TLS socket options */
        sec_tag_t sec_tag_list[] = {
            CA_CERT_TAG,
        };
        
        /* Set receive and send timeout to avoid blocking indefinitely */
        struct timeval timeout = {
            .tv_sec = 10,
            .tv_usec = 0,
        };
        
        ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
        if (ret < 0) {
            LOG_ERR("Failed to set socket receive timeout: %d", errno);
            close(sock);
            untrack_socket(sock);
            retry_count++;
            continue;
        }
        
        // [Additional socket option settings omitted for brevity]
        
        /* All options set successfully */
        LOG_INF("TLS socket configured successfully");
        return sock;
    }
    
    LOG_ERR("Failed to create TLS socket after %d attempts", MAX_SOCKET_RETRIES);
    return -ENOMEM;
}

I'm tracking sockets and cleaning them up:
void track_socket(int sock)
{
// Track socket for potential cleanup
}

void untrack_socket(int sock)
{
// Remove socket from tracking
}

void close_all_sockets(void)
{
// Close all tracked sockets to free resources
}

I've made the following memory optimizations in prj.conf:

Increase heap memory pool size

CONFIG_HEAP_MEM_POOL_SIZE=200000
CONFIG_HEAP_MEM_POOL_IGNORE_MIN=y

TLS Configuration

CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_BUILTIN=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=85000
CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=1536

Reduce TLS resource usage

CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=2
CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS=2
CONFIG_NET_CONTEXT_MAX_CONN=4

Are there additional memory optimizations I should be making for TLS on constrained devices like the Thingy53?
Could there be any memory leaks or resource allocation issues that I'm missing in my implementation?
Are there specific mbedTLS configurations I should be adjusting to reduce memory usage further?
Is there a way to debug exactly what's happening during TLS socket creation that's causing the ENOMEM error?
Should I be implementing a different approach for TLS on this device?

Parents
  • Hi

    Is there a reason you've reduced the CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS all the way to 2 here? And how many TLS sockets is your application trying to create here? Since you initially refer to the ENOMEM error, it seems like you're already within what the memory can handle now, but instead have restrained the TLS socket numbers too much. Please try increasing these configs:
    CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=2
    CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS=2
    CONFIG_NET_CONTEXT_MAX_CONN=4

    As well as possibly CONFIG_POSIX_MAX_FDS.

    It's also important that you properly close unused sockets when you're done with them to free up resources. The MBEDTLS_HEAP_SIZE seem more than sufficient, but I'll need more information on what exactly the application is supposed to do here to know more about exact numbers for your configs here.

    Best regards,

    Simon

  • I am trying to connect to Azure's text to speech API using Thingy53. I changed the code:
    ```c

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/net/socket.h>
    #include <zephyr/net/net_mgmt.h>
    #include <zephyr/net/net_event.h>
    #include <zephyr/net/net_if.h>
    #include <zephyr/net/wifi_mgmt.h>
    #include <zephyr/net/tls_credentials.h>
    #include <zephyr/net/dns_resolve.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/logging/log.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>

    /* Define Zephyr socket control flags */
    #ifndef ZSOCK_FCNTL_OPTS
    #define ZSOCK_F_GETFL 3
    #define ZSOCK_F_SETFL 4
    #define ZSOCK_O_NONBLOCK 0x800
    #else
    #define ZSOCK_F_GETFL F_GETFL
    #define ZSOCK_F_SETFL F_SETFL
    #define ZSOCK_O_NONBLOCK O_NONBLOCK
    #endif

    /* Debug level control - Only keep Azure and WiFi connection debug as requested */
    #define DEBUG_AZURE 1  /* Set to 1 to enable Azure debug, 0 to disable */
    #define DEBUG_WIFI_CONN 0  /* Set to 0 to disable WiFi connection debug */
    #define DEBUG_GENERAL 0  /* Set to 1 to enable general debug, 0 to disable */

    LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);

    /*
     * Copyright (c) 2022 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */

    /** @file
     * @brief WiFi station sample
     */

    #include <zephyr/drivers/gpio.h>

    #include <net/wifi_mgmt_ext.h>
    #include <net/wifi_ready.h>

    /* HTTP client includes */
    #include <zephyr/net/http/client.h>

    /* TLS credential includes */
    #include <zephyr/fs/fs.h>

    #if defined(CONFIG_BOARD_NRF7002DK_NRF7001_NRF5340_CPUAPP) || \
        defined(CONFIG_BOARD_NRF7002DK_NRF5340_CPUAPP)
    #include <zephyr/drivers/wifi/nrf_wifi/bus/qspi_if.h>
    #endif

    #include "net_private.h"
    #include "ca_certificate.h"

    #define WIFI_SHELL_MODULE "wifi"

    #define WIFI_SHELL_MGMT_EVENTS (NET_EVENT_WIFI_CONNECT_RESULT |     \
                    NET_EVENT_WIFI_DISCONNECT_RESULT)

    #define MAX_SSID_LEN        32
    #define STATUS_POLLING_MS   300

    /* 1000 msec = 1 sec */
    #define LED_SLEEP_TIME_MS   100

    /* The devicetree node identifier for the "led0" alias. */
    #define LED0_NODE DT_ALIAS(led0)
    /*
     * A build error on this line means your board is unsupported.
     * See the sample documentation for information on how to fix this.
     */
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

    static struct net_mgmt_event_callback wifi_shell_mgmt_cb;
    static struct net_mgmt_event_callback net_shell_mgmt_cb;

    #ifdef CONFIG_WIFI_READY_LIB
    static K_SEM_DEFINE(wifi_ready_state_changed_sem, 0, 1);
    static bool wifi_ready_status;
    #endif /* CONFIG_WIFI_READY_LIB */

    static struct {
        const struct shell *sh;
        union {
            struct {
                uint8_t connected   : 1;
                uint8_t connect_result  : 1;
                uint8_t disconnect_requested    : 1;
                uint8_t _unused     : 5;
            };
            uint8_t all;
        };
    } context;

    /* HTTP client defines */
    #define HTTP_PORT 80
    #define HTTPS_PORT 443
    #define MAX_RECV_BUF_LEN 512
    #define MAX_SOCKET_RETRIES 5  /* Maximum number of socket creation retries */
    #define MAX_WIFI_RECONNECT_ATTEMPTS 3
    #define WIFI_RECONNECT_DELAY_MS 5000
    #define SOCKET_CONNECT_TIMEOUT_SEC 15  /* Socket connection timeout in seconds */
    #define SOCKET_RECV_TIMEOUT_SEC 10     /* Socket receive timeout in seconds */
    #define SOCKET_SEND_TIMEOUT_SEC 10     /* Socket send timeout in seconds */
    #define MAX_TLS_FAILURES 5

    /* TLS socket timeout settings */
    #define TLS_SOCKET_CONNECT_TIMEOUT_SEC 30  /* Longer timeout for TLS */

    /* TLS certificate defines */
    #define CA_CERT_TAG 1
    #define SERVER_CERT_TAG 2
    #define PEER_VERIFY_REQUIRED 2

    /* TLS socket option defines - using Zephyr's definitions */
    /* Do not redefine TLS_PEER_VERIFY, use the one from socket.h */
    #define TLS_HOSTNAME_OPTION 2
    #define TLS_CIPHERSUITE_LIST_OPTION 3
    #define TLS_HANDSHAKE_TIMEOUT_MS_OPTION 4
    #define TLS_ERROR_OPTION 5

    /* TLS credentials management */
    static bool tls_credentials_added = false;

    static void cleanup_tls_credentials(void)
    {
        int ret;
       
        if (tls_credentials_added) {
            ret = tls_credential_delete(CA_CERT_TAG, TLS_CREDENTIAL_CA_CERTIFICATE);
            if (ret < 0 && ret != -ENOENT) {
                LOG_ERR("Failed to delete CA certificate: %d", ret);
            } else {
                LOG_INF("TLS credentials cleaned up");
                tls_credentials_added = false;
            }
        }
       
        /* Force memory cleanup */
        k_sleep(K_MSEC(100));
        k_yield();
    }

    static int setup_tls_credentials(void)
    {
        int ret = 0;
       
        /* If credentials are already added, no need to add again */
        if (tls_credentials_added) {
            return 0;
        }
       
        /* Add CA certificate */
        ret = tls_credential_add(CA_CERT_TAG, TLS_CREDENTIAL_CA_CERTIFICATE,
            azure_ca_certificate, sizeof(azure_ca_certificate));
        if (ret < 0) {
            LOG_ERR("Failed to add CA certificate: %d", ret);
            return ret;
        }
       
        LOG_INF("CA certificate added to TLS credentials");
        tls_credentials_added = true;
       
        return 0;
    }

    /* Global variables for socket tracking */
    #define MAX_TRACKED_SOCKETS 4
    static int active_sockets_array[MAX_TRACKED_SOCKETS] = {-1, -1, -1, -1};
    static K_MUTEX_DEFINE(socket_mutex);

    /* Socket health monitoring */
    static int consecutive_socket_failures = 0;
    #define MAX_CONSECUTIVE_FAILURES 3

    /* Global variables for TLS error tracking */
    static int tls_consecutive_failures = 0;

    /* Forward declarations */
    static void cleanup_tls_credentials(void);
    static void reconnect_work_handler(struct k_work *work);
    static K_WORK_DEFINE(reconnect_work, reconnect_work_handler);
    static void force_socket_cleanup(void);

    /* Socket tracking functions */
    static void track_socket(int sock)
    {
        if (sock < 0) {
            return;
        }

        k_mutex_lock(&socket_mutex, K_FOREVER);
       
        /* First check if socket is already tracked */
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            if (active_sockets_array[i] == sock) {
                k_mutex_unlock(&socket_mutex);
                return;
            }
        }
       
        /* Find an empty slot */
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            if (active_sockets_array[i] < 0) {
                active_sockets_array[i] = sock;
                LOG_INF("Tracking socket %d in slot %d", sock, i);
                k_mutex_unlock(&socket_mutex);
                return;
            }
        }
       
        /* No empty slots, force cleanup and try again */
        LOG_WRN("No empty socket tracking slots, forcing cleanup");
        k_mutex_unlock(&socket_mutex);
        force_socket_cleanup();
       
        /* Try again after cleanup */
        k_mutex_lock(&socket_mutex, K_FOREVER);
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            if (active_sockets_array[i] < 0) {
                active_sockets_array[i] = sock;
                LOG_INF("Tracking socket %d in slot %d after cleanup", sock, i);
                k_mutex_unlock(&socket_mutex);
                return;
            }
        }
       
        LOG_ERR("Failed to track socket %d, all slots full even after cleanup", sock);
        k_mutex_unlock(&socket_mutex);
    }

    static void untrack_socket(int sock)
    {
        if (sock < 0) {
            return;
        }

        k_mutex_lock(&socket_mutex, K_FOREVER);
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            if (active_sockets_array[i] == sock) {
                LOG_INF("Untracking socket %d from slot %d", sock, i);
                active_sockets_array[i] = -1;
                k_mutex_unlock(&socket_mutex);
                return;
            }
        }
        k_mutex_unlock(&socket_mutex);
        LOG_WRN("Socket %d was not being tracked", sock);
    }

    static void cleanup_unhealthy_sockets(void)
    {
        struct zsock_pollfd fds;
        int ret;
       
        LOG_INF("Checking for unhealthy sockets");
       
        k_mutex_lock(&socket_mutex, K_FOREVER);
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            int sock = active_sockets_array[i];
            if (sock >= 0) {
                /* Check if socket is still valid */
                fds.fd = sock;
                fds.events = ZSOCK_POLLIN;
                ret = zsock_poll(&fds, 1, 0);
               
                if (ret < 0 || (fds.revents & (ZSOCK_POLLERR | ZSOCK_POLLHUP | ZSOCK_POLLNVAL))) {
                    LOG_WRN("Socket %d appears unhealthy (poll result: %d, revents: 0x%x), closing",
                            sock, ret, fds.revents);
                    close(sock);
                    active_sockets_array[i] = -1;
                }
            }
        }
        k_mutex_unlock(&socket_mutex);
    }

    static void close_all_sockets(void)
    {
        LOG_INF("Closing all tracked sockets");
       
        k_mutex_lock(&socket_mutex, K_FOREVER);
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            if (active_sockets_array[i] >= 0) {
                LOG_INF("Closing socket %d", active_sockets_array[i]);
                /* First try to gracefully shutdown the connection */
                zsock_shutdown(active_sockets_array[i], ZSOCK_SHUT_RDWR);
                /* Then close it */
                close(active_sockets_array[i]);
                active_sockets_array[i] = -1;
            }
        }
        k_mutex_unlock(&socket_mutex);
    }

    static void force_socket_cleanup(void)
    {
        int i;
        struct zsock_pollfd fds;
       
        LOG_INF("Performing forced socket cleanup");
       
        /* First check tracked sockets */
        k_mutex_lock(&socket_mutex, K_FOREVER);
        for (i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            if (active_sockets_array[i] >= 0) {
                LOG_WRN("Closing tracked socket %d", active_sockets_array[i]);
                zsock_shutdown(active_sockets_array[i], ZSOCK_SHUT_RDWR);
                close(active_sockets_array[i]);
                active_sockets_array[i] = -1;
            }
        }
        k_mutex_unlock(&socket_mutex);
       
        /* Then brute-force check common socket descriptor range */
        for (i = 0; i < CONFIG_POSIX_MAX_FDS; i++) {
            fds.fd = i;
            fds.events = ZSOCK_POLLIN;
            if (zsock_poll(&fds, 1, 0) >= 0 && !(fds.revents & ZSOCK_POLLNVAL)) {
                LOG_WRN("Force closing socket descriptor %d", i);
                zsock_shutdown(i, ZSOCK_SHUT_RDWR);
                close(i);
            }
        }
       
        /* Reset consecutive failures counter after cleanup */
        consecutive_socket_failures = 0;
    }

    static void recycle_system_resources(void)
    {
        LOG_INF("Recycling system resources to recover from potential resource exhaustion");
       
        /* Close all tracked sockets */
        close_all_sockets();
       
        /* Clean up TLS credentials */
        cleanup_tls_credentials();
       
        /* Force socket cleanup to catch any untracked sockets */
        force_socket_cleanup();
       
        /* Give the system time to free resources */
        k_sleep(K_MSEC(2000));
       
        /* Check WiFi connection and reconnect if needed */
        struct net_if *iface = net_if_get_default();
        struct wifi_iface_status status = { 0 };
       
        if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status, sizeof(status)) >= 0) {
            if (status.state < WIFI_STATE_ASSOCIATED) {
                LOG_WRN("WiFi disconnected during resource recycling, reconnecting");
                k_work_submit(&reconnect_work);
                k_sleep(K_MSEC(5000)); /* Wait for reconnection */
            }
        }
       
        /* Run garbage collection */
        k_yield();
       
        /* Reset consecutive failures counter */
        consecutive_socket_failures = 0;
    }

    /* HTTP client variables */
    static uint8_t recv_buf_ipv4[MAX_RECV_BUF_LEN];
    static int sock4 = -1;
    static struct sockaddr_in addr4;

    static bool connected;

    /* Track WiFi connection state */
    static bool wifi_connected = false;
    static bool wifi_reconnect_in_progress = false;

    /* Function declarations */
    static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb);
    static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb);
    static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
                         uint32_t mgmt_event, struct net_if *iface);
    static int connect_to_server(const char *hostname, const char *port_str, bool use_tls);
    static int disconnect_from_server(int sock);
    static int perform_http_get(int sock, const char *server, const char *path);
    static int get_azure_auth_token(void);
    static int start_app(void);

    /* Forward declarations */
    void net_mgmt_callback_init(void);

    void toggle_led(void)
    {
        int ret;

        if (!device_is_ready(led.port)) {
            LOG_ERR("LED device is not ready");
            return;
        }

        ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
        if (ret < 0) {
            LOG_ERR("Error %d: failed to configure LED pin", ret);
            return;
        }

        while (1) {
            if (context.connected) {
                gpio_pin_toggle_dt(&led);
                k_msleep(LED_SLEEP_TIME_MS);
            } else {
                gpio_pin_set_dt(&led, 0);
                k_msleep(LED_SLEEP_TIME_MS);
            }
        }
    }

    K_THREAD_DEFINE(led_thread_id, 1024, toggle_led, NULL, NULL, NULL,
            7, 0, 0);

    static int cmd_wifi_status(const struct shell *sh, size_t argc, char **argv)
    {
        struct net_if *iface = net_if_get_default();
        struct wifi_iface_status status = { 0 };

        if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, iface, &status,
                    sizeof(struct wifi_iface_status))) {
    #if DEBUG_GENERAL
            LOG_INF("Status request failed");
    #endif
            return -ENOEXEC;
        }

        /* Always show SSID and connection state regardless of debug level */
        LOG_INF("==================");
        LOG_INF("State: %s", wifi_state_txt(status.state));
       
        if (status.state >= WIFI_STATE_ASSOCIATED) {
            LOG_INF("SSID: %.32s", status.ssid);
        }

    #if DEBUG_WIFI_CONN
        if (status.state >= WIFI_STATE_ASSOCIATED) {
            uint8_t mac_string_buf[sizeof("xx:xx:xx:xx:xx:xx")];

            LOG_INF("Interface Mode: %s",
                   wifi_mode_txt(status.iface_mode));
            LOG_INF("Link Mode: %s",
                   wifi_link_mode_txt(status.link_mode));
            LOG_INF("BSSID: %s",
                   net_sprint_ll_addr_buf(
                    status.bssid, WIFI_MAC_ADDR_LEN,
                    mac_string_buf, sizeof(mac_string_buf)));
            LOG_INF("Band: %s", wifi_band_txt(status.band));
            LOG_INF("Channel: %d", status.channel);
            LOG_INF("Security: %s", wifi_security_txt(status.security));
            LOG_INF("MFP: %s", wifi_mfp_txt(status.mfp));
            LOG_INF("RSSI: %d", status.rssi);
        }
    #endif
        return 0;
    }

    static void handle_wifi_connect_result(struct net_mgmt_event_callback *cb)
    {
        const struct wifi_status *status =
            (const struct wifi_status *) cb->info;

        if (status->status) {
            LOG_ERR("Connection failed (%d)", status->status);
            context.connected = false;
            wifi_connected = false;
        } else {
            LOG_INF("Connected");
            context.connected = true;
            wifi_connected = true;
        }

        context.connect_result = true;
    }

    static void handle_wifi_disconnect_result(struct net_mgmt_event_callback *cb)
    {
        const struct wifi_status *status =
            (const struct wifi_status *) cb->info;
       
        if (status->status) {
            LOG_ERR("Connection request failed (%d)", status->status);
        } else {
            LOG_INF("Disconnected from WiFi");
            context.connected = false;
            wifi_connected = false;
           
            /* Close all active sockets when WiFi disconnects */
            close_all_sockets();
           
            /* Clean up TLS credentials */
            cleanup_tls_credentials();
           
            /* Schedule reconnection work */
            k_work_submit(&reconnect_work);
        }
       
        context.connect_result = true;  /* Use connect_result instead of disconnect_result */
    }

    static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
                         uint32_t mgmt_event, struct net_if *iface)
    {
        switch (mgmt_event) {
        case NET_EVENT_WIFI_CONNECT_RESULT:
            handle_wifi_connect_result(cb);
            break;
        case NET_EVENT_WIFI_DISCONNECT_RESULT:
            handle_wifi_disconnect_result(cb);
            break;
        default:
            break;
        }
    }

    static void print_dhcp_ip(struct net_mgmt_event_callback *cb)
    {
        struct net_if_dhcpv4 *dhcpv4 = (struct net_if_dhcpv4 *)cb->info;
       
        if (dhcpv4 && dhcpv4->state == NET_DHCPV4_BOUND) {
            LOG_INF("IPv4 address: %s", net_sprint_ipv4_addr(&dhcpv4->requested_ip));
            LOG_INF("Lease time: %u seconds", dhcpv4->lease_time);
            LOG_INF("Subnet: %s", net_sprint_ipv4_addr(&dhcpv4->netmask));
        }
    }

    static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb,
                        uint32_t mgmt_event, struct net_if *iface)
    {
        switch (mgmt_event) {
        case NET_EVENT_IPV4_DHCP_BOUND:
            print_dhcp_ip(cb);
            break;
        default:
            break;
        }
    }

    static int wifi_connect(void)
    {
        struct net_if *iface = net_if_get_first_wifi();

        context.connected = false;
        context.connect_result = false;

        if (net_mgmt(NET_REQUEST_WIFI_CONNECT_STORED, iface, NULL, 0)) {
            LOG_ERR("Connection request failed");

            return -ENOEXEC;
        }

        LOG_INF("Connection requested");

        return 0;
    }

    int bytes_from_str(const char *str, uint8_t *bytes, size_t bytes_len)
    {
        size_t i;
        char byte_str[3];

        if (strlen(str) != bytes_len * 2) {
            LOG_ERR("Invalid string length: %zu (expected: %d)\n",
                strlen(str), bytes_len * 2);
            return -EINVAL;
        }

        for (i = 0; i < bytes_len; i++) {
            memcpy(byte_str, str + i * 2, 2);
            byte_str[2] = '\0';
            bytes[i] = strtol(byte_str, NULL, 16);
        }

        return 0;
    }

    static void net_event_handler(struct net_mgmt_event_callback *cb,
                     uint32_t mgmt_event, struct net_if *iface)
    {
        if (mgmt_event == NET_EVENT_L4_CONNECTED) {
            LOG_INF("Connected");
        } else if (mgmt_event == NET_EVENT_L4_DISCONNECTED) {
            LOG_INF("Disconnected");
        }
    }

    static int reconnect_wifi(void)
    {
        int ret;
        int attempts = 0;
       
        if (wifi_reconnect_in_progress) {
            LOG_INF("WiFi reconnection already in progress");
            return 0;
        }
       
        wifi_reconnect_in_progress = true;
       
        while (attempts < MAX_WIFI_RECONNECT_ATTEMPTS && !context.connected) {
            LOG_INF("Attempting WiFi reconnection (%d/%d)...",
                attempts + 1, MAX_WIFI_RECONNECT_ATTEMPTS);
           
            /* Reset connection state */
            context.connected = false;
            context.connect_result = false;
           
            /* Request WiFi connection */
            ret = wifi_connect();
            if (ret) {
                LOG_ERR("Failed to request WiFi connection: %d", ret);
                attempts++;
                k_sleep(K_MSEC(WIFI_RECONNECT_DELAY_MS));
                continue;
            }
           
            /* Wait for connection result */
            int timeout_counter = 0;
            const int max_timeout = 15; // 15 seconds timeout
           
            while (!context.connect_result && timeout_counter < max_timeout) {
                k_sleep(K_MSEC(1000));
                timeout_counter++;
            }
           
            if (context.connected) {
                LOG_INF("WiFi reconnection successful");
                wifi_connected = true;
                wifi_reconnect_in_progress = false;
                return 0;
            }
           
            attempts++;
            k_sleep(K_MSEC(WIFI_RECONNECT_DELAY_MS));
        }
       
        LOG_ERR("Failed to reconnect to WiFi after %d attempts", attempts);
        wifi_reconnect_in_progress = false;
        return -ETIMEDOUT;
    }

    static int connect_to_server(const char *hostname, const char *port_str, bool use_tls)
    {
        int err;
        int sock;
        int retry_count = 0;
        int port;
        struct zsock_addrinfo hints = {0};
        struct zsock_addrinfo *result;
        struct zsock_addrinfo *addr;
        struct zsock_pollfd fds;
        int flags;
        int ret;
        bool is_connected = false;
        struct timeval timeout;
       
        /* Check if WiFi is connected before attempting socket operations */
        if (!context.connected) {
            LOG_ERR("WiFi not connected, cannot create socket");
            return -ENETUNREACH;
        }
       
        /* Convert port string to integer */
        port = atoi(port_str);
        if (port <= 0 || port > 65535) {
            LOG_ERR("Invalid port number: %s", port_str);
            return -EINVAL;
        }
       
        /* Clean up any unhealthy sockets before creating a new one */
        cleanup_unhealthy_sockets();
       
        /* Set up hints for getaddrinfo */
        hints.ai_family = AF_INET;  /* IPv4 only for now */
        hints.ai_socktype = SOCK_STREAM;
       
        /* Resolve the hostname */
        LOG_INF("Resolving hostname: %s", hostname);
        err = zsock_getaddrinfo(hostname, port_str, &hints, &result);
        if (err) {
            LOG_ERR("Failed to resolve hostname %s: %d", hostname, err);
            return -EHOSTUNREACH;
        }
       
        /* Try each address until we successfully connect */
        for (addr = result; addr != NULL; addr = addr->ai_next) {
            /* Create socket */
            retry_count = 0;
            while (retry_count < MAX_SOCKET_RETRIES) {
                sock = zsock_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
                if (sock < 0) {
                    LOG_ERR("Failed to create socket, attempt %d/%d: %d",
                            retry_count + 1, MAX_SOCKET_RETRIES, errno);
                    consecutive_socket_failures++;
                   
                    if (consecutive_socket_failures >= MAX_CONSECUTIVE_FAILURES) {
                        LOG_ERR("Too many consecutive socket failures, forcing cleanup");
                        force_socket_cleanup();
                    }
                   
                    retry_count++;
                    k_sleep(K_MSEC(500));  /* Wait before retrying */
                    continue;
                }
               
                /* Track the socket immediately after creation */
                track_socket(sock);
               
                /* Set socket options */
                /* Set SO_REUSEADDR option */
                int reuse = 1;
                ret = zsock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
                if (ret < 0) {
                    LOG_WRN("Failed to set SO_REUSEADDR: %d", errno);
                    /* Continue anyway, not critical */
                }
               
                /* Set receive timeout */
                timeout.tv_sec = SOCKET_RECV_TIMEOUT_SEC;
                timeout.tv_usec = 0;
                ret = zsock_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
                if (ret < 0) {
                    if (errno == ENOTSUP) {
                        LOG_WRN("Socket receive timeout not supported on this platform");
                    } else {
                        LOG_WRN("Failed to set receive timeout: %d", errno);
                    }
                    /* Continue anyway, not critical */
                }
               
                /* Set send timeout */
                timeout.tv_sec = SOCKET_SEND_TIMEOUT_SEC;
                timeout.tv_usec = 0;
                ret = zsock_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
                if (ret < 0) {
                    if (errno == ENOTSUP) {
                        LOG_WRN("Socket send timeout not supported on this platform");
                    } else {
                        LOG_WRN("Failed to set send timeout: %d", errno);
                    }
                    /* Continue anyway, not critical */
                }
               
                /* Set up TLS if requested */
                if (use_tls) {
                    /* Set up TLS credentials */
                    ret = setup_tls_credentials();
                    if (ret < 0) {
                        LOG_ERR("Failed to set up TLS credentials: %d", ret);
                        close(sock);
                        untrack_socket(sock);
                        zsock_freeaddrinfo(result);
                        return ret;
                    }
                   
                    /* Try with minimal TLS settings - just securely connect without strict verification */
                    LOG_INF("Proceeding with TLS connection with minimal verification");
                   
                    /* Skip setting TLS options if they're not supported */
                }
               
                /* Connect to server with timeout */
                LOG_INF("Connecting to %s:%s...", hostname, port_str);
               
                /* Set socket to non-blocking mode for connect with timeout */
                flags = zsock_fcntl(sock, ZSOCK_F_GETFL, 0);
                zsock_fcntl(sock, ZSOCK_F_SETFL, flags | ZSOCK_O_NONBLOCK);
               
                /* Initiate connection */
                ret = zsock_connect(sock, addr->ai_addr, addr->ai_addrlen);
                if (ret < 0 && errno != EINPROGRESS) {
                    LOG_ERR("Failed to initiate connection: %d", errno);
                    close(sock);
                    untrack_socket(sock);
                    retry_count++;
                    k_sleep(K_MSEC(500));  /* Wait before retrying */
                    continue;
                }
               
                /* Wait for connection to complete or timeout */
                fds.fd = sock;
                fds.events = ZSOCK_POLLOUT;
                int timeout_ms = use_tls ?
                    TLS_SOCKET_CONNECT_TIMEOUT_SEC * 1000 :
                    SOCKET_CONNECT_TIMEOUT_SEC * 1000;
               
                ret = zsock_poll(&fds, 1, timeout_ms);
                if (ret <= 0) {
                    if (ret == 0) {
                        LOG_ERR("Connection timed out");
                    } else {
                        LOG_ERR("Poll error: %d", errno);
                    }
                    close(sock);
                    untrack_socket(sock);
                    retry_count++;
                    k_sleep(K_MSEC(500));  /* Wait before retrying */
                    continue;
                }
               
                /* Check if connection was successful */
                if (fds.revents & ZSOCK_POLLOUT) {
                    /* Socket is writable, but we need to check for errors */
                    int err_code;
                    socklen_t err_len = sizeof(err_code);
                    ret = zsock_getsockopt(sock, SOL_SOCKET, SO_ERROR, &err_code, &err_len);
                    if (ret < 0 || err_code != 0) {
                        LOG_ERR("Connection failed with error: %d", err_code);
                        close(sock);
                        untrack_socket(sock);
                        retry_count++;
                        k_sleep(K_MSEC(500));  /* Wait before retrying */
                        continue;
                    }
                   
                    /* Connection successful */
                    is_connected = true;
                } else {
                    /* Socket has error condition */
                    LOG_ERR("Connection failed with revents: 0x%x", fds.revents);
                    close(sock);
                    untrack_socket(sock);
                    retry_count++;
                    k_sleep(K_MSEC(500));  /* Wait before retrying */
                    continue;
                }
               
                /* Set socket back to blocking mode */
                zsock_fcntl(sock, ZSOCK_F_SETFL, flags);
               
                /* If we got here, we successfully connected */
                if (is_connected) {
                    LOG_INF("Successfully connected to %s:%s", hostname, port_str);
                    consecutive_socket_failures = 0;  /* Reset failure counter on success */
                    zsock_freeaddrinfo(result);
                    return sock;
                }
            }
           
            /* If we've exhausted all retry attempts for this address, try the next one */
            LOG_WRN("Failed to connect using current address after %d attempts, trying next", MAX_SOCKET_RETRIES);
        }
       
        /* If we get here, we failed to connect to any address */
        zsock_freeaddrinfo(result);
        LOG_ERR("Failed to connect to %s:%s after trying all available addresses", hostname, port_str);
        return -ECONNREFUSED;
    }

    static int perform_http_get(int sock, const char *server, const char *path)
    {
        char http_request[256];
        int request_len;
        int sent;
        int total_sent = 0;
        int received;
        char recv_buf[1024];
        int ret = 0;
       
        /* Check WiFi connection before HTTP operation */
        if (!context.connected) {
            LOG_ERR("WiFi not connected before HTTP operation, attempting to reconnect");
            ret = reconnect_wifi();
            if (ret < 0) {
                LOG_ERR("Failed to reconnect WiFi: %d", ret);
                return ret;
            }
        }
       
        /* Formulate HTTP GET request */
        request_len = snprintf(http_request, sizeof(http_request),
                      "GET %s HTTP/1.1\r\n"
                      "Host: %s\r\n"
                      "Connection: close\r\n"
                      "\r\n",
                      path, server);
       
        if (request_len >= sizeof(http_request)) {
            LOG_ERR("HTTP request too large for buffer");
            return -ENOMEM;
        }
       
        /* Send HTTP request with timeout protection */
    #if DEBUG_AZURE
        LOG_INF("Sending HTTP GET request to %s%s", server, path);
    #endif
        int retry_count = 0;
        const int MAX_SEND_RETRIES = 3;
       
        do {
            /* Check WiFi connection before sending */
            if (!context.connected) {
                LOG_ERR("WiFi disconnected before HTTP send, attempting to reconnect");
                ret = reconnect_wifi();
                if (ret < 0) {
                    LOG_ERR("Failed to reconnect WiFi: %d", ret);
                    return ret;
                }
            }
           
            sent = zsock_send(sock, http_request + total_sent, request_len - total_sent, 0);
            if (sent < 0) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    /* Socket would block, wait and retry */
                    if (retry_count < MAX_SEND_RETRIES) {
                        LOG_WRN("Socket send would block, retrying (%d/%d)",
                            retry_count + 1, MAX_SEND_RETRIES);
                        k_sleep(K_MSEC(1000));
                        retry_count++;
                        continue;
                    } else {
                        LOG_ERR("Failed to send after %d retries", MAX_SEND_RETRIES);
                        return -ETIMEDOUT;
                    }
                } else {
                    LOG_ERR("Failed to send HTTP request: %d", errno);
                    return -errno;
                }
            }
            total_sent += sent;
        } while (total_sent < request_len);
       
        /* Receive HTTP response with timeout protection */
    #if DEBUG_AZURE
        LOG_INF("HTTP request sent, waiting for response...");
    #endif
       
        retry_count = 0;
        const int MAX_RECV_RETRIES = 5;
        bool response_complete = false;
       
        while (!response_complete) {
            /* Check WiFi connection before receiving */
            if (!context.connected) {
                LOG_ERR("WiFi disconnected during HTTP receive, attempting to reconnect");
                ret = reconnect_wifi();
                if (ret < 0) {
                    LOG_ERR("Failed to reconnect WiFi: %d", ret);
                    return ret;
                }
            }
           
            received = zsock_recv(sock, recv_buf, sizeof(recv_buf) - 1, 0);
            if (received < 0) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    /* Socket would block, wait and retry */
                    if (retry_count < MAX_RECV_RETRIES) {
                        LOG_WRN("Socket receive would block, retrying (%d/%d)",
                            retry_count + 1, MAX_RECV_RETRIES);
                        k_sleep(K_MSEC(1000));
                        retry_count++;
                        continue;
                    } else {
                        LOG_ERR("Failed to receive after %d retries", MAX_RECV_RETRIES);
                        return -ETIMEDOUT;
                    }
                } else {
                    LOG_ERR("Failed to receive HTTP response: %d", errno);
                    return -errno;
                }
            }
           
            if (received == 0) {
                /* Connection closed by server */
                response_complete = true;
                break;
            }
           
            /* Null-terminate the received data for printing */
            recv_buf[received] = 0;
    #if DEBUG_AZURE
            LOG_INF("%s", recv_buf);
    #endif
           
            /* Check for HTTP response code */
            if (strstr(recv_buf, "HTTP/1.1 200") != NULL ||
                strstr(recv_buf, "HTTP/1.0 200") != NULL) {
                /* 200 OK response */
                ret = 0;
            } else if (strstr(recv_buf, "HTTP/1.1 4") != NULL ||
                       strstr(recv_buf, "HTTP/1.0 4") != NULL) {
                /* 4xx Client Error */
                LOG_ERR("HTTP client error response");
                ret = -EBADMSG;
            } else if (strstr(recv_buf, "HTTP/1.1 5") != NULL ||
                       strstr(recv_buf, "HTTP/1.0 5") != NULL) {
                /* 5xx Server Error */
                LOG_ERR("HTTP server error response");
                ret = -EIO;  /* Using standard EIO instead of EREMOTEIO */
            }
        }
       
        /* Force memory cleanup after HTTP operations */
        k_sleep(K_MSEC(500));
        k_yield();
       
        return ret;
    }

    static int get_azure_auth_token(void)
    {
        int sock;
        int ret;
       
        LOG_INF("Getting Azure authentication token...");
        LOG_INF("Connecting to westeurope.api.cognitive.microsoft.com...");
       
        sock = connect_to_server("westeurope.api.cognitive.microsoft.com", "443", true);
        if (sock < 0) {
            LOG_ERR("Failed to connect to Azure server: %d", sock);
            return sock;
        }
       
        LOG_INF("Connected to Azure server, socket fd: %d", sock);
       
        /* Send HTTP request matching exactly your C code */
        char http_request[512];
        int request_len;
       
        /* Notice this matches your C implementation exactly */
        request_len = snprintf(http_request, sizeof(http_request),
            "POST /sts/v1.0/issuetoken HTTP/1.1\r\n"
            "Host: westeurope.api.cognitive.microsoft.com\r\n"
            "Ocp-Apim-Subscription-Key: %s\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n"
            "Content-Length: 0\r\n"
            "\r\n",
            "5Mkszj3yFl2vmbRDchDUHDAOMiZAYmzaLzA508JrnpRYYKBsv4nqJQQJ99BCAC5RqLJXJ3w3AAAYACOGVfQg");
       
        LOG_INF("Sending HTTP request to Azure authentication server");
       
        /* Send the request */
        int sent;
        int total_sent = 0;
       
        do {
            sent = zsock_send(sock, http_request + total_sent, request_len - total_sent, 0);
            if (sent < 0) {
                LOG_ERR("Failed to send HTTP request, err: %d", errno);
                disconnect_from_server(sock);
                return -errno;
            }
            total_sent += sent;
        } while (total_sent < request_len);
       
        LOG_INF("HTTP request sent: %d bytes", total_sent);
        LOG_INF("Waiting for HTTP response...");
       
        /* Receive HTTP response */
        char recv_buf[2048];
        int received;
        int total_received = 0;
       
        while (1) {
            received = zsock_recv(sock, recv_buf + total_received,
                                sizeof(recv_buf) - 1 - total_received, 0);
           
            if (received < 0) {
                if (errno == ECONNRESET) {
                    LOG_WRN("Connection reset by peer");
                    /* Break if we already received some data */
                    if (total_received > 0) {
                        break;
                    } else {
                        disconnect_from_server(sock);
                        return -EIO;
                    }
                } else {
                    LOG_ERR("Failed to receive HTTP response, err: %d", errno);
                    disconnect_from_server(sock);
                    return -errno;
                }
            } else if (received == 0) {
                /* Connection closed by server */
                LOG_INF("Connection closed by server");
                break;
            } else {
                total_received += received;
                recv_buf[total_received] = '\0';
               
                LOG_INF("Received %d bytes (total: %d)", received, total_received);
               
                /* Print the response for debugging */
                if (total_received > 0) {
                    LOG_INF("Response: %s", recv_buf);
                }
            }
        }
       
        /* Disconnect from server */
        disconnect_from_server(sock);
       
        if (total_received > 0) {
            LOG_INF("Azure authentication successful");
            return 0;
        } else {
            LOG_ERR("Azure authentication failed - no data received");
            return -EIO;
        }
    }

    static void reconnect_work_handler(struct k_work *work)
    {
        ARG_UNUSED(work);
       
        if (!context.connected && !wifi_reconnect_in_progress) {
            reconnect_wifi();
        }
    }

    static void wifi_status_thread(void *p1, void *p2, void *p3)
    {
        ARG_UNUSED(p1);
        ARG_UNUSED(p2);
        ARG_UNUSED(p3);
       
        int consecutive_disconnects = 0;
        const int MAX_CONSECUTIVE_DISCONNECTS = 5;
        int check_interval = 5; /* seconds */
       
        while (1) {
            k_sleep(K_SECONDS(check_interval));
           
            if (context.connected) {
                LOG_INF("WiFi State: CONNECTED");
                consecutive_disconnects = 0;
                check_interval = 5; /* Normal check interval when connected */
            } else {
                LOG_INF("WiFi State: DISCONNECTED");
                consecutive_disconnects++;
               
                if (consecutive_disconnects >= MAX_CONSECUTIVE_DISCONNECTS) {
                    LOG_ERR("Multiple consecutive disconnects detected (%d), forcing reconnection",
                        consecutive_disconnects);
                   
                    /* Close all sockets to free resources */
                    close_all_sockets();
                   
                    /* Clean up TLS credentials */
                    cleanup_tls_credentials();
                   
                    /* Force reconnection */
                    if (!wifi_reconnect_in_progress) {
                        reconnect_wifi();
                    }
                   
                    consecutive_disconnects = 0;
                }
               
                /* More frequent checks when disconnected */
                check_interval = 2;
            }
           
            /* Check for any socket leaks */
            int active_count = 0;
            k_mutex_lock(&socket_mutex, K_FOREVER);
            for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
                if (active_sockets_array[i] >= 0) {
                    active_count++;
                }
            }
            k_mutex_unlock(&socket_mutex);
           
            if (active_count > 0) {
                LOG_WRN("%d active sockets tracked", active_count);
            }
        }
    }

    K_THREAD_DEFINE(wifi_status_thread_id, 1024, wifi_status_thread, NULL, NULL, NULL,
            7, 0, 0);

    static int start_app(void)
    {
        int ret;

        LOG_INF("Starting application...");

        /* Initialize LED */
        if (!device_is_ready(led.port)) {
            LOG_ERR("LED device not ready");
            return -ENODEV;
        }

        ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
        if (ret < 0) {
            LOG_ERR("Failed to configure the LED pin, err: %d", ret);
            return ret;
        }

        /* Initialize net_mgmt callbacks */
        net_mgmt_callback_init();
       
        /* Initialize work queue for reconnection */
        k_work_init(&reconnect_work, reconnect_work_handler);

        /* Connect to WiFi network */
        ret = wifi_connect();
        if (ret) {
            LOG_ERR("Failed to connect to WiFi: %d", ret);
            return ret;
        }

        /* Wait for connection to complete */
        LOG_INF("Waiting for WiFi connection...");
        int timeout_counter = 0;
        const int max_timeout = 30; // 30 seconds timeout
       
        while (!context.connected && timeout_counter < max_timeout) {
            k_sleep(K_MSEC(1000));
            timeout_counter++;
            LOG_INF("Waiting for WiFi connection... %d/%d", timeout_counter, max_timeout);
        }
       
        if (!context.connected) {
            LOG_ERR("WiFi connection timed out after %d seconds", max_timeout);
            return -ETIMEDOUT;
        }
       
        wifi_connected = true;
       
        /* Wait a bit more to ensure DHCP is completed */
        LOG_INF("WiFi connected, waiting for DHCP...");
        k_sleep(K_SECONDS(3));
       
        /* Check WiFi status */
        cmd_wifi_status(context.sh, 0, NULL);
       
        /* Get Azure authentication token */
        ret = get_azure_auth_token();
        if (ret) {
            LOG_ERR("Azure authentication failed: %d", ret);
        } else {
            LOG_INF("Azure authentication completed successfully");
        }

        return 0;
    }

    #ifdef CONFIG_WIFI_READY_LIB
    void start_wifi_thread(void);
    #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
    K_THREAD_DEFINE(start_wifi_thread_id, CONFIG_STA_SAMPLE_START_WIFI_THREAD_STACK_SIZE,
            start_wifi_thread, NULL, NULL, NULL,
            THREAD_PRIORITY, 0, -1);

    void start_wifi_thread(void)
    {
        start_app();
    }

    void wifi_ready_cb(bool wifi_ready)
    {
        LOG_DBG("Is Wi-Fi ready?: %s", wifi_ready ? "yes" : "no");
        wifi_ready_status = wifi_ready;
        k_sem_give(&wifi_ready_state_changed_sem);
    }
    #endif /* CONFIG_WIFI_READY_LIB */

    void net_mgmt_callback_init(void)
    {
        memset(&context, 0, sizeof(context));

        net_mgmt_init_event_callback(&wifi_shell_mgmt_cb,
                         wifi_mgmt_event_handler,
                         WIFI_SHELL_MGMT_EVENTS);

        net_mgmt_add_event_callback(&wifi_shell_mgmt_cb);

        net_mgmt_init_event_callback(&net_shell_mgmt_cb,
                         net_mgmt_event_handler,
                         NET_EVENT_IPV4_DHCP_BOUND);

        net_mgmt_add_event_callback(&net_shell_mgmt_cb);

        LOG_INF("Starting %s with CPU frequency: %d MHz", CONFIG_BOARD, SystemCoreClock/MHZ(1));
        k_sleep(K_SECONDS(1));
    }

    #ifdef CONFIG_WIFI_READY_LIB
    static int register_wifi_ready(void)
    {
        int ret = 0;
        wifi_ready_callback_t cb;
        struct net_if *iface = net_if_get_first_wifi();

        if (!iface) {
            LOG_ERR("Failed to get Wi-Fi interface");
            return -1;
        }

        cb.wifi_ready_cb = wifi_ready_cb;

        LOG_DBG("Registering Wi-Fi ready callbacks");
        ret = register_wifi_ready_callback(cb, iface);
        if (ret) {
            LOG_ERR("Failed to register Wi-Fi ready callbacks %s", strerror(ret));
            return ret;
        }

        return ret;
    }
    #endif /* CONFIG_WIFI_READY_LIB */

    int main(void)
    {
        if (gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE) < 0) {
            LOG_ERR("Error: Failed to configure LED pin");
            return 0;
        }

        net_mgmt_callback_init();

    #ifdef CONFIG_WIFI_READY_LIB
        register_wifi_ready();
    #endif /* CONFIG_WIFI_READY_LIB */

        /* Initialize socket tracking array */
        for (int i = 0; i < MAX_TRACKED_SOCKETS; i++) {
            active_sockets_array[i] = -1;
        }

        start_app();
        return 0;
    }

    static int disconnect_from_server(int sock)
    {
        int ret;
       
        if (sock < 0) {
            LOG_WRN("Invalid socket handle %d, already disconnected", sock);
            return 0;
        }
       
        LOG_INF("Disconnecting from server, socket %d", sock);
       
        /* Untrack the socket before closing it */
        untrack_socket(sock);
       
        /* First try to gracefully shutdown the connection */
        ret = zsock_shutdown(sock, ZSOCK_SHUT_RDWR);
        if (ret < 0 && errno != ENOTCONN) {
            LOG_WRN("Socket shutdown failed: %d", errno);
            /* Continue with close anyway */
        }
       
        /* Close the socket */
        ret = close(sock);
        if (ret < 0) {
            LOG_ERR("Failed to close socket %d: %d", sock, errno);
            return -errno;
        }
       
        /* Verify socket is actually closed by attempting to get socket options */
        int error;
        socklen_t len = sizeof(error);
        ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len);
       
        if (ret == 0) {
            LOG_WRN("Socket %d appears to still be valid after close, forcing cleanup", sock);
            /* Socket is still valid, this shouldn't happen */
            force_socket_cleanup();
        } else {
            LOG_INF("Socket %d successfully closed", sock);
        }
       
        /* Add a small delay to allow system to free resources */
        k_sleep(K_MSEC(100));
       
        return 0;
    }
    ```

    And now I am getting this error:
    [00:00:11.878,631] <inf> main: State: COMPLETED
    [00:00:11.879,516] <inf> main: SSID: iPhone
    [00:00:11.880,310] <inf> main: Getting Azure authentication token...
    [00:00:11.881,408] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com...
    [00:00:11.882,476] <inf> main: Checking for unhealthy sockets
    [00:00:11.883,361] <inf> main: Resolving hostname: westeurope.api.cognitive.microsoft.com
    [00:00:12.005,920] <inf> main: Tracking socket 14 in slot 0
    [00:00:12.006,713] <wrn> main: Failed to set receive timeout: 109
    [00:00:12.007,751] <wrn> main: Failed to set send timeout: 109
    [00:00:12.008,728] <inf> main: CA certificate added to TLS credentials
    [00:00:12.009,735] <inf> main: Proceeding with TLS connection with minimal verification
    [00:00:12.010,864] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com:443...
    [00:00:12.112,976] <inf> main: Successfully connected to westeurope.api.cognitive.microsoft.com:443
    [00:00:12.114,349] <inf> main: Connected to Azure server, socket fd: 14
    [00:00:12.115,386] <inf> main: Sending HTTP request to Azure authentication server
    [00:00:12.117,279] <inf> main: HTTP request sent: 265 bytes
    [00:00:12.118,835] <inf> main: Waiting for HTTP response...
    [00:00:12.212,127] <wrn> main: Connection reset by peer
    [00:00:12.212,890] <inf> main: Disconnecting from server, socket 14
    [00:00:12.213,928] <inf> main: Untracking socket 14 from slot 0
    [00:00:12.214,935] <wrn> main: Socket shutdown failed: 134
    [00:00:12.216,033] <inf> main: Socket 14 successfully closed
    [00:00:12.317,047] <err> main: Azure authentication failed: -5
    [00:00:14.300,567] <inf> main: WiFi State: CONNECTED
  • [00:00:11.880,706] <inf> main: State: COMPLETED
    [00:00:11.881,622] <inf> main: SSID: iPhone
    [00:00:11.882,415] <inf> main: Getting Azure authentication token...
    [00:00:11.883,605] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com...
    [00:00:11.884,735] <inf> main: Checking for unhealthy sockets
    [00:00:11.885,528] <inf> main: Resolving hostname: westeurope.api.cognitive.microsoft.com
    [00:00:12.250,915] <inf> main: Tracking socket 14 in slot 0
    [00:00:12.251,770] <wrn> main: Failed to set receive timeout: 109
    [00:00:12.252,807] <wrn> main: Failed to set send timeout: 109
    [00:00:12.253,845] <inf> main: CA certificate added to TLS credentials
    [00:00:12.254,882] <err> main: Failed to set TLS peer verification option: 109
    [00:00:12.256,011] <err> main: Failed to set TLS hostname: 109
    [00:00:12.257,019] <err> main: Failed to set TLS handshake timeout: 109
    [00:00:12.258,209] <inf> main: Proceeding with TLS connection with minimal verification
    [00:00:12.259,307] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com:443...
    [00:00:12.368,499] <inf> main: Successfully connected to westeurope.api.cognitive.microsoft.com:443
    [00:00:12.369,903] <inf> main: Connected to Azure server, socket fd: 14
    [00:00:12.370,910] <inf> main: Sending HTTP request (284 bytes):
    [00:00:12.371,795] <inf> main: ------ BEGIN HTTP REQUEST ------
    [00:00:12.372,772] <inf> main: POST /sts/v1.0/issuetoken HTTP/1.1
    Host: westeurope.api.cognitive.microsoft.com
    Ocp-Apim-Subscription-Key: 5Mkszj3yFl2vmbRDchDUHDAOMiZAYmzaLzA508JrnpRYYKBsv4nqJQQJ99BCAC5RqLJXJ3w3AAAYACOGVfQg
    Content-Type: application/x-www-form-urlencoded
    Connection: close
    Content-Length: 0


    [00:00:12.375,671] <inf> main: ------ END HTTP REQUEST ------
    [00:00:12.377,777] <inf> main: HTTP request sent: 284 bytes
    [00:00:12.378,570] <inf> main: Waiting for HTTP response...
    [00:00:12.556,854] <wrn> main: Connection reset by peer
    [00:00:12.557,678] <err> main: Failed to get TLS error: 109
    [00:00:12.558,654] <inf> main: Disconnecting from server, socket 14
    [00:00:12.559,692] <inf> main: Untracking socket 14 from slot 0
    [00:00:12.560,729] <wrn> main: Socket shutdown failed: 134
    [00:00:12.561,859] <inf> main: Socket 14 successfully closed
    [00:00:12.662,933] <err> main: Azure authentication failed: -5
    [00:00:14.302,673] <inf> main: WiFi State: CONNECTED

  • Key Issues Observed

    1. TLS Configuration Errors

      • Several errors occur when setting up TLS options:

        • Failed to set TLS peer verification (Failed to set TLS peer verification option: 109).

        • Failed to set the hostname for TLS (Failed to set TLS hostname: 109).

        • Failed to set the TLS handshake timeout (Failed to set TLS handshake timeout: 109).

      • These indicate that the TLS configuration is incomplete or incorrect.

    2. Minimal Verification Proceeded

      • Despite the errors, the system proceeds with a "minimal verification" TLS connection. This is risky as it bypasses critical security checks, such as verifying the server's certificate.

    3. Connection Reset by Peer

      • After sending an HTTP request, the connection is reset by the server (Connection reset by peer). This could be due to:

        • The server rejecting the request because of improper TLS setup.

        • An issue with the HTTP request format or headers.

    4. Azure Authentication Failure

      • The final error (Azure authentication failed: -5) suggests that the authentication process did not complete successfully, likely due to the preceding issues

  • What I've done to fix the Azure authentication issue:

    I have inspected the Zephyr code which couldn't successfully complete Azure cognitive services authentication.
    I've compared it with your my curl-based C implementation that uses the same endpoint and API key.
    I have identified several issues:

    TLS socket options failing with error 109 (ENOTSUP)
    Possible HTTP request formatting issues
    Connection being reset by the server after sending the request

    I've tried multiple approaches:

    Fixed HTTP request formatting to match curl exactly
    Simplified TLS configuration
    Tried sending the HTTP headers and empty line separately
    Added more debugging

    Nothing did work.

    The latest log shows:

    ```
    [00:00:11.880,798] <inf> main: State: COMPLETED
    [00:00:11.881,774] <inf> main: SSID: iPhone
    [00:00:11.882,659] <inf> main: Getting Azure authentication token...
    [00:00:11.883,605] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com...
    [00:00:11.884,796] <inf> main: Checking for unhealthy sockets
    [00:00:11.885,589] <inf> main: Resolving hostname: westeurope.api.cognitive.microsoft.com
    [00:00:12.398,315] <inf> main: Tracking socket 14 in slot 0
    [00:00:12.399,139] <wrn> main: Failed to set receive timeout: 109
    [00:00:12.400,207] <wrn> main: Failed to set send timeout: 109
    [00:00:12.401,214] <inf> main: CA certificate added to TLS credentials
    [00:00:12.402,252] <inf> main: Proceeding with TLS connection
    [00:00:12.403,228] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com:443...
    [00:00:12.644,805] <inf> main: Successfully connected to westeurope.api.cognitive.microsoft.com:443
    [00:00:12.646,209] <inf> main: Connected to Azure server, socket fd: 14
    [00:00:12.647,186] <inf> main: Sending HTTP request (265 bytes):
    [00:00:12.648,101] <inf> main: ------ BEGIN HTTP REQUEST ------
    [00:00:12.649,078] <inf> main: POST /sts/v1.0/issuetoken HTTP/1.1
    Host: westeurope.api.cognitive.microsoft.com
    Ocp-Apim-Subscription-Key: 5Mkszj3yFl2vmbRDchDUHDAOMiZAYmzaLzA508JrnpRYYKBsv4nqJQQJ99BCAC5RqLJXJ3w3AAAYACOGVfQg
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 0
    [00:00:12.652,008] <inf> main: ------ END HTTP REQUEST ------
    [00:00:12.653,778] <inf> main: HTTP request sent: 265 bytes
    [00:00:12.654,724] <inf> main: Waiting for HTTP response...
    [00:00:12.759,216] <wrn> main: Connection reset by peer
    [00:00:12.760,009] <err> main: Failed to get TLS error: 109
    [00:00:12.760,986] <inf> main: Disconnecting from server, socket 14
    [00:00:12.762,054] <inf> main: Untracking socket 14 from slot 0
    [00:00:12.763,061] <wrn> main: Socket shutdown failed: 134
    [00:00:12.764,160] <inf> main: Socket 14 successfully closed
    [00:00:12.865,234] <err> main: Azure authentication failed: -5
    ```

    Current code

    ```c
    /* TLS configuration in connect_to_server */
    if (use_tls) {
    ret = setup_tls_credentials();
    if (ret < 0) {
    LOG_ERR("Failed to set up TLS credentials: %d", ret);
    close(sock);
    untrack_socket(sock);
    zsock_freeaddrinfo(result);
    return ret;
    }

    /* Set TLS options */
    int tls_options = TLS_PEER_VERIFY_REQUIRED;
    ret = zsock_setsockopt(sock, SOL_TLS, TLS_PEER_VERIFY, &tls_options, sizeof(tls_options));
    if (ret < 0) {
    LOG_ERR("Failed to set TLS peer verification: %d", errno);
    close(sock);
    untrack_socket(sock);
    zsock_freeaddrinfo(result);
    return -EIO;
    }

    /* Set TLS certificate */
    struct tls_credential cert = {
    .type = TLS_CREDENTIAL_CA_CERTIFICATE,
    .tag = CA_CERT_TAG
    };
    ret = zsock_setsockopt(sock, SOL_TLS, TLS_CREDENTIAL, &cert, sizeof(cert));
    if (ret < 0) {
    LOG_ERR("Failed to set TLS certificate: %d", errno);
    close(sock);
    untrack_socket(sock);
    zsock_freeaddrinfo(result);
    return -EIO;
    }

    LOG_INF("Proceeding with TLS connection");
    }
    ```

    ```c

    /* HTTP request sent in two parts in get_azure_auth_token */
    const char *http_headers =
    "POST /sts/v1.0/issuetoken HTTP/1.1\r\n"
    "Host: westeurope.api.cognitive.microsoft.com\r\n"
    "Ocp-Apim-Subscription-Key: 5Mkszj3yFl2vmbRDchDUHDAOMiZAYmzaLzA508JrnpRYYKBsv4nqJQQJ99BCAC5RqLJXJ3w3AAAYACOGVfQg\r\n"
    "Content-Type: application/x-www-form-urlencoded\r\n"
    "Content-Length: 0\r\n";

    /* Empty line to separate headers from body */
    const char *empty_line = "\r\n";

    /* Send headers first */
    int sent = zsock_send(sock, http_headers, headers_len, 0);

    /* Add small delay to ensure headers are processed */
    k_sleep(K_MSEC(100));

    /* Now send the empty line separately */
    sent = zsock_send(sock, empty_line, 2, 0);

    ```

    ```c

    /* print_tls_error_info function to debug TLS issues */
    void print_tls_error_info(int sock)
    {
    int err;
    socklen_t optlen = sizeof(err);

    if (getsockopt(sock, SOL_TLS, TLS_ERROR_OPTION, &err, &optlen) == 0) {
    LOG_ERR("TLS error code: %d", err);

    switch (err) {
    case MBEDTLS_ERR_SSL_CONN_RESET:
    LOG_ERR("Connection reset by peer");
    break;
    case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO:
    LOG_ERR("Bad server hello message");
    break;
    /* Other error cases... */
    }
    }
    }

    ```

Reply
  • What I've done to fix the Azure authentication issue:

    I have inspected the Zephyr code which couldn't successfully complete Azure cognitive services authentication.
    I've compared it with your my curl-based C implementation that uses the same endpoint and API key.
    I have identified several issues:

    TLS socket options failing with error 109 (ENOTSUP)
    Possible HTTP request formatting issues
    Connection being reset by the server after sending the request

    I've tried multiple approaches:

    Fixed HTTP request formatting to match curl exactly
    Simplified TLS configuration
    Tried sending the HTTP headers and empty line separately
    Added more debugging

    Nothing did work.

    The latest log shows:

    ```
    [00:00:11.880,798] <inf> main: State: COMPLETED
    [00:00:11.881,774] <inf> main: SSID: iPhone
    [00:00:11.882,659] <inf> main: Getting Azure authentication token...
    [00:00:11.883,605] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com...
    [00:00:11.884,796] <inf> main: Checking for unhealthy sockets
    [00:00:11.885,589] <inf> main: Resolving hostname: westeurope.api.cognitive.microsoft.com
    [00:00:12.398,315] <inf> main: Tracking socket 14 in slot 0
    [00:00:12.399,139] <wrn> main: Failed to set receive timeout: 109
    [00:00:12.400,207] <wrn> main: Failed to set send timeout: 109
    [00:00:12.401,214] <inf> main: CA certificate added to TLS credentials
    [00:00:12.402,252] <inf> main: Proceeding with TLS connection
    [00:00:12.403,228] <inf> main: Connecting to westeurope.api.cognitive.microsoft.com:443...
    [00:00:12.644,805] <inf> main: Successfully connected to westeurope.api.cognitive.microsoft.com:443
    [00:00:12.646,209] <inf> main: Connected to Azure server, socket fd: 14
    [00:00:12.647,186] <inf> main: Sending HTTP request (265 bytes):
    [00:00:12.648,101] <inf> main: ------ BEGIN HTTP REQUEST ------
    [00:00:12.649,078] <inf> main: POST /sts/v1.0/issuetoken HTTP/1.1
    Host: westeurope.api.cognitive.microsoft.com
    Ocp-Apim-Subscription-Key: 5Mkszj3yFl2vmbRDchDUHDAOMiZAYmzaLzA508JrnpRYYKBsv4nqJQQJ99BCAC5RqLJXJ3w3AAAYACOGVfQg
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 0
    [00:00:12.652,008] <inf> main: ------ END HTTP REQUEST ------
    [00:00:12.653,778] <inf> main: HTTP request sent: 265 bytes
    [00:00:12.654,724] <inf> main: Waiting for HTTP response...
    [00:00:12.759,216] <wrn> main: Connection reset by peer
    [00:00:12.760,009] <err> main: Failed to get TLS error: 109
    [00:00:12.760,986] <inf> main: Disconnecting from server, socket 14
    [00:00:12.762,054] <inf> main: Untracking socket 14 from slot 0
    [00:00:12.763,061] <wrn> main: Socket shutdown failed: 134
    [00:00:12.764,160] <inf> main: Socket 14 successfully closed
    [00:00:12.865,234] <err> main: Azure authentication failed: -5
    ```

    Current code

    ```c
    /* TLS configuration in connect_to_server */
    if (use_tls) {
    ret = setup_tls_credentials();
    if (ret < 0) {
    LOG_ERR("Failed to set up TLS credentials: %d", ret);
    close(sock);
    untrack_socket(sock);
    zsock_freeaddrinfo(result);
    return ret;
    }

    /* Set TLS options */
    int tls_options = TLS_PEER_VERIFY_REQUIRED;
    ret = zsock_setsockopt(sock, SOL_TLS, TLS_PEER_VERIFY, &tls_options, sizeof(tls_options));
    if (ret < 0) {
    LOG_ERR("Failed to set TLS peer verification: %d", errno);
    close(sock);
    untrack_socket(sock);
    zsock_freeaddrinfo(result);
    return -EIO;
    }

    /* Set TLS certificate */
    struct tls_credential cert = {
    .type = TLS_CREDENTIAL_CA_CERTIFICATE,
    .tag = CA_CERT_TAG
    };
    ret = zsock_setsockopt(sock, SOL_TLS, TLS_CREDENTIAL, &cert, sizeof(cert));
    if (ret < 0) {
    LOG_ERR("Failed to set TLS certificate: %d", errno);
    close(sock);
    untrack_socket(sock);
    zsock_freeaddrinfo(result);
    return -EIO;
    }

    LOG_INF("Proceeding with TLS connection");
    }
    ```

    ```c

    /* HTTP request sent in two parts in get_azure_auth_token */
    const char *http_headers =
    "POST /sts/v1.0/issuetoken HTTP/1.1\r\n"
    "Host: westeurope.api.cognitive.microsoft.com\r\n"
    "Ocp-Apim-Subscription-Key: 5Mkszj3yFl2vmbRDchDUHDAOMiZAYmzaLzA508JrnpRYYKBsv4nqJQQJ99BCAC5RqLJXJ3w3AAAYACOGVfQg\r\n"
    "Content-Type: application/x-www-form-urlencoded\r\n"
    "Content-Length: 0\r\n";

    /* Empty line to separate headers from body */
    const char *empty_line = "\r\n";

    /* Send headers first */
    int sent = zsock_send(sock, http_headers, headers_len, 0);

    /* Add small delay to ensure headers are processed */
    k_sleep(K_MSEC(100));

    /* Now send the empty line separately */
    sent = zsock_send(sock, empty_line, 2, 0);

    ```

    ```c

    /* print_tls_error_info function to debug TLS issues */
    void print_tls_error_info(int sock)
    {
    int err;
    socklen_t optlen = sizeof(err);

    if (getsockopt(sock, SOL_TLS, TLS_ERROR_OPTION, &err, &optlen) == 0) {
    LOG_ERR("TLS error code: %d", err);

    switch (err) {
    case MBEDTLS_ERR_SSL_CONN_RESET:
    LOG_ERR("Connection reset by peer");
    break;
    case MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO:
    LOG_ERR("Bad server hello message");
    break;
    /* Other error cases... */
    }
    }
    }

    ```

Children
No Data
Related