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