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