Skip to content

Commit

Permalink
Fix complete annihilation of storage on new pair
Browse files Browse the repository at this point in the history
- Might fix Mixiaoxiao#103, Mixiaoxiao#139, Mixiaoxiao#147, Mixiaoxiao#184, Mixiaoxiao#198
- Also adds changes by @ruleechen
- Also adds changes by @thiti-y
  • Loading branch information
paullj1 committed Feb 25, 2023
1 parent c90fa32 commit f22abab
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 108 deletions.
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

0 comments on commit f22abab

Please sign in to comment.