mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 23:21:40 +01:00 
			
		
		
		
	
		
			
	
	
		
			256 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			256 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Unlicense OR CC0-1.0 | ||
|  |  */ | ||
|  | #include "sdkconfig.h"
 | ||
|  | #include <string.h>
 | ||
|  | #include <unistd.h>
 | ||
|  | #include <sys/socket.h>
 | ||
|  | #include <errno.h>
 | ||
|  | #include <netdb.h>            // struct addrinfo
 | ||
|  | #include <arpa/inet.h>
 | ||
|  | #include "esp_netif.h"
 | ||
|  | #include "esp_log.h"
 | ||
|  | #if defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
 | ||
|  | #include "addr_from_stdin.h"
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if defined(CONFIG_EXAMPLE_IPV6_ADDR)
 | ||
|  | #define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
 | ||
|  | #else
 | ||
|  | #define HOST_IP_ADDR ""
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #define PORT CONFIG_EXAMPLE_PORT
 | ||
|  | 
 | ||
|  | static const char *TAG = "example"; | ||
|  | static const char *payload = "Message from ESP32 "; | ||
|  | 
 | ||
|  | #if defined(CONFIG_IDF_TARGET_LINUX)
 | ||
|  | // Checks for Global address, Unique Unicast(RFC4193) and link-local address.
 | ||
|  | #define ip6_addr_isglobal(ip6addr) ((((ip6addr)->sin6_addr.s6_addr[0] & htonl(0xe0000000UL)) & htonl(0x20000000UL)) || \
 | ||
|  |                                     (((ip6addr)->sin6_addr.s6_addr[0] & htonl(0xff000000UL)) & htonl(0xfc000000UL)) || \ | ||
|  |                                     (((ip6addr)->sin6_addr.s6_addr[0] & htonl(0xff000000UL)) & htonl(0xfe800000UL))) | ||
|  | 
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief In case of Auto mode returns the interface name with a valid IPv6 address or | ||
|  |  *        In case the user has specified interface, validates and returns the interface name. | ||
|  |  * | ||
|  |  * @param[out] interface Name of the interface in as a string. | ||
|  |  * | ||
|  |  * @return 0 incase of success. | ||
|  |  */ | ||
|  | static int get_src_iface(char *interface) | ||
|  | { | ||
|  |     struct ifaddrs *ifap, *ifa; | ||
|  |     char src_addr_str[INET6_ADDRSTRLEN]; | ||
|  | 
 | ||
|  |     if (getifaddrs(&ifap) == -1) { | ||
|  |         ESP_LOGE(TAG, "getifaddrs failed"); | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     for (ifa = ifap; ifa; ifa = ifa->ifa_next) { | ||
|  |         if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { | ||
|  | #if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
 | ||
|  |             if (0 == strcmp(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE_NAME, ifa->ifa_name)) { | ||
|  |                 strcpy(interface, ifa->ifa_name); | ||
|  |                 freeifaddrs(ifap); | ||
|  |                 ESP_LOGI(TAG, "Interface: %s", interface); | ||
|  |                 return 0; | ||
|  |             } | ||
|  | #else
 | ||
|  |             strcpy(interface, ifa->ifa_name); | ||
|  |             getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), src_addr_str, | ||
|  |                         sizeof(src_addr_str), NULL, 0, NI_NUMERICHOST); | ||
|  | 
 | ||
|  |             struct sockaddr_in6 *src_addr = (struct sockaddr_in6 *) ifa->ifa_addr; | ||
|  |             inet_ntop(AF_INET6, &(src_addr->sin6_addr), src_addr_str, INET6_ADDRSTRLEN); | ||
|  | 
 | ||
|  |             if (ip6_addr_isglobal(src_addr)) { | ||
|  |                 //Return as we have the source address
 | ||
|  |                 freeifaddrs(ifap); | ||
|  |                 ESP_LOGI(TAG, "Interface: %s", interface); | ||
|  |                 return 0; | ||
|  |             } | ||
|  | #endif    // #if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
 | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     freeifaddrs(ifap); | ||
|  |     return -1; | ||
|  | } | ||
|  | #else
 | ||
|  | 
 | ||
|  | static esp_netif_t *get_esp_netif_from_iface(char *interface_i) | ||
|  | { | ||
|  |     esp_netif_t *netif = NULL; | ||
|  |     esp_err_t ret = ESP_FAIL; | ||
|  |     char iface[10]; | ||
|  | 
 | ||
|  |     // Get interface details and own global ipv6 address
 | ||
|  |     for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) { | ||
|  |         netif = esp_netif_next(netif); | ||
|  |         ret = esp_netif_get_netif_impl_name(netif, iface); | ||
|  |         if ((ESP_FAIL == ret) || (NULL == netif)) { | ||
|  |             ESP_LOGE(TAG, "No interface available"); | ||
|  |             return NULL; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (0 == strcmp(interface_i, iface)) { | ||
|  |             return netif; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * @brief In case of Auto mode returns the interface name with a valid IPv6 address or | ||
|  |  *        In case the user has specified interface, validates and returns the interface name. | ||
|  |  * | ||
|  |  * @param[out] interface Name of the interface in as a string. | ||
|  |  * | ||
|  |  * @return 0 incase of success. | ||
|  |  */ | ||
|  | static int get_src_iface(char *interface) | ||
|  | { | ||
|  |     esp_netif_t *netif = NULL; | ||
|  |     esp_err_t ret = ESP_FAIL; | ||
|  |     int ip6_addrs_count = 0; | ||
|  |     esp_ip6_addr_t ip6[LWIP_IPV6_NUM_ADDRESSES]; | ||
|  | 
 | ||
|  |     // Get interface details and own global ipv6 address
 | ||
|  |     for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) { | ||
|  |         netif = esp_netif_next(netif); | ||
|  |         ret = esp_netif_get_netif_impl_name(netif, interface); | ||
|  | 
 | ||
|  |         if ((ESP_FAIL == ret) || (NULL == netif)) { | ||
|  |             ESP_LOGE(TAG, "No interface available"); | ||
|  |             return -1; | ||
|  |         } | ||
|  | 
 | ||
|  | #if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
 | ||
|  |         if (!strcmp(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE_NAME, interface)) { | ||
|  |             ESP_LOGI(TAG, "Interface: %s", interface); | ||
|  |             return 0; | ||
|  |         } | ||
|  | #else
 | ||
|  |         ip6_addrs_count = esp_netif_get_all_ip6(netif, ip6); | ||
|  |         for (int j = 0; j < ip6_addrs_count; ++j) { | ||
|  |             esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j])); | ||
|  | 
 | ||
|  |             if ((ESP_IP6_ADDR_IS_GLOBAL == ipv6_type) || | ||
|  |                     (ESP_IP6_ADDR_IS_UNIQUE_LOCAL == ipv6_type) || | ||
|  |                     (ESP_IP6_ADDR_IS_LINK_LOCAL == ipv6_type)) { | ||
|  |                 // Break as we have the source address
 | ||
|  |                 ESP_LOGI(TAG, "Interface: %s", interface); | ||
|  |                 return 0; | ||
|  |             } | ||
|  |         } | ||
|  | #endif    // #if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
 | ||
|  |     } | ||
|  | 
 | ||
|  |     return -1; | ||
|  | } | ||
|  | #endif    // #if defined(CONFIG_IDF_TARGET_LINUX)
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void tcp_client(void) | ||
|  | { | ||
|  |     char rx_buffer[128]; | ||
|  |     char host_ip[] = HOST_IP_ADDR; | ||
|  |     int addr_family = 0; | ||
|  |     int ip_protocol = 0; | ||
|  |     char interface[10]; | ||
|  | #if defined(CONFIG_IDF_TARGET_LINUX)
 | ||
|  |     struct ifreq ifr; | ||
|  | #else
 | ||
|  |     esp_netif_t *netif = NULL; | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     while (1) { | ||
|  | #if defined(CONFIG_EXAMPLE_IPV6)
 | ||
|  |         struct sockaddr_in6 dest_addr = { 0 }; | ||
|  |         inet_pton(AF_INET6, host_ip, &dest_addr.sin6_addr); | ||
|  |         dest_addr.sin6_family = AF_INET6; | ||
|  |         dest_addr.sin6_port = htons(PORT); | ||
|  |         addr_family = AF_INET6; | ||
|  |         ip_protocol = IPPROTO_TCP; | ||
|  | #elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
 | ||
|  |         struct sockaddr_storage dest_addr = { 0 }; | ||
|  |         ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr)); | ||
|  | #endif
 | ||
|  |         int sock =  socket(addr_family, SOCK_STREAM, ip_protocol); | ||
|  |         if (sock < 0) { | ||
|  |             ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); | ||
|  |             break; | ||
|  |         } | ||
|  |         ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT); | ||
|  | 
 | ||
|  |         if (0 != get_src_iface(interface)) { | ||
|  |             ESP_LOGE(TAG, "Interface: Unavailable\n"); | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  | #if defined(CONFIG_IDF_TARGET_LINUX)
 | ||
|  |         memset (&ifr, 0, sizeof(ifr)); | ||
|  |         snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface); | ||
|  |         if (ioctl (sock, SIOCGIFINDEX, &ifr) < 0) { | ||
|  |             ESP_LOGE(TAG, "ioctl() failed to find interface "); | ||
|  |             break; | ||
|  |         } | ||
|  | #if defined(CONFIG_EXAMPLE_IPV6)
 | ||
|  |         dest_addr.sin6_scope_id = ifr.ifr_ifindex; | ||
|  |         ESP_LOGI(TAG, "Interface index: %d\n", dest_addr.sin6_scope_id); | ||
|  | #endif
 | ||
|  | #else
 | ||
|  |         if (NULL == (netif = get_esp_netif_from_iface(interface))) { | ||
|  |             ESP_LOGE(TAG, "Failed to find interface "); | ||
|  |             break; | ||
|  |         } | ||
|  | #if defined(CONFIG_EXAMPLE_IPV6)
 | ||
|  |         dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(netif); | ||
|  |         ESP_LOGI(TAG, "Interface index: %d\n", dest_addr.sin6_scope_id); | ||
|  | #endif
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  |         int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); | ||
|  |         if (err != 0) { | ||
|  |             ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno); | ||
|  |             break; | ||
|  |         } | ||
|  |         ESP_LOGI(TAG, "Successfully connected"); | ||
|  | 
 | ||
|  |         while (1) { | ||
|  |             int err = send(sock, payload, strlen(payload), 0); | ||
|  |             if (err < 0) { | ||
|  |                 ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); | ||
|  |                 break; | ||
|  |             } | ||
|  | 
 | ||
|  |             int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); | ||
|  |             // Error occurred during receiving
 | ||
|  |             if (len < 0) { | ||
|  |                 ESP_LOGE(TAG, "recv failed: errno %d", errno); | ||
|  |                 break; | ||
|  |             } | ||
|  |             // Data received
 | ||
|  |             else { | ||
|  |                 rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
 | ||
|  |                 ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip); | ||
|  |                 ESP_LOGI(TAG, "%s", rx_buffer); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if (sock != -1) { | ||
|  |             ESP_LOGE(TAG, "Shutting down socket and restarting..."); | ||
|  |             shutdown(sock, 0); | ||
|  |             close(sock); | ||
|  |         } | ||
|  |     } | ||
|  | } |