mirror of
				https://github.com/espressif/esp-protocols.git
				synced 2025-11-04 00:21:37 +01:00 
			
		
		
		
	feat(sockutls): Add initial support for socket helpers
This commit is contained in:
		
							
								
								
									
										17
									
								
								components/sock_utils/src/gai_strerror.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								components/sock_utils/src/gai_strerror.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include "gai_strerror.h"
 | 
			
		||||
 | 
			
		||||
_Thread_local char gai_strerror_string[32];
 | 
			
		||||
 | 
			
		||||
const char *gai_strerror(int ecode)
 | 
			
		||||
{
 | 
			
		||||
    if (snprintf(gai_strerror_string, sizeof(gai_strerror_string), "EAI error:%d", ecode) < 0) {
 | 
			
		||||
        return "gai_strerror() failed";
 | 
			
		||||
    }
 | 
			
		||||
    return gai_strerror_string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								components/sock_utils/src/getnameinfo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								components/sock_utils/src/getnameinfo.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include "lwip/sockets.h"
 | 
			
		||||
#include "lwip/netdb.h"
 | 
			
		||||
#include "ifaddrs.h"
 | 
			
		||||
#include "esp_check.h"
 | 
			
		||||
 | 
			
		||||
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
 | 
			
		||||
                char *host, socklen_t hostlen,
 | 
			
		||||
                char *serv, socklen_t servlen, int flags)
 | 
			
		||||
{
 | 
			
		||||
    // Validate flags to ensure only allowed flags are passed.
 | 
			
		||||
    if (flags & ~(NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM)) {
 | 
			
		||||
        return EAI_BADFLAGS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const struct sockaddr_in *sinp = (const struct sockaddr_in *) addr;
 | 
			
		||||
 | 
			
		||||
    switch (addr->sa_family) {
 | 
			
		||||
    case AF_INET:
 | 
			
		||||
        // Handle numeric host address
 | 
			
		||||
        if (flags & NI_NUMERICHOST) {
 | 
			
		||||
            if (host == NULL || hostlen == 0) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            if (inet_ntop(AF_INET, &sinp->sin_addr, host, hostlen) == NULL) {
 | 
			
		||||
                return EOVERFLOW;  // Error if address couldn't be converted
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Handle numeric service (port)
 | 
			
		||||
        if (flags & NI_NUMERICSERV) {
 | 
			
		||||
            // Print the port number, but for UDP services (if NI_DGRAM), we treat it the same way
 | 
			
		||||
            int port = ntohs(sinp->sin_port);  // Convert port from network byte order
 | 
			
		||||
            if (serv == NULL || servlen == 0) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            if (snprintf(serv, servlen, "%d", port) < 0) {
 | 
			
		||||
                return EOVERFLOW;  // Error if snprintf failed
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        return EAI_FAMILY;  // Unsupported address family
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								components/sock_utils/src/ifaddrs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								components/sock_utils/src/ifaddrs.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include "esp_netif.h"
 | 
			
		||||
#include "esp_check.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "ifaddrs.h"
 | 
			
		||||
 | 
			
		||||
static const char *TAG = "sockutls_getifaddr";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static esp_err_t getifaddrs_unsafe(void *ctx)
 | 
			
		||||
{
 | 
			
		||||
    struct ifaddrs **ifap = ctx;
 | 
			
		||||
    struct ifaddrs *ifaddr = NULL;
 | 
			
		||||
    struct ifaddrs **next_addr = NULL;
 | 
			
		||||
    struct sockaddr_in *addr_in = NULL;
 | 
			
		||||
    esp_netif_t *netif = NULL;
 | 
			
		||||
    char if_name[5];    // lwip netif name buffer (e.g. `st1`, 2 letters + number)
 | 
			
		||||
    esp_netif_ip_info_t ip;
 | 
			
		||||
    esp_err_t ret = ESP_OK;
 | 
			
		||||
 | 
			
		||||
    while ((netif = esp_netif_next_unsafe(netif)) != NULL) {
 | 
			
		||||
        ESP_GOTO_ON_FALSE((ifaddr = (struct ifaddrs *)calloc(1, sizeof(struct ifaddrs))),
 | 
			
		||||
                          ESP_ERR_NO_MEM, err, TAG, "Failed to allocate ifaddr");
 | 
			
		||||
        if (next_addr == NULL) {    // the first address -> attach the head
 | 
			
		||||
            *ifap = ifaddr;
 | 
			
		||||
        } else {
 | 
			
		||||
            *next_addr = ifaddr;    // attach next addr
 | 
			
		||||
        }
 | 
			
		||||
        ESP_GOTO_ON_ERROR(esp_netif_get_netif_impl_name(netif, if_name), err, TAG, "Failed to get netif name");
 | 
			
		||||
        ESP_GOTO_ON_FALSE((ifaddr->ifa_name = strdup(if_name)),
 | 
			
		||||
                          ESP_ERR_NO_MEM, err, TAG, "Failed to allocate if name");
 | 
			
		||||
        ESP_GOTO_ON_FALSE((addr_in = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in))),
 | 
			
		||||
                          ESP_ERR_NO_MEM, err, TAG, "Failed to allocate addr_in");
 | 
			
		||||
        ifaddr->ifa_addr = (struct sockaddr *)addr_in;
 | 
			
		||||
        ESP_GOTO_ON_ERROR(esp_netif_get_ip_info(netif, &ip), err, TAG, "Failed to get netif IP");
 | 
			
		||||
        ESP_LOGD(TAG, "IPv4 address: " IPSTR, IP2STR(&ip.ip));
 | 
			
		||||
        addr_in->sin_family = AF_INET;
 | 
			
		||||
        addr_in->sin_addr.s_addr = ip.ip.addr;
 | 
			
		||||
        ifaddr->ifa_flags = esp_netif_is_netif_up(netif) ? IFF_UP : 0;
 | 
			
		||||
        next_addr = &ifaddr->ifa_next;
 | 
			
		||||
    }
 | 
			
		||||
    if (next_addr == NULL) {
 | 
			
		||||
        *ifap = NULL;       // no addresses found
 | 
			
		||||
    } else {
 | 
			
		||||
        *next_addr = NULL;  // terminate the list
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
    if (next_addr) {
 | 
			
		||||
        *next_addr = NULL;
 | 
			
		||||
        freeifaddrs(*ifap);
 | 
			
		||||
    } else {
 | 
			
		||||
        freeifaddrs(ifaddr);
 | 
			
		||||
    }
 | 
			
		||||
    *ifap = NULL;
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int getifaddrs(struct ifaddrs **ifap)
 | 
			
		||||
{
 | 
			
		||||
    if (ifap == NULL) {
 | 
			
		||||
        errno = EINVAL;
 | 
			
		||||
        return -1; // Invalid argument
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    esp_err_t ret = esp_netif_tcpip_exec(getifaddrs_unsafe, ifap);
 | 
			
		||||
    switch (ret) {
 | 
			
		||||
    case ESP_OK:
 | 
			
		||||
        return 0;
 | 
			
		||||
    case ESP_ERR_NO_MEM:
 | 
			
		||||
        errno = ENOMEM;
 | 
			
		||||
        return -1;
 | 
			
		||||
    case ESP_ERR_INVALID_ARG:
 | 
			
		||||
    case ESP_ERR_ESP_NETIF_INVALID_PARAMS:
 | 
			
		||||
        errno = EINVAL;
 | 
			
		||||
        return -1;
 | 
			
		||||
    default:
 | 
			
		||||
    case ESP_FAIL:
 | 
			
		||||
        errno = EIO;    // Generic I/O Error
 | 
			
		||||
        return  -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void freeifaddrs(struct ifaddrs *ifa)
 | 
			
		||||
{
 | 
			
		||||
    while (ifa != NULL) {
 | 
			
		||||
        struct ifaddrs *next = ifa->ifa_next;
 | 
			
		||||
        free(ifa->ifa_name);
 | 
			
		||||
        free(ifa->ifa_addr);
 | 
			
		||||
        free(ifa);
 | 
			
		||||
        ifa = next;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										76
									
								
								components/sock_utils/src/socketpair.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								components/sock_utils/src/socketpair.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 */
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include "lwip/sockets.h"
 | 
			
		||||
#include "socketpair.h"
 | 
			
		||||
#include "esp_check.h"
 | 
			
		||||
 | 
			
		||||
#define INVALID_SOCKET (-1)
 | 
			
		||||
 | 
			
		||||
static const char *TAG = "socket_helpers";
 | 
			
		||||
 | 
			
		||||
int socketpair(int domain, int type, int protocol, int sv[2])
 | 
			
		||||
{
 | 
			
		||||
    if (protocol != 0 || type != SOCK_STREAM || domain != AF_UNIX) {
 | 
			
		||||
        errno = ENOSYS; // not implemented
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    struct sockaddr_storage ss;
 | 
			
		||||
    struct sockaddr_in *sa = (struct sockaddr_in *)&ss;
 | 
			
		||||
    socklen_t ss_len = sizeof(struct sockaddr_in);
 | 
			
		||||
    int fd1 = INVALID_SOCKET;
 | 
			
		||||
    int fd2 = INVALID_SOCKET;
 | 
			
		||||
    int listenfd = INVALID_SOCKET;
 | 
			
		||||
    int ret = 0; // Success
 | 
			
		||||
 | 
			
		||||
    sa->sin_family = AF_INET;
 | 
			
		||||
    sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 | 
			
		||||
    sa->sin_port = 0;
 | 
			
		||||
    listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 | 
			
		||||
    ESP_GOTO_ON_FALSE(listenfd != INVALID_SOCKET, -1, err, TAG, "Cannot create listening socket");
 | 
			
		||||
    ESP_GOTO_ON_FALSE(listen(listenfd, 1) == 0, -1, err, TAG, "Failed to listen");
 | 
			
		||||
 | 
			
		||||
    memset(&ss, 0, sizeof(ss));
 | 
			
		||||
    ss_len = sizeof(ss);
 | 
			
		||||
    ESP_GOTO_ON_FALSE(getsockname(listenfd, (struct sockaddr *)&ss, &ss_len) >= 0, -1, err, TAG, "getsockname failed");
 | 
			
		||||
 | 
			
		||||
    sa->sin_family = AF_INET;
 | 
			
		||||
    sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 | 
			
		||||
 | 
			
		||||
    fd1 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 | 
			
		||||
    ESP_GOTO_ON_FALSE(fd1 != INVALID_SOCKET, -1, err, TAG, "Cannot create read side socket");
 | 
			
		||||
    ESP_GOTO_ON_FALSE(connect(fd1, (struct sockaddr *)&ss, ss_len) >= 0, -1, err, TAG, "Failed to connect fd1");
 | 
			
		||||
    fd2 = accept(listenfd, NULL, 0);
 | 
			
		||||
    ESP_GOTO_ON_FALSE(fd2 != INVALID_SOCKET, -1, err, TAG, "Failed to accept fd2");
 | 
			
		||||
 | 
			
		||||
    close(listenfd);
 | 
			
		||||
    sv[0] = fd1;
 | 
			
		||||
    sv[1] = fd2;
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
    if (listenfd != INVALID_SOCKET) {
 | 
			
		||||
        close(listenfd);
 | 
			
		||||
    }
 | 
			
		||||
    if (fd1 != INVALID_SOCKET) {
 | 
			
		||||
        close(fd1);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pipe(int pipefd[2])
 | 
			
		||||
{
 | 
			
		||||
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd) == -1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    // Close the unwanted ends to make it a unidirectional pipe
 | 
			
		||||
    if (shutdown(pipefd[0], SHUT_WR) == -1 || shutdown(pipefd[1], SHUT_RD) == -1) {
 | 
			
		||||
        close(pipefd[0]);
 | 
			
		||||
        close(pipefd[1]);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user