Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix new device ID on HomeKit topology change #212

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Fix complete annihilation of storage on new pair
- Might fix #103, #139, #147, #184, #198
- Also adds changes by @ruleechen
- Also adds changes by @thiti-y
  • Loading branch information
paullj1 committed Feb 25, 2023
commit f22ababf638d4b5c1048665d693bb1a788b6267a
77 changes: 17 additions & 60 deletions src/arduino_homekit_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,27 +524,21 @@ void write(client_context_t *context, byte *data, int data_size) {
CLIENT_ERROR(context, "The socket is null! (or is closed)");
return;
}
if (context->disconnect) {
context->error_write = true;
return;
}
if (context->error_write) {
CLIENT_ERROR(context, "Abort write data since error_write.");
return;
}
int write_size = context->socket->write(data, data_size);
CLIENT_DEBUG(context, "Sending data of size %d", data_size);
if (write_size != data_size) {
CLIENT_ERROR(context, "socket.write, data_size=%d, write_size=%d", data_size, write_size);
context->error_write = true;
// Error write when :
// 1. remote client is disconnected
// 2. data_size is larger than the tcp internal send buffer
// But We has limited the data_size to 538, and TCP_SND_BUF = 1072. (See the comments on HOMEKIT_JSONBUFFER_SIZE)
// So we believe here is disconnected.
context->disconnect = true;
homekit_server_close_client(context->server, context);
// We consider the socket is 'closed' when error in writing (eg. the remote client is disconnected, NO tcp ack receive).
// Closing the socket causes memory-leak if some data has not been sent (the write_buffer did not free)
// To fix this memory-leak, add tcp_abandon(_pcb, 0); in ClientContext.h of ESP8266WiFi-library.
context->socket->keepAlive(1, 1, 1); // fast disconnected internally in 1 second.
CLIENT_ERROR(context, "socket.write, data_size=%d, write_size=%d", data_size, write_size);
}

}

int client_send_encrypted_(client_context_t *context,
Expand Down Expand Up @@ -2699,9 +2693,6 @@ void homekit_server_on_reset(client_context_t *context) {

homekit_server_reset();
send_204_response(context);

//vTaskDelay(3000 / portTICK_PERIOD_MS);

homekit_system_restart();
}

Expand Down Expand Up @@ -3141,27 +3132,30 @@ void homekit_mdns_init(homekit_server_t *server) {

homekit_accessory_t *accessory = server->config->accessories[0];
homekit_service_t *accessory_info = homekit_service_by_type(accessory,
HOMEKIT_SERVICE_ACCESSORY_INFORMATION);
HOMEKIT_SERVICE_ACCESSORY_INFORMATION);
if (!accessory_info) {
ERROR("Invalid accessory declaration: no Accessory Information service");
return;
}

homekit_characteristic_t *name = homekit_service_characteristic_by_type(accessory_info,
HOMEKIT_CHARACTERISTIC_NAME);
HOMEKIT_CHARACTERISTIC_NAME);

if (!name) {
ERROR("Invalid accessory declaration: " "no Name characteristic in AccessoryInfo service");
return;
}

homekit_characteristic_t *model = homekit_service_characteristic_by_type(accessory_info,
HOMEKIT_CHARACTERISTIC_MODEL);
HOMEKIT_CHARACTERISTIC_MODEL);

if (!model) {
ERROR("Invalid accessory declaration: " "no Model characteristic in AccessoryInfo service");
return;
}

if (homekit_mdns_started) {
// MDNS.close();
MDNS.begin(name->value.string_value, staIP);
INFO("MDNS restart: %s, IP: %s", name->value.string_value, staIP.toString().c_str());
MDNS.announce();
Expand All @@ -3175,7 +3169,7 @@ void homekit_mdns_init(homekit_server_t *server) {
INFO("MDNS begin: %s, IP: %s", name->value.string_value, staIP.toString().c_str());

MDNSResponder::hMDNSService mdns_service = MDNS.addService(name->value.string_value,
HOMEKIT_MDNS_SERVICE, HOMEKIT_MDNS_PROTO, HOMEKIT_SERVER_PORT);
HOMEKIT_MDNS_SERVICE, HOMEKIT_MDNS_PROTO, HOMEKIT_SERVER_PORT);
// Set a service specific callback for dynamic service TXT items.
// The callback is called, whenever service TXT items are needed for the given service.
MDNS.setDynamicServiceTxtCallback(mdns_service,
Expand Down Expand Up @@ -3206,31 +3200,6 @@ void homekit_mdns_init(homekit_server_t *server) {
//MDNS.addServiceTxt(HAP_SERVICE, HOMEKIT_MDNS_PROTO, "sf", (server->paired) ? "0" : "1");
MDNS.addServiceTxt(mdns_service, "ci", String(server->config->category).c_str());

/*
// accessory model name (required)
homekit_mdns_add_txt("md", "%s", model->value.string_value);
// protocol version (required)
homekit_mdns_add_txt("pv", "1.0");
// device ID (required)
// should be in format XX:XX:XX:XX:XX:XX, otherwise devices will ignore it
homekit_mdns_add_txt("id", "%s", server->accessory_id);
// current configuration number (required)
homekit_mdns_add_txt("c#", "%d", server->config->config_number);
// current state number (required)
homekit_mdns_add_txt("s#", "1");
// feature flags (required if non-zero)
// bit 0 - supports HAP pairing. required for all HomeKit accessories
// bits 1-7 - reserved
homekit_mdns_add_txt("ff", "0");
// status flags
// bit 0 - not paired
// bit 1 - not configured to join WiFi
// bit 2 - problem detected on accessory
// bits 3-7 - reserved
homekit_mdns_add_txt("sf", "%d", (server->paired) ? 0 : 1);
// accessory category identifier
homekit_mdns_add_txt("ci", "%d", server->config->category);*/

if (server->config->setupId) {
DEBUG("Accessory Setup ID = %s", server->config->setupId);

Expand All @@ -3254,8 +3223,6 @@ void homekit_mdns_init(homekit_server_t *server) {
MDNS.announce();
MDNS.update();
homekit_mdns_started = true;
//INFO("MDNS ok! Open your \"Home\" app, click \"Add or Scan Accessory\""
// " and \"I Don't Have a Code\". \nThis Accessory will show on your iOS device.");
}

// Used to update the config_number ("c#" value of Bonjour)
Expand Down Expand Up @@ -3350,19 +3317,9 @@ void homekit_server_init(homekit_server_config_t *config) {
//homekit_server_task(server);
INFO("Starting server");

int r = homekit_storage_init();
if (r == 0) {
r = homekit_storage_load_accessory_id(server->accessory_id);

if (!r)
r = homekit_storage_load_accessory_key(&server->accessory_key);
}

if (r) {
if (r < 0) {
INFO("Resetting HomeKit storage");
homekit_storage_reset();
}
if (homekit_storage_init() != 0 ||
homekit_storage_load_accessory_id(server->accessory_id) != 0 ||
homekit_storage_load_accessory_key(&server->accessory_key) != 0) {

homekit_accessory_id_generate(server->accessory_id);
homekit_storage_save_accessory_id(server->accessory_id);
Expand Down
2 changes: 1 addition & 1 deletion src/homekit_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ typedef unsigned char byte;
#define HOMEKIT_LOG_DEBUG 3

#ifndef HOMEKIT_LOG_LEVEL
#define HOMEKIT_LOG_LEVEL HOMEKIT_NO_LOG
#define HOMEKIT_LOG_LEVEL HOMEKIT_LOG_DEBUG
#endif

#define HOMEKIT_PRINTF XPGM_PRINTF
Expand Down
109 changes: 62 additions & 47 deletions src/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,59 +78,62 @@ extern uint32_t _SPIFFS_start; //See spiffs_api.h

#define STORAGE_DEBUG(message, ...) //printf("*** [Storage] %s: " message "\n", __func__, ##__VA_ARGS__)

const char magic1[] = "HAP";
const char hap_magic[] = "HAP";

// TODO: figure out alignment issues
typedef struct {
char magic[sizeof(magic1)];
char magic[sizeof(hap_magic)];
byte permissions;
char device_id[DEVICE_ID_SIZE];
byte device_public_key[32];

byte _reserved[7]; // align record to be 80 bytes
} pairing_data_t;

bool homekit_storage_magic_valid() {
char magic_test[sizeof(hap_magic)];
bzero(magic_test, sizeof(magic_test));

int homekit_storage_init() {
if (!spiflash_read(MAGIC_ADDR, (byte *)magic_test, sizeof(magic_test))) {
ERROR("Failed to read HomeKit storage magic");
return false;
}
return (memcmp(magic_test, hap_magic, sizeof(hap_magic)) == 0);
}

STORAGE_DEBUG("EEPROM max: %d B", SPI_FLASH_SEC_SIZE);//4096B
STORAGE_DEBUG("Pairing_data size: %d ", (sizeof(pairing_data_t)));//80B
STORAGE_DEBUG("MAX pairing count: %d ", MAX_PAIRINGS);//16
STORAGE_DEBUG("_EEPROM_start: 0x%x (%u)",
HOMEKIT_EEPROM_PHYS_ADDR, HOMEKIT_EEPROM_PHYS_ADDR);
STORAGE_DEBUG("_SPIFFS_start: 0x%x (%u)",
HOMEKIT_SPIFFS_PHYS_ADDR, HOMEKIT_SPIFFS_PHYS_ADDR);
bool homekit_storage_set_magic() {
if (!spiflash_write(MAGIC_ADDR, (byte *)hap_magic, sizeof(hap_magic))) {
ERROR("Failed to write HomeKit storage magic");
return false;
}
return true;
}

char magic[sizeof(magic1)];
memset(magic, 0, sizeof(magic));
int homekit_storage_init() {

if (!spiflash_read(MAGIC_ADDR, (byte *)magic, sizeof(magic))) {
ERROR("Failed to read HomeKit storage magic");
}
STORAGE_DEBUG("EEPROM max: %d B", SPI_FLASH_SEC_SIZE);//4096B
STORAGE_DEBUG("Pairing_data size: %d ", (sizeof(pairing_data_t)));//80B
STORAGE_DEBUG("MAX pairing count: %d ", MAX_PAIRINGS);//16
STORAGE_DEBUG("_EEPROM_start: 0x%x (%u)",
HOMEKIT_EEPROM_PHYS_ADDR, HOMEKIT_EEPROM_PHYS_ADDR);
STORAGE_DEBUG("_SPIFFS_start: 0x%x (%u)",
HOMEKIT_SPIFFS_PHYS_ADDR, HOMEKIT_SPIFFS_PHYS_ADDR);

if (strncmp(magic, magic1, sizeof(magic1))) {
if (!homekit_storage_magic_valid()) {
INFO("Formatting HomeKit storage at 0x%x", STORAGE_BASE_ADDR);
if (!spiflash_erase_sector(STORAGE_BASE_ADDR)) {
if (!spiflash_erase_sector(STORAGE_BASE_ADDR) || !homekit_storage_set_magic()) {
ERROR("Failed to erase HomeKit storage");
return -1;
return -1; // Fail case
}

strncpy(magic, magic1, sizeof(magic));
if (!spiflash_write(MAGIC_ADDR, (byte *)magic, sizeof(magic))) {
ERROR("Failed to write HomeKit storage magic");
return -1;
}

return 1;
return 1; // Wasn't valid, is now
}

return 0;
return 0; // Was valid
}


int homekit_storage_reset() {
byte blank[sizeof(magic1)];
memset(blank, 0, sizeof(blank));
byte blank[sizeof(hap_magic)];
bzero(blank, sizeof(blank));

if (!spiflash_write(MAGIC_ADDR, blank, sizeof(blank))) {
ERROR("Failed to reset HomeKit storage");
Expand All @@ -140,6 +143,18 @@ int homekit_storage_reset() {
return homekit_storage_init();
}

int homekit_storage_reset_pairing_data() {

byte blank[sizeof(pairing_data_t) * MAX_PAIRINGS];
bzero(blank,sizeof(blank));

INFO("Formatting HomeKit storage at 0x%x", PAIRINGS_OFFSET);
if (!spiflash_write(PAIRINGS_OFFSET, blank, sizeof(blank))) {
ERROR("Failed to erase HomeKit pairing storage");
return -1; // Fail case
}
return 0;
}

void homekit_storage_save_accessory_id(const char *accessory_id) {
if (!spiflash_write(ACCESSORY_ID_ADDR, (byte *)accessory_id, ACCESSORY_ID_SIZE)) {
Expand Down Expand Up @@ -209,7 +224,7 @@ bool homekit_storage_can_add_pairing() {
pairing_data_t data;
for (int i=0; i<MAX_PAIRINGS; i++) {
spiflash_read(PAIRINGS_ADDR + sizeof(data)*i, (byte *)&data, sizeof(data));
if (strncmp(data.magic, magic1, sizeof(magic1)))
if (memcmp(data.magic, hap_magic, sizeof(hap_magic)))
return true;
}
return false;
Expand All @@ -226,7 +241,7 @@ static int compact_data() {
int next_pairing_idx = 0;
for (int i=0; i<MAX_PAIRINGS; i++) {
pairing_data_t *pairing_data = (pairing_data_t *)&data[PAIRINGS_OFFSET + sizeof(pairing_data_t)*i];
if (!strncmp(pairing_data->magic, magic1, sizeof(magic1))) {
if (!memcmp(pairing_data->magic, hap_magic, sizeof(hap_magic))) {
if (i != next_pairing_idx) {
memcpy(&data[PAIRINGS_ADDR + sizeof(pairing_data_t)*next_pairing_idx],
pairing_data, sizeof(*pairing_data));
Expand All @@ -241,7 +256,7 @@ static int compact_data() {
return 0;
}

if (homekit_storage_reset()) {
if (homekit_storage_reset_pairing_data()) {
ERROR("Failed to compact HomeKit storage: error resetting flash");
free(data);
return -1;
Expand Down Expand Up @@ -291,10 +306,10 @@ int homekit_storage_add_pairing(const char *device_id, const ed25519_key *device

pairing_data_t data;

memset(&data, 0, sizeof(data));
strncpy(data.magic, magic1, sizeof(data.magic));
bzero(&data, sizeof(data));
memcpy(data.magic, hap_magic, sizeof(data.magic));
data.permissions = permissions;
strncpy(data.device_id, device_id, sizeof(data.device_id));
memcpy(data.device_id, device_id, sizeof(data.device_id));
size_t device_public_key_size = sizeof(data.device_public_key);
int r = crypto_ed25519_export_public_key(
device_key, data.device_public_key, &device_public_key_size
Expand All @@ -317,10 +332,10 @@ int homekit_storage_update_pairing(const char *device_id, byte permissions) {
pairing_data_t data;
for (int i=0; i<MAX_PAIRINGS; i++) {
spiflash_read(PAIRINGS_ADDR + sizeof(data)*i, (byte *)&data, sizeof(data));
if (strncmp(data.magic, magic1, sizeof(data.magic)))
if (memcmp(data.magic, hap_magic, sizeof(data.magic)))
continue;

if (!strncmp(data.device_id, device_id, sizeof(data.device_id))) {
if (!memcmp(data.device_id, device_id, sizeof(data.device_id))) {
int next_block_idx = find_empty_block();
if (next_block_idx == -1) {
compact_data();
Expand All @@ -339,7 +354,7 @@ int homekit_storage_update_pairing(const char *device_id, byte permissions) {
return -1;
}

memset(&data, 0, sizeof(data));
bzero(&data, sizeof(data));
if (!spiflash_write(PAIRINGS_ADDR + sizeof(data)*i, (byte *)&data, sizeof(data))) {
ERROR("Failed to update pairing: error erasing old record from HomeKit storage");
return -2;
Expand All @@ -356,11 +371,11 @@ int homekit_storage_remove_pairing(const char *device_id) {
pairing_data_t data;
for (int i=0; i<MAX_PAIRINGS; i++) {
spiflash_read(PAIRINGS_ADDR + sizeof(data)*i, (byte *)&data, sizeof(data));
if (strncmp(data.magic, magic1, sizeof(data.magic)))
if (memcmp(data.magic, hap_magic, sizeof(data.magic)))
continue;

if (!strncmp(data.device_id, device_id, sizeof(data.device_id))) {
memset(&data, 0, sizeof(data));
if (!memcmp(data.device_id, device_id, sizeof(data.device_id))) {
bzero(&data, sizeof(data));
if (!spiflash_write(PAIRINGS_ADDR + sizeof(data)*i, (byte *)&data, sizeof(data))) {
ERROR("Failed to remove pairing from HomeKit storage");
return -2;
Expand All @@ -377,10 +392,10 @@ int homekit_storage_find_pairing(const char *device_id, pairing_t *pairing) {
pairing_data_t data;
for (int i=0; i<MAX_PAIRINGS; i++) {
spiflash_read(PAIRINGS_ADDR + sizeof(data)*i, (byte *)&data, sizeof(data));
if (strncmp(data.magic, magic1, sizeof(data.magic)))
if (memcmp(data.magic, hap_magic, sizeof(data.magic)))
continue;

if (!strncmp(data.device_id, device_id, sizeof(data.device_id))) {
if (!memcmp(data.device_id, device_id, sizeof(data.device_id))) {
crypto_ed25519_init(&pairing->device_key);
int r = crypto_ed25519_import_public_key(&pairing->device_key, data.device_public_key, sizeof(data.device_public_key));
if (r) {
Expand All @@ -389,7 +404,7 @@ int homekit_storage_find_pairing(const char *device_id, pairing_t *pairing) {
}

pairing->id = i;
strncpy(pairing->device_id, data.device_id, DEVICE_ID_SIZE);
memcpy(pairing->device_id, data.device_id, DEVICE_ID_SIZE);
pairing->device_id[DEVICE_ID_SIZE] = 0;
pairing->permissions = data.permissions;

Expand All @@ -416,7 +431,7 @@ int homekit_storage_next_pairing(pairing_iterator_t *it, pairing_t *pairing) {
int id = it->idx++;

spiflash_read(PAIRINGS_ADDR + sizeof(data)*id, (byte *)&data, sizeof(data));
if (!strncmp(data.magic, magic1, sizeof(data.magic))) {
if (!memcmp(data.magic, hap_magic, sizeof(data.magic))) {
crypto_ed25519_init(&pairing->device_key);
int r = crypto_ed25519_import_public_key(&pairing->device_key, data.device_public_key, sizeof(data.device_public_key));
if (r) {
Expand All @@ -425,7 +440,7 @@ int homekit_storage_next_pairing(pairing_iterator_t *it, pairing_t *pairing) {
}

pairing->id = id;
strncpy(pairing->device_id, data.device_id, DEVICE_ID_SIZE);
memcpy(pairing->device_id, data.device_id, DEVICE_ID_SIZE);
pairing->device_id[DEVICE_ID_SIZE] = 0;
pairing->permissions = data.permissions;

Expand Down
Loading