mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'examples/tcp_client_linux_support' into 'master'
tcp_client example: support for Linux target. Closes IDF-5636 See merge request espressif/esp-idf!19203
This commit is contained in:
commit
fbc32c0312
@ -238,6 +238,8 @@ examples/protocols/sockets/tcp_client:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
enable:
|
||||
- if: INCLUDE_DEFAULT == 1 or IDF_TARGET == "linux"
|
||||
|
||||
examples/protocols/sockets/tcp_client_multi_net:
|
||||
disable:
|
||||
|
@ -1,10 +1,14 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
if(${IDF_TARGET} STREQUAL "linux")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
|
||||
set(COMPONENTS main)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
else()
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
endif()
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(tcp_client)
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | Linux |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | ----- |
|
||||
|
||||
|
||||
# TCP Client example
|
||||
@ -8,13 +8,38 @@
|
||||
|
||||
The application creates a TCP socket and tries to connect to the server with predefined IP address and port number. When a connection is successfully established, the application sends message and waits for the answer. After the server's reply, application prints received reply as ASCII text, waits for 2 seconds and sends another message.
|
||||
|
||||
## How to use example
|
||||
## Configure the project
|
||||
This example can be configured to run on ESP32 and Linux target to communicate over IPv4 and IPv6.
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Set following parameters under ```Example Configuration``` Options:
|
||||
|
||||
* Set `IP version` of example to be IPV4 or IPV6.
|
||||
|
||||
* Set `IPV4 Address` in case your chose IP version IPV4 above.
|
||||
|
||||
* Set `IPV6 Address` in case your chose IP version IPV6 above.
|
||||
* For IPv6 there's an additional option for ```Interface selection```.
|
||||
* Enter the name of the interface to explicitely establish communication over a specific interface.
|
||||
* On selecting ```Auto``` the example will find the first interface with an IPv6 address and use it.
|
||||
|
||||
* Set `Port` number that represents remote port the example will connect to.
|
||||
|
||||
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
|
||||
Note: please replace `192.168.0.167 3333` with desired IPV4/IPV6 address (displayed in monitor console) and port number in the following command.
|
||||
|
||||
|
||||
## How to use example:
|
||||
|
||||
In order to create TCP server that communicates with TCP Client example, choose one of the following options.
|
||||
|
||||
There are many host-side tools which can be used to interact with the UDP/TCP server/client.
|
||||
One command line tool is [netcat](http://netcat.sourceforge.net) which can send and receive many kinds of packets.
|
||||
Note: please replace `192.168.0.167 3333` with desired IPV4/IPV6 address (displayed in monitor console) and port number in the following command.
|
||||
|
||||
In addition to those tools, simple Python scripts can be found under sockets/scripts directory. Every script is designed to interact with one of the examples.
|
||||
|
||||
@ -24,35 +49,24 @@ nc -l 192.168.0.167 3333
|
||||
```
|
||||
|
||||
### Python scripts
|
||||
Script example_test.py could be used as a counter part to the tcp-client project, ip protocol name (IPv4 or IPv6) shall be stated as argument. Example:
|
||||
Script example_test.py could be used as a counter part to the tcp-client project, ip protocol name (IPv4 or IPv6) shall be stated as argument.
|
||||
|
||||
Note that this script is used in automated tests, as well, so the IDF test framework packages need to be imported.
|
||||
Please run the following commands to configure the terminal to execute the script.
|
||||
```
|
||||
export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages"
|
||||
python -m pip install -r $IDF_PATH/tools/ci/python_packages/ttfw_idf/requirements.txt
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
python example_test.py IPv4
|
||||
```
|
||||
Note that this script is used in automated tests, as well, so the IDF test framework packages need to be imported;
|
||||
please add `$IDF_PATH/tools/ci/python_packages` to `PYTHONPATH`.
|
||||
|
||||
## Hardware Required
|
||||
|
||||
This example can be run on any commonly available ESP32 development board.
|
||||
This example can also run on any Linux environment.
|
||||
|
||||
## Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Set following parameters under Example Configuration Options:
|
||||
|
||||
* Set `IP version` of example to be IPV4 or IPV6.
|
||||
|
||||
* Set `IPV4 Address` in case your chose IP version IPV4 above.
|
||||
|
||||
* Set `IPV6 Address` in case your chose IP version IPV6 above.
|
||||
|
||||
* Set `Port` number that represents remote port the example will connect to.
|
||||
|
||||
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
## Build and Flash
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
if(${IDF_TARGET} STREQUAL "linux")
|
||||
idf_component_register(SRCS
|
||||
esp_stubs/esp_stubs.c
|
||||
INCLUDE_DIRS . include/stubs
|
||||
REQUIRES main)
|
||||
endif()
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
extern void app_main(void);
|
||||
|
||||
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
|
||||
{
|
||||
ESP_LOGE("ESP_ERROR_CHECK", "Failed with esp_err_t: 0x%x", rc);
|
||||
ESP_LOGE("ESP_ERROR_CHECK", "Expression: %s", expression);
|
||||
ESP_LOGE("ESP_ERROR_CHECK", "Functions: %s %s(%d)", function, file, line);
|
||||
abort();
|
||||
}
|
||||
|
||||
esp_err_t esp_event_loop_create_default(void)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_init(void)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t example_connect(void)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t nvs_flash_init(void)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
app_main();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "esp_err.h"
|
||||
|
||||
esp_err_t esp_event_loop_create_default(void);
|
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
esp_err_t esp_netif_init(void);
|
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "esp_err.h"
|
||||
|
||||
esp_err_t nvs_flash_init(void);
|
@ -0,0 +1,8 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "esp_err.h"
|
||||
|
||||
esp_err_t example_connect(void);
|
@ -1,2 +1,13 @@
|
||||
idf_component_register(SRCS "tcp_client.c"
|
||||
INCLUDE_DIRS ".")
|
||||
if(${IDF_TARGET} STREQUAL "linux")
|
||||
set(requires esp_stubs)
|
||||
endif()
|
||||
|
||||
if("${CONFIG_EXAMPLE_IPV4}" STREQUAL y)
|
||||
set(tcp_client_ip tcp_client_v4.c)
|
||||
else()
|
||||
set(tcp_client_ip tcp_client_v6.c)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "tcp_client_main.c" "${tcp_client_ip}"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES ${requires})
|
||||
|
@ -35,6 +35,26 @@ menu "Example Configuration"
|
||||
help
|
||||
The remote port to which the client example will connect to.
|
||||
|
||||
choice EXAMPLE_INTERFACE
|
||||
prompt "Interface selection"
|
||||
depends on EXAMPLE_IPV6
|
||||
help
|
||||
Example can use either "Auto" or "User specified".
|
||||
|
||||
config EXAMPLE_IFACE_AUTO
|
||||
bool "Auto"
|
||||
|
||||
config EXAMPLE_USER_SPECIFIED_IFACE
|
||||
bool "User specified interface"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_USER_SPECIFIED_IFACE_NAME
|
||||
string "User specified interface name"
|
||||
default "st1"
|
||||
depends on EXAMPLE_USER_SPECIFIED_IFACE
|
||||
help
|
||||
This interface will be used for communication.
|
||||
|
||||
choice EXAMPLE_SOCKET_IP_INPUT
|
||||
prompt "Socket example source"
|
||||
default EXAMPLE_SOCKET_IP_INPUT_STRING
|
||||
|
27
examples/protocols/sockets/tcp_client/main/tcp_client_main.c
Normal file
27
examples/protocols/sockets/tcp_client/main/tcp_client_main.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
|
||||
extern void tcp_client(void);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
tcp_client();
|
||||
}
|
@ -1,33 +1,24 @@
|
||||
/* BSD Socket API Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.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 "protocol_examples_common.h"
|
||||
#include "esp_log.h"
|
||||
#if defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
|
||||
#include "addr_from_stdin.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_IPV4)
|
||||
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
|
||||
#elif defined(CONFIG_EXAMPLE_IPV6)
|
||||
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
|
||||
#else
|
||||
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
|
||||
#define HOST_IP_ADDR ""
|
||||
#endif
|
||||
|
||||
@ -36,7 +27,8 @@
|
||||
static const char *TAG = "example";
|
||||
static const char *payload = "Message from ESP32 ";
|
||||
|
||||
static void tcp_client_task(void *pvParameters)
|
||||
|
||||
void tcp_client(void)
|
||||
{
|
||||
char rx_buffer[128];
|
||||
char host_ip[] = HOST_IP_ADDR;
|
||||
@ -46,23 +38,16 @@ static void tcp_client_task(void *pvParameters)
|
||||
while (1) {
|
||||
#if defined(CONFIG_EXAMPLE_IPV4)
|
||||
struct sockaddr_in dest_addr;
|
||||
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
|
||||
inet_pton(AF_INET, host_ip, &dest_addr.sin_addr);
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = htons(PORT);
|
||||
addr_family = AF_INET;
|
||||
ip_protocol = IPPROTO_IP;
|
||||
#elif defined(CONFIG_EXAMPLE_IPV6)
|
||||
struct sockaddr_in6 dest_addr = { 0 };
|
||||
inet6_aton(host_ip, &dest_addr.sin6_addr);
|
||||
dest_addr.sin6_family = AF_INET6;
|
||||
dest_addr.sin6_port = htons(PORT);
|
||||
dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
|
||||
addr_family = AF_INET6;
|
||||
ip_protocol = IPPROTO_IPV6;
|
||||
#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);
|
||||
@ -70,7 +55,7 @@ static void tcp_client_task(void *pvParameters)
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
|
||||
|
||||
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
|
||||
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;
|
||||
@ -96,8 +81,6 @@ static void tcp_client_task(void *pvParameters)
|
||||
ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
|
||||
ESP_LOGI(TAG, "%s", rx_buffer);
|
||||
}
|
||||
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
if (sock != -1) {
|
||||
@ -106,20 +89,4 @@ static void tcp_client_task(void *pvParameters)
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
|
||||
}
|
255
examples/protocols/sockets/tcp_client/main/tcp_client_v6.c
Normal file
255
examples/protocols/sockets/tcp_client/main/tcp_client_v6.c
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
4
examples/protocols/sockets/tcp_client/sdkconfig.defaults
Normal file
4
examples/protocols/sockets/tcp_client/sdkconfig.defaults
Normal file
@ -0,0 +1,4 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
# CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER is not set
|
Loading…
x
Reference in New Issue
Block a user