libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
linux_wifi_client.hpp
1#pragma once
2
3#include "libxr_def.hpp"
4#if defined(HAVE_WPA_CLIENT)
5
6#include <NetworkManager.h>
7#include <unistd.h>
8#include <wpa_ctrl.h>
9
10#include <cstring>
11#include <sstream>
12#include <string>
13#include <vector>
14
15#include "logger.hpp"
16#include "net/wifi_client.hpp"
17#include "thread.hpp"
18
19namespace LibXR
20{
21
25class LinuxWifiClient : public WifiClient
26{
27 public:
32 LinuxWifiClient(const char* ifname = nullptr)
33 {
34 if (ifname)
35 {
36 strncpy(ifname_cstr_, ifname, sizeof(ifname_cstr_) - 1);
37 }
38 else
39 {
40 std::string iface = DetectWifiInterface();
41 if (iface.empty())
42 {
43 XR_LOG_ERROR("Wi-Fi interface not found");
44 ASSERT(false);
45 }
46 else
47 {
48 strncpy(ifname_cstr_, iface.c_str(), sizeof(ifname_cstr_) - 1);
49 }
50 }
51
52 socket_path_ = "/var/run/wpa_supplicant/" + std::string(ifname_cstr_);
53 }
54
58 ~LinuxWifiClient() override
59 {
60 Disconnect();
61 if (ctrl_)
62 {
63 wpa_ctrl_close(ctrl_);
64 }
65 }
66
67 bool Enable() override
68 {
69 if (ctrl_)
70 {
71 return true;
72 }
73 ctrl_ = wpa_ctrl_open(socket_path_.c_str());
74 if (ctrl_)
75 {
76 XR_LOG_PASS("Wi-Fi enabled: %s", socket_path_.c_str());
77 return true;
78 }
79 XR_LOG_ERROR("Wi-Fi enable failed: %s", socket_path_.c_str());
80 return false;
81 }
82
83 void Disable() override
84 {
85 Disconnect();
86 if (ctrl_)
87 {
88 wpa_ctrl_close(ctrl_);
89 ctrl_ = nullptr;
90 }
91 }
92
93 bool IsConnected() const override
94 {
95 std::string out;
96 if (!SendCommand("STATUS", out))
97 {
98 return false;
99 }
100 return out.find("wpa_state=COMPLETED") != std::string::npos;
101 }
102
103 IPAddressRaw GetIPAddress() const override
104 {
105 char cmd[128];
106 auto ans = snprintf(cmd, sizeof(cmd), "ip -4 addr show %s | grep inet", ifname_cstr_);
107 UNUSED(ans);
108 FILE* fp = popen(cmd, "r");
109 if (!fp)
110 {
111 return {};
112 }
113
114 char buf[64] = {};
115 IPAddressRaw ip = {};
116 if (fgets(buf, sizeof(buf), fp))
117 {
118 char ip_str[32] = {};
119 auto ret = sscanf(buf, " inet %[^/]", ip_str);
120 UNUSED(ret);
121 ip = IPAddressRaw::FromString(ip_str);
122 }
123 pclose(fp);
124 return ip;
125 }
126
127 MACAddressRaw GetMACAddress() const override
128 {
129 char path[128];
130 auto ans = snprintf(path, sizeof(path), "/sys/class/net/%s/address", ifname_cstr_);
131 UNUSED(ans);
132 FILE* fp = fopen(path, "r");
133 if (!fp)
134 {
135 return {};
136 }
137
138 char mac_str[32] = {};
139 if (!fgets(mac_str, sizeof(mac_str), fp))
140 {
141 auto ans = fclose(fp);
142 UNUSED(ans);
143 return {};
144 }
145 auto ret = fclose(fp);
146 UNUSED(ret);
147 mac_str[strcspn(mac_str, "\n")] = 0;
148 return MACAddressRaw::FromString(mac_str);
149 }
150
151 WifiError Connect(const Config& config) override
152 {
153 std::string out;
154 SendCommand("REMOVE_NETWORK all", out);
155 SendCommand("ADD_NETWORK", out);
156 int netid = atoi(out.c_str());
157 if (netid < 0)
158 {
159 XR_LOG_ERROR("ADD_NETWORK failed: %s", out.c_str());
160 return WifiError::HARDWARE_FAILURE;
161 }
162
163 std::stringstream cmd;
164 cmd << "SET_NETWORK " << netid << " ssid \"" << config.ssid << "\"";
165 if (!SendCommand(cmd.str().c_str(), out) || out.find("OK") == std::string::npos)
166 {
167 XR_LOG_ERROR("SET_NETWORK ssid failed: %s", out.c_str());
168 return WifiError::AUTHENTICATION_FAILED;
169 }
170
171 cmd.str("");
172 cmd << "SET_NETWORK " << netid << " psk \"" << config.password << "\"";
173 if (!SendCommand(cmd.str().c_str(), out) || out.find("OK") == std::string::npos)
174 {
175 XR_LOG_ERROR("SET_NETWORK psk failed: %s", out.c_str());
176 return WifiError::AUTHENTICATION_FAILED;
177 }
178
179 std::vector<std::string> cleanup_cmds = {
180 "key_mgmt WPA-PSK", "eap NONE", "phase1 \"\"", "identity \"\"", "password \"\"",
181 };
182 for (const auto& line : cleanup_cmds)
183 {
184 cmd.str("");
185 cmd << "SET_NETWORK " << netid << " " << line;
186 SendCommand(cmd.str().c_str(), out);
187 }
188
189 cmd.str("");
190 cmd << "ENABLE_NETWORK " << netid;
191 if (!SendCommand(cmd.str().c_str(), out) || out.find("OK") == std::string::npos)
192 {
193 XR_LOG_ERROR("ENABLE_NETWORK failed: %s", out.c_str());
194 return WifiError::HARDWARE_FAILURE;
195 }
196
197 cmd.str("");
198 cmd << "SELECT_NETWORK " << netid;
199 SendCommand(cmd.str().c_str(), out);
200
201 const int TIMEOUT_MS = 30000;
202 const int INTERVAL_MS = 300;
203 int elapsed = 0;
204
205 while (elapsed < TIMEOUT_MS)
206 {
207 std::string status;
208 SendCommand("STATUS", status);
209
210 if (status.find("wpa_state=COMPLETED") != std::string::npos)
211 {
212 XR_LOG_PASS("Wi-Fi Connected to SSID: %s", config.ssid);
213 return WifiError::NONE;
214 }
215
216 if (status.find("wpa_state=INACTIVE") != std::string::npos)
217 {
218 XR_LOG_ERROR("Wi-Fi Connection failed: %s", status.c_str());
219 return WifiError::AUTHENTICATION_FAILED;
220 }
221
222 LibXR::Thread::Sleep(INTERVAL_MS);
223 elapsed += INTERVAL_MS;
224 }
225
226 XR_LOG_ERROR("Wi-Fi Connection timeout");
227 return WifiError::CONNECTION_TIMEOUT;
228 }
229
230 WifiError Disconnect() override
231 {
232 std::string out;
233 SendCommand("DISCONNECT", out);
234 SendCommand("REMOVE_NETWORK all", out);
235 if (IsConnected())
236 {
237 return WifiError::UNKNOWN;
238 }
239 return WifiError::NONE;
240 }
241
242 WifiError Scan(ScanResult* out_list, size_t max_count, size_t& out_found) override
243 {
244 std::string out;
245 SendCommand("SCAN", out);
246 sleep(2);
247 SendCommand("SCAN_RESULTS", out);
248
249 std::istringstream ss(out);
250 std::string line;
251 out_found = 0;
252 std::getline(ss, line);
253 while (std::getline(ss, line) && out_found < max_count)
254 {
255 std::istringstream ls(line);
256 std::string bssid, freq, signal, flags, ssid;
257 ls >> bssid >> freq >> signal >> flags;
258 std::getline(ls, ssid);
259 if (!ssid.empty() && ssid[0] == '\t')
260 {
261 ssid.erase(0, 1);
262 }
263
264 auto& r = out_list[out_found++];
265 strncpy(r.ssid, ssid.c_str(), sizeof(r.ssid) - 1);
266 r.rssi = atoi(signal.c_str());
267 r.security =
268 (flags.find("WPA2") != std::string::npos) ? Security::WPA2_PSK : Security::OPEN;
269 }
270
271 return WifiError::NONE;
272 }
273
274 int GetRSSI() const override
275 {
276 std::string out;
277 SendCommand("SIGNAL_POLL", out);
278 auto pos = out.find("RSSI=");
279 return pos != std::string::npos ? atoi(out.c_str() + pos + 5) : 0;
280 }
281
282 private:
283 bool SendCommand(const char* cmd, std::string& result) const
284 {
285 if (!ctrl_)
286 {
287 return false;
288 }
289 char buf[4096];
290 size_t len = sizeof(buf);
291 int ret = wpa_ctrl_request(ctrl_, cmd, strlen(cmd), buf, &len, nullptr);
292 if (ret == 0)
293 {
294 result.assign(buf, len);
295 return true;
296 }
297 XR_LOG_ERROR("wpa_ctrl_request failed: %s\n", strerror(errno));
298 return false;
299 }
300
301 std::string DetectWifiInterface()
302 {
303 GError* error = nullptr;
304 NMClient* client = nm_client_new(nullptr, &error);
305 if (!client)
306 {
307 auto ans = fprintf(stderr, "Failed to create NMClient: %s\n",
308 error ? error->message : "unknown error");
309 UNUSED(ans);
310
311 if (error)
312 {
313 g_error_free(error);
314 }
315 return "";
316 }
317
318 const GPtrArray* devices = nm_client_get_devices(client);
319 for (guint i = 0; i < devices->len; ++i)
320 {
321 NMDevice* dev = (NMDevice*)g_ptr_array_index(devices, i);
322 if (NM_IS_DEVICE_WIFI(dev))
323 {
324 const char* ifname = nm_device_get_iface(dev);
325 if (ifname)
326 {
327 std::string iface_str(ifname);
328 g_object_unref(client);
329 return iface_str;
330 }
331 }
332 }
333
334 g_object_unref(client);
335 return "";
336 }
337
338 char ifname_cstr_[32] = {}; // 静态存储接口名,避免动态分配
339 std::string socket_path_;
340 wpa_ctrl* ctrl_ = nullptr;
341};
342
343} // namespace LibXR
344
345#endif
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep
Definition thread.cpp:16
LibXR 命名空间
Definition ch32_can.hpp:14