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