1 /* OpenThread Command Line Example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 
10 #include "esp_check.h"
11 #include "esp_err.h"
12 #include "esp_log.h"
13 #include "esp_ot_tcp_socket.h"
14 #include "lwip/err.h"
15 #include "lwip/sockets.h"
16 
17 #define TAG "ot_socket"
18 
tcp_socket_server_task(void * pvParameters)19 static void tcp_socket_server_task(void *pvParameters)
20 {
21     char addr_str[128];
22     char rx_buffer[128];
23     esp_err_t ret = ESP_OK;
24     int err = 0;
25     int len = 0;
26     int listen_sock;
27     int opt = 1;
28     int port = CONFIG_OPENTHREAD_CLI_TCP_SERVER_PORT;
29     int client_sock = 0;
30     struct timeval timeout = { 0 };
31     struct sockaddr_storage source_addr; // Large enough for both IPv6
32     struct sockaddr_in6 listen_addr = { 0 };
33     // The TCP server listen at the address "::", which means all addresses can be listened to.
34     inet6_aton("::", &listen_addr.sin6_addr);
35     listen_addr.sin6_family = AF_INET6;
36     listen_addr.sin6_port = htons(port);
37 
38     listen_sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
39     ESP_GOTO_ON_FALSE((listen_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
40 
41     setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
42     // Note that by default IPV6 binds to both protocols, it is must be disabled
43     // if both protocols used at the same time (used in CI)
44     setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
45 
46     ESP_LOGI(TAG, "Socket created");
47 
48     err = bind(listen_sock, (struct sockaddr *)&listen_addr, sizeof(struct sockaddr_in6) );
49     ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET6);
50     ESP_LOGI(TAG, "Socket bound, port %d", port);
51 
52     err = listen(listen_sock, 1);
53     ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
54 
55     //blocking-mode accept, set timeout 30 seconds
56     timeout.tv_sec = 30;
57     setsockopt(listen_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
58 
59     ESP_LOGI(TAG, "Socket listening, timeout is 30 seconds");
60 
61     socklen_t addr_len = sizeof(source_addr);
62     client_sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
63     ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_FAIL, exit, TAG, "Unable to accept connection: errno %d", errno);
64 
65     ESP_GOTO_ON_FALSE((err >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
66 
67     //blocking-mode receive, set timeout 30 seconds
68     timeout.tv_sec = 30;
69     setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
70 
71     len = recv(client_sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
72     // Error occurred during receiving
73     ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recv failed: errno %d", errno);
74     // Data received
75     rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
76     ESP_LOGI(TAG, "Received %d bytes from client:", len);
77     ESP_LOGI(TAG, "%s", rx_buffer);
78 
79     // Convert ip address to string
80     inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);
81     ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
82 exit:
83     if (ret != ESP_OK || listen_sock != -1) {
84         shutdown(listen_sock, 0);
85         close(listen_sock);
86     }
87     if (client_sock != -1) {
88         shutdown(client_sock, 0);
89         close(client_sock);
90     }
91     ESP_LOGI(TAG, "Socket server is closed.");
92     vTaskDelete(NULL);
93 }
94 
tcp_socket_client_task(void * pvParameters)95 static void tcp_socket_client_task(void *pvParameters)
96 {
97     char *host_ip = (char *)pvParameters;
98     char *payload = "This message is from client\n";
99     char rx_buffer[128];
100     esp_err_t ret = ESP_OK;
101     int client_sock;
102     int err = 0;
103     int len = 0;
104     int port = CONFIG_OPENTHREAD_CLI_TCP_SERVER_PORT;
105     struct sockaddr_in6 dest_addr = { 0 };
106 
107     inet6_aton(host_ip, &dest_addr.sin6_addr);
108     dest_addr.sin6_family = AF_INET6;
109     dest_addr.sin6_port = htons(port);
110 
111     client_sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
112     ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
113 
114     ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, port);
115 
116     err = connect(client_sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
117     ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
118     ESP_LOGI(TAG, "Successfully connected");
119 
120     len = send(client_sock, payload, strlen(payload), 0);
121     ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
122 
123     len = recv(client_sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
124     // Error occurred during receiving
125     ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recv failed: errno %d", errno);
126     // Data received
127     rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
128     ESP_LOGI(TAG, "Received %d bytes from %s", len, host_ip);
129     ESP_LOGI(TAG, "%s", rx_buffer);
130 
131 exit:
132     if (ret != ESP_OK || client_sock != -1) {
133         shutdown(client_sock, 0);
134         close(client_sock);
135     }
136     ESP_LOGI(TAG, "Socket client is closed.");
137     vTaskDelete(NULL);
138 }
139 
esp_ot_process_tcp_server(void * aContext,uint8_t aArgsLength,char * aArgs[])140 void esp_ot_process_tcp_server(void *aContext, uint8_t aArgsLength, char *aArgs[])
141 {
142     (void)(aContext);
143     (void)(aArgsLength);
144     (void)(*aArgs);
145     xTaskCreate(tcp_socket_server_task, "ot_tcp_scoket_server", 4096, xTaskGetCurrentTaskHandle(), 4, NULL);
146 }
147 
esp_ot_process_tcp_client(void * aContext,uint8_t aArgsLength,char * aArgs[])148 void esp_ot_process_tcp_client(void *aContext, uint8_t aArgsLength, char *aArgs[])
149 {
150     (void)(aContext);
151     (void)(aArgsLength);
152     if (aArgsLength == 0) {
153         ESP_LOGE(TAG, "Invalid arguments.");
154     } else {
155         xTaskCreate(tcp_socket_client_task, "ot_tcp_socket_client", 4096, aArgs[0], 4, NULL);
156     }
157 }
158