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_udp_socket.h"
14 #include "lwip/err.h"
15 #include "lwip/sockets.h"
16
17 #define TAG "ot_socket"
18
udp_socket_server_task(void * pvParameters)19 static void udp_socket_server_task(void *pvParameters)
20 {
21 char addr_str[128];
22 char *payload = "This message is from server\n";
23 char rx_buffer[128];
24 esp_err_t ret = ESP_OK;
25 int err = 0;
26 int len;
27 int listen_sock;
28
29 int port = CONFIG_OPENTHREAD_CLI_UDP_SERVER_PORT;
30 struct timeval timeout = { 0 };
31 struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
32 struct sockaddr_in6 listen_addr;
33
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_DGRAM, IPPROTO_UDP);
39 ESP_GOTO_ON_FALSE((listen_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
40 ESP_LOGI(TAG, "Socket created");
41
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 int opt = 1;
45 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
46 setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
47
48 err = bind(listen_sock, (struct sockaddr *)&listen_addr, sizeof(listen_addr));
49 ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
50 ESP_LOGI(TAG, "Socket bound, port %d", port);
51
52 timeout.tv_sec = 30;
53 setsockopt(listen_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
54
55 ESP_LOGI(TAG, "Waiting for data, timeout is 30 seconds");
56 socklen_t socklen = sizeof(source_addr);
57 len = recvfrom(listen_sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
58
59 // Error occurred during receiving
60 ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recvfrom failed: errno %d", errno);
61 // Data received
62 // Get the sender's ip address as string
63 inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);
64
65 rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string...
66 ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str);
67 ESP_LOGI(TAG, "%s", rx_buffer);
68
69 err = sendto(listen_sock, payload, strlen(payload), 0, (struct sockaddr *)&source_addr, sizeof(source_addr));
70 ESP_GOTO_ON_FALSE((err >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
71 exit:
72 if (ret != ESP_OK || listen_sock != -1) {
73 shutdown(listen_sock, 0);
74 close(listen_sock);
75 }
76 ESP_LOGI(TAG, "Socket server is closed.");
77 vTaskDelete(NULL);
78 }
79
udp_socket_client_task(void * pvParameters)80 static void udp_socket_client_task(void *pvParameters)
81 {
82 char rx_buffer[128];
83 char *host_ip = (char *)pvParameters;
84 char *payload = "This message is from client\n";
85 int client_sock;
86 int port = CONFIG_OPENTHREAD_CLI_UDP_SERVER_PORT;
87 int err = 0;
88 int len;
89 esp_err_t ret = ESP_OK;
90 struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
91 struct sockaddr_in6 dest_addr = { 0 };
92
93 inet6_aton(host_ip, &dest_addr.sin6_addr);
94 dest_addr.sin6_family = AF_INET6;
95 dest_addr.sin6_port = htons(port);
96
97 client_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
98 ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
99 ESP_LOGI(TAG, "Socket created, sending to %s:%d", host_ip, port);
100
101 err = sendto(client_sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
102 ESP_GOTO_ON_FALSE((err >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
103 ESP_LOGI(TAG, "Message sent");
104
105 socklen_t socklen = sizeof(source_addr);
106 len = recvfrom(client_sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
107
108 // Error occurred during receiving
109 ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recvfrom failed: errno %d", errno);
110 // Data received
111 rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
112 ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
113 ESP_LOGI(TAG, "%s", rx_buffer);
114 exit:
115 if (ret != ESP_OK || client_sock != -1) {
116 shutdown(client_sock, 0);
117 close(client_sock);
118 }
119 ESP_LOGI(TAG, "Socket client is closed");
120 vTaskDelete(NULL);
121 }
122
esp_ot_process_udp_server(void * aContext,uint8_t aArgsLength,char * aArgs[])123 void esp_ot_process_udp_server(void *aContext, uint8_t aArgsLength, char *aArgs[])
124 {
125 (void)(aContext);
126 (void)(aArgsLength);
127 xTaskCreate(udp_socket_server_task, "ot_udp_scoket_server", 4096, xTaskGetCurrentTaskHandle(), 4, NULL);
128 }
129
esp_ot_process_udp_client(void * aContext,uint8_t aArgsLength,char * aArgs[])130 void esp_ot_process_udp_client(void *aContext, uint8_t aArgsLength, char *aArgs[])
131 {
132 (void)(aContext);
133 (void)(aArgsLength);
134 if (aArgsLength == 0) {
135 ESP_LOGE(TAG, "Invalid arguments.");
136 } else {
137 xTaskCreate(udp_socket_client_task, "ot_udp_socket_client", 4096, aArgs[0], 4, NULL);
138 }
139 }
140