Skip to content

Commit 732b1d5

Browse files
committed
fix(wifi_remote): Fix server event/command race condtion using eventfd
1 parent 9e13870 commit 732b1d5

File tree

4 files changed

+146
-24
lines changed

4 files changed

+146
-24
lines changed

components/esp_wifi_remote/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ idf_component_register(INCLUDE_DIRS include
1414
${src_wifi_is_remote}
1515
PRIV_INCLUDE_DIRS eppp
1616
REQUIRES esp_event esp_netif
17-
PRIV_REQUIRES esp_wifi esp-tls)
17+
PRIV_REQUIRES esp_wifi esp-tls vfs)
1818

1919
idf_component_get_property(wifi esp_wifi COMPONENT_LIB)
2020
target_link_libraries(${wifi} PUBLIC ${COMPONENT_LIB})

components/esp_wifi_remote/eppp/wifi_remote_rpc_impl.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@ class RpcEngine {
129129
return ESP_OK;
130130
}
131131

132+
int get_socket_fd()
133+
{
134+
int sock;
135+
if (esp_tls_get_conn_sockfd(tls_, &sock) != ESP_OK) {
136+
return -1;
137+
}
138+
return sock;
139+
}
140+
132141
RpcHeader get_header()
133142
{
134143
RpcHeader header{};

components/esp_wifi_remote/eppp/wifi_remote_rpc_params.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct esp_wifi_remote_mac_t {
1616
};
1717

1818
struct esp_wifi_remote_eppp_ip_event {
19-
uint32_t id;
19+
int32_t id;
2020
esp_netif_ip_info_t wifi_ip;
2121
esp_netif_ip_info_t ppp_ip;
2222
esp_netif_dns_info_t dns;

components/esp_wifi_remote/eppp/wifi_remote_rpc_server.cpp

Lines changed: 135 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "eppp_link.h"
1616
#include "wifi_remote_rpc_params.h"
1717
#include "lwip/apps/snmp.h"
18+
#include "esp_vfs.h"
19+
#include "esp_vfs_eventfd.h"
1820

1921
extern "C" esp_netif_t *wifi_remote_eppp_init(eppp_type_t role);
2022

@@ -32,30 +34,70 @@ const unsigned char key[] = "-----BEGIN PRIVATE KEY-----\n" CONFIG_ESP_WIFI_REMO
3234

3335
using namespace server;
3436

37+
struct Events {
38+
api_id type;
39+
int32_t id;
40+
esp_wifi_remote_eppp_ip_event *ip_data{nullptr};
41+
bool clean_ip_data{true};
42+
esp_err_t create_ip_data()
43+
{
44+
ip_data = new (std::nothrow) esp_wifi_remote_eppp_ip_event;
45+
return ip_data ? ESP_OK : ESP_ERR_NO_MEM;
46+
}
47+
~Events()
48+
{
49+
if (clean_ip_data) {
50+
delete ip_data;
51+
}
52+
}
53+
};
54+
3555
class Sync {
3656
friend class RpcInstance;
3757
public:
38-
void lock()
58+
esp_err_t put(Events &ev)
3959
{
40-
xSemaphoreTake(mutex, portMAX_DELAY);
60+
ESP_RETURN_ON_FALSE(xQueueSend(queue, &ev, pdMS_TO_TICKS(queue_timeout)), ESP_FAIL, TAG, "Failed to queue event %" PRIi32, ev.id);
61+
ev.clean_ip_data = false; // IP data were successfully sent to the queue, will free manually after receiving from it
62+
uint64_t event_queued = 1;
63+
write(fd, &event_queued, sizeof(event_queued)); // trigger the wait loop that
64+
return ESP_OK;
4165
}
42-
void unlock()
66+
Events get()
4367
{
44-
xSemaphoreGive(mutex);
68+
Events ev{};
69+
if (!xQueueReceive(queue, &ev, 0)) {
70+
ev.type = api_id::ERROR;
71+
}
72+
return ev;
4573
}
4674
esp_err_t init()
4775
{
48-
mutex = xSemaphoreCreateMutex();
49-
return mutex == nullptr ? ESP_ERR_NO_MEM : ESP_OK;
76+
queue = xQueueCreate(max_items, sizeof(Events));
77+
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
78+
esp_vfs_eventfd_register(&config);
79+
fd = eventfd(0, EFD_SUPPORT_ISR);
80+
return queue == nullptr || fd < 0 ? ESP_ERR_NO_MEM : ESP_OK;
5081
}
5182
~Sync()
5283
{
53-
if (mutex) {
54-
vSemaphoreDelete(mutex);
84+
if (queue) {
85+
vQueueDelete(queue);
86+
}
87+
if (fd >= 0) {
88+
close(fd);
5589
}
5690
}
91+
int fd{-1};
92+
// Used to trigger task by either an internal event or rpc command
93+
static const int NONE = 0;
94+
static const int ERROR = 1;
95+
static const int EVENT = 2;
96+
static const int RPC = 4;
5797
private:
58-
SemaphoreHandle_t mutex{nullptr};
98+
QueueHandle_t queue{nullptr};
99+
const int max_items = 15;
100+
const int queue_timeout = 200;
59101
};
60102

61103
class RpcInstance {
@@ -70,7 +112,7 @@ class RpcInstance {
70112
ESP_RETURN_ON_ERROR(start_server(), TAG, "Failed to start RPC server");
71113
ESP_RETURN_ON_ERROR(rpc.init(), TAG, "Failed to init RPC engine");
72114
ESP_RETURN_ON_ERROR(esp_netif_napt_enable(netif), TAG, "Failed to enable NAPT");
73-
ESP_RETURN_ON_ERROR(sync.init(), TAG, "Failed to init locks");
115+
ESP_RETURN_ON_ERROR(sync.init(), TAG, "Failed to init event queue");
74116
ESP_RETURN_ON_ERROR(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, handler, this), TAG, "Failed to register event");
75117
ESP_RETURN_ON_ERROR(esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, handler, this), TAG, "Failed to register event");
76118
return xTaskCreate(task, "server", 8192, this, 5, nullptr) == pdTRUE ? ESP_OK : ESP_FAIL;
@@ -109,25 +151,24 @@ class RpcInstance {
109151
esp_err_t wifi_event(int32_t id)
110152
{
111153
ESP_LOGI(TAG, "Received WIFI event %" PRIi32, id);
112-
std::lock_guard<Sync> lock(sync);
113-
ESP_RETURN_ON_ERROR(rpc.send(api_id::WIFI_EVENT, &id), TAG, "Failed to marshall WiFi event");
154+
Events ev{api_id::WIFI_EVENT, id, nullptr};
155+
ESP_RETURN_ON_ERROR(sync.put(ev), TAG, "Failed to queue WiFi event");
114156
return ESP_OK;
115157
}
116158
esp_err_t ip_event(int32_t id, ip_event_got_ip_t *ip_data)
117159
{
118160
ESP_LOGI(TAG, "Received IP event %" PRIi32, id);
119-
esp_wifi_remote_eppp_ip_event ip_event{};
120-
ip_event.id = id;
161+
Events ev{api_id::IP_EVENT, id, nullptr};
121162
if (ip_data->esp_netif) {
122-
// marshall additional data, only if netif available
123-
ESP_RETURN_ON_ERROR(esp_netif_get_dns_info(ip_data->esp_netif, ESP_NETIF_DNS_MAIN, &ip_event.dns), TAG, "Failed to get DNS info");
124-
ESP_LOGI(TAG, "Main DNS:" IPSTR, IP2STR(&ip_event.dns.ip.u_addr.ip4));
125-
memcpy(&ip_event.wifi_ip, &ip_data->ip_info, sizeof(ip_event.wifi_ip));
126-
ESP_RETURN_ON_ERROR(esp_netif_get_ip_info(netif, &ip_event.ppp_ip), TAG, "Failed to get IP info");
163+
ESP_RETURN_ON_ERROR(ev.create_ip_data(), TAG, "Failed to allocate event data");
164+
ev.ip_data->id = id;
165+
ESP_RETURN_ON_ERROR(esp_netif_get_dns_info(ip_data->esp_netif, ESP_NETIF_DNS_MAIN, &ev.ip_data->dns), TAG, "Failed to get DNS info");
166+
ESP_LOGI(TAG, "Main DNS:" IPSTR, IP2STR(&ev.ip_data->dns.ip.u_addr.ip4));
167+
memcpy(&ev.ip_data->wifi_ip, &ip_data->ip_info, sizeof(ev.ip_data->wifi_ip));
168+
ESP_RETURN_ON_ERROR(esp_netif_get_ip_info(netif, &ev.ip_data->ppp_ip), TAG, "Failed to get IP info");
127169
ESP_LOGI(TAG, "IP address:" IPSTR, IP2STR(&ip_data->ip_info.ip));
128170
}
129-
std::lock_guard<Sync> lock(sync);
130-
ESP_RETURN_ON_ERROR(rpc.send(api_id::IP_EVENT, &ip_event), TAG, "Failed to marshal IP event");
171+
ESP_RETURN_ON_ERROR(sync.put(ev), TAG, "Failed to queue IP event");
131172
return ESP_OK;
132173
}
133174
static void handler(void *ctx, esp_event_base_t base, int32_t id, void *data)
@@ -140,11 +181,83 @@ class RpcInstance {
140181
instance->ip_event(id, ip_data);
141182
}
142183
}
184+
int select()
185+
{
186+
struct timeval timeout = { .tv_sec = 1, .tv_usec = 0};
187+
int rpc_sock = rpc.get_socket_fd();
188+
189+
ESP_RETURN_ON_FALSE(rpc_sock != -1, Sync::ERROR, TAG, "failed ot get rpc socket");
190+
fd_set readset;
191+
fd_set errset;
192+
FD_ZERO(&readset);
193+
FD_ZERO(&errset);
194+
FD_SET(rpc_sock, &readset);
195+
FD_SET(sync.fd, &readset);
196+
FD_SET(rpc_sock, &errset);
197+
int ret = ::select(std::max(rpc_sock, 5) + 1, &readset, nullptr, &errset, &timeout);
198+
if (ret == 0) {
199+
ESP_LOGV(TAG, "poll_read: select - Timeout before any socket was ready!");
200+
return Sync::NONE;
201+
}
202+
if (ret < 0) {
203+
ESP_LOGE(TAG, "select error: %d", errno);
204+
return Sync::ERROR;
205+
}
206+
if (FD_ISSET(rpc_sock, &errset)) {
207+
int sock_errno = 0;
208+
uint32_t optlen = sizeof(sock_errno);
209+
getsockopt(rpc_sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
210+
ESP_LOGE(TAG, "select failed, socket errno = %d", sock_errno);
211+
return Sync::ERROR;
212+
}
213+
int result = Sync::NONE;
214+
if (FD_ISSET(rpc_sock, &readset)) {
215+
result |= Sync::RPC;
216+
}
217+
if (FD_ISSET(sync.fd, &readset)) {
218+
result |= Sync::EVENT;
219+
}
220+
return result;
221+
}
222+
esp_err_t marshall_events()
223+
{
224+
api_id type;
225+
do {
226+
Events ev = sync.get();
227+
type = ev.type;
228+
if (ev.type == api_id::WIFI_EVENT) {
229+
ESP_RETURN_ON_ERROR(rpc.send(api_id::WIFI_EVENT, &ev.id), TAG, "Failed to marshall WiFi event");
230+
} else if (ev.type == api_id::IP_EVENT && ev.ip_data) {
231+
ESP_RETURN_ON_ERROR(rpc.send(api_id::IP_EVENT, ev.ip_data), TAG, "Failed to marshal IP event");
232+
}
233+
} while (type != api_id::ERROR);
234+
return ESP_OK;
235+
}
143236
esp_err_t perform()
237+
{
238+
auto res = select();
239+
if (res == Sync::ERROR) {
240+
return ESP_FAIL;
241+
}
242+
if (res & Sync::EVENT) {
243+
uint64_t data;
244+
read(sync.fd, &data, sizeof(data));
245+
if (marshall_events() != ESP_OK) {
246+
return ESP_FAIL;
247+
}
248+
}
249+
if (res & Sync::RPC) {
250+
if (handle_commands() != ESP_OK) {
251+
return ESP_FAIL;
252+
}
253+
}
254+
return ESP_OK;
255+
}
256+
257+
esp_err_t handle_commands()
144258
{
145259
auto header = rpc.get_header();
146260
ESP_LOGI(TAG, "Received header id %d", (int) header.id);
147-
std::lock_guard<Sync> lock(sync);
148261
switch (header.id) {
149262
case api_id::SET_MODE: {
150263
auto req = rpc.get_payload<wifi_mode_t>(api_id::SET_MODE, header);

0 commit comments

Comments
 (0)