Send BlueZ flow acknowledgements without ATT responses

This commit is contained in:
evgeny committed 2026-10-30 04:35:12 +01:00
1 parent e0076d5d10
commit d0df49446c
3 files changed
+13 -12

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
/* Внутренний платформенный контракт. Все вызовы/события в uasync, send/close не вызывают события синхронно.
* ACCEPTED send копирует значение и даёт ровно один sent, либо closed отменяет все операции соединения.
* DATA sent означает локальное завершение; INVITE/ACK используют Request/Indication.
* DATA/ACK sent означает локальное завершение Without Response/Notify; только INVITE использует Request/Indication.
* close/destroy отменяют callbacks; transport создаёт идентификаторы, backend не хранит указатели core-link.
* Реализации не создают неограниченных очередей: максимум одна операция send на link. */
#ifndef VIBECHAT_BLE_BACKEND_H
+7 -6
View File
@@ -146,7 +146,7 @@ static void notify_read(int fd, void* arg) {
link_error(l, "notification socket read failed"); return;
}
if (!n) { link_error(l, "notification subscription closed"); return; }
if (n != 1 || data[0] != 1 || l->channel == BLE_WIRE_DATA || fd != l->fd[l->channel] ||
if (n != 1 || data[0] != 1 || l->channel != BLE_WIRE_INVITE || fd != l->fd[l->channel] ||
!l->sending || l->buffered) {
DEBUG_WARN(CAT, "BLE indication completion invalid fd=%d expected_fd=%d bytes=%zd sending=%d buffered=%d",
fd, l->fd[l->channel], n, l->sending, l->buffered);
@@ -166,7 +166,7 @@ static void notify_write(int fd, void* arg) {
link_error(l, "notification socket write failed"); return;
}
l->buffered = 0; uasync_set_socket_write(l->backend->ua, l->io[l->channel], 0);
if (l->channel == BLE_WIRE_DATA) {
if (l->channel != BLE_WIRE_INVITE) {
l->sending = 0;
ble_backend_sent(l->backend->owner, l->id, 1);
}
@@ -232,7 +232,7 @@ static int acquire_notify(sd_bus_message* m, void* arg, sd_bus_error* error) {
link_error(l, "AcquireNotify reply failed"); return r;
}
DEBUG_DEBUG(CAT, "BLE BlueZ subscription link=%llu channel=%d mode=%s mtu=%u",
(unsigned long long)l->id, channel, channel == BLE_WIRE_DATA ? "notification" : "indication", mtu);
(unsigned long long)l->id, channel, channel == BLE_WIRE_INVITE ? "indication" : "notification", mtu);
if (l->fd[0] >= 0 && l->fd[1] >= 0 && l->fd[2] >= 0 && !l->opened) {
l->opened = 1; ble_backend_opened(b->owner, l->id, mtu);
}
@@ -249,7 +249,8 @@ static int get_char(sd_bus* bus, const char* path, const char* interface, const
if (!strcmp(property, "UUID")) return sd_bus_message_append(reply, "s",
ctx->tx == 3 ? BLE_ACK_UUID : ctx->tx == 2 ? BLE_INVITE_UUID : ctx->tx ? BLE_TX_UUID : BLE_RX_UUID);
if (!strcmp(property, "Service")) return sd_bus_message_append(reply, "o", SERVICE);
if (!strcmp(property, "Flags") && ctx->tx >= 2) return sd_bus_message_append(reply, "as", 2, "write", "indicate");
if (!strcmp(property, "Flags") && ctx->tx == 2) return sd_bus_message_append(reply, "as", 2, "write", "indicate");
if (!strcmp(property, "Flags") && ctx->tx == 3) return sd_bus_message_append(reply, "as", 2, "write-without-response", "notify");
if (!strcmp(property, "Flags")) return sd_bus_message_append(reply, "as", 1, ctx->tx ? "notify" : "write-without-response");
return sd_bus_message_append(reply, "b", 0); /* NotifyAcquired объявляет поддержку адресного fd API. */
}
@@ -635,11 +636,11 @@ int ble_backend_send(struct ble_backend* b, ble_link_id id, enum ble_wire_channe
const char* path = channel == BLE_WIRE_ACK ? l->ack : channel == BLE_WIRE_INVITE ? l->invite : l->rx;
int r = sd_bus_message_new_method_call(b->bus, &m, "org.bluez", path, CHAR_IF, "WriteValue");
if (r >= 0) r = sd_bus_message_append_array(m, 'y', data, len);
if (r >= 0) r = sd_bus_message_append(m, "a{sv}", 1, "type", "s", channel == BLE_WIRE_DATA ? "command" : "request");
if (r >= 0) r = sd_bus_message_append(m, "a{sv}", 1, "type", "s", channel == BLE_WIRE_INVITE ? "request" : "command");
if (r >= 0) r = sd_bus_call_async(b->bus, &l->write, m, written, l, 10000000);
sd_bus_message_unref(m);
if (r < 0) { DEBUG_ERROR(CAT, "BLE WriteValue request: %s", strerror(-r)); return BLE_ERROR; }
DEBUG_TRACE(CAT, "BLE WriteValue submitted link=%llu channel=%d type=%s bytes=%zu", (unsigned long long)id, channel,
channel == BLE_WIRE_DATA ? "command" : "request", len);
channel == BLE_WIRE_INVITE ? "request" : "command", len);
l->sending = 1; bus_update(b); return BLE_OK;
}
+5 -5
View File
@@ -1,4 +1,4 @@
/* Private D-Bus + настоящий backend: DATA без ATT ACK, адресные INVITE/ACK indications, два клиента. */
/* Private D-Bus + настоящий backend: DATA/ACK без ATT ACK, адресные INVITE indications, два клиента. */
#include "ble_backend.h"
#include "u_async.h"
#include "mem.h"
@@ -31,7 +31,7 @@ static void poll_all(void) {
for (int j = 0; j < 2; j++) if (ack_fds[j] >= 0) {
uint8_t ack[8]; ssize_t n = recv(ack_fds[j], ack, sizeof(ack), MSG_DONTWAIT);
if (n < 0) { CHECK(errno == EAGAIN); continue; }
CHECK(n == 2); ack_values++; CHECK(send(ack_fds[j], "\1", 1, MSG_NOSIGNAL) == 1);
CHECK(n == 2); ack_values++; /* ACK notification не требует ATT confirmation. */
}
}
}
@@ -78,7 +78,7 @@ static int remote_write(sd_bus_message* m, void* arg, sd_bus_error* e) {
CHECK(sd_bus_message_read(m, "s", &type) > 0);
int invitation = strstr(sd_bus_message_get_path(m), "/invite") != NULL;
int ack = strstr(sd_bus_message_get_path(m), "/ack") != NULL;
CHECK(!strcmp(type, invitation || ack ? "request" : "command"));
CHECK(!strcmp(type, invitation ? "request" : "command"));
if (ack) { CHECK(len == 2); ack_requests++; } else if (invitation) requests++; else commands++;
int r = sd_bus_reply_method_return(m, "");
if (!invitation && !ack && len == 19 && ((const uint8_t*)data)[2] == 1) {
@@ -235,11 +235,11 @@ int main(void) {
poll_all(); CHECK(ready_links == 3 && commands == 1);
CHECK(!ble_tx_put(transport, links[3], frame(0xe5)));
CHECK(!ble_channel_tx_put(transport, links[3], BLE_CHANNEL_INVITE, frame(0xe6)));
poll_all(); CHECK(commands == 2 && requests == 1 && ack_requests >= 1); /* MTU517 и ACK Write Request. */
poll_all(); CHECK(commands == 2 && requests == 1 && ack_requests >= 1); /* MTU517 и ACK Write Command. */
ble_destroy(transport); uasync_destroy(ua, 0);
for (int i = 0; i < 5; i++) sd_bus_slot_unref(remote[i]);
sd_bus_slot_unref(manager); sd_bus_slot_unref(adapter); sd_bus_slot_unref(gatt); sd_bus_slot_unref(adv); sd_bus_close_unref(bus);
CHECK(u_get_allocated_count() == before);
puts("BlueZ private-bus tests PASS (DATA commands, addressed INVITE/ACK indications, mandatory ACK, two clients, teardown)");
puts("BlueZ private-bus tests PASS (DATA/ACK commands and notifications, INVITE indications, two clients, teardown)");
return 0;
}