1 /* ASIO chat server client 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 "protocol_examples_common.h"
11 #include "esp_log.h"
12 #include "esp_event.h"
13 #include "nvs_flash.h"
14 #include "server.hpp"
15 #include "client.hpp"
16 #include <thread>
17 #include <pthread.h>
18 
19 using asio::ip::tcp;
20 
21 static const char *TAG = "asio-chat";
22 
23 // This variable is necessary for `python test` execution, it provides synchronisation between server/client(as server should be started before client)
24 std::mutex server_ready;
25 
26 #ifdef CONFIG_EXAMPLE_CHAT_CLIENT
get_string(char * line,size_t size)27 static void get_string(char *line, size_t size)
28 {
29     int count = 0;
30     while (count < size) {
31         int c = fgetc(stdin);
32         if (c == '\n') {
33             line[count] = '\0';
34             break;
35         } else if (c > 0 && c < 127) {
36             line[count] = c;
37             ++count;
38         }
39         vTaskDelay(10 / portTICK_PERIOD_MS);
40     }
41 }
42 
start_client(void)43 void start_client(void)
44 {
45     const std::string port(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_PORT);
46     const std::string name(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS);
47     asio::io_context io_context;
48     char line[128];
49 
50     tcp::resolver resolver(io_context);
51     auto endpoints = resolver.resolve(name, port);
52     chat_client c(io_context, endpoints);
53 #ifdef CONFIG_EXAMPLE_CHAT_SERVER
54     std::lock_guard<std::mutex> guard(server_ready);
55 #endif
56     std::thread t([&io_context]() { try {
57                                         io_context.run();
58                                   } catch (const std::exception &e) {
59                                         ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
60                                   }
61                                     catch (...) {
62                                          ESP_LOGE(TAG, "Unknown exception");
63                                    }});
64     do {
65         ESP_LOGI(TAG, "CLIENT: Waiting for input");
66         get_string(line, sizeof(line));
67 
68         chat_message msg;
69         msg.body_length(std::strlen(line));
70         std::memcpy(msg.body(), line, msg.body_length());
71         msg.encode_header();
72         c.write(msg);
73         sleep(1);
74     } while (strcmp(line, "exit") != 0);
75 
76     c.close();
77     t.join();
78 }
79 #endif // CONFIG_EXAMPLE_CHAT_CLIENT
80 
app_main(void)81 extern "C" void app_main(void)
82 {
83     ESP_ERROR_CHECK(nvs_flash_init());
84     esp_netif_init();
85     ESP_ERROR_CHECK(esp_event_loop_create_default());
86 
87     /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
88      * Read "Establishing Wi-Fi or Ethernet Connection" section in
89      * examples/protocols/README.md for more information about this function.
90      */
91     ESP_ERROR_CHECK(example_connect());
92 
93     try {
94 #ifdef CONFIG_EXAMPLE_CHAT_SERVER
95         asio::io_context io_context;
96         chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
97         std::thread t =  std::thread([&io_context]() { // Chat server starting here
98                                      try {
99                                            io_context.run();
100                                      } catch (const std::exception &e) {
101                                            ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
102                                      }
103                                        catch (...) {
104                                            ESP_LOGE(TAG, "Unknown exception");
105                                      }});;
106 #endif
107 #ifdef CONFIG_EXAMPLE_CHAT_CLIENT
108         start_client();
109 #endif
110 #ifdef CONFIG_EXAMPLE_CHAT_SERVER
111         t.join();
112 #endif
113     } catch (const std::exception &e) {
114         ESP_LOGE(TAG, "Exception occured during run %s", e.what());
115     } catch (...) {
116         ESP_LOGE(TAG, "Unknown exception");
117     }
118     ESP_ERROR_CHECK(example_disconnect());
119 }
120