You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.5 KiB
181 lines
4.5 KiB
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
|
|
|
#include <rom/queue.h>
|
|
#include <malloc.h>
|
|
#include <assert.h>
|
|
#include <esp_log.h>
|
|
#include <esp_err.h>
|
|
#include <string.h>
|
|
#include "httpd_utils/session_kvmap.h"
|
|
|
|
static const char *TAG = "sess_kvmap";
|
|
|
|
// this struct is opaque, a stub like this is sufficient for the head pointer.
|
|
struct sess_kv_entry;
|
|
|
|
/** Session head structure, dynamically allocated */
|
|
SLIST_HEAD(sess_kv_map, sess_kv_entry);
|
|
|
|
struct sess_kv_entry {
|
|
SLIST_ENTRY(sess_kv_entry) link;
|
|
char key[SESS_KVMAP_KEY_LEN];
|
|
void *value;
|
|
sess_kv_free_func_t free_fn;
|
|
};
|
|
|
|
struct sess_kv_map *sess_kv_map_alloc(void)
|
|
{
|
|
ESP_LOGD(TAG, "kv store alloc");
|
|
struct sess_kv_map *map = malloc(sizeof(struct sess_kv_map));
|
|
assert(map);
|
|
SLIST_INIT(map);
|
|
return map;
|
|
}
|
|
|
|
void sess_kv_map_free(void *head_v)
|
|
{
|
|
struct sess_kv_map* head = head_v;
|
|
|
|
ESP_LOGD(TAG, "kv store free");
|
|
assert(head);
|
|
struct sess_kv_entry *item, *tmp;
|
|
SLIST_FOREACH_SAFE(item, head, link, tmp) {
|
|
if (item->free_fn) {
|
|
item->free_fn(item->value);
|
|
free(item);
|
|
}
|
|
}
|
|
free(head);
|
|
}
|
|
|
|
|
|
void * sess_kv_map_get(struct sess_kv_map *head, const char *key)
|
|
{
|
|
assert(head);
|
|
assert(key);
|
|
ESP_LOGD(TAG, "kv store get %s", key);
|
|
|
|
struct sess_kv_entry *item;
|
|
SLIST_FOREACH(item, head, link) {
|
|
if (0==strcmp(item->key, key)) {
|
|
ESP_LOGD(TAG, "got ok");
|
|
return item->value;
|
|
}
|
|
}
|
|
|
|
ESP_LOGD(TAG, "not found in store");
|
|
return NULL;
|
|
}
|
|
|
|
void * sess_kv_map_take(struct sess_kv_map *head, const char *key)
|
|
{
|
|
assert(head);
|
|
assert(key);
|
|
ESP_LOGD(TAG, "kv store take %s", key);
|
|
|
|
struct sess_kv_entry *item;
|
|
SLIST_FOREACH(item, head, link) {
|
|
if (0==strcmp(item->key, key)) {
|
|
item->key[0] = 0;
|
|
item->free_fn = NULL;
|
|
ESP_LOGD(TAG, "taken ok");
|
|
return item->value;
|
|
}
|
|
}
|
|
|
|
ESP_LOGD(TAG, "not found in store");
|
|
return NULL;
|
|
}
|
|
|
|
esp_err_t sess_kv_map_remove(struct sess_kv_map *head, const char *key)
|
|
{
|
|
assert(head);
|
|
assert(key);
|
|
ESP_LOGD(TAG, "kv store remove %s", key);
|
|
|
|
struct sess_kv_entry *item;
|
|
SLIST_FOREACH(item, head, link) {
|
|
if (0==strcmp(item->key, key)) {
|
|
if (item->free_fn) {
|
|
item->free_fn(item->value);
|
|
}
|
|
item->key[0] = 0;
|
|
item->value = NULL;
|
|
item->free_fn = NULL;
|
|
return ESP_OK;
|
|
}
|
|
}
|
|
|
|
ESP_LOGD(TAG, "couldn't remove, not found: %s", key);
|
|
return ESP_ERR_NOT_FOUND;
|
|
}
|
|
|
|
|
|
esp_err_t sess_kv_map_set(struct sess_kv_map *head, const char *key, void *value, sess_kv_free_func_t free_fn)
|
|
{
|
|
assert(head);
|
|
assert(key);
|
|
ESP_LOGD(TAG, "kv set value for key %s", key);
|
|
|
|
size_t key_len = strlen(key);
|
|
if (key_len > SESS_KVMAP_KEY_LEN-1) {
|
|
ESP_LOGE(TAG, "Key too long: %s", key);
|
|
// discard illegal key
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (key_len == 0) {
|
|
ESP_LOGE(TAG, "Key too short: \"%s\"", key);
|
|
// discard illegal key
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
struct sess_kv_entry *item = NULL;
|
|
struct sess_kv_entry *empty_item = NULL; // found item with no content
|
|
SLIST_FOREACH(item, head, link) {
|
|
ESP_LOGD(TAG, "test item with key %s, ptr %p > %p", item->key, item, item->link.sle_next);
|
|
if (0 == item->key[0]) {
|
|
ESP_LOGD(TAG, "found an empty slot");
|
|
empty_item = item;
|
|
}
|
|
else if (0==strcmp(item->key, key)) {
|
|
ESP_LOGD(TAG, "old value replaced");
|
|
if (item->free_fn) {
|
|
item->free_fn(item->value);
|
|
}
|
|
item->value = value;
|
|
item->free_fn = free_fn;
|
|
return ESP_OK;
|
|
} else {
|
|
ESP_LOGD(TAG, "skip this one");
|
|
}
|
|
}
|
|
|
|
struct sess_kv_entry *new_item = NULL;
|
|
|
|
// insert new or reuse an empty item
|
|
if (empty_item) {
|
|
new_item = empty_item;
|
|
ESP_LOGD(TAG, "empty item reused (%p)", new_item);
|
|
} else {
|
|
ESP_LOGD(TAG, "alloc new item");
|
|
// key not found, add a new entry.
|
|
new_item = malloc(sizeof(struct sess_kv_entry));
|
|
if (!new_item) {
|
|
ESP_LOGE(TAG, "New entry alloc failed");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
}
|
|
|
|
strcpy(new_item->key, key);
|
|
new_item->free_fn = free_fn;
|
|
new_item->value = value;
|
|
|
|
if (!empty_item) {
|
|
ESP_LOGD(TAG, "insert new item into list");
|
|
// this item was malloc'd
|
|
SLIST_INSERT_HEAD(head, new_item, link);
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|